diff options
author | Andrew Pinski <andrew.pinski@oss.qualcomm.com> | 2025-08-30 18:52:09 -0700 |
---|---|---|
committer | Andrew Pinski <andrew.pinski@oss.qualcomm.com> | 2025-09-02 14:36:53 -0700 |
commit | 97e77f567c2b21799010fe34e9a05f078abd5b55 (patch) | |
tree | 0a177ebf7b40868679fabadd8cc907009e86ac0d | |
parent | caa1c2f42691d68af4d894a5c3e700ecd2dba080 (diff) | |
download | gcc-97e77f567c2b21799010fe34e9a05f078abd5b55.zip gcc-97e77f567c2b21799010fe34e9a05f078abd5b55.tar.gz gcc-97e77f567c2b21799010fe34e9a05f078abd5b55.tar.bz2 |
Move the folding of memcmpy to memcmpy_eq to fold all builtins
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.
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.pinski@oss.qualcomm.com>
-rw-r--r-- | gcc/tree-ssa-ccp.cc | 35 | ||||
-rw-r--r-- | gcc/tree-ssa-strlen.cc | 71 |
2 files changed, 35 insertions, 71 deletions
diff --git a/gcc/tree-ssa-ccp.cc b/gcc/tree-ssa-ccp.cc index f33cc04..f16b37f 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 3cef33b..ade8c7d 100644 --- a/gcc/tree-ssa-strlen.cc +++ b/gcc/tree-ssa-strlen.cc @@ -3971,73 +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); - - /* Create unaligned types if needed. */ - tree type1 = type, type2 = type; - if (TYPE_ALIGN (type1) > align1) - type1 = build_aligned_type (type1, align1); - if (TYPE_ALIGN (type2) > align2) - type2 = build_aligned_type (type2, align2); - - arg1 = build2_loc (loc, MEM_REF, type1, arg1, off); - arg2 = build2_loc (loc, MEM_REF, type2, 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 @@ -5528,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 ()) |