https://gcc.gnu.org/g:1b73c190a28390ac6f7ff27e1a58df89527773ad
commit 1b73c190a28390ac6f7ff27e1a58df89527773ad Author: Mikael Morin <mik...@gcc.gnu.org> Date: Tue May 6 17:41:55 2025 +0200 Correction régression loop_versioning_8 Diff: --- gcc/gimple-loop-versioning.cc | 187 +++++++++++++++++++++++++++++++++--------- 1 file changed, 146 insertions(+), 41 deletions(-) diff --git a/gcc/gimple-loop-versioning.cc b/gcc/gimple-loop-versioning.cc index 5c9b2fb77ff9..f881e07edcc2 100644 --- a/gcc/gimple-loop-versioning.cc +++ b/gcc/gimple-loop-versioning.cc @@ -172,6 +172,8 @@ struct address_term_info /* True if STRIDE == 1 is a versioning opportunity when considered in isolation. */ bool versioning_opportunity_p; + + unsigned HOST_WIDE_INT versioning_value; }; /* Information about an address calculation, and the range of constant @@ -237,6 +239,13 @@ public: (keyed off their SSA_NAME_VERSION) are all equal to 1 at runtime. */ bitmap_head unity_names; + /* We'd like to version the loop for the case in which these SSA names + (keyed off their SSA_NAME_VERSION) are equal to the respective access size + at runtime. */ + hash_map <unsigned, unsigned HOST_WIDE_INT, + simple_hashmap_traits <int_hash <unsigned, UINT_MAX>, unsigned HOST_WIDE_INT>> + non_unity_versioning_values; + /* If versioning succeeds, this points the version of the loop that assumes the version conditions holds. */ class loop *optimized_loop; @@ -283,7 +292,7 @@ private: unsigned int max_insns_for_loop (class loop *); bool expensive_stmt_p (gimple *); - void version_for_unity (gimple *, tree); + void version_for_value (gimple *, tree, unsigned HOST_WIDE_INT); bool acceptable_multiplier_p (tree, unsigned HOST_WIDE_INT, unsigned HOST_WIDE_INT * = 0); bool acceptable_type_p (tree, unsigned HOST_WIDE_INT *); @@ -487,7 +496,9 @@ bool loop_info::worth_versioning_p () const { return (!rejected_p - && (!bitmap_empty_p (&unity_names) || subloops_benefit_p)); + && (!bitmap_empty_p (&unity_names) + || !non_unity_versioning_values.is_empty () + || subloops_benefit_p)); } loop_versioning::lv_dom_walker::lv_dom_walker (loop_versioning &lv) @@ -512,9 +523,17 @@ loop_versioning::lv_dom_walker::before_dom_children (basic_block bb) tree loop_versioning::name_prop::value_of_expr (tree val, gimple *) { - if (TREE_CODE (val) == SSA_NAME - && bitmap_bit_p (&m_li.unity_names, SSA_NAME_VERSION (val))) + if (TREE_CODE (val) != SSA_NAME) + return NULL_TREE; + + if (bitmap_bit_p (&m_li.unity_names, SSA_NAME_VERSION (val))) return build_one_cst (TREE_TYPE (val)); + + unsigned HOST_WIDE_INT *version_size; + version_size = m_li.non_unity_versioning_values.get (SSA_NAME_VERSION (val)); + if (version_size) + return build_int_cst (TREE_TYPE (val), version_size); + return NULL_TREE; } @@ -535,6 +554,7 @@ loop_versioning::loop_versioning (function *fn) { m_loops[i].outermost = get_loop (m_fn, 0); bitmap_initialize (&m_loops[i].unity_names, &m_bitmap_obstack); + m_loops[i].non_unity_versioning_values.empty (); } /* Initialize the list of blocks that belong to each loop. */ @@ -606,12 +626,40 @@ loop_versioning::expensive_stmt_p (gimple *stmt) is invariant in the loop. */ void -loop_versioning::version_for_unity (gimple *stmt, tree name) +loop_versioning::version_for_value (gimple *stmt, tree name, + unsigned HOST_WIDE_INT value) { class loop *loop = loop_containing_stmt (stmt); loop_info &li = get_loop_info (loop); - if (bitmap_set_bit (&li.unity_names, SSA_NAME_VERSION (name))) + bool changed = false; + if (value == 1 + && bitmap_set_bit (&li.unity_names, SSA_NAME_VERSION (name))) + changed = true; + else + { + bool existed; + unsigned HOST_WIDE_INT &versioning_value + = li.non_unity_versioning_values.get_or_insert ( + SSA_NAME_VERSION (name), &existed); + if (!existed) + { + versioning_value = value; + changed = true; + } + else if (versioning_value != value) + { + li.rejected_p = true; + if (dump_enabled_p ()) + dump_printf_loc (MSG_NOTE, stmt, "disabling versioning of loop with" + " multiple values for %T: " HOST_WIDE_INT_PRINT_DEC + " and " HOST_WIDE_INT_PRINT_DEC "\n", name, + versioning_value, value); + return; + } + } + + if (changed) { /* This is the first time we've wanted to version LOOP for NAME. Keep track of the outermost loop that can handle all versioning @@ -624,7 +672,8 @@ loop_versioning::version_for_unity (gimple *stmt, tree name) if (dump_enabled_p ()) { dump_printf_loc (MSG_NOTE, stmt, "want to version containing loop" - " for when %T == 1", name); + " for when %T == " HOST_WIDE_INT_PRINT_UNSIGNED, + name, value); if (outermost == loop) dump_printf (MSG_NOTE, "; cannot hoist check further"); else @@ -645,7 +694,8 @@ loop_versioning::version_for_unity (gimple *stmt, tree name) /* This is a duplicate request. */ if (dump_enabled_p ()) dump_printf_loc (MSG_NOTE, stmt, "already asked to version containing" - " loop for when %T == 1\n", name); + " loop for when %T == " HOST_WIDE_INT_PRINT_UNSIGNED "\n", + name, value); } } @@ -836,15 +886,24 @@ loop_versioning::analyze_stride (address_info &address, - the stride is an SSA name that is invariant in STMT's loop, since otherwise versioning isn't possible. */ unsigned HOST_WIDE_INT access_size = address.max_offset - address.min_offset; - if (term.multiplier == access_size + if ((term.multiplier == access_size + || term.multiplier == 1) && address.loop == op_loop && TREE_CODE (stride) == SSA_NAME && expr_invariant_in_loop_p (address.loop, stride)) { term.versioning_opportunity_p = true; + if (term.multiplier == access_size) + term.versioning_value = 1; + else + term.versioning_value = access_size; + if (dump_enabled_p ()) - dump_printf_loc (MSG_NOTE, address.stmt, "%T == 1 is a versioning" - " opportunity\n", stride); + dump_printf_loc (MSG_NOTE, address.stmt, "%T == " + HOST_WIDE_INT_PRINT_DEC " is a versioning" + " opportunity\n", stride, + term.multiplier == access_size ? HOST_WIDE_INT_1U + : access_size); } } @@ -1125,36 +1184,39 @@ loop_versioning::analyze_address_fragment (address_info &address) Pointer equality is enough to check for uniqueness in (1), since we only care about SSA names. */ - tree chosen_stride = NULL_TREE; - tree version_stride = NULL_TREE; + address_term_info *chosen_term = nullptr; + address_term_info *version_term = nullptr; for (unsigned int i = 0; i < address.terms.length (); ++i) - if (chosen_stride != address.terms[i].stride + if ((chosen_term == nullptr + || chosen_term->stride != address.terms[i].stride) && address.terms[i].inner_likelihood == INNER_LIKELY) { - if (chosen_stride) + if (chosen_term) return; - chosen_stride = address.terms[i].stride; + chosen_term = &address.terms[i]; if (address.terms[i].versioning_opportunity_p) - version_stride = chosen_stride; + version_term = chosen_term; } /* If there are no likely inner strides, see if there is a single versioning opportunity for a stride that was rated as INNER_DONT_KNOW. See the comment above the function for the cases that this code handles. */ - if (!chosen_stride) + if (!chosen_term) for (unsigned int i = 0; i < address.terms.length (); ++i) - if (version_stride != address.terms[i].stride + if ((version_term == nullptr + || version_term->stride != address.terms[i].stride) && address.terms[i].inner_likelihood == INNER_DONT_KNOW && address.terms[i].versioning_opportunity_p) { - if (version_stride) + if (version_term) return; - version_stride = address.terms[i].stride; + version_term = &address.terms[i]; } - if (version_stride) - version_for_unity (address.stmt, version_stride); + if (version_term) + version_for_value (address.stmt, version_term->stride, + version_term->versioning_value); } /* Treat EXPR * MULTIPLIER + OFFSET as a fragment of an address that addresses @@ -1190,6 +1252,7 @@ loop_versioning::record_address_fragment (gimple *stmt, address->terms[0].stride = NULL_TREE; address->terms[0].inner_likelihood = INNER_UNLIKELY; address->terms[0].versioning_opportunity_p = false; + address->terms[0].versioning_value = 0; address->min_offset = offset; /* Peel apart the expression into a sum of address_terms, where each @@ -1455,6 +1518,50 @@ loop_versioning::analyze_blocks () return m_num_conditions != 0; } + +static bool +name_can_have_value_in_loop (unsigned id_name, unsigned HOST_WIDE_INT value, + class loop *loop) +{ + tree name = ssa_name (id_name); + gimple *stmt = first_stmt (loop->header); + + int_range_max r; + if (get_range_query (cfun)->range_of_expr (r, name, stmt) + && !r.contains_p (wi::one (TYPE_PRECISION (TREE_TYPE (name))))) + { + if (dump_enabled_p ()) + dump_printf_loc (MSG_NOTE, find_loop_location (loop), + "%T can never be " HOST_WIDE_INT_PRINT_DEC + " in this loop\n", name, value); + + return false; + } + else + return true; +} + + +struct loop_versioning_info +{ + class loop *loop; + class loop_versioning *loop_versioning; + bitmap names_to_remove; +}; + +static bool +check_possible_value (const unsigned &id_name, + const unsigned HOST_WIDE_INT &version_value, + struct loop_versioning_info &versioning_info) +{ + if (!name_can_have_value_in_loop (id_name, version_value, + versioning_info.loop)) + bitmap_set_bit (versioning_info.names_to_remove, id_name); + + return true; +} + + /* Use the ranges in VRS to remove impossible versioning conditions from LOOP. */ @@ -1463,30 +1570,28 @@ loop_versioning::prune_loop_conditions (class loop *loop) { loop_info &li = get_loop_info (loop); - int to_remove = -1; + auto_bitmap names_to_remove; + bitmap_iterator bi; unsigned int i; - int_range_max r; EXECUTE_IF_SET_IN_BITMAP (&li.unity_names, 0, i, bi) - { - tree name = ssa_name (i); - gimple *stmt = first_stmt (loop->header); + if (!name_can_have_value_in_loop (i, 1, loop)) + bitmap_set_bit (names_to_remove, i); - if (get_range_query (cfun)->range_of_expr (r, name, stmt) - && !r.contains_p (wi::one (TYPE_PRECISION (TREE_TYPE (name))))) - { - if (dump_enabled_p ()) - dump_printf_loc (MSG_NOTE, find_loop_location (loop), - "%T can never be 1 in this loop\n", name); + struct loop_versioning_info versioning_info; + versioning_info.loop = loop; + versioning_info.loop_versioning = this; + versioning_info.names_to_remove = names_to_remove; - if (to_remove >= 0) - bitmap_clear_bit (&li.unity_names, to_remove); - to_remove = i; - m_num_conditions -= 1; - } + li.non_unity_versioning_values + .traverse<loop_versioning_info &, check_possible_value> ( + versioning_info); + + EXECUTE_IF_SET_IN_BITMAP (names_to_remove, 0, i, bi) + { + bitmap_clear_bit (&li.unity_names, i); + li.non_unity_versioning_values.remove (i); } - if (to_remove >= 0) - bitmap_clear_bit (&li.unity_names, to_remove); } /* Remove any scheduled loop version conditions that will never be true.