/* Subroutines used for code generation on Renesas RX processors.
- Copyright (C) 2008, 2009, 2010 Free Software Foundation, Inc.
+ Copyright (C) 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
Contributed by Red Hat.
This file is part of GCC.
#include "target-def.h"
#include "langhooks.h"
\f
+#define CC_FLAG_S (1 << 0)
+#define CC_FLAG_Z (1 << 1)
+#define CC_FLAG_O (1 << 2)
+#define CC_FLAG_C (1 << 3)
+#define CC_FLAG_FP (1 << 4) /* Fake, to differentiate CC_Fmode. */
+
enum rx_cpu_types rx_cpu_type = RX600;
\f
/* Return true if OP is a reference to an object in a small data area. */
break;
}
+ case CONST:
+ if (GET_CODE (XEXP (addr, 0)) == UNSPEC)
+ {
+ addr = XEXP (addr, 0);
+ gcc_assert (XINT (addr, 1) == UNSPEC_CONST);
+
+ addr = XVECEXP (addr, 0, 0);
+ gcc_assert (CONST_INT_P (addr));
+ }
+ /* Fall through. */
case LABEL_REF:
case SYMBOL_REF:
- case CONST:
fprintf (file, "#");
default:
output_addr_const (file, addr);
return true;
}
+/* Convert a CC_MODE to the set of flags that it represents. */
+
+static unsigned int
+flags_from_mode (enum machine_mode mode)
+{
+ switch (mode)
+ {
+ case CC_ZSmode:
+ return CC_FLAG_S | CC_FLAG_Z;
+ case CC_ZSOmode:
+ return CC_FLAG_S | CC_FLAG_Z | CC_FLAG_O;
+ case CC_ZSCmode:
+ return CC_FLAG_S | CC_FLAG_Z | CC_FLAG_C;
+ case CCmode:
+ return CC_FLAG_S | CC_FLAG_Z | CC_FLAG_O | CC_FLAG_C;
+ case CC_Fmode:
+ return CC_FLAG_FP;
+ default:
+ gcc_unreachable ();
+ }
+}
+
+/* Convert a set of flags to a CC_MODE that can implement it. */
+
+static enum machine_mode
+mode_from_flags (unsigned int f)
+{
+ if (f & CC_FLAG_FP)
+ return CC_Fmode;
+ if (f & CC_FLAG_O)
+ {
+ if (f & CC_FLAG_C)
+ return CCmode;
+ else
+ return CC_ZSOmode;
+ }
+ else if (f & CC_FLAG_C)
+ return CC_ZSCmode;
+ else
+ return CC_ZSmode;
+}
+
+/* Convert an RTX_CODE to the set of flags needed to implement it.
+ This assumes an integer comparison. */
-int rx_float_compare_mode;
+static unsigned int
+flags_from_code (enum rtx_code code)
+{
+ switch (code)
+ {
+ case LT:
+ case GE:
+ return CC_FLAG_S | CC_FLAG_O;
+ case GT:
+ case LE:
+ return CC_FLAG_S | CC_FLAG_O | CC_FLAG_Z;
+ case GEU:
+ case LTU:
+ return CC_FLAG_C;
+ case GTU:
+ case LEU:
+ return CC_FLAG_C | CC_FLAG_Z;
+ case EQ:
+ case NE:
+ return CC_FLAG_Z;
+ default:
+ gcc_unreachable ();
+ }
+}
/* Handles the insertion of a single operand into the assembler output.
The %<letter> directives supported are:
break;
case 'B':
- switch (GET_CODE (op))
- {
- case LT: fprintf (file, "lt"); break;
- case GE: fprintf (file, "ge"); break;
- case GT: fprintf (file, "gt"); break;
- case LE: fprintf (file, "le"); break;
- case GEU: fprintf (file, "geu"); break;
- case LTU: fprintf (file, "ltu"); break;
- case GTU: fprintf (file, "gtu"); break;
- case LEU: fprintf (file, "leu"); break;
- case EQ: fprintf (file, "eq"); break;
- case NE: fprintf (file, "ne"); break;
- default: debug_rtx (op); gcc_unreachable ();
- }
- break;
+ {
+ enum rtx_code code = GET_CODE (op);
+ enum machine_mode mode = GET_MODE (XEXP (op, 0));
+ const char * ret;
+
+ if (mode == CC_Fmode)
+ {
+ /* C flag is undefined, and O flag carries unordered. None of the
+ branch combinations that include O use it helpfully. */
+ switch (code)
+ {
+ case ORDERED: ret = "no"; break;
+ case UNORDERED: ret = "o"; break;
+ case LT: ret = "n"; break;
+ case GE: ret = "pz"; break;
+ case EQ: ret = "eq"; break;
+ case NE: ret = "ne"; break;
+ default: gcc_unreachable ();
+ }
+ }
+ else
+ {
+ switch (code)
+ {
+ case LT: ret = "lt"; break;
+ case GE: ret = "ge"; break;
+ case GT: ret = "gt"; break;
+ case LE: ret = "le"; break;
+ case GEU: ret = "geu"; break;
+ case LTU: ret = "ltu"; break;
+ case GTU: ret = "gtu"; break;
+ case LEU: ret = "leu"; break;
+ case EQ: ret = "eq"; break;
+ case NE: ret = "ne"; break;
+ default: gcc_unreachable ();
+ }
+ gcc_assert ((flags_from_code (code)
+ & ~flags_from_mode (mode)) == 0);
+ }
+ fputs (ret, file);
+ break;
+ }
case 'C':
gcc_assert (CONST_INT_P (op));
extension, src_template, dst_template);
return out_template;
}
-
-/* Returns an assembler template for a conditional branch instruction. */
-
-const char *
-rx_gen_cond_branch_template (rtx condition, bool reversed)
-{
- enum rtx_code code = GET_CODE (condition);
-
- if (reversed)
- {
- if (rx_float_compare_mode)
- code = reverse_condition_maybe_unordered (code);
- else
- code = reverse_condition (code);
- }
-
- /* We do not worry about encoding the branch length here as GAS knows
- how to choose the smallest version, and how to expand a branch that
- is to a destination that is out of range. */
-
- switch (code)
- {
- case UNEQ: return "bo\t1f\n\tbeq\t%0\n1:";
- case LTGT: return "bo\t1f\n\tbne\t%0\n1:";
- case UNLT: return "bo\t1f\n\tbn\t%0\n1:";
- case UNGE: return "bo\t1f\n\tbpz\t%0\n1:";
- case UNLE: return "bo\t1f\n\tbgt\t1f\n\tbra\t%0\n1:";
- case UNGT: return "bo\t1f\n\tble\t1f\n\tbra\t%0\n1:";
- case UNORDERED: return "bo\t%0";
- case ORDERED: return "bno\t%0";
-
- case LT: return rx_float_compare_mode ? "bn\t%0" : "blt\t%0";
- case GE: return rx_float_compare_mode ? "bpz\t%0" : "bge\t%0";
- case GT: return "bgt\t%0";
- case LE: return "ble\t%0";
- case GEU: return "bgeu\t%0";
- case LTU: return "bltu\t%0";
- case GTU: return "bgtu\t%0";
- case LEU: return "bleu\t%0";
- case EQ: return "beq\t%0";
- case NE: return "bne\t%0";
- default:
- gcc_unreachable ();
- }
-}
\f
/* Return VALUE rounded up to the next ALIGNMENT boundary. */
/* RX ABI specifies that small integer types are
promoted to int when returned by a function. */
- if (GET_MODE_SIZE (mode) > 0 && GET_MODE_SIZE (mode) < 4)
+ if (GET_MODE_SIZE (mode) > 0
+ && GET_MODE_SIZE (mode) < 4
+ && ! COMPLEX_MODE_P (mode))
return gen_rtx_REG (SImode, FUNC_RETURN_REGNUM);
return gen_rtx_REG (mode, FUNC_RETURN_REGNUM);
{
if (for_return != 1
|| GET_MODE_SIZE (mode) >= 4
+ || COMPLEX_MODE_P (mode)
|| GET_MODE_SIZE (mode) < 1)
return mode;
for (save_mask = high = low = 0, reg = 1; reg < CC_REGNUM; reg++)
{
- if (df_regs_ever_live_p (reg)
+ if ((df_regs_ever_live_p (reg)
+ /* Always save all call clobbered registers inside non-leaf
+ interrupt handlers, even if they are not live - they may
+ be used in (non-interrupt aware) routines called from this one. */
+ || (call_used_regs[reg]
+ && is_interrupt_func (NULL_TREE)
+ && ! current_function_is_leaf))
&& (! call_used_regs[reg]
/* Even call clobbered registered must
be pushed inside interrupt handlers. */
}
}
+static bool
+ok_for_max_constant (HOST_WIDE_INT val)
+{
+ if (rx_max_constant_size == 0 || rx_max_constant_size == 4)
+ /* If there is no constraint on the size of constants
+ used as operands, then any value is legitimate. */
+ return true;
+
+ /* rx_max_constant_size specifies the maximum number
+ of bytes that can be used to hold a signed value. */
+ return IN_RANGE (val, (-1 << (rx_max_constant_size * 8)),
+ ( 1 << (rx_max_constant_size * 8)));
+}
+
+/* Generate an ADD of SRC plus VAL into DEST.
+ Handles the case where VAL is too big for max_constant_value.
+ Sets FRAME_RELATED_P on the insn if IS_FRAME_RELATED is true. */
+
+static void
+gen_safe_add (rtx dest, rtx src, rtx val, bool is_frame_related)
+{
+ rtx insn;
+
+ if (val == NULL_RTX || INTVAL (val) == 0)
+ {
+ gcc_assert (dest != src);
+
+ insn = emit_move_insn (dest, src);
+ }
+ else if (ok_for_max_constant (INTVAL (val)))
+ insn = emit_insn (gen_addsi3 (dest, src, val));
+ else
+ {
+ /* Wrap VAL in an UNSPEC so that rx_is_legitimate_constant
+ will not reject it. */
+ val = gen_rtx_CONST (SImode, gen_rtx_UNSPEC (SImode, gen_rtvec (1, val), UNSPEC_CONST));
+ insn = emit_insn (gen_addsi3 (dest, src, val));
+
+ if (is_frame_related)
+ /* We have to provide our own frame related note here
+ as the dwarf2out code cannot be expected to grok
+ our unspec. */
+ add_reg_note (insn, REG_FRAME_RELATED_EXPR,
+ gen_rtx_SET (SImode, dest,
+ gen_rtx_PLUS (SImode, src, val)));
+ return;
+ }
+
+ if (is_frame_related)
+ RTX_FRAME_RELATED_P (insn) = 1;
+ return;
+}
+
void
rx_expand_prologue (void)
{
emit_insn (gen_stack_pushm (GEN_INT (2 * UNITS_PER_WORD),
gen_rx_store_vector (acc_low, acc_high)));
}
-
- frame_size += 2 * UNITS_PER_WORD;
}
/* If needed, set up the frame pointer. */
if (frame_pointer_needed)
- {
- if (frame_size)
- insn = emit_insn (gen_addsi3 (frame_pointer_rtx, stack_pointer_rtx,
- GEN_INT (- (HOST_WIDE_INT) frame_size)));
- else
- insn = emit_move_insn (frame_pointer_rtx, stack_pointer_rtx);
-
- RTX_FRAME_RELATED_P (insn) = 1;
- }
-
- insn = NULL_RTX;
+ gen_safe_add (frame_pointer_rtx, stack_pointer_rtx,
+ GEN_INT (- (HOST_WIDE_INT) frame_size), true);
/* Allocate space for the outgoing args.
If the stack frame has not already been set up then handle this as well. */
if (frame_size)
{
if (frame_pointer_needed)
- insn = emit_insn (gen_addsi3 (stack_pointer_rtx, frame_pointer_rtx,
- GEN_INT (- (HOST_WIDE_INT)
- stack_size)));
+ gen_safe_add (stack_pointer_rtx, frame_pointer_rtx,
+ GEN_INT (- (HOST_WIDE_INT) stack_size), true);
else
- insn = emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx,
- GEN_INT (- (HOST_WIDE_INT)
- (frame_size + stack_size))));
+ gen_safe_add (stack_pointer_rtx, stack_pointer_rtx,
+ GEN_INT (- (HOST_WIDE_INT) (frame_size + stack_size)),
+ true);
}
else
- insn = emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx,
- GEN_INT (- (HOST_WIDE_INT) stack_size)));
+ gen_safe_add (stack_pointer_rtx, stack_pointer_rtx,
+ GEN_INT (- (HOST_WIDE_INT) stack_size), true);
}
else if (frame_size)
{
if (! frame_pointer_needed)
- insn = emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx,
- GEN_INT (- (HOST_WIDE_INT) frame_size)));
+ gen_safe_add (stack_pointer_rtx, stack_pointer_rtx,
+ GEN_INT (- (HOST_WIDE_INT) frame_size), true);
else
- insn = emit_move_insn (stack_pointer_rtx, frame_pointer_rtx);
+ gen_safe_add (stack_pointer_rtx, frame_pointer_rtx, NULL_RTX,
+ true);
}
-
- if (insn != NULL_RTX)
- RTX_FRAME_RELATED_P (insn) = 1;
}
static void
{
/* Cannot use the special instructions - deconstruct by hand. */
if (total_size)
- emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx,
- GEN_INT (total_size)));
+ gen_safe_add (stack_pointer_rtx, stack_pointer_rtx,
+ GEN_INT (total_size), false);
if (MUST_SAVE_ACC_REGISTER)
{
return;
}
- emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx,
- GEN_INT (total_size)));
+ gen_safe_add (stack_pointer_rtx, stack_pointer_rtx,
+ GEN_INT (total_size), false);
}
if (low)
if (rx_cpu_type == RX610)
return NULL_RTX;
- if (! CONST_INT_P (arg) || ! IN_RANGE (arg, 0, (1 << 4) - 1))
+ if (! CONST_INT_P (arg) || ! IN_RANGE (INTVAL (arg), 0, (1 << 4) - 1))
return NULL_RTX;
emit_insn (gen_mvtipl (arg));
return target;
}
+static int
+valid_psw_flag (rtx op, const char *which)
+{
+ static int mvtc_inform_done = 0;
+
+ if (GET_CODE (op) == CONST_INT)
+ switch (INTVAL (op))
+ {
+ case 0: case 'c': case 'C':
+ case 1: case 'z': case 'Z':
+ case 2: case 's': case 'S':
+ case 3: case 'o': case 'O':
+ case 8: case 'i': case 'I':
+ case 9: case 'u': case 'U':
+ return 1;
+ }
+
+ error ("__builtin_rx_%s takes 'C', 'Z', 'S', 'O', 'I', or 'U'", which);
+ if (!mvtc_inform_done)
+ error ("use __builtin_rx_mvtc (0, ... ) to write arbitrary values to PSW");
+ mvtc_inform_done = 1;
+
+ return 0;
+}
+
static rtx
rx_expand_builtin (tree exp,
rtx target,
switch (fcode)
{
case RX_BUILTIN_BRK: emit_insn (gen_brk ()); return NULL_RTX;
- case RX_BUILTIN_CLRPSW: return rx_expand_void_builtin_1_arg
- (op, gen_clrpsw, false);
- case RX_BUILTIN_SETPSW: return rx_expand_void_builtin_1_arg
- (op, gen_setpsw, false);
+ case RX_BUILTIN_CLRPSW:
+ if (! valid_psw_flag (op, "clrpsw"))
+ return NULL_RTX;
+ return rx_expand_void_builtin_1_arg (op, gen_clrpsw, false);
+ if (! valid_psw_flag (op, "setpsw"))
+ return NULL_RTX;
+ return rx_expand_void_builtin_1_arg (op, gen_setpsw, false);
+ case RX_BUILTIN_SETPSW:
case RX_BUILTIN_INT: return rx_expand_void_builtin_1_arg
(op, gen_int, false);
case RX_BUILTIN_MACHI: return rx_expand_builtin_mac (exp, gen_machi);
error ("Changing the FPU insns/math optimizations pairing is not supported");
}
}
-
\f
static bool
rx_allocate_stack_slots_for_args (void)
static bool
rx_is_ms_bitfield_layout (const_tree record_type ATTRIBUTE_UNUSED)
{
- return TRUE;
+ /* The packed attribute overrides the MS behaviour. */
+ return ! TYPE_PACKED (record_type);
}
-/* Try to generate code for the "isnv" pattern which inserts bits
- into a word.
- operands[0] => Location to be altered.
- operands[1] => Number of bits to change.
- operands[2] => Starting bit.
- operands[3] => Value to insert.
- Returns TRUE if successful, FALSE otherwise. */
-
-bool
-rx_expand_insv (rtx * operands)
-{
- if (INTVAL (operands[1]) != 1
- || ! CONST_INT_P (operands[3]))
- return false;
-
- if (MEM_P (operands[0])
- && INTVAL (operands[2]) > 7)
- return false;
-
- switch (INTVAL (operands[3]))
- {
- case 0:
- if (MEM_P (operands[0]))
- emit_insn (gen_bitclr_in_memory (operands[0], operands[0],
- operands[2]));
- else
- emit_insn (gen_bitclr (operands[0], operands[0], operands[2]));
- break;
- case 1:
- case -1:
- if (MEM_P (operands[0]))
- emit_insn (gen_bitset_in_memory (operands[0], operands[0],
- operands[2]));
- else
- emit_insn (gen_bitset (operands[0], operands[0], operands[2]));
- break;
- default:
- return false;
- }
- return true;
-}
\f
/* Returns true if X a legitimate constant for an immediate
operand on the RX. X is already known to satisfy CONSTANT_P. */
bool
rx_is_legitimate_constant (rtx x)
{
- HOST_WIDE_INT val;
-
switch (GET_CODE (x))
{
case CONST:
case SYMBOL_REF:
return true;
- /* One day we may have to handle UNSPEC constants here. */
+ case UNSPEC:
+ return XINT (x, 1) == UNSPEC_CONST;
+
default:
/* FIXME: Can this ever happen ? */
abort ();
break;
}
- if (rx_max_constant_size == 0 || rx_max_constant_size == 4)
- /* If there is no constraint on the size of constants
- used as operands, then any value is legitimate. */
- return true;
-
- val = INTVAL (x);
-
- /* rx_max_constant_size specifies the maximum number
- of bytes that can be used to hold a signed value. */
- return IN_RANGE (val, (-1 << (rx_max_constant_size * 8)),
- ( 1 << (rx_max_constant_size * 8)));
+ return ok_for_max_constant (INTVAL (x));
}
static int
}
}
+/* Return a CC_MODE of which both M1 and M2 are subsets. */
+
static enum machine_mode
rx_cc_modes_compatible (enum machine_mode m1, enum machine_mode m2)
{
- if (m1 == CCmode)
- return m2;
- if (m2 == CCmode)
- return m1;
+ unsigned f;
+
+ /* Early out for identical modes. */
if (m1 == m2)
return m1;
- if (m1 == CC_ZSmode)
- return m1;
- if (m2 == CC_ZSmode)
- return m2;
- return VOIDmode;
+
+ /* There's no valid combination for FP vs non-FP. */
+ f = flags_from_mode (m1) | flags_from_mode (m2);
+ if (f & CC_FLAG_FP)
+ return VOIDmode;
+
+ /* Otherwise, see what mode can implement all the flags. */
+ return mode_from_flags (f);
}
-#define CC_FLAG_S (1 << 0)
-#define CC_FLAG_Z (1 << 1)
-#define CC_FLAG_O (1 << 2)
-#define CC_FLAG_C (1 << 3)
+/* Return the minimal CC mode needed to implement (CMP_CODE X Y). */
-static unsigned int
-flags_needed_for_conditional (rtx conditional)
+enum machine_mode
+rx_select_cc_mode (enum rtx_code cmp_code, rtx x, rtx y ATTRIBUTE_UNUSED)
{
- switch (GET_CODE (conditional))
- {
- case LE:
- case GT: return CC_FLAG_S | CC_FLAG_Z | CC_FLAG_O;
-
- case LEU:
- case GTU: return CC_FLAG_Z | CC_FLAG_C;
+ if (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT)
+ return CC_Fmode;
- case LT:
- case GE: return CC_FLAG_S | CC_FLAG_O;
+ return mode_from_flags (flags_from_code (cmp_code));
+}
- case LTU:
- case GEU: return CC_FLAG_C;
+/* Split the conditional branch. Emit (COMPARE C1 C2) into CC_REG with
+ CC_MODE, and use that in branches based on that compare. */
- case EQ:
- case NE: return CC_FLAG_Z;
+void
+rx_split_cbranch (enum machine_mode cc_mode, enum rtx_code cmp1,
+ rtx c1, rtx c2, rtx label)
+{
+ rtx flags, x;
- default: gcc_unreachable ();
- }
-}
+ flags = gen_rtx_REG (cc_mode, CC_REG);
+ x = gen_rtx_COMPARE (cc_mode, c1, c2);
+ x = gen_rtx_SET (VOIDmode, flags, x);
+ emit_insn (x);
-static unsigned int
-flags_from_mode (enum machine_mode mode)
-{
- switch (mode)
- {
- case CCmode: return CC_FLAG_S | CC_FLAG_Z | CC_FLAG_O | CC_FLAG_C;
- case CC_ZSmode: return CC_FLAG_S | CC_FLAG_Z;
- case CC_ZSOmode: return CC_FLAG_S | CC_FLAG_Z | CC_FLAG_O;
- case CC_ZSCmode: return CC_FLAG_S | CC_FLAG_Z | CC_FLAG_C;
- default: gcc_unreachable ();
- }
+ x = gen_rtx_fmt_ee (cmp1, VOIDmode, flags, const0_rtx);
+ x = gen_rtx_IF_THEN_ELSE (VOIDmode, x, label, pc_rtx);
+ x = gen_rtx_SET (VOIDmode, pc_rtx, x);
+ emit_jump_insn (x);
}
-/* Returns true if a compare insn is redundant because it
- would only set flags that are already set correctly. */
+/* A helper function for matching parallels that set the flags. */
bool
-rx_compare_redundant (rtx cmp)
-{
- unsigned int flags_needed;
- unsigned int flags_set;
- rtx next;
- rtx prev;
- rtx source;
- rtx dest;
- static rtx cc_reg = NULL_RTX;
-
- if (cc_reg == NULL_RTX)
- cc_reg = gen_rtx_REG (CCmode, CC_REGNUM);
-
- /* We can only eliminate compares against 0. */
- if (GET_CODE (XEXP (SET_SRC (PATTERN (cmp)), 1)) != CONST_INT
- || INTVAL (XEXP (SET_SRC (PATTERN (cmp)), 1)) != 0)
- return false;
-
- /* Locate the branch insn that follows the
- compare and which tests the bits in the PSW. */
- next = cmp;
- do
- {
- /* If we have found an insn that sets or clobbers the CC
- register and it was not the IF_THEN_ELSE insn that we
- are looking for, then the comparison is redundant. */
- if (next != cmp && reg_mentioned_p (cc_reg, PATTERN (next)))
- return true;
-
- next = next_nonnote_insn (next);
-
- /* If we run out of insns without finding the
- user then the comparison is unnecessary. */
- if (next == NULL_RTX)
- return true;
-
- /* If we have found another comparison
- insn then the first one is redundant. */
- if (INSN_P (next)
- && GET_CODE (PATTERN (next)) == SET
- && REG_P (SET_DEST (PATTERN (next)))
- && REGNO (SET_DEST (PATTERN (next))) == CC_REGNUM)
- return true;
+rx_match_ccmode (rtx insn, enum machine_mode cc_mode)
+{
+ rtx op1, flags;
+ enum machine_mode flags_mode;
- /* If we have found another arithmetic/logic insn that
- sets the PSW flags then the comparison is redundant. */
- if (INSN_P (next)
- && GET_CODE (PATTERN (next)) == PARALLEL
- && GET_CODE (XVECEXP (PATTERN (next), 0, 1)) == SET
- && REG_P (SET_DEST (XVECEXP (PATTERN (next), 0, 1)))
- && REGNO (SET_DEST (XVECEXP (PATTERN (next), 0, 1))) == CC_REGNUM)
- return true;
+ gcc_assert (XVECLEN (PATTERN (insn), 0) == 2);
- /* If we have found an unconditional branch then the
- PSW flags might be carried along with the jump, so
- the comparison is necessary. */
- if (INSN_P (next) && JUMP_P (next))
- {
- if (GET_CODE (PATTERN (next)) != SET)
- /* If the jump does not involve setting the PC
- then it is a return of some kind, and we know
- that the comparison is not used. */
- return true;
+ op1 = XVECEXP (PATTERN (insn), 0, 1);
+ gcc_assert (GET_CODE (SET_SRC (op1)) == COMPARE);
- if (GET_CODE (SET_SRC (PATTERN (next))) != IF_THEN_ELSE)
- return false;
- }
- }
- while (! INSN_P (next)
- || DEBUG_INSN_P (next)
- || GET_CODE (PATTERN (next)) != SET
- || GET_CODE (SET_SRC (PATTERN (next))) != IF_THEN_ELSE);
-
- flags_needed = flags_needed_for_conditional (XEXP (SET_SRC (PATTERN (next)), 0));
-
- /* Now look to see if there was a previous
- instruction which set the PSW bits. */
- source = XEXP (SET_SRC (PATTERN (cmp)), 0);
- prev = cmp;
- do
- {
- /* If this insn uses/sets/clobbers the CC register
- and it is not the insn that we are looking for
- below, then we must need the comparison. */
- if (prev != cmp && reg_mentioned_p (cc_reg, PATTERN (prev)))
- return false;
-
- prev = prev_nonnote_insn (prev);
+ flags = SET_DEST (op1);
+ flags_mode = GET_MODE (flags);
- if (prev == NULL_RTX)
- return false;
-
- /* If we encounter an insn which changes the contents of
- the register which is the source of the comparison then
- we will definitely need the comparison. */
- if (INSN_P (prev)
- && GET_CODE (PATTERN (prev)) == SET
- && rtx_equal_p (SET_DEST (PATTERN (prev)), source))
- {
- /* Unless this instruction is a simple register move
- instruction. In which case we can continue our
- scan backwards, but now using the *source* of this
- set instruction. */
- if (REG_P (SET_SRC (PATTERN (prev))))
- source = SET_SRC (PATTERN (prev));
- /* We can also survive a sign-extension if the test is
- for EQ/NE. Note the same does not apply to zero-
- extension as this can turn a non-zero bit-pattern
- into zero. */
- else if (flags_needed == CC_FLAG_Z
- && GET_CODE (SET_SRC (PATTERN (prev))) == SIGN_EXTEND)
- source = XEXP (SET_SRC (PATTERN (prev)), 0);
- else
- return false;
- }
+ if (GET_MODE (SET_SRC (op1)) != flags_mode)
+ return false;
+ if (GET_MODE_CLASS (flags_mode) != MODE_CC)
+ return false;
- /* A label means a possible branch into the
- code here, so we have to stop scanning. */
- if (LABEL_P (prev))
- return false;
- }
- while (! INSN_P (prev)
- || DEBUG_INSN_P (prev)
- || GET_CODE (PATTERN (prev)) != PARALLEL
- || GET_CODE (XVECEXP (PATTERN (prev), 0, 1)) != SET
- || ! REG_P (SET_DEST (XVECEXP (PATTERN (prev), 0, 1)))
- || REGNO (SET_DEST (XVECEXP (PATTERN (prev), 0, 1))) != CC_REGNUM);
-
- flags_set = flags_from_mode (GET_MODE (SET_DEST (XVECEXP (PATTERN (prev), 0, 1))));
-
- dest = SET_DEST (XVECEXP (PATTERN (prev), 0, 0));
- /* The destination of the previous arithmetic/logic instruction
- must match the source in the comparison operation. For registers
- we ignore the mode as there may have been a sign-extension involved. */
- if (! rtx_equal_p (source, dest))
- {
- if (REG_P (source) && REG_P (dest) && REGNO (dest) == REGNO (source))
- ;
- else
- return false;
- }
+ /* Ensure that the mode of FLAGS is compatible with CC_MODE. */
+ if (flags_from_mode (flags_mode) & ~flags_from_mode (cc_mode))
+ return false;
- return ((flags_set & flags_needed) == flags_needed);
+ return true;
}
\f
#undef TARGET_FUNCTION_VALUE
;; Machine Description for Renesas RX processors
-;; Copyright (C) 2008, 2009, 2010 Free Software Foundation, Inc.
+;; Copyright (C) 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
;; Contributed by Red Hat.
;; This file is part of GCC.
;; <http://www.gnu.org/licenses/>.
\f
-;; This code iterator allows all branch instructions to
-;; be generated from a single define_expand template.
-(define_code_iterator most_cond [eq ne gt ge lt le gtu geu ltu leu
- unordered ordered ])
-
-;; Likewise, but only the ones that use Z or S.
-(define_code_iterator zs_cond [eq ne gtu geu ltu leu ])
-
;; This code iterator is used for sign- and zero- extensions.
(define_mode_iterator small_int_modes [(HI "") (QI "")])
[(SF "ALLOW_RX_FPU_INSNS") (SI "") (HI "") (QI "")])
-;; Used to map RX condition names to GCC
-;; condition names for builtin instructions.
-(define_code_iterator gcc_conds [eq ne gt ge lt le gtu geu ltu leu
- unge unlt uneq ltgt])
-(define_code_attr rx_conds [(eq "eq") (ne "ne") (gt "gt") (ge "ge") (lt "lt")
- (le "le") (gtu "gtu") (geu "geu") (ltu "ltu")
- (leu "leu") (unge "pz") (unlt "n") (uneq "o")
- (ltgt "no")])
-
(define_constants
[
(SP_REG 0)
(UNSPEC_RTE 10)
(UNSPEC_RTFI 11)
(UNSPEC_NAKED 12)
+ (UNSPEC_CONST 13)
(UNSPEC_MOVSTR 20)
(UNSPEC_MOVMEM 21)
(define_insn_reservation "throughput_18_latency_18" 1
(eq_attr "timings" "1818") "throughput*18")
+;; ----------------------------------------------------------------------------
+
;; Comparisons
;; Note - we do not specify the two instructions necessary to perform
(define_expand "cbranchsi4"
[(set (pc)
- (if_then_else (match_operator 0 "comparison_operator"
- [(match_operand:SI 1 "register_operand")
- (match_operand:SI 2 "rx_source_operand")])
- (label_ref (match_operand 3 ""))
- (pc)))
- ]
- ""
+ (if_then_else
+ (match_operator 0 "comparison_operator"
+ [(match_operand:SI 1 "register_operand")
+ (match_operand:SI 2 "rx_source_operand")])
+ (label_ref (match_operand 3 ""))
+ (pc)))]
""
)
-(define_insn_and_split "*cbranchsi4_<code>"
+(define_insn_and_split "*cbranchsi4"
[(set (pc)
- (if_then_else (most_cond (match_operand:SI 0 "register_operand" "r")
- (match_operand:SI 1 "rx_source_operand" "riQ"))
- (label_ref (match_operand 2 "" ""))
- (pc)))
- ]
+ (if_then_else
+ (match_operator 3 "comparison_operator"
+ [(match_operand:SI 0 "register_operand" "r")
+ (match_operand:SI 1 "rx_source_operand" "riQ")])
+ (match_operand 2 "label_ref_operand" "")
+ (pc)))]
""
"#"
"reload_completed"
[(const_int 0)]
- "
- /* We contstruct 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_conditional_branch (operands[2],
- gen_rtx_fmt_ee (<most_cond:CODE>, CCmode,
- gen_rtx_REG (CCmode, CC_REG), const0_rtx)));
- "
-)
+{
+ rx_split_cbranch (CCmode, GET_CODE (operands[3]),
+ operands[0], operands[1], operands[2]);
+ DONE;
+})
-;; -----------------------------------------------------------------------------
-;; These two are the canonical TST/branch insns. However, GCC
-;; generates a wide variety of tst-like patterns, we catch those
-;; below.
-(define_insn_and_split "*tstbranchsi4_<code>"
- [(set (pc)
- (if_then_else (zs_cond (and:SI (match_operand:SI 0 "register_operand" "r")
- (match_operand:SI 1 "rx_source_operand" "riQ"))
- (const_int 0))
- (label_ref (match_operand 2 "" ""))
- (pc)))
- ]
- ""
- "#"
+(define_insn "*cmpsi"
+ [(set (reg:CC CC_REG)
+ (compare:CC (match_operand:SI 0 "register_operand" "r,r,r,r,r,r,r")
+ (match_operand:SI 1 "rx_source_operand" "r,Uint04,Int08,Sint16,Sint24,i,Q")))]
"reload_completed"
- [(const_int 0)]
- "
- emit_insn (gen_tstsi (operands[0], operands[1]));
-
- emit_jump_insn (gen_conditional_branch (operands[2],
- gen_rtx_fmt_ee (<zs_cond:CODE>, CCmode,
- gen_rtx_REG (CCmode, CC_REG), const0_rtx)));
- "
+ "cmp\t%Q1, %0"
+ [(set_attr "timings" "11,11,11,11,11,11,33")
+ (set_attr "length" "2,2,3,4,5,6,5")]
)
-;; Inverse of above
-(define_insn_and_split "*tstbranchsi4_<code>"
+;; Canonical method for representing TST.
+(define_insn_and_split "*cbranchsi4_tst"
[(set (pc)
- (if_then_else (zs_cond (and:SI (match_operand:SI 0 "register_operand" "r")
- (match_operand:SI 1 "rx_source_operand" "riQ"))
- (const_int 0))
- (pc)
- (label_ref (match_operand 2 "" ""))))
- ]
+ (if_then_else
+ (match_operator 3 "rx_zs_comparison_operator"
+ [(and:SI (match_operand:SI 0 "register_operand" "r")
+ (match_operand:SI 1 "rx_source_operand" "riQ"))
+ (const_int 0)])
+ (match_operand 2 "label_ref_operand" "")
+ (pc)))]
""
"#"
"reload_completed"
[(const_int 0)]
- "
- emit_insn (gen_tstsi (operands[0], operands[1]));
-
- emit_jump_insn (gen_conditional_branch (operands[2],
- gen_rtx_fmt_ee (reverse_condition (<zs_cond:CODE>), CCmode,
- gen_rtx_REG (CCmode, CC_REG), const0_rtx)));
- "
-)
+{
+ rx_split_cbranch (CC_ZSmode, GET_CODE (operands[3]),
+ XEXP (operands[3], 0), XEXP (operands[3], 1),
+ operands[2]);
+ DONE;
+})
;; Various other ways that GCC codes "var & const"
-
-(define_insn_and_split "*tstbranchsi4m_eq"
+(define_insn_and_split "*cbranchsi4_tst_ext"
[(set (pc)
- (if_then_else (eq (zero_extract:SI (match_operand:SI 0 "register_operand" "r")
- (match_operand 1 "rx_constshift_operand" "i")
- (match_operand 2 "rx_constshift_operand" "i"))
- (const_int 0))
- (label_ref (match_operand 3 "" ""))
- (pc)))
- ]
- ""
- "#"
- ""
- [(set (pc)
- (if_then_else (eq (and:SI (match_dup 0)
- (match_dup 4))
- (const_int 0))
- (label_ref (match_dup 3))
- (pc)))
- ]
- "operands[4] = GEN_INT (((1 << INTVAL (operands[1]))-1) << INTVAL (operands[2]));"
-)
-
-(define_insn_and_split "*tstbranchsi4m_ne"
- [(set (pc)
- (if_then_else (ne (zero_extract:SI (match_operand:SI 0 "register_operand" "r")
- (match_operand 1 "rx_constshift_operand" "i")
- (match_operand 2 "rx_constshift_operand" "i"))
- (const_int 0))
- (label_ref (match_operand 3 "" ""))
- (pc)))
- ]
+ (if_then_else
+ (match_operator 4 "rx_z_comparison_operator"
+ [(zero_extract:SI
+ (match_operand:SI 0 "register_operand" "r")
+ (match_operand:SI 1 "rx_constshift_operand" "")
+ (match_operand:SI 2 "rx_constshift_operand" ""))
+ (const_int 0)])
+ (match_operand 3 "label_ref_operand" "")
+ (pc)))]
""
"#"
- ""
- [(set (pc)
- (if_then_else (ne (and:SI (match_dup 0)
- (match_dup 4))
- (const_int 0))
- (label_ref (match_dup 3))
- (pc)))
- ]
- "operands[4] = GEN_INT (((1 << INTVAL (operands[1]))-1) << INTVAL (operands[2]));"
+ "reload_completed"
+ [(const_int 0)]
+{
+ HOST_WIDE_INT mask;
+ rtx x;
+
+ mask = 1;
+ mask <<= INTVAL (operands[1]);
+ mask -= 1;
+ mask <<= INTVAL (operands[2]);
+ x = gen_rtx_AND (SImode, operands[0], gen_int_mode (mask, SImode));
+
+ rx_split_cbranch (CC_ZSmode, GET_CODE (operands[4]),
+ x, const0_rtx, operands[3]);
+ DONE;
+})
+
+(define_insn "*tstsi"
+ [(set (reg:CC_ZS CC_REG)
+ (compare:CC_ZS
+ (and:SI (match_operand:SI 0 "register_operand" "r,r,r")
+ (match_operand:SI 1 "rx_source_operand" "r,i,Q"))
+ (const_int 0)))]
+ "reload_completed"
+ "tst\t%Q1, %0"
+ [(set_attr "timings" "11,11,33")
+ (set_attr "length" "3,7,6")]
)
-;; -----------------------------------------------------------------------------
-
(define_expand "cbranchsf4"
[(set (pc)
- (if_then_else (match_operator 0 "comparison_operator"
- [(match_operand:SF 1 "register_operand")
- (match_operand:SF 2 "rx_source_operand")])
- (label_ref (match_operand 3 ""))
- (pc)))
- ]
+ (if_then_else
+ (match_operator 0 "rx_fp_comparison_operator"
+ [(match_operand:SF 1 "register_operand")
+ (match_operand:SF 2 "rx_source_operand")])
+ (label_ref (match_operand 3 ""))
+ (pc)))]
"ALLOW_RX_FPU_INSNS"
- ""
)
-(define_insn_and_split "*cbranchsf4_<code>"
+(define_insn_and_split "*cbranchsf4"
[(set (pc)
- (if_then_else (most_cond (match_operand:SF 0 "register_operand" "r")
- (match_operand:SF 1 "rx_source_operand" "rFiQ"))
- (label_ref (match_operand 2 "" ""))
- (pc)))
- ]
+ (if_then_else
+ (match_operator 3 "rx_fp_comparison_operator"
+ [(match_operand:SF 0 "register_operand" "r")
+ (match_operand:SF 1 "rx_source_operand" "rFQ")])
+ (match_operand 2 "label_ref_operand" "")
+ (pc)))]
"ALLOW_RX_FPU_INSNS"
"#"
"&& reload_completed"
[(const_int 0)]
- "
- /* We contstruct the split by hand as otherwise the JUMP_LABEL
- attribute is not set correctly on the jump insn. */
- emit_insn (gen_cmpsf (operands[0], operands[1]));
-
- emit_jump_insn (gen_conditional_branch (operands[2],
- gen_rtx_fmt_ee (<most_cond:CODE>, CCmode,
- gen_rtx_REG (CCmode, CC_REG), const0_rtx)));
- "
-)
-
-(define_insn "tstsi"
- [(set (reg:CC_ZS CC_REG)
- (compare:CC_ZS (and:SI (match_operand:SI 0 "register_operand" "r,r,r")
- (match_operand:SI 1 "rx_source_operand" "r,i,Q"))
- (const_int 0)))]
- ""
- {
- rx_float_compare_mode = false;
- return "tst\t%Q1, %0";
- }
- [(set_attr "timings" "11,11,33")
- (set_attr "length" "3,7,6")]
-)
-
-(define_insn "cmpsi"
- [(set (reg:CC CC_REG)
- (compare:CC (match_operand:SI 0 "register_operand" "r,r,r,r,r,r,r")
- (match_operand:SI 1 "rx_source_operand" "r,Uint04,Int08,Sint16,Sint24,i,Q")))]
- ""
- {
- rx_float_compare_mode = false;
- if (rx_compare_redundant (insn))
- return "; Compare Eliminated: cmp %Q1, %0";
- return "cmp\t%Q1, %0";
- }
- [(set_attr "timings" "11,11,11,11,11,11,33")
- (set_attr "length" "2,2,3,4,5,6,5")]
-)
-
-;; This pattern is disabled when -fnon-call-exceptions is active because
-;; it could generate a floating point exception, which would introduce an
-;; edge into the flow graph between this insn and the conditional branch
-;; insn to follow, thus breaking the cc0 relationship. Run the g++ test
-;; g++.dg/eh/080514-1.C to see this happen.
-(define_insn "cmpsf"
- [(set (reg:CC_ZSO CC_REG)
- (compare:CC_ZSO (match_operand:SF 0 "register_operand" "r,r,r")
- (match_operand:SF 1 "rx_source_operand" "r,iF,Q")))]
- "ALLOW_RX_FPU_INSNS"
- {
- rx_float_compare_mode = true;
- return "fcmp\t%1, %0";
- }
+{
+ rx_split_cbranch (CC_Fmode, GET_CODE (operands[3]),
+ operands[0], operands[1], operands[2]);
+ DONE;
+})
+
+(define_insn "*cmpsf"
+ [(set (reg:CC_F CC_REG)
+ (compare:CC_F
+ (match_operand:SF 0 "register_operand" "r,r,r")
+ (match_operand:SF 1 "rx_source_operand" "r,F,Q")))]
+ "ALLOW_RX_FPU_INSNS && reload_completed"
+ "fcmp\t%1, %0"
[(set_attr "timings" "11,11,33")
(set_attr "length" "3,7,5")]
)
;; Flow Control Instructions:
-(define_expand "b<code>"
+(define_insn "*conditional_branch"
[(set (pc)
- (if_then_else (most_cond (reg:CC CC_REG) (const_int 0))
- (label_ref (match_operand 0))
- (pc)))]
- ""
- ""
-)
-
-(define_insn "conditional_branch"
- [(set (pc)
- (if_then_else (match_operator 1 "comparison_operator"
- [(reg:CC CC_REG) (const_int 0)])
- (label_ref (match_operand 0 "" ""))
- (pc)))]
- ""
- {
- return rx_gen_cond_branch_template (operands[1], false);
- }
+ (if_then_else
+ (match_operator 1 "comparison_operator"
+ [(reg CC_REG) (const_int 0)])
+ (label_ref (match_operand 0 "" ""))
+ (pc)))]
+ "reload_completed"
+ "b%B1\t%0"
[(set_attr "length" "8") ;; This length is wrong, but it is
;; too hard to compute statically.
(set_attr "timings" "33")] ;; The timing assumes that the branch is taken.
)
-(define_insn "*reveresed_conditional_branch"
- [(set (pc)
- (if_then_else (match_operator 1 "comparison_operator"
- [(reg:CC CC_REG) (const_int 0)])
- (pc)
- (label_ref (match_operand 0 "" ""))))]
- ""
- {
- return rx_gen_cond_branch_template (operands[1], true);
- }
- [(set_attr "length" "8") ;; This length is wrong, but it is
- ;; too hard to compute statically.
- (set_attr "timings" "33")] ;; The timing assumes that the branch is taken.
-)
+;; ----------------------------------------------------------------------------
(define_insn "jump"
[(set (pc)
(set_attr "timings" "55")]
)
+;; Unspec used so that the constant will not be invalid
+;; if -mmax-constant-size has been specified.
(define_insn "deallocate_and_return"
[(set (reg:SI SP_REG)
(plus:SI (reg:SI SP_REG)
- (match_operand:SI 0 "immediate_operand" "i")))
+ (const:SI (unspec:SI [(match_operand 0 "const_int_operand" "n")] UNSPEC_CONST))))
(return)]
""
"rtsd\t%0"
(define_insn "pop_and_return"
[(match_parallel 1 "rx_rtsd_vector"
- [(set:SI (reg:SI SP_REG)
- (plus:SI (reg:SI SP_REG)
- (match_operand:SI 0 "const_int_operand" "n")))])]
+ [(set (reg:SI SP_REG)
+ (plus:SI (reg:SI SP_REG)
+ (match_operand:SI 0 "const_int_operand" "n")))])
+ (return)]
"reload_completed"
{
rx_emit_stack_popm (operands, false);
if (! rx_call_operand (dest, Pmode))
dest = force_reg (Pmode, dest);
- emit_call_insn (gen_call_internal (dest, operands[1]));
+ emit_call_insn (gen_call_internal (dest));
DONE;
}
)
(define_insn "call_internal"
[(call (mem:QI (match_operand:SI 0 "rx_call_operand" "r,Symbol"))
- (match_operand:SI 1 "general_operand" "g,g"))
+ (const_int 0))
(clobber (reg:CC CC_REG))]
""
"@
if (! rx_call_operand (dest, Pmode))
dest = force_reg (Pmode, dest);
- emit_call_insn (gen_call_value_internal (operands[0], dest, operands[2]));
+ emit_call_insn (gen_call_value_internal (operands[0], dest));
DONE;
}
)
(define_insn "call_value_internal"
[(set (match_operand 0 "register_operand" "=r,r")
(call (mem:QI (match_operand:SI 1 "rx_call_operand" "r,Symbol"))
- (match_operand:SI 2 "general_operand" "g,g")))
+ (const_int 0)))
(clobber (reg:CC CC_REG))]
""
"@
{
if (MEM_P (operands[0]))
operands[0] = XEXP (operands[0], 0);
+ emit_call_insn (gen_sibcall_internal (operands[0]));
+ DONE;
}
)
(define_insn "sibcall_internal"
[(call (mem:QI (match_operand:SI 0 "rx_symbolic_call_operand" "Symbol"))
- (match_operand:SI 1 "general_operand" "g"))
+ (const_int 0))
(return)]
""
"bra\t%A0"
{
if (MEM_P (operands[1]))
operands[1] = XEXP (operands[1], 0);
+ emit_call_insn (gen_sibcall_value_internal (operands[0], operands[1]));
+ DONE;
}
)
(define_insn "sibcall_value_internal"
[(set (match_operand 0 "register_operand" "=r")
(call (mem:QI (match_operand:SI 1 "rx_symbolic_call_operand" "Symbol"))
- (match_operand:SI 2 "general_operand" "g")))
+ (const_int 0)))
(return)]
""
"bra\t%A1"
{
if (MEM_P (operand0) && MEM_P (operand1))
operands[1] = copy_to_mode_reg (<register_modes:MODE>mode, operand1);
+ if (CONST_INT_P (operand1)
+ && ! rx_is_legitimate_constant (operand1))
+ FAIL;
}
)
)
(define_insn "stack_push"
- [(set:SI (reg:SI SP_REG)
- (minus:SI (reg:SI SP_REG)
- (const_int 4)))
- (set:SI (mem:SI (reg:SI SP_REG))
- (match_operand:SI 0 "register_operand" "r"))]
+ [(set (reg:SI SP_REG)
+ (minus:SI (reg:SI SP_REG)
+ (const_int 4)))
+ (set (mem:SI (reg:SI SP_REG))
+ (match_operand:SI 0 "register_operand" "r"))]
""
"push.l\t%0"
[(set_attr "length" "2")]
(define_insn "stack_pushm"
[(match_parallel 1 "rx_store_multiple_vector"
- [(set:SI (reg:SI SP_REG)
- (minus:SI (reg:SI SP_REG)
- (match_operand:SI 0 "const_int_operand" "n")))])]
+ [(set (reg:SI SP_REG)
+ (minus:SI (reg:SI SP_REG)
+ (match_operand:SI 0 "const_int_operand" "n")))])]
"reload_completed"
{
rx_emit_stack_pushm (operands);
)
(define_insn "stack_pop"
- [(set:SI (match_operand:SI 0 "register_operand" "=r")
- (mem:SI (reg:SI SP_REG)))
- (set:SI (reg:SI SP_REG)
- (plus:SI (reg:SI SP_REG)
- (const_int 4)))]
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (mem:SI (reg:SI SP_REG)))
+ (set (reg:SI SP_REG)
+ (plus:SI (reg:SI SP_REG)
+ (const_int 4)))]
""
"pop\t%0"
[(set_attr "length" "2")
(define_insn "stack_popm"
[(match_parallel 1 "rx_load_multiple_vector"
- [(set:SI (reg:SI SP_REG)
- (plus:SI (reg:SI SP_REG)
- (match_operand:SI 0 "const_int_operand" "n")))])]
+ [(set (reg:SI SP_REG)
+ (plus:SI (reg:SI SP_REG)
+ (match_operand:SI 0 "const_int_operand" "n")))])]
"reload_completed"
{
rx_emit_stack_popm (operands, true);
(set_attr "timings" "45")] ;; The timing is a guesstimate average timing.
)
-;; FIXME: Add memory destination options ?
-(define_insn "cstoresi4"
- [(set (match_operand:SI 0 "register_operand" "=r,r,r,r,r,r,r")
+(define_insn_and_split "cstoresi4"
+ [(set (match_operand:SI 0 "register_operand" "=r")
(match_operator:SI 1 "comparison_operator"
- [(match_operand:SI 2 "register_operand" "r,r,r,r,r,r,r")
- (match_operand:SI 3 "rx_source_operand" "r,Uint04,Int08,Sint16,Sint24,i,Q")]))
- (clobber (reg:CC CC_REG))] ;; Because the cc flags are set based on comparing ops 2 & 3 not the value in op 0.
+ [(match_operand:SI 2 "register_operand" "r")
+ (match_operand:SI 3 "rx_source_operand" "riQ")]))
+ (clobber (reg:CC CC_REG))]
""
- {
- rx_float_compare_mode = false;
- return "cmp\t%Q3, %Q2\n\tsc%B1.L\t%0";
- }
- [(set_attr "timings" "22,22,22,22,22,22,44")
- (set_attr "length" "5,5,6,7,8,9,8")]
+ "#"
+ "reload_completed"
+ [(const_int 0)]
+{
+ rtx flags, x;
+
+ flags = gen_rtx_REG (CCmode, CC_REG);
+ x = gen_rtx_COMPARE (CCmode, operands[2], operands[3]);
+ x = gen_rtx_SET (VOIDmode, flags, x);
+ emit_insn (x);
+
+ x = gen_rtx_fmt_ee (GET_CODE (operands[1]), SImode, flags, const0_rtx);
+ x = gen_rtx_SET (VOIDmode, operands[0], x);
+ emit_insn (x);
+ DONE;
+})
+
+(define_insn "*sccc"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (match_operator:SI 1 "comparison_operator"
+ [(reg CC_REG) (const_int 0)]))]
+ "reload_completed"
+ "sc%B1.L\t%0"
+ [(set_attr "length" "3")]
)
+(define_insn_and_split "cstoresf4"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (match_operator:SI 1 "rx_fp_comparison_operator"
+ [(match_operand:SF 2 "register_operand" "r")
+ (match_operand:SF 3 "rx_source_operand" "rFQ")]))]
+ "ALLOW_RX_FPU_INSNS"
+ "#"
+ "reload_completed"
+ [(const_int 0)]
+{
+ rtx flags, x;
+
+ flags = gen_rtx_REG (CC_Fmode, CC_REG);
+ x = gen_rtx_COMPARE (CC_Fmode, operands[2], operands[3]);
+ x = gen_rtx_SET (VOIDmode, flags, x);
+ emit_insn (x);
+
+ x = gen_rtx_fmt_ee (GET_CODE (operands[1]), SImode, flags, const0_rtx);
+ x = gen_rtx_SET (VOIDmode, operands[0], x);
+ emit_insn (x);
+ DONE;
+})
+
(define_expand "movsicc"
[(parallel
[(set (match_operand:SI 0 "register_operand")
(if_then_else:SI (match_operand:SI 1 "comparison_operator")
(match_operand:SI 2 "nonmemory_operand")
- (match_operand:SI 3 "immediate_operand")))
- (clobber (reg:CC CC_REG))])] ;; See cstoresi4
+ (match_operand:SI 3 "nonmemory_operand")))
+ (clobber (reg:CC CC_REG))])]
""
- {
- if (GET_CODE (operands[1]) != EQ && GET_CODE (operands[1]) != NE)
- FAIL;
- if (! CONST_INT_P (operands[3]))
- FAIL;
- }
+{
+ /* ??? Support other conditions via cstore into a temporary? */
+ if (GET_CODE (operands[1]) != EQ && GET_CODE (operands[1]) != NE)
+ FAIL;
+ /* One operand must be a constant. */
+ if (!CONSTANT_P (operands[2]) && !CONSTANT_P (operands[3]))
+ FAIL;
+})
+
+(define_insn_and_split "*movsicc"
+ [(set (match_operand:SI 0 "register_operand" "=r,r")
+ (if_then_else:SI
+ (match_operator 5 "rx_z_comparison_operator"
+ [(match_operand:SI 3 "register_operand" "r,r")
+ (match_operand:SI 4 "rx_source_operand" "riQ,riQ")])
+ (match_operand:SI 1 "nonmemory_operand" "i,ri")
+ (match_operand:SI 2 "nonmemory_operand" "ri,i")))
+ (clobber (reg:CC CC_REG))]
+ "CONSTANT_P (operands[1]) || CONSTANT_P (operands[2])"
+ "#"
+ "&& reload_completed"
+ [(const_int 0)]
+{
+ rtx x, flags, op0, op1, op2;
+ enum rtx_code cmp_code;
+
+ flags = gen_rtx_REG (CCmode, CC_REG);
+ x = gen_rtx_COMPARE (CCmode, operands[3], operands[4]);
+ emit_insn (gen_rtx_SET (VOIDmode, flags, x));
+
+ cmp_code = GET_CODE (operands[5]);
+ op0 = operands[0];
+ op1 = operands[1];
+ op2 = operands[2];
+
+ /* If OP2 is the constant, reverse the sense of the move. */
+ if (!CONSTANT_P (operands[1]))
+ {
+ x = op1, op1 = op2, op2 = x;
+ cmp_code = reverse_condition (cmp_code);
+ }
+
+ /* If OP2 does not match the output, copy it into place. We have allowed
+ these alternatives so that the destination can legitimately be one of
+ the comparison operands without increasing register pressure. */
+ if (!rtx_equal_p (op0, op2))
+ emit_move_insn (op0, op2);
+
+ x = gen_rtx_fmt_ee (cmp_code, VOIDmode, flags, const0_rtx);
+ x = gen_rtx_IF_THEN_ELSE (SImode, x, op1, op0);
+ emit_insn (gen_rtx_SET (VOIDmode, op0, x));
+ DONE;
+})
+
+(define_insn "*stcc"
+ [(set (match_operand:SI 0 "register_operand" "+r,r,r,r")
+ (if_then_else:SI
+ (match_operator 2 "rx_z_comparison_operator"
+ [(reg CC_REG) (const_int 0)])
+ (match_operand:SI 1 "immediate_operand" "Sint08,Sint16,Sint24,i")
+ (match_dup 0)))]
+ "reload_completed"
+{
+ if (GET_CODE (operands[2]) == EQ)
+ return "stz\t%1, %0";
+ else
+ return "stnz\t%1, %0";
+}
+ [(set_attr "length" "4,5,6,7")]
)
-(define_insn "*movsieq"
- [(set (match_operand:SI 0 "register_operand" "=r,r,r")
- (if_then_else:SI (eq (match_operand:SI 3 "register_operand" "r,r,r")
- (match_operand:SI 4 "rx_source_operand" "riQ,riQ,riQ"))
- (match_operand:SI 1 "nonmemory_operand" "0,i,r")
- (match_operand:SI 2 "immediate_operand" "i,i,i")))
- (clobber (reg:CC CC_REG))] ;; See cstoresi4
- ""
- "@
- cmp\t%Q4, %Q3\n\tstnz\t%2, %0
- cmp\t%Q4, %Q3\n\tmov.l\t%2, %0\n\tstz\t%1, %0
- cmp\t%Q4, %Q3\n\tmov.l\t%1, %0\n\tstnz\t%2, %0"
- [(set_attr "length" "13,19,15")
- (set_attr "timings" "22,33,33")]
-)
+;; Arithmetic Instructions
-(define_insn "*movsine"
- [(set (match_operand:SI 0 "register_operand" "=r,r,r")
- (if_then_else:SI (ne (match_operand:SI 3 "register_operand" "r,r,r")
- (match_operand:SI 4 "rx_source_operand" "riQ,riQ,riQ"))
- (match_operand:SI 1 "nonmemory_operand" "0,i,r")
- (match_operand:SI 2 "immediate_operand" "i,i,i")))
- (clobber (reg:CC CC_REG))] ;; See cstoresi4
+(define_insn "abssi2"
+ [(set (match_operand:SI 0 "register_operand" "=r,r")
+ (abs:SI (match_operand:SI 1 "register_operand" "0,r")))
+ (clobber (reg:CC CC_REG))]
""
"@
- cmp\t%Q4, %Q3\n\tstz\t%2, %0
- cmp\t%Q4, %Q3\n\tmov.l\t%2, %0\n\tstnz\t%1, %0
- cmp\t%Q4, %Q3\n\tmov.l\t%1, %0\n\tstz\t%2, %0"
- [(set_attr "length" "13,19,15")
- (set_attr "timings" "22,33,33")]
+ abs\t%0
+ abs\t%1, %0"
+ [(set_attr "length" "2,3")]
)
-;; Arithmetic Instructions
-
-(define_insn "abssi2"
+(define_insn "*abssi2_flags"
[(set (match_operand:SI 0 "register_operand" "=r,r")
(abs:SI (match_operand:SI 1 "register_operand" "0,r")))
- (set (reg:CC_ZSO CC_REG)
- (compare:CC_ZSO (abs:SI (match_dup 1))
- (const_int 0)))]
- ""
+ (set (reg CC_REG)
+ (compare (abs:SI (match_dup 1))
+ (const_int 0)))]
+ "reload_completed && rx_match_ccmode (insn, CC_ZSOmode)"
"@
abs\t%0
abs\t%1, %0"
[(set (match_operand:SI 0 "register_operand" "=r,r,r,r,r,r,r,r,r,r,r,r,r,r")
(plus:SI (match_operand:SI 1 "register_operand" "%0,0,0,0,0,0,0,r,r,r,r,r,r,0")
(match_operand:SI 2 "rx_source_operand" "r,Uint04,NEGint4,Sint08,Sint16,Sint24,i,0,r,Sint08,Sint16,Sint24,i,Q")))
- (set (reg:CC_ZSC CC_REG) ;; See subsi3
- (compare:CC_ZSC (plus:SI (match_dup 1) (match_dup 2))
- (const_int 0)))]
+ (clobber (reg:CC CC_REG))]
""
"@
add\t%2, %0
(set_attr "length" "2,2,2,3,4,5,6,2,3,3,4,5,6,5")]
)
-(define_insn "adddi3"
- [(set (match_operand:DI 0 "register_operand" "=r,r,r,r,r,r")
- (plus:DI (match_operand:DI 1 "register_operand" "%0,0,0,0,0,0")
- (match_operand:DI 2 "rx_source_operand"
- "r,Sint08,Sint16,Sint24,i,Q")))
- (set (reg:CC_ZSC CC_REG) ;; See subsi3
- (compare:CC_ZSC (plus:DI (match_dup 1) (match_dup 2))
- (const_int 0)))]
- ""
- "add\t%L2, %L0\n\tadc\t%H2, %H0"
- [(set_attr "timings" "22,22,22,22,22,44")
- (set_attr "length" "5,7,9,11,13,11")]
+(define_insn "*addsi3_flags"
+ [(set (match_operand:SI 0 "register_operand" "=r,r,r,r,r,r,r,r,r,r,r,r,r,r")
+ (plus:SI (match_operand:SI 1 "register_operand" "%0,0,0,0,0,0,0,r,r,r,r,r,r,0")
+ (match_operand:SI 2 "rx_source_operand" "r,Uint04,NEGint4,Sint08,Sint16,Sint24,i,0,r,Sint08,Sint16,Sint24,i,Q")))
+ (set (reg CC_REG)
+ (compare (plus:SI (match_dup 1) (match_dup 2))
+ (const_int 0)))]
+ "reload_completed && rx_match_ccmode (insn, CC_ZSCmode)"
+ "@
+ add\t%2, %0
+ add\t%2, %0
+ sub\t%N2, %0
+ add\t%2, %0
+ add\t%2, %0
+ add\t%2, %0
+ add\t%2, %0
+ add\t%1, %0
+ add\t%2, %1, %0
+ add\t%2, %1, %0
+ add\t%2, %1, %0
+ add\t%2, %1, %0
+ add\t%2, %1, %0
+ add\t%Q2, %0"
+ [(set_attr "timings" "11,11,11,11,11,11,11,11,11,11,11,11,11,33")
+ (set_attr "length" "2,2,2,3,4,5,6,2,3,3,4,5,6,5")]
)
+;; A helper to expand the above with the CC_MODE filled in.
+(define_expand "addsi3_flags"
+ [(parallel [(set (match_operand:SI 0 "register_operand")
+ (plus:SI (match_operand:SI 1 "register_operand")
+ (match_operand:SI 2 "rx_source_operand")))
+ (set (reg:CC_ZSC CC_REG)
+ (compare:CC_ZSC (plus:SI (match_dup 1) (match_dup 2))
+ (const_int 0)))])]
+)
+
+(define_insn "adc_internal"
+ [(set (match_operand:SI 0 "register_operand" "=r,r,r,r,r,r")
+ (plus:SI
+ (plus:SI
+ (ltu:SI (reg:CC CC_REG) (const_int 0))
+ (match_operand:SI 1 "register_operand" "%0,0,0,0,0,0"))
+ (match_operand:SI 2 "rx_source_operand" "r,Sint08,Sint16,Sint24,i,Q")))
+ (clobber (reg:CC CC_REG))]
+ "reload_completed"
+ "adc %2,%0"
+ [(set_attr "timings" "11,11,11,11,11,33")
+ (set_attr "length" "3,4,5,6,7,6")]
+)
+
+(define_insn "*adc_flags"
+ [(set (match_operand:SI 0 "register_operand" "=r,r,r,r,r,r")
+ (plus:SI
+ (plus:SI
+ (ltu:SI (reg:CC CC_REG) (const_int 0))
+ (match_operand:SI 1 "register_operand" "%0,0,0,0,0,0"))
+ (match_operand:SI 2 "rx_source_operand" "r,Sint08,Sint16,Sint24,i,Q")))
+ (set (reg CC_REG)
+ (compare
+ (plus:SI
+ (plus:SI
+ (ltu:SI (reg:CC CC_REG) (const_int 0))
+ (match_dup 1))
+ (match_dup 2))
+ (const_int 0)))]
+ "reload_completed && rx_match_ccmode (insn, CC_ZSCmode)"
+ "adc %2,%0"
+ [(set_attr "timings" "11,11,11,11,11,33")
+ (set_attr "length" "3,4,5,6,7,6")]
+)
+
+(define_expand "adddi3"
+ [(set (match_operand:DI 0 "register_operand")
+ (plus:DI (match_operand:DI 1 "register_operand")
+ (match_operand:DI 2 "rx_source_operand")))]
+ ""
+{
+ rtx op0l, op0h, op1l, op1h, op2l, op2h;
+
+ op0l = gen_lowpart (SImode, operands[0]);
+ op1l = gen_lowpart (SImode, operands[1]);
+ op2l = gen_lowpart (SImode, operands[2]);
+ op0h = gen_highpart (SImode, operands[0]);
+ op1h = gen_highpart (SImode, operands[1]);
+ op2h = gen_highpart_mode (SImode, DImode, operands[2]);
+
+ emit_insn (gen_adddi3_internal (op0l, op0h, op1l, op2l, op1h, op2h));
+ DONE;
+})
+
+(define_insn_and_split "adddi3_internal"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (plus:SI (match_operand:SI 2 "register_operand" "r")
+ (match_operand:SI 3 "rx_source_operand" "riQ")))
+ (set (match_operand:SI 1 "register_operand" "=r")
+ (plus:SI
+ (plus:SI
+ (ltu:SI (plus:SI (match_dup 2) (match_dup 3)) (match_dup 2))
+ (match_operand:SI 4 "register_operand" "%1"))
+ (match_operand:SI 5 "rx_source_operand" "riQ")))
+ (clobber (match_scratch:SI 6 "=&r"))
+ (clobber (reg:CC CC_REG))]
+ ""
+ "#"
+ "reload_completed"
+ [(const_int 0)]
+{
+ rtx op0l = operands[0];
+ rtx op0h = operands[1];
+ rtx op1l = operands[2];
+ rtx op2l = operands[3];
+ rtx op1h = operands[4];
+ rtx op2h = operands[5];
+ rtx scratch = operands[6];
+ rtx x;
+
+ if (reg_overlap_mentioned_p (op0l, op1h))
+ {
+ emit_move_insn (scratch, op0l);
+ op1h = scratch;
+ if (reg_overlap_mentioned_p (op0l, op2h))
+ op2h = scratch;
+ }
+ else if (reg_overlap_mentioned_p (op0l, op2h))
+ {
+ emit_move_insn (scratch, op0l);
+ op2h = scratch;
+ }
+
+ if (rtx_equal_p (op0l, op1l))
+ ;
+ /* It is preferable that op0l == op1l... */
+ else if (rtx_equal_p (op0l, op2l))
+ x = op1l, op1l = op2l, op2l = x;
+ /* ... but it is only a requirement if op2l == MEM. */
+ else if (MEM_P (op2l))
+ {
+ /* Let's hope that we still have a scratch register free. */
+ gcc_assert (op1h != scratch);
+ emit_move_insn (scratch, op2l);
+ op2l = scratch;
+ }
+
+ emit_insn (gen_addsi3_flags (op0l, op1l, op2l));
+
+ if (rtx_equal_p (op0h, op1h))
+ ;
+ else if (rtx_equal_p (op0h, op2h))
+ x = op1h, op1h = op2h, op2h = x;
+ else
+ {
+ emit_move_insn (op0h, op1h);
+ op1h = op0h;
+ }
+ emit_insn (gen_adc_internal (op0h, op1h, op2h));
+ DONE;
+})
+
(define_insn "andsi3"
[(set (match_operand:SI 0 "register_operand" "=r,r,r,r,r,r,r,r,r")
(and:SI (match_operand:SI 1 "register_operand" "%0,0,0,0,0,0,r,r,0")
(match_operand:SI 2 "rx_source_operand" "r,Uint04,Sint08,Sint16,Sint24,i,0,r,Q")))
- (set (reg:CC_ZS CC_REG)
- (compare:CC_ZS (and:SI (match_dup 1) (match_dup 2))
- (const_int 0)))]
+ (clobber (reg:CC CC_REG))]
""
"@
and\t%2, %0
(set_attr "length" "2,2,3,4,5,6,2,5,5")]
)
+(define_insn "*andsi3_flags"
+ [(set (match_operand:SI 0 "register_operand" "=r,r,r,r,r,r,r,r,r")
+ (and:SI (match_operand:SI 1 "register_operand" "%0,0,0,0,0,0,r,r,0")
+ (match_operand:SI 2 "rx_source_operand" "r,Uint04,Sint08,Sint16,Sint24,i,0,r,Q")))
+ (set (reg CC_REG)
+ (compare (and:SI (match_dup 1) (match_dup 2))
+ (const_int 0)))]
+ "reload_completed && rx_match_ccmode (insn, CC_ZSmode)"
+ "@
+ and\t%2, %0
+ and\t%2, %0
+ and\t%2, %0
+ and\t%2, %0
+ and\t%2, %0
+ and\t%2, %0
+ and\t%1, %0
+ and\t%2, %1, %0
+ and\t%Q2, %0"
+ [(set_attr "timings" "11,11,11,11,11,11,11,33,33")
+ (set_attr "length" "2,2,3,4,5,6,2,5,5")]
+)
+
;; Byte swap (single 32-bit value).
(define_insn "bswapsi2"
- [(set (match_operand:SI 0 "register_operand" "+r")
+ [(set (match_operand:SI 0 "register_operand" "=r")
(bswap:SI (match_operand:SI 1 "register_operand" "r")))]
""
"revl\t%1, %0"
;; Byte swap (single 16-bit value). Note - we ignore the swapping of the high 16-bits.
(define_insn "bswaphi2"
- [(set (match_operand:HI 0 "register_operand" "+r")
+ [(set (match_operand:HI 0 "register_operand" "=r")
(bswap:HI (match_operand:HI 1 "register_operand" "r")))]
""
"revw\t%1, %0"
(define_insn "negsi2"
[(set (match_operand:SI 0 "register_operand" "=r,r")
(neg:SI (match_operand:SI 1 "register_operand" "0,r")))
- (set (reg:CC CC_REG)
- (compare:CC (neg:SI (match_dup 1))
- (const_int 0)))]
- ;; The NEG instruction does not comply with -fwrapv semantics.
- ;; See gcc.c-torture/execute/pr22493-1.c for an example of this.
- "! flag_wrapv"
+ (clobber (reg:CC CC_REG))]
+ ""
+ "@
+ neg\t%0
+ neg\t%1, %0"
+ [(set_attr "length" "2,3")]
+)
+
+;; Note that the O and C flags are not set as per a normal compare,
+;; and thus are unusable in that context.
+(define_insn "*negsi2_flags"
+ [(set (match_operand:SI 0 "register_operand" "=r,r")
+ (neg:SI (match_operand:SI 1 "register_operand" "0,r")))
+ (set (reg CC_REG)
+ (compare (neg:SI (match_dup 1))
+ (const_int 0)))]
+ "reload_completed && rx_match_ccmode (insn, CC_ZSmode)"
"@
neg\t%0
neg\t%1, %0"
(define_insn "one_cmplsi2"
[(set (match_operand:SI 0 "register_operand" "=r,r")
(not:SI (match_operand:SI 1 "register_operand" "0,r")))
- (set (reg:CC_ZS CC_REG)
- (compare:CC_ZS (not:SI (match_dup 1))
- (const_int 0)))]
+ (clobber (reg:CC CC_REG))]
""
"@
not\t%0
[(set_attr "length" "2,3")]
)
+(define_insn "*one_cmplsi2_flags"
+ [(set (match_operand:SI 0 "register_operand" "=r,r")
+ (not:SI (match_operand:SI 1 "register_operand" "0,r")))
+ (set (reg CC_REG)
+ (compare (not:SI (match_dup 1))
+ (const_int 0)))]
+ "reload_completed && rx_match_ccmode (insn, CC_ZSmode)"
+ "@
+ not\t%0
+ not\t%1, %0"
+ [(set_attr "length" "2,3")]
+)
+
(define_insn "iorsi3"
[(set (match_operand:SI 0 "register_operand" "=r,r,r,r,r,r,r,r,r")
(ior:SI (match_operand:SI 1 "register_operand" "%0,0,0,0,0,0,r,r,0")
(match_operand:SI 2 "rx_source_operand" "r,Uint04,Sint08,Sint16,Sint24,i,0,r,Q")))
- (set (reg:CC_ZS CC_REG)
- (compare:CC_ZS (ior:SI (match_dup 1) (match_dup 2))
- (const_int 0)))]
+ (clobber (reg:CC CC_REG))]
""
"@
or\t%2, %0
(set_attr "length" "2,2,3,4,5,6,2,3,5")]
)
+(define_insn "*iorsi3_flags"
+ [(set (match_operand:SI 0 "register_operand" "=r,r,r,r,r,r,r,r,r")
+ (ior:SI (match_operand:SI 1 "register_operand" "%0,0,0,0,0,0,r,r,0")
+ (match_operand:SI 2 "rx_source_operand" "r,Uint04,Sint08,Sint16,Sint24,i,0,r,Q")))
+ (set (reg CC_REG)
+ (compare (ior:SI (match_dup 1) (match_dup 2))
+ (const_int 0)))]
+ "reload_completed && rx_match_ccmode (insn, CC_ZSmode)"
+ "@
+ or\t%2, %0
+ or\t%2, %0
+ or\t%2, %0
+ or\t%2, %0
+ or\t%2, %0
+ or\t%Q2, %0
+ or\t%1, %0
+ or\t%2, %1, %0
+ or\t%Q2, %0"
+ [(set_attr "timings" "11,11,11,11,11,11,11,11,33")
+ (set_attr "length" "2,2,3,4,5,6,2,3,5")]
+)
+
(define_insn "rotlsi3"
[(set (match_operand:SI 0 "register_operand" "=r")
(rotate:SI (match_operand:SI 1 "register_operand" "0")
(match_operand:SI 2 "rx_shift_operand" "rn")))
- (set (reg:CC_ZS CC_REG)
- (compare:CC_ZS (rotate:SI (match_dup 1) (match_dup 2))
- (const_int 0)))]
+ (clobber (reg:CC CC_REG))]
""
"rotl\t%2, %0"
[(set_attr "length" "3")]
)
+(define_insn "*rotlsi3_flags"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (rotate:SI (match_operand:SI 1 "register_operand" "0")
+ (match_operand:SI 2 "rx_shift_operand" "rn")))
+ (set (reg CC_REG)
+ (compare (rotate:SI (match_dup 1) (match_dup 2))
+ (const_int 0)))]
+ "reload_completed && rx_match_ccmode (insn, CC_ZSmode)"
+ "rotl\t%2, %0"
+ [(set_attr "length" "3")]
+)
+
(define_insn "rotrsi3"
[(set (match_operand:SI 0 "register_operand" "=r")
(rotatert:SI (match_operand:SI 1 "register_operand" "0")
(match_operand:SI 2 "rx_shift_operand" "rn")))
- (set (reg:CC_ZS CC_REG)
- (compare:CC_ZS (rotatert:SI (match_dup 1) (match_dup 2))
- (const_int 0)))]
+ (clobber (reg:CC CC_REG))]
""
"rotr\t%2, %0"
[(set_attr "length" "3")]
)
+(define_insn "*rotrsi3_flags"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (rotatert:SI (match_operand:SI 1 "register_operand" "0")
+ (match_operand:SI 2 "rx_shift_operand" "rn")))
+ (set (reg CC_REG)
+ (compare (rotatert:SI (match_dup 1) (match_dup 2))
+ (const_int 0)))]
+ "reload_completed && rx_match_ccmode (insn, CC_ZSmode)"
+ "rotr\t%2, %0"
+ [(set_attr "length" "3")]
+)
+
(define_insn "ashrsi3"
[(set (match_operand:SI 0 "register_operand" "=r,r,r")
(ashiftrt:SI (match_operand:SI 1 "register_operand" "0,0,r")
(match_operand:SI 2 "rx_shift_operand" "r,n,n")))
- (set (reg:CC_ZS CC_REG)
- (compare:CC_ZS (ashiftrt:SI (match_dup 1) (match_dup 2))
- (const_int 0)))]
+ (clobber (reg:CC CC_REG))]
""
"@
shar\t%2, %0
[(set_attr "length" "3,2,3")]
)
+(define_insn "*ashrsi3_flags"
+ [(set (match_operand:SI 0 "register_operand" "=r,r,r")
+ (ashiftrt:SI (match_operand:SI 1 "register_operand" "0,0,r")
+ (match_operand:SI 2 "rx_shift_operand" "r,n,n")))
+ (set (reg CC_REG)
+ (compare (ashiftrt:SI (match_dup 1) (match_dup 2))
+ (const_int 0)))]
+ "reload_completed && rx_match_ccmode (insn, CC_ZSmode)"
+ "@
+ shar\t%2, %0
+ shar\t%2, %0
+ shar\t%2, %1, %0"
+ [(set_attr "length" "3,2,3")]
+)
+
(define_insn "lshrsi3"
[(set (match_operand:SI 0 "register_operand" "=r,r,r")
(lshiftrt:SI (match_operand:SI 1 "register_operand" "0,0,r")
(match_operand:SI 2 "rx_shift_operand" "r,n,n")))
- (set (reg:CC_ZS CC_REG)
- (compare:CC_ZS (lshiftrt:SI (match_dup 1) (match_dup 2))
- (const_int 0)))]
+ (clobber (reg:CC CC_REG))]
""
"@
shlr\t%2, %0
[(set_attr "length" "3,2,3")]
)
+(define_insn "*lshrsi3_flags"
+ [(set (match_operand:SI 0 "register_operand" "=r,r,r")
+ (lshiftrt:SI (match_operand:SI 1 "register_operand" "0,0,r")
+ (match_operand:SI 2 "rx_shift_operand" "r,n,n")))
+ (set (reg CC_REG)
+ (compare (lshiftrt:SI (match_dup 1) (match_dup 2))
+ (const_int 0)))]
+ "reload_completed && rx_match_ccmode (insn, CC_ZSmode)"
+ "@
+ shlr\t%2, %0
+ shlr\t%2, %0
+ shlr\t%2, %1, %0"
+ [(set_attr "length" "3,2,3")]
+)
+
(define_insn "ashlsi3"
[(set (match_operand:SI 0 "register_operand" "=r,r,r")
(ashift:SI (match_operand:SI 1 "register_operand" "0,0,r")
(match_operand:SI 2 "rx_shift_operand" "r,n,n")))
- (set (reg:CC_ZS CC_REG)
- (compare:CC_ZS (ashift:SI (match_dup 1) (match_dup 2))
- (const_int 0)))]
+ (clobber (reg:CC CC_REG))]
""
"@
shll\t%2, %0
[(set_attr "length" "3,2,3")]
)
+(define_insn "*ashlsi3_flags"
+ [(set (match_operand:SI 0 "register_operand" "=r,r,r")
+ (ashift:SI (match_operand:SI 1 "register_operand" "0,0,r")
+ (match_operand:SI 2 "rx_shift_operand" "r,n,n")))
+ (set (reg CC_REG)
+ (compare (ashift:SI (match_dup 1) (match_dup 2))
+ (const_int 0)))]
+ "reload_completed && rx_match_ccmode (insn, CC_ZSmode)"
+ "@
+ shll\t%2, %0
+ shll\t%2, %0
+ shll\t%2, %1, %0"
+ [(set_attr "length" "3,2,3")]
+)
+
+;; Saturate to 32-bits
+(define_insn_and_split "ssaddsi3"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (ss_plus:SI (match_operand:SI 1 "register_operand" "r")
+ (match_operand:SI 2 "rx_source_operand" "riQ")))
+ (clobber (reg:CC CC_REG))]
+ ""
+ "#"
+ "reload_completed"
+ [(parallel [(set (match_dup 0)
+ (plus:SI (match_dup 1) (match_dup 2)))
+ (set (reg:CC_ZSC CC_REG)
+ (compare:CC_ZSC
+ (plus:SI (match_dup 1) (match_dup 2))
+ (const_int 0)))])
+ (set (match_dup 0)
+ (unspec:SI [(match_dup 0) (reg:CC CC_REG)]
+ UNSPEC_BUILTIN_SAT))]
+ ""
+)
+
+(define_insn "*sat"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (unspec:SI [(match_operand:SI 1 "register_operand" "0")
+ (reg:CC CC_REG)]
+ UNSPEC_BUILTIN_SAT))]
+ "reload_completed"
+ "sat\t%0"
+ [(set_attr "length" "2")]
+)
+
(define_insn "subsi3"
[(set (match_operand:SI 0 "register_operand" "=r,r,r,r,r")
(minus:SI (match_operand:SI 1 "register_operand" "0,0,0,r,0")
(match_operand:SI 2 "rx_source_operand" "r,Uint04,n,r,Q")))
- (set (reg:CC_ZSC CC_REG)
- ;; Note - we do not acknowledge that the SUB instruction sets the Overflow
- ;; flag because its interpretation is different from comparing the result
- ;; against zero. Compile and run gcc.c-torture/execute/cmpsi-1.c to see this.
- (compare:CC_ZSC (minus:SI (match_dup 1) (match_dup 2))
- (const_int 0)))]
+ (clobber (reg:CC CC_REG))]
""
"@
sub\t%2, %0
(set_attr "length" "2,2,6,3,5")]
)
-(define_insn "subdi3"
- [(set (match_operand:DI 0 "register_operand" "=r,r")
- (minus:DI (match_operand:DI 1 "register_operand" "0,0")
- (match_operand:DI 2 "rx_source_operand" "r,Q")))
- (set (reg:CC_ZSC CC_REG) ;; See subsi3
- (compare:CC_ZSC (minus:DI (match_dup 1) (match_dup 2))
- (const_int 0)))]
- ""
- "sub\t%L2, %L0\n\tsbb\t%H2, %H0"
- [(set_attr "timings" "22,44")
- (set_attr "length" "5,11")]
+;; Note that the O flag is set as if (compare op1 op2) not for
+;; what is described here, (compare op0 0).
+(define_insn "*subsi3_flags"
+ [(set (match_operand:SI 0 "register_operand" "=r,r,r,r,r")
+ (minus:SI (match_operand:SI 1 "register_operand" "0,0,0,r,0")
+ (match_operand:SI 2 "rx_source_operand" "r,Uint04,n,r,Q")))
+ (set (reg CC_REG)
+ (compare (minus:SI (match_dup 1) (match_dup 2))
+ (const_int 0)))]
+ "reload_completed && rx_match_ccmode (insn, CC_ZSCmode)"
+ "@
+ sub\t%2, %0
+ sub\t%2, %0
+ add\t%N2, %0
+ sub\t%2, %1, %0
+ sub\t%Q2, %0"
+ [(set_attr "timings" "11,11,11,11,33")
+ (set_attr "length" "2,2,6,3,5")]
)
+;; A helper to expand the above with the CC_MODE filled in.
+(define_expand "subsi3_flags"
+ [(parallel [(set (match_operand:SI 0 "register_operand")
+ (minus:SI (match_operand:SI 1 "register_operand")
+ (match_operand:SI 2 "rx_source_operand")))
+ (set (reg:CC_ZSC CC_REG)
+ (compare:CC_ZSC (minus:SI (match_dup 1) (match_dup 2))
+ (const_int 0)))])]
+)
+
+(define_insn "sbb_internal"
+ [(set (match_operand:SI 0 "register_operand" "=r,r")
+ (minus:SI
+ (minus:SI
+ (match_operand:SI 1 "register_operand" " 0,0")
+ (match_operand:SI 2 "rx_compare_operand" " r,Q"))
+ (geu:SI (reg:CC CC_REG) (const_int 0))))
+ (clobber (reg:CC CC_REG))]
+ "reload_completed"
+ "sbb\t%2, %0"
+ [(set_attr "timings" "11,33")
+ (set_attr "length" "3,6")]
+)
+
+(define_insn "*sbb_flags"
+ [(set (match_operand:SI 0 "register_operand" "=r,r")
+ (minus:SI
+ (minus:SI
+ (match_operand:SI 1 "register_operand" " 0,0")
+ (match_operand:SI 2 "rx_compare_operand" " r,Q"))
+ (geu:SI (reg:CC CC_REG) (const_int 0))))
+ (set (reg CC_REG)
+ (compare
+ (minus:SI
+ (minus:SI (match_dup 1) (match_dup 2))
+ (geu:SI (reg:CC CC_REG) (const_int 0)))
+ (const_int 0)))]
+ "reload_completed"
+ "sbb\t%2, %0"
+ [(set_attr "timings" "11,33")
+ (set_attr "length" "3,6")]
+)
+
+(define_expand "subdi3"
+ [(set (match_operand:DI 0 "register_operand")
+ (minus:DI (match_operand:DI 1 "register_operand")
+ (match_operand:DI 2 "rx_compare_operand")))]
+ ""
+{
+ rtx op0l, op0h, op1l, op1h, op2l, op2h;
+
+ op0l = gen_lowpart (SImode, operands[0]);
+ op1l = gen_lowpart (SImode, operands[1]);
+ op2l = gen_lowpart (SImode, operands[2]);
+ op0h = gen_highpart (SImode, operands[0]);
+ op1h = gen_highpart (SImode, operands[1]);
+ op2h = gen_highpart_mode (SImode, DImode, operands[2]);
+
+ emit_insn (gen_subdi3_internal (op0l, op0h, op1l, op2l, op1h, op2h));
+ DONE;
+})
+
+(define_insn_and_split "subdi3_internal"
+ [(set (match_operand:SI 0 "register_operand" "=&r,&r")
+ (minus:SI (match_operand:SI 2 "register_operand" " 0, r")
+ (match_operand:SI 3 "rx_compare_operand" "rQ, r")))
+ (set (match_operand:SI 1 "register_operand" "= r, r")
+ (minus:SI
+ (minus:SI
+ (match_operand:SI 4 "register_operand" " 1, 1")
+ (match_operand:SI 5 "rx_compare_operand" " rQ,rQ"))
+ (geu:SI (match_dup 2) (match_dup 3))))
+ (clobber (reg:CC CC_REG))]
+ ""
+ "#"
+ "reload_completed"
+ [(const_int 0)]
+{
+ emit_insn (gen_subsi3_flags (operands[0], operands[2], operands[3]));
+ emit_insn (gen_sbb_internal (operands[1], operands[4], operands[5]));
+ DONE;
+})
+
(define_insn "xorsi3"
[(set (match_operand:SI 0 "register_operand" "=r,r,r,r,r,r")
(xor:SI (match_operand:SI 1 "register_operand" "%0,0,0,0,0,0")
(match_operand:SI 2 "rx_source_operand"
"r,Sint08,Sint16,Sint24,i,Q")))
- (set (reg:CC_ZS CC_REG)
- (compare:CC_ZS (xor:SI (match_dup 1) (match_dup 2))
- (const_int 0)))]
+ (clobber (reg:CC CC_REG))]
""
"xor\t%Q2, %0"
[(set_attr "timings" "11,11,11,11,11,33")
(set_attr "length" "3,4,5,6,7,6")]
)
+
+(define_insn "*xorsi3_flags"
+ [(set (match_operand:SI 0 "register_operand" "=r,r,r,r,r,r")
+ (xor:SI (match_operand:SI 1 "register_operand" "%0,0,0,0,0,0")
+ (match_operand:SI 2 "rx_source_operand"
+ "r,Sint08,Sint16,Sint24,i,Q")))
+ (set (reg CC_REG)
+ (compare (xor:SI (match_dup 1) (match_dup 2))
+ (const_int 0)))]
+ "reload_completed && rx_match_ccmode (insn, CC_ZSmode)"
+ "xor\t%Q2, %0"
+ [(set_attr "timings" "11,11,11,11,11,33")
+ (set_attr "length" "3,4,5,6,7,6")]
+)
\f
;; Floating Point Instructions
[(set (match_operand:SF 0 "register_operand" "=r,r,r")
(plus:SF (match_operand:SF 1 "register_operand" "%0,0,0")
(match_operand:SF 2 "rx_source_operand" "r,F,Q")))
- (set (reg:CC_ZS CC_REG)
- (compare:CC_ZS (plus:SF (match_dup 1) (match_dup 2))
- (const_int 0)))]
+ (clobber (reg:CC CC_REG))]
"ALLOW_RX_FPU_INSNS"
"fadd\t%2, %0"
[(set_attr "timings" "44,44,66")
[(set (match_operand:SF 0 "register_operand" "=r,r,r")
(div:SF (match_operand:SF 1 "register_operand" "0,0,0")
(match_operand:SF 2 "rx_source_operand" "r,F,Q")))
- (set (reg:CC_ZS CC_REG)
- (compare:CC_ZS (div:SF (match_dup 1) (match_dup 2))
- (const_int 0)))]
+ (clobber (reg:CC CC_REG))]
"ALLOW_RX_FPU_INSNS"
"fdiv\t%2, %0"
[(set_attr "timings" "1616,1616,1818")
[(set (match_operand:SF 0 "register_operand" "=r,r,r")
(mult:SF (match_operand:SF 1 "register_operand" "%0,0,0")
(match_operand:SF 2 "rx_source_operand" "r,F,Q")))
- (set (reg:CC_ZS CC_REG)
- (compare:CC_ZS (mult:SF (match_dup 1) (match_dup 2))
- (const_int 0)))]
+ (clobber (reg:CC CC_REG))]
"ALLOW_RX_FPU_INSNS"
"fmul\t%2, %0"
[(set_attr "timings" "33,33,55")
[(set (match_operand:SF 0 "register_operand" "=r,r,r")
(minus:SF (match_operand:SF 1 "register_operand" "0,0,0")
(match_operand:SF 2 "rx_source_operand" "r,F,Q")))
- (set (reg:CC_ZS CC_REG)
- (compare:CC_ZS (minus:SF (match_dup 1) (match_dup 2))
- (const_int 0)))]
+ (clobber (reg:CC CC_REG))]
"ALLOW_RX_FPU_INSNS"
"fsub\t%Q2, %0"
[(set_attr "timings" "44,44,66")
(define_insn "fix_truncsfsi2"
[(set (match_operand:SI 0 "register_operand" "=r,r")
(fix:SI (match_operand:SF 1 "rx_compare_operand" "r,Q")))
- (set (reg:CC_ZS CC_REG)
- (compare:CC_ZS (fix:SI (match_dup 1))
- (const_int 0)))]
+ (clobber (reg:CC CC_REG))]
"ALLOW_RX_FPU_INSNS"
"ftoi\t%Q1, %0"
[(set_attr "timings" "22,44")
(define_insn "floatsisf2"
[(set (match_operand:SF 0 "register_operand" "=r,r")
(float:SF (match_operand:SI 1 "rx_compare_operand" "r,Q")))
- (set (reg:CC_ZS CC_REG)
- (compare:CC_ZS (float:SF (match_dup 1))
- (const_int 0)))]
+ (clobber (reg:CC CC_REG))]
"ALLOW_RX_FPU_INSNS"
"itof\t%Q1, %0"
[(set_attr "timings" "22,44")
)
\f
;; Bit manipulation instructions.
-;; Note - there are two versions of each pattern because the memory
-;; accessing versions use QImode whilst the register accessing
-;; versions use SImode.
-;; The peephole are here because the combiner only looks at a maximum
-;; of three instructions at a time.
-
-(define_insn "bitset"
- [(set:SI (match_operand:SI 0 "register_operand" "=r")
- (ior:SI (match_operand:SI 1 "register_operand" "0")
- (ashift:SI (const_int 1)
- (match_operand:SI 2 "nonmemory_operand" "ri"))))]
- ""
- "bset\t%2, %0"
+
+;; ??? The *_in_memory patterns will not be matched without further help.
+;; At one time we had the insv expander generate them, but I suspect that
+;; in general we get better performance by exposing the register load to
+;; the optimizers.
+;;
+;; An alternate solution would be to re-organize these patterns such
+;; that allow both register and memory operands. This would allow the
+;; register allocator to spill and not load the register operand. This
+;; would be possible only for operations for which we have a constant
+;; bit offset, so that we can adjust the address by ofs/8 and replace
+;; the offset in the insn by ofs%8.
+
+(define_insn "*bitset"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (ior:SI (ashift:SI (const_int 1)
+ (match_operand:SI 1 "rx_shift_operand" "ri"))
+ (match_operand:SI 2 "register_operand" "0")))]
+ ""
+ "bset\t%1, %0"
[(set_attr "length" "3")]
)
-(define_insn "bitset_in_memory"
- [(set:QI (match_operand:QI 0 "memory_operand" "=m")
- (ior:QI (match_operand:QI 1 "memory_operand" "0")
- (ashift:QI (const_int 1)
- (match_operand:QI 2 "nonmemory_operand" "ri"))))]
+(define_insn "*bitset_in_memory"
+ [(set (match_operand:QI 0 "memory_operand" "+Q")
+ (ior:QI (ashift:QI (const_int 1)
+ (match_operand:QI 1 "nonmemory_operand" "ri"))
+ (match_dup 0)))]
""
- "bset\t%2, %0.B"
+ "bset\t%1, %0.B"
[(set_attr "length" "3")
(set_attr "timings" "34")]
)
-;; (set (reg A) (const_int 1))
-;; (set (reg A) (ashift (reg A) (reg B)))
-;; (set (reg C) (ior (reg A) (reg C)))
-(define_peephole2
- [(set:SI (match_operand:SI 0 "register_operand" "")
- (const_int 1))
- (set:SI (match_dup 0)
- (ashift:SI (match_dup 0)
- (match_operand:SI 1 "register_operand" "")))
- (set:SI (match_operand:SI 2 "register_operand" "")
- (ior:SI (match_dup 0)
- (match_dup 2)))]
- "dead_or_set_p (insn, operands[0])"
- [(set:SI (match_dup 2)
- (ior:SI (match_dup 2)
- (ashift:SI (const_int 1)
- (match_dup 1))))]
-)
-
-;; (set (reg A) (const_int 1))
-;; (set (reg A) (ashift (reg A) (reg B)))
-;; (set (reg A) (ior (reg A) (reg C)))
-;; (set (reg C) (reg A)
-(define_peephole2
- [(set:SI (match_operand:SI 0 "register_operand" "")
- (const_int 1))
- (set:SI (match_dup 0)
- (ashift:SI (match_dup 0)
- (match_operand:SI 1 "register_operand" "")))
- (set:SI (match_dup 0)
- (ior:SI (match_dup 0)
- (match_operand:SI 2 "register_operand" "")))
- (set:SI (match_dup 2) (match_dup 0))]
- "dead_or_set_p (insn, operands[0])"
- [(set:SI (match_dup 2)
- (ior:SI (match_dup 2)
- (ashift:SI (const_int 1)
- (match_dup 1))))]
-)
-
-(define_insn "bitinvert"
- [(set:SI (match_operand:SI 0 "register_operand" "+r")
- (xor:SI (match_operand:SI 1 "register_operand" "0")
- (ashift:SI (const_int 1)
- (match_operand:SI 2 "nonmemory_operand" "ri"))))]
+(define_insn "*bitinvert"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (xor:SI (ashift:SI (const_int 1)
+ (match_operand:SI 1 "rx_shift_operand" "ri"))
+ (match_operand:SI 2 "register_operand" "0")))]
""
- "bnot\t%2, %0"
+ "bnot\t%1, %0"
[(set_attr "length" "3")]
)
-(define_insn "bitinvert_in_memory"
- [(set:QI (match_operand:QI 0 "memory_operand" "+m")
- (xor:QI (match_operand:QI 1 "register_operand" "0")
- (ashift:QI (const_int 1)
- (match_operand:QI 2 "nonmemory_operand" "ri"))))]
+(define_insn "*bitinvert_in_memory"
+ [(set (match_operand:QI 0 "memory_operand" "+Q")
+ (xor:QI (ashift:QI (const_int 1)
+ (match_operand:QI 1 "nonmemory_operand" "ri"))
+ (match_dup 0)))]
""
- "bnot\t%2, %0.B"
+ "bnot\t%1, %0.B"
[(set_attr "length" "5")
(set_attr "timings" "33")]
)
-;; (set (reg A) (const_int 1))
-;; (set (reg A) (ashift (reg A) (reg B)))
-;; (set (reg C) (xor (reg A) (reg C)))
-(define_peephole2
- [(set:SI (match_operand:SI 0 "register_operand" "")
- (const_int 1))
- (set:SI (match_dup 0)
- (ashift:SI (match_dup 0)
- (match_operand:SI 1 "register_operand" "")))
- (set:SI (match_operand:SI 2 "register_operand" "")
- (xor:SI (match_dup 0)
- (match_dup 2)))]
- "dead_or_set_p (insn, operands[0])"
- [(set:SI (match_dup 2)
- (xor:SI (match_dup 2)
- (ashift:SI (const_int 1)
- (match_dup 1))))]
+(define_insn "*bitclr"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (and:SI (not:SI
+ (ashift:SI
+ (const_int 1)
+ (match_operand:SI 1 "rx_shift_operand" "ri")))
+ (match_operand:SI 2 "register_operand" "0")))]
""
-)
-
-;; (set (reg A) (const_int 1))
-;; (set (reg A) (ashift (reg A) (reg B)))
-;; (set (reg A) (xor (reg A) (reg C)))
-;; (set (reg C) (reg A))
-(define_peephole2
- [(set:SI (match_operand:SI 0 "register_operand" "")
- (const_int 1))
- (set:SI (match_dup 0)
- (ashift:SI (match_dup 0)
- (match_operand:SI 1 "register_operand" "")))
- (set:SI (match_dup 0)
- (xor:SI (match_dup 0)
- (match_operand:SI 2 "register_operand" "")))
- (set:SI (match_dup 2) (match_dup 0))]
- "dead_or_set_p (insn, operands[0])"
- [(set:SI (match_dup 2)
- (xor:SI (match_dup 2)
- (ashift:SI (const_int 1)
- (match_dup 1))))]
- ""
-)
-
-(define_insn "bitclr"
- [(set:SI (match_operand:SI 0 "register_operand" "+r")
- (and:SI (match_operand:SI 1 "register_operand" "0")
- (not:SI (ashift:SI (const_int 1)
- (match_operand:SI 2 "nonmemory_operand" "ri")))))]
- ""
- "bclr\t%2, %0"
+ "bclr\t%1, %0"
[(set_attr "length" "3")]
)
-(define_insn "bitclr_in_memory"
- [(set:QI (match_operand:QI 0 "memory_operand" "+m")
- (and:QI (match_operand:QI 1 "memory_operand" "0")
- (not:QI (ashift:QI (const_int 1)
- (match_operand:QI 2 "nonmemory_operand" "ri")))))]
+(define_insn "*bitclr_in_memory"
+ [(set (match_operand:QI 0 "memory_operand" "+Q")
+ (and:QI (not:QI
+ (ashift:QI
+ (const_int 1)
+ (match_operand:QI 1 "nonmemory_operand" "ri")))
+ (match_dup 0)))]
""
- "bclr\t%2, %0.B"
+ "bclr\t%1, %0.B"
[(set_attr "length" "3")
(set_attr "timings" "34")]
)
-;; (set (reg A) (const_int -2))
-;; (set (reg A) (rotate (reg A) (reg B)))
-;; (set (reg C) (and (reg A) (reg C)))
-(define_peephole2
- [(set:SI (match_operand:SI 0 "register_operand" "")
- (const_int -2))
- (set:SI (match_dup 0)
- (rotate:SI (match_dup 0)
- (match_operand:SI 1 "register_operand" "")))
- (set:SI (match_operand:SI 2 "register_operand" "")
- (and:SI (match_dup 0)
- (match_dup 2)))]
- "dead_or_set_p (insn, operands[0])"
- [(set:SI (match_dup 2)
- (and:SI (match_dup 2)
- (not:SI (ashift:SI (const_int 1)
- (match_dup 1)))))]
+(define_insn "*insv_imm"
+ [(set (zero_extract:SI
+ (match_operand:SI 0 "register_operand" "+r")
+ (const_int 1)
+ (match_operand:SI 1 "rx_shift_operand" "ri"))
+ (match_operand:SI 2 "const_int_operand" ""))]
+ ""
+{
+ if (INTVAL (operands[2]) & 1)
+ return "bset\t%1, %0";
+ else
+ return "bclr\t%1, %0";
+}
+ [(set_attr "length" "3")]
)
-
-;; (set (reg A) (const_int -2))
-;; (set (reg A) (rotate (reg A) (reg B)))
-;; (set (reg A) (and (reg A) (reg C)))
-;; (set (reg C) (reg A)
-(define_peephole2
- [(set:SI (match_operand:SI 0 "register_operand" "")
- (const_int -2))
- (set:SI (match_dup 0)
- (rotate:SI (match_dup 0)
- (match_operand:SI 1 "register_operand" "")))
- (set:SI (match_dup 0)
- (and:SI (match_dup 0)
- (match_operand:SI 2 "register_operand" "")))
- (set:SI (match_dup 2) (match_dup 0))]
- "dead_or_set_p (insn, operands[0])"
- [(set:SI (match_dup 2)
- (and:SI (match_dup 2)
- (not:SI (ashift:SI (const_int 1)
- (match_dup 1)))))]
+
+(define_insn_and_split "rx_insv_reg"
+ [(set (zero_extract:SI
+ (match_operand:SI 0 "register_operand" "+r")
+ (const_int 1)
+ (match_operand:SI 1 "const_int_operand" ""))
+ (match_operand:SI 2 "register_operand" "r"))
+ (clobber (reg:CC CC_REG))]
+ ""
+ "#"
+ "reload_completed"
+ [(set (zero_extract:SI (match_dup 0) (const_int 1) (match_dup 1))
+ (match_dup 3))]
+{
+ rtx flags, x;
+
+ /* Emit tst #1, op2. */
+ flags = gen_rtx_REG (CC_ZSmode, CC_REG);
+ x = gen_rtx_AND (SImode, operands[2], const1_rtx);
+ x = gen_rtx_COMPARE (CC_ZSmode, x, const0_rtx);
+ x = gen_rtx_SET (VOIDmode, flags, x);
+ emit_insn (x);
+
+ /* Emit bmne. */
+ operands[3] = gen_rtx_NE (SImode, flags, const0_rtx);
+})
+
+(define_insn_and_split "*insv_cond"
+ [(set (zero_extract:SI
+ (match_operand:SI 0 "register_operand" "+r")
+ (const_int 1)
+ (match_operand:SI 1 "const_int_operand" ""))
+ (match_operator:SI 4 "comparison_operator"
+ [(match_operand:SI 2 "register_operand" "r")
+ (match_operand:SI 3 "rx_source_operand" "riQ")]))
+ (clobber (reg:CC CC_REG))]
+ ""
+ "#"
+ "reload_completed"
+ [(set (zero_extract:SI (match_dup 0) (const_int 1) (match_dup 1))
+ (match_dup 4))]
+{
+ rtx flags, x;
+
+ flags = gen_rtx_REG (CCmode, CC_REG);
+ x = gen_rtx_COMPARE (CCmode, operands[2], operands[3]);
+ x = gen_rtx_SET (VOIDmode, flags, x);
+ emit_insn (x);
+
+ operands[4] = gen_rtx_fmt_ee (GET_CODE (operands[4]), SImode,
+ flags, const0_rtx);
+})
+
+(define_insn "*bmcc"
+ [(set (zero_extract:SI
+ (match_operand:SI 0 "register_operand" "+r")
+ (const_int 1)
+ (match_operand:SI 1 "const_int_operand" ""))
+ (match_operator:SI 2 "comparison_operator"
+ [(reg CC_REG) (const_int 0)]))]
+ "reload_completed"
+ "bm%B2\t%1, %0"
+ [(set_attr "length" "3")]
)
-(define_expand "insv"
- [(set:SI (zero_extract:SI (match_operand:SI 0 "nonimmediate_operand") ;; Destination
- (match_operand 1 "immediate_operand") ;; # of bits to set
- (match_operand 2 "immediate_operand")) ;; Starting bit
- (match_operand 3 "immediate_operand"))] ;; Bits to insert
+;; Work around the fact that X=Y<0 is preferentially expanded as a shift.
+(define_insn_and_split "*insv_cond_lt"
+ [(set (zero_extract:SI
+ (match_operand:SI 0 "register_operand" "+r")
+ (const_int 1)
+ (match_operand:SI 1 "const_int_operand" ""))
+ (match_operator:SI 3 "rshift_operator"
+ [(match_operand:SI 2 "register_operand" "r")
+ (const_int 31)]))
+ (clobber (reg:CC CC_REG))]
""
- {
- if (rx_expand_insv (operands))
+ "#"
+ ""
+ [(parallel [(set (zero_extract:SI (match_dup 0) (const_int 1) (match_dup 1))
+ (lt:SI (match_dup 2) (const_int 0)))
+ (clobber (reg:CC CC_REG))])]
+ ""
+)
+
+(define_expand "insv"
+ [(set (zero_extract:SI
+ (match_operand:SI 0 "register_operand") ;; Destination
+ (match_operand:SI 1 "const_int_operand") ;; # of bits to set
+ (match_operand:SI 2 "nonmemory_operand")) ;; Starting bit
+ (match_operand:SI 3 "nonmemory_operand"))] ;; Bits to insert
+ ""
+{
+ /* We only handle single-bit inserts. */
+ if (!CONST_INT_P (operands[1]) || INTVAL (operands[1]) != 1)
+ FAIL;
+
+ /* Either the bit to insert or the position must be constant. */
+ if (CONST_INT_P (operands[3]))
+ operands[3] = GEN_INT (INTVAL (operands[3]) & 1);
+ else if (CONST_INT_P (operands[2]))
+ {
+ emit_insn (gen_rx_insv_reg (operands[0], operands[2], operands[3]));
DONE;
+ }
+ else
FAIL;
- }
-)
+})
\f
;; Atomic exchange operation.
(define_insn "sync_lock_test_and_setsi"
- [(set:SI (match_operand:SI 0 "register_operand" "=r,r")
- (match_operand:SI 1 "rx_compare_operand" "=r,Q"))
- (set:SI (match_dup 1)
- (match_operand:SI 2 "register_operand" "0,0"))]
+ [(set (match_operand:SI 0 "register_operand" "=r,r")
+ (match_operand:SI 1 "rx_compare_operand" "=r,Q"))
+ (set (match_dup 1)
+ (match_operand:SI 2 "register_operand" "0,0"))]
""
"xchg\t%1, %0"
[(set_attr "length" "3,6")
;; Block move functions.
(define_expand "movstr"
- [(set:SI (match_operand:BLK 1 "memory_operand") ;; Dest
- (match_operand:BLK 2 "memory_operand")) ;; Source
- (use (match_operand:SI 0 "register_operand")) ;; Updated Dest
+ [(set (match_operand:BLK 1 "memory_operand") ;; Dest
+ (match_operand:BLK 2 "memory_operand")) ;; Source
+ (use (match_operand:SI 0 "register_operand")) ;; Updated Dest
]
""
{
)
(define_insn "rx_movstr"
- [(set:SI (mem:BLK (reg:SI 1))
- (mem:BLK (reg:SI 2)))
+ [(set (mem:BLK (reg:SI 1))
+ (mem:BLK (reg:SI 2)))
(unspec_volatile:BLK [(reg:SI 1) (reg:SI 2) (reg:SI 3)] UNSPEC_MOVSTR)
(clobber (reg:SI 1))
(clobber (reg:SI 2))
)
(define_insn "rx_strend"
- [(set:SI (match_operand:SI 0 "register_operand" "=r")
- (unspec_volatile:SI [(match_operand:SI 1 "register_operand" "r")
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (unspec_volatile:SI [(match_operand:SI 1 "register_operand" "r")
(reg:SI 3)] UNSPEC_STRLEN))
(clobber (reg:SI 1))
(clobber (reg:SI 2))
)
(define_insn "rx_setmem"
- [(set:BLK (mem:BLK (reg:SI 1)) (reg 2))
- (unspec_volatile:BLK [(reg:SI 1) (reg:SI 2) (reg:SI 3)] UNSPEC_SETMEM)
+ [(set (mem:BLK (reg:SI 1))
+ (unspec_volatile:BLK [(reg:SI 1) (reg:SI 2) (reg:SI 3)] UNSPEC_SETMEM))
(clobber (reg:SI 1))
(clobber (reg:SI 3))]
""
)
(define_insn "rx_cmpstrn"
- [(set:SI (match_operand:SI 0 "register_operand" "=r")
- (unspec_volatile:SI [(reg:SI 1) (reg:SI 2) (reg:SI 3)]
- UNSPEC_CMPSTRN))
- (use (match_operand:BLK 1 "memory_operand" "m"))
- (use (match_operand:BLK 2 "memory_operand" "m"))
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (unspec_volatile:SI [(reg:SI 1) (reg:SI 2) (reg:SI 3)]
+ UNSPEC_CMPSTRN))
+ (use (match_operand:BLK 1 "memory_operand" "m"))
+ (use (match_operand:BLK 2 "memory_operand" "m"))
(clobber (reg:SI 1))
(clobber (reg:SI 2))
(clobber (reg:SI 3))
;; Byte swap (two 16-bit values).
(define_insn "revw"
- [(set (match_operand:SI 0 "register_operand" "+r")
+ [(set (match_operand:SI 0 "register_operand" "=r")
(unspec:SI [(match_operand:SI 1 "register_operand" "r")]
UNSPEC_BUILTIN_REVW))]
""
;; Clear Processor Status Word
(define_insn "clrpsw"
- [(unspec:SI [(match_operand:SI 0 "immediate_operand" "i")]
+ [(unspec_volatile:SI [(match_operand:SI 0 "immediate_operand" "i")]
UNSPEC_BUILTIN_CLRPSW)
(clobber (reg:CC CC_REG))]
""
;; Set Processor Status Word
(define_insn "setpsw"
- [(unspec:SI [(match_operand:SI 0 "immediate_operand" "i")]
+ [(unspec_volatile:SI [(match_operand:SI 0 "immediate_operand" "i")]
UNSPEC_BUILTIN_SETPSW)
(clobber (reg:CC CC_REG))]
""
;; Move from control register
(define_insn "mvfc"
[(set (match_operand:SI 0 "register_operand" "=r")
- (unspec:SI [(match_operand:SI 1 "immediate_operand" "i")]
+ (unspec_volatile:SI [(match_operand:SI 1 "immediate_operand" "i")]
UNSPEC_BUILTIN_MVFC))]
""
"mvfc\t%C1, %0"
;; Move to control register
(define_insn "mvtc"
- [(unspec:SI [(match_operand:SI 0 "immediate_operand" "i,i")
+ [(unspec_volatile:SI [(match_operand:SI 0 "immediate_operand" "i,i")
(match_operand:SI 1 "nonmemory_operand" "r,i")]
UNSPEC_BUILTIN_MVTC)]
""
;; Move to interrupt priority level
(define_insn "mvtipl"
- [(unspec:SI [(match_operand:SI 0 "immediate_operand" "Uint04")]
+ [(unspec_volatile:SI [(match_operand:SI 0 "immediate_operand" "Uint04")]
UNSPEC_BUILTIN_MVTIPL)]
""
"mvtipl\t%0"