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

PR target/51244
	* config/sh/sh.c (sh_expand_t_scc): Remove SH2A special case
	and use unified expansion logic.
	* config/sh/sh.md (xorsi3_movrt): Rename to movrt.  Move
	closer to the existing movt insn.
	(negc): Rename insn to *negc.  Add new expander.
	(movnegt): Use xor pattern for T bit negation.  Reserve helper
	constant for negc pattern.
	(*movnegt): New insn and splitter.

	PR target/51244
	* gcc.target/sh/pr51244-1.c: New.
	* gcc.target/sh/pr51244-2.c: New.
	* gcc.target/sh/pr51244-3.c: New.

From-SVN: r184966
This commit is contained in:
Oleg Endo 2012-03-05 23:12:20 +00:00
parent 5de724244f
commit 9747719a9c
8 changed files with 176 additions and 44 deletions

View File

@ -1,3 +1,15 @@
2012-03-06 Oleg Endo <olegendo@gcc.gnu.org>
PR target/51244
* config/sh/sh.c (sh_expand_t_scc): Remove SH2A special case
and use unified expansion logic.
* config/sh/sh.md (xorsi3_movrt): Rename to movrt. Move
closer to the existing movt insn.
(negc): Rename insn to *negc. Add new expander.
(movnegt): Use xor pattern for T bit negation. Reserve helper
constant for negc pattern.
(*movnegt): New insn and splitter.
2012-03-05 Bernd Schmidt <bernds@codesourcery.com>
* c-typeck.c (pointer_diff): Check for POINTER_PLUS_EXPR, not

View File

@ -11888,15 +11888,8 @@ sh_expand_t_scc (rtx operands[])
val = INTVAL (op1);
if ((code == EQ && val == 1) || (code == NE && val == 0))
emit_insn (gen_movt (result));
else if (TARGET_SH2A && ((code == EQ && val == 0)
|| (code == NE && val == 1)))
emit_insn (gen_xorsi3_movrt (result));
else if ((code == EQ && val == 0) || (code == NE && val == 1))
{
emit_clobber (result);
emit_insn (gen_subc (result, result, result));
emit_insn (gen_addsi3 (result, result, const1_rtx));
}
emit_insn (gen_movnegt (result));
else if (code == EQ || code == NE)
emit_insn (gen_move_insn (result, GEN_INT (code == NE)));
else

View File

