On Mon, Oct 12, 2026 at 1:47 AM <[email protected]> wrote:
>
> From: Dhruv Chawla <[email protected]>
>
> r17-4816-gb24418a2212866 gives a call whose result is discarded a placeholder
> lhs using create_tmp_var, which gives a VAR_DECL. This ends up setting
> ssa_renaming_needed and the subsequent fold passes do not set TODO_update_ssa,
> so execute_todo ICEs. This is only set for register types and not for
> aggregates, like svfloat32x2_t, which cannot be made via make_ssa_name
> regardless. Thus, only generate the SSA name when is_gimple_reg_type is
> true.
>
> This needs the fold to run after SSA construction. In the testcase the second
> operand is not yet a constant when intrinsics are first folded from
> gimple-low, so the fold only succeeds once CCP has executed.
>
> Bootstrapped and regtested on aarch64-linux-gnu.
>
> Signed-off-by: Dhruv Chawla <[email protected]>
>
> gcc/ChangeLog:
>
>         PR target/127771
>         * config/aarch64/aarch64-acle-builtins.cc: Include ssa.h.
>         (gimple_folder::fold): Make an SSA name for the placeholder when
>         is_gimple_reg_type and release it when unused.

What about this alternative patch?  This should be less fragile though
it requires some more changes than the current approach.
I have not tested it either so there might be some typos.


>
> gcc/testsuite/ChangeLog:
>
>         PR target/127771
>         * gcc.target/aarch64/sve/acle/general/pr127771.c: New test.
> ---
>  gcc/config/aarch64/aarch64-acle-builtins.cc   | 37 ++++++++++++++++---
>  .../aarch64/sve/acle/general/pr127771.c       | 21 +++++++++++
>  2 files changed, 52 insertions(+), 6 deletions(-)
>  create mode 100644 
> gcc/testsuite/gcc.target/aarch64/sve/acle/general/pr127771.c
>
> diff --git a/gcc/config/aarch64/aarch64-acle-builtins.cc 
> b/gcc/config/aarch64/aarch64-acle-builtins.cc
> index 5abcc01b96bf..238570d9becd 100644
> --- a/gcc/config/aarch64/aarch64-acle-builtins.cc
> +++ b/gcc/config/aarch64/aarch64-acle-builtins.cc
> @@ -46,6 +46,7 @@
>  #include "gimple-fold.h"
>  #include "langhooks.h"
>  #include "stringpool.h"
> +#include "ssa.h"
>  #include "attribs.h"
>  #include "value-range.h"
>  #include "tree-ssanames.h"
> @@ -3142,16 +3143,40 @@ gimple_folder::fold ()
>    /* Create a placeholder variable for the result.
>       This allows implementers of `fold` to assume `lhs` will never be null.
>       If the result is unused, it will be optimized away later.  */
> +  tree placeholder = NULL_TREE;
>    if (!lhs && TREE_TYPE (gimple_call_fntype (call)) != void_type_node)
> -    lhs = create_tmp_var (TREE_TYPE (gimple_call_fntype (call)));
> +    {
> +      tree type = TREE_TYPE (gimple_call_fntype (call));
> +
> +      /* PR target/127771: A register result has to be an SSA name as 
> VAR_DECLs
> +        created via create_tmp_var set ssa_renaming_needed and the fold 
> passes
> +        do not set TODO_update_ssa, so execute_todo ICEs.  Aggregates cannot 
> be
> +        SSA names at all, but they do not set that flag either, so a
> +        declaration is both necessary and safe for them.  */
> +      if (is_gimple_reg_type (type))
> +       lhs = placeholder = make_ssa_name (type);
> +      else
> +       lhs = create_tmp_var (type);
> +    }
>
>    /* First try some simplifications that are common to many functions.  */
> -  if (auto *call = redirect_pred_x ())
> -    return call;
> -  if (auto *call = fold_pfalse ())
> -    return call;
> +  gimple *stmt = redirect_pred_x ();
> +  if (!stmt)
> +    stmt = fold_pfalse ();
> +  if (!stmt)
> +    stmt = base->fold (*this);
> +
> +  /* Release a placeholder that nothing defines and nothing uses, because
> +     gimple_build_assign does not set the definition until insertion and
> +     convert_and_fold returns a different statement from the one it inserts. 
>  */
> +  if (placeholder && (!stmt || gimple_get_lhs (stmt) != placeholder))
> +    {
> +      gimple *def = SSA_NAME_DEF_STMT (placeholder);
> +      if (has_zero_uses (placeholder) && (!def || gimple_nop_p (def)))
> +       release_ssa_name (placeholder);
> +    }
>
> -  return base->fold (*this);
> +  return stmt;
>  }
>
>  /* Force EXPR to be a GIMPLE value, putting it into a new variable if
> diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/pr127771.c 
> b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/pr127771.c
> new file mode 100644
> index 000000000000..0a024ca4954f
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/pr127771.c
> @@ -0,0 +1,21 @@
> +/* { dg-do compile } */
> +/* { dg-options "-O1" } */
> +
> +#include <arm_sve.h>
> +
> +/* PR target/127771  */
> +
> +void
> +g (svbool_t p, svuint32_t a)
> +{
> +  svmul_x (p, a, svdup_u32 (1));
> +}
> +
> +/* The placeholder for a discarded result cannot be an SSA name when the
> +   return type is an aggregate.  */
> +
> +void
> +h (svuint32_t a, svuint32_t b)
> +{
> +  svcreate2_u32 (a, b);
> +}
> --
> 2.43.0
>
diff --git a/gcc/config/aarch64/aarch64-acle-builtins.cc 
b/gcc/config/aarch64/aarch64-acle-builtins.cc
index 5abcc01b96b..d6b3b87786f 100644
--- a/gcc/config/aarch64/aarch64-acle-builtins.cc
+++ b/gcc/config/aarch64/aarch64-acle-builtins.cc
@@ -2803,7 +2803,8 @@ is_pfalse (tree v)
 gimple_folder::gimple_folder (const function_instance &instance, tree fndecl,
                              gimple_stmt_iterator *gsi_in, gcall *call_in)
   : function_call_info (gimple_location (call_in), instance, fndecl),
