From: Oleg Endo Date: Thu, 26 Feb 2015 19:14:23 +0000 (+0000) Subject: re PR target/61142 ([SH] QImode/HImode @(R0,Rm),Rn does not load to Rn = R0) X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=dac2637b751b72612d909b5cc78ed06d6c9f8d9a;p=gcc.git re PR target/61142 ([SH] QImode/HImode @(R0,Rm),Rn does not load to Rn = R0) gcc/ PR target/61142 * config/sh/sh.c (sh_check_add_incdec_notes): New function. * config/sh/sh-protos.h (sh_check_add_incdec_notes): Declare it. * config/sh/predicates.md (const_logical_operand): New predicate. * config/sh/sh.md: Add new peephole2 patterns. From-SVN: r221026 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 4fa8ad66478..4e8f5478b46 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,11 @@ +2015-02-26 Oleg Endo + + PR target/61142 + * config/sh/sh.c (sh_check_add_incdec_notes): New function. + * config/sh/sh-protos.h (sh_check_add_incdec_notes): Declare it. + * config/sh/predicates.md (const_logical_operand): New predicate. + * config/sh/sh.md: Add new peephole2 patterns. + 2015-02-26 Marek Polacek PR ipa/65008 diff --git a/gcc/config/sh/predicates.md b/gcc/config/sh/predicates.md index 8447524c67f..8d876b65d4b 100644 --- a/gcc/config/sh/predicates.md +++ b/gcc/config/sh/predicates.md @@ -798,6 +798,12 @@ return 0; }) +;; Returns true if OP is a valid constant source operand for a logical +;; operations tst/and/or/xor #imm,r0. +(define_predicate "const_logical_operand" + (and (match_code "const_int") + (match_test "satisfies_constraint_K08 (op)"))) + ;; Like logical_operand but allows additional constant values which can be ;; done with zero extensions. Used for the second operand of and insns. (define_predicate "logical_and_operand" diff --git a/gcc/config/sh/sh-protos.h b/gcc/config/sh/sh-protos.h index c706e745c19..5a552e2be81 100644 --- a/gcc/config/sh/sh-protos.h +++ b/gcc/config/sh/sh-protos.h @@ -309,6 +309,7 @@ extern bool sh_insn_operands_modified_between_p (rtx_insn* operands_insn, extern bool sh_reg_dead_or_unused_after_insn (const rtx_insn* i, int regno); extern void sh_remove_reg_dead_or_unused_notes (rtx_insn* i, int regno); +extern rtx_insn* sh_check_add_incdec_notes (rtx_insn* i); extern bool sh_in_recog_treg_set_expr (void); extern bool sh_recog_treg_set_expr (rtx op, machine_mode mode); diff --git a/gcc/config/sh/sh.c b/gcc/config/sh/sh.c index 02c617667b2..1cf6ed0a9ca 100644 --- a/gcc/config/sh/sh.c +++ b/gcc/config/sh/sh.c @@ -13757,6 +13757,35 @@ sh_remove_reg_dead_or_unused_notes (rtx_insn* i, int regno) remove_note (i, n); } +/* Given an insn check if it contains any post/pre inc/dec mem operands and + add the REG_INC notes accordingly. + FIXME: This function is very similar to lra.c (add_auto_inc_notes). + FIXME: This function is currently used by peephole2 patterns because + the peephole2 pass does not preserve REG_INC notes. If the notes + are dropped the following passes will do wrong things. */ +rtx_insn* +sh_check_add_incdec_notes (rtx_insn* i) +{ + struct for_each_inc_dec_clb + { + static int func (rtx mem ATTRIBUTE_UNUSED, rtx op ATTRIBUTE_UNUSED, + rtx dest, rtx src ATTRIBUTE_UNUSED, + rtx srcoff ATTRIBUTE_UNUSED, void* arg) + { + gcc_assert (REG_P (dest)); + + rtx_insn* i = (rtx_insn*)arg; + if (find_regno_note (i, REG_INC, REGNO (dest)) == NULL) + add_reg_note (i, REG_INC, dest); + + return 0; + } + }; + + for_each_inc_dec (PATTERN (i), for_each_inc_dec_clb::func, i); + return i; +} + /* Given an op rtx and an insn, try to find out whether the result of the specified op consists only of logical operations on T bit stores. */ bool diff --git a/gcc/config/sh/sh.md b/gcc/config/sh/sh.md index d2f34a3a991..2435ec94a02 100644 --- a/gcc/config/sh/sh.md +++ b/gcc/config/sh/sh.md @@ -14532,6 +14532,179 @@ label: (mem:HI (plus:SI (match_dup 1) (match_dup 2))))] "") +;; extu.bw a,b +;; mov b,c -> extu.bw a,c +(define_peephole2 + [(set (match_operand:SI 0 "arith_reg_dest") + (zero_extend:SI (match_operand:QIHI 1 "arith_reg_operand"))) + (set (match_operand:SI 2 "arith_reg_dest") + (match_dup 0))] + "TARGET_SH1 && peep2_reg_dead_p (2, operands[0])" + [(set (match_dup 2) (zero_extend:SI (match_dup 1)))]) + +;; mov r0,r1 +;; extu.bw r1,r1 -> extu.bw r0,r1 +(define_peephole2 + [(set (match_operand 0 "arith_reg_dest") + (match_operand 1 "arith_reg_operand")) + (set (match_operand:SI 2 "arith_reg_dest") + (zero_extend:SI (match_operand:QIHI 3 "arith_reg_operand")))] + "TARGET_SH1 + && REGNO (operands[0]) == REGNO (operands[3]) + && (REGNO (operands[0]) == REGNO (operands[2]) + || peep2_reg_dead_p (2, operands[0]))" + [(set (match_dup 2) (zero_extend:SI (match_dup 1)))] +{ + operands[1] = gen_rtx_REG (mode, REGNO (operands[1])); +}) + +;; mov a,b +;; mov b,a -> < nop > +(define_peephole2 + [(set (match_operand 0 "register_operand") + (match_operand 1 "register_operand")) + (set (match_operand 2 "register_operand") + (match_operand 3 "register_operand"))] + "TARGET_SH1 + && REGNO (operands[0]) == REGNO (operands[3]) + && REGNO (operands[1]) == REGNO (operands[2]) + && peep2_reg_dead_p (2, operands[3])" + [(const_int 0)]) + +;; mov #3,r4 +;; and r4,r1 -> mov r1,r0 +;; mov r1,r0 and #3,r0 +(define_code_iterator ANDIORXOR [and ior xor]) +(define_peephole2 + [(set (match_operand:SI 0 "register_operand") + (match_operand:SI 1 "const_logical_operand")) + (set (match_operand:SI 2) (ANDIORXOR:SI (match_dup 2) (match_dup 0))) + (set (reg:SI R0_REG) (match_dup 2))] + "TARGET_SH1 + && peep2_reg_dead_p (3, operands[0]) && peep2_reg_dead_p (3, operands[2])" + [(set (reg:SI R0_REG) (match_dup 2)) + (set (reg:SI R0_REG) (ANDIORXOR:SI (reg:SI R0_REG) (match_dup 1)))]) + +;; ... r2,r0 ... r2,r0 +;; or r1,r0 -> or r0,r1 +;; mov r0,r1 +;; (r0 dead) +(define_code_iterator ANDIORXORPLUS [and ior xor plus]) +(define_peephole2 + [(set (match_operand:SI 0 "arith_reg_dest") + (ANDIORXORPLUS:SI (match_dup 0) (match_operand:SI 1 "arith_reg_dest"))) + (set (match_dup 1) (match_dup 0))] + "TARGET_SH1 && peep2_reg_dead_p (2, operands[0])" + [(set (match_dup 1) (ANDIORXORPLUS:SI (match_dup 1) (match_dup 0)))]) + +;; mov r12,r0 +;; add #-48,r0 -> add #-48,r12 +;; mov.l r0,@(4,r10) mov.l r12,@(4,r10) +;; (r12 dead) +(define_peephole2 + [(set (match_operand:SI 0 "arith_reg_dest") + (match_operand:SI 1 "arith_reg_dest")) + (set (match_dup 0) (plus:SI (match_dup 0) + (match_operand:SI 2 "const_int_operand"))) + (set (match_operand:SI 3 "general_movdst_operand") (match_dup 0))] + "TARGET_SH1 + && peep2_reg_dead_p (2, operands[1]) && peep2_reg_dead_p (3, operands[0])" + [(const_int 0)] +{ + emit_insn (gen_addsi3 (operands[1], operands[1], operands[2])); + sh_check_add_incdec_notes (emit_move_insn (operands[3], operands[1])); +}) + +;; mov.l @(r0,r9),r1 +;; mov r1,r0 -> mov @(r0,r9),r0 +(define_peephole2 + [(set (match_operand:SI 0 "arith_reg_dest") + (match_operand:SI 1 "general_movsrc_operand")) + (set (match_operand:SI 2 "arith_reg_dest") + (match_dup 0))] + "TARGET_SH1 && peep2_reg_dead_p (2, operands[0])" + [(const_int 0)] +{ + sh_check_add_incdec_notes (emit_move_insn (operands[2], operands[1])); +}) + +(define_peephole2 + [(set (match_operand:QIHI 0 "register_operand") + (match_operand:QIHI 1 "movsrc_no_disp_mem_operand")) + (set (match_operand:QIHI 2 "register_operand") + (match_dup 0))] + "TARGET_SH1 && peep2_reg_dead_p (2, operands[0])" + [(const_int 0)] +{ + sh_check_add_incdec_notes (emit_move_insn (operands[2], operands[1])); +}) + +(define_peephole2 + [(set (match_operand:SI 0 "arith_reg_dest") + (sign_extend:SI (match_operand:QIHI 1 "movsrc_no_disp_mem_operand"))) + (set (match_operand:SI 2 "arith_reg_dest") + (match_dup 0))] + "TARGET_SH1 && peep2_reg_dead_p (2, operands[0])" + [(const_int 0)] +{ + sh_check_add_incdec_notes (emit_insn (gen_extendsi2 (operands[2], + operands[1]))); +}) + +;; mov.w @(18,r1),r0 (r0 = HImode) +;; mov r0,r1 (r0 = r1 = HImode) mov.w @(18,r1),r0 +;; ... ..,r13 (r13 = SImode) -> ... ..,r13 +;; tst r1,r13 tst r0,r13 +(define_peephole2 + [(set (match_operand 0 "arith_reg_dest") + (match_operand 1 "arith_reg_dest")) + (set (match_operand:SI 2 "arith_reg_dest") + (match_operand:SI 3)) + (set (reg:SI T_REG) + (eq:SI (and:SI (match_operand:SI 4 "arith_reg_operand") + (match_operand:SI 5 "arith_reg_operand")) + (const_int 0)))] + "TARGET_SH1 + && peep2_reg_dead_p (3, operands[0]) + && !reg_overlap_mentioned_p (operands[0], operands[3]) + && (REGNO (operands[0]) == REGNO (operands[4]) + || REGNO (operands[0]) == REGNO (operands[5])) + && (REGNO (operands[2]) == REGNO (operands[4]) + || REGNO (operands[2]) == REGNO (operands[5]))" + [(const_int 0)] +{ + sh_check_add_incdec_notes (emit_move_insn (operands[2], operands[3])); + emit_insn (gen_tstsi_t (operands[2], + gen_rtx_REG (SImode, (REGNO (operands[1]))))); +}) + +;; mov.w @(18,r1),r0 (r0 = HImode) +;; ... ..,r13 (r13 = SImode) mov.w @(18,r1),r0 +;; mov r0,r1 (r0 = r1 = HImode) -> ... ..,r13 +;; tst r1,r13 tst r0,r13 +(define_peephole2 + [(set (match_operand:SI 2 "arith_reg_dest") + (match_operand:SI 3)) + (set (match_operand 0 "arith_reg_dest") + (match_operand 1 "arith_reg_operand")) + (set (reg:SI T_REG) + (eq:SI (and:SI (match_operand:SI 4 "arith_reg_operand") + (match_operand:SI 5 "arith_reg_operand")) + (const_int 0)))] + "TARGET_SH1 + && peep2_reg_dead_p (3, operands[0]) + && !reg_overlap_mentioned_p (operands[0], operands[3]) + && (REGNO (operands[0]) == REGNO (operands[4]) + || REGNO (operands[0]) == REGNO (operands[5])) + && (REGNO (operands[2]) == REGNO (operands[4]) + || REGNO (operands[2]) == REGNO (operands[5]))" + [(const_int 0)] +{ + sh_check_add_incdec_notes (emit_move_insn (operands[2], operands[3])); + emit_insn (gen_tstsi_t (operands[2], + gen_rtx_REG (SImode, (REGNO (operands[1]))))); +}) + (define_peephole [(set (match_operand:SI 0 "register_operand" "=r") (plus:SI (match_dup 0) (match_operand:SI 1 "register_operand" "r")))