@ -3354,15 +3354,6 @@ label:
xori %1, %2, %0"
[(set_attr "type" "arith_media")])
;; Store the complements of the T bit in a register.
(define_insn "xorsi3_movrt"
[(set (match_operand:SI 0 "arith_reg_dest" "=r")
(xor:SI (reg:SI T_REG)
(const_int 1)))]
"TARGET_SH2A"
"movrt\\t%0"
[(set_attr "type" "arith")])
(define_insn "xordi3"
[(set (match_operand:DI 0 "arith_reg_dest" "=r,r")
(xor:DI (match_operand:DI 1 "arith_reg_operand" "%r,r")
@ -4387,7 +4378,17 @@ label:
;; Unary arithmetic
;; -------------------------------------------------------------------------
(define_insn "negc"
(define_expand "negc"
[(parallel [(set (match_operand:SI 0 "arith_reg_dest" "")
(neg:SI (plus:SI (reg:SI T_REG)
(match_operand:SI 1 "arith_reg_operand" ""))))
(set (reg:SI T_REG)
(ne:SI (ior:SI (reg:SI T_REG) (match_dup 1))
(const_int 0)))])]
""
"")
(define_insn "*negc"
[(set (match_operand:SI 0 "arith_reg_dest" "=r")
(neg:SI (plus:SI (reg:SI T_REG)
(match_operand:SI 1 "arith_reg_operand" "r"))))
@ -9528,6 +9529,13 @@ mov.l\\t1f,r0\\n\\
"movt %0"
[(set_attr "type" "arith")])
(define_insn "movrt"
[(set (match_operand:SI 0 "arith_reg_dest" "=r")
(xor:SI (reg:SI T_REG) (const_int 1)))]
"TARGET_SH2A"
"movrt %0"
[(set_attr "type" "arith")])
(define_expand "cstore4_media"
[(set (match_operand:SI 0 "register_operand" "=r")
(match_operator:SI 1 "sh_float_comparison_operator"
@ -9654,40 +9662,55 @@ mov.l\\t1f,r0\\n\\
DONE;
")
;; sne moves the complement of the T reg to DEST like this:
;; cmp/eq ...
;; mov #-1,temp
;; negc temp,dest
;; This is better than xoring compare result with 1 because it does
;; not require r0 and further, the -1 may be CSE-ed or lifted out of a
;; loop.
;; Move the complement of the T reg to a reg.
;; On SH2A the movrt insn can be used.
;; On anything else than SH2A this has to be done with multiple instructions.
;; One obvious way would be:
;; cmp/eq ...
;; movt r0
;; xor #1,r0
;;
;; However, this puts pressure on r0 in most cases and thus the following is
;; more appealing:
;; cmp/eq ...
;; mov #-1,temp
;; negc temp,dest
;;
;; If the constant -1 can be CSE-ed or lifted out of a loop it effectively
;; becomes a one instruction operation. Moreover, care must be taken that
;; the insn can still be combined with inverted compare and branch code
;; around it.
;; The expander will reserve the constant -1, the insn makes the whole thing
;; combinable, the splitter finally emits the insn if it was not combined
;; away.
;; Notice that when using the negc variant the T bit also gets inverted.
(define_expand "movnegt"
[(set (match_dup 1) (const_int -1))
(parallel [(set (match_operand:SI 0 "" "")
(neg:SI (plus:SI (reg:SI T_REG)
(match_dup 1))))
(set (reg:SI T_REG)
(ne:SI (ior:SI (reg:SI T_REG) (match_dup 1))
(const_int 0)))])]
(parallel [(set (match_operand:SI 0 "arith_reg_dest" "")
(xor:SI (reg:SI T_REG) (const_int 1)))
(use (match_dup 1))])]
""
"
{
operands[1] = gen_reg_rtx (SImode);
}")
})
;; Recognize mov #-1/negc/neg sequence, and change it to movt/add #-1.
;; This prevents a regression that occurred when we switched from xor to
;; mov/neg for sne.
(define_split
[(set (match_operand:SI 0 "arith_reg_dest" "")
(plus:SI (reg:SI T_REG)
(const_int -1)))]
(define_insn_and_split "*movnegt"
[(set (match_operand:SI 0 "arith_reg_dest" "=r")
(xor:SI (reg:SI T_REG) (const_int 1)))
(use (match_operand:SI 1 "arith_reg_operand" "r"))]
"TARGET_SH1"
[(set (match_dup 0) (eq:SI (reg:SI T_REG) (const_int 1)))
(set (match_dup 0) (plus:SI (match_dup 0) (const_int -1)))]
"")
"#"
"&& 1"
[(const_int 0)]
{
if (TARGET_SH2A)
emit_insn (gen_movrt (operands[0]));
else
emit_insn (gen_negc (operands[0], operands[1]));
DONE;
}
[(set_attr "type" "arith")])
(define_expand "cstoresf4"
[(set (match_operand:SI 0 "register_operand" "=r")

View File

@ -1,3 +1,10 @@
2012-03-06 Oleg Endo <olegendo@gcc.gnu.org>
PR target/51244
* gcc.target/sh/pr51244-1.c: New.
* gcc.target/sh/pr51244-2.c: New.
* gcc.target/sh/pr51244-3.c: New.
2012-03-05 Jason Merrill <jason@redhat.com>
PR c++/51930

View File

@ -0,0 +1,31 @@
/* Check that the following code compiles without errors. */
/* { dg-do compile { target "sh*-*-*" } } */
/* { dg-options "-O1" } */
enum { nrrdCenterUnknown, nrrdCenterNode, nrrdCenterCell, nrrdCenterLast };
typedef struct { int size; int center; } NrrdAxis;
typedef struct { int dim; NrrdAxis axis[10]; } Nrrd;
typedef struct { } NrrdKernel;
typedef struct { const NrrdKernel *kernel[10]; int samples[10]; } Info;
void
foo (Nrrd *nout, Nrrd *nin, const NrrdKernel *kernel, const double *parm,
const int *samples, const double *scalings)
{
Info *info;
int d, p, np, center;
for (d=0; d<nin->dim; d++)
{
info->kernel[d] = kernel;
if (samples)
info->samples[d] = samples[d];
else
{
center = _nrrdCenter(nin->axis[d].center);
if (nrrdCenterCell == center)
info->samples[d] = nin->axis[d].size*scalings[d];
else
info->samples[d] = (nin->axis[d].size - 1)*scalings[d] + 1;
}
}
}

View File

@ -0,0 +1,32 @@
/* Check that inverted conditional branch logic does not generate
unnecessary explicit T bit extractions, inversions and
test instructions. */
/* { dg-do compile { target "sh*-*-*" } } */
/* { dg-options "-O1 -mbranch-cost=2" } */
/* { dg-skip-if "" { "sh*-*-*" } { "-m5*"} { "" } } */
/* { dg-final { scan-assembler-not "tst|negc|extu" } } */
int
testfunc_00 (int a, int b, int c, int d)
{
return (a != b || a != d) ? b : c;
}
int
testfunc_01 (int a, char* p, int b, int c)
{
return (a == b && a == c) ? b : c;
}
int
testfunc_02 (int a, char* p, int b, int c)
{
return (a == b && a == c) ? b : c;
}
int
testfunc_03 (int a, char* p, int b, int c)
{
return (a != b && a != c) ? b : c;
}

View File

@ -0,0 +1,18 @@
/* Check that when taking the complement of the T bit using the negc
instruction pattern, the constant -1 is loaded only once.
On SH2A this test is skipped because the movrt instruction is used
to get the complement of the T bit. */
/* { dg-do compile { target "sh*-*-*" } } */
/* { dg-options "-O1 -mbranch-cost=2" } */
/* { dg-skip-if "" { "sh*-*-*" } { "-m5*" "-m2a*" } { "" } } */
/* { dg-final { scan-assembler-times "mov\t#-1" 1 } } */
void
testfunc_00 (int* a, int* b, int c, int d)
{
b[0] = a[0] != c;
b[1] = a[1] != d;
b[2] = a[2] != c;
b[3] = a[3] != d;
}

View File

@ -0,0 +1,16 @@
/* Check that when taking the complement of the T bit on SH2A,
the movrt instruction is being generated. */
/* { dg-do compile { target "sh*-*-*" } } */
/* { dg-options "-O1 -mbranch-cost=2" } */
/* { dg-skip-if "" { "sh*-*-*" } { "*" } { "-m2a*" } } */
/* { dg-final { scan-assembler-times "movrt" 4 } } */
void
testfunc_00 (int* a, int* b, int c, int d)
{
b[0] = a[0] != c;
b[1] = a[1] != d;
b[2] = a[2] != c;
b[3] = a[3] != d;
}