-    gsi (gsi_in), call (call_in), lhs (gimple_call_lhs (call_in))
+    gsi (gsi_in), call (call_in), lhs (gimple_call_lhs (call_in)),
+    lhs_type(TREE_TYPE (TREE_TYPE (fndecl)))
 {
 }
 
@@ -2910,7 +2911,6 @@ gimple_folder::redirect_pred_x ()
   if (gimple_call_num_args (call) < 2)
     return nullptr;
 
-  tree lhs_type = TREE_TYPE (TREE_TYPE (fndecl));
   tree arg0_type = type_argument_type (TREE_TYPE (fndecl), 1);
   tree arg1_type = type_argument_type (TREE_TYPE (fndecl), 2);
   if (!VECTOR_TYPE_P (lhs_type)
@@ -2953,15 +2953,15 @@ gimple_folder::fold_pfalse ()
       return nullptr;
     }
   if ((pred == PRED_x || pred == PRED_z) && is_pfalse (gp))
-    return fold_call_to (build_zero_cst (TREE_TYPE (lhs)));
+    return fold_call_to (build_zero_cst (lhs_type));
   if (pred == PRED_implicit && is_pfalse (gp))
     {
       unsigned int flags = call_properties ();
       /* Folding to lhs = {0, ...} is not appropriate for intrinsics with
         AGGREGATE types as lhs.  */
       if ((flags & CP_READ_MEMORY)
-         && !AGGREGATE_TYPE_P (TREE_TYPE (lhs)))
-       return fold_call_to (build_zero_cst (TREE_TYPE (lhs)));
+         && !AGGREGATE_TYPE_P (lhs_type))
+       return fold_call_to (build_zero_cst (lhs_type));
       if (flags & (CP_WRITE_MEMORY | CP_PREFETCH_MEMORY))
        return fold_to_stmt_vops (gimple_build_nop ());
     }
