re PR target/61142 ([SH] QImode/HImode @(R0,Rm),Rn does not load to Rn = R0)
authorOleg Endo <olegendo@gcc.gnu.org>
Thu, 26 Feb 2015 19:14:23 +0000 (19:14 +0000)
committerOleg Endo <olegendo@gcc.gnu.org>
Thu, 26 Feb 2015 19:14:23 +0000 (19:14 +0000)
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

gcc/ChangeLog
gcc/config/sh/predicates.md
gcc/config/sh/sh-protos.h
gcc/config/sh/sh.c
gcc/config/sh/sh.md

index 4fa8ad664788542c41ce8f50bf3c7fd532a2494c..4e8f5478b46540a957043f073cf9592e16134945 100644 (file)
@@ -1,3 +1,11 @@
+2015-02-26  Oleg Endo  <olegendo@gcc.gnu.org>
+
+       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  <polacek@redhat.com>
 
        PR ipa/65008
index 8447524c67ff08223e2b1d9f858e627f98d29eab..8d876b65d4b669683b76e824d14a530d42887d78 100644 (file)
   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"
index c706e745c19c033b5e6b81086c48f0ed27a4a172..5a552e2be81425b792b1aff76905e3b400b9707c 100644 (file)
@@ -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);
index 02c617667b2b820c6e3138f409d5db587d978e92..1cf6ed0a9cae2c79647bf030aea2bd1dbc648449 100644 (file)
@@ -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
index d2f34a3a9910889afde9bbef3cd8751d15f92ebb..2435ec94a029b6d04b8c7dd7514ef1048163ede5 100644 (file)
@@ -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>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_extend<mode>si2 (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")))