mn10300.c: Include tm-constrs.h.

* config/mn10300/mn10300.c: Include tm-constrs.h.
	(struct liw_data): New data structure describing an LIW candidate
	instruction.
	(extract_bundle): Use struct liw_data.  Allow small integer
	operands for some instructions.
	(check_liw_constraints): Use struct liw_data.  Remove swapped
	parameter.  Add comments describing the checks.  Fix bug when
	assigning the source of liw1 to the source of liw2.
	(liw_candidate): Delete.  Code moved into extract_bundle.
	(mn10300_bundle_liw): Use struct liw_data.  Check constraints
	before swapping.
	* config/mn10300/predicates.md (liw_operand): New predicate.
	Allows registers and small integer constants.
	* config/mn10300/constraints.md (O): New constraint.  Accetps
	integers in the range -8 to +7 inclusive.
	* config/mn10300/mn10300.md (movesi_internal): Add an alternative
	for moving a small integer into a register.  Give this alternative
	LIW attributes.
	(addsi3, subsi3, cmpsi, lshrsi3, ashrsi3): Likewise.
	(ashlsi3): Likewise, plus give LIW attributes to the alternatives
	using the J,K,L and M constraints,
	(liw): Remove SI mode on second operands to allow for HI and QI
	mode values.
	(cmp_liw, liw_cmp): Likewise.  Plus fix order of operands in the
	instruction.

From-SVN: r170182
This commit is contained in:
Nick Clifton 2011-02-15 17:09:39 +00:00 committed by Nick Clifton
parent 8a73faf108
commit a45d420abf
5 changed files with 223 additions and 145 deletions

View File

@ -1,3 +1,31 @@
2011-02-15 Nick Clifton <nickc@redhat.com>
* config/mn10300/mn10300.c: Include tm-constrs.h.
(struct liw_data): New data structure describing an LIW candidate
instruction.
(extract_bundle): Use struct liw_data. Allow small integer
operands for some instructions.
(check_liw_constraints): Use struct liw_data. Remove swapped
parameter. Add comments describing the checks. Fix bug when
assigning the source of liw1 to the source of liw2.
(liw_candidate): Delete. Code moved into extract_bundle.
(mn10300_bundle_liw): Use struct liw_data. Check constraints
before swapping.
* config/mn10300/predicates.md (liw_operand): New predicate.
Allows registers and small integer constants.
* config/mn10300/constraints.md (O): New constraint. Accetps
integers in the range -8 to +7 inclusive.
* config/mn10300/mn10300.md (movesi_internal): Add an alternative
for moving a small integer into a register. Give this alternative
LIW attributes.
(addsi3, subsi3, cmpsi, lshrsi3, ashrsi3): Likewise.
(ashlsi3): Likewise, plus give LIW attributes to the alternatives
using the J,K,L and M constraints,
(liw): Remove SI mode on second operands to allow for HI and QI
mode values.
(cmp_liw, liw_cmp): Likewise. Plus fix order of operands in the
instruction.
2011-02-15 H.J. Lu <hongjiu.lu@intel.com>
PR middle-end/47725

View File

