]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
re PR target/54236 ([SH] Improve addc and subc insn utilization)
authorOleg Endo <olegendo@gcc.gnu.org>
Tue, 29 Oct 2013 20:45:56 +0000 (20:45 +0000)
committerOleg Endo <olegendo@gcc.gnu.org>
Tue, 29 Oct 2013 20:45:56 +0000 (20:45 +0000)
PR target/54236
* config/sh/sh.md (*addc): Rename existing variations to ...
(*addc_r_r_1, *addc_2r_1, *addc_r_1): ... these.
(*addc_r_lsb, *addc_r_r_lsb, *addc_r_lsb_r, *addc_2r_lsb, *addc_r_msb,
*addc_r_r_msb, *addc_2r_msb): New insn_and_split patterns.
* config/sh/sh.c (addsubcosts): Handle some addc special cases.

PR target/54236
* gcc.target/sh/pr54236-2: New.
* gcc.target/sh/pr54089-6: Add another rotl special case.

From-SVN: r204180

gcc/ChangeLog
gcc/config/sh/sh.c
gcc/config/sh/sh.md
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.target/sh/pr54089-6.c
gcc/testsuite/gcc.target/sh/pr54236-2.c [new file with mode: 0644]

index d7be352cb881773498bee4547a975d7392bf46f8..4c1cc9cac4ecbd3e24a54204869febdc7ea5c81c 100644 (file)
@@ -1,3 +1,12 @@
+2013-10-29  Oleg Endo  <olegendo@gcc.gnu.org>
+
+       PR target/54236
+       * config/sh/sh.md (*addc): Rename existing variations to ...
+       (*addc_r_r_1, *addc_2r_1, *addc_r_1): ... these.
+       (*addc_r_lsb, *addc_r_r_lsb, *addc_r_lsb_r, *addc_2r_lsb, *addc_r_msb,
+       *addc_r_r_msb, *addc_2r_msb): New insn_and_split patterns.
+       * config/sh/sh.c (addsubcosts): Handle some addc special cases.
+
 2013-10-29  Teresa Johnson  <tejohnson@google.com>
 
        PR ipa/58862
