From: Bernd Schmidt Date: Mon, 25 Nov 2019 12:31:16 +0000 (+0000) Subject: Convert m68k to not use cc0 X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=6cebc6cbbb801183090dbb2752aa6b698331a31c;p=gcc.git Convert m68k to not use cc0 * config/m68k/m68k.c (output_move_himode, output_move_qimode): Replace code for non-CONST_INT constants with gcc_unreachable. * config/m68k/m68k.md (cbranchdi): Don't generate individual compare and test. (CMPMODE): New mode_iterator. (cbranchsi4, cbranchqi4, cbranchhi4): Replace expanders with cbranch4. (cstoresi4, cstoreqi4, cstorehi4): Replace expanders with cstore4. (cmp_68881): Remove 'F' constraint from first comparison operand. (bit test insns patterns): Use nonimmediate_operand, not register_operand, for source operands that allow memory in their constraints. (divmodsi4, udivmodsi4, divmodhi4 and related unnamed patterns): Use register_operand, not nonimmediate_operand, for the destinations. (DBCC): New mode_iterator. (dbcc peepholes): Use it to reduce duplication. (trap): Use const_true_rtx, not const1_rtx. * config/m68k/predicates.md (m68k_comparison_operand): Renamed from m68k_subword_comparison_operand and changed to handle SImode. PR target/91851 * config/m68k/m68k-protos.h (output-dbcc_and_branch): Adjust declaration. (m68k_init_cc): New declaration. (m68k_output_compare_di, m68k_output_compare_si) (m68k_output_compare_hi, m68k_output_compare_qi) (m68k_output_compare_fp, m68k_output_btst, m68k_output_bftst) (m68k_find_flags_value, m68k_output_scc, m68k_output_scc_float) (m68k_output_branch_integer, m68k_output_branch_integer_rev. m68k_output_branch_float, m68k_output_branch_float_rev): Likewise. (valid_dbcc_comparison_p_2, flags_in_68881) (output_btst): Remove declaration. * config/m68k/m68k.c (INCLDUE_STRING): Define. (TARGET_ASM_FINAL_POSTSCAN_INSN): Define. (valid_dbcc_comparison_p_2, flags_in_68881): Delete functions. (flags_compare_op0, flags_compare_op1, flags_operand1, flags_operand2, flags_valid): New static variables. (m68k_find_flags_value, m68k_init_cc): New functions. (handle_flags_for_move, m68k_asm_final_postscan_insn, remember_compare_flags): New static functions. (output_dbcc_and_branch): New argument CODE. Use it, and add PLUS and MINUS to the possible codes. All callers changed. (m68k_output_btst): Renamed from output_btst. Remove OPERANDS and INSN arguments, add CODE arg. Return the comparison code to use. All callers changed. Use CODE instead of next_insn_tests_no_inequality, and replace cc_status management with changing the return code. (m68k_rtx_costs): Instead of testing for COMPARE, test for RTX_COMPARE or RTX_COMM_COMPARE. (output_move_simode, output_move_qimode): Call handle_flags_for_move. (notice_update_cc): Delete function. (m68k_output_bftst, m68k_output_compare_di, m68k_output_compare_si, m68k_output_compare_hi, m68k_output_compare_qi, m68k_output_compare_fp, m68k_output_branch_integer, m68k_output_branch_integer_rev, m68k_output_scc, m68k_output_branch_float, m68k_output_branch_float_rev, m68k_output_scc_float): New functions. (output_andsi3, output_iorsi3, output_xorsi3): Call CC_STATUS_INIT once at the start, and set flags_valid and flags_operand1 if the flags are usable. * config/m68k/m68k.h (CC_IN_68881, NOTICE_UPDATE_CC, CC_OVERFLOW_UNUSABLE, CC_NO_CARRY, OUTPUT_JUMP): Remove definitions. (CC_STATUS_INIT): Define. * config/m68k/m68k.md (flags_valid): New define_attr. (tstdi, tstsi_internal_68020_cf, tstsi_internal, tsthi_internal, tstqi_internal, tst_68881, tst_cf, cmpdi_internal, cmpdi, unnamed cmpsi/cmphi/cmpqi patterns, cmpsi_cf, cmp_68881, cmp_cf, unnamed btst patterns, tst_bftst_reg, tst_bftst_reg, unnamed scc patterns, scc, sls, sordered_1, sunordered_1, suneq_1, sunge_1, sungt_1, sunle_1, sunlt_1, sltgt_1, fsogt_1, fsoge_1, fsolt_1, fsole_1, bge0_di, blt0_di, beq, bne, bgt, bgtu, blt, bltu, bge, bgeu, ble, bleu, bordered, bunordered, buneq, bunge, bungt, bunle, bunlt, bltgt, beq_rev, bne_rev, bgt_rev, bgtu_rev, blt_rev, bltu_rev, bge_rev, bgeu_rev, ble_rev, bleu_rev, bordered_rev, bunordered_rev, buneq_rev, bunge_rv, bungt_rev, bunle_rev, bunlt_rev, bltgt_rev, ctrapdi4, ctrapsi4, ctraphi4, ctrapqi4, conditional_trap): Delete patterns. (cbranchdi4_insn): New pattern. (cbranchdi4): Don't generate cc0 patterns. When testing LT or GE, test high part only. When testing EQ or NE, generate beq0_di and bne0_di patterns directly. (cstoredi4): When testing LT or GE, test high part only. (both sets of cbranch4, cstore4): Don't generate cc0 patterns. (scc0_constraints, cmp1_constraints, cmp2_constraints, scc0_cf_constraints, cmp1_cf_constraints, cmp2_cf_constraints, cmp2_cf_predicate): New define_mode_attrs. (cbranch4_insn, cbranch4_insn_rev, cbranch4_insn_cf, cbranch4_insn_cf_rev, cstore4_insn, cstore4_insn_cf for integer modes) New patterns. (cbranch4_insn_68881, cbranch4_insn_rev_68881): (cbranch4_insn_cf, cbranch4_insn_rev_cf, cstore4_insn_68881, cstore4_insn_cf for FP): New patterns. (cbranchsi4_btst_mem_insn, cbranchsi4_btst_reg_insn, cbranchsi4_btst_mem_insn_1, cbranchsi4_btst_reg_insn_1): Likewise. (BTST): New define_mode_iterator. (btst_predicate, btst_constraint, btst_range): New define_mode_attrs. (cbranch_bftst_insn, cstore_bftst_insn): New patterns. (movsi_m68k_movsi_m68k2, movsi_cf, unnamed movstrict patterns, unnamed movhi and movqi patterns, unnamed movsf, movdf and movxf patterns): Set attr "flags_valid". (truncsiqi2, trunchiqi2, truncsihi2): Remove manual CC_STATUS management. Set attr "flags_valid". (extendsidi2, extendplussidi, unnamed float_extendsfdf pattern, extendsfdf2_cf, fix_truncdfsi2, fix_truncdfhi2, fix_truncdfqi2, addi_sexthishl32, adddi_dilshr32, adddi_dilshr32_cf, addi_dishl32, subdi_sexthishl32, subdi_dishl32, subdi3): Remove manual CC_STATUS management. (addsi3_internal, addhi3, addqi3, subsi3, subhi3, subqi3, unnamed strict_lowpart subhi and subqi patterns): Set attr "flags_valid". (unnamed strict_lowpart addhi3 and addqi3 patterns): Likewise. Remove code to operate on address regs and assert the case does not occur. (unnamed mulsidi patterns, divmodhi4, udivmodhi4): Remove manual CC_STATUS_INIT. (andsi3_internal, andhi3, andqi3, iorsi3_internal, iorhi3, iorqi3, xorsi3_internal, xorhi3, xorqi3, negsi2_internal, negsi2_5200, neghi2, negqi2, one_cmplsi2_internal, one_cmplhi2, one_cmplqi2, unnamed strict_lowpart patterns for andhi, andqi, iorhi, iorqi, xorhi, xorqi, neghi, negqi, one_cmplhi and one_cmplqi): Set attr "flags_valid". (iorsi_zext_ashl16, iorsi_zext): Remove manual CC_STATUS_INIT. (ashldi_sexthi, ashlsi_16, ashlsi_17_24): Remove manual CC_STATUS_INIT. (ashlsi3, ashlhi3, ashlqi3, ashrsi3, ashrhi3, ashrqi3, lshrsi3, lshrhi3, shrqi3, rotlsi3, rotlhi3, rotlhi3_lowpart, rotlqi3, rotlqi3_lowpart, rotrsi3, rotrhi3, rotrhi_lowpart, rotrqi3, unnamed strict_low_part patterns for HI and QI versions): Set attr "flags_valid". (bsetmemqi, bsetmemqi_ext, bsetdreg, bchgdreg, bclrdreg, bclrmemqi, extzv_8_16_reg, extzv_bfextu_mem, insv_bfchg_mem, insv_bfclr_mem, insv_bfset_mem, extv_bfextu_reg, insv_bfclr_reg, insv_bfset_reg, dbne_hi, dbne_si, dbge_hi, dbge_si, extendsfxf2, extenddfxf2, ): Remove manual cc_status management. (various unnamed peepholes): Adjust compare/branch sequences for new cbranch patterns. (dbcc peepholes): Likewise, and output the comparison here as well. * config/m68k/predicates.md (valid_dbcc_comparison_p): Delete. (fp_src_operand): Allow constant zero. (address_reg_operand): New predicate. * rtl.h (inequality_comparisons_p): Remove declaration. * recog.h (next_insn_tests_no_inequality): Likewise. * rtlanal.c (inequality_comparisons_p): Delete function. * recog.c (next_insn_tests_no_inequality): Likewise. From-SVN: r278681 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 6dee39e6823..b0957b0f973 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,166 @@ +2019-11-25 Bernd Schmidt + + * config/m68k/m68k.c (output_move_himode, output_move_qimode): + Replace code for non-CONST_INT constants with gcc_unreachable. + * config/m68k/m68k.md (cbranchdi): Don't generate individual + compare and test. + (CMPMODE): New mode_iterator. + (cbranchsi4, cbranchqi4, cbranchhi4): Replace expanders with + cbranch4. + (cstoresi4, cstoreqi4, cstorehi4): Replace expanders with + cstore4. + (cmp_68881): Remove 'F' constraint from first comparison + operand. + (bit test insns patterns): Use nonimmediate_operand, not + register_operand, for source operands that allow memory in + their constraints. + (divmodsi4, udivmodsi4, divmodhi4 and related unnamed patterns): + Use register_operand, not nonimmediate_operand, for the + destinations. + (DBCC): New mode_iterator. + (dbcc peepholes): Use it to reduce duplication. + (trap): Use const_true_rtx, not const1_rtx. + * config/m68k/predicates.md (m68k_comparison_operand): Renamed + from m68k_subword_comparison_operand and changed to handle + SImode. + + PR target/91851 + * config/m68k/m68k-protos.h (output-dbcc_and_branch): Adjust + declaration. + (m68k_init_cc): New declaration. + (m68k_output_compare_di, m68k_output_compare_si) + (m68k_output_compare_hi, m68k_output_compare_qi) + (m68k_output_compare_fp, m68k_output_btst, m68k_output_bftst) + (m68k_find_flags_value, m68k_output_scc, m68k_output_scc_float) + (m68k_output_branch_integer, m68k_output_branch_integer_rev. + m68k_output_branch_float, m68k_output_branch_float_rev): + Likewise. + (valid_dbcc_comparison_p_2, flags_in_68881) + (output_btst): Remove declaration. + * config/m68k/m68k.c (INCLDUE_STRING): Define. + (TARGET_ASM_FINAL_POSTSCAN_INSN): Define. + (valid_dbcc_comparison_p_2, flags_in_68881): Delete functions. + (flags_compare_op0, flags_compare_op1, flags_operand1, + flags_operand2, flags_valid): New static variables. + (m68k_find_flags_value, m68k_init_cc): New functions. + (handle_flags_for_move, m68k_asm_final_postscan_insn, + remember_compare_flags): New static functions. + (output_dbcc_and_branch): New argument CODE. Use it, and add + PLUS and MINUS to the possible codes. All callers changed. + (m68k_output_btst): Renamed from output_btst. Remove OPERANDS + and INSN arguments, add CODE arg. Return the comparison code + to use. All callers changed. Use CODE instead of + next_insn_tests_no_inequality, and replace cc_status management + with changing the return code. + (m68k_rtx_costs): Instead of testing for COMPARE, test for + RTX_COMPARE or RTX_COMM_COMPARE. + (output_move_simode, output_move_qimode): Call + handle_flags_for_move. + (notice_update_cc): Delete function. + (m68k_output_bftst, m68k_output_compare_di, m68k_output_compare_si, + m68k_output_compare_hi, m68k_output_compare_qi, + m68k_output_compare_fp, m68k_output_branch_integer, + m68k_output_branch_integer_rev, m68k_output_scc, + m68k_output_branch_float, m68k_output_branch_float_rev, + m68k_output_scc_float): New functions. + (output_andsi3, output_iorsi3, output_xorsi3): Call CC_STATUS_INIT + once at the start, and set flags_valid and flags_operand1 if the + flags are usable. + * config/m68k/m68k.h (CC_IN_68881, NOTICE_UPDATE_CC, + CC_OVERFLOW_UNUSABLE, CC_NO_CARRY, OUTPUT_JUMP): Remove + definitions. + (CC_STATUS_INIT): Define. + * config/m68k/m68k.md (flags_valid): New define_attr. + (tstdi, tstsi_internal_68020_cf, tstsi_internal, tsthi_internal, + tstqi_internal, tst_68881, tst_cf, cmpdi_internal, + cmpdi, unnamed cmpsi/cmphi/cmpqi patterns, cmpsi_cf, + cmp_68881, cmp_cf, unnamed btst patterns, + tst_bftst_reg, tst_bftst_reg, unnamed scc patterns, scc, + sls, sordered_1, sunordered_1, suneq_1, sunge_1, sungt_1, + sunle_1, sunlt_1, sltgt_1, fsogt_1, fsoge_1, fsolt_1, fsole_1, + bge0_di, blt0_di, beq, bne, bgt, bgtu, blt, bltu, bge, bgeu, + ble, bleu, bordered, bunordered, buneq, bunge, bungt, bunle, + bunlt, bltgt, beq_rev, bne_rev, bgt_rev, bgtu_rev, + blt_rev, bltu_rev, bge_rev, bgeu_rev, ble_rev, bleu_rev, + bordered_rev, bunordered_rev, buneq_rev, bunge_rv, bungt_rev, + bunle_rev, bunlt_rev, bltgt_rev, ctrapdi4, ctrapsi4, ctraphi4, + ctrapqi4, conditional_trap): Delete patterns. + (cbranchdi4_insn): New pattern. + (cbranchdi4): Don't generate cc0 patterns. When testing LT or GE, + test high part only. When testing EQ or NE, generate beq0_di + and bne0_di patterns directly. + (cstoredi4): When testing LT or GE, test high part only. + (both sets of cbranch4, cstore4): Don't generate cc0 + patterns. + (scc0_constraints, cmp1_constraints, cmp2_constraints, + scc0_cf_constraints, cmp1_cf_constraints, cmp2_cf_constraints, + cmp2_cf_predicate): New define_mode_attrs. + (cbranch4_insn, cbranch4_insn_rev, + cbranch4_insn_cf, cbranch4_insn_cf_rev, + cstore4_insn, cstore4_insn_cf for integer modes) + New patterns. + (cbranch4_insn_68881, cbranch4_insn_rev_68881): + (cbranch4_insn_cf, cbranch4_insn_rev_cf, + cstore4_insn_68881, cstore4_insn_cf for FP): + New patterns. + (cbranchsi4_btst_mem_insn, cbranchsi4_btst_reg_insn, + cbranchsi4_btst_mem_insn_1, cbranchsi4_btst_reg_insn_1): + Likewise. + (BTST): New define_mode_iterator. + (btst_predicate, btst_constraint, btst_range): New + define_mode_attrs. + (cbranch_bftst_insn, cstore_bftst_insn): New + patterns. + (movsi_m68k_movsi_m68k2, movsi_cf, unnamed movstrict patterns, + unnamed movhi and movqi patterns, unnamed movsf, movdf and movxf + patterns): Set attr "flags_valid". + (truncsiqi2, trunchiqi2, truncsihi2): Remove manual CC_STATUS + management. Set attr "flags_valid". + (extendsidi2, extendplussidi, unnamed float_extendsfdf pattern, + extendsfdf2_cf, fix_truncdfsi2, fix_truncdfhi2, fix_truncdfqi2, + addi_sexthishl32, adddi_dilshr32, adddi_dilshr32_cf, + addi_dishl32, subdi_sexthishl32, subdi_dishl32, subdi3): Remove + manual CC_STATUS management. + (addsi3_internal, addhi3, addqi3, subsi3, subhi3, subqi3, + unnamed strict_lowpart subhi and subqi patterns): Set attr + "flags_valid". + (unnamed strict_lowpart addhi3 and addqi3 patterns): Likewise. + Remove code to operate on address regs and assert the case + does not occur. + (unnamed mulsidi patterns, divmodhi4, udivmodhi4): Remove + manual CC_STATUS_INIT. + (andsi3_internal, andhi3, andqi3, iorsi3_internal, iorhi3, iorqi3, + xorsi3_internal, xorhi3, xorqi3, negsi2_internal, + negsi2_5200, neghi2, negqi2, one_cmplsi2_internal, one_cmplhi2, + one_cmplqi2, unnamed strict_lowpart patterns + for andhi, andqi, iorhi, iorqi, xorhi, xorqi, neghi, negqi, + one_cmplhi and one_cmplqi): Set attr "flags_valid". + (iorsi_zext_ashl16, iorsi_zext): Remove manual CC_STATUS_INIT. + (ashldi_sexthi, ashlsi_16, ashlsi_17_24): Remove manual + CC_STATUS_INIT. + (ashlsi3, ashlhi3, ashlqi3, ashrsi3, ashrhi3, ashrqi3, lshrsi3, + lshrhi3, shrqi3, rotlsi3, rotlhi3, rotlhi3_lowpart, rotlqi3, + rotlqi3_lowpart, rotrsi3, rotrhi3, rotrhi_lowpart, rotrqi3, + unnamed strict_low_part patterns for HI and + QI versions): Set attr "flags_valid". + (bsetmemqi, bsetmemqi_ext, bsetdreg, bchgdreg, bclrdreg, + bclrmemqi, extzv_8_16_reg, extzv_bfextu_mem, insv_bfchg_mem, + insv_bfclr_mem, insv_bfset_mem, extv_bfextu_reg, + insv_bfclr_reg, insv_bfset_reg, dbne_hi, dbne_si, dbge_hi, + dbge_si, extendsfxf2, extenddfxf2, ): Remove manual cc_status management. + (various unnamed peepholes): Adjust compare/branch sequences + for new cbranch patterns. + (dbcc peepholes): Likewise, and output the comparison here + as well. + * config/m68k/predicates.md (valid_dbcc_comparison_p): Delete. + (fp_src_operand): Allow constant zero. + (address_reg_operand): New predicate. + + * rtl.h (inequality_comparisons_p): Remove declaration. + * recog.h (next_insn_tests_no_inequality): Likewise. + * rtlanal.c (inequality_comparisons_p): Delete function. + * recog.c (next_insn_tests_no_inequality): Likewise. + 2019-11-25 Richard Biener * tree-vect-slp.c (vect_detect_hybrid_slp_stmts): Add assertion. diff --git a/gcc/config/m68k/m68k-protos.h b/gcc/config/m68k/m68k-protos.h index abd920e70f3..a88d9032347 100644 --- a/gcc/config/m68k/m68k-protos.h +++ b/gcc/config/m68k/m68k-protos.h @@ -42,7 +42,23 @@ extern const char *output_iorsi3 (rtx *); extern const char *output_xorsi3 (rtx *); extern const char *output_call (rtx); extern const char *output_sibcall (rtx); -extern void output_dbcc_and_branch (rtx *); +extern void m68k_init_cc (); +extern void output_dbcc_and_branch (rtx *, rtx_code); +extern rtx_code m68k_output_compare_di (rtx, rtx, rtx, rtx, rtx_insn *, rtx_code); +extern rtx_code m68k_output_compare_si (rtx, rtx, rtx_code); +extern rtx_code m68k_output_compare_hi (rtx, rtx, rtx_code); +extern rtx_code m68k_output_compare_qi (rtx, rtx, rtx_code); +extern rtx_code m68k_output_compare_fp (rtx, rtx, rtx_code); +extern rtx_code m68k_output_btst (rtx, rtx, rtx_code, int); +extern rtx_code m68k_output_bftst (rtx, rtx, rtx, rtx_code); +extern rtx_code m68k_find_flags_value (rtx, rtx, rtx_code); + +extern const char *m68k_output_scc (rtx_code); +extern const char *m68k_output_scc_float (rtx_code); +extern const char *m68k_output_branch_integer (rtx_code); +extern const char *m68k_output_branch_integer_rev (rtx_code); +extern const char *m68k_output_branch_float (rtx_code); +extern const char *m68k_output_branch_float_rev (rtx_code); extern int floating_exact_log2 (rtx); extern bool strict_low_part_peephole_ok (machine_mode mode, rtx_insn *first_insn, rtx target); @@ -88,7 +104,6 @@ extern enum attr_op_mem m68k_sched_attr_op_mem (rtx_insn *); extern enum reg_class m68k_secondary_reload_class (enum reg_class, machine_mode, rtx); extern enum reg_class m68k_preferred_reload_class (rtx, enum reg_class); -extern int flags_in_68881 (void); extern void m68k_expand_prologue (void); extern bool m68k_use_return_insn (void); extern void m68k_expand_epilogue (bool); diff --git a/gcc/config/m68k/m68k.c b/gcc/config/m68k/m68k.c index 1030dfa5957..8d010ebe6e9 100644 --- a/gcc/config/m68k/m68k.c +++ b/gcc/config/m68k/m68k.c @@ -20,6 +20,7 @@ along with GCC; see the file COPYING3. If not see #define IN_TARGET_CODE 1 #include "config.h" +#define INCLUDE_STRING #include "system.h" #include "coretypes.h" #include "backend.h" @@ -194,6 +195,7 @@ static bool m68k_hard_regno_mode_ok (unsigned int, machine_mode); static bool m68k_modes_tieable_p (machine_mode, machine_mode); static machine_mode m68k_promote_function_mode (const_tree, machine_mode, int *, const_tree, int); +static void m68k_asm_final_postscan_insn (FILE *, rtx_insn *insn, rtx [], int); /* Initialize the GCC target structure. */ @@ -355,6 +357,9 @@ static machine_mode m68k_promote_function_mode (const_tree, machine_mode, #undef TARGET_HAVE_SPECULATION_SAFE_VALUE #define TARGET_HAVE_SPECULATION_SAFE_VALUE speculation_safe_value_not_needed +#undef TARGET_ASM_FINAL_POSTSCAN_INSN +#define TARGET_ASM_FINAL_POSTSCAN_INSN m68k_asm_final_postscan_insn + static const struct attribute_spec m68k_attribute_table[] = { /* { name, min_len, max_len, decl_req, type_req, fn_type_req, @@ -1356,40 +1361,6 @@ m68k_expand_epilogue (bool sibcall_p) emit_jump_insn (ret_rtx); } -/* Return true if X is a valid comparison operator for the dbcc - instruction. - - Note it rejects floating point comparison operators. - (In the future we could use Fdbcc). - - It also rejects some comparisons when CC_NO_OVERFLOW is set. */ - -int -valid_dbcc_comparison_p_2 (rtx x, machine_mode mode ATTRIBUTE_UNUSED) -{ - switch (GET_CODE (x)) - { - case EQ: case NE: case GTU: case LTU: - case GEU: case LEU: - return 1; - - /* Reject some when CC_NO_OVERFLOW is set. This may be over - conservative */ - case GT: case LT: case GE: case LE: - return ! (cc_prev_status.flags & CC_NO_OVERFLOW); - default: - return 0; - } -} - -/* Return nonzero if flags are currently in the 68881 flag register. */ -int -flags_in_68881 (void) -{ - /* We could add support for these in the future */ - return cc_status.flags & CC_IN_68881; -} - /* Return true if PARALLEL contains register REGNO. */ static bool m68k_reg_present_p (const_rtx parallel, unsigned int regno) @@ -1580,18 +1551,186 @@ m68k_legitimize_address (rtx x, rtx oldx, machine_mode mode) return x; } + +/* For eliding comparisons, we remember how the flags were set. + FLAGS_COMPARE_OP0 and FLAGS_COMPARE_OP1 are remembered for a direct + comparison, they take priority. FLAGS_OPERAND1 and FLAGS_OPERAND2 + are used in more cases, they are a fallback for comparisons against + zero after a move or arithmetic insn. + FLAGS_VALID is set to FLAGS_VALID_NO if we should not use any of + these values. */ + +static rtx flags_compare_op0, flags_compare_op1; +static rtx flags_operand1, flags_operand2; +static attr_flags_valid flags_valid = FLAGS_VALID_NO; + +/* Return a code other than UNKNOWN if we can elide a CODE comparison of + OP0 with OP1. */ + +rtx_code +m68k_find_flags_value (rtx op0, rtx op1, rtx_code code) +{ + if (flags_compare_op0 != NULL_RTX) + { + if (rtx_equal_p (op0, flags_compare_op0) + && rtx_equal_p (op1, flags_compare_op1)) + return code; + if (rtx_equal_p (op0, flags_compare_op1) + && rtx_equal_p (op1, flags_compare_op0)) + return swap_condition (code); + return UNKNOWN; + } + + machine_mode mode = GET_MODE (op0); + if (op1 != CONST0_RTX (mode)) + return UNKNOWN; + /* Comparisons against 0 with these two should have been optimized out. */ + gcc_assert (code != LTU && code != GEU); + if (flags_valid == FLAGS_VALID_NOOV && (code == GT || code == LE)) + return UNKNOWN; + if (rtx_equal_p (flags_operand1, op0) || rtx_equal_p (flags_operand2, op0)) + return (FLOAT_MODE_P (mode) ? code + : code == GE ? PLUS : code == LT ? MINUS : code); + /* See if we are testing whether the high part of a DImode value is + positive or negative and we have the full value as a remembered + operand. */ + if (code != GE && code != LT) + return UNKNOWN; + if (mode == SImode + && flags_operand1 != NULL_RTX && GET_MODE (flags_operand1) == DImode + && REG_P (flags_operand1) && REG_P (op0) + && hard_regno_nregs (REGNO (flags_operand1), DImode) == 2 + && REGNO (flags_operand1) == REGNO (op0)) + return code == GE ? PLUS : MINUS; + if (mode == SImode + && flags_operand2 != NULL_RTX && GET_MODE (flags_operand2) == DImode + && REG_P (flags_operand2) && REG_P (op0) + && hard_regno_nregs (REGNO (flags_operand2), DImode) == 2 + && REGNO (flags_operand2) == REGNO (op0)) + return code == GE ? PLUS : MINUS; + return UNKNOWN; +} + +/* Called through CC_STATUS_INIT, which is invoked by final whenever a + label is encountered. */ + +void +m68k_init_cc () +{ + flags_compare_op0 = flags_compare_op1 = NULL_RTX; + flags_operand1 = flags_operand2 = NULL_RTX; + flags_valid = FLAGS_VALID_NO; +} + +/* Update flags for a move operation with OPERANDS. Called for move + operations where attr_flags_valid returns "set". */ + +static void +handle_flags_for_move (rtx *operands) +{ + flags_compare_op0 = flags_compare_op1 = NULL_RTX; + if (!ADDRESS_REG_P (operands[0])) + { + flags_valid = FLAGS_VALID_MOVE; + flags_operand1 = side_effects_p (operands[0]) ? NULL_RTX : operands[0]; + if (side_effects_p (operands[1]) + /* ??? For mem->mem moves, this can discard the source as a + valid compare operand. If you assume aligned moves, this + is unnecessary, but in theory, we could have an unaligned + move overwriting parts of its source. */ + || modified_in_p (operands[1], current_output_insn)) + flags_operand2 = NULL_RTX; + else + flags_operand2 = operands[1]; + return; + } + if (flags_operand1 != NULL_RTX + && modified_in_p (flags_operand1, current_output_insn)) + flags_operand1 = NULL_RTX; + if (flags_operand2 != NULL_RTX + && modified_in_p (flags_operand2, current_output_insn)) + flags_operand2 = NULL_RTX; +} + +/* Process INSN to remember flag operands if possible. */ + +static void +m68k_asm_final_postscan_insn (FILE *, rtx_insn *insn, rtx [], int) +{ + enum attr_flags_valid v = get_attr_flags_valid (insn); + if (v == FLAGS_VALID_SET) + return; + /* Comparisons use FLAGS_VALID_SET, so we can be sure we need to clear these + now. */ + flags_compare_op0 = flags_compare_op1 = NULL_RTX; + + if (v == FLAGS_VALID_NO) + { + flags_operand1 = flags_operand2 = NULL_RTX; + return; + } + else if (v == FLAGS_VALID_UNCHANGED) + { + if (flags_operand1 != NULL_RTX && modified_in_p (flags_operand1, insn)) + flags_operand1 = NULL_RTX; + if (flags_operand2 != NULL_RTX && modified_in_p (flags_operand2, insn)) + flags_operand2 = NULL_RTX; + return; + } + + flags_valid = v; + rtx set = single_set (insn); + rtx dest = SET_DEST (set); + rtx src = SET_SRC (set); + if (side_effects_p (dest)) + dest = NULL_RTX; + + switch (v) + { + case FLAGS_VALID_YES: + case FLAGS_VALID_NOOV: + flags_operand1 = dest; + flags_operand2 = NULL_RTX; + break; + case FLAGS_VALID_MOVE: + /* fmoves to memory or data registers do not set the condition + codes. Normal moves _do_ set the condition codes, but not in + a way that is appropriate for comparison with 0, because -0.0 + would be treated as a negative nonzero number. Note that it + isn't appropriate to conditionalize this restriction on + HONOR_SIGNED_ZEROS because that macro merely indicates whether + we care about the difference between -0.0 and +0.0. */ + if (dest != NULL_RTX + && !FP_REG_P (dest) + && (FP_REG_P (src) + || GET_CODE (src) == FIX + || FLOAT_MODE_P (GET_MODE (dest)))) + flags_operand1 = flags_operand2 = NULL_RTX; + else + { + flags_operand1 = dest; + if (GET_MODE (src) != VOIDmode && !side_effects_p (src) + && !modified_in_p (src, insn)) + flags_operand2 = src; + else + flags_operand2 = NULL_RTX; + } + break; + default: + gcc_unreachable (); + } + return; +} - /* Output a dbCC; jCC sequence. Note we do not handle the - floating point version of this sequence (Fdbcc). We also - do not handle alternative conditions when CC_NO_OVERFLOW is - set. It is assumed that valid_dbcc_comparison_p and flags_in_68881 will - kick those out before we get here. */ + floating point version of this sequence (Fdbcc). + OPERANDS are as in the two peepholes. CODE is the code + returned by m68k_output_branch_. */ void -output_dbcc_and_branch (rtx *operands) +output_dbcc_and_branch (rtx *operands, rtx_code code) { - switch (GET_CODE (operands[3])) + switch (code) { case EQ: output_asm_insn ("dbeq %0,%l1\n\tjeq %l2", operands); @@ -1633,6 +1772,14 @@ output_dbcc_and_branch (rtx *operands) output_asm_insn ("dbls %0,%l1\n\tjls %l2", operands); break; + case PLUS: + output_asm_insn ("dbpl %0,%l1\n\tjle %l2", operands); + break; + + case MINUS: + output_asm_insn ("dbmi %0,%l1\n\tjle %l2", operands); + break; + default: gcc_unreachable (); } @@ -1790,11 +1937,12 @@ output_scc_di (rtx op, rtx operand1, rtx operand2, rtx dest) return ""; } -const char * -output_btst (rtx *operands, rtx countop, rtx dataop, rtx_insn *insn, int signpos) +rtx_code +m68k_output_btst (rtx countop, rtx dataop, rtx_code code, int signpos) { - operands[0] = countop; - operands[1] = dataop; + rtx ops[2]; + ops[0] = countop; + ops[1] = dataop; if (GET_CODE (countop) == CONST_INT) { @@ -1805,40 +1953,41 @@ output_btst (rtx *operands, rtx countop, rtx dataop, rtx_insn *insn, int signpos { int offset = (count & ~signpos) / 8; count = count & signpos; - operands[1] = dataop = adjust_address (dataop, QImode, offset); + ops[1] = dataop = adjust_address (dataop, QImode, offset); + } + + if (code == EQ || code == NE) + { + if (count == 31) + { + output_asm_insn ("tst%.l %1", ops); + return code == EQ ? PLUS : MINUS; + } + if (count == 15) + { + output_asm_insn ("tst%.w %1", ops); + return code == EQ ? PLUS : MINUS; + } + if (count == 7) + { + output_asm_insn ("tst%.b %1", ops); + return code == EQ ? PLUS : MINUS; + } } - if (count == signpos) - cc_status.flags = CC_NOT_POSITIVE | CC_Z_IN_NOT_N; - else - cc_status.flags = CC_NOT_NEGATIVE | CC_Z_IN_NOT_N; - - /* These three statements used to use next_insns_test_no... - but it appears that this should do the same job. */ - if (count == 31 - && next_insn_tests_no_inequality (insn)) - return "tst%.l %1"; - if (count == 15 - && next_insn_tests_no_inequality (insn)) - return "tst%.w %1"; - if (count == 7 - && next_insn_tests_no_inequality (insn)) - return "tst%.b %1"; /* Try to use `movew to ccr' followed by the appropriate branch insn. On some m68k variants unfortunately that's slower than btst. On 68000 and higher, that should also work for all HImode operands. */ if (TUNE_CPU32 || TARGET_COLDFIRE || optimize_size) { - if (count == 3 && DATA_REG_P (operands[1]) - && next_insn_tests_no_inequality (insn)) + if (count == 3 && DATA_REG_P (ops[1]) && (code == EQ || code == NE)) { - cc_status.flags = CC_NOT_NEGATIVE | CC_Z_IN_NOT_N | CC_NO_OVERFLOW; - return "move%.w %1,%%ccr"; + output_asm_insn ("move%.w %1,%%ccr", ops); + return code == EQ ? PLUS : MINUS; } - if (count == 2 && DATA_REG_P (operands[1]) - && next_insn_tests_no_inequality (insn)) + if (count == 2 && DATA_REG_P (ops[1]) && (code == EQ || code == NE)) { - cc_status.flags = CC_NOT_NEGATIVE | CC_INVERTED | CC_NO_OVERFLOW; - return "move%.w %1,%%ccr"; + output_asm_insn ("move%.w %1,%%ccr", ops); + return code == EQ ? NE : EQ; } /* count == 1 followed by bvc/bvs and count == 0 followed by bcc/bcs are also possible, but need @@ -1847,7 +1996,28 @@ output_btst (rtx *operands, rtx countop, rtx dataop, rtx_insn *insn, int signpos cc_status.flags = CC_NOT_NEGATIVE; } - return "btst %0,%1"; + output_asm_insn ("btst %0,%1", ops); + return code; +} + +/* Output a bftst instruction for a zero_extract with ZXOP0, ZXOP1 and ZXOP2 + operands. CODE is the code of the comparison, and we return the code to + be actually used in the jump. */ + +rtx_code +m68k_output_bftst (rtx zxop0, rtx zxop1, rtx zxop2, rtx_code code) +{ + if (zxop1 == const1_rtx && GET_CODE (zxop2) == CONST_INT) + { + int width = GET_CODE (zxop0) == REG ? 31 : 7; + /* Pass 1000 as SIGNPOS argument so that btst will + not think we are testing the sign bit for an `and' + and assume that nonzero implies a negative result. */ + return m68k_output_btst (GEN_INT (width - INTVAL (zxop2)), zxop0, code, 1000); + } + rtx ops[3] = { zxop0, zxop1, zxop2 }; + output_asm_insn ("bftst %0{%b2:%b1}", ops); + return code; } /* Return true if X is a legitimate base register. STRICT_P says @@ -2839,7 +3009,8 @@ m68k_rtx_costs (rtx x, machine_mode mode, int outer_code, case CONST_DOUBLE: /* Make 0.0 cheaper than other floating constants to encourage creating tstsf and tstdf insns. */ - if (outer_code == COMPARE + if ((GET_RTX_CLASS (outer_code) == RTX_COMPARE + || GET_RTX_CLASS (outer_code) == RTX_COMM_COMPARE) && (x == CONST0_RTX (SFmode) || x == CONST0_RTX (DFmode))) *total = 4; else @@ -2953,7 +3124,8 @@ m68k_rtx_costs (rtx x, machine_mode mode, int outer_code, return true; case ZERO_EXTRACT: - if (outer_code == COMPARE) + if (GET_RTX_CLASS (outer_code) == RTX_COMPARE + || GET_RTX_CLASS (outer_code) == RTX_COMM_COMPARE) *total = 0; return false; @@ -3056,6 +3228,8 @@ output_move_simode_const (rtx *operands) const char * output_move_simode (rtx *operands) { + handle_flags_for_move (operands); + if (GET_CODE (operands[1]) == CONST_INT) return output_move_simode_const (operands); else if ((GET_CODE (operands[1]) == SYMBOL_REF @@ -3072,7 +3246,7 @@ output_move_simode (rtx *operands) const char * output_move_himode (rtx *operands) { - if (GET_CODE (operands[1]) == CONST_INT) + if (GET_CODE (operands[1]) == CONST_INT) { if (operands[1] == const0_rtx && (DATA_REG_P (operands[0]) @@ -3094,16 +3268,18 @@ output_move_himode (rtx *operands) return "move%.w %1,%0"; } else if (CONSTANT_P (operands[1])) - return "move%.l %1,%0"; + gcc_unreachable (); return "move%.w %1,%0"; } const char * output_move_qimode (rtx *operands) { + handle_flags_for_move (operands); + /* 68k family always modifies the stack pointer by at least 2, even for byte pushes. The 5200 (ColdFire) does not do this. */ - + /* This case is generated by pushqi1 pattern now. */ gcc_assert (!(GET_CODE (operands[0]) == MEM && GET_CODE (XEXP (operands[0], 0)) == PRE_DEC @@ -3134,11 +3310,15 @@ output_move_qimode (rtx *operands) if (operands[1] == const0_rtx && ADDRESS_REG_P (operands[0])) return "sub%.l %0,%0"; if (GET_CODE (operands[1]) != CONST_INT && CONSTANT_P (operands[1])) - return "move%.l %1,%0"; + gcc_unreachable (); /* 68k family (including the 5200 ColdFire) does not support byte moves to from address registers. */ if (ADDRESS_REG_P (operands[0]) || ADDRESS_REG_P (operands[1])) - return "move%.w %1,%0"; + { + if (ADDRESS_REG_P (operands[1])) + CC_STATUS_INIT; + return "move%.w %1,%0"; + } return "move%.b %1,%0"; } @@ -4136,125 +4316,440 @@ output_addsi3 (rtx *operands) } return "add%.l %2,%0"; } - -/* Store in cc_status the expressions that the condition codes will - describe after execution of an instruction whose pattern is EXP. - Do not alter them if the instruction would not alter the cc's. */ - -/* On the 68000, all the insns to store in an address register fail to - set the cc's. However, in some cases these instructions can make it - possibly invalid to use the saved cc's. In those cases we clear out - some or all of the saved cc's so they won't be used. */ -void -notice_update_cc (rtx exp, rtx insn) +/* Emit a comparison between OP0 and OP1. Return true iff the comparison + was reversed. SC1 is an SImode scratch reg, and SC2 a DImode scratch reg, + as needed. CODE is the code of the comparison, we return it unchanged or + swapped, as necessary. */ +rtx_code +m68k_output_compare_di (rtx op0, rtx op1, rtx sc1, rtx sc2, rtx_insn *insn, + rtx_code code) { - if (GET_CODE (exp) == SET) + rtx ops[4]; + ops[0] = op0; + ops[1] = op1; + ops[2] = sc1; + ops[3] = sc2; + if (op1 == const0_rtx) { - if (GET_CODE (SET_SRC (exp)) == CALL) - CC_STATUS_INIT; - else if (ADDRESS_REG_P (SET_DEST (exp))) + if (!REG_P (op0) || ADDRESS_REG_P (op0)) { - if (cc_status.value1 && modified_in_p (cc_status.value1, insn)) - cc_status.value1 = 0; - if (cc_status.value2 && modified_in_p (cc_status.value2, insn)) - cc_status.value2 = 0; + rtx xoperands[2]; + + xoperands[0] = sc2; + xoperands[1] = op0; + output_move_double (xoperands); + output_asm_insn ("neg%.l %R0\n\tnegx%.l %0", xoperands); + return swap_condition (code); } - /* fmoves to memory or data registers do not set the condition - codes. Normal moves _do_ set the condition codes, but not in - a way that is appropriate for comparison with 0, because -0.0 - would be treated as a negative nonzero number. Note that it - isn't appropriate to conditionalize this restriction on - HONOR_SIGNED_ZEROS because that macro merely indicates whether - we care about the difference between -0.0 and +0.0. */ - else if (!FP_REG_P (SET_DEST (exp)) - && SET_DEST (exp) != cc0_rtx - && (FP_REG_P (SET_SRC (exp)) - || GET_CODE (SET_SRC (exp)) == FIX - || FLOAT_MODE_P (GET_MODE (SET_DEST (exp))))) - CC_STATUS_INIT; - /* A pair of move insns doesn't produce a useful overall cc. */ - else if (!FP_REG_P (SET_DEST (exp)) - && !FP_REG_P (SET_SRC (exp)) - && GET_MODE_SIZE (GET_MODE (SET_SRC (exp))) > 4 - && (GET_CODE (SET_SRC (exp)) == REG - || GET_CODE (SET_SRC (exp)) == MEM - || GET_CODE (SET_SRC (exp)) == CONST_DOUBLE)) - CC_STATUS_INIT; - else if (SET_DEST (exp) != pc_rtx) + if (find_reg_note (insn, REG_DEAD, op0)) { - cc_status.flags = 0; - cc_status.value1 = SET_DEST (exp); - cc_status.value2 = SET_SRC (exp); + output_asm_insn ("neg%.l %R0\n\tnegx%.l %0", ops); + return swap_condition (code); } - } - else if (GET_CODE (exp) == PARALLEL - && GET_CODE (XVECEXP (exp, 0, 0)) == SET) - { - rtx dest = SET_DEST (XVECEXP (exp, 0, 0)); - rtx src = SET_SRC (XVECEXP (exp, 0, 0)); - - if (ADDRESS_REG_P (dest)) - CC_STATUS_INIT; - else if (dest != pc_rtx) + else { - cc_status.flags = 0; - cc_status.value1 = dest; - cc_status.value2 = src; + /* 'sub' clears %1, and also clears the X cc bit. + 'tst' sets the Z cc bit according to the low part of the DImode + operand. + 'subx %1' (i.e. subx #0) acts as a (non-existent) tstx on the high + part. */ + output_asm_insn ("sub%.l %2,%2\n\ttst%.l %R0\n\tsubx%.l %2,%0", ops); + return code; } } + + if (rtx_equal_p (sc2, op0)) + { + output_asm_insn ("sub%.l %R1,%R3\n\tsubx%.l %1,%3", ops); + return code; + } else + { + output_asm_insn ("sub%.l %R0,%R3\n\tsubx%.l %0,%3", ops); + return swap_condition (code); + } +} + +static void +remember_compare_flags (rtx op0, rtx op1) +{ + if (side_effects_p (op0) || side_effects_p (op1)) CC_STATUS_INIT; - if (cc_status.value2 != 0 - && ADDRESS_REG_P (cc_status.value2) - && GET_MODE (cc_status.value2) == QImode) - CC_STATUS_INIT; - if (cc_status.value2 != 0) - switch (GET_CODE (cc_status.value2)) - { - case ASHIFT: case ASHIFTRT: case LSHIFTRT: - case ROTATE: case ROTATERT: - /* These instructions always clear the overflow bit, and set - the carry to the bit shifted out. */ - cc_status.flags |= CC_OVERFLOW_UNUSABLE | CC_NO_CARRY; - break; + else + { + flags_compare_op0 = op0; + flags_compare_op1 = op1; + flags_operand1 = flags_operand2 = NULL_RTX; + flags_valid = FLAGS_VALID_SET; + } +} - case PLUS: case MINUS: case MULT: - case DIV: case UDIV: case MOD: case UMOD: case NEG: - if (GET_MODE (cc_status.value2) != VOIDmode) - cc_status.flags |= CC_NO_OVERFLOW; - break; - case ZERO_EXTEND: - /* (SET r1 (ZERO_EXTEND r2)) on this machine - ends with a move insn moving r2 in r2's mode. - Thus, the cc's are set for r2. - This can set N bit spuriously. */ - cc_status.flags |= CC_NOT_NEGATIVE; +/* Emit a comparison between OP0 and OP1. CODE is the code of the + comparison. It is returned, potentially modified if necessary. */ +rtx_code +m68k_output_compare_si (rtx op0, rtx op1, rtx_code code) +{ + rtx_code tmp = m68k_find_flags_value (op0, op1, code); + if (tmp != UNKNOWN) + return tmp; - default: - break; - } - if (cc_status.value1 && GET_CODE (cc_status.value1) == REG - && cc_status.value2 - && reg_overlap_mentioned_p (cc_status.value1, cc_status.value2)) - cc_status.value2 = 0; - /* Check for PRE_DEC in dest modifying a register used in src. */ - if (cc_status.value1 && GET_CODE (cc_status.value1) == MEM - && GET_CODE (XEXP (cc_status.value1, 0)) == PRE_DEC - && cc_status.value2 - && reg_overlap_mentioned_p (XEXP (XEXP (cc_status.value1, 0), 0), - cc_status.value2)) - cc_status.value2 = 0; - if (((cc_status.value1 && FP_REG_P (cc_status.value1)) - || (cc_status.value2 && FP_REG_P (cc_status.value2)))) - cc_status.flags = CC_IN_68881; - if (cc_status.value2 && GET_CODE (cc_status.value2) == COMPARE - && GET_MODE_CLASS (GET_MODE (XEXP (cc_status.value2, 0))) == MODE_FLOAT) - { - cc_status.flags = CC_IN_68881; - if (!FP_REG_P (XEXP (cc_status.value2, 0)) - && FP_REG_P (XEXP (cc_status.value2, 1))) - cc_status.flags |= CC_REVERSED; + remember_compare_flags (op0, op1); + + rtx ops[2]; + ops[0] = op0; + ops[1] = op1; + if (op1 == const0_rtx && (TARGET_68020 || TARGET_COLDFIRE || !ADDRESS_REG_P (op0))) + output_asm_insn ("tst%.l %0", ops); + else if (GET_CODE (op0) == MEM && GET_CODE (op1) == MEM) + output_asm_insn ("cmpm%.l %1,%0", ops); + else if (REG_P (op1) + || (!REG_P (op0) && GET_CODE (op0) != MEM)) + { + output_asm_insn ("cmp%.l %d0,%d1", ops); + std::swap (flags_compare_op0, flags_compare_op1); + return swap_condition (code); + } + else if (!TARGET_COLDFIRE + && ADDRESS_REG_P (op0) + && GET_CODE (op1) == CONST_INT + && INTVAL (op1) < 0x8000 + && INTVAL (op1) >= -0x8000) + output_asm_insn ("cmp%.w %1,%0", ops); + else + output_asm_insn ("cmp%.l %d1,%d0", ops); + return code; +} + +/* Emit a comparison between OP0 and OP1. CODE is the code of the + comparison. It is returned, potentially modified if necessary. */ +rtx_code +m68k_output_compare_hi (rtx op0, rtx op1, rtx_code code) +{ + rtx_code tmp = m68k_find_flags_value (op0, op1, code); + if (tmp != UNKNOWN) + return tmp; + + remember_compare_flags (op0, op1); + + rtx ops[2]; + ops[0] = op0; + ops[1] = op1; + if (op1 == const0_rtx) + output_asm_insn ("tst%.w %d0", ops); + else if (GET_CODE (op0) == MEM && GET_CODE (op1) == MEM) + output_asm_insn ("cmpm%.w %1,%0", ops); + else if ((REG_P (op1) && !ADDRESS_REG_P (op1)) + || (!REG_P (op0) && GET_CODE (op0) != MEM)) + { + output_asm_insn ("cmp%.w %d0,%d1", ops); + std::swap (flags_compare_op0, flags_compare_op1); + return swap_condition (code); + } + else + output_asm_insn ("cmp%.w %d1,%d0", ops); + return code; +} + +/* Emit a comparison between OP0 and OP1. CODE is the code of the + comparison. It is returned, potentially modified if necessary. */ +rtx_code +m68k_output_compare_qi (rtx op0, rtx op1, rtx_code code) +{ + rtx_code tmp = m68k_find_flags_value (op0, op1, code); + if (tmp != UNKNOWN) + return tmp; + + remember_compare_flags (op0, op1); + + rtx ops[2]; + ops[0] = op0; + ops[1] = op1; + if (op1 == const0_rtx) + output_asm_insn ("tst%.b %d0", ops); + else if (GET_CODE (op0) == MEM && GET_CODE (op1) == MEM) + output_asm_insn ("cmpm%.b %1,%0", ops); + else if (REG_P (op1) || (!REG_P (op0) && GET_CODE (op0) != MEM)) + { + output_asm_insn ("cmp%.b %d0,%d1", ops); + std::swap (flags_compare_op0, flags_compare_op1); + return swap_condition (code); + } + else + output_asm_insn ("cmp%.b %d1,%d0", ops); + return code; +} + +/* Emit a comparison between OP0 and OP1. CODE is the code of the + comparison. It is returned, potentially modified if necessary. */ +rtx_code +m68k_output_compare_fp (rtx op0, rtx op1, rtx_code code) +{ + rtx_code tmp = m68k_find_flags_value (op0, op1, code); + if (tmp != UNKNOWN) + return tmp; + + rtx ops[2]; + ops[0] = op0; + ops[1] = op1; + + remember_compare_flags (op0, op1); + + machine_mode mode = GET_MODE (op0); + std::string prec = mode == SFmode ? "s" : mode == DFmode ? "d" : "x"; + + if (op1 == CONST0_RTX (GET_MODE (op0))) + { + if (FP_REG_P (op0)) + output_asm_insn ("ftst%.x %0", ops); + else + output_asm_insn (("ftst%." + prec + " %0").c_str (), ops); + return code; + } + + switch (which_alternative) + { + case 0: + output_asm_insn ("fcmp%.x %1,%0", ops); + break; + case 1: + output_asm_insn (("fcmp%." + prec + " %f1,%0").c_str (), ops); + break; + case 2: + output_asm_insn (("fcmp%." + prec + " %0,%f1").c_str (), ops); + std::swap (flags_compare_op0, flags_compare_op1); + return swap_condition (code); + case 3: + /* This is the ftst case, handled earlier. */ + gcc_unreachable (); + } + return code; +} + +/* Return an output template for a branch with CODE. */ +const char * +m68k_output_branch_integer (rtx_code code) +{ + switch (code) + { + case EQ: + return "jeq %l3"; + case NE: + return "jne %l3"; + case GT: + return "jgt %l3"; + case GTU: + return "jhi %l3"; + case LT: + return "jlt %l3"; + case LTU: + return "jcs %l3"; + case GE: + return "jge %l3"; + case GEU: + return "jcc %l3"; + case LE: + return "jle %l3"; + case LEU: + return "jls %l3"; + case PLUS: + return "jpl %l3"; + case MINUS: + return "jmi %l3"; + default: + gcc_unreachable (); + } +} + +/* Return an output template for a reversed branch with CODE. */ +const char * +m68k_output_branch_integer_rev (rtx_code code) +{ + switch (code) + { + case EQ: + return "jne %l3"; + case NE: + return "jeq %l3"; + case GT: + return "jle %l3"; + case GTU: + return "jls %l3"; + case LT: + return "jge %l3"; + case LTU: + return "jcc %l3"; + case GE: + return "jlt %l3"; + case GEU: + return "jcs %l3"; + case LE: + return "jgt %l3"; + case LEU: + return "jhi %l3"; + case PLUS: + return "jmi %l3"; + case MINUS: + return "jpl %l3"; + default: + gcc_unreachable (); + } +} + +/* Return an output template for a scc instruction with CODE. */ +const char * +m68k_output_scc (rtx_code code) +{ + switch (code) + { + case EQ: + return "seq %0"; + case NE: + return "sne %0"; + case GT: + return "sgt %0"; + case GTU: + return "shi %0"; + case LT: + return "slt %0"; + case LTU: + return "scs %0"; + case GE: + return "sge %0"; + case GEU: + return "scc %0"; + case LE: + return "sle %0"; + case LEU: + return "sls %0"; + case PLUS: + return "spl %0"; + case MINUS: + return "smi %0"; + default: + gcc_unreachable (); + } +} + +/* Return an output template for a floating point branch + instruction with CODE. */ +const char * +m68k_output_branch_float (rtx_code code) +{ + switch (code) + { + case EQ: + return "fjeq %l3"; + case NE: + return "fjne %l3"; + case GT: + return "fjgt %l3"; + case LT: + return "fjlt %l3"; + case GE: + return "fjge %l3"; + case LE: + return "fjle %l3"; + case ORDERED: + return "fjor %l3"; + case UNORDERED: + return "fjun %l3"; + case UNEQ: + return "fjueq %l3"; + case UNGE: + return "fjuge %l3"; + case UNGT: + return "fjugt %l3"; + case UNLE: + return "fjule %l3"; + case UNLT: + return "fjult %l3"; + case LTGT: + return "fjogl %l3"; + default: + gcc_unreachable (); + } +} + +/* Return an output template for a reversed floating point branch + instruction with CODE. */ +const char * +m68k_output_branch_float_rev (rtx_code code) +{ + switch (code) + { + case EQ: + return "fjne %l3"; + case NE: + return "fjeq %l3"; + case GT: + return "fjngt %l3"; + case LT: + return "fjnlt %l3"; + case GE: + return "fjnge %l3"; + case LE: + return "fjnle %l3"; + case ORDERED: + return "fjun %l3"; + case UNORDERED: + return "fjor %l3"; + case UNEQ: + return "fjogl %l3"; + case UNGE: + return "fjolt %l3"; + case UNGT: + return "fjole %l3"; + case UNLE: + return "fjogt %l3"; + case UNLT: + return "fjoge %l3"; + case LTGT: + return "fjueq %l3"; + default: + gcc_unreachable (); + } +} + +/* Return an output template for a floating point scc + instruction with CODE. */ +const char * +m68k_output_scc_float (rtx_code code) +{ + switch (code) + { + case EQ: + return "fseq %0"; + case NE: + return "fsne %0"; + case GT: + return "fsgt %0"; + case GTU: + return "fshi %0"; + case LT: + return "fslt %0"; + case GE: + return "fsge %0"; + case LE: + return "fsle %0"; + case ORDERED: + return "fsor %0"; + case UNORDERED: + return "fsun %0"; + case UNEQ: + return "fsueq %0"; + case UNGE: + return "fsuge %0"; + case UNGT: + return "fsugt %0"; + case UNLE: + return "fsule %0"; + case UNLT: + return "fsult %0"; + case LTGT: + return "fsogl %0"; + default: + gcc_unreachable (); } } @@ -4932,6 +5427,7 @@ const char * output_andsi3 (rtx *operands) { int logval; + CC_STATUS_INIT; if (GET_CODE (operands[2]) == CONST_INT && (INTVAL (operands[2]) | 0xffff) == -1 && (DATA_REG_P (operands[0]) @@ -4941,8 +5437,6 @@ output_andsi3 (rtx *operands) if (GET_CODE (operands[0]) != REG) operands[0] = adjust_address (operands[0], HImode, 2); operands[2] = GEN_INT (INTVAL (operands[2]) & 0xffff); - /* Do not delete a following tstl %0 insn; that would be incorrect. */ - CC_STATUS_INIT; if (operands[2] == const0_rtx) return "clr%.w %0"; return "and%.w %2,%0"; @@ -4959,10 +5453,13 @@ output_andsi3 (rtx *operands) operands[0] = adjust_address (operands[0], SImode, 3 - (logval / 8)); operands[1] = GEN_INT (logval % 8); } - /* This does not set condition codes in a standard way. */ - CC_STATUS_INIT; return "bclr %1,%0"; } + /* Only a standard logical operation on the whole word sets the + condition codes in a way we can use. */ + if (!side_effects_p (operands[0])) + flags_operand1 = operands[0]; + flags_valid = FLAGS_VALID_YES; return "and%.l %2,%0"; } @@ -4970,6 +5467,7 @@ const char * output_iorsi3 (rtx *operands) { register int logval; + CC_STATUS_INIT; if (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) >> 16 == 0 && (DATA_REG_P (operands[0]) @@ -4978,8 +5476,6 @@ output_iorsi3 (rtx *operands) { if (GET_CODE (operands[0]) != REG) operands[0] = adjust_address (operands[0], HImode, 2); - /* Do not delete a following tstl %0 insn; that would be incorrect. */ - CC_STATUS_INIT; if (INTVAL (operands[2]) == 0xffff) return "mov%.w %2,%0"; return "or%.w %2,%0"; @@ -4996,9 +5492,13 @@ output_iorsi3 (rtx *operands) operands[0] = adjust_address (operands[0], SImode, 3 - (logval / 8)); operands[1] = GEN_INT (logval % 8); } - CC_STATUS_INIT; return "bset %1,%0"; } + /* Only a standard logical operation on the whole word sets the + condition codes in a way we can use. */ + if (!side_effects_p (operands[0])) + flags_operand1 = operands[0]; + flags_valid = FLAGS_VALID_YES; return "or%.l %2,%0"; } @@ -5006,6 +5506,7 @@ const char * output_xorsi3 (rtx *operands) { register int logval; + CC_STATUS_INIT; if (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) >> 16 == 0 && (offsettable_memref_p (operands[0]) || DATA_REG_P (operands[0])) @@ -5013,8 +5514,6 @@ output_xorsi3 (rtx *operands) { if (! DATA_REG_P (operands[0])) operands[0] = adjust_address (operands[0], HImode, 2); - /* Do not delete a following tstl %0 insn; that would be incorrect. */ - CC_STATUS_INIT; if (INTVAL (operands[2]) == 0xffff) return "not%.w %0"; return "eor%.w %2,%0"; @@ -5031,9 +5530,13 @@ output_xorsi3 (rtx *operands) operands[0] = adjust_address (operands[0], SImode, 3 - (logval / 8)); operands[1] = GEN_INT (logval % 8); } - CC_STATUS_INIT; return "bchg %1,%0"; } + /* Only a standard logical operation on the whole word sets the + condition codes in a way we can use. */ + if (!side_effects_p (operands[0])) + flags_operand1 = operands[0]; + flags_valid = FLAGS_VALID_YES; return "eor%.l %2,%0"; } diff --git a/gcc/config/m68k/m68k.h b/gcc/config/m68k/m68k.h index fc65e524b13..39955b05f1d 100644 --- a/gcc/config/m68k/m68k.h +++ b/gcc/config/m68k/m68k.h @@ -670,36 +670,6 @@ __transfer_from_trampoline () \ #define Pmode SImode #define FUNCTION_MODE QImode - -/* Tell final.c how to eliminate redundant test instructions. */ - -/* Here we define machine-dependent flags and fields in cc_status - (see `conditions.h'). */ - -/* Set if the cc value is actually in the 68881, so a floating point - conditional branch must be output. */ -#define CC_IN_68881 04000 - -/* On the 68000, all the insns to store in an address register fail to - set the cc's. However, in some cases these instructions can make it - possibly invalid to use the saved cc's. In those cases we clear out - some or all of the saved cc's so they won't be used. */ -#define NOTICE_UPDATE_CC(EXP,INSN) notice_update_cc (EXP, INSN) - -/* The shift instructions always clear the overflow bit. */ -#define CC_OVERFLOW_UNUSABLE 01000 - -/* The shift instructions use the carry bit in a way not compatible with - conditional branches. conditions.h uses CC_NO_OVERFLOW for this purpose. - Rename it to something more understandable. */ -#define CC_NO_CARRY CC_NO_OVERFLOW - -#define OUTPUT_JUMP(NORMAL, FLOAT, NO_OV) \ -do { if (cc_prev_status.flags & CC_IN_68881) \ - return FLOAT; \ - if (cc_prev_status.flags & CC_NO_OVERFLOW) \ - return NO_OV; \ - return NORMAL; } while (0) /* Control the assembler format that we output. */ @@ -900,6 +870,8 @@ do { if (cc_prev_status.flags & CC_IN_68881) \ #define PRINT_OPERAND_ADDRESS(FILE, ADDR) print_operand_address (FILE, ADDR) +#define CC_STATUS_INIT m68k_init_cc () + #include "config/m68k/m68k-opts.h" enum fpu_type diff --git a/gcc/config/m68k/m68k.md b/gcc/config/m68k/m68k.md index 31e8767e7e3..25e0b73741f 100644 --- a/gcc/config/m68k/m68k.md +++ b/gcc/config/m68k/m68k.md @@ -250,6 +250,18 @@ ;; Alternative is OK for ColdFire. (define_attr "ok_for_coldfire" "yes,no" (const_string "yes")) +;; Instruction sets flags predictably to allow a following comparison to be +;; elided. +;; "no" means we should clear all flag state. "yes" means the destination +;; register is valid. "noov" is similar but does not allow tests that rely +;; on the overflow flag. "unchanged" means the instruction does not set the +;; flags (but we should still verify none of the remembered operands are +;; clobbered). "move" is a special case for which we remember both the +;; destination and the source. "set" is another special case where the +;; instruction pattern already performs the update and no more work is +;; required in postscan_insn. +(define_attr "flags_valid" "no,yes,set,noov,move,unchanged" (const_string "no")) + ;; Define 'enabled' attribute. (define_attr "enabled" "" (cond [(and (match_test "TARGET_COLDFIRE") @@ -303,150 +315,129 @@ DONE; }) -;; We don't want to allow a constant operand for test insns because -;; (set (cc0) (const_int foo)) has no mode information. Such insns will -;; be folded while optimizing anyway. - -(define_insn "tstdi" - [(set (cc0) - (compare (match_operand:DI 0 "nonimmediate_operand" "am,d") - (const_int 0))) - (clobber (match_scratch:SI 1 "=X,d")) - (clobber (match_scratch:DI 2 "=d,X"))] +;; Compare instructions, combined with jumps or scc operations. + +(define_insn "beq0_di" + [(set (pc) + (if_then_else (eq (match_operand:DI 0 "general_operand" "d*a,o,<>") + (const_int 0)) + (label_ref (match_operand 1 "" ",,")) + (pc))) + (clobber (match_scratch:SI 2 "=d,&d,d"))] "" { - if (which_alternative == 0) - { - rtx xoperands[2]; - - xoperands[0] = operands[2]; - xoperands[1] = operands[0]; - output_move_double (xoperands); - cc_status.flags |= CC_REVERSED; /*|*/ - return "neg%.l %R2\;negx%.l %2"; - } - if (find_reg_note (insn, REG_DEAD, operands[0])) + rtx_code code = m68k_find_flags_value (operands[0], const0_rtx, EQ); + if (code == EQ) + return "jeq %l1"; + if (which_alternative == 2) + return "move%.l %0,%2\;or%.l %0,%2\;jeq %l1"; + if (GET_CODE (operands[0]) == REG) + operands[3] = gen_rtx_REG (SImode, REGNO (operands[0]) + 1); + else + operands[3] = adjust_address (operands[0], SImode, 4); + if (! ADDRESS_REG_P (operands[0])) { - cc_status.flags |= CC_REVERSED; /*|*/ - return "neg%.l %R0\;negx%.l %0"; + if (reg_overlap_mentioned_p (operands[2], operands[0])) + { + if (reg_overlap_mentioned_p (operands[2], operands[3])) + return "or%.l %0,%2\;jeq %l1"; + else + return "or%.l %3,%2\;jeq %l1"; + } + return "move%.l %0,%2\;or%.l %3,%2\;jeq %l1"; } + operands[4] = gen_label_rtx(); + if (TARGET_68020 || TARGET_COLDFIRE) + output_asm_insn ("tst%.l %0\;jne %l4\;tst%.l %3\;jeq %l1", operands); else - /* - 'sub' clears %1, and also clears the X cc bit - 'tst' sets the Z cc bit according to the low part of the DImode operand - 'subx %1' (i.e. subx #0) acts as a (non-existent) tstx on the high part. - */ - return "sub%.l %1,%1\;tst%.l %R0\;subx%.l %1,%0"; -}) - -;; If you think that the 68020 does not support tstl a0, -;; reread page B-167 of the 68020 manual more carefully. -(define_insn "*tstsi_internal_68020_cf" - [(set (cc0) - (compare (match_operand:SI 0 "nonimmediate_operand" "rm") - (const_int 0)))] - "TARGET_68020 || TARGET_COLDFIRE" - "tst%.l %0" - [(set_attr "type" "tst_l")]) - -;; On an address reg, cmpw may replace cmpl. -(define_insn "*tstsi_internal" - [(set (cc0) - (compare (match_operand:SI 0 "nonimmediate_operand" "dm,r") - (const_int 0)))] - "!(TARGET_68020 || TARGET_COLDFIRE)" - "@ - tst%.l %0 - cmp%.w #0,%0" - [(set_attr "type" "tst_l,cmp")]) - -;; This can't use an address register, because comparisons -;; with address registers as second operand always test the whole word. -(define_insn "*tsthi_internal" - [(set (cc0) - (compare (match_operand:HI 0 "nonimmediate_operand" "dm") - (const_int 0)))] - "" - "tst%.w %0" - [(set_attr "type" "tst")]) - -(define_insn "*tstqi_internal" - [(set (cc0) - (compare (match_operand:QI 0 "nonimmediate_operand" "dm") - (const_int 0)))] - "" - "tst%.b %0" - [(set_attr "type" "tst")]) - -(define_insn "tst_68881" - [(set (cc0) - (compare (match_operand:FP 0 "general_operand" "fm") - (match_operand:FP 1 "const0_operand" "H")))] - "TARGET_68881" -{ - cc_status.flags = CC_IN_68881; - if (FP_REG_P (operands[0])) - return "ftst%.x %0"; - return "ftst%. %0"; -} - [(set_attr "type" "ftst")]) - -(define_insn "tst_cf" - [(set (cc0) - (compare (match_operand:FP 0 "general_operand" "fU") - (match_operand:FP 1 "const0_operand" "H")))] - "TARGET_COLDFIRE_FPU" -{ - cc_status.flags = CC_IN_68881; - if (FP_REG_P (operands[0])) - return "ftst%.d %0"; - return "ftst%. %0"; -} - [(set_attr "type" "ftst")]) - - -;; compare instructions. + output_asm_insn ("cmp%.w #0,%0\;jne %l4\;cmp%.w #0,%3\;jeq %l1", operands); + (*targetm.asm_out.internal_label) (asm_out_file, "L", + CODE_LABEL_NUMBER (operands[4])); + return ""; +}) -(define_insn "*cmpdi_internal" - [(set (cc0) - (compare (match_operand:DI 1 "nonimmediate_operand" "0,d") - (match_operand:DI 2 "general_operand" "d,0"))) - (clobber (match_scratch:DI 0 "=d,d"))] +(define_insn "bne0_di" + [(set (pc) + (if_then_else (ne (match_operand:DI 0 "general_operand" "d,o,*a") + (const_int 0)) + (label_ref (match_operand 1 "" ",,")) + (pc))) + (clobber (match_scratch:SI 2 "=d,&d,X"))] "" { - if (rtx_equal_p (operands[0], operands[1])) - return "sub%.l %R2,%R0\;subx%.l %2,%0"; + rtx_code code = m68k_find_flags_value (operands[0], const0_rtx, NE); + if (code == NE) + return "jne %l1"; + if (GET_CODE (operands[0]) == REG) + operands[3] = gen_rtx_REG (SImode, REGNO (operands[0]) + 1); else + operands[3] = adjust_address (operands[0], SImode, 4); + if (!ADDRESS_REG_P (operands[0])) { - cc_status.flags |= CC_REVERSED; /*|*/ - return "sub%.l %R1,%R0\;subx%.l %1,%0"; + if (reg_overlap_mentioned_p (operands[2], operands[0])) + { + if (reg_overlap_mentioned_p (operands[2], operands[3])) + return "or%.l %0,%2\;jne %l1"; + else + return "or%.l %3,%2\;jne %l1"; + } + return "move%.l %0,%2\;or%.l %3,%2\;jne %l1"; } + if (TARGET_68020 || TARGET_COLDFIRE) + return "tst%.l %0\;jne %l1\;tst%.l %3\;jne %l1"; + else + return "cmp%.w #0,%0\;jne %l1\;cmp%.w #0,%3\;jne %l1"; }) -(define_insn "cmpdi" - [(set (cc0) - (compare (match_operand:DI 0 "nonimmediate_operand") - (match_operand:DI 1 "general_operand"))) - (clobber (match_scratch:DI 2))] +(define_insn "cbranchdi4_insn" + [(set (pc) + (if_then_else (match_operator 1 "ordered_comparison_operator" + [(match_operand:DI 2 "nonimmediate_operand" "0,d,am,d") + (match_operand:DI 3 "general_operand" "d,0,C0,C0")]) + (label_ref (match_operand 4 "")) + (pc))) + (clobber (match_scratch:DI 0 "=d,d,d,X")) + (clobber (match_scratch:SI 5 "=X,X,X,d"))] "" - "") - +{ + rtx_code code = GET_CODE (operands[1]); + code = m68k_output_compare_di (operands[2], operands[3], operands[5], operands[0], insn, code); + operands[3] = operands[4]; + return m68k_output_branch_integer (code); +}) (define_expand "cbranchdi4" - [(set (pc) - (if_then_else (match_operator 0 "ordered_comparison_operator" - [(match_operand:DI 1 "nonimmediate_operand") - (match_operand:DI 2 "general_operand")]) - (label_ref (match_operand 3 "")) - (pc)))] + [(parallel + [(set (pc) + (if_then_else (match_operator 0 "ordered_comparison_operator" + [(match_operand:DI 1 "nonimmediate_operand") + (match_operand:DI 2 "general_operand")]) + (label_ref (match_operand 3 "")) + (pc))) + (clobber (match_scratch:DI 4 "")) + (clobber (match_scratch:SI 5 ""))])] "" { - if (operands[2] == const0_rtx) - emit_insn (gen_tstdi (operands[1])); - else - emit_insn (gen_cmpdi (operands[1], operands[2])); - operands[1] = cc0_rtx; - operands[2] = const0_rtx; + rtx_code code = GET_CODE (operands[0]); + if ((code == GE || code == LT) && operands[2] == const0_rtx) + { + rtx xop1 = operand_subword_force (operands[1], 0, DImode); + rtx xop2 = operand_subword_force (operands[2], 0, DImode); + /* gen_cbranchsi4 won't use anything from operands[0] other than the + code. */ + emit_jump_insn (gen_cbranchsi4 (operands[0], xop1, xop2, operands[3])); + DONE; + } + if (code == EQ && operands[2] == const0_rtx) + { + emit_jump_insn (gen_beq0_di (operands[1], operands[3])); + DONE; + } + if (code == NE && operands[2] == const0_rtx) + { + emit_jump_insn (gen_bne0_di (operands[1], operands[3])); + DONE; + } }) (define_expand "cstoredi4" @@ -456,40 +447,38 @@ (match_operand:DI 3 "general_operand")]))] "" { - if (operands[3] == const0_rtx) - emit_insn (gen_tstdi (operands[2])); - else - emit_insn (gen_cmpdi (operands[2], operands[3])); - operands[2] = cc0_rtx; - operands[3] = const0_rtx; + rtx_code code = GET_CODE (operands[1]); + if ((code == GE || code == LT) && operands[3] == const0_rtx) + { + rtx xop2 = operand_subword_force (operands[2], 0, DImode); + rtx xop3 = operand_subword_force (operands[3], 0, DImode); + /* gen_cstoresi4 won't use anything from operands[1] other than the + code. */ + emit_jump_insn (gen_cstoresi4 (operands[0], operands[1], xop2, xop3)); + DONE; + } }) +(define_mode_iterator CMPMODE [QI HI SI]) -(define_expand "cbranchsi4" - [(set (cc0) - (compare (match_operand:SI 1 "nonimmediate_operand" "") - (match_operand:SI 2 "general_operand" ""))) - (set (pc) +(define_expand "cbranch4" + [(set (pc) (if_then_else (match_operator 0 "ordered_comparison_operator" - [(cc0) (const_int 0)]) + [(match_operand:CMPMODE 1 "nonimmediate_operand" "") + (match_operand:CMPMODE 2 "m68k_comparison_operand" "")]) (label_ref (match_operand 3 "")) (pc)))] "" "") -(define_expand "cstoresi4" - [(set (cc0) - (compare (match_operand:SI 2 "nonimmediate_operand" "") - (match_operand:SI 3 "general_operand" ""))) - (set (match_operand:QI 0 "register_operand") +(define_expand "cstore4" + [(set (match_operand:QI 0 "register_operand") (match_operator:QI 1 "ordered_comparison_operator" - [(cc0) (const_int 0)]))] + [(match_operand:CMPMODE 2 "nonimmediate_operand" "") + (match_operand:CMPMODE 3 "m68k_comparison_operand" "")]))] "" "") - -;; A composite of the cmp, cmpa, cmpi & cmpm m68000 op codes. -;; ;; In theory we ought to be able to use some 'S' constraints and ;; operand predicates that allow PC-rel addressing modes in the ;; comparison patterns and expanders below. But we would have to be @@ -497,315 +486,357 @@ ;; both operands and determining whether or not we emit the operands in ;; order or reversed is not trivial to do just based on the constraints ;; and operand predicates. So to be safe, just don't allow the PC-rel -;; versions in the various comparison expanders, patterns, for comparisons. -(define_insn "" - [(set (cc0) - (compare (match_operand:SI 0 "nonimmediate_operand" "rKT,rKs,mr,ma,>") - (match_operand:SI 1 "general_operand" "mr,ma,KTr,Ksr,>")))] + +(define_mode_attr scc0_constraints [(QI "=d,d,d") (HI "=d,d,d,d,d") (SI "=d,d,d,d,d,d")]) +(define_mode_attr cmp1_constraints [(QI "dn,dm,>") (HI "rnm,d,n,m,>") (SI "r,r,r,mr,ma,>")]) +(define_mode_attr cmp2_constraints [(QI "dm,nd,>") (HI "d,rnm,m,n,>") (SI "mrC0,mr,ma,KTrC0,Ksr,>")]) + +;; Note that operand 0 of an SCC insn is supported in the hardware as +;; memory, but we cannot allow it to be in memory in case the address +;; needs to be reloaded. + +(define_mode_attr scc0_cf_constraints [(QI "=d") (HI "=d") (SI "=d,d,d")]) +(define_mode_attr cmp1_cf_constraints [(QI "dm") (HI "dm") (SI "mrKs,r,rm")]) +(define_mode_attr cmp2_cf_constraints [(QI "C0") (HI "C0") (SI "r,mrKs,C0")]) +(define_mode_attr cmp2_cf_predicate [(QI "const0_operand") (HI "const0_operand") (SI "general_operand")]) + +(define_insn "cbranch4_insn" + [(set (pc) + (if_then_else (match_operator 0 "ordered_comparison_operator" + [(match_operand:CMPMODE 1 "nonimmediate_operand" "") + (match_operand:CMPMODE 2 "general_operand" "")]) + (label_ref (match_operand 3 "")) + (pc)))] "!TARGET_COLDFIRE" { - if (GET_CODE (operands[0]) == MEM && GET_CODE (operands[1]) == MEM) - return "cmpm%.l %1,%0"; - if (REG_P (operands[1]) - || (!REG_P (operands[0]) && GET_CODE (operands[0]) != MEM)) - { - cc_status.flags |= CC_REVERSED; /*|*/ - return "cmp%.l %d0,%d1"; - } - if (ADDRESS_REG_P (operands[0]) - && GET_CODE (operands[1]) == CONST_INT - && INTVAL (operands[1]) < 0x8000 - && INTVAL (operands[1]) >= -0x8000) - return "cmp%.w %1,%0"; - return "cmp%.l %d1,%d0"; -}) - -(define_insn "*cmpsi_cf" - [(set (cc0) - (compare (match_operand:SI 0 "nonimmediate_operand" "mrKs,r") - (match_operand:SI 1 "general_operand" "r,mrKs")))] - "TARGET_COLDFIRE" + rtx_code code = GET_CODE (operands[0]); + code = m68k_output_compare_ (operands[1], operands[2], code); + return m68k_output_branch_integer (code); +} + [(set_attr "flags_valid" "set")]) + +(define_insn "cbranch4_insn_rev" + [(set (pc) + (if_then_else (match_operator 0 "ordered_comparison_operator" + [(match_operand:CMPMODE 1 "nonimmediate_operand" "") + (match_operand:CMPMODE 2 "general_operand" "")]) + (pc) + (label_ref (match_operand 3 ""))))] + "!TARGET_COLDFIRE" { - if (REG_P (operands[1]) - || (!REG_P (operands[0]) && GET_CODE (operands[0]) != MEM)) - { - cc_status.flags |= CC_REVERSED; /*|*/ - return "cmp%.l %d0,%d1"; - } - return "cmp%.l %d1,%d0"; + rtx_code code = GET_CODE (operands[0]); + code = m68k_output_compare_ (operands[1], operands[2], code); + return m68k_output_branch_integer_rev (code); } - [(set_attr "type" "cmp_l")]) + [(set_attr "flags_valid" "set")]) -(define_expand "cbranchhi4" - [(set (cc0) - (compare (match_operand:HI 1 "nonimmediate_operand" "") - (match_operand:HI 2 "m68k_subword_comparison_operand" ""))) - (set (pc) +(define_insn "cbranch4_insn_cf" + [(set (pc) (if_then_else (match_operator 0 "ordered_comparison_operator" - [(cc0) (const_int 0)]) + [(match_operand:CMPMODE 1 "nonimmediate_operand" "") + (match_operand:CMPMODE 2 "" "")]) (label_ref (match_operand 3 "")) (pc)))] - "" - "") + "TARGET_COLDFIRE" +{ + rtx_code code = GET_CODE (operands[0]); + code = m68k_output_compare_ (operands[1], operands[2], code); + return m68k_output_branch_integer (code); +} + [(set_attr "flags_valid" "set")]) -(define_expand "cstorehi4" - [(set (cc0) - (compare (match_operand:HI 2 "nonimmediate_operand" "") - (match_operand:HI 3 "m68k_subword_comparison_operand" ""))) - (set (match_operand:QI 0 "register_operand") - (match_operator:QI 1 "ordered_comparison_operator" - [(cc0) (const_int 0)]))] - "" - "") +(define_insn "cbranch4_insn_cf_rev" + [(set (pc) + (if_then_else (match_operator 0 "ordered_comparison_operator" + [(match_operand:CMPMODE 1 "nonimmediate_operand" "") + (match_operand:CMPMODE 2 "" "")]) + (pc) + (label_ref (match_operand 3 ""))))] + "TARGET_COLDFIRE" +{ + rtx_code code = GET_CODE (operands[0]); + code = m68k_output_compare_ (operands[1], operands[2], code); + return m68k_output_branch_integer_rev (code); +} + [(set_attr "flags_valid" "set")]) -(define_insn "" - [(set (cc0) - (compare (match_operand:HI 0 "nonimmediate_operand" "rnm,d,n,m,>") - (match_operand:HI 1 "general_operand" "d,rnm,m,n,>")))] +(define_insn "cstore4_insn" + [(set (match_operand:QI 0 "register_operand" "") + (match_operator:QI 1 "ordered_comparison_operator" + [(match_operand:CMPMODE 2 "nonimmediate_operand" "") + (match_operand:CMPMODE 3 "general_operand" "")]))] "!TARGET_COLDFIRE" { - if (GET_CODE (operands[0]) == MEM && GET_CODE (operands[1]) == MEM) - return "cmpm%.w %1,%0"; - if ((REG_P (operands[1]) && !ADDRESS_REG_P (operands[1])) - || (!REG_P (operands[0]) && GET_CODE (operands[0]) != MEM)) - { - cc_status.flags |= CC_REVERSED; /*|*/ - return "cmp%.w %d0,%d1"; - } - return "cmp%.w %d1,%d0"; -}) + rtx_code code = GET_CODE (operands[1]); + code = m68k_output_compare_ (operands[2], operands[3], code); + return m68k_output_scc (code); +} + [(set_attr "flags_valid" "set")]) -(define_expand "cbranchqi4" - [(set (cc0) - (compare (match_operand:QI 1 "nonimmediate_operand" "") - (match_operand:QI 2 "m68k_subword_comparison_operand" ""))) - (set (pc) - (if_then_else (match_operator 0 "ordered_comparison_operator" - [(cc0) (const_int 0)]) +(define_insn "cstore4_insn_cf" + [(set (match_operand:QI 0 "register_operand" "") + (match_operator:QI 1 "ordered_comparison_operator" + [(match_operand:CMPMODE 2 "nonimmediate_operand" "") + (match_operand:CMPMODE 3 "" "")]))] + "TARGET_COLDFIRE" +{ + rtx_code code = GET_CODE (operands[1]); + code = m68k_output_compare_ (operands[2], operands[3], code); + return m68k_output_scc (code); +} + [(set_attr "flags_valid" "set")]) + +;; ColdFire/5200 only allows "" type addresses when the bit position is +;; specified as a constant, so we must disable all patterns that may extract +;; from a MEM at a constant bit position if we can't use this as a constraint. + +(define_insn "cbranchsi4_btst_mem_insn" + [(set (pc) + (if_then_else (match_operator 0 "equality_comparison_operator" + [(zero_extract:SI (match_operand:QI 1 "memory_src_operand" "oS,o") + (const_int 1) + (minus:SI (const_int 7) + (match_operand:SI 2 "general_operand" "di,d"))) + (const_int 0)]) (label_ref (match_operand 3 "")) (pc)))] "" - "") +{ + rtx_code code = GET_CODE (operands[0]); + code = m68k_output_btst (operands[2], operands[1], code, 7); + return m68k_output_branch_integer (code); +} + [(set_attr "ok_for_coldfire" "no,yes")]) -(define_expand "cstoreqi4" - [(set (cc0) - (compare (match_operand:QI 2 "nonimmediate_operand" "") - (match_operand:QI 3 "m68k_subword_comparison_operand" ""))) - (set (match_operand:QI 0 "register_operand") - (match_operator:QI 1 "ordered_comparison_operator" - [(cc0) (const_int 0)]))] - "" - "") +(define_insn "cbranchsi4_btst_reg_insn" + [(set (pc) + (if_then_else (match_operator 0 "equality_comparison_operator" + [(zero_extract:SI (match_operand:SI 1 "register_operand" "d") + (const_int 1) + (minus:SI (const_int 31) + (match_operand:SI 2 "general_operand" "di"))) + (const_int 0)]) + (label_ref (match_operand 3 "")) + (pc)))] + "!(CONST_INT_P (operands[1]) && !IN_RANGE (INTVAL (operands[1]), 0, 31))" +{ + rtx_code code = GET_CODE (operands[0]); + code = m68k_output_btst (operands[2], operands[1], code, 31); + return m68k_output_branch_integer (code); +}) -(define_insn "" - [(set (cc0) - (compare (match_operand:QI 0 "nonimmediate_operand" "dn,dm,>") - (match_operand:QI 1 "general_operand" "dm,nd,>")))] - "!TARGET_COLDFIRE" +;; Nonoffsettable mem refs are ok in this one pattern +;; since we don't try to adjust them. +(define_insn "cbranchsi4_btst_mem_insn_1" + [(set (pc) + (if_then_else (match_operator 0 "equality_comparison_operator" + [(zero_extract:SI (match_operand:QI 1 "memory_operand" "m") + (const_int 1) + (match_operand:SI 2 "const_int_operand" "n")) + (const_int 0)]) + (label_ref (match_operand 3 "")) + (pc)))] + "!TARGET_COLDFIRE && (unsigned) INTVAL (operands[2]) < 8" +{ + rtx_code code = GET_CODE (operands[0]); + operands[2] = GEN_INT (7 - INTVAL (operands[2])); + code = m68k_output_btst (operands[2], operands[1], code, 7); + return m68k_output_branch_integer (code); +}) + +(define_insn "cbranchsi4_btst_reg_insn_1" + [(set (pc) + (if_then_else (match_operator 0 "equality_comparison_operator" + [(zero_extract:SI (match_operand:SI 1 "nonimmediate_operand" "do,dQ") + (const_int 1) + (match_operand:SI 2 "const_int_operand" "n,n")) + (const_int 0)]) + (label_ref (match_operand 3 "")) + (pc)))] + "!(REG_P (operands[1]) && !IN_RANGE (INTVAL (operands[2]), 0, 31))" { - if (GET_CODE (operands[0]) == MEM && GET_CODE (operands[1]) == MEM) - return "cmpm%.b %1,%0"; - if (REG_P (operands[1]) - || (!REG_P (operands[0]) && GET_CODE (operands[0]) != MEM)) + rtx_code code = GET_CODE (operands[0]); + if (GET_CODE (operands[1]) == MEM) { - cc_status.flags |= CC_REVERSED; /*|*/ - return "cmp%.b %d0,%d1"; + operands[1] = adjust_address (operands[1], QImode, + INTVAL (operands[2]) / 8); + operands[2] = GEN_INT (7 - INTVAL (operands[2]) % 8); + code = m68k_output_btst (operands[2], operands[1], code, 7); } - return "cmp%.b %d1,%d0"; + else + { + operands[2] = GEN_INT (31 - INTVAL (operands[2])); + code = m68k_output_btst (operands[2], operands[1], code, 31); + } + return m68k_output_branch_integer (code); +} + [(set_attr "ok_for_coldfire" "no,yes")]) + +(define_mode_iterator BTST [QI SI]) +(define_mode_attr btst_predicate [(QI "memory_operand") (SI "register_operand")]) +(define_mode_attr btst_constraint [(QI "o") (SI "d")]) +(define_mode_attr btst_range [(QI "7") (SI "31")]) + +;; Special patterns for optimizing bit-field instructions. +(define_insn "cbranch_bftst_insn" + [(set (pc) + (if_then_else (match_operator 0 "ordered_comparison_operator" + [(zero_extract:SI (match_operand:BTST 1 "" "") + (match_operand:SI 2 "const_int_operand" "n") + (match_operand:SI 3 "general_operand" "dn")) + (const_int 0)]) + (label_ref (match_operand 4 "")) + (pc)))] + "TARGET_68020 && TARGET_BITFIELD + && (!REG_P (operands[1]) || !CONST_INT_P (operands[3]) + || IN_RANGE (INTVAL (operands[3]), 0, 31))" +{ + rtx_code code = GET_CODE (operands[0]); + code = m68k_output_bftst (operands[1], operands[2], operands[3], code); + operands[3] = operands[4]; + return m68k_output_branch_integer (code); }) +(define_insn "cstore_bftst_insn" + [(set (match_operand:QI 0 "register_operand" "=d") + (match_operator:QI 1 "ordered_comparison_operator" + [(zero_extract:SI (match_operand:BTST 2 "" "") + (match_operand:SI 3 "const_int_operand" "n") + (match_operand:SI 4 "general_operand" "dn")) + (const_int 0)]))] + "TARGET_68020 && TARGET_BITFIELD + && (!REG_P (operands[2]) || !CONST_INT_P (operands[4]) + || IN_RANGE (INTVAL (operands[4]), 0, 31))" +{ + rtx_code code = GET_CODE (operands[1]); + code = m68k_output_bftst (operands[2], operands[3], operands[4], code); + return m68k_output_scc (code); +}) + +;; Floating point comparison patterns (define_expand "cbranch4" - [(set (cc0) - (compare (match_operand:FP 1 "register_operand" "") - (match_operand:FP 2 "fp_src_operand" ""))) - (set (pc) + [(set (pc) (if_then_else (match_operator 0 "comparison_operator" - [(cc0) (const_int 0)]) + [(match_operand:FP 1 "register_operand" "") + (match_operand:FP 2 "fp_src_operand" "")]) (label_ref (match_operand 3 "")) (pc)))] "TARGET_HARD_FLOAT" "") +;; ??? This presumably tries to allow tests against zero for coldfire, but +;; it would have to test operands[3] and use CONST0_RTX (mode). (define_expand "cstore4" - [(set (cc0) - (compare (match_operand:FP 2 "register_operand" "") - (match_operand:FP 3 "fp_src_operand" ""))) - (set (match_operand:QI 0 "register_operand") + [(set (match_operand:QI 0 "register_operand") (match_operator:QI 1 "m68k_cstore_comparison_operator" - [(cc0) (const_int 0)]))] + [(match_operand:FP 2 "register_operand" "") + (match_operand:FP 3 "fp_src_operand" "")]))] "TARGET_HARD_FLOAT && !(TUNE_68060 || TARGET_COLDFIRE_FPU)" "if (TARGET_COLDFIRE && operands[2] != const0_rtx) FAIL;") -(define_insn "*cmp_68881" - [(set (cc0) - (compare (match_operand:FP 0 "fp_src_operand" "f,f,mF") - (match_operand:FP 1 "fp_src_operand" "f,mF,f")))] +(define_insn "cbranch4_insn_68881" + [(set (pc) + (if_then_else (match_operator 0 "comparison_operator" + [(match_operand:FP 1 "fp_src_operand" "f,f,mF,fm") + (match_operand:FP 2 "fp_src_operand" "f,mF,f,H")]) + (label_ref (match_operand 3 "")) + (pc)))] "TARGET_68881 - && (register_operand (operands[0], mode) - || register_operand (operands[1], mode))" - "@ - fcmp%.x %1,%0 - fcmp%. %f1,%0 - fcmp%. %0,%f1" - [(set_attr "type" "fcmp")]) - -(define_insn "*cmp_cf" - [(set (cc0) - (compare (match_operand:FP 0 "fp_src_operand" "f,f,U") - (match_operand:FP 1 "fp_src_operand" "f,U,f")))] - "TARGET_COLDFIRE_FPU - && (register_operand (operands[0], mode) - || register_operand (operands[1], mode))" - "@ - fcmp%.d %1,%0 - fcmp%. %f1,%0 - fcmp%. %0,%f1" - [(set_attr "type" "fcmp")]) - -;; Recognizers for btst instructions. - -;; ColdFire/5200 only allows "" type addresses when the bit position is -;; specified as a constant, so we must disable all patterns that may extract -;; from a MEM at a constant bit position if we can't use this as a constraint. - -(define_insn "" - [(set - (cc0) - (compare (zero_extract:SI (match_operand:QI 0 "memory_src_operand" "oS") - (const_int 1) - (minus:SI (const_int 7) - (match_operand:SI 1 "general_operand" "di"))) - (const_int 0)))] - "!TARGET_COLDFIRE" + && (register_operand (operands[1], mode) + || register_operand (operands[2], mode) + || const0_operand (operands[2], mode))" { - return output_btst (operands, operands[1], operands[0], insn, 7); -}) + rtx_code code = GET_CODE (operands[0]); + code = m68k_output_compare_fp (operands[1], operands[2], code); + return m68k_output_branch_float (code); +} + [(set_attr "flags_valid" "set")]) -;; This is the same as the above pattern except for the constraints. The 'i' -;; has been deleted. +(define_insn "cbranch4_insn_cf" + [(set (pc) + (if_then_else (match_operator 0 "comparison_operator" + [(match_operand:FP 1 "fp_src_operand" "f,f,U,fU") + (match_operand:FP 2 "fp_src_operand" "f,U,f,H")]) + (label_ref (match_operand 3 "")) + (pc)))] + "TARGET_COLDFIRE_FPU + && (register_operand (operands[1], mode) + || register_operand (operands[2], mode) + || const0_operand (operands[2], mode))" +{ + rtx_code code = GET_CODE (operands[0]); + code = m68k_output_compare_fp (operands[1], operands[2], code); + return m68k_output_branch_float (code); +} + [(set_attr "flags_valid" "set")]) -(define_insn "" - [(set - (cc0) - (compare (zero_extract:SI (match_operand:QI 0 "memory_operand" "o") - (const_int 1) - (minus:SI (const_int 7) - (match_operand:SI 1 "general_operand" "d"))) - (const_int 0)))] - "TARGET_COLDFIRE" +(define_insn "cbranch4_insn_rev_68881" + [(set (pc) + (if_then_else (match_operator 0 "comparison_operator" + [(match_operand:FP 1 "fp_src_operand" "f,f,mF,fm") + (match_operand:FP 2 "fp_src_operand" "f,mF,f,H")]) + (pc) + (label_ref (match_operand 3 ""))))] + "TARGET_68881 + && (register_operand (operands[1], mode) + || register_operand (operands[2], mode) + || const0_operand (operands[2], mode))" { - return output_btst (operands, operands[1], operands[0], insn, 7); -}) + rtx_code code = GET_CODE (operands[0]); + code = m68k_output_compare_fp (operands[1], operands[2], code); + return m68k_output_branch_float_rev (code); +} + [(set_attr "flags_valid" "set")]) -(define_insn "" - [(set - (cc0) - (compare (zero_extract:SI (match_operand:SI 0 "register_operand" "d") - (const_int 1) - (minus:SI (const_int 31) - (match_operand:SI 1 "general_operand" "di"))) - (const_int 0)))] - "!(CONST_INT_P (operands[1]) && !IN_RANGE (INTVAL (operands[1]), 0, 31))" +(define_insn "cbranch4_insn_rev_cf" + [(set (pc) + (if_then_else (match_operator 0 "comparison_operator" + [(match_operand:FP 1 "fp_src_operand" "f,f,U,fU") + (match_operand:FP 2 "fp_src_operand" "f,U,f,H")]) + (pc) + (label_ref (match_operand 3 ""))))] + "TARGET_COLDFIRE_FPU + && (register_operand (operands[1], mode) + || register_operand (operands[2], mode) + || const0_operand (operands[2], mode))" { - return output_btst (operands, operands[1], operands[0], insn, 31); -}) + rtx_code code = GET_CODE (operands[0]); + code = m68k_output_compare_fp (operands[1], operands[2], code); + return m68k_output_branch_float_rev (code); +} + [(set_attr "flags_valid" "set")]) -;; The following two patterns are like the previous two -;; except that they use the fact that bit-number operands -;; are automatically masked to 3 or 5 bits. +(define_insn "cstore4_insn_68881" + [(set (match_operand:QI 0 "register_operand" "=d,d,d,d") + (match_operator:QI 1 "m68k_cstore_comparison_operator" + [(match_operand:FP 2 "fp_src_operand" "f,f,mF,fm") + (match_operand:FP 3 "fp_src_operand" "f,mF,f,H")]))] + "TARGET_HARD_FLOAT && !(TUNE_68060 || TARGET_COLDFIRE_FPU) + && (register_operand (operands[2], mode) + || register_operand (operands[3], mode) + || const0_operand (operands[3], mode))" +{ + rtx_code code = GET_CODE (operands[1]); + code = m68k_output_compare_fp (operands[2], operands[3], code); + return m68k_output_scc_float (code); +} + [(set_attr "flags_valid" "set")]) -(define_insn "" - [(set - (cc0) - (compare (zero_extract:SI (match_operand:QI 0 "memory_operand" "o") - (const_int 1) - (minus:SI (const_int 7) - (and:SI - (match_operand:SI 1 "register_operand" "d") - (const_int 7)))) - (const_int 0)))] - "" +;; Test against zero only for coldfire floating point cstore. +(define_insn "cstore4_insn_cf" + [(set (match_operand:QI 0 "register_operand" "=d") + (match_operator:QI 1 "m68k_cstore_comparison_operator" + [(match_operand:FP 2 "fp_src_operand" "fU") + (match_operand:FP 3 "const0_operand" "H")]))] + "TARGET_HARD_FLOAT && TARGET_COLDFIRE_FPU" { - return output_btst (operands, operands[1], operands[0], insn, 7); -}) + rtx_code code = GET_CODE (operands[1]); + code = m68k_output_compare_fp (operands[2], operands[3], code); + return m68k_output_scc_float (code); +} + [(set_attr "flags_valid" "set")]) -(define_insn "" - [(set - (cc0) - (compare (zero_extract:SI (match_operand:SI 0 "register_operand" "d") - (const_int 1) - (minus:SI (const_int 31) - (and:SI - (match_operand:SI 1 "register_operand" "d") - (const_int 31)))) - (const_int 0)))] - "" -{ - return output_btst (operands, operands[1], operands[0], insn, 31); -}) - -;; Nonoffsettable mem refs are ok in this one pattern -;; since we don't try to adjust them. -(define_insn "" - [(set - (cc0) - (compare (zero_extract:SI (match_operand:QI 0 "memory_operand" "m") - (const_int 1) - (match_operand:SI 1 "const_int_operand" "n")) - (const_int 0)))] - "(unsigned) INTVAL (operands[1]) < 8 && !TARGET_COLDFIRE" -{ - operands[1] = GEN_INT (7 - INTVAL (operands[1])); - return output_btst (operands, operands[1], operands[0], insn, 7); -}) - -(define_insn "" - [(set - (cc0) - (compare (zero_extract:SI (match_operand:SI 0 "register_operand" "do") - (const_int 1) - (match_operand:SI 1 "const_int_operand" "n")) - (const_int 0)))] - "!TARGET_COLDFIRE - && !(REG_P (operands[0]) && !IN_RANGE (INTVAL (operands[1]), 0, 31))" -{ - if (GET_CODE (operands[0]) == MEM) - { - operands[0] = adjust_address (operands[0], QImode, - INTVAL (operands[1]) / 8); - operands[1] = GEN_INT (7 - INTVAL (operands[1]) % 8); - return output_btst (operands, operands[1], operands[0], insn, 7); - } - operands[1] = GEN_INT (31 - INTVAL (operands[1])); - return output_btst (operands, operands[1], operands[0], insn, 31); -}) - -;; This is the same as the above pattern except for the constraints. -;; The 'o' has been replaced with 'Q'. - -(define_insn "" - [(set - (cc0) - (compare (zero_extract:SI (match_operand:SI 0 "register_operand" "dQ") - (const_int 1) - (match_operand:SI 1 "const_int_operand" "n")) - (const_int 0)))] - "TARGET_COLDFIRE - && !(REG_P (operands[0]) && !IN_RANGE (INTVAL (operands[1]), 0, 31))" -{ - if (GET_CODE (operands[0]) == MEM) - { - operands[0] = adjust_address (operands[0], QImode, - INTVAL (operands[1]) / 8); - operands[1] = GEN_INT (7 - INTVAL (operands[1]) % 8); - return output_btst (operands, operands[1], operands[0], insn, 7); - } - operands[1] = GEN_INT (31 - INTVAL (operands[1])); - return output_btst (operands, operands[1], operands[0], insn, 31); -}) - - ;; move instructions ;; A special case in which it is not desirable @@ -964,7 +995,8 @@ "!TARGET_COLDFIRE && reload_completed" { return output_move_simode (operands); -}) +} + [(set_attr "flags_valid" "set")]) ;; Before reload is completed the register constraints ;; force integer constants in range for a moveq to be reloaded @@ -976,7 +1008,8 @@ "!TARGET_COLDFIRE" { return output_move_simode (operands); -}) +} + [(set_attr "flags_valid" "set")]) ;; ColdFire move instructions can have at most one operand of mode >= 6. (define_insn "*movsi_cf" @@ -1052,13 +1085,21 @@ [(set (match_operand:HI 0 "nonimmediate_operand" "=g") (match_operand:HI 1 "general_src_operand" "gS"))] "!TARGET_COLDFIRE" - "* return output_move_himode (operands);") + "* return output_move_himode (operands);" + [(set (attr "flags_valid") + (if_then_else (match_operand 0 "address_reg_operand") + (const_string "unchanged") + (const_string "move")))]) (define_insn "" [(set (match_operand:HI 0 "nonimmediate_operand" "=r,g,U") (match_operand:HI 1 "general_operand" "g,r,U"))] "TARGET_COLDFIRE" - "* return output_move_himode (operands);") + "* return output_move_himode (operands);" + [(set (attr "flags_valid") + (if_then_else (match_operand 0 "address_reg_operand") + (const_string "unchanged") + (const_string "move")))]) (define_expand "movstricthi" [(set (strict_low_part (match_operand:HI 0 "nonimmediate_operand" "")) @@ -1070,13 +1111,15 @@ [(set (strict_low_part (match_operand:HI 0 "nonimmediate_operand" "+dm")) (match_operand:HI 1 "general_src_operand" "rmSn"))] "!TARGET_COLDFIRE" - "* return output_move_stricthi (operands);") + "* return output_move_stricthi (operands);" + [(set_attr "flags_valid" "move")]) (define_insn "" [(set (strict_low_part (match_operand:HI 0 "nonimmediate_operand" "+d,m")) (match_operand:HI 1 "general_src_operand" "rmn,r"))] "TARGET_COLDFIRE" - "* return output_move_stricthi (operands);") + "* return output_move_stricthi (operands);" + [(set_attr "flags_valid" "move")]) (define_expand "movqi" [(set (match_operand:QI 0 "nonimmediate_operand" "") @@ -1088,13 +1131,15 @@ [(set (match_operand:QI 0 "nonimmediate_operand" "=d,*a,m") (match_operand:QI 1 "general_src_operand" "dmSi*a,di*a,dmSi"))] "!TARGET_COLDFIRE" - "* return output_move_qimode (operands);") + "* return output_move_qimode (operands);" + [(set_attr "flags_valid" "set")]) (define_insn "" [(set (match_operand:QI 0 "nonimmediate_operand" "=d,dm,U,d*a") (match_operand:QI 1 "general_src_operand" "dmi,d,U,di*a"))] "TARGET_COLDFIRE" - "* return output_move_qimode (operands);") + "* return output_move_qimode (operands);" + [(set_attr "flags_valid" "set")]) (define_expand "movstrictqi" [(set (strict_low_part (match_operand:QI 0 "nonimmediate_operand" "")) @@ -1106,7 +1151,8 @@ [(set (strict_low_part (match_operand:QI 0 "nonimmediate_operand" "+dm")) (match_operand:QI 1 "general_src_operand" "dmSn"))] "!TARGET_COLDFIRE" - "* return output_move_strictqi (operands);") + "* return output_move_strictqi (operands);" + [(set_attr "flags_valid" "move")]) (define_insn "*movstrictqi_cf" [(set (strict_low_part (match_operand:QI 0 "nonimmediate_operand" "+d, Ac, d,m")) @@ -1200,7 +1246,8 @@ return "clr%.l %0"; } return "move%.l %1,%0"; -}) +} + [(set_attr "flags_valid" "move")]) (define_insn "movsf_cf_soft" [(set (match_operand:SF 0 "nonimmediate_operand" "=r,g,U") @@ -1340,7 +1387,8 @@ return "fmove%.d %f1,%0"; } return output_move_double (operands); -}) +} + [(set_attr "flags_valid" "move")]) (define_insn_and_split "movdf_cf_soft" [(set (match_operand:DF 0 "nonimmediate_operand" "=r,g") @@ -1461,7 +1509,8 @@ return "fmove%.x %f1,%0"; } return output_move_double (operands); -}) +} + [(set_attr "flags_valid" "move")]) (define_insn "" [(set (match_operand:XF 0 "nonimmediate_operand" "=rm,rf,&rof<>") @@ -1582,16 +1631,16 @@ "!TARGET_COLDFIRE" { if (GET_CODE (operands[0]) == REG) - { - /* Must clear condition codes, since the move.l bases them on - the entire 32 bits, not just the desired 8 bits. */ - CC_STATUS_INIT; - return "move%.l %1,%0"; - } + return "move%.l %1,%0"; + if (GET_CODE (operands[1]) == MEM) operands[1] = adjust_address (operands[1], QImode, 3); return "move%.b %1,%0"; -}) +} + [(set (attr "flags_valid") + (if_then_else (match_operand 0 "register_operand") + (const_string "no") + (const_string "yes")))]) (define_insn "trunchiqi2" [(set (match_operand:QI 0 "nonimmediate_operand" "=dm,d") @@ -1602,23 +1651,19 @@ if (GET_CODE (operands[0]) == REG && (GET_CODE (operands[1]) == MEM || GET_CODE (operands[1]) == CONST_INT)) - { - /* Must clear condition codes, since the move.w bases them on - the entire 16 bits, not just the desired 8 bits. */ - CC_STATUS_INIT; - return "move%.w %1,%0"; - } + return "move%.w %1,%0"; + if (GET_CODE (operands[0]) == REG) - { - /* Must clear condition codes, since the move.l bases them on - the entire 32 bits, not just the desired 8 bits. */ - CC_STATUS_INIT; - return "move%.l %1,%0"; - } + return "move%.l %1,%0"; + if (GET_CODE (operands[1]) == MEM) operands[1] = adjust_address (operands[1], QImode, 1); return "move%.b %1,%0"; -}) +} + [(set (attr "flags_valid") + (if_then_else (match_operand 0 "register_operand") + (const_string "no") + (const_string "yes")))]) (define_insn "truncsihi2" [(set (match_operand:HI 0 "nonimmediate_operand" "=dm,d") @@ -1627,16 +1672,16 @@ "!TARGET_COLDFIRE" { if (GET_CODE (operands[0]) == REG) - { - /* Must clear condition codes, since the move.l bases them on - the entire 32 bits, not just the desired 8 bits. */ - CC_STATUS_INIT; - return "move%.l %1,%0"; - } + return "move%.l %1,%0"; + if (GET_CODE (operands[1]) == MEM) operands[1] = adjust_address (operands[1], QImode, 2); return "move%.w %1,%0"; -}) +} + [(set (attr "flags_valid") + (if_then_else (match_operand 0 "register_operand") + (const_string "no") + (const_string "yes")))]) ;; zero extension instructions @@ -1804,7 +1849,6 @@ (sign_extend:DI (match_operand:QI 1 "general_src_operand" "rmS")))] "" { - CC_STATUS_INIT; operands[2] = gen_rtx_REG (SImode, REGNO (operands[0]) + 1); if (ISA_HAS_MVS_MVZ) return "mvs%.b %1,%2\;smi %0\;extb%.l %0"; @@ -1830,7 +1874,6 @@ (match_operand:HI 1 "general_src_operand" "rmS")))] "" { - CC_STATUS_INIT; operands[2] = gen_rtx_REG (SImode, REGNO (operands[0]) + 1); if (ISA_HAS_MVS_MVZ) return "mvs%.w %1,%2\;smi %0\;extb%.l %0"; @@ -1847,8 +1890,6 @@ (clobber (match_scratch:SI 2 "=X,d,d,d"))] "" { - CC_STATUS_INIT; - if (which_alternative == 0) /* Handle alternative 0. */ { @@ -1883,7 +1924,6 @@ (match_operand:SI 2 "general_operand" "rmn"))))] "" { - CC_STATUS_INIT; operands[3] = gen_rtx_REG (SImode, REGNO (operands[0]) + 1); if (GET_CODE (operands[1]) == CONST_INT && (unsigned) INTVAL (operands[1]) > 8) @@ -1975,10 +2015,7 @@ { if (REGNO (operands[0]) == REGNO (operands[1])) { - /* Extending float to double in an fp-reg is a no-op. - NOTICE_UPDATE_CC has already assumed that the - cc will be set. So cancel what it did. */ - cc_status = cc_prev_status; + /* Extending float to double in an fp-reg is a no-op. */ return ""; } return "f%&move%.x %1,%0"; @@ -2004,10 +2041,7 @@ { if (REGNO (operands[0]) == REGNO (operands[1])) { - /* Extending float to double in an fp-reg is a no-op. - NOTICE_UPDATE_CC has already assumed that the - cc will be set. So cancel what it did. */ - cc_status = cc_prev_status; + /* Extending float to double in an fp-reg is a no-op. */ return ""; } return "fdmove%.d %1,%0"; @@ -2137,7 +2171,6 @@ (clobber (match_scratch:SI 3 "=d"))] "TARGET_68881 && TUNE_68040" { - CC_STATUS_INIT; return "fmovem%.l %!,%2\;moveq #16,%3\;or%.l %2,%3\;and%.w #-33,%3\;fmovem%.l %3,%!\;fmove%.l %1,%0\;fmovem%.l %2,%!"; }) @@ -2148,7 +2181,6 @@ (clobber (match_scratch:SI 3 "=d"))] "TARGET_68881 && TUNE_68040" { - CC_STATUS_INIT; return "fmovem%.l %!,%2\;moveq #16,%3\;or%.l %2,%3\;and%.w #-33,%3\;fmovem%.l %3,%!\;fmove%.w %1,%0\;fmovem%.l %2,%!"; }) @@ -2159,7 +2191,6 @@ (clobber (match_scratch:SI 3 "=d"))] "TARGET_68881 && TUNE_68040" { - CC_STATUS_INIT; return "fmovem%.l %!,%2\;moveq #16,%3\;or%.l %2,%3\;and%.w #-33,%3\;fmovem%.l %3,%!\;fmove%.b %1,%0\;fmovem%.l %2,%!"; }) @@ -2301,7 +2332,6 @@ (clobber (match_scratch:SI 3 "=&d,X,a,?d"))] "!TARGET_COLDFIRE" { - CC_STATUS_INIT; if (ADDRESS_REG_P (operands[0])) return "add%.w %1,%0"; else if (ADDRESS_REG_P (operands[3])) @@ -2317,7 +2347,6 @@ (match_operand:DI 2 "general_operand" "0,0")))] "!TARGET_COLDFIRE" { - CC_STATUS_INIT; if (GET_CODE (operands[0]) == REG) operands[2] = gen_rtx_REG (SImode, REGNO (operands[0]) + 1); else @@ -2332,7 +2361,6 @@ (match_operand:DI 2 "register_operand" "0")))] "TARGET_COLDFIRE" { - CC_STATUS_INIT; return "add%.l %1,%R0\;negx%.l %0\;neg%.l %0"; }) @@ -2346,7 +2374,6 @@ (match_operand:DI 2 "general_operand" "0,0")))] "" { - CC_STATUS_INIT; if (GET_CODE (operands[1]) == REG) operands[1] = gen_rtx_REG (SImode, REGNO (operands[1]) + 1); else @@ -2412,7 +2439,6 @@ else { gcc_assert (GET_CODE (operands[0]) == MEM); - CC_STATUS_INIT; if (GET_CODE (XEXP (operands[0], 0)) == POST_INC) { operands[1] = gen_rtx_MEM (SImode, @@ -2431,7 +2457,11 @@ return "add%.l %R2,%1\;move%.l %0,%3\;addx%.l %2,%3\;move%.l %3,%0"; } } -}) +} + [(set (attr "flags_valid") + (if_then_else (match_operand 0 "register_operand") + (const_string "noov") + (const_string "no")))]) (define_insn "addsi_lshrsi_31" [(set (match_operand:SI 0 "nonimmediate_operand" "=dm,dm,d") @@ -2476,7 +2506,8 @@ "! TARGET_COLDFIRE" - "* return output_addsi3 (operands);") + "* return output_addsi3 (operands);" + [(set_attr "flags_valid" "noov,unchanged,unchanged,noov,unchanged")]) (define_insn_and_split "*addsi3_5200" [(set (match_operand:SI 0 "nonimmediate_operand" "=mr,mr,a, m,r, ?a, ?a,?a,?a") @@ -2561,7 +2592,7 @@ return "subq%.w %2,%0"; } /* On the CPU32 it is faster to use two addqw instructions to - add a small integer (8 < N <= 16) to a register. + add a small integer (8 < N <= 16) to a register. Likewise for subqw. */ if (TUNE_CPU32 && REG_P (operands[0])) { @@ -2582,7 +2613,11 @@ return MOTOROLA ? "lea (%c2,%0),%0" : "lea %0@(%c2),%0"; } return "add%.w %2,%0"; -}) +} + [(set (attr "flags_valid") + (if_then_else (match_operand 0 "address_reg_operand") + (const_string "unchanged") + (const_string "noov")))]) ;; These insns must use MATCH_DUP instead of the more expected ;; use of a matching constraint because the "output" here is also @@ -2596,6 +2631,7 @@ (match_operand:HI 1 "general_src_operand" "dn,rmSn")))] "!TARGET_COLDFIRE" { + gcc_assert (!ADDRESS_REG_P (operands[0])); if (GET_CODE (operands[1]) == CONST_INT) { /* If the constant would be a negative number when interpreted as @@ -2633,11 +2669,10 @@ return "subq%.w #8,%0\;subq%.w %1,%0"; } } - if (ADDRESS_REG_P (operands[0]) && !TUNE_68040) - return MOTOROLA ? "lea (%c1,%0),%0" : "lea %0@(%c1),%0"; } return "add%.w %1,%0"; -}) +} + [(set_attr "flags_valid" "noov")]) (define_insn "" [(set (strict_low_part (match_operand:HI 0 "nonimmediate_operand" "+m,d")) @@ -2645,6 +2680,7 @@ (match_dup 0)))] "!TARGET_COLDFIRE" { + gcc_assert (!ADDRESS_REG_P (operands[0])); if (GET_CODE (operands[1]) == CONST_INT) { /* If the constant would be a negative number when interpreted as @@ -2682,11 +2718,10 @@ return "subq%.w #8,%0\;subq%.w %1,%0"; } } - if (ADDRESS_REG_P (operands[0]) && !TUNE_68040) - return MOTOROLA ? "lea (%c1,%0),%0" : "lea %0@(%c1),%0"; } return "add%.w %1,%0"; -}) +} + [(set_attr "flags_valid" "noov")]) (define_insn "addqi3" [(set (match_operand:QI 0 "nonimmediate_operand" "=m,d") @@ -2709,7 +2744,8 @@ } } return "add%.b %2,%0"; -}) +} + [(set_attr "flags_valid" "noov")]) (define_insn "" [(set (strict_low_part (match_operand:QI 0 "nonimmediate_operand" "+m,d")) @@ -2827,7 +2863,6 @@ (clobber (match_scratch:SI 3 "=&d,X,a,?d"))] "!TARGET_COLDFIRE" { - CC_STATUS_INIT; if (ADDRESS_REG_P (operands[0])) return "sub%.w %2,%0"; else if (ADDRESS_REG_P (operands[3])) @@ -2843,7 +2878,6 @@ (const_int 32))))] "" { - CC_STATUS_INIT; if (GET_CODE (operands[1]) == REG) operands[1] = gen_rtx_REG (SImode, REGNO (operands[1]) + 1); else @@ -2911,7 +2945,6 @@ else { gcc_assert (GET_CODE (operands[0]) == MEM); - CC_STATUS_INIT; if (GET_CODE (XEXP (operands[0], 0)) == POST_INC) { operands[1] @@ -2930,20 +2963,26 @@ return "sub%.l %R2,%1\;move%.l %0,%3\;subx%.l %2,%3\;move%.l %3,%0"; } } -}) +} + [(set (attr "flags_valid") + (if_then_else (match_operand 0 "register_operand") + (const_string "noov") + (const_string "no")))]) (define_insn "subsi3" - [(set (match_operand:SI 0 "nonimmediate_operand" "=mda,m,d,a") - (minus:SI (match_operand:SI 1 "general_operand" "0,0,0,0") - (match_operand:SI 2 "general_src_operand" "I,dT,mSrT,mSrs")))] + [(set (match_operand:SI 0 "nonimmediate_operand" "=md,ma,m,d,a") + (minus:SI (match_operand:SI 1 "general_operand" "0,0,0,0,0") + (match_operand:SI 2 "general_src_operand" "I,I,dT,mSrT,mSrs")))] "" "@ + subq%.l %2, %0 subq%.l %2, %0 sub%.l %2,%0 sub%.l %2,%0 sub%.l %2,%0" - [(set_attr "type" "aluq_l,alu_l,alu_l,alu_l") - (set_attr "opy" "2")]) + [(set_attr "type" "aluq_l,aluq_l,alu_l,alu_l,alu_l") + (set_attr "opy" "2") + (set_attr "flags_valid" "noov,unchanged,noov,noov,unchanged")]) (define_insn "" [(set (match_operand:SI 0 "nonimmediate_operand" "=a") @@ -2958,28 +2997,32 @@ (minus:HI (match_operand:HI 1 "general_operand" "0,0") (match_operand:HI 2 "general_src_operand" "dn,rmSn")))] "!TARGET_COLDFIRE" - "sub%.w %2,%0") + "sub%.w %2,%0" + [(set_attr "flags_valid" "noov")]) (define_insn "" [(set (strict_low_part (match_operand:HI 0 "nonimmediate_operand" "+m,d")) (minus:HI (match_dup 0) (match_operand:HI 1 "general_src_operand" "dn,rmSn")))] "!TARGET_COLDFIRE" - "sub%.w %1,%0") + "sub%.w %1,%0" + [(set_attr "flags_valid" "noov")]) (define_insn "subqi3" [(set (match_operand:QI 0 "nonimmediate_operand" "=m,d") (minus:QI (match_operand:QI 1 "general_operand" "0,0") (match_operand:QI 2 "general_src_operand" "dn,dmSn")))] "!TARGET_COLDFIRE" - "sub%.b %2,%0") + "sub%.b %2,%0" + [(set_attr "flags_valid" "noov")]) (define_insn "" [(set (strict_low_part (match_operand:QI 0 "nonimmediate_operand" "+m,d")) (minus:QI (match_dup 0) (match_operand:QI 1 "general_src_operand" "dn,dmSn")))] "!TARGET_COLDFIRE" - "sub%.b %1,%0") + "sub%.b %1,%0" + [(set_attr "flags_valid" "noov")]) (define_expand "sub3" [(set (match_operand:FP 0 "nonimmediate_operand" "") @@ -3240,10 +3283,7 @@ (const_int 32)))) (clobber (match_operand:SI 1 "register_operand" "=d"))] "TARGET_68020 && !TUNE_68060 && !TARGET_COLDFIRE" -{ - CC_STATUS_INIT; - return "mulu%.l %3,%0:%1"; -}) + "mulu%.l %3,%0:%1") (define_insn "const_umulsi3_highpart" [(set (match_operand:SI 0 "register_operand" "=d") @@ -3254,10 +3294,7 @@ (const_int 32)))) (clobber (match_operand:SI 1 "register_operand" "=d"))] "TARGET_68020 && !TUNE_68060 && !TARGET_COLDFIRE" -{ - CC_STATUS_INIT; - return "mulu%.l %3,%0:%1"; -}) + "mulu%.l %3,%0:%1") (define_expand "smulsi3_highpart" [(parallel @@ -3289,10 +3326,7 @@ (const_int 32)))) (clobber (match_operand:SI 1 "register_operand" "=d"))] "TARGET_68020 && !TUNE_68060 && !TARGET_COLDFIRE" -{ - CC_STATUS_INIT; - return "muls%.l %3,%0:%1"; -}) + "muls%.l %3,%0:%1") (define_insn "const_smulsi3_highpart" [(set (match_operand:SI 0 "register_operand" "=d") @@ -3303,10 +3337,7 @@ (const_int 32)))) (clobber (match_operand:SI 1 "register_operand" "=d"))] "TARGET_68020 && !TUNE_68060 && !TARGET_COLDFIRE" -{ - CC_STATUS_INIT; - return "muls%.l %3,%0:%1"; -}) + "muls%.l %3,%0:%1") (define_expand "mul3" [(set (match_operand:FP 0 "nonimmediate_operand" "") @@ -3483,19 +3514,19 @@ (define_expand "divmodsi4" [(parallel - [(set (match_operand:SI 0 "nonimmediate_operand" "") + [(set (match_operand:SI 0 "register_operand" "") (div:SI (match_operand:SI 1 "general_operand" "") (match_operand:SI 2 "general_src_operand" ""))) - (set (match_operand:SI 3 "nonimmediate_operand" "") + (set (match_operand:SI 3 "register_operand" "") (mod:SI (match_dup 1) (match_dup 2)))])] "TARGET_68020 || TARGET_CF_HWDIV" "") (define_insn "" - [(set (match_operand:SI 0 "nonimmediate_operand" "=d") + [(set (match_operand:SI 0 "register_operand" "=d") (div:SI (match_operand:SI 1 "general_operand" "0") (match_operand:SI 2 "general_src_operand" "dU"))) - (set (match_operand:SI 3 "nonimmediate_operand" "=&d") + (set (match_operand:SI 3 "register_operand" "=&d") (mod:SI (match_dup 1) (match_dup 2)))] "TARGET_CF_HWDIV" { @@ -3510,10 +3541,10 @@ (set_attr "opy" "2")]) (define_insn "" - [(set (match_operand:SI 0 "nonimmediate_operand" "=d") + [(set (match_operand:SI 0 "register_operand" "=d") (div:SI (match_operand:SI 1 "general_operand" "0") (match_operand:SI 2 "general_src_operand" "dmSTK"))) - (set (match_operand:SI 3 "nonimmediate_operand" "=d") + (set (match_operand:SI 3 "register_operand" "=d") (mod:SI (match_dup 1) (match_dup 2)))] "TARGET_68020" { @@ -3525,19 +3556,19 @@ (define_expand "udivmodsi4" [(parallel - [(set (match_operand:SI 0 "nonimmediate_operand" "=d") + [(set (match_operand:SI 0 "register_operand" "=d") (udiv:SI (match_operand:SI 1 "general_operand" "0") (match_operand:SI 2 "general_src_operand" "dmSTK"))) - (set (match_operand:SI 3 "nonimmediate_operand" "=d") + (set (match_operand:SI 3 "register_operand" "=d") (umod:SI (match_dup 1) (match_dup 2)))])] "TARGET_68020 || TARGET_CF_HWDIV" "") (define_insn "" - [(set (match_operand:SI 0 "nonimmediate_operand" "=d") + [(set (match_operand:SI 0 "register_operand" "=d") (udiv:SI (match_operand:SI 1 "general_operand" "0") (match_operand:SI 2 "general_src_operand" "dU"))) - (set (match_operand:SI 3 "nonimmediate_operand" "=&d") + (set (match_operand:SI 3 "register_operand" "=&d") (umod:SI (match_dup 1) (match_dup 2)))] "TARGET_CF_HWDIV" { @@ -3552,10 +3583,10 @@ (set_attr "opy" "2")]) (define_insn "" - [(set (match_operand:SI 0 "nonimmediate_operand" "=d") + [(set (match_operand:SI 0 "register_operand" "=d") (udiv:SI (match_operand:SI 1 "general_operand" "0") (match_operand:SI 2 "general_src_operand" "dmSTK"))) - (set (match_operand:SI 3 "nonimmediate_operand" "=d") + (set (match_operand:SI 3 "register_operand" "=d") (umod:SI (match_dup 1) (match_dup 2)))] "TARGET_68020 && !TARGET_COLDFIRE" { @@ -3566,10 +3597,10 @@ }) (define_insn "divmodhi4" - [(set (match_operand:HI 0 "nonimmediate_operand" "=d") + [(set (match_operand:HI 0 "register_operand" "=d") (div:HI (match_operand:HI 1 "general_operand" "0") (match_operand:HI 2 "general_src_operand" "dmSKT"))) - (set (match_operand:HI 3 "nonimmediate_operand" "=d") + (set (match_operand:HI 3 "register_operand" "=d") (mod:HI (match_dup 1) (match_dup 2)))] "!TARGET_COLDFIRE || TARGET_CF_HWDIV" { @@ -3578,19 +3609,16 @@ "extl %0\;divs %2,%0", operands); if (!find_reg_note(insn, REG_UNUSED, operands[3])) - { - CC_STATUS_INIT; - return "move%.l %0,%3\;swap %3"; - } + return "move%.l %0,%3\;swap %3"; else return ""; }) (define_insn "udivmodhi4" - [(set (match_operand:HI 0 "nonimmediate_operand" "=d") + [(set (match_operand:HI 0 "register_operand" "=d") (udiv:HI (match_operand:HI 1 "general_operand" "0") (match_operand:HI 2 "general_src_operand" "dmSKT"))) - (set (match_operand:HI 3 "nonimmediate_operand" "=d") + (set (match_operand:HI 3 "register_operand" "=d") (umod:HI (match_dup 1) (match_dup 2)))] "!TARGET_COLDFIRE || TARGET_CF_HWDIV" { @@ -3606,10 +3634,7 @@ operands); if (!find_reg_note(insn, REG_UNUSED, operands[3])) - { - CC_STATUS_INIT; - return "move%.l %0,%3\;swap %3"; - } + return "move%.l %0,%3\;swap %3"; else return ""; }) @@ -3644,7 +3669,8 @@ "!TARGET_COLDFIRE" { return output_andsi3 (operands); -}) +} + [(set_attr "flags_valid" "set")]) (define_insn "andsi3_5200" [(set (match_operand:SI 0 "not_sp_operand" "=m,d") @@ -3669,35 +3695,40 @@ (and:HI (match_operand:HI 1 "general_operand" "%0,0") (match_operand:HI 2 "general_src_operand" "dn,dmSn")))] "!TARGET_COLDFIRE" - "and%.w %2,%0") + "and%.w %2,%0" + [(set_attr "flags_valid" "yes")]) (define_insn "" [(set (strict_low_part (match_operand:HI 0 "nonimmediate_operand" "+m,d")) (and:HI (match_dup 0) (match_operand:HI 1 "general_src_operand" "dn,dmSn")))] "!TARGET_COLDFIRE" - "and%.w %1,%0") + "and%.w %1,%0" + [(set_attr "flags_valid" "yes")]) (define_insn "" [(set (strict_low_part (match_operand:HI 0 "nonimmediate_operand" "+m,d")) (and:HI (match_operand:HI 1 "general_src_operand" "dn,dmSn") (match_dup 0)))] "!TARGET_COLDFIRE" - "and%.w %1,%0") + "and%.w %1,%0" + [(set_attr "flags_valid" "yes")]) (define_insn "andqi3" [(set (match_operand:QI 0 "nonimmediate_operand" "=m,d") (and:QI (match_operand:QI 1 "general_operand" "%0,0") (match_operand:QI 2 "general_src_operand" "dn,dmSn")))] "!TARGET_COLDFIRE" - "and%.b %2,%0") + "and%.b %2,%0" + [(set_attr "flags_valid" "yes")]) (define_insn "" [(set (strict_low_part (match_operand:QI 0 "nonimmediate_operand" "+m,d")) (and:QI (match_dup 0) (match_operand:QI 1 "general_src_operand" "dn,dmSn")))] "!TARGET_COLDFIRE" - "and%.b %1,%0") + "and%.b %1,%0" + [(set_attr "flags_valid" "yes")]) (define_insn "" [(set (strict_low_part (match_operand:QI 0 "nonimmediate_operand" "+m,d")) @@ -3716,7 +3747,6 @@ { int byte_mode; - CC_STATUS_INIT; if (GET_CODE (operands[0]) == REG) operands[0] = gen_rtx_REG (SImode, REGNO (operands[0]) + 1); else @@ -3747,7 +3777,8 @@ "! TARGET_COLDFIRE" { return output_iorsi3 (operands); -}) +} + [(set_attr "flags_valid" "set")]) (define_insn "iorsi3_5200" [(set (match_operand:SI 0 "nonimmediate_operand" "=m,d") @@ -3756,7 +3787,8 @@ "TARGET_COLDFIRE" { return output_iorsi3 (operands); -}) +} + [(set_attr "flags_valid" "set")]) (define_insn "iorhi3" [(set (match_operand:HI 0 "nonimmediate_operand" "=m,d") @@ -3777,28 +3809,32 @@ (ior:HI (match_operand:HI 1 "general_src_operand" "dn,dmSn") (match_dup 0)))] "!TARGET_COLDFIRE" - "or%.w %1,%0") + "or%.w %1,%0" + [(set_attr "flags_valid" "yes")]) (define_insn "iorqi3" [(set (match_operand:QI 0 "nonimmediate_operand" "=m,d") (ior:QI (match_operand:QI 1 "general_operand" "%0,0") (match_operand:QI 2 "general_src_operand" "dn,dmSn")))] "!TARGET_COLDFIRE" - "or%.b %2,%0") + "or%.b %2,%0" + [(set_attr "flags_valid" "yes")]) (define_insn "" [(set (strict_low_part (match_operand:QI 0 "nonimmediate_operand" "+m,d")) (ior:QI (match_dup 0) (match_operand:QI 1 "general_src_operand" "dn,dmSn")))] "!TARGET_COLDFIRE" - "or%.b %1,%0") + "or%.b %1,%0" + [(set_attr "flags_valid" "yes")]) (define_insn "" [(set (strict_low_part (match_operand:QI 0 "nonimmediate_operand" "+m,d")) (ior:QI (match_operand:QI 1 "general_src_operand" "dn,dmSn") (match_dup 0)))] "!TARGET_COLDFIRE" - "or%.b %1,%0") + "or%.b %1,%0" + [(set_attr "flags_valid" "yes")]) ;; On all 68k models, this makes faster code in a special case. ;; See also ashlsi_16, ashrsi_16 and lshrsi_16. @@ -3810,7 +3846,6 @@ (const_int 16))))] "" { - CC_STATUS_INIT; if (GET_CODE (operands[2]) != REG) operands[2] = adjust_address (operands[2], HImode, 2); if (GET_CODE (operands[2]) != REG @@ -3827,7 +3862,6 @@ { int byte_mode; - CC_STATUS_INIT; byte_mode = (GET_MODE (operands[1]) == QImode); if (GET_CODE (operands[0]) == MEM) operands[0] = adjust_address (operands[0], byte_mode ? QImode : HImode, @@ -3855,7 +3889,8 @@ "!TARGET_COLDFIRE" { return output_xorsi3 (operands); -}) +} + [(set_attr "flags_valid" "set")]) (define_insn "xorsi3_5200" [(set (match_operand:SI 0 "nonimmediate_operand" "=dm,d") @@ -3864,49 +3899,56 @@ "TARGET_COLDFIRE" { return output_xorsi3 (operands); -}) +} + [(set_attr "flags_valid" "set")]) (define_insn "xorhi3" [(set (match_operand:HI 0 "nonimmediate_operand" "=dm") (xor:HI (match_operand:HI 1 "general_operand" "%0") (match_operand:HI 2 "general_operand" "dn")))] "!TARGET_COLDFIRE" - "eor%.w %2,%0") + "eor%.w %2,%0" + [(set_attr "flags_valid" "yes")]) (define_insn "" [(set (strict_low_part (match_operand:HI 0 "nonimmediate_operand" "+dm")) (xor:HI (match_dup 0) (match_operand:HI 1 "general_operand" "dn")))] "!TARGET_COLDFIRE" - "eor%.w %1,%0") + "eor%.w %1,%0" + [(set_attr "flags_valid" "yes")]) (define_insn "" [(set (strict_low_part (match_operand:HI 0 "nonimmediate_operand" "+dm")) (xor:HI (match_operand:HI 1 "general_operand" "dn") (match_dup 0)))] "!TARGET_COLDFIRE" - "eor%.w %1,%0") + "eor%.w %1,%0" + [(set_attr "flags_valid" "yes")]) (define_insn "xorqi3" [(set (match_operand:QI 0 "nonimmediate_operand" "=dm") (xor:QI (match_operand:QI 1 "general_operand" "%0") (match_operand:QI 2 "general_operand" "dn")))] "!TARGET_COLDFIRE" - "eor%.b %2,%0") + "eor%.b %2,%0" + [(set_attr "flags_valid" "yes")]) (define_insn "" [(set (strict_low_part (match_operand:QI 0 "nonimmediate_operand" "+dm")) (xor:QI (match_dup 0) (match_operand:QI 1 "general_operand" "dn")))] "!TARGET_COLDFIRE" - "eor%.b %1,%0") + "eor%.b %1,%0" + [(set_attr "flags_valid" "yes")]) (define_insn "" [(set (strict_low_part (match_operand:QI 0 "nonimmediate_operand" "+dm")) (xor:QI (match_operand:QI 1 "general_operand" "dn") (match_dup 0)))] "!TARGET_COLDFIRE" - "eor%.b %1,%0") + "eor%.b %1,%0" + [(set_attr "flags_valid" "yes")]) ;; negation instructions @@ -3965,38 +4007,44 @@ (neg:SI (match_operand:SI 1 "general_operand" "0")))] "!TARGET_COLDFIRE" "neg%.l %0" - [(set_attr "type" "neg_l")]) + [(set_attr "type" "neg_l") + (set_attr "flags_valid" "noov")]) (define_insn "negsi2_5200" [(set (match_operand:SI 0 "nonimmediate_operand" "=d") (neg:SI (match_operand:SI 1 "general_operand" "0")))] "TARGET_COLDFIRE" "neg%.l %0" - [(set_attr "type" "neg_l")]) + [(set_attr "type" "neg_l") + (set_attr "flags_valid" "noov")]) (define_insn "neghi2" [(set (match_operand:HI 0 "nonimmediate_operand" "=dm") (neg:HI (match_operand:HI 1 "general_operand" "0")))] "!TARGET_COLDFIRE" - "neg%.w %0") + "neg%.w %0" + [(set_attr "flags_valid" "noov")]) (define_insn "" [(set (strict_low_part (match_operand:HI 0 "nonimmediate_operand" "+dm")) (neg:HI (match_dup 0)))] "!TARGET_COLDFIRE" - "neg%.w %0") + "neg%.w %0" + [(set_attr "flags_valid" "noov")]) (define_insn "negqi2" [(set (match_operand:QI 0 "nonimmediate_operand" "=dm") (neg:QI (match_operand:QI 1 "general_operand" "0")))] "!TARGET_COLDFIRE" - "neg%.b %0") + "neg%.b %0" + [(set_attr "flags_valid" "noov")]) (define_insn "" [(set (strict_low_part (match_operand:QI 0 "nonimmediate_operand" "+dm")) (neg:QI (match_dup 0)))] "!TARGET_COLDFIRE" - "neg%.b %0") + "neg%.b %0" + [(set_attr "flags_valid" "noov")]) ;; If using software floating point, just flip the sign bit. @@ -4290,20 +4338,14 @@ [(set (match_operand:SI 0 "register_operand" "=d") (clz:SI (match_operand:SI 1 "general_operand" "do")))] "TARGET_68020 && TARGET_BITFIELD" -{ - CC_STATUS_INIT; - return "bfffo %1{#0:#0},%0"; -}) + "bfffo %1{#0:#0},%0") ;; ColdFire ff1 instruction implements clz. (define_insn "*clzsi2_cf" [(set (match_operand:SI 0 "register_operand" "=d") (clz:SI (match_operand:SI 1 "register_operand" "0")))] "ISA_HAS_FF1" -{ - CC_STATUS_INIT; - return "ff1 %0"; -} + "ff1 %0" [(set_attr "type" "ext")]) ;; one complement instructions @@ -4324,7 +4366,8 @@ [(set (match_operand:SI 0 "nonimmediate_operand" "=dm") (not:SI (match_operand:SI 1 "general_operand" "0")))] "!TARGET_COLDFIRE" - "not%.l %0") + "not%.l %0" + [(set_attr "flags_valid" "yes")]) (define_insn "one_cmplsi2_5200" [(set (match_operand:SI 0 "nonimmediate_operand" "=d") @@ -4337,25 +4380,29 @@ [(set (match_operand:HI 0 "nonimmediate_operand" "=dm") (not:HI (match_operand:HI 1 "general_operand" "0")))] "!TARGET_COLDFIRE" - "not%.w %0") + "not%.w %0" + [(set_attr "flags_valid" "yes")]) (define_insn "" [(set (strict_low_part (match_operand:HI 0 "nonimmediate_operand" "+dm")) (not:HI (match_dup 0)))] "!TARGET_COLDFIRE" - "not%.w %0") + "not%.w %0" + [(set_attr "flags_valid" "yes")]) (define_insn "one_cmplqi2" [(set (match_operand:QI 0 "nonimmediate_operand" "=dm") (not:QI (match_operand:QI 1 "general_operand" "0")))] "!TARGET_COLDFIRE" - "not%.b %0") + "not%.b %0" + [(set_attr "flags_valid" "yes")]) (define_insn "" [(set (strict_low_part (match_operand:QI 0 "nonimmediate_operand" "+dm")) (not:QI (match_dup 0)))] "!TARGET_COLDFIRE" - "not%.b %0") + "not%.b %0" + [(set_attr "flags_valid" "yes")]) ;; arithmetic shift instructions ;; We don't need the shift memory by 1 bit instruction @@ -4379,7 +4426,6 @@ (clobber (match_scratch:SI 2 "=a,X"))] "" { - CC_STATUS_INIT; if (GET_CODE (operands[0]) == MEM) { if (GET_CODE (XEXP (operands[0], 0)) == PRE_DEC) @@ -4577,13 +4623,10 @@ (ashift:SI (match_operand:SI 1 "register_operand" "0") (const_int 16)))] "!TUNE_68060" -{ - CC_STATUS_INIT; - return "swap %0\;clr%.w %0"; -}) + "swap %0\;clr%.w %0") ;; ashift patterns : use lsl instead of asl, because lsl always clears the -;; overflow bit, so we must not set CC_NO_OVERFLOW. +;; overflow bit, allowing more comparisons. ;; On the 68000, this makes faster code in a special case. @@ -4595,8 +4638,6 @@ && INTVAL (operands[2]) > 16 && INTVAL (operands[2]) <= 24" { - CC_STATUS_INIT; - operands[2] = GEN_INT (INTVAL (operands[2]) - 16); return "lsl%.w %2,%0\;swap %0\;clr%.w %0"; }) @@ -4608,40 +4649,45 @@ "" { if (operands[2] == const1_rtx) - { - cc_status.flags = CC_NO_OVERFLOW; - return "add%.l %0,%0"; - } + return "add%.l %0,%0"; return "lsl%.l %2,%0"; -}) +} + [(set (attr "flags_valid") + (if_then_else (match_operand 2 "const1_operand") + (const_string "noov") + (const_string "yes")))]) (define_insn "ashlhi3" [(set (match_operand:HI 0 "register_operand" "=d") (ashift:HI (match_operand:HI 1 "register_operand" "0") (match_operand:HI 2 "general_operand" "dI")))] "!TARGET_COLDFIRE" - "lsl%.w %2,%0") + "lsl%.w %2,%0" + [(set_attr "flags_valid" "yes")]) (define_insn "" [(set (strict_low_part (match_operand:HI 0 "register_operand" "+d")) (ashift:HI (match_dup 0) (match_operand:HI 1 "general_operand" "dI")))] "!TARGET_COLDFIRE" - "lsl%.w %1,%0") + "lsl%.w %1,%0" + [(set_attr "flags_valid" "yes")]) (define_insn "ashlqi3" [(set (match_operand:QI 0 "register_operand" "=d") (ashift:QI (match_operand:QI 1 "register_operand" "0") (match_operand:QI 2 "general_operand" "dI")))] "!TARGET_COLDFIRE" - "lsl%.b %2,%0") + "lsl%.b %2,%0" + [(set_attr "flags_valid" "yes")]) (define_insn "" [(set (strict_low_part (match_operand:QI 0 "register_operand" "+d")) (ashift:QI (match_dup 0) (match_operand:QI 1 "general_operand" "dI")))] "!TARGET_COLDFIRE" - "lsl%.b %1,%0") + "lsl%.b %1,%0" + [(set_attr "flags_valid" "yes")]) ;; On most 68k models, this makes faster code in a special case. @@ -4695,7 +4741,6 @@ "!TARGET_COLDFIRE" { operands[1] = gen_rtx_REG (SImode, REGNO (operands[0]) + 1); - CC_STATUS_INIT; return "asr%.l #1,%0\;roxr%.l #1,%1"; }) @@ -4761,7 +4806,6 @@ (const_int 32)))] "" { - CC_STATUS_INIT; if (TARGET_68020) return "move%.l %1,%R0\;smi %0\;extb%.l %0"; else @@ -4775,7 +4819,6 @@ (clobber (match_scratch:SI 2 "=d,d"))] "" { - CC_STATUS_INIT; operands[3] = adjust_address (operands[0], SImode, which_alternative == 0 ? 4 : 0); operands[0] = adjust_address (operands[0], SImode, 0); @@ -4808,7 +4851,6 @@ || (INTVAL (operands[2]) > 32 && INTVAL (operands[2]) <= 63))" { operands[1] = gen_rtx_REG (SImode, REGNO (operands[0]) + 1); - CC_STATUS_INIT; if (INTVAL (operands[2]) == 48) return "swap %0\;ext%.l %0\;move%.l %0,%1\;smi %0\;ext%.w %0"; if (INTVAL (operands[2]) == 31) @@ -4858,35 +4900,40 @@ "" "asr%.l %2,%0" [(set_attr "type" "shift") - (set_attr "opy" "2")]) + (set_attr "opy" "2") + (set_attr "flags_valid" "noov")]) (define_insn "ashrhi3" [(set (match_operand:HI 0 "register_operand" "=d") (ashiftrt:HI (match_operand:HI 1 "register_operand" "0") (match_operand:HI 2 "general_operand" "dI")))] "!TARGET_COLDFIRE" - "asr%.w %2,%0") + "asr%.w %2,%0" + [(set_attr "flags_valid" "noov")]) (define_insn "" [(set (strict_low_part (match_operand:HI 0 "register_operand" "+d")) (ashiftrt:HI (match_dup 0) (match_operand:HI 1 "general_operand" "dI")))] "!TARGET_COLDFIRE" - "asr%.w %1,%0") + "asr%.w %1,%0" + [(set_attr "flags_valid" "noov")]) (define_insn "ashrqi3" [(set (match_operand:QI 0 "register_operand" "=d") (ashiftrt:QI (match_operand:QI 1 "register_operand" "0") (match_operand:QI 2 "general_operand" "dI")))] "!TARGET_COLDFIRE" - "asr%.b %2,%0") + "asr%.b %2,%0" + [(set_attr "flags_valid" "noov")]) (define_insn "" [(set (strict_low_part (match_operand:QI 0 "register_operand" "+d")) (ashiftrt:QI (match_dup 0) (match_operand:QI 1 "general_operand" "dI")))] "!TARGET_COLDFIRE" - "asr%.b %1,%0") + "asr%.b %1,%0" + [(set_attr "flags_valid" "noov")]) ;; logical shift instructions @@ -4933,7 +4980,6 @@ (const_int 1)))] "!TARGET_COLDFIRE" { - CC_STATUS_INIT; return "lsr%.l #1,%0\;roxr%.l #1,%R0"; }) @@ -5131,7 +5177,6 @@ (const_int 16)))] "!TUNE_68060" { - CC_STATUS_INIT; return "clr%.w %0\;swap %0"; }) @@ -5157,35 +5202,40 @@ "" "lsr%.l %2,%0" [(set_attr "type" "shift") - (set_attr "opy" "2")]) + (set_attr "opy" "2") + (set_attr "flags_valid" "yes")]) (define_insn "lshrhi3" [(set (match_operand:HI 0 "register_operand" "=d") (lshiftrt:HI (match_operand:HI 1 "register_operand" "0") (match_operand:HI 2 "general_operand" "dI")))] "!TARGET_COLDFIRE" - "lsr%.w %2,%0") + "lsr%.w %2,%0" + [(set_attr "flags_valid" "yes")]) (define_insn "" [(set (strict_low_part (match_operand:HI 0 "register_operand" "+d")) (lshiftrt:HI (match_dup 0) (match_operand:HI 1 "general_operand" "dI")))] "!TARGET_COLDFIRE" - "lsr%.w %1,%0") + "lsr%.w %1,%0" + [(set_attr "flags_valid" "yes")]) (define_insn "lshrqi3" [(set (match_operand:QI 0 "register_operand" "=d") (lshiftrt:QI (match_operand:QI 1 "register_operand" "0") (match_operand:QI 2 "general_operand" "dI")))] "!TARGET_COLDFIRE" - "lsr%.b %2,%0") + "lsr%.b %2,%0" + [(set_attr "flags_valid" "yes")]) (define_insn "" [(set (strict_low_part (match_operand:QI 0 "register_operand" "+d")) (lshiftrt:QI (match_dup 0) (match_operand:QI 1 "general_operand" "dI")))] "!TARGET_COLDFIRE" - "lsr%.b %1,%0") + "lsr%.b %1,%0" + [(set_attr "flags_valid" "yes")]) ;; rotate instructions @@ -5195,7 +5245,8 @@ (const_int 16)))] "" "swap %0" - [(set_attr "type" "shift")]) + [(set_attr "type" "shift") + (set_attr "flags_valid" "yes")]) (define_insn "rotlsi3" [(set (match_operand:SI 0 "register_operand" "=d") @@ -5212,7 +5263,8 @@ } else return "rol%.l %2,%0"; -}) +} + [(set_attr "flags_valid" "yes")]) (define_insn "rotlhi3" [(set (match_operand:HI 0 "register_operand" "=d") @@ -5227,7 +5279,8 @@ } else return "rol%.w %2,%0"; -}) +} + [(set_attr "flags_valid" "yes")]) (define_insn "*rotlhi3_lowpart" [(set (strict_low_part (match_operand:HI 0 "register_operand" "+d")) @@ -5242,7 +5295,8 @@ } else return "rol%.w %1,%0"; -}) +} + [(set_attr "flags_valid" "yes")]) (define_insn "rotlqi3" [(set (match_operand:QI 0 "register_operand" "=d") @@ -5257,7 +5311,8 @@ } else return "rol%.b %2,%0"; -}) +} + [(set_attr "flags_valid" "yes")]) (define_insn "*rotlqi3_lowpart" [(set (strict_low_part (match_operand:QI 0 "register_operand" "+d")) @@ -5272,14 +5327,16 @@ } else return "rol%.b %1,%0"; -}) +} + [(set_attr "flags_valid" "yes")]) (define_insn "rotrsi3" [(set (match_operand:SI 0 "register_operand" "=d") (rotatert:SI (match_operand:SI 1 "register_operand" "0") (match_operand:SI 2 "general_operand" "dI")))] "!TARGET_COLDFIRE" - "ror%.l %2,%0") + "ror%.l %2,%0" + [(set_attr "flags_valid" "yes")]) (define_insn "rotrhi3" [(set (match_operand:HI 0 "register_operand" "=d") @@ -5300,14 +5357,16 @@ (rotatert:QI (match_operand:QI 1 "register_operand" "0") (match_operand:QI 2 "general_operand" "dI")))] "!TARGET_COLDFIRE" - "ror%.b %2,%0") + "ror%.b %2,%0" + [(set_attr "flags_valid" "yes")]) (define_insn "" [(set (strict_low_part (match_operand:QI 0 "register_operand" "+d")) (rotatert:QI (match_dup 0) (match_operand:QI 1 "general_operand" "dI")))] "!TARGET_COLDFIRE" - "ror%.b %1,%0") + "ror%.b %1,%0" + [(set_attr "flags_valid" "yes")]) (define_expand "bswapsi2" [(set (match_operand:SI 0 "register_operand") @@ -5332,10 +5391,7 @@ (match_operand:SI 1 "general_operand" "d")) 3) (match_dup 0)))] "" -{ - CC_STATUS_INIT; - return "bset %1,%0"; -} + "bset %1,%0" [(set_attr "type" "bitrw")]) ;; set bit, bit number is (sign/zero)_extended from HImode/QImode @@ -5346,10 +5402,7 @@ [(match_operand 1 "general_operand" "d")])) 3) (match_dup 0)))] "" -{ - CC_STATUS_INIT; - return "bset %1,%0"; -} + "bset %1,%0" [(set_attr "type" "bitrw")]) (define_insn "*bsetdreg" @@ -5359,10 +5412,7 @@ (const_int 31))) (match_operand:SI 2 "register_operand" "0")))] "" -{ - CC_STATUS_INIT; - return "bset %1,%0"; -} + "bset %1,%0" [(set_attr "type" "bitrw")]) (define_insn "*bchgdreg" @@ -5372,10 +5422,7 @@ (const_int 31))) (match_operand:SI 2 "register_operand" "0")))] "" -{ - CC_STATUS_INIT; - return "bchg %1,%0"; -} + "bchg %1,%0" [(set_attr "type" "bitrw")]) (define_insn "*bclrdreg" @@ -5385,10 +5432,7 @@ (const_int 31))) (match_operand:SI 2 "register_operand" "0")))] "" -{ - CC_STATUS_INIT; - return "bclr %1,%0"; -} + "bclr %1,%0" [(set_attr "type" "bitrw")]) ;; clear bit, bit number is int @@ -5399,10 +5443,7 @@ (match_operand:SI 1 "general_operand" "d"))) (const_int 0))] "" -{ - CC_STATUS_INIT; - return "bclr %1,%0"; -} + "bclr %1,%0" [(set_attr "type" "bitrw")]) ;; clear bit, bit number is (sign/zero)_extended from HImode/QImode @@ -5414,10 +5455,7 @@ [(match_operand 1 "general_operand" "d")]))) (const_int 0))] "" -{ - CC_STATUS_INIT; - return "bclr %1,%0"; -} + "bclr %1,%0" [(set_attr "type" "bitrw")]) ;; Special cases of bit-field insns which we should @@ -5500,7 +5538,6 @@ && (INTVAL (operands[2]) == 8 || INTVAL (operands[2]) == 16) && INTVAL (operands[3]) % INTVAL (operands[2]) == 0" { - cc_status.flags |= CC_NOT_NEGATIVE; if (INTVAL (operands[2]) + INTVAL (operands[3]) != 32) return "bfextu %1{%b3:%b2},%0"; @@ -5576,1125 +5613,177 @@ (zero_extract:SI (match_operand:SI 1 "general_operand" "") (match_operand:SI 2 "const_int_operand" "") (match_operand:SI 3 "const_int_operand" "")))] - "TARGET_68020 && TARGET_BITFIELD" - "") - -(define_insn "*extzv_bfextu_mem" - [(set (match_operand:SI 0 "register_operand" "=d") - (zero_extract:SI (match_operand:QI 1 "memory_operand" "o") - (match_operand:SI 2 "nonmemory_operand" "dn") - (match_operand:SI 3 "nonmemory_operand" "dn")))] - "TARGET_68020 && TARGET_BITFIELD" -{ - if (GET_CODE (operands[2]) == CONST_INT) - { - if (INTVAL (operands[2]) != 32) - cc_status.flags |= CC_NOT_NEGATIVE; - } - else - { - CC_STATUS_INIT; - } - return "bfextu %1{%b3:%b2},%0"; -}) - -(define_insn "*insv_bfchg_mem" - [(set (zero_extract:SI (match_operand:QI 0 "memory_operand" "+o") - (match_operand:SI 1 "nonmemory_operand" "dn") - (match_operand:SI 2 "nonmemory_operand" "dn")) - (xor:SI (zero_extract:SI (match_dup 0) (match_dup 1) (match_dup 2)) - (match_operand 3 "const_int_operand" "n")))] - "TARGET_68020 && TARGET_BITFIELD - && (INTVAL (operands[3]) == -1 - || (GET_CODE (operands[1]) == CONST_INT - && (~ INTVAL (operands[3]) & ((1 << INTVAL (operands[1]))- 1)) == 0))" -{ - CC_STATUS_INIT; - return "bfchg %0{%b2:%b1}"; -}) - -(define_insn "*insv_bfclr_mem" - [(set (zero_extract:SI (match_operand:QI 0 "memory_operand" "+o") - (match_operand:SI 1 "nonmemory_operand" "dn") - (match_operand:SI 2 "nonmemory_operand" "dn")) - (const_int 0))] - "TARGET_68020 && TARGET_BITFIELD" -{ - CC_STATUS_INIT; - return "bfclr %0{%b2:%b1}"; -}) - -(define_insn "*insv_bfset_mem" - [(set (zero_extract:SI (match_operand:QI 0 "memory_operand" "+o") - (match_operand:SI 1 "general_operand" "dn") - (match_operand:SI 2 "general_operand" "dn")) - (const_int -1))] - "TARGET_68020 && TARGET_BITFIELD" -{ - CC_STATUS_INIT; - return "bfset %0{%b2:%b1}"; -}) - -(define_expand "insv" - [(set (zero_extract:SI (match_operand:SI 0 "nonimmediate_operand" "") - (match_operand:SI 1 "const_int_operand" "") - (match_operand:SI 2 "const_int_operand" "")) - (match_operand:SI 3 "reg_or_pow2_m1_operand" ""))] - "TARGET_68020 && TARGET_BITFIELD" - " -{ - /* Special case initializing a field to all ones. */ - if (GET_CODE (operands[3]) == CONST_INT) - { - if (exact_log2 (INTVAL (operands[3]) + 1) != INTVAL (operands[1])) - operands[3] = force_reg (SImode, operands[3]); - else - operands[3] = constm1_rtx; - - } -}") - -(define_insn "*insv_bfins_mem" - [(set (zero_extract:SI (match_operand:QI 0 "memory_operand" "+o") - (match_operand:SI 1 "nonmemory_operand" "dn") - (match_operand:SI 2 "nonmemory_operand" "dn")) - (match_operand:SI 3 "register_operand" "d"))] - "TARGET_68020 && TARGET_BITFIELD" - "bfins %3,%0{%b2:%b1}") - -;; Now recognize bit-field insns that operate on registers -;; (or at least were intended to do so). - -(define_insn "*extv_bfexts_reg" - [(set (match_operand:SI 0 "nonimmediate_operand" "=d") - (sign_extract:SI (match_operand:SI 1 "register_operand" "d") - (match_operand:SI 2 "const_int_operand" "n") - (match_operand:SI 3 "const_int_operand" "n")))] - "TARGET_68020 && TARGET_BITFIELD && IN_RANGE (INTVAL (operands[3]), 0, 31)" - "bfexts %1{%b3:%b2},%0") - -(define_insn "*extv_bfextu_reg" - [(set (match_operand:SI 0 "nonimmediate_operand" "=d") - (zero_extract:SI (match_operand:SI 1 "register_operand" "d") - (match_operand:SI 2 "const_int_operand" "n") - (match_operand:SI 3 "const_int_operand" "n")))] - "TARGET_68020 && TARGET_BITFIELD && IN_RANGE (INTVAL (operands[3]), 0, 31)" -{ - if (GET_CODE (operands[2]) == CONST_INT) - { - if (INTVAL (operands[2]) != 32) - cc_status.flags |= CC_NOT_NEGATIVE; - } - else - { - CC_STATUS_INIT; - } - return "bfextu %1{%b3:%b2},%0"; -}) - -(define_insn "*insv_bfclr_reg" - [(set (zero_extract:SI (match_operand:SI 0 "register_operand" "+d") - (match_operand:SI 1 "const_int_operand" "n") - (match_operand:SI 2 "const_int_operand" "n")) - (const_int 0))] - "TARGET_68020 && TARGET_BITFIELD && IN_RANGE (INTVAL (operands[2]), 0, 31)" -{ - CC_STATUS_INIT; - return "bfclr %0{%b2:%b1}"; -}) - -(define_insn "*insv_bfset_reg" - [(set (zero_extract:SI (match_operand:SI 0 "register_operand" "+d") - (match_operand:SI 1 "const_int_operand" "n") - (match_operand:SI 2 "const_int_operand" "n")) - (const_int -1))] - "TARGET_68020 && TARGET_BITFIELD && IN_RANGE (INTVAL (operands[2]), 0, 31)" -{ - CC_STATUS_INIT; - return "bfset %0{%b2:%b1}"; -}) - -(define_insn "*insv_bfins_reg" - [(set (zero_extract:SI (match_operand:SI 0 "register_operand" "+d") - (match_operand:SI 1 "const_int_operand" "n") - (match_operand:SI 2 "const_int_operand" "n")) - (match_operand:SI 3 "register_operand" "d"))] - "TARGET_68020 && TARGET_BITFIELD && IN_RANGE (INTVAL (operands[2]), 0, 31)" -{ -#if 0 - /* These special cases are now recognized by a specific pattern. */ - if (GET_CODE (operands[1]) == CONST_INT && GET_CODE (operands[2]) == CONST_INT - && INTVAL (operands[1]) == 16 && INTVAL (operands[2]) == 16) - return "move%.w %3,%0"; - if (GET_CODE (operands[1]) == CONST_INT && GET_CODE (operands[2]) == CONST_INT - && INTVAL (operands[1]) == 24 && INTVAL (operands[2]) == 8) - return "move%.b %3,%0"; -#endif - return "bfins %3,%0{%b2:%b1}"; -}) - -;; Special patterns for optimizing bit-field instructions. - -(define_insn "*tst_bftst_mem" - [(set (cc0) - (compare (zero_extract:SI (match_operand:QI 0 "memory_operand" "o") - (match_operand:SI 1 "const_int_operand" "n") - (match_operand:SI 2 "general_operand" "dn")) - (const_int 0)))] - "TARGET_68020 && TARGET_BITFIELD" -{ - if (operands[1] == const1_rtx - && GET_CODE (operands[2]) == CONST_INT) - { - int width = GET_CODE (operands[0]) == REG ? 31 : 7; - return output_btst (operands, - GEN_INT (width - INTVAL (operands[2])), - operands[0], insn, 1000); - /* Pass 1000 as SIGNPOS argument so that btst will - not think we are testing the sign bit for an `and' - and assume that nonzero implies a negative result. */ - } - if (INTVAL (operands[1]) != 32) - cc_status.flags = CC_NOT_NEGATIVE; - return "bftst %0{%b2:%b1}"; -}) - - -;;; now handle the register cases -(define_insn "*tst_bftst_reg" - [(set (cc0) - (compare (zero_extract:SI (match_operand:SI 0 "register_operand" "d") - (match_operand:SI 1 "const_int_operand" "n") - (match_operand:SI 2 "general_operand" "dn")) - (const_int 0)))] - "TARGET_68020 && TARGET_BITFIELD - && !(CONST_INT_P (operands[2]) && !IN_RANGE (INTVAL (operands[2]), 0, 31))" -{ - if (operands[1] == const1_rtx - && GET_CODE (operands[2]) == CONST_INT) - { - int width = GET_CODE (operands[0]) == REG ? 31 : 7; - return output_btst (operands, GEN_INT (width - INTVAL (operands[2])), - operands[0], insn, 1000); - /* Pass 1000 as SIGNPOS argument so that btst will - not think we are testing the sign bit for an `and' - and assume that nonzero implies a negative result. */ - } - if (INTVAL (operands[1]) != 32) - cc_status.flags = CC_NOT_NEGATIVE; - return "bftst %0{%b2:%b1}"; -}) - -(define_insn "scc0_di" - [(set (match_operand:QI 0 "nonimmediate_operand" "=dm") - (match_operator 1 "ordered_comparison_operator" - [(match_operand:DI 2 "general_operand" "ro") (const_int 0)]))] - "! TARGET_COLDFIRE" -{ - return output_scc_di (operands[1], operands[2], const0_rtx, operands[0]); -}) - -(define_insn "scc0_di_5200" - [(set (match_operand:QI 0 "nonimmediate_operand" "=d") - (match_operator 1 "ordered_comparison_operator" - [(match_operand:DI 2 "general_operand" "ro") (const_int 0)]))] - "TARGET_COLDFIRE" -{ - return output_scc_di (operands[1], operands[2], const0_rtx, operands[0]); -}) - -(define_insn "scc_di" - [(set (match_operand:QI 0 "nonimmediate_operand" "=dm,dm") - (match_operator 1 "ordered_comparison_operator" - [(match_operand:DI 2 "general_operand" "ro,r") - (match_operand:DI 3 "general_operand" "r,ro")]))] - "! TARGET_COLDFIRE" -{ - return output_scc_di (operands[1], operands[2], operands[3], operands[0]); -}) - -(define_insn "scc_di_5200" - [(set (match_operand:QI 0 "nonimmediate_operand" "=d,d") - (match_operator 1 "ordered_comparison_operator" - [(match_operand:DI 2 "general_operand" "ro,r") - (match_operand:DI 3 "general_operand" "r,ro")]))] - "TARGET_COLDFIRE" -{ - return output_scc_di (operands[1], operands[2], operands[3], operands[0]); -}) - -;; Note that operand 0 of an SCC insn is supported in the hardware as -;; memory, but we cannot allow it to be in memory in case the address -;; needs to be reloaded. - -(define_insn "" - [(set (match_operand:QI 0 "register_operand" "=d") - (eq:QI (cc0) (const_int 0)))] - "" -{ - cc_status = cc_prev_status; - OUTPUT_JUMP ("seq %0", "fseq %0", "seq %0"); -}) - -(define_insn "" - [(set (match_operand:QI 0 "register_operand" "=d") - (ne:QI (cc0) (const_int 0)))] - "" -{ - cc_status = cc_prev_status; - OUTPUT_JUMP ("sne %0", "fsne %0", "sne %0"); -}) - -(define_insn "" - [(set (match_operand:QI 0 "register_operand" "=d") - (gt:QI (cc0) (const_int 0)))] - "" -{ - cc_status = cc_prev_status; - OUTPUT_JUMP ("sgt %0", "fsgt %0", 0); -}) - -(define_insn "" - [(set (match_operand:QI 0 "register_operand" "=d") - (gtu:QI (cc0) (const_int 0)))] - "" -{ - cc_status = cc_prev_status; - return "shi %0"; -}) - -(define_insn "" - [(set (match_operand:QI 0 "register_operand" "=d") - (lt:QI (cc0) (const_int 0)))] - "" -{ - cc_status = cc_prev_status; - OUTPUT_JUMP ("slt %0", "fslt %0", "smi %0"); -}) - -(define_insn "" - [(set (match_operand:QI 0 "register_operand" "=d") - (ltu:QI (cc0) (const_int 0)))] - "" -{ - cc_status = cc_prev_status; - return "scs %0"; -}) - -(define_insn "" - [(set (match_operand:QI 0 "register_operand" "=d") - (ge:QI (cc0) (const_int 0)))] - "" -{ - cc_status = cc_prev_status; - OUTPUT_JUMP ("sge %0", "fsge %0", "spl %0"); -}) - -(define_insn "*scc" - [(set (match_operand:QI 0 "register_operand" "=d") - (geu:QI (cc0) (const_int 0)))] - "" -{ - cc_status = cc_prev_status; - return "scc %0"; -} - [(set_attr "type" "scc")]) - -(define_insn "" - [(set (match_operand:QI 0 "register_operand" "=d") - (le:QI (cc0) (const_int 0)))] - "" -{ - cc_status = cc_prev_status; - OUTPUT_JUMP ("sle %0", "fsle %0", 0); -}) - -(define_insn "*sls" - [(set (match_operand:QI 0 "register_operand" "=d") - (leu:QI (cc0) (const_int 0)))] - "" -{ - cc_status = cc_prev_status; - return "sls %0"; -} - [(set_attr "type" "scc")]) - -(define_insn "*sordered_1" - [(set (match_operand:QI 0 "register_operand" "=d") - (ordered:QI (cc0) (const_int 0)))] - "TARGET_68881 && !TUNE_68060" -{ - cc_status = cc_prev_status; - return "fsor %0"; -}) - -(define_insn "*sunordered_1" - [(set (match_operand:QI 0 "register_operand" "=d") - (unordered:QI (cc0) (const_int 0)))] - "TARGET_68881 && !TUNE_68060" -{ - cc_status = cc_prev_status; - return "fsun %0"; -}) - -(define_insn "*suneq_1" - [(set (match_operand:QI 0 "register_operand" "=d") - (uneq:QI (cc0) (const_int 0)))] - "TARGET_68881 && !TUNE_68060" -{ - cc_status = cc_prev_status; - return "fsueq %0"; -}) - -(define_insn "*sunge_1" - [(set (match_operand:QI 0 "register_operand" "=d") - (unge:QI (cc0) (const_int 0)))] - "TARGET_68881 && !TUNE_68060" -{ - cc_status = cc_prev_status; - return "fsuge %0"; -}) - -(define_insn "*sungt_1" - [(set (match_operand:QI 0 "register_operand" "=d") - (ungt:QI (cc0) (const_int 0)))] - "TARGET_68881 && !TUNE_68060" -{ - cc_status = cc_prev_status; - return "fsugt %0"; -}) - -(define_insn "*sunle_1" - [(set (match_operand:QI 0 "register_operand" "=d") - (unle:QI (cc0) (const_int 0)))] - "TARGET_68881 && !TUNE_68060" -{ - cc_status = cc_prev_status; - return "fsule %0"; -}) - -(define_insn "*sunlt_1" - [(set (match_operand:QI 0 "register_operand" "=d") - (unlt:QI (cc0) (const_int 0)))] - "TARGET_68881 && !TUNE_68060" -{ - cc_status = cc_prev_status; - return "fsult %0"; -}) - -(define_insn "*sltgt_1" - [(set (match_operand:QI 0 "register_operand" "=d") - (ltgt:QI (cc0) (const_int 0)))] - "TARGET_68881 && !TUNE_68060" -{ - cc_status = cc_prev_status; - return "fsogl %0"; -}) - -(define_insn "*fsogt_1" - [(set (match_operand:QI 0 "register_operand" "=d") - (not:QI (unle:QI (cc0) (const_int 0))))] - "TARGET_68881 && !TUNE_68060" -{ - cc_status = cc_prev_status; - return "fsogt %0"; -}) - -(define_insn "*fsoge_1" - [(set (match_operand:QI 0 "register_operand" "=d") - (not:QI (unlt:QI (cc0) (const_int 0))))] - "TARGET_68881 && !TUNE_68060" -{ - cc_status = cc_prev_status; - return "fsoge %0"; -}) - -(define_insn "*fsolt_1" - [(set (match_operand:QI 0 "register_operand" "=d") - (not:QI (unge:QI (cc0) (const_int 0))))] - "TARGET_68881 && !TUNE_68060" -{ - cc_status = cc_prev_status; - return "fsolt %0"; -}) - -(define_insn "*fsole_1" - [(set (match_operand:QI 0 "register_operand" "=d") - (not:QI (ungt:QI (cc0) (const_int 0))))] - "TARGET_68881 && !TUNE_68060" -{ - cc_status = cc_prev_status; - return "fsole %0"; -}) - -;; Basic conditional jump instructions. - -(define_insn "beq0_di" - [(set (pc) - (if_then_else (eq (match_operand:DI 0 "general_operand" "d*a,o,<>") - (const_int 0)) - (label_ref (match_operand 1 "" ",,")) - (pc))) - (clobber (match_scratch:SI 2 "=d,&d,d"))] - "" -{ - CC_STATUS_INIT; - if (which_alternative == 2) - return "move%.l %0,%2\;or%.l %0,%2\;jeq %l1"; - if ((cc_prev_status.value1 - && rtx_equal_p (cc_prev_status.value1, operands[0])) - || (cc_prev_status.value2 - && rtx_equal_p (cc_prev_status.value2, operands[0]))) - { - cc_status = cc_prev_status; - return "jeq %l1"; - } - if (GET_CODE (operands[0]) == REG) - operands[3] = gen_rtx_REG (SImode, REGNO (operands[0]) + 1); - else - operands[3] = adjust_address (operands[0], SImode, 4); - if (! ADDRESS_REG_P (operands[0])) - { - if (reg_overlap_mentioned_p (operands[2], operands[0])) - { - if (reg_overlap_mentioned_p (operands[2], operands[3])) - return "or%.l %0,%2\;jeq %l1"; - else - return "or%.l %3,%2\;jeq %l1"; - } - return "move%.l %0,%2\;or%.l %3,%2\;jeq %l1"; - } - operands[4] = gen_label_rtx(); - if (TARGET_68020 || TARGET_COLDFIRE) - output_asm_insn ("tst%.l %0\;jne %l4\;tst%.l %3\;jeq %l1", operands); - else - output_asm_insn ("cmp%.w #0,%0\;jne %l4\;cmp%.w #0,%3\;jeq %l1", operands); - (*targetm.asm_out.internal_label) (asm_out_file, "L", - CODE_LABEL_NUMBER (operands[4])); - return ""; -}) - -(define_insn "bne0_di" - [(set (pc) - (if_then_else (ne (match_operand:DI 0 "general_operand" "d,o,*a") - (const_int 0)) - (label_ref (match_operand 1 "" ",,")) - (pc))) - (clobber (match_scratch:SI 2 "=d,&d,X"))] - "" -{ - if ((cc_prev_status.value1 - && rtx_equal_p (cc_prev_status.value1, operands[0])) - || (cc_prev_status.value2 - && rtx_equal_p (cc_prev_status.value2, operands[0]))) - { - cc_status = cc_prev_status; - return "jne %l1"; - } - CC_STATUS_INIT; - if (GET_CODE (operands[0]) == REG) - operands[3] = gen_rtx_REG (SImode, REGNO (operands[0]) + 1); - else - operands[3] = adjust_address (operands[0], SImode, 4); - if (!ADDRESS_REG_P (operands[0])) - { - if (reg_overlap_mentioned_p (operands[2], operands[0])) - { - if (reg_overlap_mentioned_p (operands[2], operands[3])) - return "or%.l %0,%2\;jne %l1"; - else - return "or%.l %3,%2\;jne %l1"; - } - return "move%.l %0,%2\;or%.l %3,%2\;jne %l1"; - } - if (TARGET_68020 || TARGET_COLDFIRE) - return "tst%.l %0\;jne %l1\;tst%.l %3\;jne %l1"; - else - return "cmp%.w #0,%0\;jne %l1\;cmp%.w #0,%3\;jne %l1"; -}) - -(define_insn "bge0_di" - [(set (pc) - (if_then_else (ge (match_operand:DI 0 "general_operand" "ro") - (const_int 0)) - (label_ref (match_operand 1 "" "")) - (pc)))] - "" -{ - if ((cc_prev_status.value1 - && rtx_equal_p (cc_prev_status.value1, operands[0])) - || (cc_prev_status.value2 - && rtx_equal_p (cc_prev_status.value2, operands[0]))) - { - cc_status = cc_prev_status; - return cc_status.flags & CC_REVERSED ? "jle %l1" : "jpl %l1"; - } - CC_STATUS_INIT; - if (TARGET_68020 || TARGET_COLDFIRE || ! ADDRESS_REG_P (operands[0])) - output_asm_insn("tst%.l %0", operands); - else - { - /* On an address reg, cmpw may replace cmpl. */ - output_asm_insn("cmp%.w #0,%0", operands); - } - return "jpl %l1"; -}) - -(define_insn "blt0_di" - [(set (pc) - (if_then_else (lt (match_operand:DI 0 "general_operand" "ro") - (const_int 0)) - (label_ref (match_operand 1 "" "")) - (pc)))] - "" -{ - if ((cc_prev_status.value1 - && rtx_equal_p (cc_prev_status.value1, operands[0])) - || (cc_prev_status.value2 - && rtx_equal_p (cc_prev_status.value2, operands[0]))) - { - cc_status = cc_prev_status; - return cc_status.flags & CC_REVERSED ? "jgt %l1" : "jmi %l1"; - } - CC_STATUS_INIT; - if (TARGET_68020 || TARGET_COLDFIRE || ! ADDRESS_REG_P (operands[0])) - output_asm_insn("tst%.l %0", operands); - else - { - /* On an address reg, cmpw may replace cmpl. */ - output_asm_insn("cmp%.w #0,%0", operands); - } - return "jmi %l1"; -}) - -(define_insn "beq" - [(set (pc) - (if_then_else (eq (cc0) - (const_int 0)) - (label_ref (match_operand 0 "" "")) - (pc)))] - "" -{ - OUTPUT_JUMP ("jeq %l0", "fjeq %l0", "jeq %l0"); -} - [(set_attr "type" "bcc")]) - -(define_insn "bne" - [(set (pc) - (if_then_else (ne (cc0) - (const_int 0)) - (label_ref (match_operand 0 "" "")) - (pc)))] - "" -{ - OUTPUT_JUMP ("jne %l0", "fjne %l0", "jne %l0"); -} - [(set_attr "type" "bcc")]) - -(define_insn "bgt" - [(set (pc) - (if_then_else (gt (cc0) - (const_int 0)) - (label_ref (match_operand 0 "" "")) - (pc)))] - "" -{ - if ((cc_status.flags & CC_OVERFLOW_UNUSABLE) != 0) - { - cc_status.flags &= ~CC_OVERFLOW_UNUSABLE; - return 0; - } - - OUTPUT_JUMP ("jgt %l0", "fjgt %l0", 0); -} - [(set_attr "type" "bcc")]) - -(define_insn "bgtu" - [(set (pc) - (if_then_else (gtu (cc0) - (const_int 0)) - (label_ref (match_operand 0 "" "")) - (pc)))] - "" -{ - if ((cc_status.flags & CC_OVERFLOW_UNUSABLE) != 0) - { - cc_status.flags &= ~CC_OVERFLOW_UNUSABLE; - return 0; - } - - return "jhi %l0"; -} - [(set_attr "type" "bcc")]) - -(define_insn "blt" - [(set (pc) - (if_then_else (lt (cc0) - (const_int 0)) - (label_ref (match_operand 0 "" "")) - (pc)))] - "" -{ - if ((cc_status.flags & CC_OVERFLOW_UNUSABLE) != 0) - { - cc_status.flags &= ~CC_OVERFLOW_UNUSABLE; - return 0; - } - - OUTPUT_JUMP ("jlt %l0", "fjlt %l0", "jmi %l0"); -} - [(set_attr "type" "bcc")]) - -(define_insn "bltu" - [(set (pc) - (if_then_else (ltu (cc0) - (const_int 0)) - (label_ref (match_operand 0 "" "")) - (pc)))] - "" -{ - if ((cc_status.flags & CC_OVERFLOW_UNUSABLE) != 0) - { - cc_status.flags &= ~CC_OVERFLOW_UNUSABLE; - return 0; - } - - return "jcs %l0"; -} - [(set_attr "type" "bcc")]) - -(define_insn "bge" - [(set (pc) - (if_then_else (ge (cc0) - (const_int 0)) - (label_ref (match_operand 0 "" "")) - (pc)))] - "" -{ - if ((cc_status.flags & CC_OVERFLOW_UNUSABLE) != 0) - { - cc_status.flags &= ~CC_OVERFLOW_UNUSABLE; - return 0; - } - - OUTPUT_JUMP ("jge %l0", "fjge %l0", "jpl %l0"); -}) - -(define_insn "bgeu" - [(set (pc) - (if_then_else (geu (cc0) - (const_int 0)) - (label_ref (match_operand 0 "" "")) - (pc)))] - "" -{ - if ((cc_status.flags & CC_OVERFLOW_UNUSABLE) != 0) - { - cc_status.flags &= ~CC_OVERFLOW_UNUSABLE; - return 0; - } - - return "jcc %l0"; -} - [(set_attr "type" "bcc")]) - -(define_insn "ble" - [(set (pc) - (if_then_else (le (cc0) - (const_int 0)) - (label_ref (match_operand 0 "" "")) - (pc)))] - "" -{ - if ((cc_status.flags & CC_OVERFLOW_UNUSABLE) != 0) - { - cc_status.flags &= ~CC_OVERFLOW_UNUSABLE; - return 0; - } - - OUTPUT_JUMP ("jle %l0", "fjle %l0", 0); -} - [(set_attr "type" "bcc")]) - -(define_insn "bleu" - [(set (pc) - (if_then_else (leu (cc0) - (const_int 0)) - (label_ref (match_operand 0 "" "")) - (pc)))] - "" -{ - if ((cc_status.flags & CC_OVERFLOW_UNUSABLE) != 0) - { - cc_status.flags &= ~CC_OVERFLOW_UNUSABLE; - return 0; - } - - return "jls %l0"; -} - [(set_attr "type" "bcc")]) - -(define_insn "bordered" - [(set (pc) - (if_then_else (ordered (cc0) (const_int 0)) - (label_ref (match_operand 0 "" "")) - (pc)))] - "TARGET_HARD_FLOAT" -{ - gcc_assert (cc_prev_status.flags & CC_IN_68881); - return "fjor %l0"; -} - [(set_attr "type" "fbcc")]) - -(define_insn "bunordered" - [(set (pc) - (if_then_else (unordered (cc0) (const_int 0)) - (label_ref (match_operand 0 "" "")) - (pc)))] - "TARGET_HARD_FLOAT" -{ - gcc_assert (cc_prev_status.flags & CC_IN_68881); - return "fjun %l0"; -} - [(set_attr "type" "fbcc")]) - -(define_insn "buneq" - [(set (pc) - (if_then_else (uneq (cc0) (const_int 0)) - (label_ref (match_operand 0 "" "")) - (pc)))] - "TARGET_HARD_FLOAT" -{ - gcc_assert (cc_prev_status.flags & CC_IN_68881); - return "fjueq %l0"; -} - [(set_attr "type" "fbcc")]) - -(define_insn "bunge" - [(set (pc) - (if_then_else (unge (cc0) (const_int 0)) - (label_ref (match_operand 0 "" "")) - (pc)))] - "TARGET_HARD_FLOAT" -{ - gcc_assert (cc_prev_status.flags & CC_IN_68881); - return "fjuge %l0"; -} - [(set_attr "type" "fbcc")]) - -(define_insn "bungt" - [(set (pc) - (if_then_else (ungt (cc0) (const_int 0)) - (label_ref (match_operand 0 "" "")) - (pc)))] - "TARGET_HARD_FLOAT" -{ - gcc_assert (cc_prev_status.flags & CC_IN_68881); - return "fjugt %l0"; -} - [(set_attr "type" "fbcc")]) - -(define_insn "bunle" - [(set (pc) - (if_then_else (unle (cc0) (const_int 0)) - (label_ref (match_operand 0 "" "")) - (pc)))] - "TARGET_HARD_FLOAT" -{ - gcc_assert (cc_prev_status.flags & CC_IN_68881); - return "fjule %l0"; -} - [(set_attr "type" "fbcc")]) - -(define_insn "bunlt" - [(set (pc) - (if_then_else (unlt (cc0) (const_int 0)) - (label_ref (match_operand 0 "" "")) - (pc)))] - "TARGET_HARD_FLOAT" -{ - gcc_assert (cc_prev_status.flags & CC_IN_68881); - return "fjult %l0"; -} - [(set_attr "type" "fbcc")]) - -(define_insn "bltgt" - [(set (pc) - (if_then_else (ltgt (cc0) (const_int 0)) - (label_ref (match_operand 0 "" "")) - (pc)))] - "TARGET_HARD_FLOAT" -{ - gcc_assert (cc_prev_status.flags & CC_IN_68881); - return "fjogl %l0"; -} - [(set_attr "type" "fbcc")]) - -;; Negated conditional jump instructions. - -(define_insn "*beq_rev" - [(set (pc) - (if_then_else (eq (cc0) - (const_int 0)) - (pc) - (label_ref (match_operand 0 "" ""))))] - "" -{ - OUTPUT_JUMP ("jne %l0", "fjne %l0", "jne %l0"); -} - [(set_attr "type" "bcc")]) - -(define_insn "*bne_rev" - [(set (pc) - (if_then_else (ne (cc0) - (const_int 0)) - (pc) - (label_ref (match_operand 0 "" ""))))] - "" -{ - OUTPUT_JUMP ("jeq %l0", "fjeq %l0", "jeq %l0"); -} - [(set_attr "type" "bcc")]) - -(define_insn "*bgt_rev" - [(set (pc) - (if_then_else (gt (cc0) - (const_int 0)) - (pc) - (label_ref (match_operand 0 "" ""))))] - "" -{ - if ((cc_status.flags & CC_OVERFLOW_UNUSABLE) != 0) - { - cc_status.flags &= ~CC_OVERFLOW_UNUSABLE; - return 0; - } - - OUTPUT_JUMP ("jle %l0", "fjngt %l0", 0); -} - [(set_attr "type" "bcc")]) - -(define_insn "*bgtu_rev" - [(set (pc) - (if_then_else (gtu (cc0) - (const_int 0)) - (pc) - (label_ref (match_operand 0 "" ""))))] - "" -{ - if ((cc_status.flags & CC_OVERFLOW_UNUSABLE) != 0) - { - cc_status.flags &= ~CC_OVERFLOW_UNUSABLE; - return 0; - } - - return "jls %l0"; -} - [(set_attr "type" "bcc")]) - -(define_insn "*blt_rev" - [(set (pc) - (if_then_else (lt (cc0) - (const_int 0)) - (pc) - (label_ref (match_operand 0 "" ""))))] - "" -{ - if ((cc_status.flags & CC_OVERFLOW_UNUSABLE) != 0) - { - cc_status.flags &= ~CC_OVERFLOW_UNUSABLE; - return 0; - } - - OUTPUT_JUMP ("jge %l0", "fjnlt %l0", "jpl %l0"); -} - [(set_attr "type" "bcc")]) - -(define_insn "*bltu_rev" - [(set (pc) - (if_then_else (ltu (cc0) - (const_int 0)) - (pc) - (label_ref (match_operand 0 "" ""))))] - "" -{ - if ((cc_status.flags & CC_OVERFLOW_UNUSABLE) != 0) - { - cc_status.flags &= ~CC_OVERFLOW_UNUSABLE; - return 0; - } - - return "jcc %l0"; -} - [(set_attr "type" "bcc")]) + "TARGET_68020 && TARGET_BITFIELD" + "") -(define_insn "*bge_rev" - [(set (pc) - (if_then_else (ge (cc0) - (const_int 0)) - (pc) - (label_ref (match_operand 0 "" ""))))] - "" +(define_insn "*extzv_bfextu_mem" + [(set (match_operand:SI 0 "register_operand" "=d") + (zero_extract:SI (match_operand:QI 1 "memory_operand" "o") + (match_operand:SI 2 "nonmemory_operand" "dn") + (match_operand:SI 3 "nonmemory_operand" "dn")))] + "TARGET_68020 && TARGET_BITFIELD" { - if ((cc_status.flags & CC_OVERFLOW_UNUSABLE) != 0) - { - cc_status.flags &= ~CC_OVERFLOW_UNUSABLE; - return 0; - } + return "bfextu %1{%b3:%b2},%0"; +}) - OUTPUT_JUMP ("jlt %l0", "fjnge %l0", "jmi %l0"); -} - [(set_attr "type" "bcc")]) +(define_insn "*insv_bfchg_mem" + [(set (zero_extract:SI (match_operand:QI 0 "memory_operand" "+o") + (match_operand:SI 1 "nonmemory_operand" "dn") + (match_operand:SI 2 "nonmemory_operand" "dn")) + (xor:SI (zero_extract:SI (match_dup 0) (match_dup 1) (match_dup 2)) + (match_operand 3 "const_int_operand" "n")))] + "TARGET_68020 && TARGET_BITFIELD + && (INTVAL (operands[3]) == -1 + || (GET_CODE (operands[1]) == CONST_INT + && (~ INTVAL (operands[3]) & ((1 << INTVAL (operands[1]))- 1)) == 0))" +{ + return "bfchg %0{%b2:%b1}"; +}) -(define_insn "*bgeu_rev" - [(set (pc) - (if_then_else (geu (cc0) - (const_int 0)) - (pc) - (label_ref (match_operand 0 "" ""))))] - "" +(define_insn "*insv_bfclr_mem" + [(set (zero_extract:SI (match_operand:QI 0 "memory_operand" "+o") + (match_operand:SI 1 "nonmemory_operand" "dn") + (match_operand:SI 2 "nonmemory_operand" "dn")) + (const_int 0))] + "TARGET_68020 && TARGET_BITFIELD" { - if ((cc_status.flags & CC_OVERFLOW_UNUSABLE) != 0) - { - cc_status.flags &= ~CC_OVERFLOW_UNUSABLE; - return 0; - } + return "bfclr %0{%b2:%b1}"; +}) - return "jcs %l0"; -} - [(set_attr "type" "bcc")]) +(define_insn "*insv_bfset_mem" + [(set (zero_extract:SI (match_operand:QI 0 "memory_operand" "+o") + (match_operand:SI 1 "general_operand" "dn") + (match_operand:SI 2 "general_operand" "dn")) + (const_int -1))] + "TARGET_68020 && TARGET_BITFIELD" +{ + return "bfset %0{%b2:%b1}"; +}) -(define_insn "*ble_rev" - [(set (pc) - (if_then_else (le (cc0) - (const_int 0)) - (pc) - (label_ref (match_operand 0 "" ""))))] - "" +(define_expand "insv" + [(set (zero_extract:SI (match_operand:SI 0 "nonimmediate_operand" "") + (match_operand:SI 1 "const_int_operand" "") + (match_operand:SI 2 "const_int_operand" "")) + (match_operand:SI 3 "reg_or_pow2_m1_operand" ""))] + "TARGET_68020 && TARGET_BITFIELD" + " { - if ((cc_status.flags & CC_OVERFLOW_UNUSABLE) != 0) + /* Special case initializing a field to all ones. */ + if (GET_CODE (operands[3]) == CONST_INT) { - cc_status.flags &= ~CC_OVERFLOW_UNUSABLE; - return 0; + if (exact_log2 (INTVAL (operands[3]) + 1) != INTVAL (operands[1])) + operands[3] = force_reg (SImode, operands[3]); + else + operands[3] = constm1_rtx; + } +}") - OUTPUT_JUMP ("jgt %l0", "fjnle %l0", 0); -} - [(set_attr "type" "bcc")]) +(define_insn "*insv_bfins_mem" + [(set (zero_extract:SI (match_operand:QI 0 "memory_operand" "+o") + (match_operand:SI 1 "nonmemory_operand" "dn") + (match_operand:SI 2 "nonmemory_operand" "dn")) + (match_operand:SI 3 "register_operand" "d"))] + "TARGET_68020 && TARGET_BITFIELD" + "bfins %3,%0{%b2:%b1}") -(define_insn "*bleu_rev" - [(set (pc) - (if_then_else (leu (cc0) - (const_int 0)) - (pc) - (label_ref (match_operand 0 "" ""))))] - "" -{ - if ((cc_status.flags & CC_OVERFLOW_UNUSABLE) != 0) - { - cc_status.flags &= ~CC_OVERFLOW_UNUSABLE; - return 0; - } +;; Now recognize bit-field insns that operate on registers +;; (or at least were intended to do so). - return "jhi %l0"; -} - [(set_attr "type" "bcc")]) +(define_insn "*extv_bfexts_reg" + [(set (match_operand:SI 0 "nonimmediate_operand" "=d") + (sign_extract:SI (match_operand:SI 1 "register_operand" "d") + (match_operand:SI 2 "const_int_operand" "n") + (match_operand:SI 3 "const_int_operand" "n")))] + "TARGET_68020 && TARGET_BITFIELD && IN_RANGE (INTVAL (operands[3]), 0, 31)" + "bfexts %1{%b3:%b2},%0") -(define_insn "*bordered_rev" - [(set (pc) - (if_then_else (ordered (cc0) (const_int 0)) - (pc) - (label_ref (match_operand 0 "" ""))))] - "TARGET_HARD_FLOAT" +(define_insn "*extv_bfextu_reg" + [(set (match_operand:SI 0 "nonimmediate_operand" "=d") + (zero_extract:SI (match_operand:SI 1 "register_operand" "d") + (match_operand:SI 2 "const_int_operand" "n") + (match_operand:SI 3 "const_int_operand" "n")))] + "TARGET_68020 && TARGET_BITFIELD && IN_RANGE (INTVAL (operands[3]), 0, 31)" { - gcc_assert (cc_prev_status.flags & CC_IN_68881); - return "fjun %l0"; -} - [(set_attr "type" "fbcc")]) + return "bfextu %1{%b3:%b2},%0"; +}) -(define_insn "*bunordered_rev" - [(set (pc) - (if_then_else (unordered (cc0) (const_int 0)) - (pc) - (label_ref (match_operand 0 "" ""))))] - "TARGET_HARD_FLOAT" +(define_insn "*insv_bfclr_reg" + [(set (zero_extract:SI (match_operand:SI 0 "register_operand" "+d") + (match_operand:SI 1 "const_int_operand" "n") + (match_operand:SI 2 "const_int_operand" "n")) + (const_int 0))] + "TARGET_68020 && TARGET_BITFIELD && IN_RANGE (INTVAL (operands[2]), 0, 31)" { - gcc_assert (cc_prev_status.flags & CC_IN_68881); - return "fjor %l0"; -} - [(set_attr "type" "fbcc")]) + return "bfclr %0{%b2:%b1}"; +}) -(define_insn "*buneq_rev" - [(set (pc) - (if_then_else (uneq (cc0) (const_int 0)) - (pc) - (label_ref (match_operand 0 "" ""))))] - "TARGET_HARD_FLOAT" +(define_insn "*insv_bfset_reg" + [(set (zero_extract:SI (match_operand:SI 0 "register_operand" "+d") + (match_operand:SI 1 "const_int_operand" "n") + (match_operand:SI 2 "const_int_operand" "n")) + (const_int -1))] + "TARGET_68020 && TARGET_BITFIELD && IN_RANGE (INTVAL (operands[2]), 0, 31)" { - gcc_assert (cc_prev_status.flags & CC_IN_68881); - return "fjogl %l0"; -} - [(set_attr "type" "fbcc")]) + return "bfset %0{%b2:%b1}"; +}) -(define_insn "*bunge_rev" - [(set (pc) - (if_then_else (unge (cc0) (const_int 0)) - (pc) - (label_ref (match_operand 0 "" ""))))] - "TARGET_HARD_FLOAT" +(define_insn "*insv_bfins_reg" + [(set (zero_extract:SI (match_operand:SI 0 "register_operand" "+d") + (match_operand:SI 1 "const_int_operand" "n") + (match_operand:SI 2 "const_int_operand" "n")) + (match_operand:SI 3 "register_operand" "d"))] + "TARGET_68020 && TARGET_BITFIELD && IN_RANGE (INTVAL (operands[2]), 0, 31)" { - gcc_assert (cc_prev_status.flags & CC_IN_68881); - return "fjolt %l0"; -} - [(set_attr "type" "fbcc")]) - -(define_insn "*bungt_rev" - [(set (pc) - (if_then_else (ungt (cc0) (const_int 0)) - (pc) - (label_ref (match_operand 0 "" ""))))] - "TARGET_HARD_FLOAT" +#if 0 + /* These special cases are now recognized by a specific pattern. */ + if (GET_CODE (operands[1]) == CONST_INT && GET_CODE (operands[2]) == CONST_INT + && INTVAL (operands[1]) == 16 && INTVAL (operands[2]) == 16) + return "move%.w %3,%0"; + if (GET_CODE (operands[1]) == CONST_INT && GET_CODE (operands[2]) == CONST_INT + && INTVAL (operands[1]) == 24 && INTVAL (operands[2]) == 8) + return "move%.b %3,%0"; +#endif + return "bfins %3,%0{%b2:%b1}"; +}) + +(define_insn "scc0_di" + [(set (match_operand:QI 0 "nonimmediate_operand" "=dm") + (match_operator 1 "ordered_comparison_operator" + [(match_operand:DI 2 "general_operand" "ro") (const_int 0)]))] + "! TARGET_COLDFIRE" { - gcc_assert (cc_prev_status.flags & CC_IN_68881); - return "fjole %l0"; -} - [(set_attr "type" "fbcc")]) + return output_scc_di (operands[1], operands[2], const0_rtx, operands[0]); +}) -(define_insn "*bunle_rev" - [(set (pc) - (if_then_else (unle (cc0) (const_int 0)) - (pc) - (label_ref (match_operand 0 "" ""))))] - "TARGET_HARD_FLOAT" +(define_insn "scc0_di_5200" + [(set (match_operand:QI 0 "nonimmediate_operand" "=d") + (match_operator 1 "ordered_comparison_operator" + [(match_operand:DI 2 "general_operand" "ro") (const_int 0)]))] + "TARGET_COLDFIRE" { - gcc_assert (cc_prev_status.flags & CC_IN_68881); - return "fjogt %l0"; -} - [(set_attr "type" "fbcc")]) + return output_scc_di (operands[1], operands[2], const0_rtx, operands[0]); +}) -(define_insn "*bunlt_rev" - [(set (pc) - (if_then_else (unlt (cc0) (const_int 0)) - (pc) - (label_ref (match_operand 0 "" ""))))] - "TARGET_HARD_FLOAT" +(define_insn "scc_di" + [(set (match_operand:QI 0 "nonimmediate_operand" "=dm,dm") + (match_operator 1 "ordered_comparison_operator" + [(match_operand:DI 2 "general_operand" "ro,r") + (match_operand:DI 3 "general_operand" "r,ro")]))] + "! TARGET_COLDFIRE" { - gcc_assert (cc_prev_status.flags & CC_IN_68881); - return "fjoge %l0"; -} - [(set_attr "type" "fbcc")]) + return output_scc_di (operands[1], operands[2], operands[3], operands[0]); +}) -(define_insn "*bltgt_rev" - [(set (pc) - (if_then_else (ltgt (cc0) (const_int 0)) - (pc) - (label_ref (match_operand 0 "" ""))))] - "TARGET_HARD_FLOAT" +(define_insn "scc_di_5200" + [(set (match_operand:QI 0 "nonimmediate_operand" "=d,d") + (match_operator 1 "ordered_comparison_operator" + [(match_operand:DI 2 "general_operand" "ro,r") + (match_operand:DI 3 "general_operand" "r,ro")]))] + "TARGET_COLDFIRE" { - gcc_assert (cc_prev_status.flags & CC_IN_68881); - return "fjueq %l0"; -} - [(set_attr "type" "fbcc")]) + return output_scc_di (operands[1], operands[2], operands[3], operands[0]); +}) ;; Unconditional and other jump instructions (define_insn "jump" @@ -6779,7 +5868,6 @@ (const_int -1)))] "!TARGET_COLDFIRE" { - CC_STATUS_INIT; if (DATA_REG_P (operands[0])) return "dbra %0,%l1"; if (GET_CODE (operands[0]) == MEM) @@ -6799,7 +5887,6 @@ (const_int -1)))] "!TARGET_COLDFIRE" { - CC_STATUS_INIT; if (DATA_REG_P (operands[0])) return "dbra %0,%l1\;clr%.w %0\;subq%.l #1,%0\;jcc %l1"; if (GET_CODE (operands[0]) == MEM) @@ -6822,7 +5909,6 @@ (const_int -1)))] "!TARGET_COLDFIRE && find_reg_note (insn, REG_NONNEG, 0)" { - CC_STATUS_INIT; if (DATA_REG_P (operands[0])) return "dbra %0,%l1"; if (GET_CODE (operands[0]) == MEM) @@ -6857,7 +5943,6 @@ (const_int -1)))] "!TARGET_COLDFIRE && find_reg_note (insn, REG_NONNEG, 0)" { - CC_STATUS_INIT; if (DATA_REG_P (operands[0])) return "dbra %0,%l1\;clr%.w %0\;subq%.l #1,%0\;jcc %l1"; if (GET_CODE (operands[0]) == MEM) @@ -7004,13 +6089,15 @@ (define_insn "blockage" [(unspec_volatile [(const_int 0)] UNSPECV_BLOCKAGE)] "" - "") + "" + [(set_attr "flags_valid" "unchanged")]) (define_insn "nop" [(const_int 0)] "" "nop" - [(set_attr "type" "nop")]) + [(set_attr "type" "nop") + (set_attr "flags_valid" "unchanged")]) (define_expand "prologue" [(const_int 0)] @@ -7379,97 +6466,56 @@ ;; ;; Which moves the jCC condition outside the inner loop for free. ;; +(define_mode_iterator DBCC [HI SI]) (define_peephole - [(set (pc) (if_then_else (match_operator 3 "valid_dbcc_comparison_p" - [(cc0) (const_int 0)]) - (label_ref (match_operand 2 "" "")) - (pc))) - (parallel - [(set (pc) - (if_then_else - (ne (match_operand:HI 0 "register_operand" "") - (const_int 0)) - (label_ref (match_operand 1 "" "")) - (pc))) - (set (match_dup 0) - (plus:HI (match_dup 0) - (const_int -1)))])] - "!TARGET_COLDFIRE && DATA_REG_P (operands[0]) && ! flags_in_68881 ()" -{ - CC_STATUS_INIT; - output_dbcc_and_branch (operands); - return ""; -}) - -(define_peephole - [(set (pc) (if_then_else (match_operator 3 "valid_dbcc_comparison_p" - [(cc0) (const_int 0)]) - (label_ref (match_operand 2 "" "")) - (pc))) - (parallel - [(set (pc) - (if_then_else - (ne (match_operand:SI 0 "register_operand" "") - (const_int 0)) - (label_ref (match_operand 1 "" "")) - (pc))) - (set (match_dup 0) - (plus:SI (match_dup 0) - (const_int -1)))])] - "!TARGET_COLDFIRE && DATA_REG_P (operands[0]) && ! flags_in_68881 ()" -{ - CC_STATUS_INIT; - output_dbcc_and_branch (operands); - return ""; -}) - -(define_peephole - [(set (pc) (if_then_else (match_operator 3 "valid_dbcc_comparison_p" - [(cc0) (const_int 0)]) + [(set (pc) (if_then_else (match_operator 3 "ordered_comparison_operator" + [(match_operand:CMPMODE 4 "general_operand" "") + (match_operand:CMPMODE 5 "general_operand" "")]) (label_ref (match_operand 2 "" "")) (pc))) (parallel [(set (pc) (if_then_else - (ge (plus:HI (match_operand:HI 0 "register_operand" "") - (const_int -1)) + (ne (match_operand:DBCC 0 "register_operand" "") (const_int 0)) (label_ref (match_operand 1 "" "")) (pc))) (set (match_dup 0) - (plus:HI (match_dup 0) - (const_int -1)))])] - "!TARGET_COLDFIRE && DATA_REG_P (operands[0]) && ! flags_in_68881 ()" + (plus:DBCC (match_dup 0) + (const_int -1)))])] + "!TARGET_COLDFIRE && DATA_REG_P (operands[0])" { - CC_STATUS_INIT; - output_dbcc_and_branch (operands); + rtx_code code = GET_CODE (operands[3]); + code = m68k_output_compare_ (operands[4], operands[5], code); + output_dbcc_and_branch (operands, code); return ""; }) (define_peephole - [(set (pc) (if_then_else (match_operator 3 "valid_dbcc_comparison_p" - [(cc0) (const_int 0)]) + [(set (pc) (if_then_else (match_operator 3 "ordered_comparison_operator" + [(match_operand:CMPMODE 4 "general_operand" "") + (match_operand:CMPMODE 5 "general_operand" "")]) (label_ref (match_operand 2 "" "")) (pc))) (parallel [(set (pc) (if_then_else - (ge (plus:SI (match_operand:SI 0 "register_operand" "") - (const_int -1)) + (ge (plus:DBCC (match_operand:DBCC 0 "register_operand" "") + (const_int -1)) (const_int 0)) (label_ref (match_operand 1 "" "")) (pc))) (set (match_dup 0) - (plus:SI (match_dup 0) - (const_int -1)))])] - "!TARGET_COLDFIRE && DATA_REG_P (operands[0]) && ! flags_in_68881 ()" + (plus:DBCC (match_dup 0) + (const_int -1)))])] + "!TARGET_COLDFIRE && DATA_REG_P (operands[0])" { - CC_STATUS_INIT; - output_dbcc_and_branch (operands); + rtx_code code = GET_CODE (operands[3]); + code = m68k_output_compare_ (operands[4], operands[5], code); + output_dbcc_and_branch (operands, code); return ""; }) - (define_insn "extendsfxf2" [(set (match_operand:XF 0 "nonimmediate_operand" "=fm,f") @@ -7480,10 +6526,7 @@ { if (REGNO (operands[0]) == REGNO (operands[1])) { - /* Extending float to double in an fp-reg is a no-op. - NOTICE_UPDATE_CC has already assumed that the - cc will be set. So cancel what it did. */ - cc_status = cc_prev_status; + /* Extending float to double in an fp-reg is a no-op. */ return ""; } return "f%$move%.x %1,%0"; @@ -7512,10 +6555,7 @@ { if (REGNO (operands[0]) == REGNO (operands[1])) { - /* Extending float to double in an fp-reg is a no-op. - NOTICE_UPDATE_CC has already assumed that the - cc will be set. So cancel what it did. */ - cc_status = cc_prev_status; + /* Extending float to double in an fp-reg is a no-op. */ return ""; } return "fmove%.x %1,%0"; @@ -7583,64 +6623,52 @@ return "fcos%. %1,%0"; }) -;; Unconditional traps are assumed to have (const_int 1) for the condition. +;; Unconditional traps are assumed to have const_true_rtx for the condition. (define_insn "trap" - [(trap_if (const_int 1) (const_int 7))] + [(trap_if (const_int -1) (const_int 7))] "" "trap #7" [(set_attr "type" "trap")]) -(define_expand "ctrapdi4" +;; ??? Our trap instruction uses constant 7 for operand 3, which is +;; also the trap vector used by TRAPcc instruction. By restricting +;; these patterns to const1_operand, they will not be generated. +;; Left disabled for now, as enabling it seems to cause issues. +(define_insn "ctrap4" [(trap_if (match_operator 0 "ordered_comparison_operator" - [(cc0) (const_int 0)]) - (match_operand:SI 3 "const1_operand" ""))] - "TARGET_68020" + [(match_operand:CMPMODE 1 "nonimmediate_operand" "") + (match_operand:CMPMODE 2 "general_operand" "")]) + (match_operand:SI 3 "const1_operand" ""))] + "TARGET_68020 && !TARGET_COLDFIRE" { - if (operands[2] == const0_rtx) - emit_insn (gen_tstdi (operands[1])); - else - emit_insn (gen_cmpdi (operands[1], operands[2])); - operands[1] = cc0_rtx; - operands[2] = const0_rtx; -}) - -(define_expand "ctrapsi4" - [(set (cc0) - (compare (match_operand:SI 1 "nonimmediate_operand" "") - (match_operand:SI 2 "general_operand" ""))) - (trap_if (match_operator 0 "ordered_comparison_operator" - [(cc0) (const_int 0)]) - (match_operand:SI 3 "const1_operand" ""))] - "TARGET_68020" - "") - -(define_expand "ctraphi4" - [(set (cc0) - (compare (match_operand:HI 1 "nonimmediate_src_operand" "") - (match_operand:HI 2 "general_src_operand" ""))) - (trap_if (match_operator 0 "ordered_comparison_operator" - [(cc0) (const_int 0)]) - (match_operand:SI 3 "const1_operand" ""))] - "TARGET_68020" - "") - -(define_expand "ctrapqi4" - [(set (cc0) - (compare (match_operand:QI 1 "nonimmediate_src_operand" "") - (match_operand:QI 2 "general_src_operand" ""))) - (trap_if (match_operator 0 "ordered_comparison_operator" - [(cc0) (const_int 0)]) - (match_operand:SI 3 "const1_operand" ""))] - "TARGET_68020" - "") + rtx_code code = GET_CODE (operands[0]); + code = m68k_output_compare_ (operands[1], operands[2], code); + switch (code) + { + case EQ: return "trapeq"; + case NE: return "trapne"; + case GT: return "trapgt"; + case GTU: return "traphi"; + case LT: return "traplt"; + case LTU: return "trapcs"; + case GE: return "trapge"; + case GEU: return "trapcc"; + case LE: return "traple"; + case LEU: return "trapls"; + default: gcc_unreachable (); + } +}) -(define_insn "*conditional_trap" +(define_insn "ctrap4_cf" [(trap_if (match_operator 0 "ordered_comparison_operator" - [(cc0) (const_int 0)]) - (match_operand:SI 1 "const1_operand" "I"))] - "TARGET_68020 && ! flags_in_68881 ()" -{ - switch (GET_CODE (operands[0])) + [(match_operand:CMPMODE 1 "nonimmediate_operand" "") + (match_operand:CMPMODE 2 "general_operand" "")]) + (match_operand:SI 3 "const1_operand" ""))] + "TARGET_68020 && TARGET_COLDFIRE" +{ + rtx_code code = GET_CODE (operands[0]); + code = m68k_output_compare_ (operands[1], operands[2], code); + switch (code) { case EQ: return "trapeq"; case NE: return "trapne"; @@ -7735,10 +6763,8 @@ (define_peephole2 [(set (match_operand:SI 0 "register_operand" "") (match_operand:SI 1 "addq_subq_operand" "")) - (set (cc0) (compare (match_operand:SI 2 "register_operand" "") - (match_dup 0))) (set (pc) (if_then_else (match_operator 5 "equality_comparison_operator" - [(cc0) (const_int 0)]) + [(match_operand:SI 2 "register_operand" "") (match_dup 0)]) (match_operand 3 "pc_or_label_operand") (match_operand 4 "pc_or_label_operand")))] "peep2_reg_dead_p (2, operands[0]) @@ -7747,8 +6773,7 @@ && DATA_REG_P (operands[2]) && !rtx_equal_p (operands[0], operands[2])" [(set (match_dup 2) (plus:SI (match_dup 2) (match_dup 6))) - (set (cc0) (compare (match_dup 2) (const_int 0))) - (set (pc) (if_then_else (match_op_dup 5 [(cc0) (const_int 0)]) + (set (pc) (if_then_else (match_op_dup 5 [(match_dup 2) (const_int 0)]) (match_dup 3) (match_dup 4)))] "operands[6] = GEN_INT (-INTVAL (operands[1]));") @@ -7756,9 +6781,8 @@ (define_peephole2 [(set (match_operand:SI 0 "register_operand" "") (match_operand:SI 1 "pow2_m1_operand" "")) - (set (cc0) (compare (match_operand:SI 2 "register_operand" "") - (match_operand:SI 3 "register_operand" ""))) - (set (pc) (if_then_else (gtu (cc0) (const_int 0)) + (set (pc) (if_then_else (gtu (match_operand:SI 2 "register_operand" "") + (match_operand:SI 3 "register_operand" "")) (match_operand 4 "pc_or_label_operand") (match_operand 5 "pc_or_label_operand")))] "INTVAL (operands[1]) <= 255 @@ -7769,8 +6793,7 @@ && (optimize_size || TUNE_68040_60) && DATA_REG_P (operands[2])" [(set (match_dup 7) (lshiftrt:SI (match_dup 7) (match_dup 6))) - (set (cc0) (compare (match_dup 7) (const_int 0))) - (set (pc) (if_then_else (ne (cc0) (const_int 0)) + (set (pc) (if_then_else (ne (match_dup 7) (const_int 0)) (match_dup 4) (match_dup 5)))] " { @@ -7779,9 +6802,8 @@ }") (define_peephole2 - [(set (cc0) (compare (match_operand:SI 0 "register_operand" "") - (match_operand:SI 1 "pow2_m1_operand" ""))) - (set (pc) (if_then_else (gtu (cc0) (const_int 0)) + [(set (pc) (if_then_else (gtu (match_operand:SI 0 "register_operand" "") + (match_operand:SI 1 "pow2_m1_operand" "")) (match_operand 2 "pc_or_label_operand") (match_operand 3 "pc_or_label_operand")))] "INTVAL (operands[1]) <= 255 @@ -7790,17 +6812,15 @@ && (optimize_size || TUNE_68040_60) && DATA_REG_P (operands[0])" [(set (match_dup 0) (lshiftrt:SI (match_dup 0) (match_dup 4))) - (set (cc0) (compare (match_dup 0) (const_int 0))) - (set (pc) (if_then_else (ne (cc0) (const_int 0)) + (set (pc) (if_then_else (ne (match_dup 0) (const_int 0)) (match_dup 2) (match_dup 3)))] "{ operands[4] = GEN_INT (exact_log2 (INTVAL (operands[1]) + 1)); }") (define_peephole2 [(set (match_operand:SI 0 "register_operand" "") (match_operand:SI 1 "pow2_m1_operand" "")) - (set (cc0) (compare (match_operand:SI 2 "register_operand" "") - (match_operand:SI 3 "register_operand" ""))) - (set (pc) (if_then_else (leu (cc0) (const_int 0)) + (set (pc) (if_then_else (leu (match_operand:SI 2 "register_operand" "") + (match_operand:SI 3 "register_operand" "")) (match_operand 4 "pc_or_label_operand") (match_operand 5 "pc_or_label_operand")))] "INTVAL (operands[1]) <= 255 @@ -7811,8 +6831,7 @@ && (optimize_size || TUNE_68040_60) && DATA_REG_P (operands[2])" [(set (match_dup 7) (lshiftrt:SI (match_dup 7) (match_dup 6))) - (set (cc0) (compare (match_dup 7) (const_int 0))) - (set (pc) (if_then_else (eq (cc0) (const_int 0)) + (set (pc) (if_then_else (eq (match_dup 7) (const_int 0)) (match_dup 4) (match_dup 5)))] " { @@ -7820,9 +6839,8 @@ operands[7] = operands[2]; }") (define_peephole2 - [(set (cc0) (compare (match_operand:SI 0 "register_operand" "") - (match_operand:SI 1 "pow2_m1_operand" ""))) - (set (pc) (if_then_else (leu (cc0) (const_int 0)) + [(set (pc) (if_then_else (leu (match_operand:SI 0 "register_operand" "") + (match_operand:SI 1 "pow2_m1_operand" "")) (match_operand 2 "pc_or_label_operand") (match_operand 3 "pc_or_label_operand")))] "INTVAL (operands[1]) <= 255 @@ -7831,8 +6849,7 @@ && (optimize_size || TUNE_68040_60) && DATA_REG_P (operands[0])" [(set (match_dup 0) (lshiftrt:SI (match_dup 0) (match_dup 4))) - (set (cc0) (compare (match_dup 0) (const_int 0))) - (set (pc) (if_then_else (eq (cc0) (const_int 0)) + (set (pc) (if_then_else (eq (match_dup 0) (const_int 0)) (match_dup 2) (match_dup 3)))] "{ operands[4] = GEN_INT (exact_log2 (INTVAL (operands[1]) + 1)); }") @@ -7841,10 +6858,9 @@ ;; internally against 65535). ;; The rotate in the output pattern will turn into a swap. (define_peephole2 - [(set (cc0) (compare (match_operand:SI 0 "register_operand" "") - (const_int 65535))) - (set (pc) (if_then_else (match_operator 1 "swap_peephole_relational_operator" - [(cc0) (const_int 0)]) + [(set (pc) (if_then_else (match_operator 1 "swap_peephole_relational_operator" + [(match_operand:SI 0 "register_operand" "") + (const_int 65535)]) (match_operand 2 "pc_or_label_operand") (match_operand 3 "pc_or_label_operand")))] "peep2_reg_dead_p (1, operands[0]) @@ -7852,7 +6868,6 @@ && (optimize_size || TUNE_68000_10) && DATA_REG_P (operands[0])" [(set (match_dup 0) (rotate:SI (match_dup 0) (const_int 16))) - (set (cc0) (compare (subreg:HI (match_dup 0) 2) (const_int 0))) - (set (pc) (if_then_else (match_op_dup 1 [(cc0) (const_int 0)]) + (set (pc) (if_then_else (match_op_dup 1 [(subreg:HI (match_dup 0) 2) (const_int 0)]) (match_dup 2) (match_dup 3)))] "") diff --git a/gcc/config/m68k/predicates.md b/gcc/config/m68k/predicates.md index ad297883f85..9e4c8ba864f 100644 --- a/gcc/config/m68k/predicates.md +++ b/gcc/config/m68k/predicates.md @@ -115,15 +115,6 @@ && (INTVAL (op) >= (-0x7fffffff - 1) && INTVAL (op) <= 0x7fffffff)); }) -;; Return true if X is a valid comparison operator for the dbcc -;; instruction. Note it rejects floating point comparison -;; operators. (In the future we could use Fdbcc). It also rejects -;; some comparisons when CC_NO_OVERFLOW is set. - -(define_predicate "valid_dbcc_comparison_p" - (and (match_code "eq,ne,gtu,ltu,geu,leu,gt,lt,ge,le") - (match_test "valid_dbcc_comparison_p_2 (op, mode)"))) - (define_predicate "m68k_cstore_comparison_operator" (if_then_else (match_test "TARGET_68881") (match_operand 0 "comparison_operator") @@ -210,10 +201,10 @@ (and (match_code "const_int") (match_test "op == const1_rtx"))) -;; A valid operand for a HImode or QImode conditional operation. -;; ColdFire has tst patterns, but not cmp patterns. -(define_predicate "m68k_subword_comparison_operand" - (if_then_else (match_test "TARGET_COLDFIRE") +;; A valid operand for a conditional operation. +;; ColdFire has tst patterns for HImode and QImode, but not cmp patterns. +(define_predicate "m68k_comparison_operand" + (if_then_else (match_test "TARGET_COLDFIRE && mode != SImode") (and (match_code "const_int") (match_test "op == const0_rtx")) (match_operand 0 "general_src_operand"))) @@ -234,15 +225,17 @@ ;; Special case of general_src_operand, which rejects a few fp ;; constants (which we prefer in registers) before reload. +;; Used only in comparisons, and we do want to allow zero. (define_predicate "fp_src_operand" (match_operand 0 "general_src_operand") { - return !CONSTANT_P (op) - || (TARGET_68881 - && (!standard_68881_constant_p (op) - || reload_in_progress - || reload_completed)); + return (!CONSTANT_P (op) + || op == CONST0_RTX (mode) + || (TARGET_68881 + && (!standard_68881_constant_p (op) + || reload_in_progress + || reload_completed))); }) ;; Used to detect constants that are valid for addq/subq instructions @@ -282,3 +275,6 @@ (define_predicate "swap_peephole_relational_operator" (match_code "gtu,leu,gt,le")) + +(define_predicate "address_reg_operand" + (match_test ("ADDRESS_REG_P (op)"))) diff --git a/gcc/recog.c b/gcc/recog.c index 9e9cca7db02..0482818c453 100644 --- a/gcc/recog.c +++ b/gcc/recog.c @@ -923,23 +923,6 @@ validate_simplify_insn (rtx_insn *insn) return ((num_changes_pending () > 0) && (apply_change_group () > 0)); } -/* Return 1 if the insn using CC0 set by INSN does not contain - any ordered tests applied to the condition codes. - EQ and NE tests do not count. */ - -int -next_insn_tests_no_inequality (rtx_insn *insn) -{ - rtx_insn *next = next_cc0_user (insn); - - /* If there is no next insn, we have to take the conservative choice. */ - if (next == 0) - return 0; - - return (INSN_P (next) - && ! inequality_comparisons_p (PATTERN (next))); -} - /* Return 1 if OP is a valid general operand for machine mode MODE. This is either a register reference, a memory reference, or a constant. In the case of a memory reference, the address diff --git a/gcc/recog.h b/gcc/recog.h index 71d88e3e376..69238cf16a6 100644 --- a/gcc/recog.h +++ b/gcc/recog.h @@ -112,7 +112,6 @@ extern void validate_replace_rtx_group (rtx, rtx, rtx_insn *); extern void validate_replace_src_group (rtx, rtx, rtx_insn *); extern bool validate_simplify_insn (rtx_insn *insn); extern int num_changes_pending (void); -extern int next_insn_tests_no_inequality (rtx_insn *); extern bool reg_fits_class_p (const_rtx, reg_class_t, int, machine_mode); extern int offsettable_memref_p (rtx); diff --git a/gcc/rtl.h b/gcc/rtl.h index 1369e66a136..be27937f7f9 100644 --- a/gcc/rtl.h +++ b/gcc/rtl.h @@ -3514,7 +3514,6 @@ extern bool insn_nothrow_p (const_rtx); extern bool can_nonlocal_goto (const rtx_insn *); extern void copy_reg_eh_region_note_forward (rtx, rtx_insn *, rtx); extern void copy_reg_eh_region_note_backward (rtx, rtx_insn *, rtx); -extern int inequality_comparisons_p (const_rtx); extern rtx replace_rtx (rtx, rtx, rtx, bool = false); extern void replace_label (rtx *, rtx, rtx, bool); extern void replace_label_in_insn (rtx_insn *, rtx_insn *, rtx_insn *, bool); diff --git a/gcc/rtlanal.c b/gcc/rtlanal.c index 720aa093a23..241a35b0e6c 100644 --- a/gcc/rtlanal.c +++ b/gcc/rtlanal.c @@ -3021,64 +3021,6 @@ may_trap_or_fault_p (const_rtx x) return may_trap_p_1 (x, 1); } -/* Return nonzero if X contains a comparison that is not either EQ or NE, - i.e., an inequality. */ - -int -inequality_comparisons_p (const_rtx x) -{ - const char *fmt; - int len, i; - const enum rtx_code code = GET_CODE (x); - - switch (code) - { - case REG: - case SCRATCH: - case PC: - case CC0: - CASE_CONST_ANY: - case CONST: - case LABEL_REF: - case SYMBOL_REF: - return 0; - - case LT: - case LTU: - case GT: - case GTU: - case LE: - case LEU: - case GE: - case GEU: - return 1; - - default: - break; - } - - len = GET_RTX_LENGTH (code); - fmt = GET_RTX_FORMAT (code); - - for (i = 0; i < len; i++) - { - if (fmt[i] == 'e') - { - if (inequality_comparisons_p (XEXP (x, i))) - return 1; - } - else if (fmt[i] == 'E') - { - int j; - for (j = XVECLEN (x, i) - 1; j >= 0; j--) - if (inequality_comparisons_p (XVECEXP (x, i, j))) - return 1; - } - } - - return 0; -} - /* Replace any occurrence of FROM in X with TO. The function does not enter into CONST_DOUBLE for the replace.