===================================================================
@@ -1910,6 +1910,126 @@
(match_dup 1)))
(clobber (reg:SI T_REG))])])
+;; Use shlr-addc to do 'reg + (reg & 1)'.
+(define_insn_and_split "*addc"
+ [(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"
+ [(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"
+ [(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"
+ [(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"
+ [(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"
+ [(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"
+ [(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" "")
===================================================================
@@ -3162,6 +3162,35 @@
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
===================================================================
@@ -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;
+}
===================================================================
@@ -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 @@
{
return ((a >> 1) & 0x7FFFFFFF) | (a << 31);
}
+
+int
+test_04 (int a)
+{
+ return a + a + ((a >> 31) & 1);
+}