Commit dd331dd0 by Oleg Endo

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
parent c6a684e3
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
......@@ -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
......
......@@ -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" "")
......
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
......
......@@ -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);
}
/* 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;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment