aboutsummaryrefslogtreecommitdiff
path: root/gcc/config
diff options
context:
space:
mode:
authorRichard Henderson <rth@redhat.com>2011-01-19 10:38:56 -0800
committerRichard Henderson <rth@gcc.gnu.org>2011-01-19 10:38:56 -0800
commitbad41521231654dafc67f31cb8abfa47ad09c691 (patch)
treeace1f21241006fb62f9953f7971b5fd323b64fde /gcc/config
parent9efb4993cbbe8ca0ee1ae50e472ac7beb58f13f1 (diff)
downloadgcc-bad41521231654dafc67f31cb8abfa47ad09c691.zip
gcc-bad41521231654dafc67f31cb8abfa47ad09c691.tar.gz
gcc-bad41521231654dafc67f31cb8abfa47ad09c691.tar.bz2
mn10300: Cleanup all arithmetic.
For addition and logicals, define an operation-plus-flags update pattern in preparation for compare elimination. In addition, clean up the way we compare and validate CC_MODEs. Define NEG in terms of NOT; this is smaller and allows a non-clobbering destination alternative. From-SVN: r169010
Diffstat (limited to 'gcc/config')
-rw-r--r--gcc/config/mn10300/mn10300-modes.def2
-rw-r--r--gcc/config/mn10300/mn10300-protos.h7
-rw-r--r--gcc/config/mn10300/mn10300.c480
-rw-r--r--gcc/config/mn10300/mn10300.h2
-rw-r--r--gcc/config/mn10300/mn10300.md1128
-rw-r--r--gcc/config/mn10300/predicates.md16
6 files changed, 685 insertions, 950 deletions
diff --git a/gcc/config/mn10300/mn10300-modes.def b/gcc/config/mn10300/mn10300-modes.def
index 8bcffcd..832663e 100644
--- a/gcc/config/mn10300/mn10300-modes.def
+++ b/gcc/config/mn10300/mn10300-modes.def
@@ -19,4 +19,6 @@
the Free Software Foundation, , Inc., 51 Franklin Street - Fifth
Floor, Boston, MA 02110-1301, USA. */
+CC_MODE (CCZN);
+CC_MODE (CCZNC);
CC_MODE (CC_FLOAT);
diff --git a/gcc/config/mn10300/mn10300-protos.h b/gcc/config/mn10300/mn10300-protos.h
index d0ce1b3..28a9412 100644
--- a/gcc/config/mn10300/mn10300-protos.h
+++ b/gcc/config/mn10300/mn10300-protos.h
@@ -32,13 +32,16 @@ extern int mn10300_get_live_callee_saved_regs (void);
extern bool mn10300_hard_regno_mode_ok (unsigned int, Mmode);
extern bool mn10300_legitimate_constant_p (rtx);
extern bool mn10300_modes_tieable (Mmode, Mmode);
-extern Cstar mn10300_output_cmp (rtx, rtx);
+extern Cstar mn10300_output_add (rtx[3], bool);
extern void mn10300_print_operand (FILE *, rtx, int);
extern void mn10300_print_operand_address (FILE *, rtx);
extern void mn10300_print_reg_list (FILE *, int);
-extern Mmode mn10300_select_cc_mode (rtx);
+extern Mmode mn10300_select_cc_mode (enum rtx_code, rtx, rtx);
extern int mn10300_store_multiple_operation (rtx, Mmode);
extern int mn10300_symbolic_operand (rtx, Mmode);
+extern void mn10300_split_cbranch (Mmode, rtx, rtx);
+extern int mn10300_split_and_operand_count (rtx);
+extern bool mn10300_match_ccmode (rtx, Mmode);
#endif /* RTX_CODE */
extern bool mn10300_regno_in_class_p (unsigned, int, bool);
diff --git a/gcc/config/mn10300/mn10300.c b/gcc/config/mn10300/mn10300.c
index 023c69c..7535253 100644
--- a/gcc/config/mn10300/mn10300.c
+++ b/gcc/config/mn10300/mn10300.c
@@ -81,6 +81,14 @@ static const struct default_options mn10300_option_optimization_table[] =
{ OPT_LEVELS_1_PLUS, OPT_fomit_frame_pointer, NULL, 1 },
{ OPT_LEVELS_NONE, 0, NULL, 0 }
};
+
+#define CC_FLAG_Z 1
+#define CC_FLAG_N 2
+#define CC_FLAG_C 4
+#define CC_FLAG_V 8
+
+static int cc_flags_for_mode(enum machine_mode);
+static int cc_flags_for_code(enum rtx_code);
/* Implement TARGET_HANDLE_OPTION. */
@@ -134,7 +142,7 @@ mn10300_option_override (void)
when this flag is not enabled by default. */
flag_split_wide_types = 1;
}
-
+
if (mn10300_tune_string)
{
if (strcasecmp (mn10300_tune_string, "mn10300") == 0)
@@ -171,95 +179,82 @@ mn10300_print_operand (FILE *file, rtx x, int code)
{
case 'b':
case 'B':
- if (GET_MODE (XEXP (x, 0)) == CC_FLOATmode)
- {
- switch (code == 'b' ? GET_CODE (x)
- : reverse_condition_maybe_unordered (GET_CODE (x)))
- {
- case NE:
- fprintf (file, "ne");
- break;
- case EQ:
- fprintf (file, "eq");
- break;
- case GE:
- fprintf (file, "ge");
- break;
- case GT:
- fprintf (file, "gt");
- break;
- case LE:
- fprintf (file, "le");
- break;
- case LT:
- fprintf (file, "lt");
- break;
- case ORDERED:
- fprintf (file, "lge");
- break;
- case UNORDERED:
- fprintf (file, "uo");
- break;
- case LTGT:
- fprintf (file, "lg");
- break;
- case UNEQ:
- fprintf (file, "ue");
- break;
- case UNGE:
- fprintf (file, "uge");
- break;
- case UNGT:
- fprintf (file, "ug");
- break;
- case UNLE:
- fprintf (file, "ule");
- break;
- case UNLT:
- fprintf (file, "ul");
- break;
- default:
- gcc_unreachable ();
- }
- break;
- }
- /* These are normal and reversed branches. */
- switch (code == 'b' ? GET_CODE (x) : reverse_condition (GET_CODE (x)))
- {
- case NE:
- fprintf (file, "ne");
- break;
- case EQ:
- fprintf (file, "eq");
- break;
- case GE:
- fprintf (file, "ge");
- break;
- case GT:
- fprintf (file, "gt");
- break;
- case LE:
- fprintf (file, "le");
- break;
- case LT:
- fprintf (file, "lt");
- break;
- case GEU:
- fprintf (file, "cc");
- break;
- case GTU:
- fprintf (file, "hi");
- break;
- case LEU:
- fprintf (file, "ls");
- break;
- case LTU:
- fprintf (file, "cs");
- break;
- default:
- gcc_unreachable ();
- }
+ {
+ enum rtx_code cmp = GET_CODE (x);
+ enum machine_mode mode = GET_MODE (XEXP (x, 0));
+ const char *str;
+ int have_flags;
+
+ if (code == 'B')
+ cmp = reverse_condition (cmp);
+ have_flags = cc_flags_for_mode (mode);
+
+ switch (cmp)
+ {
+ case NE:
+ str = "ne";
+ break;
+ case EQ:
+ str = "eq";
+ break;
+ case GE:
+ /* bge is smaller than bnc. */
+ str = (have_flags & CC_FLAG_V ? "ge" : "nc");
+ break;
+ case LT:
+ str = (have_flags & CC_FLAG_V ? "lt" : "ns");
+ break;
+ case GT:
+ str = "gt";
+ break;
+ case LE:
+ str = "le";
+ break;
+ case GEU:
+ str = "cc";
+ break;
+ case GTU:
+ str = "hi";
+ break;
+ case LEU:
+ str = "ls";
+ break;
+ case LTU:
+ str = "cs";
+ break;
+ case ORDERED:
+ str = "lge";
+ break;
+ case UNORDERED:
+ str = "uo";
+ break;
+ case LTGT:
+ str = "lg";
+ break;
+ case UNEQ:
+ str = "ue";
+ break;
+ case UNGE:
+ str = "uge";
+ break;
+ case UNGT:
+ str = "ug";
+ break;
+ case UNLE:
+ str = "ule";
+ break;
+ case UNLT:
+ str = "ul";
+ break;
+ default:
+ gcc_unreachable ();
+ }
+
+ gcc_checking_assert ((cc_flags_for_code (cmp) & ~have_flags) == 0);
+ fputs (str, file);
+ }
break;
+
case 'C':
/* This is used for the operand to a call instruction;
if it's a REG, enclose it in parens, else output
@@ -1709,95 +1704,96 @@ mn10300_function_value_regno_p (const unsigned int regno)
return (regno == FIRST_DATA_REGNUM || regno == FIRST_ADDRESS_REGNUM);
}
-/* Output a compare insn. */
+/* Output an addition operation. */
const char *
-mn10300_output_cmp (rtx operand, rtx insn)
+mn10300_output_add (rtx operands[3], bool need_flags)
{
- rtx temp;
- int past_call = 0;
+ rtx dest, src1, src2;
+ unsigned int dest_regnum, src1_regnum, src2_regnum;
+ enum reg_class src1_class, src2_class, dest_class;
- /* We can save a byte if we can find a register which has the value
- zero in it. */
- temp = PREV_INSN (insn);
- while (optimize && temp)
- {
- rtx set;
-
- /* We allow the search to go through call insns. We record
- the fact that we've past a CALL_INSN and reject matches which
- use call clobbered registers. */
- if (LABEL_P (temp)
- || JUMP_P (temp)
- || GET_CODE (temp) == BARRIER)
- break;
+ dest = operands[0];
+ src1 = operands[1];
+ src2 = operands[2];
- if (CALL_P (temp))
- past_call = 1;
+ dest_regnum = true_regnum (dest);
+ src1_regnum = true_regnum (src1);
- if (GET_CODE (temp) == NOTE)
- {
- temp = PREV_INSN (temp);
- continue;
- }
+ dest_class = REGNO_REG_CLASS (dest_regnum);
+ src1_class = REGNO_REG_CLASS (src1_regnum);
- /* It must be an insn, see if it is a simple set. */
- set = single_set (temp);
- if (!set)
- {
- temp = PREV_INSN (temp);
- continue;
- }
+ if (GET_CODE (src2) == CONST_INT)
+ {
+ gcc_assert (dest_regnum == src1_regnum);
- /* Are we setting a data register to zero (this does not win for
- address registers)?
-
- If it's a call clobbered register, have we past a call?
-
- Make sure the register we find isn't the same as ourself;
- the mn10300 can't encode that.
-
- ??? reg_set_between_p return nonzero anytime we pass a CALL_INSN
- so the code to detect calls here isn't doing anything useful. */
- if (REG_P (SET_DEST (set))
- && SET_SRC (set) == CONST0_RTX (GET_MODE (SET_DEST (set)))
- && !reg_set_between_p (SET_DEST (set), temp, insn)
- && (REGNO_REG_CLASS (REGNO (SET_DEST (set)))
- == REGNO_REG_CLASS (REGNO (operand)))
- && REGNO_REG_CLASS (REGNO (SET_DEST (set))) != EXTENDED_REGS
- && REGNO (SET_DEST (set)) != REGNO (operand)
- && (!past_call
- || ! call_really_used_regs [REGNO (SET_DEST (set))]))
- {
- rtx xoperands[2];
- xoperands[0] = operand;
- xoperands[1] = SET_DEST (set);
+ if (src2 == const1_rtx && !need_flags)
+ return "inc %0";
+ if (INTVAL (src2) == 4 && !need_flags && dest_class != DATA_REGS)
+ return "inc4 %0";
- output_asm_insn ("cmp %1,%0", xoperands);
- return "";
- }
+ gcc_assert (!need_flags || dest_class != SP_REGS);
+ return "add %2,%0";
+ }
+ else if (CONSTANT_P (src2))
+ return "add %2,%0";
+
+ src2_regnum = true_regnum (src2);
+ src2_class = REGNO_REG_CLASS (src2_regnum);
+
+ if (dest_regnum == src1_regnum)
+ return "add %2,%0";
+ if (dest_regnum == src2_regnum)
+ return "add %1,%0";
+
+ /* The rest of the cases are reg = reg+reg. For AM33, we can implement
+ this directly, as below, but when optimizing for space we can sometimes
+ do better by using a mov+add. For MN103, we claimed that we could
+ implement a three-operand add because the various move and add insns
+ change sizes across register classes, and we can often do better than
+ reload in choosing which operand to move. */
+ if (TARGET_AM33 && optimize_insn_for_speed_p ())
+ return "add %2,%1,%0";
+
+ /* Catch cases where no extended register was used. */
+ if (src1_class != EXTENDED_REGS
+ && src2_class != EXTENDED_REGS
+ && dest_class != EXTENDED_REGS)
+ {
+ /* We have to copy one of the sources into the destination, then
+ add the other source to the destination.
+
+ Carefully select which source to copy to the destination; a
+ naive implementation will waste a byte when the source classes
+ are different and the destination is an address register.
+ Selecting the lowest cost register copy will optimize this
+ sequence. */
+ if (src1_class == dest_class)
+ return "mov %1,%0\n\tadd %2,%0";
+ else
+ return "mov %2,%0\n\tadd %1,%0";
+ }
- if (REGNO_REG_CLASS (REGNO (operand)) == EXTENDED_REGS
- && REG_P (SET_DEST (set))
- && SET_SRC (set) == CONST0_RTX (GET_MODE (SET_DEST (set)))
- && !reg_set_between_p (SET_DEST (set), temp, insn)
- && (REGNO_REG_CLASS (REGNO (SET_DEST (set)))
- != REGNO_REG_CLASS (REGNO (operand)))
- && REGNO_REG_CLASS (REGNO (SET_DEST (set))) == EXTENDED_REGS
- && REGNO (SET_DEST (set)) != REGNO (operand)
- && (!past_call
- || ! call_really_used_regs [REGNO (SET_DEST (set))]))
- {
- rtx xoperands[2];
- xoperands[0] = operand;
- xoperands[1] = SET_DEST (set);
+ /* At least one register is an extended register. */
- output_asm_insn ("cmp %1,%0", xoperands);
- return "";
- }
- temp = PREV_INSN (temp);
- }
- return "cmp 0,%0";
+ /* The three operand add instruction on the am33 is a win iff the
+ output register is an extended register, or if both source
+ registers are extended registers. */
+ if (dest_class == EXTENDED_REGS || src1_class == src2_class)
+ return "add %2,%1,%0";
+
+ /* It is better to copy one of the sources to the destination, then
+ perform a 2 address add. The destination in this case must be
+ an address or data register and one of the sources must be an
+ extended register and the remaining source must not be an extended
+ register.
+
+ The best code for this case is to copy the extended reg to the
+ destination, then emit a two address add. */
+ if (src1_class == EXTENDED_REGS)
+ return "mov %1,%0\n\tadd %2,%0";
+ else
+ return "mov %2,%0\n\tadd %1,%0";
}
/* Return 1 if X contains a symbolic expression. We know these
@@ -2674,10 +2670,80 @@ mn10300_modes_tieable (enum machine_mode mode1, enum machine_mode mode2)
return false;
}
+static int
+cc_flags_for_mode (enum machine_mode mode)
+{
+ switch (mode)
+ {
+ case CCmode:
+ return CC_FLAG_Z | CC_FLAG_N | CC_FLAG_C | CC_FLAG_V;
+ case CCZNCmode:
+ return CC_FLAG_Z | CC_FLAG_N | CC_FLAG_C;
+ case CCZNmode:
+ return CC_FLAG_Z | CC_FLAG_N;
+ case CC_FLOATmode:
+ return -1;
+ default:
+ gcc_unreachable ();
+ }
+}
+
+static int
+cc_flags_for_code (enum rtx_code code)
+{
+ switch (code)
+ {
+ case EQ: /* Z */
+ case NE: /* ~Z */
+ return CC_FLAG_Z;
+
+ case LT: /* N */
+ case GE: /* ~N */
+ return CC_FLAG_N;
+ break;
+
+ case GT: /* ~(Z|(N^V)) */
+ case LE: /* Z|(N^V) */
+ return CC_FLAG_Z | CC_FLAG_N | CC_FLAG_V;
+
+ case GEU: /* ~C */
+ case LTU: /* C */
+ return CC_FLAG_C;
+
+ case GTU: /* ~(C | Z) */
+ case LEU: /* C | Z */
+ return CC_FLAG_Z | CC_FLAG_C;
+
+ case ORDERED:
+ case UNORDERED:
+ case LTGT:
+ case UNEQ:
+ case UNGE:
+ case UNGT:
+ case UNLE:
+ case UNLT:
+ return -1;
+
+ default:
+ gcc_unreachable ();
+ }
+}
+
enum machine_mode
-mn10300_select_cc_mode (rtx x)
+mn10300_select_cc_mode (enum rtx_code code, rtx x, rtx y ATTRIBUTE_UNUSED)
{
- return (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT) ? CC_FLOATmode : CCmode;
+ int req;
+
+ if (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT)
+ return CC_FLOATmode;
+
+ req = cc_flags_for_code (code);
+
+ if (req & CC_FLAG_V)
+ return CCmode;
+ if (req & CC_FLAG_C)
+ return CCZNCmode;
+ return CCZNmode;
}
static inline bool
@@ -2811,6 +2877,82 @@ mn10300_md_asm_clobbers (tree outputs ATTRIBUTE_UNUSED,
return clobbers;
}
+/* A helper function for splitting cbranch patterns after reload. */
+
+void
+mn10300_split_cbranch (enum machine_mode cmp_mode, rtx cmp_op, rtx label_ref)
+{
+ rtx flags, x;
+
+ flags = gen_rtx_REG (cmp_mode, CC_REG);
+ x = gen_rtx_COMPARE (cmp_mode, XEXP (cmp_op, 0), XEXP (cmp_op, 1));
+ x = gen_rtx_SET (VOIDmode, flags, x);
+ emit_insn (x);
+
+ x = gen_rtx_fmt_ee (GET_CODE (cmp_op), VOIDmode, flags, const0_rtx);
+ x = gen_rtx_IF_THEN_ELSE (VOIDmode, x, label_ref, pc_rtx);
+ x = gen_rtx_SET (VOIDmode, pc_rtx, x);
+ emit_jump_insn (x);
+}
+
+/* A helper function for matching parallels that set the flags. */
+
+bool
+mn10300_match_ccmode (rtx insn, enum machine_mode cc_mode)
+{
+ rtx op1, flags;
+ enum machine_mode flags_mode;
+
+ gcc_checking_assert (XVECLEN (PATTERN (insn), 0) == 2);
+
+ op1 = XVECEXP (PATTERN (insn), 0, 1);
+ gcc_checking_assert (GET_CODE (SET_SRC (op1)) == COMPARE);
+
+ flags = SET_DEST (op1);
+ flags_mode = GET_MODE (flags);
+
+ if (GET_MODE (SET_SRC (op1)) != flags_mode)
+ return false;
+ if (GET_MODE_CLASS (flags_mode) != MODE_CC)
+ return false;
+
+ /* Ensure that the mode of FLAGS is compatible with CC_MODE. */
+ if (cc_flags_for_mode (flags_mode) & ~cc_flags_for_mode (cc_mode))
+ return false;
+
+ return true;
+}
+
+int
+mn10300_split_and_operand_count (rtx op)
+{
+ HOST_WIDE_INT val = INTVAL (op);
+ int count;
+
+ if (val < 0)
+ {
+ /* High bit is set, look for bits clear at the bottom. */
+ count = exact_log2 (-val);
+ if (count < 0)
+ return 0;
+ /* This is only size win if we can use the asl2 insn. Otherwise we
+ would be replacing 1 6-byte insn with 2 3-byte insns. */
+ if (count > (optimize_insn_for_speed_p () ? 2 : 4))
+ return 0;
+ return -count;
+ }
+ else
+ {
+ /* High bit is clear, look for bits set at the bottom. */
+ count = exact_log2 (val + 1);
+ count = 32 - count;
+ /* Again, this is only a size win with asl2. */
+ if (count > (optimize_insn_for_speed_p () ? 2 : 4))
+ return 0;
+ return -count;
+ }
+}
+
/* Initialize the GCC target structure. */
#undef TARGET_EXCEPT_UNWIND_INFO
diff --git a/gcc/config/mn10300/mn10300.h b/gcc/config/mn10300/mn10300.h
index 05c7826..21d3633 100644
--- a/gcc/config/mn10300/mn10300.h
+++ b/gcc/config/mn10300/mn10300.h
@@ -600,7 +600,7 @@ do { \
/* Non-global SYMBOL_REFs have SYMBOL_REF_FLAG enabled. */
#define MN10300_GLOBAL_P(X) (! SYMBOL_REF_FLAG (X))
-#define SELECT_CC_MODE(OP, X, Y) mn10300_select_cc_mode (X)
+#define SELECT_CC_MODE(OP, X, Y) mn10300_select_cc_mode (OP, X, Y)
#define REVERSIBLE_CC_MODE(MODE) 0
/* Nonzero if access to memory by bytes or half words is no faster
diff --git a/gcc/config/mn10300/mn10300.md b/gcc/config/mn10300/mn10300.md
index bc68ca5..152477c 100644
--- a/gcc/config/mn10300/mn10300.md
+++ b/gcc/config/mn10300/mn10300.md
@@ -507,104 +507,6 @@
])]
)
-
-;; ----------------------------------------------------------------------
-;; ADD INSTRUCTIONS
-;; ----------------------------------------------------------------------
-
-(define_expand "addsi3"
- [(parallel [(set (match_operand:SI 0 "register_operand")
- (plus:SI (match_operand:SI 1 "register_operand")
- (match_operand:SI 2 "nonmemory_operand")))
- (clobber (reg:CC CC_REG))
- ])
- ]
- ""
- "")
-
-(define_insn "*am33_addsi3"
- [(set (match_operand:SI 0 "register_operand" "=dx,a,x,a,dax,!*y,!dax")
- (plus:SI (match_operand:SI 1 "register_operand" "%0,0,0,0,0,0,dax")
- (match_operand:SI 2 "nonmemory_operand" "J,J,L,L,daxi,i,dax")))
- (clobber (reg:CC CC_REG))
- ]
- "TARGET_AM33"
- "*
-{
- switch (which_alternative)
- {
- case 0:
- case 1:
- return \"inc %0\";
- case 2:
- case 3:
- return \"inc4 %0\";
- case 4:
- case 5:
- return \"add %2,%0\";
- case 6:
- {
- enum reg_class src1_class, src2_class, dst_class;
-
- src1_class = REGNO_REG_CLASS (true_regnum (operands[1]));
- src2_class = REGNO_REG_CLASS (true_regnum (operands[2]));
- dst_class = REGNO_REG_CLASS (true_regnum (operands[0]));
-
- /* I'm not sure if this can happen or not. Might as well be prepared
- and generate the best possible code if it does happen. */
- if (true_regnum (operands[0]) == true_regnum (operands[1]))
- return \"add %2,%0\";
- if (true_regnum (operands[0]) == true_regnum (operands[2]))
- return \"add %1,%0\";
-
- /* Catch cases where no extended register was used. These should be
- handled just like the mn10300. */
- if (src1_class != EXTENDED_REGS
- && src2_class != EXTENDED_REGS
- && dst_class != EXTENDED_REGS)
- {
- /* We have to copy one of the sources into the destination, then
- add the other source to the destination.
-
- Carefully select which source to copy to the destination; a
- naive implementation will waste a byte when the source classes
- are different and the destination is an address register.
- Selecting the lowest cost register copy will optimize this
- sequence. */
- if (REGNO_REG_CLASS (true_regnum (operands[1]))
- == REGNO_REG_CLASS (true_regnum (operands[0])))
- return \"mov %1,%0\;add %2,%0\";
- return \"mov %2,%0\;add %1,%0\";
- }
-
- /* At least one register is an extended register. */
-
- /* The three operand add instruction on the am33 is a win iff the
- output register is an extended register, or if both source
- registers are extended registers. */
- if (dst_class == EXTENDED_REGS
- || src1_class == src2_class)
- return \"add %2,%1,%0\";
-
- /* It is better to copy one of the sources to the destination, then
- perform a 2 address add. The destination in this case must be
- an address or data register and one of the sources must be an
- extended register and the remaining source must not be an extended
- register.
-
- The best code for this case is to copy the extended reg to the
- destination, then emit a two address add. */
- if (src1_class == EXTENDED_REGS)
- return \"mov %1,%0\;add %2,%0\";
- return \"mov %2,%0\;add %1,%0\";
- }
- default:
- gcc_unreachable ();
- }
- }"
- [(set_attr "timings" "11,11,11,11,11,11,22")]
-)
-
;; If the flags register is not live, generate CLR instead of MOV 0.
;; For MN103, this is only legal for DATA_REGS; for AM33 this is legal
;; but not a win for ADDRESS_REGS.
@@ -629,123 +531,90 @@
;; ADD INSTRUCTIONS
;; ----------------------------------------------------------------------
-(define_insn "*mn10300_addsi3"
- [(set (match_operand:SI 0 "register_operand" "=dx,a,a,dax,!*y,!dax")
- (plus:SI (match_operand:SI 1 "register_operand" "%0,0,0,0,0,dax")
- (match_operand:SI 2 "nonmemory_operand" "J,J,L,daxi,i,dax")))
- (clobber (reg:CC CC_REG))
- ]
+(define_insn "addsi3"
+ [(set (match_operand:SI 0 "register_operand" "=r,!*y,!r")
+ (plus:SI (match_operand:SI 1 "register_operand" "%0, 0, r")
+ (match_operand:SI 2 "nonmemory_operand" "ri, i, r")))
+ (clobber (reg:CC CC_REG))]
""
- "*
-{
- switch (which_alternative)
- {
- case 0:
- case 1:
- return \"inc %0\";
- case 2:
- return \"inc4 %0\";
- case 3:
- case 4:
- return \"add %2,%0\";
- case 5:
- /* I'm not sure if this can happen or not. Might as well be prepared
- and generate the best possible code if it does happen. */
- if (true_regnum (operands[0]) == true_regnum (operands[1]))
- return \"add %2,%0\";
- if (true_regnum (operands[0]) == true_regnum (operands[2]))
- return \"add %1,%0\";
-
- /* We have to copy one of the sources into the destination, then add
- the other source to the destination.
-
- Carefully select which source to copy to the destination; a naive
- implementation will waste a byte when the source classes are different
- and the destination is an address register. Selecting the lowest
- cost register copy will optimize this sequence. */
- if (REGNO_REG_CLASS (true_regnum (operands[1]))
- == REGNO_REG_CLASS (true_regnum (operands[0])))
- return \"mov %1,%0\;add %2,%0\";
- return \"mov %2,%0\;add %1,%0\";
- default:
- gcc_unreachable ();
- }
-}"
- [(set_attr "timings" "11,11,11,11,11,22")]
+ { return mn10300_output_add (operands, false); }
+ [(set_attr "timings" "11,11,22")]
+)
+
+;; Note that ADD IMM,SP does not set the flags, so omit that here.
+(define_insn "*addsi3_flags"
+ [(set (match_operand:SI 0 "register_operand" "=r,!r")
+ (plus:SI (match_operand:SI 1 "register_operand" "%0, r")
+ (match_operand:SI 2 "nonmemory_operand" "ri, r")))
+ (set (reg CC_REG)
+ (compare (plus:SI (match_dup 1) (match_dup 2))
+ (const_int 0)))]
+ "reload_completed && mn10300_match_ccmode (insn, CCZNCmode)"
+ { return mn10300_output_add (operands, true); }
+ [(set_attr "timings" "11,22")]
)
;; ----------------------------------------------------------------------
;; SUBTRACT INSTRUCTIONS
;; ----------------------------------------------------------------------
-(define_expand "subsi3"
- [(parallel [(set (match_operand:SI 0 "register_operand")
- (minus:SI (match_operand:SI 1 "register_operand")
- (match_operand:SI 2 "nonmemory_operand")))
- (clobber (reg:CC CC_REG))
- ])
- ]
+(define_insn "subsi3"
+ [(set (match_operand:SI 0 "register_operand" "=r,r")
+ (minus:SI (match_operand:SI 1 "register_operand" " 0,r")
+ (match_operand:SI 2 "nonmemory_operand" "ri,r")))
+ (clobber (reg:CC CC_REG))]
""
- "")
-
-(define_insn "*am33_subsi3"
- [(set (match_operand:SI 0 "register_operand" "=dax,!dax")
- (minus:SI (match_operand:SI 1 "register_operand" "0,dax")
- (match_operand:SI 2 "nonmemory_operand" "daxi,dax")))
- (clobber (reg:CC CC_REG))
- ]
- "TARGET_AM33"
- "*
- {
- if (true_regnum (operands[0]) == true_regnum (operands[1]))
- return \"sub %2,%0\";
- else
- {
- enum reg_class src1_class, src2_class, dst_class;
-
- src1_class = REGNO_REG_CLASS (true_regnum (operands[1]));
- src2_class = REGNO_REG_CLASS (true_regnum (operands[2]));
- dst_class = REGNO_REG_CLASS (true_regnum (operands[0]));
-
- /* If no extended registers are used, then the best way to handle
- this is to copy the first source operand into the destination
- and emit a two address subtraction. */
- if (src1_class != EXTENDED_REGS
- && src2_class != EXTENDED_REGS
- && dst_class != EXTENDED_REGS
- && true_regnum (operands[0]) != true_regnum (operands[2]))
- return \"mov %1,%0\;sub %2,%0\";
- return \"sub %2,%1,%0\";
- }
- }"
- [(set_attr "timings" "11,22")]
+ "@
+ sub %2,%0
+ sub %2,%1,%0"
+ [(set_attr "isa" "*,am33")
+ (set_attr "timings" "11,22")]
)
-(define_insn "*mn10300_subsi3"
- [(set (match_operand:SI 0 "register_operand" "=dax")
- (minus:SI (match_operand:SI 1 "register_operand" "0")
- (match_operand:SI 2 "nonmemory_operand" "daxi")))
- (clobber (reg:CC CC_REG))
- ]
- ""
- "sub %2,%0"
- [(set (attr "timings") (if_then_else (eq_attr "cpu" "am34")
- (const_int 11) (const_int 22)))]
+(define_insn "*subsi3_flags"
+ [(set (match_operand:SI 0 "register_operand" "=r,r")
+ (minus:SI (match_operand:SI 1 "register_operand" " 0,r")
+ (match_operand:SI 2 "nonmemory_operand" "ri,r")))
+ (set (reg CC_REG)
+ (compare (minus:SI (match_dup 1) (match_dup 2))
+ (const_int 0)))]
+ "reload_completed && mn10300_match_ccmode (insn, CCZNCmode)"
+ "@
+ sub %2,%0
+ sub %2,%1,%0"
+ [(set_attr "isa" "*,am33")
+ (set_attr "timings" "11,22")]
)
-(define_expand "negsi2"
- [(set (match_operand:SI 0 "register_operand")
- (neg:SI (match_operand:SI 1 "register_operand")))]
+(define_insn_and_split "negsi2"
+ [(set (match_operand:SI 0 "register_operand" "=D,&r")
+ (neg:SI (match_operand:SI 1 "register_operand" " 0, r")))
+ (clobber (reg:CC CC_REG))]
""
- "
+ "#"
+ "&& reload_completed"
+ [(const_int 0)]
{
- rtx target = gen_reg_rtx (SImode);
-
- emit_move_insn (target, const0_rtx);
- emit_insn (gen_subsi3 (target, target, operands[1]));
- emit_move_insn (operands[0], target);
+ /* Recall that twos-compliment is ones-compliment plus one. When
+ allocated in DATA_REGS this is 2+1 bytes; otherwise (for am33)
+ this is 3+3 bytes.
+
+ For AM33, it would have been possible to load zero and use the
+ three-address subtract to have a total size of 3+4*N bytes for
+ multiple negations, plus increased throughput. Not attempted here. */
+
+ if (true_regnum (operands[0]) == true_regnum (operands[1]))
+ {
+ emit_insn (gen_one_cmplsi2 (operands[0], operands[0]));
+ emit_insn (gen_addsi3 (operands[0], operands[0], const1_rtx));
+ }
+ else
+ {
+ emit_move_insn (operands[0], const0_rtx);
+ emit_insn (gen_subsi3 (operands[0], operands[0], operands[1]));
+ }
DONE;
-}")
+})
;; ----------------------------------------------------------------------
;; MULTIPLY INSTRUCTIONS
@@ -935,221 +804,174 @@
;; AND INSTRUCTIONS
;; ----------------------------------------------------------------------
-(define_expand "andsi3"
- [(parallel [(set (match_operand:SI 0 "register_operand")
- (and:SI (match_operand:SI 1 "register_operand")
- (match_operand:SI 2 "nonmemory_operand")))
- (clobber (reg:CC CC_REG))
- ])
- ]
+(define_insn "andsi3"
+ [(set (match_operand:SI 0 "register_operand" "=D,D,r")
+ (and:SI (match_operand:SI 1 "register_operand" "%0,0,r")
+ (match_operand:SI 2 "nonmemory_operand" " i,D,r")))
+ (clobber (reg:CC CC_REG))]
""
- "")
-
-(define_insn "*am33_andsi3"
- [(set (match_operand:SI 0 "register_operand" "=dx,dx,!dax")
- (and:SI (match_operand:SI 1 "register_operand" "%0,0,dax")
- (match_operand:SI 2 "nonmemory_operand" "N,dxi,dax")))
- (clobber (reg:CC CC_REG))
- ]
- "TARGET_AM33"
- {
- if (CONST_INT_P (operands[2]))
- switch (INTVAL (operands[2]))
- {
- case 0xff: return "extbu %0";
- case 0xffff: return "exthu %0";
- case 0x7fffffff: return "add %0, %0; lsr 1, %0";
- case 0x3fffffff: return "asl2 %0; lsr 2, %0";
- case 0x1fffffff: return "add %0, %0; asl2 %0; lsr 3, %0";
- case 0x0fffffff: return "asl2 %0; asl2 %0; lsr 4, %0";
- case 0xfffffffe: return "lsr 1, %0; add %0, %0";
- case 0xfffffffc: return "lsr 2, %0; asl2 %0";
- case 0xfffffff8: return "lsr 3, %0; add %0, %0; asl2 %0";
- case 0xfffffff0: return "lsr 4, %0; asl2 %0; asl2 %0";
- }
-
- if (REG_P (operands[2]) && REG_P (operands[1])
- && true_regnum (operands[0]) != true_regnum (operands[1])
- && true_regnum (operands[0]) != true_regnum (operands[2])
- && REGNO_REG_CLASS (true_regnum (operands[0])) == DATA_REGS
- && REGNO_REG_CLASS (true_regnum (operands[1])) == DATA_REGS
- && REGNO_REG_CLASS (true_regnum (operands[2])) == DATA_REGS)
- return "mov %1, %0; and %2, %0";
- if (REG_P (operands[2]) && REG_P (operands[1])
- && true_regnum (operands[0]) != true_regnum (operands[1])
- && true_regnum (operands[0]) != true_regnum (operands[2]))
- return "and %1, %2, %0";
- if (REG_P (operands[2]) && REG_P (operands[0])
- && true_regnum (operands[2]) == true_regnum (operands[0]))
- return "and %1, %0";
-
- return "and %2, %0";
- }
- [(set_attr "timings" "33")]
+ "@
+ and %2,%0
+ and %2,%0
+ and %2,%1,%0"
+ [(set_attr "isa" "*,*,am33")
+ (set_attr "timings" "22,11,11")]
+)
+
+(define_insn "*andsi3_flags"
+ [(set (match_operand:SI 0 "register_operand" "=D,D,r")
+ (and:SI (match_operand:SI 1 "register_operand" "%0,0,r")
+ (match_operand:SI 2 "nonmemory_operand" " i,D,r")))
+ (set (reg CC_REG)
+ (compare (and:SI (match_dup 1) (match_dup 2))
+ (const_int 0)))]
+ "reload_completed && mn10300_match_ccmode (insn, CCZNmode)"
+ "@
+ and %2,%0
+ and %2,%0
+ and %2,%1,%0"
+ [(set_attr "isa" "*,*,am33")
+ (set_attr "timings" "22,11,11")]
)
-(define_insn "*mn10300_andsi3"
- [(set (match_operand:SI 0 "register_operand" "=dx,dx")
- (and:SI (match_operand:SI 1 "register_operand" "%0,0")
- (match_operand:SI 2 "nonmemory_operand" "N,dxi")))
- (clobber (reg:CC CC_REG))
- ]
+;; Make sure we generate extensions instead of ANDs.
+
+(define_split
+ [(parallel [(set (match_operand:SI 0 "register_operand" "")
+ (and:SI (match_operand:SI 1 "register_operand" "")
+ (const_int 255)))
+ (clobber (reg:CC CC_REG))])]
""
- {
- if (CONST_INT_P (operands[2]))
- switch (INTVAL (operands[2]))
- {
- case 0xff: return "extbu %0";
- case 0xffff: return "exthu %0";
- case 0x7fffffff: return "add %0, %0; lsr 1, %0";
- case 0x3fffffff: return "asl2 %0; lsr 2, %0";
- case 0x1fffffff: return "add %0, %0; asl2 %0; lsr 3, %0";
- case 0x0fffffff: return "asl2 %0; asl2 %0; lsr 4, %0";
- case 0xfffffffe: return "lsr 1, %0; add %0, %0";
- case 0xfffffffc: return "lsr 2, %0; asl2 %0";
- case 0xfffffff8: return "lsr 3, %0; add %0, %0; asl2 %0";
- case 0xfffffff0: return "lsr 4, %0; asl2 %0; asl2 %0";
- }
+ [(set (match_dup 0) (zero_extend:SI (match_dup 1)))]
+ { operands[1] = gen_lowpart (QImode, operands[1]); }
+)
- return "and %2, %0";
- }
- [(set_attr "timings" "33")]
+(define_split
+ [(parallel [(set (match_operand:SI 0 "register_operand" "")
+ (and:SI (match_operand:SI 1 "register_operand" "")
+ (const_int 65535)))
+ (clobber (reg:CC CC_REG))])]
+ ""
+ [(set (match_dup 0) (zero_extend:SI (match_dup 1)))]
+ { operands[1] = gen_lowpart (HImode, operands[1]); }
)
+;; Split AND by an appropriate constant into two shifts. Recall that
+;; operations with a full 32-bit immediate require an extra cycle, so
+;; this is a size optimization with no speed penalty. This only applies
+;; do DATA_REGS; the shift insns that AM33 adds are too large for a win.
+
+(define_split
+ [(parallel [(set (match_operand:SI 0 "register_operand" "")
+ (and:SI (match_dup 0)
+ (match_operand:SI 1 "const_int_operand" "")))
+ (clobber (reg:CC CC_REG))])]
+ "reload_completed
+ && REGNO_DATA_P (true_regnum (operands[0]), 1)
+ && mn10300_split_and_operand_count (operands[1]) != 0"
+ [(const_int 0)]
+{
+ int count = mn10300_split_and_operand_count (operands[1]);
+ if (count > 0)
+ {
+ emit_insn (gen_lshrsi3 (operands[0], operands[0], GEN_INT (count)));
+ emit_insn (gen_ashlsi3 (operands[0], operands[0], GEN_INT (count)));
+ }
+ else
+ {
+ emit_insn (gen_ashlsi3 (operands[0], operands[0], GEN_INT (-count)));
+ emit_insn (gen_lshrsi3 (operands[0], operands[0], GEN_INT (-count)));
+ }
+ DONE;
+})
+
;; ----------------------------------------------------------------------
;; OR INSTRUCTIONS
;; ----------------------------------------------------------------------
-(define_expand "iorsi3"
- [(parallel [(set (match_operand:SI 0 "register_operand")
- (ior:SI (match_operand:SI 1 "register_operand")
- (match_operand:SI 2 "nonmemory_operand")))
- (clobber (reg:CC CC_REG))
- ])
- ]
- ""
- "")
-
-(define_insn "*am33_iorsi3"
- [(set (match_operand:SI 0 "register_operand" "=dx,!dax")
- (ior:SI (match_operand:SI 1 "register_operand" "%0,dax")
- (match_operand:SI 2 "nonmemory_operand" "dxi,dax")))
- (clobber (reg:CC CC_REG))
- ]
- "TARGET_AM33"
- "*
- {
- if (REG_P (operands[2]) && REG_P (operands[1])
- && true_regnum (operands[0]) != true_regnum (operands[1])
- && true_regnum (operands[0]) != true_regnum (operands[2])
- && REGNO_REG_CLASS (true_regnum (operands[0])) == DATA_REGS
- && REGNO_REG_CLASS (true_regnum (operands[1])) == DATA_REGS
- && REGNO_REG_CLASS (true_regnum (operands[2])) == DATA_REGS)
- return \"mov %1,%0\;or %2,%0\";
- if (REG_P (operands[2]) && REG_P (operands[1])
- && true_regnum (operands[0]) != true_regnum (operands[1])
- && true_regnum (operands[0]) != true_regnum (operands[2]))
- return \"or %1,%2,%0\";
- if (REG_P (operands[2]) && REG_P (operands[0])
- && true_regnum (operands[2]) == true_regnum (operands[0]))
- return \"or %1,%0\";
- return \"or %2,%0\";
- }"
- [(set_attr "timings" "22")]
-)
-
-(define_insn "*mn10300_iorsi3"
- [(set (match_operand:SI 0 "register_operand" "=dx")
- (ior:SI (match_operand:SI 1 "register_operand" "%0")
- (match_operand:SI 2 "nonmemory_operand" "dxi")))
- (clobber (reg:CC CC_REG))
- ]
+(define_insn "iorsi3"
+ [(set (match_operand:SI 0 "register_operand" "=D,D,r")
+ (ior:SI (match_operand:SI 1 "register_operand" "%0,0,r")
+ (match_operand:SI 2 "nonmemory_operand" " i,D,r")))
+ (clobber (reg:CC CC_REG))]
""
- "or %2,%0"
- [(set_attr "timings" "33")]
+ "@
+ or %2,%0
+ or %2,%0
+ or %2,%1,%0"
+ [(set_attr "isa" "*,*,am33")
+ (set_attr "timings" "22,11,11")]
+)
+
+(define_insn "*iorsi3_flags"
+ [(set (match_operand:SI 0 "register_operand" "=D,D,r")
+ (ior:SI (match_operand:SI 1 "register_operand" "%0,0,r")
+ (match_operand:SI 2 "nonmemory_operand" " i,D,r")))
+ (set (reg CC_REG)
+ (compare (ior:SI (match_dup 1) (match_dup 2))
+ (const_int 0)))]
+ "reload_completed && mn10300_match_ccmode (insn, CCZNmode)"
+ "@
+ or %2,%0
+ or %2,%0
+ or %2,%1,%0"
+ [(set_attr "isa" "*,*,am33")
+ (set_attr "timings" "22,11,11")]
)
;; ----------------------------------------------------------------------
;; XOR INSTRUCTIONS
;; ----------------------------------------------------------------------
-(define_expand "xorsi3"
- [(parallel [(set (match_operand:SI 0 "register_operand")
- (xor:SI (match_operand:SI 1 "register_operand")
- (match_operand:SI 2 "nonmemory_operand")))
- (clobber (reg:CC CC_REG))
- ])
- ]
- ""
- "")
-
-(define_insn "*am33_xorsi3"
- [(set (match_operand:SI 0 "register_operand" "=dx,!dax")
- (xor:SI (match_operand:SI 1 "register_operand" "%0,dax")
- (match_operand:SI 2 "nonmemory_operand" "dxi,dax")))
- (clobber (reg:CC CC_REG))
- ]
- "TARGET_AM33"
- "*
- {
- if (REG_P (operands[2]) && REG_P (operands[1])
- && true_regnum (operands[0]) != true_regnum (operands[1])
- && true_regnum (operands[0]) != true_regnum (operands[2])
- && REGNO_REG_CLASS (true_regnum (operands[0])) == DATA_REGS
- && REGNO_REG_CLASS (true_regnum (operands[1])) == DATA_REGS
- && REGNO_REG_CLASS (true_regnum (operands[2])) == DATA_REGS)
- return \"mov %1,%0\;xor %2,%0\";
- if (REG_P (operands[2]) && REG_P (operands[1])
- && true_regnum (operands[0]) != true_regnum (operands[1])
- && true_regnum (operands[0]) != true_regnum (operands[2]))
- return \"xor %1,%2,%0\";
- if (REG_P (operands[2]) && REG_P (operands[0])
- && true_regnum (operands[2]) == true_regnum (operands[0]))
- return \"xor %1,%0\";
- return \"xor %2,%0\";
- }"
- [(set_attr "timings" "22")]
-)
-
-(define_insn "*mn10300_xorsi3"
- [(set (match_operand:SI 0 "register_operand" "=dx")
- (xor:SI (match_operand:SI 1 "register_operand" "%0")
- (match_operand:SI 2 "nonmemory_operand" "dxi")))
- (clobber (reg:CC CC_REG))
- ]
+(define_insn "xorsi3"
+ [(set (match_operand:SI 0 "register_operand" "=D,D,r")
+ (xor:SI (match_operand:SI 1 "register_operand" "%0,0,r")
+ (match_operand:SI 2 "nonmemory_operand" " i,D,r")))
+ (clobber (reg:CC CC_REG))]
""
- "xor %2,%0"
- [(set_attr "timings" "11")]
+ "@
+ xor %2,%0
+ xor %2,%0
+ xor %2,%1,%0"
+ [(set_attr "isa" "*,*,am33")
+ (set_attr "timings" "22,11,11")]
+)
+
+(define_insn "*xorsi3_flags"
+ [(set (match_operand:SI 0 "register_operand" "=D,D,r")
+ (xor:SI (match_operand:SI 1 "register_operand" "%0,0,r")
+ (match_operand:SI 2 "nonmemory_operand" " i,D,r")))
+ (set (reg CC_REG)
+ (compare (xor:SI (match_dup 1) (match_dup 2))
+ (const_int 0)))]
+ "reload_completed && mn10300_match_ccmode (insn, CCZNmode)"
+ "@
+ xor %2,%0
+ xor %2,%0
+ xor %2,%1,%0"
+ [(set_attr "isa" "*,*,am33")
+ (set_attr "timings" "22,11,11")]
)
;; ----------------------------------------------------------------------
;; NOT INSTRUCTIONS
;; ----------------------------------------------------------------------
-(define_expand "one_cmplsi2"
- [(parallel [(set (match_operand:SI 0 "register_operand")
- (not:SI (match_operand:SI 1 "register_operand")))
- (clobber (reg:CC CC_REG))
- ])
- ]
+(define_insn "one_cmplsi2"
+ [(set (match_operand:SI 0 "register_operand" "=D")
+ (not:SI (match_operand:SI 1 "register_operand" " 0")))
+ (clobber (reg:CC CC_REG))]
""
- "")
-
-(define_insn "*am33_cmplsi2"
- [(set (match_operand:SI 0 "register_operand" "=dx,!dax")
- (not:SI (match_operand:SI 1 "register_operand" "0,0")))
- (clobber (reg:CC CC_REG))
- ]
- "TARGET_AM33"
"not %0"
)
-(define_insn "*mn10300_cmplsi2"
- [(set (match_operand:SI 0 "register_operand" "=dx")
- (not:SI (match_operand:SI 1 "register_operand" "0")))
- (clobber (reg:CC CC_REG))
- ]
- ""
+(define_insn "*one_cmplsi2_flags"
+ [(set (match_operand:SI 0 "register_operand" "=D")
+ (not:SI (match_operand:SI 1 "register_operand" " 0")))
+ (set (reg CC_REG)
+ (compare (not:SI (match_dup 1))
+ (const_int 0)))]
+ "reload_completed && mn10300_match_ccmode (insn, CCZNmode)"
"not %0"
)
@@ -1165,140 +987,133 @@
(match_operator 0 "ordered_comparison_operator"
[(match_operand:SI 1 "register_operand")
(match_operand:SI 2 "nonmemory_operand")])
- (label_ref (match_operand 3 ""))
+ (label_ref (match_operand 3 ""))
(pc)))]
""
""
)
-(define_insn_and_split "*cbranchsi4_post_reload"
+(define_insn_and_split "*cbranchsi4_cmp"
[(set (pc)
(if_then_else (match_operator 3 "ordered_comparison_operator"
- [(match_operand:SI 0 "register_operand" "dax")
- (match_operand:SI 1 "nonmemory_operand" "daxi")])
- (label_ref (match_operand 2 "" ""))
- (pc)))
- ]
+ [(match_operand:SI 0 "register_operand" "r")
+ (match_operand:SI 1 "nonmemory_operand" "ri")])
+ (match_operand 2 "label_ref_operand" "")
+ (pc)))]
""
"#"
"reload_completed"
[(const_int 0)]
- "
- /* We construct the split by hand as otherwise the JUMP_LABEL
- attribute is not set correctly on the jump insn. */
- emit_insn (gen_cmpsi (operands[0], operands[1]));
-
- emit_jump_insn (gen_integer_conditional_branch
- (gen_rtx_fmt_ee (GET_CODE (operands[3]),
- CCmode,
- gen_rtx_REG (CCmode, CC_REG),
- const0_rtx),
- operands[2]));
- "
-)
+{
+ mn10300_split_cbranch (CCmode, operands[3], operands[2]);
+ DONE;
+})
-;; Ordinarily, the cmp instruction will set the Z bit of cc0 to 1 if
-;; its operands hold equal values, but the operands of a cmp
-;; instruction must be distinct registers. In the case where we'd
-;; like to compare a register to itself, we can achieve this effect
-;; with a btst 0,d0 instead. (This will not alter the contents of d0
-;; but will have the proper effect on cc0. Using d0 is arbitrary; any
-;; data register would work.)
-
-;; Even though the first alternative would be preferable if it can
-;; possibly match, reload must not be given the opportunity to attempt
-;; to use it. It assumes that such matches can only occur when one of
-;; the operands is used for input and the other for output. Since
-;; this is not the case, it abort()s. Indeed, such a reload cannot be
-;; possibly satisfied, so just mark the alternative with a `!', so
-;; that it is not considered by reload.
-
-(define_insn "cmpsi"
- [(set (reg:CC CC_REG)
- (compare (match_operand:SI 0 "register_operand" "!*d*a*x,dax,dax")
- (match_operand:SI 1 "nonmemory_operand" "*0,I,daxi")))]
- ""
- {
- if (which_alternative == 0)
- return \"btst 0,d0\";
- if (which_alternative == 1)
- return mn10300_output_cmp (operands[0], insn);
- return \"cmp %1,%0\";
- }
+(define_insn "*cmpsi"
+ [(set (reg CC_REG)
+ (compare (match_operand:SI 0 "register_operand" "r")
+ (match_operand:SI 1 "nonmemory_operand" "ri")))]
+ "reload_completed"
+{
+ /* The operands of CMP must be distinct registers. In the case where
+ we've failed to optimize the comparison of a register to itself, we
+ must use another method to set the Z flag. We can achieve this
+ effect with a BTST 0,D0. This will not alter the contents of D0;
+ the use of d0 is arbitrary; any data register would work. */
+ if (rtx_equal_p (operands[0], operands[1]))
+ return "btst 0,d0";
+ else
+ return "cmp %1,%0";
+}
[(set_attr_alternative "timings"
- [(const_int 11)
- (if_then_else (eq_attr "cpu" "am34")
- (const_int 11) (const_int 22))
- (const_int 22)
- ])
- ]
+ [(if_then_else (eq_attr "cpu" "am34") (const_int 11) (const_int 22))])]
)
-(define_insn "integer_conditional_branch"
+(define_insn "*integer_conditional_branch"
[(set (pc)
(if_then_else (match_operator 0 "comparison_operator"
- [(reg:CC CC_REG) (const_int 0)])
+ [(match_operand 2 "int_mode_flags" "")
+ (const_int 0)])
(label_ref (match_operand 1 "" ""))
(pc)))]
- ""
+ "reload_completed"
"b%b0 %1"
)
+(define_insn_and_split "*cbranchsi4_btst"
+ [(set (pc)
+ (if_then_else
+ (match_operator 3 "CCZN_comparison_operator"
+ [(and:SI (match_operand:SI 0 "register_operand" "D")
+ (match_operand:SI 1 "immediate_operand" "i"))
+ (const_int 0)])
+ (match_operand 2 "label_ref_operand" "")
+ (pc)))]
+ ""
+ "#"
+ "reload_completed"
+ [(const_int 0)]
+{
+ mn10300_split_cbranch (CCZNmode, operands[3], operands[2]);
+ DONE;
+})
+
+(define_insn "*btstsi"
+ [(set (reg:CCZN CC_REG)
+ (compare:CCZN
+ (and:SI (match_operand:SI 0 "register_operand" "D")
+ (match_operand:SI 1 "immediate_operand" "i"))
+ (const_int 0)))]
+ "reload_completed"
+ "btst %1,%0"
+)
+
(define_expand "cbranchsf4"
[(set (pc)
(if_then_else
(match_operator 0 "ordered_comparison_operator"
[(match_operand:SF 1 "register_operand")
(match_operand:SF 2 "nonmemory_operand")])
- (label_ref (match_operand 3 ""))
+ (label_ref (match_operand 3 ""))
(pc)))]
"TARGET_AM33_2"
""
)
-(define_insn_and_split "*cbranchsf4_post_reload"
+(define_insn_and_split "*cbranchsf4_cmp"
[(set (pc)
(if_then_else (match_operator 3 "ordered_comparison_operator"
[(match_operand:SF 0 "register_operand" "f")
(match_operand:SF 1 "nonmemory_operand" "fF")])
- (label_ref (match_operand 2 "" ""))
+ (match_operand 2 "label_ref_operand" "")
(pc)))
]
"TARGET_AM33_2"
"#"
"&& reload_completed"
[(const_int 0)]
- "
- /* We construct the split by hand as otherwise the JUMP_LABEL
- attribute is not set correctly on the jump insn. */
- emit_insn (gen_am33_cmpsf (operands[0], operands[1]));
-
- emit_jump_insn (gen_float_conditional_branch
- (gen_rtx_fmt_ee (GET_CODE (operands[3]),
- CC_FLOATmode,
- gen_rtx_REG (CC_FLOATmode, CC_REG),
- const0_rtx),
- operands[2]));
- "
-)
+{
+ mn10300_split_cbranch (CC_FLOATmode, operands[3], operands[2]);
+ DONE;
+})
-(define_insn "am33_cmpsf"
+(define_insn "*am33_cmpsf"
[(set (reg:CC_FLOAT CC_REG)
(compare:CC_FLOAT (match_operand:SF 0 "register_operand" "f")
(match_operand:SF 1 "nonmemory_operand" "fF")))]
- "TARGET_AM33_2"
+ "TARGET_AM33_2 && reload_completed"
"fcmp %1, %0"
[(set (attr "timings") (if_then_else (eq_attr "cpu" "am34")
(const_int 17) (const_int 25)))]
)
-(define_insn "float_conditional_branch"
+(define_insn "*float_conditional_branch"
[(set (pc)
(if_then_else (match_operator 0 "comparison_operator"
[(reg:CC_FLOAT CC_REG) (const_int 0)])
(label_ref (match_operand 1 "" ""))
(pc)))]
- "TARGET_AM33_2"
+ "TARGET_AM33_2 && reload_completed"
"fb%b0 %1"
[(set (attr "timings") (if_then_else (eq_attr "cpu" "am34")
(const_int 44) (const_int 33)))]
@@ -1340,7 +1155,6 @@
(match_operand:SI 2 "immediate_operand")
(match_operand 3 "" "") (match_operand 4 "")]
""
- "
{
rtx table = gen_reg_rtx (SImode);
rtx index = gen_reg_rtx (SImode);
@@ -1360,7 +1174,7 @@
emit_jump_insn (gen_tablejump (addr, operands[3]));
DONE;
-}")
+})
(define_insn "tablejump"
[(set (pc) (match_operand:SI 0 "register_operand" "a"))
@@ -1470,7 +1284,6 @@
(match_operand 1 "")
(match_operand 2 "")])]
""
- "
{
int i;
@@ -1482,7 +1295,7 @@
emit_move_insn (SET_DEST (set), SET_SRC (set));
}
DONE;
-}")
+})
(define_insn "nop"
[(const_int 0)]
@@ -1494,328 +1307,109 @@
;; EXTEND INSTRUCTIONS
;; ----------------------------------------------------------------------
-(define_expand "zero_extendqisi2"
- [(set (match_operand:SI 0 "register_operand")
+(define_insn "zero_extendqisi2"
+ [(set (match_operand:SI 0 "register_operand" "=D,D,r")
(zero_extend:SI
- (match_operand:QI 1 "nonimmediate_operand")))]
+ (match_operand:QI 1 "nonimmediate_operand" " 0,m,r")))]
""
- "")
-
-(define_insn "*zero_extendqisi2_am33"
- [(set (match_operand:SI 0 "register_operand" "=dx,dx,dx,!dax,!dax,!dax")
- (zero_extend:SI
- (match_operand:QI 1 "nonimmediate_operand" "0,dax,m,0,dax,m")))]
- "TARGET_AM33"
"@
- extbu %0
- mov %1,%0\;extbu %0
- movbu %1,%0
- extbu %0
- mov %1,%0\;extbu %0
- movbu %1,%0"
- [(set_attr_alternative "timings"
- [(const_int 11)
- (const_int 22)
- (if_then_else (eq_attr "cpu" "am34")
- (const_int 13) (const_int 24))
- (const_int 11)
- (const_int 22)
- (if_then_else (eq_attr "cpu" "am34")
- (const_int 13) (const_int 24))
- ])
- ]
-)
-
-(define_insn "*zero_extendqisi2_mn10300"
- [(set (match_operand:SI 0 "register_operand" "=dx,dx,dx")
- (zero_extend:SI
- (match_operand:QI 1 "nonimmediate_operand" "0,d,m")))]
- ""
- "@
- extbu %0
- mov %1,%0\;extbu %0
- movbu %1,%0"
- [(set_attr_alternative "timings"
- [(const_int 11)
- (const_int 22)
- (if_then_else (eq_attr "cpu" "am34")
- (const_int 13) (const_int 24))
- ])
- ]
-)
-
-(define_expand "zero_extendhisi2"
- [(set (match_operand:SI 0 "register_operand")
- (zero_extend:SI
- (match_operand:HI 1 "nonimmediate_operand")))]
- ""
- "")
-
-(define_insn "*zero_extendhisi2_am33"
- [(set (match_operand:SI 0 "register_operand" "=dx,dx,dx,!dax,!dax,!dax")
- (zero_extend:SI
- (match_operand:HI 1 "nonimmediate_operand" "0,dax,m,0,dax,m")))]
- "TARGET_AM33"
- "@
- exthu %0
- mov %1,%0\;exthu %0
- movhu %1,%0
- exthu %0
- mov %1,%0\;exthu %0
- movhu %1,%0"
- [(set_attr_alternative "timings"
- [(const_int 11)
- (const_int 22)
- (if_then_else (eq_attr "cpu" "am34")
- (const_int 13) (const_int 24))
- (const_int 11)
- (const_int 22)
- (if_then_else (eq_attr "cpu" "am34")
- (const_int 13) (const_int 24))
- ])
- ]
+ extbu %0
+ movbu %1,%0
+ extbu %1,%0"
+ [(set_attr "isa" "*,*,am33")
+ (set_attr_alternative "timings"
+ [(const_int 11)
+ (if_then_else (eq_attr "cpu" "am34")
+ (const_int 13) (const_int 24))
+ (const_int 11)
+ ])]
)
-(define_insn "*zero_extendhisi2_mn10300"
- [(set (match_operand:SI 0 "register_operand" "=dx,dx,dx")
+(define_insn "zero_extendhisi2"
+ [(set (match_operand:SI 0 "register_operand" "=D,D,r")
(zero_extend:SI
- (match_operand:HI 1 "nonimmediate_operand" "0,dx,m")))]
- ""
- "@
- exthu %0
- mov %1,%0\;exthu %0
- movhu %1,%0"
- [(set_attr_alternative "timings"
- [(const_int 11)
- (const_int 22)
- (if_then_else (eq_attr "cpu" "am34")
- (const_int 13) (const_int 24))
- ])
- ]
-)
-
-;;- sign extension instructions
-
-(define_expand "extendqisi2"
- [(set (match_operand:SI 0 "register_operand")
- (sign_extend:SI
- (match_operand:QI 1 "register_operand")))]
+ (match_operand:HI 1 "nonimmediate_operand" " 0,m,r")))]
""
- "")
-
-(define_insn "*extendqisi2_am33"
- [(set (match_operand:SI 0 "register_operand" "=dx,dx,!dax,!dax")
- (sign_extend:SI
- (match_operand:QI 1 "register_operand" "0,dx,0,dax")))]
- "TARGET_AM33"
"@
- extb %0
- mov %1,%0\;extb %0
- extb %0
- mov %1,%0\;extb %0"
- [(set_attr "timings" "11,22,11,22")]
-)
-
-(define_insn "*extendqisi2_mn10300"
- [(set (match_operand:SI 0 "register_operand" "=dx,dx")
- (sign_extend:SI
- (match_operand:QI 1 "register_operand" "0,dx")))]
- ""
- "@
- extb %0
- mov %1,%0\;extb %0"
- [(set_attr "timings" "11,22")]
+ exthu %0
+ movhu %1,%0
+ exthu %1,%0"
+ [(set_attr "isa" "*,*,am33")
+ (set_attr_alternative "timings"
+ [(const_int 11)
+ (if_then_else (eq_attr "cpu" "am34")
+ (const_int 13) (const_int 24))
+ (const_int 11)])]
)
-(define_expand "extendhisi2"
- [(set (match_operand:SI 0 "register_operand")
+(define_insn "extendqisi2"
+ [(set (match_operand:SI 0 "register_operand" "=D,r")
(sign_extend:SI
- (match_operand:HI 1 "register_operand")))]
+ (match_operand:QI 1 "register_operand" "0,r")))]
""
- "")
-
-(define_insn "*extendhisi2_am33"
- [(set (match_operand:SI 0 "register_operand" "=dx,dx,!dax,!dax")
- (sign_extend:SI
- (match_operand:HI 1 "register_operand" "0,dax,0,dax")))]
- "TARGET_AM33"
"@
- exth %0
- mov %1,%0\;exth %0
- exth %0
- mov %1,%0\;exth %0"
- [(set_attr "timings" "11,22,11,22")]
+ extb %0
+ extb %1,%0"
+ [(set_attr "isa" "*,am33")]
)
-(define_insn "*extendhisi2_mn10300"
- [(set (match_operand:SI 0 "register_operand" "=dx,dx")
+(define_insn "extendhisi2"
+ [(set (match_operand:SI 0 "register_operand" "=D,r")
(sign_extend:SI
- (match_operand:HI 1 "register_operand" "0,dx")))]
+ (match_operand:HI 1 "register_operand" "0,r")))]
""
"@
- exth %0
- mov %1,%0\;exth %0"
- [(set_attr "timings" "11,22")]
+ exth %0
+ exth %1,%0"
+ [(set_attr "isa" "*,am33")]
)
;; ----------------------------------------------------------------------
;; SHIFTS
;; ----------------------------------------------------------------------
-(define_expand "ashlsi3"
- [(parallel [(set (match_operand:SI 0 "register_operand")
- (ashift:SI
- (match_operand:SI 1 "register_operand")
- (match_operand:QI 2 "nonmemory_operand")))
- (clobber (reg:CC CC_REG))
- ])
- ]
- ""
- "")
-
-(define_insn "*am33_ashlsi3"
- [(set (match_operand:SI 0 "register_operand" "=dax,dx,!dax")
+(define_insn "ashlsi3"
+ [(set (match_operand:SI 0 "register_operand" "=r,D,d,d, D,r")
(ashift:SI
- (match_operand:SI 1 "register_operand" "0,0,dax")
- (match_operand:QI 2 "nonmemory_operand" "J,dxi,dax")))
- (clobber (reg:CC CC_REG))
- ]
- "TARGET_AM33"
- "*
- {
- if (CONST_INT_P (operands[2]) && INTVAL (operands[2]) == 1)
- return \"add %0,%0\";
-
- if (CONST_INT_P (operands[2]) && INTVAL (operands[2]) == 2)
- return \"asl2 %0\";
-
- if (CONST_INT_P (operands[2]) && INTVAL (operands[2]) == 3
- && REGNO_REG_CLASS (true_regnum (operands[0])) == DATA_REGS)
- return \"asl2 %0\;add %0,%0\";
-
- if (CONST_INT_P (operands[2]) && INTVAL (operands[2]) == 4
- && REGNO_REG_CLASS (true_regnum (operands[0])) == DATA_REGS)
- return \"asl2 %0\;asl2 %0\";
-
- if (true_regnum (operands[1]) == true_regnum (operands[0]))
- return \"asl %S2,%0\";
-
- if (REGNO_REG_CLASS (true_regnum (operands[0])) == DATA_REGS
- && REGNO_REG_CLASS (true_regnum (operands[1])) == DATA_REGS
- && true_regnum (operands[0]) != true_regnum (operands[2]))
- return \"mov %1,%0\;asl %S2,%0\";
- return \"asl %2,%1,%0\";
- }"
- [(set_attr "timings" "22")]
-)
-
-(define_insn "*mn10300_ashlsi3"
- [(set (match_operand:SI 0 "register_operand" "=dax,dx,dx,dx,dx")
- (ashift:SI
- (match_operand:SI 1 "register_operand" "0,0,0,0,0")
- (match_operand:QI 2 "nonmemory_operand" "J,K,M,L,dxi")))
- (clobber (reg:CC CC_REG))
- ]
+ (match_operand:SI 1 "register_operand" " 0,0,0,0, 0,r")
+ (match_operand:QI 2 "nonmemory_operand" " J,K,M,L,Di,r")))
+ (clobber (reg:CC CC_REG))]
""
"@
- add %0,%0
- asl2 %0
- asl2 %0\;add %0,%0
- asl2 %0\;asl2 %0
- asl %S2,%0"
- [(set_attr "timings" "11,11,22,22,11")]
-)
-
-(define_expand "lshrsi3"
- [(parallel [(set (match_operand:SI 0 "register_operand")
- (lshiftrt:SI
- (match_operand:SI 1 "register_operand")
- (match_operand:QI 2 "nonmemory_operand")))
- (clobber (reg:CC CC_REG))
- ])
- ]
- ""
- "")
-
-(define_insn "*am33_lshrsi3"
- [(set (match_operand:SI 0 "register_operand" "=dx,!dax")
+ add %0,%0
+ asl2 %0
+ asl2 %0\;add %0,%0
+ asl2 %0\;asl2 %0
+ asl %S2,%0
+ asl %2,%1,%0"
+ [(set_attr "isa" "*,*,*,*,*,am33")
+ (set_attr "timings" "11,11,22,22,11,11")]
+)
+
+(define_insn "lshrsi3"
+ [(set (match_operand:SI 0 "register_operand" "=D,r")
(lshiftrt:SI
- (match_operand:SI 1 "register_operand" "0,dax")
- (match_operand:QI 2 "nonmemory_operand" "dxi,dax")))
- (clobber (reg:CC CC_REG))
- ]
- "TARGET_AM33"
- "*
- {
- if (true_regnum (operands[1]) == true_regnum (operands[0]))
- return \"lsr %S2,%0\";
-
- if (REGNO_REG_CLASS (true_regnum (operands[0])) == DATA_REGS
- && REGNO_REG_CLASS (true_regnum (operands[1])) == DATA_REGS
- && true_regnum (operands[0]) != true_regnum (operands[2]))
- return \"mov %1,%0\;lsr %S2,%0\";
- return \"lsr %2,%1,%0\";
- }"
- [(set_attr "timings" "22")]
-)
-
-(define_insn "*mn10300_lshrsi3"
- [(set (match_operand:SI 0 "register_operand" "=dx")
- (lshiftrt:SI
- (match_operand:SI 1 "register_operand" "0")
- (match_operand:QI 2 "nonmemory_operand" "dxi")))
- (clobber (reg:CC CC_REG))
- ]
- ""
- "lsr %S2,%0"
- [(set (attr "timings") (if_then_else (eq_attr "cpu" "am34")
- (const_int 11) (const_int 22)))]
-)
-
-(define_expand "ashrsi3"
- [(parallel [(set (match_operand:SI 0 "register_operand")
- (ashiftrt:SI
- (match_operand:SI 1 "register_operand")
- (match_operand:QI 2 "nonmemory_operand")))
- (clobber (reg:CC CC_REG))
- ])
- ]
+ (match_operand:SI 1 "register_operand" " 0,r")
+ (match_operand:QI 2 "nonmemory_operand" "Di,r")))
+ (clobber (reg:CC CC_REG))]
""
- "")
-
-(define_insn "*am33_ashrisi3"
- [(set (match_operand:SI 0 "register_operand" "=dx,!dax")
- (ashiftrt:SI
- (match_operand:SI 1 "register_operand" "0,dax")
- (match_operand:QI 2 "nonmemory_operand" "dxi,dax")))
- (clobber (reg:CC CC_REG))
- ]
- "TARGET_AM33"
- "*
- {
- if (true_regnum (operands[1]) == true_regnum (operands[0]))
- return \"asr %S2,%0\";
-
- if (REGNO_REG_CLASS (true_regnum (operands[0])) == DATA_REGS
- && REGNO_REG_CLASS (true_regnum (operands[1])) == DATA_REGS
- && true_regnum (operands[0]) != true_regnum (operands[2]))
- return \"mov %1,%0\;asr %S2,%0\";
- return \"asr %2,%1,%0\";
- }"
- [(set_attr "timings" "22")]
+ "@
+ lsr %S2,%0
+ lsr %2,%1,%0"
+ [(set_attr "isa" "*,am33")]
)
-(define_insn "*mn10300_ashrsi3"
- [(set (match_operand:SI 0 "register_operand" "=dx")
+(define_insn "ashrsi3"
+ [(set (match_operand:SI 0 "register_operand" "=D,r")
(ashiftrt:SI
- (match_operand:SI 1 "register_operand" "0")
- (match_operand:QI 2 "nonmemory_operand" "dxi")))
- (clobber (reg:CC CC_REG))
- ]
+ (match_operand:SI 1 "register_operand" " 0,r")
+ (match_operand:QI 2 "nonmemory_operand" "Di,r")))
+ (clobber (reg:CC CC_REG))]
""
- "asr %S2,%0"
- [(set (attr "timings") (if_then_else (eq_attr "cpu" "am34")
- (const_int 11) (const_int 22)))]
+ "@
+ asr %S2,%0
+ asr %2,%1,%0"
+ [(set_attr "isa" "*,am33")]
)
;; ----------------------------------------------------------------------
@@ -2092,28 +1686,6 @@
[(set_attr "timings" "66")]
)
-;; Try to combine consecutive updates of the stack pointer (or any
-;; other register for that matter).
-(define_peephole
- [(parallel [(set (match_operand:SI 0 "register_operand" "=dxay")
- (plus:SI (match_dup 0)
- (match_operand 1 "const_int_operand" "")))
- (clobber (reg:CC CC_REG))
- ])
- (parallel [(set (match_dup 0)
- (plus:SI (match_dup 0)
- (match_operand 2 "const_int_operand" "")))
- (clobber (reg:CC CC_REG))
- ])
- ]
- ""
- "*
-{
- operands[1] = GEN_INT (INTVAL (operands[2]) + INTVAL (operands[1]));
- return \"add %1,%0\";
-}"
-)
-
(define_expand "int_label"
[(unspec [(match_operand:SI 0 "" "")] UNSPEC_INT_LABEL)]
"" "")
diff --git a/gcc/config/mn10300/predicates.md b/gcc/config/mn10300/predicates.md
index df1b1f4..4badebb 100644
--- a/gcc/config/mn10300/predicates.md
+++ b/gcc/config/mn10300/predicates.md
@@ -42,3 +42,19 @@
return XEXP (op, 0) == stack_pointer_rtx
|| XEXP (op, 1) == stack_pointer_rtx;
})
+
+(define_predicate "label_ref_operand"
+ (match_code "label_ref"))
+
+(define_special_predicate "int_mode_flags"
+ (match_code "reg")
+{
+ if (REGNO (op) != CC_REG)
+ return false;
+ if (GET_MODE (op) == CC_FLOATmode)
+ return false;
+ return GET_MODE_CLASS (GET_MODE (op)) == MODE_CC;
+})
+
+(define_predicate "CCZN_comparison_operator"
+ (match_code "eq,ne,lt,ge"))