index ae4b7a525b6fb041784bc5e0284637244b03b392..167b615e37b1f57ddf9a312e678c7cd02bd64505 100644 (file)
@@ -3159,6 +3159,35 @@ and_xor_ior_costs (rtx x, int code)
 static inline int
 addsubcosts (rtx x)
 {
+  if (GET_MODE (x) == SImode)
+    {
+      /* The addc or subc patterns will eventually become one or two
+        instructions.  Below are some costs for some of the patterns
+        which combine would reject because the costs of the individual
+        insns in the patterns are lower.
+
+        FIXME: It would be much easier if we had something like insn cost
+        attributes and the cost calculation machinery used those attributes
+        in the first place.  This would eliminate redundant recog-like C
+        code to calculate costs of complex patterns.  */
+      rtx op0 = XEXP (x, 0);
+      rtx op1 = XEXP (x, 1);
+
+      if (GET_CODE (x) == PLUS)
+       {
+         if (GET_CODE (op0) == AND
+             && XEXP (op0, 1) == const1_rtx
+             && (GET_CODE (op1) == PLUS
+                 || (GET_CODE (op1) == MULT && XEXP (op1, 1) == const2_rtx)))
+           return 1;
+
+         if (GET_CODE (op0) == MULT && XEXP (op0, 1) == const2_rtx
+             && GET_CODE (op1) == LSHIFTRT
+             && CONST_INT_P (XEXP (op1, 1)) && INTVAL (XEXP (op1, 1)) == 31)
+           return 1;
+       }
+    }
+
   /* On SH1-4 we have only max. SImode operations.
      Double the cost for modes > SImode.  */
   const int cost_scale = !TARGET_SHMEDIA
index db4f8d2974a3b0cfa9d3910ce35eba0e4d62f855..0b952991039d8ff0606c22f4defca061794a9c85 100644 (file)
 
 ;; Split 'reg + reg + 1' into a sett addc sequence, as it can be scheduled
 ;; better, if the sett insn can be done early.
-(define_insn_and_split "*addc"
+(define_insn_and_split "*addc_r_r_1"
   [(set (match_operand:SI 0 "arith_reg_dest" "")
        (plus:SI (plus:SI (match_operand:SI 1 "arith_reg_operand" "")
                          (match_operand:SI 2 "arith_reg_operand" ""))
 
 ;; Left shifts by one are usually done with an add insn to avoid T_REG
 ;; clobbers.  Thus addc can also be used to do something like '(x << 1) + 1'.
-(define_insn_and_split "*addc"
+(define_insn_and_split "*addc_2r_1"
   [(set (match_operand:SI 0 "arith_reg_dest")
        (plus:SI (mult:SI (match_operand:SI 1 "arith_reg_operand")
                          (const_int 2))
 ;; can be scheduled much better since the load of the constant can be
 ;; done earlier, before any comparison insns that store the result in
 ;; the T bit.
-(define_insn_and_split "*addc"
+(define_insn_and_split "*addc_r_1"
   [(set (match_operand:SI 0 "arith_reg_dest" "")
        (plus:SI (match_operand:SI 1 "t_reg_operand" "")
                 (match_operand:SI 2 "arith_reg_operand" "")))
                            (match_dup 1)))
              (clobber (reg:SI T_REG))])])
 
+;; Use shlr-addc to do 'reg + (reg & 1)'.
+(define_insn_and_split "*addc_r_lsb"
+  [(set (match_operand:SI 0 "arith_reg_dest")
+       (plus:SI (and:SI (match_operand:SI 1 "arith_reg_operand")
+                        (const_int 1))
+                (match_operand:SI 2 "arith_reg_operand")))
+   (clobber (reg:SI T_REG))]
+  "TARGET_SH1"
+  "#"
+  "&& can_create_pseudo_p ()"
+  [(parallel [(set (match_dup 0) (plus:SI (reg:SI T_REG) (match_dup 2)))
+             (clobber (reg:SI T_REG))])]
+{
+  emit_insn (gen_shlr (gen_reg_rtx (SImode), operands[1]));
+})
+
+;; Use shlr-addc to do 'reg + reg + (reg & 1)'.
+(define_insn_and_split "*addc_r_r_lsb"
+  [(set (match_operand:SI 0 "arith_reg_dest")
+       (plus:SI (plus:SI (and:SI (match_operand:SI 1 "arith_reg_operand")
+                                 (const_int 1))
+                         (match_operand:SI 2 "arith_reg_operand"))
+                (match_operand:SI 3 "arith_reg_operand")))
+   (clobber (reg:SI T_REG))]
+  "TARGET_SH1"
+  "#"
+  "&& can_create_pseudo_p ()"
+  [(parallel [(set (match_dup 0) (plus:SI (plus:SI (match_dup 2) (match_dup 3))
+                                         (reg:SI T_REG)))
+             (clobber (reg:SI T_REG))])]
+{
+  emit_insn (gen_shlr (gen_reg_rtx (SImode), operands[1]));
+})
+
+;; Canonicalize 'reg + (reg & 1) + reg' into 'reg + reg + (reg & 1)'.
+(define_insn_and_split "*addc_r_lsb_r"
+  [(set (match_operand:SI 0 "arith_reg_dest")
+       (plus:SI (and:SI (match_operand:SI 1 "arith_reg_operand")
+                        (const_int 1))
+                (plus:SI (match_operand:SI 2 "arith_reg_operand")
+                         (match_operand:SI 3 "arith_reg_operand"))))
+   (clobber (reg:SI T_REG))]
+  "TARGET_SH1"
+  "#"
+  "&& can_create_pseudo_p ()"
+  [(parallel [(set (match_dup 0)
+                  (plus:SI (plus:SI (and:SI (match_dup 1) (const_int 1))
+                                    (match_dup 2))
+                           (match_dup 3)))
+             (clobber (reg:SI T_REG))])])
+
+;; Canonicalize '2 * reg + (reg & 1)' into 'reg + reg + (reg & 1)'.
+(define_insn_and_split "*addc_2r_lsb"
+  [(set (match_operand:SI 0 "arith_reg_dest")
+       (plus:SI (and:SI (match_operand:SI 1 "arith_reg_operand")
+                        (const_int 1))
+                (mult:SI (match_operand:SI 2 "arith_reg_operand")
+                         (const_int 2))))
+   (clobber (reg:SI T_REG))]
+  "TARGET_SH1"
+  "#"
+  "&& can_create_pseudo_p ()"
+  [(parallel [(set (match_dup 0)
+                  (plus:SI (plus:SI (and:SI (match_dup 1) (const_int 1))
+                                    (match_dup 2))
+                           (match_dup 2)))
+             (clobber (reg:SI T_REG))])])
+
+;; Use shll-addc to do 'reg + ((unsigned int)reg >> 31)'.
+(define_insn_and_split "*addc_r_msb"
+  [(set (match_operand:SI 0 "arith_reg_dest")
+       (plus:SI (lshiftrt:SI (match_operand:SI 1 "arith_reg_operand")
+                             (const_int 31))
+                (match_operand:SI 2 "arith_reg_operand")))
+   (clobber (reg:SI T_REG))]
+  "TARGET_SH1"
+  "#"
+  "&& can_create_pseudo_p ()"
+  [(parallel [(set (match_dup 0) (plus:SI (reg:SI T_REG) (match_dup 2)))
+             (clobber (reg:SI T_REG))])]
+{
+  emit_insn (gen_shll (gen_reg_rtx (SImode), operands[1]));
+})
+
+;; Use shll-addc to do 'reg + reg + ((unsigned int)reg >> 31)'.
+(define_insn_and_split "*addc_r_r_msb"
+  [(set (match_operand:SI 0 "arith_reg_dest")
+       (plus:SI (plus:SI (lshiftrt:SI (match_operand:SI 1 "arith_reg_operand")
+                                      (const_int 31))
+                         (match_operand:SI 2 "arith_reg_operand"))
+                (match_operand:SI 3 "arith_reg_operand")))
+   (clobber (reg:SI T_REG))]
+  "TARGET_SH1"
+  "#"
+  "&& can_create_pseudo_p ()"
+  [(parallel [(set (match_dup 0) (plus:SI (plus:SI (match_dup 2) (match_dup 3))
+                                         (reg:SI T_REG)))
+             (clobber (reg:SI T_REG))])]
+{
+  emit_insn (gen_shll (gen_reg_rtx (SImode), operands[1]));
+})
+
+;; Canonicalize '2 * reg + ((unsigned int)reg >> 31)'
+;; into 'reg + reg + (reg & 1)'.
+(define_insn_and_split "*addc_2r_msb"
+  [(set (match_operand:SI 0 "arith_reg_dest")
+       (plus:SI (mult:SI (match_operand:SI 1 "arith_reg_operand")
+                         (const_int 2))
+                (lshiftrt:SI (match_operand:SI 2 "arith_reg_operand")
+                             (const_int 31))))
+   (clobber (reg:SI T_REG))]
+  "TARGET_SH1"
+  "#"
+  "&& can_create_pseudo_p ()"
+  [(parallel [(set (match_dup 0)
+                  (plus:SI (plus:SI (lshiftrt:SI (match_dup 2) (const_int 31))
+                                    (match_dup 1))
+                           (match_dup 1)))
+             (clobber (reg:SI T_REG))])])
+
 (define_expand "addsi3"
   [(set (match_operand:SI 0 "arith_reg_operand" "")
        (plus:SI (match_operand:SI 1 "arith_operand" "")
index 3dfbac7a77b074ff35174d8b244fa3c502c8b56f..0f5f02b8c0457e99ebbc48e96e334929040526d1 100644 (file)
@@ -1,3 +1,9 @@
+2013-10-29  Oleg Endo  <olegendo@gcc.gnu.org>
+
+       PR target/54236
+       * gcc.target/sh/pr54236-2: New.
+       * gcc.target/sh/pr54089-6: Add another rotl special case.
+
 2013-10-29  Paul Thomas  <pault@gcc.gnu.org>
 
        PR fortran 58793
index a12a0e93044cb9fc02ab2467530072d80cc5220b..629a764418642d79b23329ddf667cb88dfcaad41 100644 (file)
@@ -3,7 +3,7 @@
 /* { dg-options "-O1" } */
 /* { dg-skip-if "" { "sh*-*-*" } { "-m5*" } { "" } }  */
 /* { dg-final { scan-assembler-times "rotr" 2 } } */
-/* { dg-final { scan-assembler-times "rotl" 2 } } */
+/* { dg-final { scan-assembler-times "rotl" 3 } } */
 
 int
 test_00 (int a)
@@ -28,3 +28,9 @@ test_03 (int a)
 {
   return ((a >> 1) & 0x7FFFFFFF) | (a << 31);
 }
+
+int
+test_04 (int a)
+{
+  return a + a + ((a >> 31) & 1);
+}
diff --git a/gcc/testsuite/gcc.target/sh/pr54236-2.c b/gcc/testsuite/gcc.target/sh/pr54236-2.c
new file mode 100644 (file)
index 0000000..afcd338
--- /dev/null
@@ -0,0 +1,270 @@
+/* Tests to check the utilization of the addc instruction in special cases.
+   If everything works as expected we won't see any movt instructions in
+   these cases.  */
+/* { dg-do compile { target "sh*-*-*" } } */
+/* { dg-options "-O1" } */
+/* { dg-skip-if "" { "sh*-*-*" } { "-m5*"} { "" } } */
+/* { dg-final { scan-assembler-times "addc" 37 } } */
+/* { dg-final { scan-assembler-times "shlr" 23 } } */
+/* { dg-final { scan-assembler-times "shll" 14 } } */
+/* { dg-final { scan-assembler-times "add\t" 12 } } */
+/* { dg-final { scan-assembler-not "movt" } } */
+
+int
+test_000 (int a, int c, int b, int d)
+{
+  // 1x shlr, 1x addc
+  return a + (b & 1);
+}
+
+int
+test_001 (int a, int c, int b, int d)
+{
+  // 1x shlr, 1x addc
+  return a + b + (c & 1);
+}
+
+int
+test_002 (int a, int c, int b, int d)
+{
+  // 1x shlr, 1x add, 1x addc
+  return a + b + c + (d & 1);
+}
+
+int
+test_003 (int a, int c, int b, int d)
+{
+  // 1x shlr, 1x addc
+  return (b & 1) + a;
+}
+
+int
+test_004 (int a, int c, int b, int d)
+{
+  // 1x shlr, 1x addc
+  return a + (c & 1) + b;
+}
+
+int
+test_005 (int a, int c, int b, int d)
+{
+  // 1x shlr, 1x add, 1x addc
+  return a + b + (d & 1) + c;
+}
+
+int
+test_006 (int a, int c, int b, int d)
+{
+  // 1x shlr, 1x addc
+  return (c & 1) + a + b;
+}
+
+int
+test_007 (int a, int c, int b, int d)
+{
+  // 1x shlr, 1x add, 1x addc
+  return a + (d & 1) + b + c;
+}
+
+int
+test_008 (int a, int c, int b, int d)
+{
+  // 1x shlr, 1x add, 1x addc
+  return (d & 1) + a + b + c;
+}
+
+int
+test_009 (int a, int c, int b, int d)
+{
+  // 1x shlr, 1x addc
+  return a + b + (b & 1);
+}
+
+int
+test_010 (int a, int c, int b, int d)
+{
+  // 1x shlr, 1x addc
+  return a + (b & 1) + b;
+}
+
+int
+test_011 (int a, int c, int b, int d)
+{
+  // 1x shlr, 1x addc
+  return (b & 1) + a + b;
+}
+
+int
+test_012 (int a, int c, int b, int d)
+{
+  // 1x shlr, 1x add, 1x addc
+  return a + b + d + (b & 1);
+}
+
+int
+test_013 (int a, int c, int b, int d)
+{
+  // 1x shlr, 1x add, 1x addc
+  return a + d + (b & 1) + b;
+}
+
+int
+test_014 (int a, int c, int b, int d)
+{
+  // 1x shlr, 1x add, 1x addc
+  return a + (b & 1) + d + b;
+}
+
+int
+test_015 (int a, int c, int b, int d)
+{
+  // 1x shlr, 1x add, 1x addc
+  return (b & 1) + a + d + b;
+}
+
+int
+test_016 (int a, int b, int c, int d)
+{
+  // 1x shlr, 1x addc
+  return a + (a & 1);
+}
+
+int
+test_017 (int a, int b, int c, int d)
+{
+  // 1x shlr, 1x addc
+  return a + a + (a & 1);
+}
+
+int
+test_018 (int a, int b, int c, int d)
+{
+  // 1x shlr, 1x addc
+  return a + (a & 1) + a;
+}
+
+int
+test_019 (int a, int b, int c, int d)
+{
+  // 1x shlr, 1x addc
+  return (a & 1) + a + a;
+}
+
+int
+test_020 (int a, int b, int c, int d)
+{
+  // 1x shlr, 1x addc
+  return b + b + (a & 1);
+}
+
+int
+test_021 (int a, int b, int c, int d)
+{
+  // 1x shlr, 1x addc
+  return b + (a & 1) + b;
+}
+
+int
+test_022 (int a, int b, int c, int d)
+{
+  // 1x shlr, 1x addc
+  return (a & 1) + b + b;
+}
+
+int
+test_023 (int a, int b, int c, int d)
+{
+  // 1x shll, 1x addc
+  return a + ((b >> 31) & 1);
+}
+
+int
+test_024 (int a, int b, int c, int d)
+{
+  // 1x shll, 1x addc
+  return ((b >> 31) & 1) + a;
+}
+
+int
+test_025 (int a, int b, int c, int d)
+{
+  // 1x shll, 1x addc
+  return ((a >> 31) & 1) + a;
+}
+
+int
+test_026 (int a, int b, int c, int d)
+{
+  // 1x shll, 1x addc
+  return a + ((a >> 31) & 1);
+}
+
+int
+test_027 (int a, int b, int c, int d)
+{
+  // 1x shll, 1x addc
+  return a + b + ((c >> 31) & 1);
+}
+
+int
+test_028 (int a, int b, int c, int d)
+{
+  // 1x shll, 1x addc
+  return a + ((c >> 31) & 1) + b;
+}
+
+int
+test_029 (int a, int b, int c, int d)
+{
+  // 1x shll, 1x addc
+  return ((c >> 31) & 1) + a + b;
+}
+
+int
+test_030 (int a, int b, int c, int d)
+{
+  // 1x shll, 1x addc, 1x add
+  return a + b + c + ((d >> 31) & 1);
+}
+
+int
+test_031 (int a, int b, int c, int d)
+{
+  // 1x shll, 1x addc, 1x add
+  return a + b + ((d >> 31) & 1) + c;
+}
+
+int
+test_032 (int a, int b, int c, int d)
+{
+  // 1x shll, 1x addc, 1x add
+  return a + ((d >> 31) & 1) + b + c;
+}
+
+int
+test_033 (int a, int b, int c, int d)
+{
+  // 1x shll, 1x addc, 1x add
+  return ((d >> 31) & 1) + a + b + c;
+}
+
+int
+test_034 (int a, int b, int c, int d)
+{
+  // 1x shll, 1x addc
+  return a + a + ((d >> 31) & 1);
+}
+
+int
+test_035 (int a, int b, int c, int d)
+{
+  // 1x shll, 1x addc
+  return a + ((d >> 31) & 1) + a;
+}
+
+int
+test_036 (int a, int b, int c, int d)
+{
+  // 1x shll, 1x addc
+  return ((d >> 31) & 1) + a + a;
+}