re PR target/54236 ([SH] Improve addc and subc insn utilization)

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
This commit is contained in:
Oleg Endo 2013-10-29 20:45:56 +00:00
parent c6a684e36c
commit dd331dd0b5
6 changed files with 444 additions and 4 deletions

View 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

View 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

View File

@ -1841,7 +1841,7 @@
;; 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" ""))
@ -1857,7 +1857,7 @@
;; 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))
@ -1897,7 +1897,7 @@
;; 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" "")))
@ -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_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" "")

View 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

View 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);
}

View File

@ -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;
}