Commit eb11dba2 by Oleg Endo

re PR target/51244 ([SH] Inefficient conditional branch and code around T bit)

	PR target/51244
	* config/sh/sh.md: Add splits for inverted compare and branch
	opportunities.
	(*cmpeqsi_t): New insn.
	(cmpgtsi_t, cmpgesi_t): Swap r and N alternatives.
	(cmpgeusi_t): Use satisfies_constraint_Z.  Emit sett insn in
	replacement insn list and not in the preparation statements.
	(clrt, sett): Add mt_group attribute.

	PR target/51244
	* gcc.target/sh/pr51244-7.c: New.
	* gcc.target/sh/pr51244-8.c: New.
	* gcc.target/sh/pr51244-9.c: New.
	* gcc.target/sh/pr51244-10.c: New.

From-SVN: r190331
parent 3722862e
2012-08-12 Oleg Endo <olegendo@gcc.gnu.org>
PR target/51244
* config/sh/sh.md: Add splits for inverted compare and branch
opportunities.
(*cmpeqsi_t): New insn.
(cmpgtsi_t, cmpgesi_t): Swap r and N alternatives.
(cmpgeusi_t): Use satisfies_constraint_Z. Emit sett insn in
replacement insn list and not in the preparation statements.
(clrt, sett): Add mt_group attribute.
2012-08-12 Marc Glisse <marc.glisse@inria.fr>
PR middle-end/54193
......
......@@ -742,12 +742,6 @@
}
[(set_attr "type" "mt_group")])
;; ??? Perhaps should only accept reg/constant if the register is reg 0.
;; That would still allow reload to create cmpi instructions, but would
;; perhaps allow forcing the constant into a register when that is better.
;; Probably should use r0 for mem/imm compares, but force constant into a
;; register for pseudo/imm compares.
(define_insn "cmpeqsi_t"
[(set (reg:SI T_REG)
(eq:SI (match_operand:SI 0 "arith_reg_operand" "r,z,r")
......@@ -759,24 +753,40 @@
cmp/eq %1,%0"
[(set_attr "type" "mt_group")])
;; FIXME: For some reason, on SH4A and SH2A combine fails to simplify this
;; pattern by itself. What this actually does is:
;; x == 0: (1 >> 0-0) & 1 = 1
;; x != 0: (1 >> 0-x) & 1 = 0
;; Without this the test pr51244-8.c fails on SH2A and SH4A.
(define_insn_and_split "*cmpeqsi_t"
[(set (reg:SI T_REG)
(and:SI (lshiftrt:SI
(const_int 1)
(neg:SI (match_operand:SI 0 "arith_reg_operand" "r")))
(const_int 1)))]
"TARGET_SH1"
"#"
"&& 1"
[(set (reg:SI T_REG) (eq:SI (match_dup 0) (const_int 0)))])
(define_insn "cmpgtsi_t"
[(set (reg:SI T_REG)
(gt:SI (match_operand:SI 0 "arith_reg_operand" "r,r")
(match_operand:SI 1 "arith_reg_or_0_operand" "r,N")))]
(match_operand:SI 1 "arith_reg_or_0_operand" "N,r")))]
"TARGET_SH1"
"@
cmp/gt %1,%0
cmp/pl %0"
cmp/pl %0
cmp/gt %1,%0"
[(set_attr "type" "mt_group")])
(define_insn "cmpgesi_t"
[(set (reg:SI T_REG)
(ge:SI (match_operand:SI 0 "arith_reg_operand" "r,r")
(match_operand:SI 1 "arith_reg_or_0_operand" "r,N")))]
(match_operand:SI 1 "arith_reg_or_0_operand" "N,r")))]
"TARGET_SH1"
"@
cmp/ge %1,%0
cmp/pz %0"
cmp/pz %0
cmp/ge %1,%0"
[(set_attr "type" "mt_group")])
;; FIXME: This is actually wrong. There is no way to literally move a
......@@ -815,6 +825,99 @@
DONE;
})
;; Combine patterns to invert compare and branch operations for which we
;; don't have actual comparison insns. These patterns are used in cases
;; which appear after the initial cbranchsi expansion, which also does
;; some condition inversion.
(define_split
[(set (pc)
(if_then_else (ne (match_operand:SI 0 "arith_reg_operand" "")
(match_operand:SI 1 "arith_reg_or_0_operand" ""))
(label_ref (match_operand 2))
(pc)))
(clobber (reg:SI T_REG))]
"TARGET_SH1"
[(set (reg:SI T_REG) (eq:SI (match_dup 0) (match_dup 1)))
(set (pc) (if_then_else (eq (reg:SI T_REG) (const_int 0))
(label_ref (match_dup 2))
(pc)))])
;; FIXME: Similar to the *cmpeqsi_t pattern above, for some reason, on SH4A
;; and SH2A combine fails to simplify this pattern by itself.
;; What this actually does is:
;; x == 0: (1 >> 0-0) & 1 = 1
;; x != 0: (1 >> 0-x) & 1 = 0
;; Without this the test pr51244-8.c fails on SH2A and SH4A.
(define_split
[(set (pc)
(if_then_else
(eq (and:SI (lshiftrt:SI
(const_int 1)
(neg:SI (match_operand:SI 0 "arith_reg_operand" "")))
(const_int 1))
(const_int 0))
(label_ref (match_operand 2))
(pc)))
(clobber (reg:SI T_REG))]
"TARGET_SH1"
[(set (reg:SI T_REG) (eq:SI (match_dup 0) (const_int 0)))
(set (pc) (if_then_else (eq (reg:SI T_REG) (const_int 0))
(label_ref (match_dup 2))
(pc)))])
(define_split
[(set (pc)
(if_then_else (le (match_operand:SI 0 "arith_reg_operand" "")
(match_operand:SI 1 "arith_reg_or_0_operand" ""))
(label_ref (match_operand 2))
(pc)))
(clobber (reg:SI T_REG))]
"TARGET_SH1"
[(set (reg:SI T_REG) (gt:SI (match_dup 0) (match_dup 1)))
(set (pc) (if_then_else (eq (reg:SI T_REG) (const_int 0))
(label_ref (match_dup 2))
(pc)))])
(define_split
[(set (pc)
(if_then_else (lt (match_operand:SI 0 "arith_reg_operand" "")
(match_operand:SI 1 "arith_reg_or_0_operand" ""))
(label_ref (match_operand 2))
(pc)))
(clobber (reg:SI T_REG))]
"TARGET_SH1"
[(set (reg:SI T_REG) (ge:SI (match_dup 0) (match_dup 1)))
(set (pc) (if_then_else (eq (reg:SI T_REG) (const_int 0))
(label_ref (match_dup 2))
(pc)))])
(define_split
[(set (pc)
(if_then_else (leu (match_operand:SI 0 "arith_reg_operand" "")
(match_operand:SI 1 "arith_reg_operand" ""))
(label_ref (match_operand 2))
(pc)))
(clobber (reg:SI T_REG))]
"TARGET_SH1"
[(set (reg:SI T_REG) (gtu:SI (match_dup 0) (match_dup 1)))
(set (pc) (if_then_else (eq (reg:SI T_REG) (const_int 0))
(label_ref (match_dup 2))
(pc)))])
(define_split
[(set (pc)
(if_then_else (ltu (match_operand:SI 0 "arith_reg_operand" "")
(match_operand:SI 1 "arith_reg_operand" ""))
(label_ref (match_operand 2))
(pc)))
(clobber (reg:SI T_REG))]
"TARGET_SH1"
[(set (reg:SI T_REG) (geu:SI (match_dup 0) (match_dup 1)))
(set (pc) (if_then_else (eq (reg:SI T_REG) (const_int 0))
(label_ref (match_dup 2))
(pc)))])
;; -------------------------------------------------------------------------
;; SImode unsigned integer comparisons
;; -------------------------------------------------------------------------
......@@ -825,12 +928,9 @@
(match_operand:SI 1 "arith_reg_or_0_operand" "rN")))]
"TARGET_SH1"
"cmp/hs %1,%0"
"&& operands[1] == CONST0_RTX (SImode)"
[(pc)]
{
emit_insn (gen_sett ());
DONE;
}
"&& satisfies_constraint_Z (operands[0])"
[(set (reg:SI T_REG) (const_int 1))]
""
[(set_attr "type" "mt_group")])
(define_insn "cmpgtusi_t"
......@@ -5132,13 +5232,14 @@ label:
(define_insn "clrt"
[(set (reg:SI T_REG) (const_int 0))]
"TARGET_SH1"
"clrt")
"clrt"
[(set_attr "type" "mt_group")])
(define_insn "sett"
[(set (reg:SI T_REG) (const_int 1))]
"TARGET_SH1"
"sett")
"sett"
[(set_attr "type" "mt_group")])
;; Use the combine pass to transform sequences such as
;; mov r5,r0
......
2012-08-12 Oleg Endo <olegendo@gcc.gnu.org>
PR target/51244
* gcc.target/sh/pr51244-7.c: New.
* gcc.target/sh/pr51244-8.c: New.
* gcc.target/sh/pr51244-9.c: New.
* gcc.target/sh/pr51244-10.c: New.
2012-08-12 Oleg Endo <olegendo@gcc.gnu.org>
* gcc.target/sh/pr50749-sf-postinc-1.c: Skip for -m3. Don't skip for
-m2e or -m2a.
* gcc.target/sh/pr50749-sf-postinc-3.c: Likewise.
......
/* Check that compare-branch is inverted properly.
In this case the improved bit test is a side effect of compare-branch
inversion patterns, even though the branch condition does not get
inverted here.
Example:
mov.b @(14,r9),r0 -> mov.b @(14,r9),r0
shll r0 cmp/pz r0
subc r0,r0 bt .L192
and #1,r0
tst r0,r0
bt .L195
*/
/* { dg-do compile { target "sh*-*-*" } } */
/* { dg-options "-O2" } */
/* { dg-skip-if "" { "sh*-*-*" } { "-m5*" } { "" } } */
/* { dg-final { scan-assembler-not "shll|subc|and" } } */
int
test_00 (int* p)
{
int nr = 15;
volatile char* addr = (volatile char*)&p[1];
if ((addr[(nr >> 3) ^ 7] & (1 << (nr & 7))) == 0)
return 40;
else
return 50;
}
/* Check that compare-branch is inverted properly.
Example:
clrt -> clrt
subc r0,r6 subc r0,r6
mov r3,r7 mov r3,r7
subc r1,r7 subc r1,r7
mov #0,r1 tst r7,r7
cmp/hi r1,r7 bf .L111
bt .L111 bra .L197
bra .L197
nop
*/
/* { dg-do compile { target "sh*-*-*" } } */
/* { dg-options "-O2" } */
/* { dg-skip-if "" { "sh*-*-*" } { "-m5*" } { "" } } */
/* { dg-final { scan-assembler-not "cmp/hi" } } */
/* { dg-final { scan-assembler-not "mov\t#0" } } */
int other_func (long long);
int
test_00 (unsigned long long a, unsigned long long b)
{
if ((a - b) > 0xFFFFFFFFLL)
return other_func (a - b);
return 20;
}
/* Check that compare-branch is inverted properly.
Example:
mov #1,r0 -> tst r8,r8
neg r8,r1 bt .L47
shad r1,r0
tst #1,r0
bf .L47
*/
/* { dg-do compile { target "sh*-*-*" } } */
/* { dg-options "-O2" } */
/* { dg-skip-if "" { "sh*-*-*" } { "-m5*" } { "" } } */
/* { dg-final { scan-assembler-not "shad|neg" } } */
int test_01_00 (int*, void*);
int
test_01 (int* m, void* v)
{
unsigned long n = (unsigned long)v - 1;
if (!n)
return 50;
if (1 & (1 << n)) /* if n == 0: 1 & (1 << 0) -> true */
return 60;
else /* if n != 0: 1 & (1 << n) -> false */
return -8;
}
/* Check that compare-branch is inverted properly.
Example:
mov.w .L566,r2 -> mov.w .L566,r2
add r11,r2 add r11,r2
mov.l @(12,r2),r7 mov.l @(8,r2),r5
mov.l @(8,r2),r5 mov.l @(12,r2),r2
mov #0,r2 tst r2,r2
cmp/hi r2,r7 bt .L534
bf .L534
*/
/* { dg-do compile { target "sh*-*-*" } } */
/* { dg-options "-O2" } */
/* { dg-skip-if "" { "sh*-*-*" } { "-m5*" } { "" } } */
/* { dg-final { scan-assembler-not "mov\t#0" } } */
static inline unsigned int
test_03_00 (unsigned int x)
{
/* Return unassigned value on purpose. */
unsigned int res;
return res;
}
struct S
{
unsigned int a;
unsigned int b;
};
int test_03 (struct S* i)
{
if ((i->a != 2 && i->a != 3) || i->a > test_03_00 (i->b))
return -5;
return -55;
}
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