https://gcc.gnu.org/g:a42bca3cec7e2cb8999de5cd43b21352a0445b81
commit a42bca3cec7e2cb8999de5cd43b21352a0445b81 Author: Mikael Morin <mik...@gcc.gnu.org> Date: Tue May 13 12:23:09 2025 +0200 Correction régressions loop versioning Diff: --- gcc/gimple-loop-versioning.cc | 243 +++++++++++++++++++++--- gcc/testsuite/gfortran.dg/loop_versioning_9.f90 | 2 +- 2 files changed, 222 insertions(+), 23 deletions(-) diff --git a/gcc/gimple-loop-versioning.cc b/gcc/gimple-loop-versioning.cc index 0c487d360ce8..6140972fcd0b 100644 --- a/gcc/gimple-loop-versioning.cc +++ b/gcc/gimple-loop-versioning.cc @@ -41,6 +41,7 @@ along with GCC; see the file COPYING3. If not see #include "tree-into-ssa.h" #include "gimple-range.h" #include "tree-cfg.h" +#include "tree-dfa.h" namespace { @@ -253,6 +254,9 @@ public: class loop *optimized_loop; }; +static void +dump_inner_likelihood (address_info &, address_term_info &); + /* The main pass structure. */ class loop_versioning { @@ -300,7 +304,6 @@ private: bool acceptable_type_p (tree, unsigned HOST_WIDE_INT *); bool multiply_term_by (address_term_info &, tree); inner_likelihood get_inner_likelihood (tree, unsigned HOST_WIDE_INT); - void dump_inner_likelihood (address_info &, address_term_info &); void analyze_stride (address_info &, address_term_info &, tree, class loop *); bool find_per_loop_multiplication (address_info &, address_term_info &); @@ -837,9 +840,8 @@ loop_versioning::get_inner_likelihood (tree stride, /* Dump the likelihood that TERM's stride is for the innermost dimension. ADDRESS is the address that contains TERM. */ -void -loop_versioning::dump_inner_likelihood (address_info &address, - address_term_info &term) +static void +dump_inner_likelihood (address_info &address, address_term_info &term) { if (term.inner_likelihood == INNER_LIKELY) dump_printf_loc (MSG_NOTE, address.stmt, "%T is likely to be the" @@ -1052,6 +1054,185 @@ loop_versioning::analyze_arbitrary_term (address_info &address, dump_inner_likelihood (address, term); } + +static bool +tree_same_expr_p (tree t1, tree t2) +{ + if (t1 == t2) + return true; + + if (TREE_CODE (t1) != TREE_CODE (t2)) + return false; + + int len1 = TREE_OPERAND_LENGTH (t1); + int len2 = TREE_OPERAND_LENGTH (t2); + if (len1 != len2) + return false; + + for (int i = 0; i < len1; ++i) + if (!tree_same_expr_p (TREE_OPERAND (t1, i), + TREE_OPERAND (t2, i))) + return false; + + return true; +} + + +static void +set_unknown_likelihood (address_info &address, address_term_info &term_info, + enum inner_likelihood value) + +{ + if (term_info.inner_likelihood == INNER_DONT_KNOW) + { + term_info.inner_likelihood = value; + if (dump_enabled_p ()) + dump_inner_likelihood (address, term_info); + } +} + + +static void +guess_likelihood_from_offsets (address_info &address) +{ + struct stride_info + { + tree data_ref; + tree base; + HOST_WIDE_INT offset; + unsigned int idx; + }; + + auto_vec<stride_info> strides; + auto_vec<tree> worklist; + + for (unsigned int i = 0; i < address.terms.length (); ++i) + { + worklist.safe_push (address.terms[i].expr); + + while (!worklist.is_empty ()) + { + tree expr = worklist.pop (); + tree old_expr = NULL_TREE; + + while (expr != old_expr) + { + old_expr = expr; + + expr = strip_casts (expr); + if (TREE_CODE (expr) == SSA_NAME) + { + gimple *stmt = SSA_NAME_DEF_STMT (expr); + if (!is_gimple_assign (stmt)) + continue; + + if (gimple_assign_single_p (stmt)) + { + gassign *assign = as_a <gassign *> (stmt); + expr = gimple_assign_rhs1 (assign); + } + else if (gimple_assign_rhs_code (stmt) == MULT_EXPR) + { + worklist.safe_push (gimple_assign_rhs1 (stmt)); + worklist.safe_push (gimple_assign_rhs2 (stmt)); + expr = NULL_TREE; + break; + } + } + } + + if (expr == NULL_TREE) + continue; + + HOST_WIDE_INT offset; + HOST_WIDE_INT scratch_size; + bool scratch_reverse; + tree base = get_ref_base_and_extent_hwi (expr, &offset, &scratch_size, + &scratch_reverse); + if (base == NULL_TREE || offset < 0) + continue; + + stride_info si; + si.data_ref = expr; + si.base = base; + si.offset = offset; + si.idx = i; + + strides.safe_push (si); + } + } + + unsigned int i; + stride_info *pinfo; + FOR_EACH_VEC_ELT (strides, i, pinfo) + if (pinfo->data_ref + && TREE_CODE (pinfo->data_ref) == COMPONENT_REF) + { + tree comp_base = TREE_OPERAND (pinfo->data_ref, 0); + if (TREE_CODE (comp_base) == ARRAY_REF) + { + unsigned int idx = pinfo->idx; + if (integer_zerop (TREE_OPERAND (comp_base, 1))) + set_unknown_likelihood (address, address.terms[idx], + INNER_LIKELY); + else if (TREE_CODE (TREE_OPERAND (comp_base, 1)) == INTEGER_CST) + set_unknown_likelihood (address, address.terms[idx], + INNER_UNLIKELY); + } + } + + while (strides.length () > 0) + { + int j = strides.length () - 1; + + stride_info min_offset_info = strides[j]; + bool has_zero_offset = min_offset_info.offset == 0; + int count_non_zero_offset = min_offset_info.offset != 0; + strides.unordered_remove (j); + + for (int i = j - 1; i >= 0; --i) + { + if (!tree_same_expr_p (strides[i].base, min_offset_info.base)) + continue; + + if (strides[i].offset == 0) + has_zero_offset = true; + else + { + if (min_offset_info.offset == 0) + min_offset_info = strides[i]; + else + { + ++count_non_zero_offset; + if (strides[i].offset < min_offset_info.offset) + { + int idx = min_offset_info.idx; + set_unknown_likelihood (address, address.terms[idx], + INNER_UNLIKELY); + + min_offset_info = strides[i]; + } + else if (strides[i].offset > min_offset_info.offset) + { + int idx = strides[i].idx; + set_unknown_likelihood (address, address.terms[idx], + INNER_UNLIKELY); + } + } + } + + strides.unordered_remove (i); + } + + if (has_zero_offset + && count_non_zero_offset > 1 + && min_offset_info.offset != 0) + set_unknown_likelihood (address, address.terms[min_offset_info.idx], + INNER_LIKELY); + } +} + + /* Try to identify loop strides in ADDRESS and try to choose realistic versioning opportunities based on these strides. @@ -1137,6 +1318,8 @@ loop_versioning::analyze_address_fragment (address_info &address) && !POINTER_TYPE_P (TREE_TYPE (address.terms[i].expr))) analyze_arbitrary_term (address, address.terms[i]); + guess_likelihood_from_offsets (address); + /* Check for strides that are likely to be for the innermost dimension. 1. If there is a single likely inner stride, if it is an SSA name, @@ -1189,15 +1372,16 @@ loop_versioning::analyze_address_fragment (address_info &address) address_term_info *chosen_term = nullptr; address_term_info *version_term = nullptr; for (unsigned int i = 0; i < address.terms.length (); ++i) - if ((chosen_term == nullptr - || chosen_term->stride != address.terms[i].stride) - && address.terms[i].inner_likelihood == INNER_LIKELY) + if (address.terms[i].inner_likelihood == INNER_LIKELY) { - if (chosen_term) + if (chosen_term == nullptr) + { + chosen_term = &address.terms[i]; + if (address.terms[i].versioning_opportunity_p) + version_term = chosen_term; + } + else if (chosen_term->stride != address.terms[i].stride) return; - chosen_term = &address.terms[i]; - if (address.terms[i].versioning_opportunity_p) - version_term = chosen_term; } /* If there are no likely inner strides, see if there is a single @@ -1206,14 +1390,13 @@ loop_versioning::analyze_address_fragment (address_info &address) handles. */ if (!chosen_term) for (unsigned int i = 0; i < address.terms.length (); ++i) - if ((version_term == nullptr - || version_term->stride != address.terms[i].stride) - && address.terms[i].inner_likelihood == INNER_DONT_KNOW + if (address.terms[i].inner_likelihood == INNER_DONT_KNOW && address.terms[i].versioning_opportunity_p) { - if (version_term) + if (version_term == nullptr) + version_term = &address.terms[i]; + else if (version_term->stride != address.terms[i].stride) return; - version_term = &address.terms[i]; } if (version_term) @@ -1611,19 +1794,31 @@ loop_versioning::prune_conditions () return m_num_conditions != 0; } +struct copy_info +{ + loop_info::name_value_map_t &dest_map; + class loop *inner_loop; +}; + static bool copy_versioning_value (const unsigned &id_name, const unsigned HOST_WIDE_INT &version_value, - loop_info::name_value_map_t &dest_map) + copy_info &info) { bool existed = false; - unsigned HOST_WIDE_INT &copied_value = dest_map.get_or_insert ( + unsigned HOST_WIDE_INT &copied_value = info.dest_map.get_or_insert ( id_name, &existed); if (!existed) - copied_value = version_value; + { + copied_value = version_value; + if (dump_enabled_p ()) + dump_printf_loc (MSG_NOTE, find_loop_location (info.inner_loop), + "hoisting check that %T == " HOST_WIDE_INT_PRINT_DEC + " to outer loop\n", ssa_name (id_name), version_value); + } else if (copied_value != version_value) - dest_map.remove (id_name); + info.dest_map.remove (id_name); return true; } @@ -1650,9 +1845,13 @@ loop_versioning::merge_loop_info (class loop *outer, class loop *inner) bitmap_ior_into (&outer_li.unity_names, &inner_li.unity_names); + copy_info info { + outer_li.non_unity_versioning_values, + inner + }; + inner_li.non_unity_versioning_values - .traverse<loop_info::name_value_map_t &, copy_versioning_value> ( - outer_li.non_unity_versioning_values); + .traverse<copy_info &, copy_versioning_value> (info); if (loop_depth (outer_li.outermost) < loop_depth (inner_li.outermost)) outer_li.outermost = inner_li.outermost; diff --git a/gcc/testsuite/gfortran.dg/loop_versioning_9.f90 b/gcc/testsuite/gfortran.dg/loop_versioning_9.f90 index 7a0fd55eaca6..4f752cfaed6c 100644 --- a/gcc/testsuite/gfortran.dg/loop_versioning_9.f90 +++ b/gcc/testsuite/gfortran.dg/loop_versioning_9.f90 @@ -26,6 +26,6 @@ subroutine f4(x, i) end do end subroutine f4 -! { dg-final { scan-tree-dump-times {likely to be the innermost dimension} 4 "lversion" } } +! { dg-final { scan-tree-dump-times {likely to be the innermost dimension} 3 "lversion" } } ! { dg-final { scan-tree-dump-not {want to version} "lversion" } } ! { dg-final { scan-tree-dump-not {versioned} "lversion" } }