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. */