diff options
author | Bernd Schmidt <bernds@redhat.com> | 2016-06-03 14:20:53 +0000 |
---|---|---|
committer | Bernd Schmidt <bernds@gcc.gnu.org> | 2016-06-03 14:20:53 +0000 |
commit | 36b85e432865a312aa8edc8978e38266e8a0f14c (patch) | |
tree | a37f7aeb86dcb59106ae4cd545a9e74dfaf5f8d7 /gcc/tree-ssa-strlen.c | |
parent | bfeee8acaabebf2eb6d4587731b2a639f530293e (diff) | |
download | gcc-36b85e432865a312aa8edc8978e38266e8a0f14c.zip gcc-36b85e432865a312aa8edc8978e38266e8a0f14c.tar.gz gcc-36b85e432865a312aa8edc8978e38266e8a0f14c.tar.bz2 |
re PR tree-optimization/52171 (memcmp/strcmp/strncmp can be optimized when the result is tested for [in]equality with 0)
PR tree-optimization/52171
* builtins.c (expand_cmpstrn_or_cmpmem): Delete, moved elsewhere.
(expand_builtin_memcmp): New arg RESULT_EQ. All callers changed.
Look for constant strings. Move some code to emit_block_cmp_hints
and use it.
* builtins.def (BUILT_IN_MEMCMP_EQ): New.
* defaults.h (COMPARE_MAX_PIECES): New macro.
* expr.c (move_by_pieces_d, store_by_pieces_d): Remove old structs.
(move_by_pieces_1, store_by_pieces_1, store_by_pieces_2): Remvoe.
(clear_by_pieces_1): Don't declare. Move definition before use.
(can_do_by_pieces): New static function.
(can_move_by_pieces): Use it. Return bool.
(by_pieces_ninsns): Renamed from move_by_pieces_ninsns. New arg
OP. All callers changed. Handle COMPARE_BY_PIECES.
(class pieces_addr); New.
(pieces_addr::pieces_addr, pieces_addr::decide_autoinc,
pieces_addr::adjust, pieces_addr::increment_address,
pieces_addr::maybe_predec, pieces_addr::maybe_postinc): New member
functions for it.
(class op_by_pieces_d): New.
(op_by_pieces_d::op_by_pieces_d, op_by_pieces_d::run): New member
functions for it.
(class move_by_pieces_d, class compare_by_pieces_d,
class store_by_pieces_d): New subclasses of op_by_pieces_d.
(move_by_pieces_d::prepare_mode, move_by_pieces_d::generate,
move_by_pieces_d::finish_endp, store_by_pieces_d::prepare_mode,
store_by_pieces_d::generate, store_by_pieces_d::finish_endp,
compare_by_pieces_d::generate, compare_by_pieces_d::prepare_mode,
compare_by_pieces_d::finish_mode): New member functions.
(compare_by_pieces, emit_block_cmp_via_cmpmem): New static
functions.
(expand_cmpstrn_or_cmpmem): Moved here from builtins.c.
(emit_block_cmp_hints): New function.
(move_by_pieces, store_by_pieces, clear_by_pieces): Rewrite to just
use the newly defined classes.
* expr.h (by_pieces_constfn): New typedef.
(can_store_by_pieces, store_by_pieces): Use it in arg declarations.
(emit_block_cmp_hints, expand_cmpstrn_or_cmpmem): Declare.
(move_by_pieces_ninsns): Don't declare.
(can_move_by_pieces): Change return value to bool.
* target.def (TARGET_USE_BY_PIECES_INFRASTRUCTURE_P): Update docs.
(compare_by_pieces_branch_ratio): New hook.
* target.h (enum by_pieces_operation): Add COMPARE_BY_PIECES.
(by_pieces_ninsns): Declare.
* targethooks.c (default_use_by_pieces_infrastructure_p): Handle
COMPARE_BY_PIECES.
(default_compare_by_pieces_branch_ratio): New function.
* targhooks.h (default_compare_by_pieces_branch_ratio): Declare.
* doc/tm.texi.in (STORE_MAX_PIECES, COMPARE_MAX_PIECES): Document.
* doc/tm.texi: Regenerate.
* tree-ssa-strlen.c: Include "builtins.h".
(handle_builtin_memcmp): New static function.
(strlen_optimize_stmt): Call it for BUILT_IN_MEMCMP.
* tree.c (build_common_builtin_nodes): Create __builtin_memcmp_eq.
testsuite/
PR tree-optimization/52171
* gcc.dg/pr52171.c: New test.
* gcc.target/i386/pr52171.c: New test.
From-SVN: r237069
Diffstat (limited to 'gcc/tree-ssa-strlen.c')
-rw-r--r-- | gcc/tree-ssa-strlen.c | 87 |
1 files changed, 87 insertions, 0 deletions
diff --git a/gcc/tree-ssa-strlen.c b/gcc/tree-ssa-strlen.c index d27b607..5e2d7db 100644 --- a/gcc/tree-ssa-strlen.c +++ b/gcc/tree-ssa-strlen.c @@ -44,6 +44,7 @@ along with GCC; see the file COPYING3. If not see #include "params.h" #include "ipa-chkp.h" #include "tree-hash-traits.h" +#include "builtins.h" /* A vector indexed by SSA_NAME_VERSION. 0 means unknown, positive value is an index into strinfo vector, negative value stands for @@ -1843,6 +1844,88 @@ handle_builtin_memset (gimple_stmt_iterator *gsi) return false; } +/* 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. */ + +static bool +handle_builtin_memcmp (gimple_stmt_iterator *gsi) +{ + gcall *stmt2 = as_a <gcall *> (gsi_stmt (*gsi)); + tree res = gimple_call_lhs (stmt2); + tree arg1 = gimple_call_arg (stmt2, 0); + tree arg2 = gimple_call_arg (stmt2, 1); + tree len = gimple_call_arg (stmt2, 2); + unsigned HOST_WIDE_INT leni; + use_operand_p use_p; + imm_use_iterator iter; + + if (!res) + return true; + + FOR_EACH_IMM_USE_FAST (use_p, iter, res) + { + gimple *ustmt = USE_STMT (use_p); + + if (gimple_code (ustmt) == GIMPLE_ASSIGN) + { + gassign *asgn = as_a <gassign *> (ustmt); + tree_code code = gimple_assign_rhs_code (asgn); + if ((code != EQ_EXPR && code != NE_EXPR) + || !integer_zerop (gimple_assign_rhs2 (asgn))) + return true; + } + else if (gimple_code (ustmt) == GIMPLE_COND) + { + tree_code code = gimple_cond_code (ustmt); + if ((code != EQ_EXPR && code != NE_EXPR) + || !integer_zerop (gimple_cond_rhs (ustmt))) + return true; + } + else + return true; + } + + if (tree_fits_uhwi_p (len) + && (leni = tree_to_uhwi (len)) <= GET_MODE_SIZE (word_mode) + && exact_log2 (leni) != -1) + { + leni *= CHAR_TYPE_SIZE; + unsigned align1 = get_pointer_alignment (arg1); + unsigned align2 = get_pointer_alignment (arg2); + unsigned align = MIN (align1, align2); + machine_mode mode = mode_for_size (leni, MODE_INT, 1); + if (mode != BLKmode + && (align >= leni || !SLOW_UNALIGNED_ACCESS (mode, align))) + { + location_t loc = gimple_location (stmt2); + tree type, off; + type = build_nonstandard_integer_type (leni, 1); + gcc_assert (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 (gsi, res); + return false; + } + } + + gimple_call_set_fndecl (stmt2, builtin_decl_explicit (BUILT_IN_MEMCMP_EQ)); + return false; +} + /* Handle a POINTER_PLUS_EXPR statement. For p = "abcd" + 2; compute associated length, or if p = q + off is pointing to a '\0' character of a string, call @@ -2100,6 +2183,10 @@ strlen_optimize_stmt (gimple_stmt_iterator *gsi) if (!handle_builtin_memset (gsi)) return false; break; + case BUILT_IN_MEMCMP: + if (!handle_builtin_memcmp (gsi)) + return false; + break; default: break; } |