@@ -2980,10 +2980,10 @@ gimple_folder::convert_and_fold (tree type,
 {
   gcc_assert (VECTOR_TYPE_P (type)
              && TYPE_MODE (type) != VNx16BImode);
-  tree old_ty = TREE_TYPE (lhs);
+  tree old_ty = lhs_type;
   gimple_seq stmts = NULL;
   bool convert_lhs_p = !useless_type_conversion_p (type, old_ty);
-  tree lhs_conv = convert_lhs_p ? make_ssa_name (type) : lhs;
+  tree lhs_conv = convert_lhs_p || !lhs ? make_ssa_name (type) : lhs;
   unsigned int num_args = gimple_call_num_args (call);
   auto_vec<tree, 16> args_conv;
   args_conv.safe_grow (num_args);
@@ -3000,7 +3000,7 @@ gimple_folder::convert_and_fold (tree type,
 
   gimple *new_stmt = fp (*this, lhs_conv, args_conv);
   gsi_insert_seq_before (gsi, stmts, GSI_SAME_STMT);
-  if (convert_lhs_p)
+  if (convert_lhs_p && !lhs)
     {
       tree t = build1 (VIEW_CONVERT_EXPR, old_ty, lhs_conv);
       gimple *g = gimple_build_assign (lhs, VIEW_CONVERT_EXPR, t);
@@ -3013,14 +3013,18 @@ gimple_folder::convert_and_fold (tree type,
 gimple *
 gimple_folder::fold_to_cstu (poly_uint64 val)
 {
-  return gimple_build_assign (lhs, build_int_cstu (TREE_TYPE (lhs), val));
+  if (!lhs)
+    return gimple_build_nop ();
+  return gimple_build_assign (lhs, build_int_cstu (lhs_type, val));
 }
 
 /* Fold the call to a PTRUE, taking the element size from type suffix 0.  */
 gimple *
 gimple_folder::fold_to_ptrue ()
 {
-  tree svbool_type = TREE_TYPE (lhs);
+  if (!lhs)
+    return gimple_build_nop ();
+  tree svbool_type = lhs_type;
   tree bool_type = TREE_TYPE (svbool_type);
   unsigned int element_bytes = type_suffix (0).element_bytes;
 
@@ -3038,7 +3042,11 @@ gimple *
 gimple_folder::fold_to_pfalse ()
 {
   if (type_suffix (0).tclass == TYPE_bool)
-    return gimple_build_assign (lhs, build_zero_cst (TREE_TYPE (lhs)));
+    {
+      if (!lhs)
+        return gimple_build_nop ();
+      return gimple_build_assign (lhs, build_zero_cst (lhs_type));
+    }
 
   if (type_suffix (0).tclass == TYPE_count)
     {
@@ -3055,7 +3063,7 @@ gimple_folder::fold_to_pfalse ()
 gimple *
 gimple_folder::fold_to_vl_pred (unsigned int vl)
 {
-  tree vectype = TREE_TYPE (lhs);
+  tree vectype = lhs_type;
   unsigned int element_bytes = type_suffix (0).element_bytes;
   tree pred = aarch64_fold_sve_ptrue_vl (vectype, vl, element_bytes);
   return gimple_build_assign (lhs, pred);
@@ -3095,7 +3103,7 @@ gimple_folder::fold_active_lanes_to (tree x)
      vector from z).  */
   tree vec_inactive;
   if (pred == PRED_z)
-    vec_inactive = build_zero_cst (TREE_TYPE (lhs));
+    vec_inactive = build_zero_cst (lhs_type);
   else
     vec_inactive = gimple_call_arg (call, 1);
   if (operand_equal_p (x, vec_inactive, 0))
@@ -3103,7 +3111,7 @@ gimple_folder::fold_active_lanes_to (tree x)
 
   gimple_seq stmts = NULL;
   tree pred = convert_pred (stmts, vector_type (0), 0);
-  x = force_vector (stmts, TREE_TYPE (lhs), x);
+  x = force_vector (stmts, lhs_type, x);
   gsi_insert_seq_before (gsi, stmts, GSI_SAME_STMT);
   return gimple_build_assign (lhs, VEC_COND_EXPR, pred, x, vec_inactive);
 }
@@ -3112,10 +3120,12 @@ gimple_folder::fold_active_lanes_to (tree x)
 gimple *
 gimple_folder::fold_call_to (tree t)
 {
-  if (types_compatible_p (TREE_TYPE (lhs), TREE_TYPE (t)))
+  if (!lhs)
+    return gimple_build_nop ();
+  if (types_compatible_p (lhs_type, TREE_TYPE (t)))
     return fold_to_stmt_vops (gimple_build_assign (lhs, t));
 
-  tree rhs = build1 (VIEW_CONVERT_EXPR, TREE_TYPE (lhs), t);
+  tree rhs = build1 (VIEW_CONVERT_EXPR, lhs_type, t);
   return fold_to_stmt_vops (gimple_build_assign (lhs, VIEW_CONVERT_EXPR, rhs));
 }
 
@@ -3139,12 +3149,6 @@ gimple_folder::fold ()
   if (!TARGET_SIMD && !TARGET_SVE)
     return NULL;
 
-  /* Create a placeholder variable for the result.
-     This allows implementers of `fold` to assume `lhs` will never be null.
-     If the result is unused, it will be optimized away later.  */
-  if (!lhs && TREE_TYPE (gimple_call_fntype (call)) != void_type_node)
-    lhs = create_tmp_var (TREE_TYPE (gimple_call_fntype (call)));
-
   /* First try some simplifications that are common to many functions.  */
   if (auto *call = redirect_pred_x ())
     return call;
diff --git a/gcc/config/aarch64/aarch64-acle-builtins.h 
b/gcc/config/aarch64/aarch64-acle-builtins.h
index eb39bbdab88..36cd6b80bbe 100644
--- a/gcc/config/aarch64/aarch64-acle-builtins.h
+++ b/gcc/config/aarch64/aarch64-acle-builtins.h
@@ -683,6 +683,7 @@ public:
 
   /* The result of the call, or null if none.  */
   tree lhs;
+  tree lhs_type;
 };
 
 /* A class for expanding a function call into RTL.  */

Reply via email to