On Wed, Sep 24, 2025 at 11:07 AM Andrew Pinski
<[email protected]> wrote:
>
> This moves from the memcmp->memcmp_eq to forwprop by
> checking PROP_last_full_fold.
>
> Note this means at -Og, we no longer optimize some
> memcmp. That will be fixed when I exchange fab/copyprop
> for a (late) forwprop.
>
> Bootstrapped and tested on x86_64-linux-gnu.
>
> gcc/ChangeLog:
>
> * tree-ssa-ccp.cc (optimize_memcmp_eq): Remove.
> (pass_fold_builtins::execute): Remove handling of memcmp.
> * tree-ssa-forwprop.cc (simplify_builtin_memcmp): Add folding
> of memcmp to memcmp_eq for PROP_last_full_fold.
>
> Signed-off-by: Andrew Pinski <[email protected]>
> ---
> gcc/tree-ssa-ccp.cc | 34 ----------------------------------
> gcc/tree-ssa-forwprop.cc | 10 +++++++++-
> 2 files changed, 9 insertions(+), 35 deletions(-)
>
> diff --git a/gcc/tree-ssa-ccp.cc b/gcc/tree-ssa-ccp.cc
> index c74f7cc9d0c..389525b4be7 100644
> --- a/gcc/tree-ssa-ccp.cc
> +++ b/gcc/tree-ssa-ccp.cc
> @@ -4205,36 +4205,6 @@ 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)
> {
> @@ -4296,10 +4266,6 @@ 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-forwprop.cc b/gcc/tree-ssa-forwprop.cc
> index 4c438a0f86c..917f3d90f6c 100644
> --- a/gcc/tree-ssa-forwprop.cc
> +++ b/gcc/tree-ssa-forwprop.cc
> @@ -1842,7 +1842,15 @@ simplify_builtin_memcmp (gimple_stmt_iterator *gsi_p,
> gcall *stmt)
> return true;
> }
> }
> - return false;
> +
> + /* Replace memcmp with memcmp_eq if the above fails. */
> + if (DECL_FUNCTION_CODE (gimple_call_fndecl (stmt)) == BUILT_IN_MEMCMP_EQ)
> + return false;
> + if (!(cfun->curr_properties & (PROP_last_full_fold)))
> + return false;
The patch is OK. Seeing the above more and more I wonder if we want to abstract
that into an inline function (in gimple-fold.h?), like
fold_before_rtl_expansion_p ()
or so? Similar to the canonicalize_math_p (),
optimize_vectors_before_lowering_p (), etc.
predicates we have in {gimple,generic}-match-head.cc
Richard.
> + gimple_call_set_fndecl (stmt, builtin_decl_explicit (BUILT_IN_MEMCMP_EQ));
> + update_stmt (stmt);
> + return true;
> }
>
> /* Optimizes builtin memchrs for small constant sizes with a const string.
> --
> 2.43.0
>