@ -94,6 +94,12 @@
(ior (match_test "ival == 255")
(match_test "ival == 65535"))))
(define_constraint "O"
"An integer between -8 and +7 inclusive."
(and (match_code "const_int")
(and (match_test "ival >= -8")
(match_test "ival <= 7"))))
;; Floating-point constraints
(define_constraint "G"
"Floating-point zero."

View File

@ -40,6 +40,7 @@
#include "obstack.h"
#include "diagnostic-core.h"
#include "tm_p.h"
#include "tm-constrs.h"
#include "target.h"
#include "target-def.h"
#include "df.h"
@ -2945,91 +2946,143 @@ mn10300_split_and_operand_count (rtx op)
}
}
/* Extract operands and (if requested) the LIW op type from the insn.
Returns false if the insn can't be bundled. */
struct liw_data
{
enum attr_liw slot;
enum attr_liw_op op;
rtx dest;
rtx src;
};
/* Decide if the given insn is a candidate for LIW bundling. If it is then
extract the operands and LIW attributes from the insn and use them to fill
in the liw_data structure. Return true upon success or false if the insn
cannot be bundled. */
static bool
extract_bundle (rtx insn, rtx * ops, enum attr_liw_op * plop)
extract_bundle (rtx insn, struct liw_data * pdata)
{
enum attr_liw_op lop;
rtx p, s;
bool allow_consts = true;
rtx p,s;
gcc_assert (pdata != NULL);
if (insn == NULL_RTX)
return false;
/* Make sure that we are dealing with a simple SET insn. */
p = single_set (insn);
s = SET_SRC (p);
lop = get_attr_liw_op (insn);
if (plop != NULL)
* plop = lop;
if (p == NULL_RTX)
return false;
switch (lop)
/* Make sure that it could go into one of the LIW pipelines. */
pdata->slot = get_attr_liw (insn);
if (pdata->slot == LIW_BOTH)
return false;
pdata->op = get_attr_liw_op (insn);
s = SET_SRC (p);
switch (pdata->op)
{
case LIW_OP_MOV:
ops[0] = SET_DEST (p);
ops[1] = SET_SRC (p);
pdata->dest = SET_DEST (p);
pdata->src = SET_SRC (p);
break;
case LIW_OP_CMP:
ops[0] = XEXP (SET_SRC (p), 0);
ops[1] = XEXP (SET_SRC (p), 1);
pdata->dest = XEXP (SET_SRC (p), 0);
pdata->src = XEXP (SET_SRC (p), 1);
break;
case LIW_OP_NONE:
return false;
case LIW_OP_AND:
case LIW_OP_OR:
case LIW_OP_XOR:
/* The AND, OR and XOR long instruction words only accept register arguments. */
allow_consts = false;
/* Fall through. */
default:
ops[0] = SET_DEST (p);
ops[1] = XEXP (SET_SRC (p), 1);
pdata->dest = SET_DEST (p);
pdata->src = XEXP (SET_SRC (p), 1);
break;
}
return REG_P (ops[0]) && REG_P (ops[1]);
}
/* Look for conflicts in the operands used in
the potential bundling of the two insns. */
static bool
check_liw_constraints (rtx ops[4],
enum attr_liw_op op1,
enum attr_liw_op op2,
bool swapped)
{
/* Look for the two destination registers being the same. This is OK if
the first op is a comparison op, since it will compare the value prior
to the completion of the second op. */
if (REGNO (ops[0]) == REGNO (ops[2])
&& ( (! swapped && op1 != LIW_OP_CMP)
|| (swapped && op2 != LIW_OP_CMP)))
if (! REG_P (pdata->dest))
return false;
/* Look for the source of the second op being the destination of the first op.
Nomrally this will prevent the bundling since GCC has generated sequential
operations and the LIW opcodes are executed in parallel. But if the first
opcode is a MOV, we can copy its source to the second ops source. */
if (swapped)
return REGNO (ops[1]) != REGNO (ops[2]);
if (REG_P (pdata->src))
return true;
if (REGNO (ops[3]) == REGNO (ops[0]))
return allow_consts && satisfies_constraint_O (pdata->src);
}
/* Make sure that it is OK to execute LIW1 and LIW2 in parallel. GCC generated
the instructions with the assumption that LIW1 would be executed before LIW2
so we must check for overlaps between their sources and destinations. */
static bool
check_liw_constraints (struct liw_data * pliw1, struct liw_data * pliw2)
{
/* Check for slot conflicts. */
if (pliw2->slot == pliw1->slot && pliw1->slot != LIW_EITHER)
return false;
/* If either operation is a compare, then "dest" is really an input; the real
destination is CC_REG. So these instructions need different checks. */
/* Changing "CMP ; OP" into "CMP | OP" is OK because the comparison will
check its values prior to any changes made by OP. */
if (pliw1->op == LIW_OP_CMP)
{
if (op1 == LIW_OP_MOV)
/* Two sequential comparisons means dead code, which ought to
have been eliminated given that bundling only happens with
optimization. We cannot bundle them in any case. */
gcc_assert (pliw1->op != pliw2->op);
return true;
}
/* Changing "OP ; CMP" into "OP | CMP" does not work if the value being compared
is the destination of OP, as the CMP will look at the old value, not the new
one. */
if (pliw2->op == LIW_OP_CMP)
{
if (REGNO (pliw2->dest) == REGNO (pliw1->dest))
return false;
if (REG_P (pliw2->src))
return REGNO (pliw2->src) != REGNO (pliw1->dest);
return true;
}
/* Changing "OP1 ; OP2" into "OP1 | OP2" does not work if they both write to the
same destination register. */
if (REGNO (pliw2->dest) == REGNO (pliw1->dest))
return false;
/* Changing "OP1 ; OP2" into "OP1 | OP2" generally does not work if the destination
of OP1 is the source of OP2. The exception is when OP1 is a MOVE instruction when
we can replace the source in OP2 with the source of OP1. */
if (REG_P (pliw2->src) && REGNO (pliw2->src) == REGNO (pliw1->dest))
{
if (pliw1->op == LIW_OP_MOV && REG_P (pliw1->src))
{
ops[3] = ops[1];
if (! REG_P (pliw1->src)
&& (pliw2->op == LIW_OP_AND
|| pliw2->op == LIW_OP_OR
|| pliw2->op == LIW_OP_XOR))
return false;
pliw2->src = pliw1->src;
return true;
}
return false;
}
/* Everything else is OK. */
return true;
}
/* Decide if the given insn is a candidate for LIW bundling. For now we just
check that the insn has an LIW attribute. Later on we check operand
constraints and such. */
static bool
liw_candidate (rtx insn)
{
return insn != NULL_RTX
&& single_set (insn) != NULL_RTX
&& get_attr_liw (insn) != LIW_BOTH;
}
/* Combine pairs of insns into LIW bundles. */
static void
@ -3039,61 +3092,41 @@ mn10300_bundle_liw (void)
for (r = get_insns (); r != NULL_RTX; r = next_nonnote_nondebug_insn (r))
{
rtx insn1, insn2, ops[4];
enum attr_liw liw1, liw2;
enum attr_liw_op op1, op2;
bool swapped = false;
rtx insn1, insn2;
struct liw_data liw1, liw2;
insn1 = r;
if (! liw_candidate (insn1))
if (! extract_bundle (insn1, & liw1))
continue;
insn2 = next_nonnote_nondebug_insn (insn1);
if (! liw_candidate (insn2))
if (! extract_bundle (insn2, & liw2))
continue;
liw1 = get_attr_liw (insn1);
if (liw1 == LIW_BOTH)
continue;
liw2 = get_attr_liw (insn2);
if (liw2 == LIW_BOTH)
continue;
if (liw2 == liw1 && liw1 != LIW_EITHER)
/* Check for source/destination overlap. */
if (! check_liw_constraints (& liw1, & liw2))
continue;
/* The scheduler always groups the insns correctly, but not
always in sequence. So, we can do a naive check and expect
it to work. */
if (liw1 == LIW_OP2 || liw2 == LIW_OP1)
if (liw1.slot == LIW_OP2 || liw2.slot == LIW_OP1)
{
rtx r;
enum attr_liw lt;
r = insn1;
insn1 = insn2;
insn2 = r;
lt = liw1;
struct liw_data temp;
temp = liw1;
liw1 = liw2;
liw2 = lt;
swapped = true;
liw2 = temp;
}
if (! extract_bundle (insn1, ops, & op1))
continue;
if (! extract_bundle (insn2, ops + 2, & op2))
continue;
if (! check_liw_constraints (ops, op1, op2, swapped))
continue;
delete_insn (insn2);
if (op1 == LIW_OP_CMP)
insn2 = gen_cmp_liw (ops[2], ops[3], ops[0], ops[1], GEN_INT (op2));
else if (op2 == LIW_OP_CMP)
insn2 = gen_liw_cmp (ops[0], ops[1], ops[2], ops[3], GEN_INT (op1));
if (liw1.op == LIW_OP_CMP)
insn2 = gen_cmp_liw (liw2.dest, liw2.src, liw1.dest, liw1.src,
GEN_INT (liw2.op));
else if (liw2.op == LIW_OP_CMP)
insn2 = gen_liw_cmp (liw1.dest, liw1.src, liw2.dest, liw2.src,
GEN_INT (liw1.op));
else
insn2 = gen_liw (ops[0], ops[2], ops[1], ops[3],
GEN_INT (op1), GEN_INT (op2));
insn2 = gen_liw (liw1.dest, liw2.dest, liw1.src, liw2.src,
GEN_INT (liw1.op), GEN_INT (liw2.op));
insn2 = emit_insn_after (insn2, insn1);
delete_insn (insn1);

View File

@ -419,9 +419,9 @@
(define_insn "*movsi_internal"
[(set (match_operand:SI 0 "nonimmediate_operand"
"=r,r,r,m,r, A,*y,*y,*z,*d")
"=r,r,r,r,m,r, A,*y,*y,*z,*d")
(match_operand:SI 1 "general_operand"
" 0,i,r,r,m,*y, A, i,*d,*z"))]
" 0,O,i,r,r,m,*y, A, i,*d,*z"))]
"register_operand (operands[0], SImode)
|| register_operand (operands[1], SImode)"
{
@ -429,7 +429,8 @@
{
case 0:
return "";
case 1: /* imm-reg*/
case 1: /* imm-reg. */
case 2:
/* See movhi for a discussion of sizes for 8-bit movu. Note that the
24-bit movu is 6 bytes, which is the same size as the full 32-bit
mov form for An and Dn. So again movu is only a win for Rn. */
@ -443,24 +444,25 @@
return "movu %1,%0";
}
/* FALLTHRU */
case 2: /* reg-reg */
case 3: /* reg-mem */
case 4: /* mem-reg */
case 5: /* sp-reg */
case 6: /* reg-sp */
case 7: /* imm-sp */
case 8: /* reg-mdr */
case 9: /* mdr-reg */
case 3: /* reg-reg */
case 4: /* reg-mem */
case 5: /* mem-reg */
case 6: /* sp-reg */
case 7: /* reg-sp */
case 8: /* imm-sp */
case 9: /* reg-mdr */
case 10: /* mdr-reg */
return "mov %1,%0";
default:
gcc_unreachable ();
}
}
[(set_attr "isa" "*,*,*,*,*,*,*,am33,*,*")
(set_attr "liw" "*,*,either,*,*,*,*,*,*,*")
[(set_attr "isa" "*,*,*,*,*,*,*,*,am33,*,*")
(set_attr "liw" "*,either,*,either,*,*,*,*,*,*,*")
(set_attr "liw_op" "mov")
(set_attr_alternative "timings"
[(const_int 11)
(const_int 22)
(const_int 22)
(const_int 11)
(if_then_else (eq_attr "cpu" "am34")
@ -563,14 +565,14 @@
;; ----------------------------------------------------------------------
(define_insn "addsi3"
[(set (match_operand:SI 0 "register_operand" "=r,r,!*y,!r")
(plus:SI (match_operand:SI 1 "register_operand" "%0,0, 0, r")
(match_operand:SI 2 "nonmemory_operand" "r,i, i, r")))
[(set (match_operand:SI 0 "register_operand" "=r,r,r,!*y,!r")
(plus:SI (match_operand:SI 1 "register_operand" "%0,0,0, 0, r")
(match_operand:SI 2 "nonmemory_operand" "r,O,i, i, r")))
(clobber (reg:CC CC_REG))]
""
{ return mn10300_output_add (operands, false); }
[(set_attr "timings" "11,11,11,22")
(set_attr "liw" "either,*,*,*")
[(set_attr "timings" "11,11,11,11,22")
(set_attr "liw" "either,either,*,*,*")
(set_attr "liw_op" "add")]
)
@ -758,19 +760,20 @@
;; ----------------------------------------------------------------------
(define_insn "subsi3"
[(set (match_operand:SI 0 "register_operand" "=r,r,r")
(minus:SI (match_operand:SI 1 "register_operand" "0,0,r")
(match_operand:SI 2 "nonmemory_operand" "r,i,r")))
[(set (match_operand:SI 0 "register_operand" "=r,r,r,r")
(minus:SI (match_operand:SI 1 "register_operand" "0,0,0,r")
(match_operand:SI 2 "nonmemory_operand" "r,O,i,r")))
(clobber (reg:CC CC_REG))]
""
"@
sub %2,%0
sub %2,%0
sub %2,%0
sub %2,%1,%0"
[(set_attr "isa" "*,*,am33")
(set_attr "liw" "either,*,*")
[(set_attr "isa" "*,*,*,am33")
(set_attr "liw" "either,either,*,*")
(set_attr "liw_op" "sub")
(set_attr "timings" "11,11,22")]
(set_attr "timings" "11,11,11,22")]
)
(define_insn "*subsi3_flags"
@ -1374,8 +1377,8 @@
(define_insn "*cmpsi"
[(set (reg CC_REG)
(compare (match_operand:SI 0 "register_operand" "r,r")
(match_operand:SI 1 "nonmemory_operand" "r,i")))]
(compare (match_operand:SI 0 "register_operand" "r,r,r")
(match_operand:SI 1 "nonmemory_operand" "r,O,i")))]
"reload_completed"
{
/* The operands of CMP must be distinct registers. In the case where
@ -1390,8 +1393,9 @@
}
[(set_attr_alternative "timings"
[(if_then_else (eq_attr "cpu" "am34") (const_int 11) (const_int 22))
(if_then_else (eq_attr "cpu" "am34") (const_int 11) (const_int 22))
(if_then_else (eq_attr "cpu" "am34") (const_int 11) (const_int 22))])
(set_attr "liw" "either,*")
(set_attr "liw" "either,either,*")
(set_attr "liw_op" "cmp")]
)
@ -1732,10 +1736,10 @@
;; ----------------------------------------------------------------------
(define_insn "ashlsi3"
[(set (match_operand:SI 0 "register_operand" "=r,D,d,d,D,D,r")
[(set (match_operand:SI 0 "register_operand" "=r,D,d,d,D,D,D,r")
(ashift:SI
(match_operand:SI 1 "register_operand" " 0,0,0,0,0,0,r")
(match_operand:QI 2 "nonmemory_operand" " J,K,M,L,D,i,r")))
(match_operand:SI 1 "register_operand" " 0,0,0,0,0,0,0,r")
(match_operand:QI 2 "nonmemory_operand" " J,K,M,L,D,O,i,r")))
(clobber (reg:CC CC_REG))]
""
"@
@ -1745,42 +1749,45 @@
asl2 %0\;asl2 %0
asl %S2,%0
asl %S2,%0
asl %S2,%0
asl %2,%1,%0"
[(set_attr "isa" "*,*,*,*,*,*,am33")
(set_attr "liw" "*,*,*,*,op2,*,*")
[(set_attr "isa" "*,*,*,*,*,*,*,am33")
(set_attr "liw" "op2,op2,op2,op2,op2,op2,*,*")
(set_attr "liw_op" "asl")
(set_attr "timings" "11,11,22,22,11,11,11")]
(set_attr "timings" "11,11,22,22,11,11,11,11")]
)
(define_insn "lshrsi3"
[(set (match_operand:SI 0 "register_operand" "=D,D,r")
[(set (match_operand:SI 0 "register_operand" "=D,D,D,r")
(lshiftrt:SI
(match_operand:SI 1 "register_operand" "0,0,r")
(match_operand:QI 2 "nonmemory_operand" "D,i,r")))
(match_operand:SI 1 "register_operand" "0,0,0,r")
(match_operand:QI 2 "nonmemory_operand" "D,O,i,r")))
(clobber (reg:CC CC_REG))]
""
"@
lsr %S2,%0
lsr %S2,%0
lsr %S2,%0
lsr %2,%1,%0"
[(set_attr "isa" "*,*,am33")
(set_attr "liw" "op2,*,*")
[(set_attr "isa" "*,*,*,am33")
(set_attr "liw" "op2,op2,*,*")
(set_attr "liw_op" "lsr")]
)
(define_insn "ashrsi3"
[(set (match_operand:SI 0 "register_operand" "=D,D,r")
[(set (match_operand:SI 0 "register_operand" "=D,D,D,r")
(ashiftrt:SI
(match_operand:SI 1 "register_operand" "0,0,r")
(match_operand:QI 2 "nonmemory_operand" "D,i,r")))
(match_operand:SI 1 "register_operand" "0,0,0,r")
(match_operand:QI 2 "nonmemory_operand" "D,O,i,r")))
(clobber (reg:CC CC_REG))]
""
"@
asr %S2,%0
asr %S2,%0
asr %S2,%0
asr %2,%1,%0"
[(set_attr "isa" "*,*,am33")
(set_attr "liw" "op2,*,*")
[(set_attr "isa" "*,*,*,am33")
(set_attr "liw" "op2,op2,*,*")
(set_attr "liw_op" "asr")]
)
@ -2100,12 +2107,12 @@
(define_insn "liw"
[(set (match_operand:SI 0 "register_operand" "=r")
(unspec:SI [(match_dup 0)
(match_operand:SI 2 "register_operand" "r")
(match_operand 2 "liw_operand" "rO")
(match_operand:SI 4 "const_int_operand" "")]
UNSPEC_LIW))
(set (match_operand:SI 1 "register_operand" "=r")
(unspec:SI [(match_dup 1)
(match_operand 3 "register_operand" "r")
(match_operand 3 "liw_operand" "rO")
(match_operand:SI 5 "const_int_operand" "")]
UNSPEC_LIW))]
"TARGET_ALLOW_LIW"
@ -2119,14 +2126,14 @@
(define_insn "cmp_liw"
[(set (reg:CC CC_REG)
(compare:CC (match_operand:SI 2 "register_operand" "r")
(match_operand:SI 3 "register_operand" "r")))
(match_operand 3 "liw_operand" "rO")))
(set (match_operand:SI 0 "register_operand" "=r")
(unspec:SI [(match_dup 0)
(match_operand 1 "register_operand" "r")
(match_operand 1 "liw_operand" "rO")
(match_operand:SI 4 "const_int_operand" "")]
UNSPEC_LIW))]
"TARGET_ALLOW_LIW"
"cmp_%W4 %2, %3, %0, %1"
"cmp_%W4 %3, %2, %1, %0"
[(set (attr "timings") (if_then_else (eq_attr "cpu" "am34")
(const_int 13) (const_int 12)))]
)
@ -2134,14 +2141,14 @@
(define_insn "liw_cmp"
[(set (match_operand:SI 0 "register_operand" "=r")
(unspec:SI [(match_dup 0)
(match_operand:SI 1 "register_operand" "r")
(match_operand 1 "liw_operand" "rO")
(match_operand:SI 4 "const_int_operand" "")]
UNSPEC_LIW))
(set (reg:CC CC_REG)
(compare:CC (match_operand:SI 2 "register_operand" "r")
(match_operand:SI 3 "register_operand" "r")))]
(match_operand 3 "liw_operand" "rO")))]
"TARGET_ALLOW_LIW"
"%W4_cmp %0, %1, %2, %3"
"%W4_cmp %1, %0, %3, %2"
[(set (attr "timings") (if_then_else (eq_attr "cpu" "am34")
(const_int 13) (const_int 12)))]
)

View File

@ -63,3 +63,7 @@
(define_predicate "CCZN_comparison_operator"
(match_code "eq,ne,lt,ge"))
(define_predicate "liw_operand"
(ior (match_operand 0 "register_operand")
(match_test "satisfies_constraint_O (op)")))