diff options
author | Nick Clifton <nickc@redhat.com> | 2011-02-15 17:09:39 +0000 |
---|---|---|
committer | Nick Clifton <nickc@gcc.gnu.org> | 2011-02-15 17:09:39 +0000 |
commit | a45d420abf5125d73bfdc2d2af3753b810c349eb (patch) | |
tree | 060852815ff3bf81b7fef60acee53e79f440a99b /gcc/config/mn10300 | |
parent | 8a73faf108721a76f55441f6d2a3937fff901b36 (diff) | |
download | gcc-a45d420abf5125d73bfdc2d2af3753b810c349eb.zip gcc-a45d420abf5125d73bfdc2d2af3753b810c349eb.tar.gz gcc-a45d420abf5125d73bfdc2d2af3753b810c349eb.tar.bz2 |
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
Diffstat (limited to 'gcc/config/mn10300')
-rw-r--r-- | gcc/config/mn10300/constraints.md | 6 | ||||
-rw-r--r-- | gcc/config/mn10300/mn10300.c | 211 | ||||
-rw-r--r-- | gcc/config/mn10300/mn10300.md | 109 | ||||
-rw-r--r-- | gcc/config/mn10300/predicates.md | 4 |
4 files changed, 190 insertions, 140 deletions
diff --git a/gcc/config/mn10300/constraints.md b/gcc/config/mn10300/constraints.md index a4816c1..c8ee2d4 100644 --- a/gcc/config/mn10300/constraints.md +++ b/gcc/config/mn10300/constraints.md @@ -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." diff --git a/gcc/config/mn10300/mn10300.c b/gcc/config/mn10300/mn10300.c index 5ff8852..0b68f2d 100644 --- a/gcc/config/mn10300/mn10300.c +++ b/gcc/config/mn10300/mn10300.c @@ -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); + if (p == NULL_RTX) + return false; + + /* 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); - lop = get_attr_liw_op (insn); - if (plop != NULL) - * plop = lop; - switch (lop) + 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]); + if (! REG_P (pdata->dest)) + return false; + + if (REG_P (pdata->src)) + return true; + + return allow_consts && satisfies_constraint_O (pdata->src); } -/* Look for conflicts in the operands used in - the potential bundling of the two insns. */ +/* 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 (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))) +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; - /* 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 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) + { + /* 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; + } - if (REGNO (ops[3]) == REGNO (ops[0])) + /* 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 (op1 == LIW_OP_MOV) + 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); diff --git a/gcc/config/mn10300/mn10300.md b/gcc/config/mn10300/mn10300.md index e8d2ae1..3d8e914 100644 --- a/gcc/config/mn10300/mn10300.md +++ b/gcc/config/mn10300/mn10300.md @@ -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,25 +444,26 @@ 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") (const_int 11) (const_int 22)) @@ -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)))] ) diff --git a/gcc/config/mn10300/predicates.md b/gcc/config/mn10300/predicates.md index 8316990..4c78c51 100644 --- a/gcc/config/mn10300/predicates.md +++ b/gcc/config/mn10300/predicates.md @@ -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)"))) |