Commit 6fb917d9 by Oleg Endo

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

gcc/
	PR target/54236
	* config/sh/predicates.md (t_reg_operand, negt_reg_operand): Allow
	and handle ne and eq codes.
	* config/sh/sh.c (sh_rtx_costs): Adjust matching of tst #imm,r0 insn.
	(sh_recog_treg_set_expr): Early accept negt_reg_operand.  Eearly reject
	CONST_INT_P.  Use reverse_condition.
	(sh_split_treg_set_expr): Likewise.

gcc/testsuite/
	PR target/54236
	* gcc.target/sh/pr54236-1.c (test_09, test_10, test_11): New.
	* gcc.target/sh/pr59533-1.c (test_23, test_24, test_25, test_26,
	test_27): New.
	* gcc.target/sh/pr54236-5.c: New.
	* gcc.target/sh/pr54236-6.c: New.

From-SVN: r228202
parent b81f1ee3
2015-09-28 Oleg Endo <olegendo@gcc.gnu.org>
PR target/54236
* config/sh/predicates.md (t_reg_operand, negt_reg_operand): Allow
and handle ne and eq codes.
* config/sh/sh.c (sh_rtx_costs): Adjust matching of tst #imm,r0 insn.
(sh_recog_treg_set_expr): Early accept negt_reg_operand. Eearly reject
CONST_INT_P. Use reverse_condition.
(sh_split_treg_set_expr): Likewise.
2015-09-28 James Greenhalgh <james.greenhalgh@arm.com>
* config/arm/types.md (type): Add rotate_imm.
......@@ -1158,10 +1158,18 @@
;; A predicate describing the T bit register in any form.
(define_predicate "t_reg_operand"
(match_code "reg,subreg,sign_extend,zero_extend")
(match_code "reg,subreg,sign_extend,zero_extend,ne,eq")
{
switch (GET_CODE (op))
{
case EQ:
return t_reg_operand (XEXP (op, 0), GET_MODE (XEXP (op, 0)))
&& XEXP (op, 1) == const1_rtx;
case NE:
return t_reg_operand (XEXP (op, 0), GET_MODE (XEXP (op, 0)))
&& XEXP (op, 1) == const0_rtx;
case REG:
return REGNO (op) == T_REG;
......@@ -1183,13 +1191,21 @@
;; A predicate describing a negated T bit register.
(define_predicate "negt_reg_operand"
(match_code "subreg,xor")
(match_code "subreg,xor,ne,eq")
{
switch (GET_CODE (op))
{
case EQ:
return t_reg_operand (XEXP (op, 0), GET_MODE (XEXP (op, 0)))
&& XEXP (op, 1) == const0_rtx;
case NE:
return t_reg_operand (XEXP (op, 0), GET_MODE (XEXP (op, 0)))
&& XEXP (op, 1) == const1_rtx;
case XOR:
return t_reg_operand (XEXP (op, 0), GET_MODE (XEXP (op, 0)))
&& satisfies_constraint_M (XEXP (op, 1));
&& XEXP (op, 1) == const1_rtx;
case SUBREG:
return negt_reg_operand (XEXP (op, 0), GET_MODE (XEXP (op, 0)));
......
......@@ -3592,13 +3592,12 @@ sh_rtx_costs (rtx x, machine_mode mode ATTRIBUTE_UNUSED, int outer_code,
case EQ:
/* An and with a constant compared against zero is
most likely going to be a TST #imm, R0 instruction.
Notice that this does not catch the zero_extract variants from
the md file. */
most likely going to be a TST #imm, R0 instruction. */
if (XEXP (x, 1) == const0_rtx
&& (GET_CODE (XEXP (x, 0)) == AND
|| (SUBREG_P (XEXP (x, 0))
&& GET_CODE (SUBREG_REG (XEXP (x, 0))) == AND)))
&& ((GET_CODE (XEXP (x, 0)) == AND
|| (SUBREG_P (XEXP (x, 0))
&& GET_CODE (SUBREG_REG (XEXP (x, 0))) == AND))
|| GET_CODE (XEXP (x, 0)) == ZERO_EXTRACT))
{
*total = 1;
return true;
......@@ -14200,7 +14199,8 @@ sh_recog_treg_set_expr (rtx op, machine_mode mode)
return false;
/* Early accept known possible operands before doing recog. */
if (op == const0_rtx || op == const1_rtx || t_reg_operand (op, mode))
if (op == const0_rtx || op == const1_rtx || t_reg_operand (op, mode)
|| negt_reg_operand (op, mode))
return true;
/* Early reject impossible operands before doing recog.
......@@ -14209,8 +14209,8 @@ sh_recog_treg_set_expr (rtx op, machine_mode mode)
such as lower-subreg will bail out. Some insns such as SH4A movua are
done with UNSPEC, so must reject those, too, or else it would result
in an invalid reg -> treg move. */
if (register_operand (op, mode) || memory_operand (op, mode)
|| sh_unspec_insn_p (op))
if (CONST_INT_P (op) || register_operand (op, mode)
|| memory_operand (op, mode) || sh_unspec_insn_p (op))
return false;
if (!can_create_pseudo_p ())
......@@ -14230,26 +14230,30 @@ sh_recog_treg_set_expr (rtx op, machine_mode mode)
SET_PREV_INSN (i) = NULL;
SET_NEXT_INSN (i) = NULL;
/* If the comparison op doesn't have a result mode, set it to SImode. */
machine_mode prev_op_mode = GET_MODE (op);
if (COMPARISON_P (op) && prev_op_mode == VOIDmode)
PUT_MODE (op, SImode);
int result = recog (PATTERN (i), i, 0);
/* It seems there is no insn like that. Create a simple negated
version and try again. If we hit a negated form, we'll allow that
and append a nott sequence when splitting out the insns. Insns that
do the split can then remove the trailing nott if they know how to
deal with it. */
if (result < 0 && GET_CODE (op) == EQ)
/* It seems there is no insn like that. Create a negated version and
try again. If we hit a negated form, we'll allow that and append a
nott sequence when splitting out the insns. Insns that do the split
can then remove the trailing nott if they know how to deal with it. */
if (result < 0 && COMPARISON_P (op))
{
PUT_CODE (op, NE);
result = recog (PATTERN (i), i, 0);
PUT_CODE (op, EQ);
}
if (result < 0 && GET_CODE (op) == NE)
{
PUT_CODE (op, EQ);
machine_mode cmp_mode = GET_MODE (XEXP (op, 0));
if (cmp_mode == VOIDmode)
cmp_mode = GET_MODE (XEXP (op, 1));
rtx_code prev_code = GET_CODE (op);
PUT_CODE (op, reverse_condition (GET_CODE (op)));
result = recog (PATTERN (i), i, 0);
PUT_CODE (op, NE);
PUT_CODE (op, prev_code);
}
PUT_MODE (op, prev_op_mode);
recog_data = prev_recog_data;
return result >= 0;
}
......@@ -14350,36 +14354,42 @@ sh_split_treg_set_expr (rtx x, rtx_insn* curr_insn)
fprintf (dump_file, "\n");
}
/* If the insn is not found, we will try a negated form and append
a nott. */
bool append_nott = false;
/* We are going to invoke recog/split_insns in a re-entrant way and thus
have to capture its current state and restore it afterwards. */
recog_data_d prev_recog_data = recog_data;
int insn_code = recog (PATTERN (i), i, 0);
/* If the insn was not found, see if we matched the negated form before
and append a nott. */
bool append_nott = false;
if (insn_code < 0 && GET_CODE (x) == EQ)
if (negt_reg_operand (x, GET_MODE (x)))
{
PUT_CODE (x, NE);
insn_code = recog (PATTERN (i), i, 0);
if (insn_code >= 0)
append_nott = true;
else
PUT_CODE (x, EQ);
/* This is a normal movt followed by a nott. It will be converted
into a movrt after initial expansion. */
XEXP (PATTERN (i), 1) = get_t_reg_rtx ();
append_nott = true;
}
if (insn_code < 0 && GET_CODE (x) == NE)
else
{
PUT_CODE (x, EQ);
insn_code = recog (PATTERN (i), i, 0);
if (insn_code >= 0)
append_nott = true;
else
PUT_CODE (x, NE);
}
/* If the comparison op doesn't have a mode set, set it to SImode. */
if (COMPARISON_P (x) && GET_MODE (x) == VOIDmode)
PUT_MODE (x, SImode);
int insn_code = recog (PATTERN (i), i, 0);
gcc_assert (insn_code >= 0);
if (insn_code < 0 && COMPARISON_P (x))
{
machine_mode cmp_mode = GET_MODE (XEXP (x, 0));
if (cmp_mode == VOIDmode)
cmp_mode = GET_MODE (XEXP (x, 1));
PUT_CODE (x, reverse_condition (GET_CODE (x)));
insn_code = recog (PATTERN (i), i, 0);
append_nott = true;
}
gcc_assert (insn_code >= 0);
}
/* Try to recursively split the insn. Some insns might refuse to split
any further while we are in the treg_set_expr splitting phase. They
......
2015-09-28 Oleg Endo <olegendo@gcc.gnu.org>
PR target/54236
* gcc.target/sh/pr54236-1.c (test_09, test_10, test_11): New.
* gcc.target/sh/pr59533-1.c (test_23, test_24, test_25, test_26,
test_27): New.
* gcc.target/sh/pr54236-5.c: New.
* gcc.target/sh/pr54236-6.c: New.
2015-09-28 Kyrylo Tkachov <kyrylo.tkachov@arm.com>
PR rtl-optimization/67456
......
......@@ -4,8 +4,8 @@
/* { dg-do compile } */
/* { dg-options "-O1" } */
/* { dg-skip-if "" { "sh*-*-*" } { "-m5*"} { "" } } */
/* { dg-final { scan-assembler-times "addc" 4 } } */
/* { dg-final { scan-assembler-times "subc" 3 } } */
/* { dg-final { scan-assembler-times "addc" 6 } } */
/* { dg-final { scan-assembler-times "subc" 4 } } */
/* { dg-final { scan-assembler-times "sett" 5 } } */
/* { dg-final { scan-assembler-times "negc" 2 { target { ! sh2a } } } } */
......@@ -86,3 +86,25 @@ test_08 (int a)
/* 1x addc, 1x sett */
return (a << 1) + 1;
}
unsigned int
test_09 (unsigned int x)
{
/* 1x tst, 1x addc */
return x - (x != 0);
}
unsigned int
test_10 (unsigned int x)
{
/* 1x tst, 1x subc */
return x + (x == 0);
}
unsigned int
test_11 (unsigned int x)
{
/* 1x tst, 1x addc */
return x + (x != 0);
}
/* Check that addc and subc instructions are generated as expected in
combination with ifcvt. */
/* { dg-do compile } */
/* { dg-options "-O2" } */
/* { dg-final { scan-assembler-times "subc" 4 { target { ! sh2a } } } } */
/* { dg-final { scan-assembler-times "addc" 4 { target { ! sh2a } } } } */
/* { dg-final { scan-assembler-times "not\t" 0 { target { ! sh2a } } } } */
/* { dg-final { scan-assembler-times "subc" 4 { target { sh2a } } } } */
/* { dg-final { scan-assembler-times "addc" 4 { target { sh2a } } } } */
/* { dg-final { scan-assembler-times "nott" 0 { target { sh2a } } } } */
/* { dg-final { scan-assembler-times "tst\t" 4 } } */
/* { dg-final { scan-assembler-times "cmp/eq" 1 } } */
/* { dg-final { scan-assembler-times "cmp/pl" 2 } } */
/* { dg-final { scan-assembler-times "cmp/gt" 1 } } */
/* { dg-final { scan-assembler-not "movt" } } */
/* { dg-final { scan-assembler-not "negc" } } */
/* { dg-final { scan-assembler-not "movrt" } } */
int
test_00 (int x, int y)
{
/* 1x tst, 1x subc */
if (y)
++x;
return x;
}
int
test_01 (int x, int y)
{
/* 1x tst, 1x addc */
if (y)
--x;
return x;
}
int
test_02 (int x, int y)
{
/* 1x tst, 1x addc */
if (!y)
++x;
return x;
}
int
test_03 (int x, int y)
{
/* 1x tst, 1x subc */
if (!y)
--x;
return x;
}
int
test_04 (int x, int y)
{
/* 1x cmp/eq, 1x addc */
if (y == x)
++x;
return x;
}
int
test_05 (int x, int y)
{
/* 1x cmp/gt, 1x subc */
if (y < 4)
++x;
return x;
}
int
test_06 (int x)
{
/* 1x cmp/pl, 1x addc */
return x > 0 ? x + 1 : x;
}
int
test_07 (int x)
{
/* 1x cmp/pl, 1x subc */
return x > 0 ? x - 1 : x;
}
/* In this snippet, there was a missed subc case:
tst #1,r0
movt r0
neg r0,r0
which should be:
tst #1,r0
subc r0,r0
*/
/* { dg-do compile } */
/* { dg-options "-O2" } */
/* { dg-final { scan-assembler-times {tst #1,r0} 1 } } */
/* { dg-final { scan-assembler-times {subc r} 1 } } */
/* { dg-final { scan-assembler-not "movt|not|neg\movrt" } } */
struct inode
{
unsigned int i_gid;
};
struct iattr
{
unsigned int ia_valid;
unsigned int ia_gid;
};
struct task_struct
{
unsigned long flags;
unsigned int cap_effective;
};
extern int in_group_p (unsigned int);
static inline struct task_struct*
get_current (void)
{
struct task_struct *current;
return current;
}
static inline int
capable (int cap)
{
if (((get_current()->cap_effective) & (1 << (cap))))
{
get_current()->flags |= 0x00000100;
return 1;
}
return 0;
}
int
inode_change_ok (struct inode *inode, struct iattr *attr)
{
int retval = -1;
unsigned int ia_valid = attr->ia_valid;
if (ia_valid & 512)
goto fine;
if ((ia_valid & 4)
&& (!in_group_p(attr->ia_gid) && attr->ia_gid != inode->i_gid)
&& !capable(0))
goto error;
fine:
retval = 0;
error:
return retval;
}
......@@ -9,13 +9,13 @@
/* { dg-final { scan-assembler-times "and" 3 } } */
/* { dg-final { scan-assembler-times "extu.b" 5 } } */
/* { dg-final { scan-assembler-times "cmp/pz" 22 { target { ! sh2a } } } } */
/* { dg-final { scan-assembler-times "addc" 3 { target { ! sh2a } } } } */
/* { dg-final { scan-assembler-times "subc" 12 { target { ! sh2a } } } } */
/* { dg-final { scan-assembler-times "cmp/pz" 27 { target { ! sh2a } } } } */
/* { dg-final { scan-assembler-times "addc" 4 { target { ! sh2a } } } } */
/* { dg-final { scan-assembler-times "subc" 16 { target { ! sh2a } } } } */
/* { dg-final { scan-assembler-times "cmp/pz" 20 { target { sh2a } } } } */
/* { dg-final { scan-assembler-times "addc" 5 { target { sh2a } } } } */
/* { dg-final { scan-assembler-times "subc" 10 { target { sh2a } } } } */
/* { dg-final { scan-assembler-times "cmp/pz" 25 { target { sh2a } } } } */
/* { dg-final { scan-assembler-times "addc" 6 { target { sh2a } } } } */
/* { dg-final { scan-assembler-times "subc" 14 { target { sh2a } } } } */
/* { dg-final { scan-assembler-times "bld" 2 { target { sh2a } } } } */
int
......@@ -183,3 +183,38 @@ test_22 (int x)
/* 1x cmp/pz, 1x movt */
return (x >> 31) + 1;
}
int
test_23 (int x)
{
/* 1x cmp/pz, 1x subc */
return x < 0 ? x + 1 : x;
}
unsigned int
test_24 (unsigned int x)
{
/* 1x cmp/pz, 1x subc */
return x & 0x80000000 ? x + 1 : x;
}
unsigned int
test_25 (unsigned int x)
{
/* 1x cmp/pz, 1x subc */
return x >> 31 ? x + 1 : x;
}
int
test_26 (int x)
{
/* 1x cmp/pz, 1x subc */
return x >> 31 ? x + 1 : x;
}
int
test_27 (int x, int y, int z)
{
/* 1x cmp/pz, 1x addc */
return 1 - ((x >> 4) < 0) + z;
}
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