> -----Original Message-----
> From: Richard Biener <[email protected]>
> Sent: Friday, August 29, 2025 12:40 PM
> To: [email protected]
> Cc: RISC-V CI <[email protected]>; Tamar Christina
> <[email protected]>
> Subject: [PATCH 2/4] Separate reduction info and associate it with SLP nodes
>
> The following splits out reduction related information from
> stmt_vec_info, retaining (and duplicating) parts used by scalar
> cycle analysis. The data is then associated with SLP nodes
> forming reduction cycles and accessible via info_for_reduction.
> The data is created at SLP discovery time as we look at it even
> pre-vectorizable_reduction analysis, but most of the data is
> only populated by the latter. There is no reduction info with
> nested cycles that are not part of an outer reduction.
> In the process this adds cycle info to each SLP tree, notably
> the reduc-idx and a way to identify the reduction info.
>
> Cleanup possibilities will be realized in a later patch of the
> series. This patch is going to be squashed with the first.
This one breaks the aarch64 build
/opt/buildAgent/work/505bfdd4dad8af3d/gcc/config/aarch64/aarch64.cc: In
function 'bool aarch64_force_single_cycle(vec_info*, stmt_vec_info)':
/opt/buildAgent/work/505bfdd4dad8af3d/gcc/config/aarch64/aarch64.cc:17778:41:
error: invalid conversion from 'vec_info*' to 'loop_vec_info' {aka
'_loop_vec_info*'} [-fpermissive]
17778 | auto reduc_info = info_for_reduction (vinfo, stmt_info);
| ^~~~~
| |
| vec_info*
/opt/buildAgent/work/505bfdd4dad8af3d/gcc/config/aarch64/aarch64.cc:17778:48:
error: cannot convert 'stmt_vec_info' {aka '_stmt_vec_info*'} to 'slp_tree'
{aka '_slp_tree*'}
17778 | auto reduc_info = info_for_reduction (vinfo, stmt_info);
| ^~~~~~~~~
| |
| stmt_vec_info {aka
_stmt_vec_info*}
Since info_for_reduction no longer takes the stmt_info. If I'm reading this
right for AArch64 we'd need:
diff --git a/gcc/config/aarch64/aarch64.cc b/gcc/config/aarch64/aarch64.cc
index 1cdd5a26a83..2831ef38948 100644
--- a/gcc/config/aarch64/aarch64.cc
+++ b/gcc/config/aarch64/aarch64.cc
@@ -17770,12 +17770,13 @@ aarch64_adjust_stmt_cost (vec_info *vinfo,
vect_cost_for_stmt kind,
with the single accumulator being read and written multiple times. */
static bool
-aarch64_force_single_cycle (vec_info *vinfo, stmt_vec_info stmt_info)
+aarch64_force_single_cycle (vec_info *vinfo, slp_tree node)
{
+ stmt_vec_info stmt_info = SLP_TREE_REPRESENTATIVE (node);
if (!STMT_VINFO_REDUC_DEF (stmt_info))
return false;
- auto reduc_info = info_for_reduction (vinfo, stmt_info);
+ auto reduc_info = info_for_reduction (vinfo, node);
return VECT_REDUC_INFO_FORCE_SINGLE_CYCLE (reduc_info);
}
@@ -17803,7 +17804,7 @@ aarch64_vector_costs::count_ops (unsigned int count,
vect_cost_for_stmt kind,
= aarch64_in_loop_reduction_latency (m_vinfo, node,
stmt_info, m_vec_flags);
if (m_costing_for_scalar
- || aarch64_force_single_cycle (m_vinfo, stmt_info))
+ || aarch64_force_single_cycle (m_vinfo, node))
/* ??? Ideally we'd use a tree to reduce the copies down to 1 vector,
and then accumulate that, but at the moment the loop-carried
dependency includes all copies. */
Should I try again with this change?
Thanks,
Tamar
>
> Bootstrapped and tested on x86_64-unknown-linux-gnu.
>
> * tree-vectorizer.h (_slp_tree::cycle_info): New member.
> (SLP_TREE_REDUC_IDX): Likewise.
> (vect_reduc_info_s): Move/copy data from ...
> (_stmt_vec_info): ... here.
> (_loop_vec_info::redcu_infos): New member.
> (info_for_reduction): Adjust to take SLP node.
> (vect_reduc_type): Adjust.
> (vect_is_reduction): Add overload for SLP node.
> * tree-vectorizer.cc (vec_info::new_stmt_vec_info):
> Do not initialize removed members.
> (vec_info::free_stmt_vec_info): Do not release them.
> * tree-vect-stmts.cc (vectorizable_condition): Adjust.
> * tree-vect-slp.cc (_slp_tree::_slp_tree): Initialize
> cycle info.
> (vect_build_slp_tree_2): Compute SLP reduc_idx and store
> it. Create, populate and propagate reduction info.
> (vect_print_slp_tree): Print cycle info.
> (vect_analyze_slp_reduc_chain): Set cycle info on the
> manual added conversion node.
> (vect_optimize_slp_pass::start_choosing_layouts): Adjust.
> * tree-vect-loop.cc (_loop_vec_info::~_loop_vec_info):
> Release reduction infos.
> (info_for_reduction): Get the reduction info from
> the vector in the loop_vinfo.
> (vect_create_epilog_for_reduction): Adjust.
> (vectorizable_reduction): Likewise.
> (vect_transform_reduction): Likewise.
> (vect_transform_cycle_phi): Likewise, deal with nested
> cycles not part of a double reduction have no reduction info.
> ---
> gcc/tree-vect-loop.cc | 82 +++++++---------------
> gcc/tree-vect-slp.cc | 79 +++++++++++++++++++--
> gcc/tree-vect-stmts.cc | 3 +-
> gcc/tree-vectorizer.cc | 12 ----
> gcc/tree-vectorizer.h | 154 +++++++++++++++++++++++------------------
> 5 files changed, 190 insertions(+), 140 deletions(-)
>
> diff --git a/gcc/tree-vect-loop.cc b/gcc/tree-vect-loop.cc
> index a0e77bdced6..db63891955b 100644
> --- a/gcc/tree-vect-loop.cc
> +++ b/gcc/tree-vect-loop.cc
> @@ -955,6 +955,8 @@ _loop_vec_info::~_loop_vec_info ()
> delete scan_map;
> delete scalar_costs;
> delete vector_costs;
> + for (auto reduc_info : reduc_infos)
> + delete reduc_info;
>
> /* When we release an epiloge vinfo that we do not intend to use
> avoid clearing AUX of the main loop which should continue to
> @@ -5135,46 +5137,12 @@ get_initial_defs_for_reduction (loop_vec_info
> loop_vinfo,
> vect_emit_reduction_init_stmts (loop_vinfo, reduc_info, ctor_seq);
> }
>
> -/* For a statement STMT_INFO taking part in a reduction operation return
> - the stmt_vec_info the meta information is stored on. */
> -
> -static vect_reduc_info
> -info_for_reduction (vec_info *vinfo, stmt_vec_info stmt_info, bool create)
> -{
> - stmt_info = vect_orig_stmt (stmt_info);
> - gcc_assert (STMT_VINFO_REDUC_DEF (stmt_info));
> - if (!is_a <gphi *> (stmt_info->stmt)
> - || !VECTORIZABLE_CYCLE_DEF (STMT_VINFO_DEF_TYPE (stmt_info)))
> - stmt_info = STMT_VINFO_REDUC_DEF (stmt_info);
> - gphi *phi = as_a <gphi *> (stmt_info->stmt);
> - if (STMT_VINFO_DEF_TYPE (stmt_info) == vect_double_reduction_def)
> - {
> - if (gimple_phi_num_args (phi) == 1)
> - stmt_info = STMT_VINFO_REDUC_DEF (stmt_info);
> - }
> - else if (STMT_VINFO_DEF_TYPE (stmt_info) == vect_nested_cycle)
> - {
> - stmt_vec_info info = vinfo->lookup_def (vect_phi_initial_value (phi));
> - if (info && STMT_VINFO_DEF_TYPE (info) == vect_double_reduction_def)
> - stmt_info = info;
> - }
> - if (create)
> - stmt_info->is_reduc_info = true;
> - else
> - gcc_assert (stmt_info->is_reduc_info);
> - return vect_reduc_info (stmt_info);
> -}
> -
> -vect_reduc_info
> -info_for_reduction (vec_info *vinfo, stmt_vec_info stmt_info)
> -{
> - return info_for_reduction (vinfo, stmt_info, false);
> -}
> -
> vect_reduc_info
> -create_info_for_reduction (vec_info *vinfo, stmt_vec_info stmt_info)
> +info_for_reduction (loop_vec_info loop_vinfo, slp_tree node)
> {
> - return info_for_reduction (vinfo, stmt_info, true);
> + if (node->cycle_info.id == -1)
> + return NULL;
> + return loop_vinfo->reduc_infos[node->cycle_info.id];
> }
>
> /* See if LOOP_VINFO is an epilogue loop whose main loop had a reduction that
> @@ -5434,7 +5402,7 @@ vect_create_epilog_for_reduction (loop_vec_info
> loop_vinfo,
> slp_instance slp_node_instance,
> edge loop_exit)
> {
> - vect_reduc_info reduc_info = info_for_reduction (loop_vinfo, stmt_info);
> + vect_reduc_info reduc_info = info_for_reduction (loop_vinfo, slp_node);
> /* For double reductions we need to get at the inner loop reduction
> stmt which has the meta info attached. Our stmt_info is that of the
> loop-closed PHI of the inner loop which we remember as
> @@ -6920,7 +6888,7 @@ vectorizable_lane_reducing (loop_vec_info loop_vinfo,
> stmt_vec_info stmt_info,
> || STMT_VINFO_REDUC_IDX (stmt_info) < 0)
> return false;
>
> - vect_reduc_info reduc_info = info_for_reduction (loop_vinfo, stmt_info);
> + vect_reduc_info reduc_info = info_for_reduction (loop_vinfo, slp_node);
>
> /* Lane-reducing pattern inside any inner loop of LOOP_VINFO is not
> recoginized. */
> @@ -7083,8 +7051,8 @@ vectorizable_reduction (loop_vec_info loop_vinfo,
> && STMT_VINFO_DEF_TYPE (stmt_info) != vect_nested_cycle)
> return false;
>
> - /* The stmt we store reduction analysis meta on. */
> - vect_reduc_info reduc_info = create_info_for_reduction (loop_vinfo,
> stmt_info);
> + /* The reduction meta. */
> + vect_reduc_info reduc_info = info_for_reduction (loop_vinfo, slp_node);
>
> if (STMT_VINFO_DEF_TYPE (stmt_info) == vect_nested_cycle)
> {
> @@ -7160,7 +7128,7 @@ vectorizable_reduction (loop_vec_info loop_vinfo,
> slp_tree vdef_slp = slp_node_instance->root;
> /* For double-reductions we start SLP analysis at the inner loop LC PHI
> which is the def of the outer loop live stmt. */
> - if (STMT_VINFO_DEF_TYPE (reduc_info.fixme ()) == vect_double_reduction_def)
> + if (VECT_REDUC_INFO_DEF_TYPE (reduc_info) == vect_double_reduction_def)
> vdef_slp = SLP_TREE_CHILDREN (vdef_slp)[0];
> while (reduc_def != PHI_RESULT (reduc_def_phi))
> {
> @@ -7399,8 +7367,7 @@ vectorizable_reduction (loop_vec_info loop_vinfo,
> }
> }
>
> - enum vect_reduction_type reduction_type = STMT_VINFO_REDUC_TYPE
> (phi_info);
> - VECT_REDUC_INFO_TYPE (reduc_info) = reduction_type;
> + enum vect_reduction_type reduction_type = VECT_REDUC_INFO_TYPE
> (reduc_info);
> /* If we have a condition reduction, see if we can simplify it further. */
> if (reduction_type == COND_REDUCTION)
> {
> @@ -7514,7 +7481,7 @@ vectorizable_reduction (loop_vec_info loop_vinfo,
>
> if (nested_cycle)
> {
> - gcc_assert (STMT_VINFO_DEF_TYPE (reduc_info.fixme ())
> + gcc_assert (VECT_REDUC_INFO_DEF_TYPE (reduc_info)
> == vect_double_reduction_def);
> double_reduc = true;
> }
> @@ -7554,7 +7521,7 @@ vectorizable_reduction (loop_vec_info loop_vinfo,
> (and also the same tree-code) when generating the epilog code and
> when generating the code inside the loop. */
>
> - code_helper orig_code = STMT_VINFO_REDUC_CODE (phi_info);
> + code_helper orig_code = VECT_REDUC_INFO_CODE (reduc_info);
>
> /* If conversion might have created a conditional operation like
> IFN_COND_ADD already. Use the internal code for the following checks.
> */
> @@ -8031,12 +7998,13 @@ vect_transform_reduction (loop_vec_info
> loop_vinfo,
> class loop *loop = LOOP_VINFO_LOOP (loop_vinfo);
> unsigned vec_num;
>
> - vect_reduc_info reduc_info = info_for_reduction (loop_vinfo, stmt_info);
> + vect_reduc_info reduc_info = info_for_reduction (loop_vinfo, slp_node);
>
> if (nested_in_vect_loop_p (loop, stmt_info))
> {
> loop = loop->inner;
> - gcc_assert (STMT_VINFO_DEF_TYPE (reduc_info.fixme ()) ==
> vect_double_reduction_def);
> + gcc_assert (VECT_REDUC_INFO_DEF_TYPE (reduc_info)
> + == vect_double_reduction_def);
> }
>
> gimple_match_op op;
> @@ -8382,10 +8350,10 @@ vect_transform_cycle_phi (loop_vec_info
> loop_vinfo,
> nested_cycle = true;
> }
>
> - vect_reduc_info reduc_info = info_for_reduction (loop_vinfo, stmt_info);
> -
> - if (VECT_REDUC_INFO_TYPE (reduc_info) == EXTRACT_LAST_REDUCTION
> - || VECT_REDUC_INFO_TYPE (reduc_info) == FOLD_LEFT_REDUCTION)
> + vect_reduc_info reduc_info = info_for_reduction (loop_vinfo, slp_node);
> + if (reduc_info
> + && (VECT_REDUC_INFO_TYPE (reduc_info) == EXTRACT_LAST_REDUCTION
> + || VECT_REDUC_INFO_TYPE (reduc_info) == FOLD_LEFT_REDUCTION))
> /* Leave the scalar phi in place. */
> return true;
>
> @@ -8393,7 +8361,7 @@ vect_transform_cycle_phi (loop_vec_info loop_vinfo,
>
> /* Check whether we should use a single PHI node and accumulate
> vectors to one before the backedge. */
> - if (VECT_REDUC_INFO_FORCE_SINGLE_CYCLE (reduc_info))
> + if (reduc_info && VECT_REDUC_INFO_FORCE_SINGLE_CYCLE (reduc_info))
> vec_num = 1;
>
> /* Create the destination vector */
> @@ -8408,7 +8376,8 @@ vect_transform_cycle_phi (loop_vec_info loop_vinfo,
> /* Optimize: if initial_def is for REDUC_MAX smaller than the base
> and we can't use zero for induc_val, use initial_def. Similarly
> for REDUC_MIN and initial_def larger than the base. */
> - if (VECT_REDUC_INFO_TYPE (reduc_info) ==
> INTEGER_INDUC_COND_REDUCTION)
> + if (reduc_info
> + && VECT_REDUC_INFO_TYPE (reduc_info) ==
> INTEGER_INDUC_COND_REDUCTION)
> {
> gcc_assert (SLP_TREE_LANES (slp_node) == 1);
> tree initial_def = vect_phi_initial_value (phi);
> @@ -8486,6 +8455,7 @@ vect_transform_cycle_phi (loop_vec_info loop_vinfo,
> vec_initial_defs.quick_push (vec_initial_def);
> }
>
> + if (reduc_info)
> if (auto *accumulator = VECT_REDUC_INFO_REUSED_ACCUMULATOR
> (reduc_info))
> {
> tree def = accumulator->reduc_input;
> @@ -10280,7 +10250,7 @@ vectorizable_live_operation (vec_info *vinfo,
> stmt_vec_info stmt_info,
> if (SLP_INSTANCE_KIND (slp_node_instance) == slp_inst_kind_reduc_group
> && slp_index != 0)
> return true;
> - vect_reduc_info reduc_info = info_for_reduction (loop_vinfo,
> stmt_info);
> + vect_reduc_info reduc_info = info_for_reduction (loop_vinfo, slp_node);
> if (VECT_REDUC_INFO_TYPE (reduc_info) == FOLD_LEFT_REDUCTION
> || VECT_REDUC_INFO_TYPE (reduc_info) ==
> EXTRACT_LAST_REDUCTION)
> return true;
> diff --git a/gcc/tree-vect-slp.cc b/gcc/tree-vect-slp.cc
> index 733f4ece724..5236eac5a42 100644
> --- a/gcc/tree-vect-slp.cc
> +++ b/gcc/tree-vect-slp.cc
> @@ -126,6 +126,8 @@ _slp_tree::_slp_tree ()
> this->avoid_stlf_fail = false;
> SLP_TREE_VECTYPE (this) = NULL_TREE;
> SLP_TREE_REPRESENTATIVE (this) = NULL;
> + this->cycle_info.id = -1;
> + this->cycle_info.reduc_idx = -1;
> SLP_TREE_REF_COUNT (this) = 1;
> this->failed = NULL;
> this->max_nunits = 1;
> @@ -2735,6 +2737,7 @@ out:
>
> stmt_info = stmts[0];
>
> + int reduc_idx = -1;
> int gs_scale = 0;
> tree gs_base = NULL_TREE;
>
> @@ -2826,6 +2829,33 @@ out:
> continue;
> }
>
> + /* See which SLP operand a reduction chain continues on. We want
> + to chain even PHIs but not backedges. */
> + if (VECTORIZABLE_CYCLE_DEF (oprnd_info->first_dt)
> + || STMT_VINFO_REDUC_IDX (oprnd_info->def_stmts[0]) != -1)
> + {
> + if (STMT_VINFO_DEF_TYPE (stmt_info) == vect_nested_cycle)
> + {
> + if (oprnd_info->first_dt == vect_double_reduction_def)
> + reduc_idx = i;
> + }
> + else if (is_a <gphi *> (stmt_info->stmt)
> + && gimple_phi_num_args
> + (as_a <gphi *> (stmt_info->stmt)) != 1)
> + ;
> + else if (STMT_VINFO_REDUC_IDX (stmt_info) == -1
> + && STMT_VINFO_DEF_TYPE (stmt_info) !=
> vect_double_reduction_def)
> + ;
> + else if (reduc_idx == -1)
> + reduc_idx = i;
> + else
> + /* For .COND_* reduction operations the else value can be the
> + same as one of the operation operands. The other def
> + stmts have been moved, so we can't check easily. Check
> + it's a call at least. */
> + gcc_assert (is_a <gcall *> (stmt_info->stmt));
> + }
> +
> /* When we have a masked load with uniform mask discover this
> as a single-lane mask with a splat permute. This way we can
> recognize this as a masked load-lane by stripping the splat. */
> @@ -3157,6 +3187,41 @@ fail:
> SLP_TREE_CHILDREN (node).splice (children);
> SLP_TREE_GS_SCALE (node) = gs_scale;
> SLP_TREE_GS_BASE (node) = gs_base;
> + if (reduc_idx != -1)
> + {
> + gcc_assert (STMT_VINFO_REDUC_IDX (stmt_info) != -1
> + || STMT_VINFO_DEF_TYPE (stmt_info) == vect_nested_cycle
> + || STMT_VINFO_DEF_TYPE (stmt_info) ==
> vect_double_reduction_def);
> + SLP_TREE_REDUC_IDX (node) = reduc_idx;
> + node->cycle_info.id = SLP_TREE_CHILDREN
> (node)[reduc_idx]->cycle_info.id;
> + }
> + /* When reaching the reduction PHI, create a vect_reduc_info. */
> + else if ((STMT_VINFO_DEF_TYPE (stmt_info) == vect_reduction_def
> + || STMT_VINFO_DEF_TYPE (stmt_info) == vect_double_reduction_def)
> + && is_a <gphi *> (STMT_VINFO_STMT (stmt_info)))
> + {
> + loop_vec_info loop_vinfo = as_a <loop_vec_info> (vinfo);
> + gcc_assert (STMT_VINFO_REDUC_IDX (stmt_info) == -1);
> + node->cycle_info.id = loop_vinfo->reduc_infos.length ();
> + vect_reduc_info reduc_info = new vect_reduc_info_s ();
> + loop_vinfo->reduc_infos.safe_push (reduc_info);
> + stmt_vec_info reduc_phi = stmt_info;
> + /* ??? For double reductions vect_is_simple_reduction stores the
> + reduction type and code on the inner loop header PHI. */
> + if (STMT_VINFO_DEF_TYPE (stmt_info) == vect_double_reduction_def)
> + {
> + use_operand_p use_p;
> + gimple *use_stmt;
> + bool res = single_imm_use (gimple_phi_result (stmt_info->stmt),
> + &use_p, &use_stmt);
> + gcc_assert (res);
> + reduc_phi = loop_vinfo->lookup_stmt (use_stmt);
> + }
> + VECT_REDUC_INFO_DEF_TYPE (reduc_info) = STMT_VINFO_DEF_TYPE
> (stmt_info);
> + VECT_REDUC_INFO_TYPE (reduc_info) = STMT_VINFO_REDUC_TYPE
> (reduc_phi);
> + VECT_REDUC_INFO_CODE (reduc_info) = STMT_VINFO_REDUC_CODE
> (reduc_phi);
> + VECT_REDUC_INFO_FN (reduc_info) = IFN_LAST;
> + }
> return node;
> }
>
> @@ -3185,8 +3250,12 @@ vect_print_slp_tree (dump_flags_t dump_kind,
> dump_location_t loc,
> SLP_TREE_REF_COUNT (node));
> if (SLP_TREE_VECTYPE (node))
> dump_printf (metadata, " %T", SLP_TREE_VECTYPE (node));
> - dump_printf (metadata, "%s\n",
> + dump_printf (metadata, "%s",
> node->avoid_stlf_fail ? " (avoid-stlf-fail)" : "");
> + if (node->cycle_info.id != -1 || node->cycle_info.reduc_idx != -1)
> + dump_printf (metadata, " cycle %d, link %d", node->cycle_info.id,
> + node->cycle_info.reduc_idx);
> + dump_printf (metadata, "\n");
> if (SLP_TREE_DEF_TYPE (node) == vect_internal_def)
> {
> if (SLP_TREE_PERMUTE_P (node))
> @@ -4241,6 +4310,8 @@ vect_analyze_slp_reduc_chain (vec_info *vinfo,
> TREE_TYPE
> (gimple_assign_lhs (scalar_def)),
> group_size);
> + SLP_TREE_REDUC_IDX (conv) = 0;
> + conv->cycle_info.id = node->cycle_info.id;
> SLP_TREE_CHILDREN (conv).quick_push (node);
> SLP_INSTANCE_TREE (new_instance) = conv;
> /* We also have to fake this conversion stmt as SLP reduction
> @@ -6719,11 +6790,9 @@ vect_optimize_slp_pass::start_choosing_layouts ()
> {
> stmt_vec_info stmt_info
> = SLP_TREE_REPRESENTATIVE (SLP_INSTANCE_TREE (instance));
> - /* ??? vectorizable_reduction did not run yet, scalar cycle
> - detection sets reduc_code. Either that or SLP discovery
> - should create a reduction info. */
> vect_reduc_info reduc_info
> - = create_info_for_reduction (m_vinfo, stmt_info);
> + = info_for_reduction (as_a <loop_vec_info> (m_vinfo),
> + SLP_INSTANCE_TREE (instance));
> if (needs_fold_left_reduction_p (TREE_TYPE
> (gimple_get_lhs (stmt_info->stmt)),
> VECT_REDUC_INFO_CODE (reduc_info)))
> diff --git a/gcc/tree-vect-stmts.cc b/gcc/tree-vect-stmts.cc
> index 2248b361e1c..77a03ed4a7b 100644
> --- a/gcc/tree-vect-stmts.cc
> +++ b/gcc/tree-vect-stmts.cc
> @@ -11572,7 +11572,8 @@ vectorizable_condition (vec_info *vinfo,
> every stmt, use the conservative default setting then. */
> if (STMT_VINFO_REDUC_DEF (vect_orig_stmt (stmt_info)))
> {
> - vect_reduc_info reduc_info = info_for_reduction (vinfo, stmt_info);
> + vect_reduc_info reduc_info
> + = info_for_reduction (loop_vinfo, slp_node);
> reduction_type = VECT_REDUC_INFO_TYPE (reduc_info);
> nested_cycle_p = nested_in_vect_loop_p (LOOP_VINFO_LOOP
> (loop_vinfo),
> stmt_info);
> diff --git a/gcc/tree-vectorizer.cc b/gcc/tree-vectorizer.cc
> index 726383f487c..d7dc30bbeac 100644
> --- a/gcc/tree-vectorizer.cc
> +++ b/gcc/tree-vectorizer.cc
> @@ -724,16 +724,6 @@ vec_info::new_stmt_vec_info (gimple *stmt)
> STMT_VINFO_SLP_VECT_ONLY (res) = false;
> STMT_VINFO_SLP_VECT_ONLY_PATTERN (res) = false;
>
> - /* To be moved. */
> - res->reduc_epilogue_adjustment = NULL_TREE;
> - res->force_single_cycle = false;
> - res->reduc_fn = IFN_LAST;
> - res->reduc_initial_values = vNULL;
> - res->reduc_scalar_results = vNULL;
> - res->reduc_vectype = NULL_TREE;
> - res->induc_cond_initial_val = NULL_TREE;
> - res->reused_accumulator = NULL;
> -
> if (is_a <loop_vec_info> (this)
> && gimple_code (stmt) == GIMPLE_PHI
> && is_loop_header_bb_p (gimple_bb (stmt)))
> @@ -794,8 +784,6 @@ vec_info::free_stmt_vec_info (stmt_vec_info stmt_info)
> release_ssa_name (lhs);
> }
>
> - stmt_info->reduc_initial_values.release ();
> - stmt_info->reduc_scalar_results.release ();
> free (stmt_info);
> }
>
> diff --git a/gcc/tree-vectorizer.h b/gcc/tree-vectorizer.h
> index 90d862f2987..260cb2ddd3e 100644
> --- a/gcc/tree-vectorizer.h
> +++ b/gcc/tree-vectorizer.h
> @@ -310,6 +310,13 @@ struct _slp_tree {
> code generation. */
> stmt_vec_info representative;
>
> + struct {
> + /* SLP cycle the node resides in, or -1. */
> + int id;
> + /* The SLP operand index with the edge on the SLP cycle, or -1. */
> + int reduc_idx;
> + } cycle_info;
> +
> /* Load permutation relative to the stores, NULL if there is no
> permutation. */
> load_permutation_t load_permutation;
> @@ -446,6 +453,7 @@ public:
> #define SLP_TREE_TYPE(S) (S)->type
> #define SLP_TREE_GS_SCALE(S) (S)->gs_scale
> #define SLP_TREE_GS_BASE(S) (S)->gs_base
> +#define SLP_TREE_REDUC_IDX(S)
> (S)->cycle_info.reduc_idx
> #define SLP_TREE_PERMUTE_P(S) ((S)->code ==
> VEC_PERM_EXPR)
>
> inline vect_memory_access_type
> @@ -816,26 +824,70 @@ typedef auto_vec<std::pair<data_reference*, tree> >
> drs_init_vec;
>
> /* Abstraction around info on reductions which is still in stmt_vec_info
> but will be duplicated or moved elsewhere. */
> -class vect_reduc_info
> +class vect_reduc_info_s
> {
> public:
> - explicit vect_reduc_info (stmt_vec_info s) : i (s) {}
> - stmt_vec_info fixme () const { return i; }
> -private:
> - stmt_vec_info i;
> + /* The def type of the main reduction PHI, vect_reduction_def or
> + vect_double_reduction_def. */
> + enum vect_def_type def_type;
> +
> + /* The reduction type as detected by
> + vect_is_simple_reduction and vectorizable_reduction. */
> + enum vect_reduction_type reduc_type;
> +
> + /* The original scalar reduction code, to be used in the epilogue. */
> + code_helper reduc_code;
> +
> + /* A vector internal function we should use in the epilogue. */
> + internal_fn reduc_fn;
> +
> + /* For loop reduction with multiple vectorized results (ncopies > 1), a
> + lane-reducing operation participating in it may not use all of those
> + results, this field specifies result index starting from which any
> + following land-reducing operation would be assigned to. */
> + unsigned int reduc_result_pos;
> +
> + /* Whether we force a single cycle PHI during reduction vectorization. */
> + bool force_single_cycle;
> +
> + /* The vector type for performing the actual reduction operation. */
> + tree reduc_vectype;
> +
> + /* For INTEGER_INDUC_COND_REDUCTION, the initial value to be used. */
> + tree induc_cond_initial_val;
> +
> + /* If not NULL the value to be added to compute final reduction value. */
> + tree reduc_epilogue_adjustment;
> +
> + /* If non-null, the reduction is being performed by an epilogue loop
> + and we have decided to reuse this accumulator from the main loop. */
> + struct vect_reusable_accumulator *reused_accumulator;
> +
> + /* If the vector code is performing N scalar reductions in parallel,
> + this variable gives the initial scalar values of those N reductions. */
> + auto_vec<tree> reduc_initial_values;
> +
> + /* If the vector code is performing N scalar reductions in parallel, this
> + variable gives the vectorized code's final (scalar) result for each of
> + those N reductions. In other words, REDUC_SCALAR_RESULTS[I] replaces
> + the original scalar code's loop-closed SSA PHI for reduction number I.
> */
> + auto_vec<tree> reduc_scalar_results;
> };
>
> -#define VECT_REDUC_INFO_TYPE(I) ((I).fixme ()->reduc_type)
> -#define VECT_REDUC_INFO_CODE(I) ((I).fixme ()->reduc_code)
> -#define VECT_REDUC_INFO_FN(I) ((I).fixme ()->reduc_fn)
> -#define VECT_REDUC_INFO_SCALAR_RESULTS(I) ((I).fixme ()-
> >reduc_scalar_results)
> -#define VECT_REDUC_INFO_INITIAL_VALUES(I) ((I).fixme
> ()->reduc_initial_values)
> -#define VECT_REDUC_INFO_REUSED_ACCUMULATOR(I) ((I).fixme ()-
> >reused_accumulator)
> -#define VECT_REDUC_INFO_INDUC_COND_INITIAL_VAL(I) ((I).fixme ()-
> >induc_cond_initial_val)
> -#define VECT_REDUC_INFO_EPILOGUE_ADJUSTMENT(I) ((I).fixme ()-
> >reduc_epilogue_adjustment)
> -#define VECT_REDUC_INFO_VECTYPE(I) ((I).fixme ()->reduc_vectype)
> -#define VECT_REDUC_INFO_FORCE_SINGLE_CYCLE(I) ((I).fixme ()-
> >force_single_cycle)
> -#define VECT_REDUC_INFO_RESULT_POS(I) ((I).fixme ()->reduc_result_pos)
> +typedef class vect_reduc_info_s *vect_reduc_info;
> +
> +#define VECT_REDUC_INFO_DEF_TYPE(I) ((I)->def_type)
> +#define VECT_REDUC_INFO_TYPE(I) ((I)->reduc_type)
> +#define VECT_REDUC_INFO_CODE(I) ((I)->reduc_code)
> +#define VECT_REDUC_INFO_FN(I) ((I)->reduc_fn)
> +#define VECT_REDUC_INFO_SCALAR_RESULTS(I) ((I)->reduc_scalar_results)
> +#define VECT_REDUC_INFO_INITIAL_VALUES(I) ((I)->reduc_initial_values)
> +#define VECT_REDUC_INFO_REUSED_ACCUMULATOR(I) ((I)-
> >reused_accumulator)
> +#define VECT_REDUC_INFO_INDUC_COND_INITIAL_VAL(I) ((I)-
> >induc_cond_initial_val)
> +#define VECT_REDUC_INFO_EPILOGUE_ADJUSTMENT(I) ((I)-
> >reduc_epilogue_adjustment)
> +#define VECT_REDUC_INFO_VECTYPE(I) ((I)->reduc_vectype)
> +#define VECT_REDUC_INFO_FORCE_SINGLE_CYCLE(I) ((I)->force_single_cycle)
> +#define VECT_REDUC_INFO_RESULT_POS(I) ((I)->reduc_result_pos)
>
> /* Information about a reduction accumulator from the main loop that could
> conceivably be reused as the input to a reduction in an epilogue loop. */
> @@ -902,6 +954,10 @@ public:
> the main loop, this edge is the one that skips the epilogue. */
> edge skip_this_loop_edge;
>
> + /* Reduction descriptors of this loop. Referenced to from SLP nodes
> + by index. */
> + auto_vec<vect_reduc_info> reduc_infos;
> +
> /* The vectorized form of a standard reduction replaces the original
> scalar code's final result (a loop-closed SSA PHI) with the result
> of a vector-to-scalar reduction operation. After vectorization,
> @@ -1517,62 +1573,22 @@ public:
> /* For both loads and stores. */
> unsigned simd_lane_access_p : 3;
>
> - /* For INTEGER_INDUC_COND_REDUCTION, the initial value to be used. */
> - tree induc_cond_initial_val;
> -
> - /* If not NULL the value to be added to compute final reduction value. */
> - tree reduc_epilogue_adjustment;
> -
> /* On a reduction PHI the reduction type as detected by
> - vect_is_simple_reduction and vectorizable_reduction. */
> + vect_is_simple_reduction. */
> enum vect_reduction_type reduc_type;
>
> - /* The original reduction code, to be used in the epilogue. */
> + /* On a reduction PHI, the original reduction code as detected by
> + vect_is_simple_reduction. */
> code_helper reduc_code;
> - /* An internal function we should use in the epilogue. */
> - internal_fn reduc_fn;
>
> - /* On a stmt participating in the reduction the index of the operand
> + /* On a stmt participating in a reduction the index of the operand
> on the reduction SSA cycle. */
> int reduc_idx;
>
> - /* On a reduction PHI the def returned by vect_force_simple_reduction.
> - On the def returned by vect_force_simple_reduction the
> - corresponding PHI. */
> + /* On a reduction PHI the def returned by vect_is_simple_reduction.
> + On the def returned by vect_is_simple_reduction the corresponding PHI.
> */
> stmt_vec_info reduc_def;
>
> - /* The vector type for performing the actual reduction. */
> - tree reduc_vectype;
> -
> - /* For loop reduction with multiple vectorized results (ncopies > 1), a
> - lane-reducing operation participating in it may not use all of those
> - results, this field specifies result index starting from which any
> - following land-reducing operation would be assigned to. */
> - unsigned int reduc_result_pos;
> -
> - /* If IS_REDUC_INFO is true and if the vector code is performing
> - N scalar reductions in parallel, this variable gives the initial
> - scalar values of those N reductions. */
> - vec<tree> reduc_initial_values;
> -
> - /* If IS_REDUC_INFO is true and if the vector code is performing
> - N scalar reductions in parallel, this variable gives the vectorized
> code's
> - final (scalar) result for each of those N reductions. In other words,
> - REDUC_SCALAR_RESULTS[I] replaces the original scalar code's loop-closed
> - SSA PHI for reduction number I. */
> - vec<tree> reduc_scalar_results;
> -
> - /* Only meaningful if IS_REDUC_INFO. If non-null, the reduction is
> - being performed by an epilogue loop and we have decided to reuse
> - this accumulator from the main loop. */
> - vect_reusable_accumulator *reused_accumulator;
> -
> - /* Whether we force a single cycle PHI during reduction vectorization. */
> - bool force_single_cycle;
> -
> - /* Whether on this stmt reduction meta is recorded. */
> - bool is_reduc_info;
> -
> /* If nonzero, the lhs of the statement could be truncated to this
> many bits without affecting any users of the result. */
> unsigned int min_output_precision;
> @@ -2674,8 +2690,7 @@ extern tree vect_gen_loop_len_mask (loop_vec_info,
> gimple_stmt_iterator *,
> unsigned int, tree, tree, unsigned int,
> unsigned int);
> extern gimple_seq vect_gen_len (tree, tree, tree, tree);
> -extern vect_reduc_info info_for_reduction (vec_info *, stmt_vec_info);
> -extern vect_reduc_info create_info_for_reduction (vec_info *, stmt_vec_info);
> +extern vect_reduc_info info_for_reduction (loop_vec_info, slp_tree);
> extern bool reduction_fn_for_scalar_code (code_helper, internal_fn *);
>
> /* Drive for loop transformation stage. */
> @@ -2891,7 +2906,14 @@ vect_is_store_elt_extraction (vect_cost_for_stmt
> kind, stmt_vec_info stmt_info)
> inline bool
> vect_is_reduction (stmt_vec_info stmt_info)
> {
> - return STMT_VINFO_REDUC_IDX (stmt_info) >= 0;
> + return STMT_VINFO_REDUC_IDX (stmt_info) != -1;
> +}
> +
> +/* Return true if SLP_NODE represents part of a reduction. */
> +inline bool
> +vect_is_reduction (slp_tree slp_node)
> +{
> + return SLP_TREE_REDUC_IDX (slp_node) != -1;
> }
>
> /* If STMT_INFO describes a reduction, return the vect_reduction_type
> @@ -2905,7 +2927,7 @@ vect_reduc_type (vec_info *vinfo, slp_tree node)
> if (STMT_VINFO_REDUC_DEF (stmt_info))
> {
> vect_reduc_info reduc_info
> - = info_for_reduction (loop_vinfo, stmt_info);
> + = info_for_reduction (loop_vinfo, node);
> return int (VECT_REDUC_INFO_TYPE (reduc_info));
> }
> }
> --
> 2.43.0