diff options
author | bstarynk <bstarynk@138bc75d-0d04-0410-961f-82ee72b054a4> | 2011-01-19 10:29:54 +0000 |
---|---|---|
committer | bstarynk <bstarynk@138bc75d-0d04-0410-961f-82ee72b054a4> | 2011-01-19 10:29:54 +0000 |
commit | 5b9a94504088e7452ea562233e9643e0d8205df6 (patch) | |
tree | fc86c19aa122e91770ae23801d19b8a249fe74d7 /gcc/config/rx | |
parent | 01c7add04011110f55f1f7b662ab1b8dc99ed9d4 (diff) | |
download | gcc-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.md | 70 | ||||
-rw-r--r-- | gcc/config/rx/rx-modes.def | 2 | ||||
-rw-r--r-- | gcc/config/rx/rx-protos.h | 8 | ||||
-rw-r--r-- | gcc/config/rx/rx.c | 561 | ||||
-rw-r--r-- | gcc/config/rx/rx.h | 12 | ||||
-rw-r--r-- | gcc/config/rx/rx.md | 1612 |
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 |