summaryrefslogtreecommitdiff
path: root/gcc/config/rx
diff options
context:
space:
mode:
authorbstarynk <bstarynk@138bc75d-0d04-0410-961f-82ee72b054a4>2011-01-19 10:29:54 +0000
committerbstarynk <bstarynk@138bc75d-0d04-0410-961f-82ee72b054a4>2011-01-19 10:29:54 +0000
commit5b9a94504088e7452ea562233e9643e0d8205df6 (patch)
treefc86c19aa122e91770ae23801d19b8a249fe74d7 /gcc/config/rx
parent01c7add04011110f55f1f7b662ab1b8dc99ed9d4 (diff)
downloadgcc-5b9a94504088e7452ea562233e9643e0d8205df6.tar.gz
2011-01-19 Basile Starynkevitch <basile@starynkevitch.net>
MELT branch merged with trunk rev 168984 2011-01-19 Basile Starynkevitch <basile@starynkevitch.net> * gcc/melt/warmelt-outobj.melt (generate_runtypesupport_mapfun): Correct some typos in generated code. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/branches/melt-branch@168988 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/config/rx')
-rw-r--r--gcc/config/rx/predicates.md70
-rw-r--r--gcc/config/rx/rx-modes.def2
-rw-r--r--gcc/config/rx/rx-protos.h8
-rw-r--r--gcc/config/rx/rx.c561
-rw-r--r--gcc/config/rx/rx.h12
-rw-r--r--gcc/config/rx/rx.md1612
6 files changed, 1362 insertions, 903 deletions
diff --git a/gcc/config/rx/predicates.md b/gcc/config/rx/predicates.md
index e1b3f0c9f91..608fca5f925 100644
--- a/gcc/config/rx/predicates.md
+++ b/gcc/config/rx/predicates.md
@@ -37,19 +37,19 @@
;; Only small integers or a value in a register are permitted.
(define_predicate "rx_shift_operand"
- (match_code "const_int,reg")
- {
- if (CONST_INT_P (op))
- return IN_RANGE (INTVAL (op), 0, 31);
- return true;
- }
+ (ior (match_operand 0 "register_operand")
+ (and (match_code "const_int")
+ (match_test "IN_RANGE (INTVAL (op), 0, 31)")))
)
(define_predicate "rx_constshift_operand"
- (match_code "const_int")
- {
- return IN_RANGE (INTVAL (op), 0, 31);
- }
+ (and (match_code "const_int")
+ (match_test "IN_RANGE (INTVAL (op), 0, 31)"))
+)
+
+(define_predicate "rx_restricted_mem_operand"
+ (and (match_code "mem")
+ (match_test "rx_is_restricted_memory_address (XEXP (op, 0), mode)"))
)
;; Check that the operand is suitable as the source operand
@@ -57,20 +57,9 @@
;; and a restricted subset of memory addresses are allowed.
(define_predicate "rx_source_operand"
- (match_code "const_int,const_double,const,symbol_ref,label_ref,reg,mem")
- {
- if (CONSTANT_P (op))
- return rx_is_legitimate_constant (op);
-
- if (! MEM_P (op))
- return true;
-
- /* Do not allow size conversions whilst accessing memory. */
- if (GET_MODE (op) != mode)
- return false;
-
- return rx_is_restricted_memory_address (XEXP (op, 0), mode);
- }
+ (ior (match_operand 0 "register_operand")
+ (match_operand 0 "immediate_operand")
+ (match_operand 0 "rx_restricted_mem_operand"))
)
;; Check that the operand is suitable as the source operand
@@ -79,16 +68,8 @@
;; CONST_INTs are not.
(define_predicate "rx_compare_operand"
- (match_code "subreg,reg,mem")
- {
- if (GET_CODE (op) == SUBREG)
- return REG_P (XEXP (op, 0));
-
- if (! MEM_P (op))
- return true;
-
- return rx_is_restricted_memory_address (XEXP (op, 0), mode);
- }
+ (ior (match_operand 0 "register_operand")
+ (match_operand 0 "rx_restricted_mem_operand"))
)
;; Return true if OP is a store multiple operation. This looks like:
@@ -293,3 +274,24 @@
element = XVECEXP (op, 0, count - 1);
return GET_CODE (element) == RETURN;
})
+
+(define_predicate "label_ref_operand"
+ (match_code "label_ref")
+)
+
+(define_predicate "rx_z_comparison_operator"
+ (match_code "eq,ne")
+)
+
+(define_predicate "rx_zs_comparison_operator"
+ (match_code "eq,ne,lt,ge")
+)
+
+;; GT, LE, UNLE, UNGT omitted due to operand swap required.
+(define_predicate "rx_fp_comparison_operator"
+ (match_code "eq,ne,lt,ge,ordered,unordered,uneq,unlt,unge,ltgt")
+)
+
+(define_predicate "rshift_operator"
+ (match_code "ashiftrt,lshiftrt")
+)
diff --git a/gcc/config/rx/rx-modes.def b/gcc/config/rx/rx-modes.def
index 0c4c192a265..31e3225c677 100644
--- a/gcc/config/rx/rx-modes.def
+++ b/gcc/config/rx/rx-modes.def
@@ -21,3 +21,5 @@
CC_MODE (CC_ZS);
CC_MODE (CC_ZSO);
CC_MODE (CC_ZSC);
+
+CC_MODE (CC_F); /* fcmp */
diff --git a/gcc/config/rx/rx-protos.h b/gcc/config/rx/rx-protos.h
index 528ccb33e1b..3c3f2d47124 100644
--- a/gcc/config/rx/rx-protos.h
+++ b/gcc/config/rx/rx-protos.h
@@ -24,22 +24,24 @@
/* A few abbreviations to make the prototypes shorter. */
#define Mmode enum machine_mode
#define Fargs CUMULATIVE_ARGS
+#define Rcode enum rtx_code
extern void rx_expand_prologue (void);
extern int rx_initial_elimination_offset (int, int);
#ifdef RTX_CODE
-extern bool rx_compare_redundant (rtx);
extern void rx_emit_stack_popm (rtx *, bool);
extern void rx_emit_stack_pushm (rtx *);
extern void rx_expand_epilogue (bool);
-extern bool rx_expand_insv (rtx *);
-extern const char * rx_gen_cond_branch_template (rtx, bool);
extern char * rx_gen_move_template (rtx *, bool);
extern bool rx_is_legitimate_constant (rtx);
extern bool rx_is_mode_dependent_addr (rtx);
extern bool rx_is_restricted_memory_address (rtx, Mmode);
extern void rx_notice_update_cc (rtx body, rtx insn);
+extern void rx_split_cbranch (Mmode, Rcode, rtx, rtx, rtx);
+extern bool rx_split_fp_compare (Rcode, Rcode *, Rcode *);
+extern Mmode rx_select_cc_mode (Rcode, rtx, rtx);
+extern bool rx_match_ccmode (rtx, Mmode);
#endif
#endif /* GCC_RX_PROTOS_H */
diff --git a/gcc/config/rx/rx.c b/gcc/config/rx/rx.c
index 8f6f384c4c2..0179b1ff520 100644
--- a/gcc/config/rx/rx.c
+++ b/gcc/config/rx/rx.c
@@ -53,6 +53,15 @@
static void rx_print_operand (FILE *, rtx, int);
+#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 */
+
+static unsigned int flags_from_mode (enum machine_mode mode);
+static unsigned int flags_from_code (enum rtx_code code);
+
enum rx_cpu_types rx_cpu_type = RX600;
/* Return true if OP is a reference to an object in a small data area. */
@@ -354,8 +363,6 @@ rx_assemble_integer (rtx x, unsigned int size, int is_aligned)
}
-int rx_float_compare_mode;
-
/* Handles the insertion of a single operand into the assembler output.
The %<letter> directives supported are:
@@ -395,21 +402,82 @@ rx_print_operand (FILE * file, rtx op, int letter)
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 = "n";
+ break;
+ case GE:
+ ret = "pz";
+ 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_checking_assert ((flags_from_code (code)
+ & ~flags_from_mode (mode)) == 0);
+ }
+ fputs (ret, file);
+ break;
+ }
case 'C':
gcc_assert (CONST_INT_P (op));
@@ -700,51 +768,6 @@ rx_gen_move_template (rtx * operands, bool is_movu)
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 ();
- }
-}
/* Return VALUE rounded up to the next ALIGNMENT boundary. */
@@ -1226,13 +1249,13 @@ gen_rx_store_vector (unsigned int low, unsigned int high)
vector = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (count));
XVECEXP (vector, 0, 0) =
- gen_rtx_SET (SImode, stack_pointer_rtx,
+ gen_rtx_SET (VOIDmode, stack_pointer_rtx,
gen_rtx_MINUS (SImode, stack_pointer_rtx,
GEN_INT ((count - 1) * UNITS_PER_WORD)));
for (i = 0; i < count - 1; i++)
XVECEXP (vector, 0, i + 1) =
- gen_rtx_SET (SImode,
+ gen_rtx_SET (VOIDmode,
gen_rtx_MEM (SImode,
gen_rtx_MINUS (SImode, stack_pointer_rtx,
GEN_INT ((i + 1) * UNITS_PER_WORD))),
@@ -1456,12 +1479,12 @@ gen_rx_rtsd_vector (unsigned int adjust, unsigned int low, unsigned int high)
vector = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (count));
XVECEXP (vector, 0, 0) =
- gen_rtx_SET (SImode, stack_pointer_rtx,
+ gen_rtx_SET (VOIDmode, stack_pointer_rtx,
plus_constant (stack_pointer_rtx, adjust));
for (i = 0; i < count - 2; i++)
XVECEXP (vector, 0, i + 1) =
- gen_rtx_SET (SImode,
+ gen_rtx_SET (VOIDmode,
gen_rtx_REG (SImode, low + i),
gen_rtx_MEM (SImode,
i == 0 ? stack_pointer_rtx
@@ -1485,13 +1508,13 @@ gen_rx_popm_vector (unsigned int low, unsigned int high)
vector = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (count));
XVECEXP (vector, 0, 0) =
- gen_rtx_SET (SImode, stack_pointer_rtx,
+ gen_rtx_SET (VOIDmode, stack_pointer_rtx,
plus_constant (stack_pointer_rtx,
(count - 1) * UNITS_PER_WORD));
for (i = 0; i < count - 1; i++)
XVECEXP (vector, 0, i + 1) =
- gen_rtx_SET (SImode,
+ gen_rtx_SET (VOIDmode,
gen_rtx_REG (SImode, low + i),
gen_rtx_MEM (SImode,
i == 0 ? stack_pointer_rtx
@@ -1824,7 +1847,6 @@ enum rx_builtin
RX_BUILTIN_REVW,
RX_BUILTIN_RMPA,
RX_BUILTIN_ROUND,
- RX_BUILTIN_SAT,
RX_BUILTIN_SETPSW,
RX_BUILTIN_WAIT,
RX_BUILTIN_max
@@ -1879,7 +1901,6 @@ rx_init_builtins (void)
ADD_RX_BUILTIN1 (RACW, "racw", void, integer);
ADD_RX_BUILTIN1 (ROUND, "round", intSI, float);
ADD_RX_BUILTIN1 (REVW, "revw", intSI, intSI);
- ADD_RX_BUILTIN1 (SAT, "sat", intSI, intSI);
ADD_RX_BUILTIN1 (WAIT, "wait", void, void);
}
@@ -2077,8 +2098,6 @@ rx_expand_builtin (tree exp,
case RX_BUILTIN_ROUND: return rx_expand_builtin_round (op, target);
case RX_BUILTIN_REVW: return rx_expand_int_builtin_1_arg
(op, target, gen_revw, false);
- case RX_BUILTIN_SAT: return rx_expand_int_builtin_1_arg
- (op, target, gen_sat, false);
case RX_BUILTIN_WAIT: emit_insn (gen_wait ()); return NULL_RTX;
default:
@@ -2316,48 +2335,6 @@ rx_is_ms_bitfield_layout (const_tree record_type ATTRIBUTE_UNUSED)
/* 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;
-}
/* Returns true if X a legitimate constant for an immediate
operand on the RX. X is already known to satisfy CONSTANT_P. */
@@ -2543,219 +2520,223 @@ rx_trampoline_init (rtx tramp, tree fndecl, rtx chain)
}
}
+static int
+rx_memory_move_cost (enum machine_mode mode, reg_class_t regclass, bool in)
+{
+ return 2 + memory_move_secondary_cost (mode, regclass, in);
+}
+
+/* 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
-rx_cc_modes_compatible (enum machine_mode m1, enum machine_mode m2)
+mode_from_flags (unsigned int f)
{
- if (m1 == CCmode)
- return m2;
- if (m2 == CCmode)
- return m1;
- if (m1 == m2)
- return m1;
- if (m1 == CC_ZSmode)
- return m1;
- if (m2 == CC_ZSmode)
- return m2;
- return VOIDmode;
+ 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;
}
-#define CC_FLAG_S (1 << 0)
-#define CC_FLAG_Z (1 << 1)
-#define CC_FLAG_O (1 << 2)
-#define CC_FLAG_C (1 << 3)
+/* Convert an RTX_CODE to the set of flags needed to implement it.
+ This assumes an integer comparison. */
static unsigned int
-flags_needed_for_conditional (rtx conditional)
+flags_from_code (enum rtx_code code)
{
- switch (GET_CODE (conditional))
+ switch (code)
{
+ case LT:
+ case GE:
+ return CC_FLAG_S;
+ case GT:
case LE:
- case GT: return CC_FLAG_S | CC_FLAG_Z | CC_FLAG_O;
-
+ return CC_FLAG_S | CC_FLAG_O | CC_FLAG_Z;
+ case GEU:
+ case LTU:
+ return CC_FLAG_C;
+ case GTU:
case LEU:
- case GTU: return CC_FLAG_Z | CC_FLAG_C;
+ return CC_FLAG_C | CC_FLAG_Z;
+ case EQ:
+ case NE:
+ return CC_FLAG_Z;
+ default:
+ gcc_unreachable ();
+ }
+}
- case LT:
- case GE: return CC_FLAG_S | CC_FLAG_O;
+/* Return a CC_MODE of which both M1 and M2 are subsets. */
- case LTU:
- case GEU: return CC_FLAG_C;
+static enum machine_mode
+rx_cc_modes_compatible (enum machine_mode m1, enum machine_mode m2)
+{
+ unsigned f;
- case EQ:
- case NE: return CC_FLAG_Z;
+ /* Early out for identical modes. */
+ if (m1 == m2)
+ return m1;
- default: gcc_unreachable ();
- }
+ /* 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);
}
-static unsigned int
-flags_from_mode (enum machine_mode mode)
+/* Return the minimal CC mode needed to implement (CMP_CODE X Y). */
+
+enum machine_mode
+rx_select_cc_mode (enum rtx_code cmp_code, rtx x, rtx y ATTRIBUTE_UNUSED)
{
- 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 ();
- }
+ if (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT)
+ return CC_Fmode;
+
+ return mode_from_flags (flags_from_code (cmp_code));
}
-/* Returns true if a compare insn is redundant because it
- would only set flags that are already set correctly. */
+/* Split the floating-point comparison IN into individual comparisons
+ O1 and O2. O2 may be UNKNOWN if there is no second comparison.
+ Return true iff the comparison operands must be swapped. */
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;
+rx_split_fp_compare (enum rtx_code in, enum rtx_code *o1, enum rtx_code *o2)
+{
+ enum rtx_code cmp1 = in, cmp2 = UNKNOWN;
+ bool swap = false;
- /* Locate the branch insn that follows the
- compare and which tests the bits in the PSW. */
- next = cmp;
- do
+ switch (in)
{
- /* 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;
+ case ORDERED:
+ case UNORDERED:
+ case LT:
+ case GE:
+ case EQ:
+ case NE:
+ break;
- /* 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;
+ case GT:
+ case LE:
+ cmp1 = swap_condition (cmp1);
+ swap = true;
+ break;
- /* 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;
+ case UNEQ:
+ cmp1 = UNORDERED;
+ cmp2 = EQ;
+ break;
+ case UNLT:
+ cmp1 = UNORDERED;
+ cmp2 = LT;
+ break;
+ case UNGE:
+ cmp1 = UNORDERED;
+ cmp2 = GE;
+ break;
+ case UNLE:
+ cmp1 = UNORDERED;
+ cmp2 = GT;
+ swap = true;
+ break;
+ case UNGT:
+ cmp1 = UNORDERED;
+ cmp2 = LE;
+ swap = true;
+ break;
+ case LTGT:
+ cmp1 = ORDERED;
+ cmp2 = NE;
+ break;
- if (GET_CODE (SET_SRC (PATTERN (next))) != IF_THEN_ELSE)
- return false;
- }
+ default:
+ gcc_unreachable ();
}
- 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);
+ *o1 = cmp1;
+ *o2 = cmp2;
+ return swap;
+}
- if (prev == NULL_RTX)
- return false;
+/* Split the conditional branch. Emit (COMPARE C1 C2) into CC_REG with
+ CC_MODE, and use that in branches based on that compare. */
- /* 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;
- }
+void
+rx_split_cbranch (enum machine_mode cc_mode, enum rtx_code cmp1,
+ rtx c1, rtx c2, rtx label)
+{
+ rtx flags, x;
- /* 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;
- }
+ 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);
- return ((flags_set & flags_needed) == flags_needed);
+ 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);
}
-static int
-rx_memory_move_cost (enum machine_mode mode, reg_class_t regclass, bool in)
+/* A helper function for matching parallels that set the flags. */
+
+bool
+rx_match_ccmode (rtx insn, enum machine_mode cc_mode)
{
- return 2 + memory_move_secondary_cost (mode, regclass, in);
+ 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 (flags_from_mode (flags_mode) & ~flags_from_mode (cc_mode))
+ return false;
+
+ return true;
}
+
#undef TARGET_FUNCTION_VALUE
#define TARGET_FUNCTION_VALUE rx_function_value
diff --git a/gcc/config/rx/rx.h b/gcc/config/rx/rx.h
index 35b5d58c4a4..e2c8641685d 100644
--- a/gcc/config/rx/rx.h
+++ b/gcc/config/rx/rx.h
@@ -595,8 +595,6 @@ typedef unsigned int CUMULATIVE_ARGS;
they contain are always computed between two same-section symbols. */
#define JUMP_TABLES_IN_TEXT_SECTION (flag_pic)
-extern int rx_float_compare_mode;
-
/* This is a version of REG_P that also returns TRUE for SUBREGs. */
#define RX_REG_P(rtl) (REG_P (rtl) || GET_CODE (rtl) == SUBREG)
@@ -624,12 +622,4 @@ extern int rx_float_compare_mode;
#define BRANCH_COST(SPEED,PREDICT) 1
#define REGISTER_MOVE_COST(MODE,FROM,TO) 2
-#define SELECT_CC_MODE(OP,X,Y) \
- (GET_MODE_CLASS (GET_MODE (X)) == MODE_FLOAT ? CC_ZSmode : \
- (GET_CODE (X) == PLUS || GET_CODE (X) == MINUS ? CC_ZSCmode : \
- (GET_CODE (X) == ABS ? CC_ZSOmode : \
- (GET_CODE (X) == AND || GET_CODE (X) == NOT || GET_CODE (X) == IOR \
- || GET_CODE (X) == XOR || GET_CODE (X) == ROTATE \
- || GET_CODE (X) == ROTATERT || GET_CODE (X) == ASHIFTRT \
- || GET_CODE (X) == LSHIFTRT || GET_CODE (X) == ASHIFT ? CC_ZSmode : \
- CCmode))))
+#define SELECT_CC_MODE(OP,X,Y) rx_select_cc_mode(OP, X, Y)
diff --git a/gcc/config/rx/rx.md b/gcc/config/rx/rx.md
index e0271d66322..d8cd66d63de 100644
--- a/gcc/config/rx/rx.md
+++ b/gcc/config/rx/rx.md
@@ -19,14 +19,6 @@
;; <http://www.gnu.org/licenses/>.
-;; 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 "")])
@@ -150,6 +142,8 @@
(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
@@ -160,250 +154,228 @@
(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 "*tstbranchsi4r_<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"
- [(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"
+(define_insn_and_split "*cbranchsi4_tst_ext"
[(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 "comparison_operator"
+ [(match_operand:SF 1 "register_operand")
+ (match_operand:SF 2 "register_operand")])
+ (label_ref (match_operand 3 ""))
+ (pc)))]
"ALLOW_RX_FPU_INSNS"
- ""
-)
-
-(define_insn_and_split "*cbranchsf4_<code>"
+{
+ enum rtx_code cmp1, cmp2;
+
+ /* If the comparison needs swapping of operands, do that now.
+ Do not split the comparison in two yet. */
+ if (rx_split_fp_compare (GET_CODE (operands[0]), &cmp1, &cmp2))
+ {
+ rtx op1, op2;
+
+ if (cmp2 != UNKNOWN)
+ {
+ gcc_assert (cmp1 == UNORDERED);
+ if (cmp2 == GT)
+ cmp1 = UNGT;
+ else if (cmp2 == LE)
+ cmp1 = UNLE;
+ else
+ gcc_unreachable ();
+ }
+
+ op1 = operands[2];
+ op2 = operands[1];
+ operands[0] = gen_rtx_fmt_ee (cmp1, VOIDmode, op1, op2);
+ operands[1] = op1;
+ operands[2] = op2;
+ }
+})
+
+(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" "rFiQ")])
+ (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")]
-)
-
-;; ??? 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";
- }
+{
+ enum rtx_code cmp0, cmp1, cmp2;
+ rtx flags, lab1, lab2, over, x;
+ bool swap;
+
+ cmp0 = GET_CODE (operands[3]);
+ swap = rx_split_fp_compare (cmp0, &cmp1, &cmp2);
+ gcc_assert (!swap);
+
+ flags = gen_rtx_REG (CC_Fmode, CC_REG);
+ x = gen_rtx_COMPARE (CC_Fmode, operands[0], operands[1]);
+ x = gen_rtx_SET (VOIDmode, flags, x);
+ emit_insn (x);
+
+ over = NULL;
+ lab1 = lab2 = operands[2];
+
+ /* The one case of LTGT needs to be split into cmp1 && cmp2. */
+ if (cmp0 == LTGT)
+ {
+ over = gen_label_rtx ();
+ lab1 = gen_rtx_LABEL_REF (VOIDmode, over);
+ cmp1 = reverse_condition_maybe_unordered (cmp1);
+ }
+
+ /* Otherwise we split into cmp1 || cmp2. */
+ x = gen_rtx_fmt_ee (cmp1, VOIDmode, flags, const0_rtx);
+ x = gen_rtx_IF_THEN_ELSE (VOIDmode, x, lab1, pc_rtx);
+ x = gen_rtx_SET (VOIDmode, pc_rtx, x);
+ emit_jump_insn (x);
+
+ if (cmp2 != UNKNOWN)
+ {
+ x = gen_rtx_fmt_ee (cmp2, VOIDmode, flags, const0_rtx);
+ x = gen_rtx_IF_THEN_ELSE (VOIDmode, x, lab2, pc_rtx);
+ x = gen_rtx_SET (VOIDmode, pc_rtx, x);
+ emit_jump_insn (x);
+ }
+
+ if (over)
+ emit_label (over);
+ 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,iF,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)))]
- ""
+ (if_then_else
+ (match_operator 1 "comparison_operator"
+ [(reg 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);
- }
+ "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)
@@ -457,9 +429,9 @@
(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")))])]
"reload_completed"
{
rx_emit_stack_popm (operands, false);
@@ -684,11 +656,11 @@
)
(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")]
@@ -696,9 +668,9 @@
(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);
@@ -709,11 +681,11 @@
)
(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")
@@ -722,9 +694,9 @@
(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);
@@ -734,79 +706,230 @@
(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_expand "cstoresf4"
+ [(parallel [(set (match_operand:SI 0 "register_operand" "")
+ (match_operator:SI 1 "comparison_operator"
+ [(match_operand:SF 2 "register_operand" "")
+ (match_operand:SF 3 "register_operand" "")]))
+ (clobber (match_scratch:SI 4))])]
+ "ALLOW_RX_FPU_INSNS"
+{
+ enum rtx_code cmp1, cmp2;
+
+ /* If the comparison needs swapping of operands, do that now.
+ Do not split the comparison in two yet. */
+ if (rx_split_fp_compare (GET_CODE (operands[0]), &cmp1, &cmp2))
+ {
+ rtx op2, op3;
+
+ if (cmp2 != UNKNOWN)
+ {
+ gcc_assert (cmp1 == UNORDERED);
+ if (cmp2 == GT)
+ cmp1 = UNGT;
+ else if (cmp2 == LE)
+ cmp1 = UNLE;
+ else
+ gcc_unreachable ();
+ }
+
+ op2 = operands[3];
+ op3 = operands[2];
+ operands[0] = gen_rtx_fmt_ee (cmp1, VOIDmode, op2, op3);
+ operands[2] = op2;
+ operands[3] = op3;
+ }
+})
+
+(define_insn_and_split "*cstoresf4"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (match_operator:SI 4 "rx_fp_comparison_operator"
+ [(match_operand:SF 2 "register_operand" "r")
+ (match_operand:SF 3 "rx_source_operand" "rFiQ")]))
+ (clobber (match_scratch:SI 1 "=r"))]
+ "ALLOW_RX_FPU_INSNS"
+ "#"
+ "reload_completed"
+ [(const_int 0)]
+{
+ enum rtx_code cmp0, cmp1, cmp2;
+ rtx flags, x;
+ bool swap;
+
+ cmp0 = GET_CODE (operands[4]);
+ swap = rx_split_fp_compare (cmp0, &cmp1, &cmp2);
+ gcc_assert (!swap);
+
+ 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 (cmp1, SImode, flags, const0_rtx);
+ x = gen_rtx_SET (VOIDmode, operands[0], x);
+ emit_insn (x);
+
+ if (cmp0 == LTGT)
+ {
+ /* The one case of LTGT needs to be split into ORDERED && NE. */
+ x = gen_rtx_fmt_ee (EQ, VOIDmode, flags, const0_rtx);
+ x = gen_rtx_IF_THEN_ELSE (SImode, x, const0_rtx, operands[0]);
+ x = gen_rtx_SET (VOIDmode, operands[0], x);
+ emit_insn (x);
+ }
+ else if (cmp2 == EQ || cmp2 == NE)
+ {
+ /* Oring the two flags can be performed with a movcc operation. */
+ x = gen_rtx_fmt_ee (cmp2, VOIDmode, flags, const0_rtx);
+ x = gen_rtx_IF_THEN_ELSE (SImode, x, const1_rtx, operands[0]);
+ x = gen_rtx_SET (VOIDmode, operands[0], x);
+ emit_insn (x);
+ }
+ else if (cmp2 != UNKNOWN)
+ {
+ /* We can't use movcc, but need to or in another compare.
+ Do this by storing the second operation into the scratch. */
+ x = gen_rtx_fmt_ee (cmp2, SImode, flags, const0_rtx);
+ x = gen_rtx_SET (VOIDmode, operands[1], x);
+ emit_insn (x);
+
+ emit_insn (gen_iorsi3 (operands[0], operands[0], operands[1]));
+ }
+ 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"
@@ -817,9 +940,7 @@
[(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
@@ -840,27 +961,160 @@
(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))
+ ;
+ else if (rtx_equal_p (op0l, op2l))
+ x = op1l, op1l = op2l, op2l = x;
+ 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
@@ -876,9 +1130,31 @@
(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"
@@ -887,7 +1163,7 @@
;; 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"
@@ -995,12 +1271,23 @@
(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"
@@ -1010,9 +1297,7 @@
(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
@@ -1020,13 +1305,24 @@
[(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
@@ -1042,37 +1338,77 @@
(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
@@ -1081,13 +1417,26 @@
[(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
@@ -1096,13 +1445,26 @@
[(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
@@ -1111,16 +1473,57 @@
[(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
@@ -1132,32 +1535,134 @@
(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_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_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_source_operand" "rnQ, 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")]
+)
;; Floating Point Instructions
@@ -1165,9 +1670,7 @@
[(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")
@@ -1178,9 +1681,7 @@
[(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")
@@ -1191,9 +1692,7 @@
[(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")
@@ -1204,9 +1703,7 @@
[(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")
@@ -1216,9 +1713,7 @@
(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")
@@ -1228,9 +1723,7 @@
(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")
@@ -1238,217 +1731,216 @@
)
;; 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;
- }
-)
+})
;; 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")
@@ -1458,9 +1950,9 @@
;; 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
]
""
{
@@ -1483,8 +1975,8 @@
)
(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))
@@ -1496,8 +1988,8 @@
)
(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))
@@ -1578,8 +2070,8 @@
)
(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))]
""
@@ -1632,11 +2124,11 @@
)
(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))
@@ -1769,7 +2261,7 @@
;; 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))]
""
@@ -1789,16 +2281,6 @@
(set_attr "length" "3,5")]
)
-;; Saturate to 32-bits
-(define_insn "sat"
- [(set (match_operand:SI 0 "register_operand" "=r")
- (unspec:SI [(match_operand:SI 1 "register_operand" "0")]
- UNSPEC_BUILTIN_SAT))]
- ""
- "sat\t%0"
- [(set_attr "length" "2")]
-)
-
;;---------- Control Registers ------------------------
;; Clear Processor Status Word