On Mon, Dec 2, 2024 at 1:55 AM Lewis Hyatt <lhy...@gmail.com> wrote: > > This patch is my new way to handle what was previously done in v2 patch > 04/14, discussed at: > https://gcc.gnu.org/pipermail/gcc-patches/2024-November/669527.html > > The only places I have found running into trouble with reallocated PHI nodes > (at least, the only places revealed by changing the size of location_t) are > those which remember a gphi object before a call to loop_version() and then > try to use it after. I fixed three affected call sites in this new patch.
I guess it might be nice to avoid PHI node re-allocation by loop_version(), I remember fixing up other CFG manipulations to avoid the need for intermittent more PHI arguments. Anway, the patch is OK besides one minor adjustment, see below ... > -- >8 -- > > While testing upcoming support for 64-bit location_t, I came across some > test failures on sparc (32-bit) that trigger when location_t is changed to > be 64-bit. The reason is that several call sites that make use of > loop_version() for performing loop optimizations assume that a gphi* > obtained prior to calling loop_version() will remain valid afterwards, but > this is not the case for a PHI that needs to be resized. It doesn't happen > usually, because PHI nodes usually have room for at least 4 arguments and > this is usually more than are needed, but this is not guaranteed. > > Fix the affected callers by avoiding the assumption that a PHI node pointer > remains valid. For most cases, this is done by remembering instead the > gphi->result pointer, which contains a pointer back to the PHI node that is > kept up to date when the PHI is moved to a new address. > > gcc/ChangeLog: > > * tree-parloops.cc (struct reduction_info): Store the result of the > reduction PHI rather than the PHI itself. > (reduction_info::reduc_phi): New member function. > (reduction_hasher::equal): Adapt to the change in struct > reduction_info. > (reduction_phi): Likewise. > (initialize_reductions): Likewise. > (create_call_for_reduction_1): Likewise. > (transform_to_exit_first_loop_alt): Likewise. > (transform_to_exit_first_loop): Likewise. > (build_new_reduction): Likewise. > (set_reduc_phi_uids): Likewise. > (try_create_reduction_list): Likewise. > * tree-ssa-loop-split.cc (split_loop): Remember the PHI result > variable so that the PHI can be found in case it is resized and move > to a new address. > * tree-vect-loop-manip.cc (vect_loop_versioning): After calling > loop_version(), fix up stored PHI pointers in case they have > changed. > * tree-vectorizer.cc (vec_info::resync_stmt_addr): New function. > * tree-vectorizer.h (vec_info::resync_stmt_addr): Declare. > --- > gcc/tree-parloops.cc | 40 +++++++++++++++++++++++-------------- > gcc/tree-ssa-loop-split.cc | 7 +++++++ > gcc/tree-vect-loop-manip.cc | 8 ++++++++ > gcc/tree-vectorizer.cc | 20 +++++++++++++++++++ > gcc/tree-vectorizer.h | 1 + > 5 files changed, 61 insertions(+), 15 deletions(-) > > diff --git a/gcc/tree-parloops.cc b/gcc/tree-parloops.cc > index 13d8e84bc8f..8427c287a6a 100644 > --- a/gcc/tree-parloops.cc > +++ b/gcc/tree-parloops.cc > @@ -895,7 +895,7 @@ parloops_force_simple_reduction (loop_vec_info loop_info, > stmt_vec_info phi_info > struct reduction_info > { > gimple *reduc_stmt; /* reduction statement. */ > - gimple *reduc_phi; /* The phi node defining the reduction. */ > + tree reduc_phi_name; /* The result of the phi node defining the > reduction. */ > enum tree_code reduction_code;/* code for the reduction operation. */ > unsigned reduc_version; /* SSA_NAME_VERSION of original reduc_phi > result. */ > @@ -910,6 +910,12 @@ struct reduction_info > will be passed to the atomic operation. > Represents > the local result each thread computed for > the reduction > operation. */ > + > + gphi * > + reduc_phi () const > + { > + return as_a<gphi *> (SSA_NAME_DEF_STMT (reduc_phi_name)); > + } > }; > > /* Reduction info hashtable helpers. */ > @@ -925,7 +931,7 @@ struct reduction_hasher : free_ptr_hash <reduction_info> > inline bool > reduction_hasher::equal (const reduction_info *a, const reduction_info *b) > { > - return (a->reduc_phi == b->reduc_phi); > + return (a->reduc_phi_name == b->reduc_phi_name); > } > > inline hashval_t > @@ -949,10 +955,10 @@ reduction_phi (reduction_info_table_type > *reduction_list, gimple *phi) > || gimple_uid (phi) == 0) > return NULL; > > - tmpred.reduc_phi = phi; > + tmpred.reduc_phi_name = gimple_phi_result (phi); > tmpred.reduc_version = gimple_uid (phi); > red = reduction_list->find (&tmpred); > - gcc_assert (red == NULL || red->reduc_phi == phi); > + gcc_assert (red == NULL || red->reduc_phi () == phi); > > return red; > } > @@ -1294,7 +1300,7 @@ initialize_reductions (reduction_info **slot, class > loop *loop) > from the preheader with the reduction initialization value. */ > > /* Initialize the reduction. */ > - type = TREE_TYPE (PHI_RESULT (reduc->reduc_phi)); > + type = TREE_TYPE (reduc->reduc_phi_name); > init = omp_reduction_init_op (gimple_location (reduc->reduc_stmt), > reduc->reduction_code, type); > reduc->init = init; > @@ -1308,11 +1314,11 @@ initialize_reductions (reduction_info **slot, class > loop *loop) > computing is done. */ > > e = loop_preheader_edge (loop); > - arg = PHI_ARG_DEF_FROM_EDGE (reduc->reduc_phi, e); > + const auto phi = reduc->reduc_phi (); > + arg = PHI_ARG_DEF_FROM_EDGE (phi, e); > /* Create new variable to hold the initial value. */ > > - SET_USE (PHI_ARG_DEF_PTR_FROM_EDGE > - (reduc->reduc_phi, loop_preheader_edge (loop)), init); > + SET_USE (PHI_ARG_DEF_PTR_FROM_EDGE (phi, loop_preheader_edge (loop)), > init); > reduc->initial_value = arg; > return 1; > } > @@ -1795,7 +1801,7 @@ create_call_for_reduction_1 (reduction_info **slot, > struct clsn_data *clsn_data) > { > struct reduction_info *const reduc = *slot; > gimple_stmt_iterator gsi; > - tree type = TREE_TYPE (PHI_RESULT (reduc->reduc_phi)); > + tree type = TREE_TYPE (reduc->reduc_phi_name); > tree load_struct; > basic_block bb; > basic_block new_bb; > @@ -2424,8 +2430,9 @@ transform_to_exit_first_loop_alt (class loop *loop, > if (red) > { > /* Register the new reduction phi. */ > - red->reduc_phi = nphi; > - gimple_set_uid (red->reduc_phi, red->reduc_version); > + red->reduc_phi_name = res_c; > + gcc_checking_assert (red->reduc_phi () == nphi); > + gimple_set_uid (nphi, red->reduc_version); > } > } > gcc_assert (gsi_end_p (gsi) && !v->iterate (i, &vm)); > @@ -2651,6 +2658,8 @@ transform_to_exit_first_loop (class loop *loop, > phi = gsi.phi (); > res = PHI_RESULT (phi); > t = copy_ssa_name (res, phi); > + if (auto red = reduction_phi (reduction_list, phi)) > + red->reduc_phi_name = t; > SET_PHI_RESULT (phi, t); > nphi = create_phi_node (res, orig_header); > add_phi_arg (nphi, t, hpred, UNKNOWN_LOCATION); > @@ -3263,8 +3272,9 @@ build_new_reduction (reduction_info_table_type > *reduction_list, > new_reduction = XCNEW (struct reduction_info); > > new_reduction->reduc_stmt = reduc_stmt; > - new_reduction->reduc_phi = phi; > - new_reduction->reduc_version = SSA_NAME_VERSION (gimple_phi_result (phi)); > + const auto phi_name = gimple_phi_result (phi); > + new_reduction->reduc_phi_name = phi_name; > + new_reduction->reduc_version = SSA_NAME_VERSION (phi_name); > new_reduction->reduction_code = reduction_code; > slot = reduction_list->find_slot (new_reduction, INSERT); > *slot = new_reduction; > @@ -3276,7 +3286,7 @@ int > set_reduc_phi_uids (reduction_info **slot, void *data ATTRIBUTE_UNUSED) > { > struct reduction_info *const red = *slot; > - gimple_set_uid (red->reduc_phi, red->reduc_version); > + gimple_set_uid (red->reduc_phi (), red->reduc_version); > return 1; > } > > @@ -3559,7 +3569,7 @@ try_create_reduction_list (loop_p loop, > if (dump_file && (dump_flags & TDF_DETAILS)) > { > fprintf (dump_file, "reduction phi is "); > - print_gimple_stmt (dump_file, red->reduc_phi, 0); > + print_gimple_stmt (dump_file, red->reduc_phi (), 0); > fprintf (dump_file, "reduction stmt is "); > print_gimple_stmt (dump_file, red->reduc_stmt, 0); > } > diff --git a/gcc/tree-ssa-loop-split.cc b/gcc/tree-ssa-loop-split.cc > index 48d153d794a..a64066a9ae4 100644 > --- a/gcc/tree-ssa-loop-split.cc > +++ b/gcc/tree-ssa-loop-split.cc > @@ -622,6 +622,7 @@ split_loop (class loop *loop1) > gphi *phi = find_or_create_guard_phi (loop1, guard_iv, &iv); > if (!phi) > continue; > + const tree phi_result = gimple_phi_result (phi); > gcond *guard_stmt = as_a<gcond *> (*gsi_last_bb (bbs[i])); > tree guard_init = PHI_ARG_DEF_FROM_EDGE (phi, > loop_preheader_edge (loop1)); > @@ -703,6 +704,12 @@ split_loop (class loop *loop1) > profile_probability::very_likely (), > true); > gcc_assert (loop2); > + > + /* The phi address may have changed due to being resized in > + loop_version (), so reobtain it. */ > + phi = as_a<gphi *> (SSA_NAME_DEF_STMT (phi_result)); > + gcc_checking_assert (gimple_bb (phi) == loop1->header); > + > /* Correct probability of edge cond_bb->preheader_of_loop2. */ > single_pred_edge > (loop_preheader_edge (loop2)->src)->probability > diff --git a/gcc/tree-vect-loop-manip.cc b/gcc/tree-vect-loop-manip.cc > index 54b29540eb5..4f3abb94e6a 100644 > --- a/gcc/tree-vect-loop-manip.cc > +++ b/gcc/tree-vect-loop-manip.cc > @@ -4190,6 +4190,14 @@ vect_loop_versioning (loop_vec_info loop_vinfo, > prob * prob2, (prob * prob2).invert (), > prob * prob2, (prob * prob2).invert (), > true); > + > + /* If the PHI nodes in the loop header were reallocated, we need to > fix up > + our internally stashed copies of those. */ > + if (loop_to_version == loop) > + for (auto gsi = gsi_start_phis (loop->header); > + !gsi_end_p (gsi); gsi_next (&gsi)) > + loop_vinfo->resync_stmt_addr (gsi.phi ()); Instead of a new resync_stmt_addr method can you simply do if (stmt_vec_info s = loop_vinfo->lookup_stmt (gsi.phi ()) STMT_VINFO_STMT (s) = gsi.phi (); please? OK with that change. Thanks, Richard. > + > /* We will later insert second conditional so overall outcome of > both is prob * prob2. */ > edge true_e, false_e; > diff --git a/gcc/tree-vectorizer.cc b/gcc/tree-vectorizer.cc > index 9a068a40864..c8bb0fe14fc 100644 > --- a/gcc/tree-vectorizer.cc > +++ b/gcc/tree-vectorizer.cc > @@ -541,6 +541,26 @@ vec_info::add_pattern_stmt (gimple *stmt, stmt_vec_info > stmt_info) > return res; > } > > +/* If STMT was previously associated with a stmt_vec_info and STMT now > resides > + at a different address than before (e.g., because STMT is a phi node that > has > + been resized), update the expected address to match the new one. */ > + > +stmt_vec_info > +vec_info::resync_stmt_addr (gimple *stmt) > +{ > + unsigned int uid = gimple_uid (stmt); > + if (uid > 0 && uid - 1 < stmt_vec_infos.length ()) > + { > + stmt_vec_info res = stmt_vec_infos[uid - 1]; > + if (res && res->stmt) > + { > + res->stmt = stmt; > + return res; > + } > + } > + return nullptr; > +} > + > /* If STMT has an associated stmt_vec_info, return that vec_info, otherwise > return null. It is safe to call this function on any statement, even if > it might not be part of the vectorizable region. */ > diff --git a/gcc/tree-vectorizer.h b/gcc/tree-vectorizer.h > index 7f69a3f57b4..749a9299d35 100644 > --- a/gcc/tree-vectorizer.h > +++ b/gcc/tree-vectorizer.h > @@ -500,6 +500,7 @@ public: > > stmt_vec_info add_stmt (gimple *); > stmt_vec_info add_pattern_stmt (gimple *, stmt_vec_info); > + stmt_vec_info resync_stmt_addr (gimple *); > stmt_vec_info lookup_stmt (gimple *); > stmt_vec_info lookup_def (tree); > stmt_vec_info lookup_single_use (tree);