On Fri, 18 Sep 2026, Tamar Christina wrote:

> Fold integer VEC_UNPACK_LO_EXPR and VEC_UNPACK_HI_EXPR for suitable
> variable-length VECTOR_CSTs.
> 
> The fixed-length case already folds.  This extends the same idea to VLA
> constants when the input has twice as many elements as the output and the
> selected half can be represented as a valid VECTOR_CST.  This helps fold
> known predicate constants before RTL expansion, avoiding unnecessary
> predicate unpack instructions.
> 
> The selftests cover the foldable low/high cases and cases that should not
> fold.
> 
> This show up often with known iteration loops and folding these in gimple
> allows us to fold away unrolled masks which end up being empty.
> 
> Bootstrapped Regtested on aarch64-none-linux-gnu,
> arm-none-linux-gnueabihf, x86_64-pc-linux-gnu
> -m32, -m64 and no issues.
> 
> OK for master?

Can you try follow Richards comments as to how to keep the
constant/non-constant paths unified that lead to r17-3738-gaaa0f6b1e87bc6?

Thanks,
Richard.

> Thanks,
> Tamar
> 
> gcc/ChangeLog:
> 
>       * fold-const.cc (const_unop): Fold VEC_UNPACK_LO_EXPR and
>       VEC_UNPACK_HI_EXPR for suitable variable-length VECTOR_CSTs.
>       (selftest::test_vec_unpack_folding): New function.
>       (selftest::fold_const_cc_tests): Call it.
> 
> ---
> diff --git a/gcc/fold-const.cc b/gcc/fold-const.cc
> index 
> 4c4b535d44041ba9fd035ac3841d6862ab5700d1..289c5d5580b4793001ddce55a4a0a0f498db9e53
>  100644
> --- a/gcc/fold-const.cc
> +++ b/gcc/fold-const.cc
> @@ -1956,7 +1956,53 @@ const_unop (enum tree_code code, tree type, tree arg0)
>         return NULL_TREE;
>  
>       if (!VECTOR_CST_NELTS (arg0).is_constant (&in_nelts))
> -       return NULL_TREE;
> +       {
> +         if (code != VEC_UNPACK_LO_EXPR && code != VEC_UNPACK_HI_EXPR)
> +           return NULL_TREE;
> +         if (!known_eq (VECTOR_CST_NELTS (arg0),
> +                        TYPE_VECTOR_SUBPARTS (type) * 2)
> +             || VECTOR_CST_STEPPED_P (arg0))
> +           return NULL_TREE;
> +
> +         unsigned int min_out_nelts
> +           = constant_lower_bound (TYPE_VECTOR_SUBPARTS (type));
> +         tree fill = fold_convert_const (NOP_EXPR, TREE_TYPE (type),
> +                                         vector_cst_elt (arg0,
> +                                                         min_out_nelts));
> +         if (fill == NULL_TREE || !CONSTANT_CLASS_P (fill))
> +           return NULL_TREE;
> +
> +         /* Check that the selected high half is a single repeated value.
> +            Since the input is not stepped, checking one full pattern is
> +            enough to prove the scalable tail.  */
> +         for (i = 1; i < VECTOR_CST_NPATTERNS (arg0); ++i)
> +           {
> +             tree elt = fold_convert_const (NOP_EXPR, TREE_TYPE (type),
> +                                            vector_cst_elt
> +                                              (arg0,
> +                                               min_out_nelts + i));
> +             if (elt == NULL_TREE
> +                 || !CONSTANT_CLASS_P (elt)
> +                 || !operand_equal_p (elt, fill, 0))
> +               return NULL_TREE;
> +           }
> +
> +         if ((!BYTES_BIG_ENDIAN) ^ (code == VEC_UNPACK_LO_EXPR))
> +           return build_vector_from_val (type, fill);
> +
> +         tree_vector_builder elts (type, min_out_nelts, 2);
> +         for (i = 0; i < min_out_nelts; ++i)
> +           {
> +             tree elt = fold_convert_const (NOP_EXPR, TREE_TYPE (type),
> +                                            vector_cst_elt (arg0, i));
> +             if (elt == NULL_TREE || !CONSTANT_CLASS_P (elt))
> +               return NULL_TREE;
> +             elts.quick_push (elt);
> +           }
> +         for (i = 0; i < min_out_nelts; ++i)
> +           elts.quick_push (fill);
> +         return elts.build ();
> +       }
>       out_nelts = in_nelts / 2;
>       gcc_assert (known_eq (out_nelts, TYPE_VECTOR_SUBPARTS (type)));
>  
> @@ -17753,6 +17799,96 @@ test_vec_duplicate_folding ()
>    ASSERT_TRUE (operand_equal_p (dup5_expr, dup5_cst, 0));
>  }
>  
> +/* Verify folding of VEC_UNPACK_{LO,HI}_EXPRs.  */
> +
> +static void
> +test_vec_unpack_folding ()
> +{
> +  machine_mode vmode;
> +  FOR_EACH_MODE_IN_CLASS (vmode, MODE_VECTOR_INT)
> +    {
> +      poly_uint64 in_nelts = GET_MODE_NUNITS (vmode);
> +      if (!test_fold_vec_perm_cst::is_simple_vla_size (in_nelts)
> +       || in_nelts.coeffs[0] < 2
> +       || !targetm.vector_mode_supported_p (vmode))
> +     continue;
> +
> +      unsigned int in_bits = GET_MODE_UNIT_BITSIZE (vmode);
> +      if (in_bits >= HOST_BITS_PER_WIDE_INT)
> +     continue;
> +
> +      unsigned int min_out_nelts = in_nelts.coeffs[0] / 2;
> +      tree in_inner_type = lang_hooks.types.type_for_mode
> +     (GET_MODE_INNER (vmode), 1);
> +      tree out_inner_type = build_nonstandard_integer_type (in_bits * 2, 1);
> +      tree in_type = build_vector_type_for_mode (in_inner_type, vmode);
> +      tree out_type = build_vector_type (out_inner_type,
> +                                      exact_div (in_nelts, 2));
> +
> +      tree_vector_builder builder (in_type, in_nelts.coeffs[0], 2);
> +      for (unsigned int i = 0; i < in_nelts.coeffs[0]; ++i)
> +     builder.quick_push (build_int_cst (in_inner_type, i + 1));
> +      for (unsigned int i = 0; i < in_nelts.coeffs[0]; ++i)
> +     builder.quick_push (build_int_cst (in_inner_type,
> +                                        i < min_out_nelts ? 100 + i : 77));
> +      tree arg = builder.build ();
> +
> +      tree lo = const_unop (VEC_UNPACK_LO_EXPR, out_type, arg);
> +      ASSERT_TRUE (lo != NULL_TREE);
> +      tree hi = const_unop (VEC_UNPACK_HI_EXPR, out_type, arg);
> +      ASSERT_TRUE (hi != NULL_TREE);
> +
> +      tree prefix = (!BYTES_BIG_ENDIAN ? lo : hi);
> +      tree dup = (!BYTES_BIG_ENDIAN ? hi : lo);
> +
> +      ASSERT_EQ (VECTOR_CST, TREE_CODE (prefix));
> +      ASSERT_EQ (VECTOR_CST, TREE_CODE (dup));
> +      ASSERT_KNOWN_EQ (TYPE_VECTOR_SUBPARTS (out_type),
> +                    VECTOR_CST_NELTS (prefix));
> +      ASSERT_KNOWN_EQ (TYPE_VECTOR_SUBPARTS (out_type),
> +                    VECTOR_CST_NELTS (dup));
> +      ASSERT_EQ (min_out_nelts, VECTOR_CST_NPATTERNS (prefix));
> +      ASSERT_EQ (2, VECTOR_CST_NELTS_PER_PATTERN (prefix));
> +      ASSERT_EQ (1, VECTOR_CST_NPATTERNS (dup));
> +      ASSERT_EQ (1, VECTOR_CST_NELTS_PER_PATTERN (dup));
> +
> +      for (unsigned int i = 0; i < min_out_nelts; ++i)
> +     {
> +       tree elt = build_int_cst (out_inner_type, i + 1);
> +       ASSERT_TRUE (operand_equal_p (VECTOR_CST_ELT (prefix, i),
> +                                     elt, 0));
> +       tree fill = build_int_cst (out_inner_type, 77);
> +       ASSERT_TRUE (operand_equal_p (VECTOR_CST_ELT
> +                                       (prefix, min_out_nelts + i),
> +                                     fill, 0));
> +       ASSERT_TRUE (operand_equal_p (VECTOR_CST_ELT (dup, i),
> +                                     fill, 0));
> +     }
> +
> +      tree_vector_builder varied (in_type, in_nelts.coeffs[0], 2);
> +      for (unsigned int i = 0; i < in_nelts.coeffs[0]; ++i)
> +     varied.quick_push (build_int_cst (in_inner_type, i + 1));
> +      for (unsigned int i = 0; i < in_nelts.coeffs[0]; ++i)
> +     varied.quick_push (build_int_cst (in_inner_type, 100 + i));
> +      ASSERT_EQ (NULL_TREE, const_unop (VEC_UNPACK_LO_EXPR, out_type,
> +                                     varied.build ()));
> +
> +      tree_vector_builder stepped (in_type, 1, 3);
> +      stepped.quick_push (build_int_cst (in_inner_type, 1));
> +      stepped.quick_push (build_int_cst (in_inner_type, 2));
> +      stepped.quick_push (build_int_cst (in_inner_type, 3));
> +      ASSERT_EQ (NULL_TREE, const_unop (VEC_UNPACK_LO_EXPR, out_type,
> +                                     stepped.build ()));
> +
> +      tree wrong_out_type = build_vector_type (out_inner_type, in_nelts);
> +      ASSERT_EQ (NULL_TREE, const_unop (VEC_UNPACK_LO_EXPR, wrong_out_type,
> +                                     arg));
> +      ASSERT_EQ (NULL_TREE, const_unop (VEC_UNPACK_FLOAT_LO_EXPR, out_type,
> +                                     arg));
> +      return;
> +    }
> +}
> +
>  /* Run all of the selftests within this file.  */
>  
>  void
> @@ -17761,6 +17897,7 @@ fold_const_cc_tests ()
>    test_arithmetic_folding ();
>    test_vector_folding ();
>    test_vec_duplicate_folding ();
> +  test_vec_unpack_folding ();
>    test_fold_vec_perm_cst::test ();
>    test_operand_equality::test ();
>  }
> 
> 
> 

-- 
Richard Biener <[email protected]>
SUSE Software Solutions Germany GmbH,
Frankenstrasse 146, 90461 Nuernberg, Germany;
GF: Stefan Gaiser, Jochen Jaser, Abhinav Puri; (HRB 36809, AG Nuernberg)

Reply via email to