On Sun, Aug 31, 2025 at 4:11 PM Andrew Pinski <andrew.pin...@oss.qualcomm.com> wrote: > > This is a small cleanup by moving the optimization of memcmp to > memcmp_eq to fab from strlen pass. Since the copy of the other > part of the memcmp strlen optimization to forwprop, this was the > only thing left that strlen can do memcmp. > > Note this move will cause memcmp_eq to be used for -Os too. > > It also removes the optimization from strlen since both are now > handled elsewhere. > > Bootstrapped and tested on x86_64-linux-gnu.
OK. Note I don't like fab much, at least the parts that are not obviously instruction selection. Most of it should be part of forwprop or ISEL or a pre-expand "cleanup" (removal of __builtin_assume_aligned and friends). So, unless memcmp_eq is unhandled elsewhere and thus we need to do it late (-> ISEL), I'd rather do it in forwprop. Richard. > gcc/ChangeLog: > > * tree-ssa-ccp.cc (optimize_memcmp_eq): New function. > (pass_fold_builtins::execute): Call optimize_memcmp_eq > for memcmp. > * tree-ssa-strlen.cc (strlen_pass::handle_builtin_memcmp): Remove. > (strlen_pass::check_and_optimize_call): Don't call > handle_builtin_memcmp. > > Signed-off-by: Andrew Pinski <andrew.pin...@oss.qualcomm.com> > --- > gcc/tree-ssa-ccp.cc | 35 +++++++++++++++++++++++ > gcc/tree-ssa-strlen.cc | 63 ------------------------------------------ > 2 files changed, 35 insertions(+), 63 deletions(-) > > diff --git a/gcc/tree-ssa-ccp.cc b/gcc/tree-ssa-ccp.cc > index f33cc042e9f..f16b37f193e 100644 > --- a/gcc/tree-ssa-ccp.cc > +++ b/gcc/tree-ssa-ccp.cc > @@ -155,6 +155,7 @@ along with GCC; see the file COPYING3. If not see > #include "ipa-prop.h" > #include "internal-fn.h" > #include "gimple-range.h" > +#include "tree-ssa-strlen.h" > > /* Possible lattice values. */ > typedef enum > @@ -4221,6 +4222,36 @@ public: > > }; // class pass_fold_builtins > > +/* Optimize memcmp STMT into memcmp_eq if it is only used with > + `== 0` or `!= 0`. */ > + > +static void > +optimize_memcmp_eq (gcall *stmt) > +{ > + /* Make sure memcmp arguments are the correct type. */ > + if (gimple_call_num_args (stmt) != 3) > + return; > + tree arg1 = gimple_call_arg (stmt, 0); > + tree arg2 = gimple_call_arg (stmt, 1); > + tree len = gimple_call_arg (stmt, 2); > + > + if (!POINTER_TYPE_P (TREE_TYPE (arg1))) > + return; > + if (!POINTER_TYPE_P (TREE_TYPE (arg2))) > + return; > + if (!INTEGRAL_TYPE_P (TREE_TYPE (len))) > + return; > + /* The return value of the memcmp has to be used > + equality comparison to zero. */ > + tree res = gimple_call_lhs (stmt); > + > + if (!res || !use_in_zero_equality (res)) > + return; > + > + gimple_call_set_fndecl (stmt, builtin_decl_explicit (BUILT_IN_MEMCMP_EQ)); > + update_stmt (stmt); > +} > + > unsigned int > pass_fold_builtins::execute (function *fun) > { > @@ -4285,6 +4316,10 @@ pass_fold_builtins::execute (function *fun) > gsi_next (&i); > continue; > > + case BUILT_IN_MEMCMP: > + optimize_memcmp_eq (as_a<gcall*>(stmt)); > + break; > + > case BUILT_IN_UNREACHABLE: > if (optimize_unreachable (i)) > cfg_changed = true; > diff --git a/gcc/tree-ssa-strlen.cc b/gcc/tree-ssa-strlen.cc > index c4d64132e53..ade8c7dcadd 100644 > --- a/gcc/tree-ssa-strlen.cc > +++ b/gcc/tree-ssa-strlen.cc > @@ -3971,65 +3971,6 @@ use_in_zero_equality (tree res, bool exclusive) > return first_use; > } > > -/* Handle a call to memcmp. We try to handle small comparisons by > - converting them to load and compare, and replacing the call to memcmp > - with a __builtin_memcmp_eq call where possible. > - return true when call is transformed, return false otherwise. */ > - > -bool > -strlen_pass::handle_builtin_memcmp () > -{ > - gcall *stmt = as_a <gcall *> (gsi_stmt (m_gsi)); > - tree res = gimple_call_lhs (stmt); > - > - if (!res || !use_in_zero_equality (res)) > - return false; > - > - tree arg1 = gimple_call_arg (stmt, 0); > - tree arg2 = gimple_call_arg (stmt, 1); > - tree len = gimple_call_arg (stmt, 2); > - unsigned HOST_WIDE_INT leni; > - > - if (tree_fits_uhwi_p (len) > - && (leni = tree_to_uhwi (len)) <= GET_MODE_SIZE (word_mode) > - && pow2p_hwi (leni)) > - { > - leni *= CHAR_TYPE_SIZE; > - unsigned align1 = get_pointer_alignment (arg1); > - unsigned align2 = get_pointer_alignment (arg2); > - unsigned align = MIN (align1, align2); > - scalar_int_mode mode; > - if (int_mode_for_size (leni, 1).exists (&mode) > - && (align >= leni || !targetm.slow_unaligned_access (mode, align))) > - { > - location_t loc = gimple_location (stmt); > - tree type, off; > - type = build_nonstandard_integer_type (leni, 1); > - gcc_assert (known_eq (GET_MODE_BITSIZE (TYPE_MODE (type)), leni)); > - tree ptrtype = build_pointer_type_for_mode (char_type_node, > - ptr_mode, true); > - off = build_int_cst (ptrtype, 0); > - arg1 = build2_loc (loc, MEM_REF, type, arg1, off); > - arg2 = build2_loc (loc, MEM_REF, type, arg2, off); > - tree tem1 = fold_const_aggregate_ref (arg1); > - if (tem1) > - arg1 = tem1; > - tree tem2 = fold_const_aggregate_ref (arg2); > - if (tem2) > - arg2 = tem2; > - res = fold_convert_loc (loc, TREE_TYPE (res), > - fold_build2_loc (loc, NE_EXPR, > - boolean_type_node, > - arg1, arg2)); > - gimplify_and_update_call_from_tree (&m_gsi, res); > - return true; > - } > - } > - > - gimple_call_set_fndecl (stmt, builtin_decl_explicit (BUILT_IN_MEMCMP_EQ)); > - return true; > -} > - > /* Given strinfo IDX for ARG, sets LENRNG[] to the range of lengths > of the string(s) referenced by ARG if it can be determined. > If the length cannot be determined, sets *SIZE to the size of > @@ -5520,10 +5461,6 @@ strlen_pass::check_and_optimize_call (bool *zero_write) > if (handle_builtin_memset (zero_write)) > return false; > break; > - case BUILT_IN_MEMCMP: > - if (handle_builtin_memcmp ()) > - return false; > - break; > case BUILT_IN_STRCMP: > case BUILT_IN_STRNCMP: > if (handle_builtin_string_cmp ()) > -- > 2.43.0 >