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/builtins.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/builtins.c')
-rw-r--r-- | gcc/builtins.c | 83 |
1 files changed, 38 insertions, 45 deletions
diff --git a/gcc/builtins.c b/gcc/builtins.c index 931d4a6..d519176 100644 --- a/gcc/builtins.c +++ b/gcc/builtins.c @@ -3671,53 +3671,24 @@ expand_cmpstr (insn_code icode, rtx target, rtx arg1_rtx, rtx arg2_rtx, return NULL_RTX; } -/* Try to expand cmpstrn or cmpmem operation ICODE with the given operands. - ARG3_TYPE is the type of ARG3_RTX. Return the result rtx on success, - otherwise return null. */ - -static rtx -expand_cmpstrn_or_cmpmem (insn_code icode, rtx target, rtx arg1_rtx, - rtx arg2_rtx, tree arg3_type, rtx arg3_rtx, - HOST_WIDE_INT align) -{ - machine_mode insn_mode = insn_data[icode].operand[0].mode; - - if (target && (!REG_P (target) || HARD_REGISTER_P (target))) - target = NULL_RTX; - - struct expand_operand ops[5]; - create_output_operand (&ops[0], target, insn_mode); - create_fixed_operand (&ops[1], arg1_rtx); - create_fixed_operand (&ops[2], arg2_rtx); - create_convert_operand_from (&ops[3], arg3_rtx, TYPE_MODE (arg3_type), - TYPE_UNSIGNED (arg3_type)); - create_integer_operand (&ops[4], align); - if (maybe_expand_insn (icode, 5, ops)) - return ops[0].value; - return NULL_RTX; -} - /* Expand expression EXP, which is a call to the memcmp built-in function. Return NULL_RTX if we failed and the caller should emit a normal call, - otherwise try to get the result in TARGET, if convenient. */ + otherwise try to get the result in TARGET, if convenient. + RESULT_EQ is true if we can relax the returned value to be either zero + or nonzero, without caring about the sign. */ static rtx -expand_builtin_memcmp (tree exp, rtx target) +expand_builtin_memcmp (tree exp, rtx target, bool result_eq) { if (!validate_arglist (exp, POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE)) return NULL_RTX; - /* Note: The cmpstrnsi pattern, if it exists, is not suitable for - implementing memcmp because it will stop if it encounters two - zero bytes. */ - insn_code icode = direct_optab_handler (cmpmem_optab, SImode); - if (icode == CODE_FOR_nothing) - return NULL_RTX; - tree arg1 = CALL_EXPR_ARG (exp, 0); tree arg2 = CALL_EXPR_ARG (exp, 1); tree len = CALL_EXPR_ARG (exp, 2); + machine_mode mode = TYPE_MODE (TREE_TYPE (exp)); + location_t loc = EXPR_LOCATION (exp); unsigned int arg1_align = get_pointer_alignment (arg1) / BITS_PER_UNIT; unsigned int arg2_align = get_pointer_alignment (arg2) / BITS_PER_UNIT; @@ -3726,22 +3697,38 @@ expand_builtin_memcmp (tree exp, rtx target) if (arg1_align == 0 || arg2_align == 0) return NULL_RTX; - machine_mode mode = TYPE_MODE (TREE_TYPE (exp)); - location_t loc = EXPR_LOCATION (exp); rtx arg1_rtx = get_memory_rtx (arg1, len); rtx arg2_rtx = get_memory_rtx (arg2, len); - rtx arg3_rtx = expand_normal (fold_convert_loc (loc, sizetype, len)); + rtx len_rtx = expand_normal (fold_convert_loc (loc, sizetype, len)); /* Set MEM_SIZE as appropriate. */ - if (CONST_INT_P (arg3_rtx)) + if (CONST_INT_P (len_rtx)) { - set_mem_size (arg1_rtx, INTVAL (arg3_rtx)); - set_mem_size (arg2_rtx, INTVAL (arg3_rtx)); + set_mem_size (arg1_rtx, INTVAL (len_rtx)); + set_mem_size (arg2_rtx, INTVAL (len_rtx)); } - rtx result = expand_cmpstrn_or_cmpmem (icode, target, arg1_rtx, arg2_rtx, - TREE_TYPE (len), arg3_rtx, - MIN (arg1_align, arg2_align)); + by_pieces_constfn constfn = NULL; + + const char *src_str = c_getstr (arg1); + if (src_str == NULL) + src_str = c_getstr (arg2); + else + std::swap (arg1_rtx, arg2_rtx); + + /* If SRC is a string constant and block move would be done + by pieces, we can avoid loading the string from memory + and only stored the computed constants. */ + if (src_str + && CONST_INT_P (len_rtx) + && (unsigned HOST_WIDE_INT) INTVAL (len_rtx) <= strlen (src_str) + 1) + constfn = builtin_memcpy_read_str; + + rtx result = emit_block_cmp_hints (arg1_rtx, arg2_rtx, len_rtx, + TREE_TYPE (len), target, + result_eq, constfn, + CONST_CAST (char *, src_str)); + if (result) { /* Return the value in the proper mode for this function. */ @@ -6073,9 +6060,15 @@ expand_builtin (tree exp, rtx target, rtx subtarget, machine_mode mode, case BUILT_IN_BCMP: case BUILT_IN_MEMCMP: - target = expand_builtin_memcmp (exp, target); + case BUILT_IN_MEMCMP_EQ: + target = expand_builtin_memcmp (exp, target, fcode == BUILT_IN_MEMCMP_EQ); if (target) return target; + if (fcode == BUILT_IN_MEMCMP_EQ) + { + tree newdecl = builtin_decl_explicit (BUILT_IN_MEMCMP); + TREE_OPERAND (exp, 1) = build_fold_addr_expr (newdecl); + } break; case BUILT_IN_SETJMP: |