Convert m68k to not use cc0
authorBernd Schmidt <bernds_cb1@t-online.de>
Mon, 25 Nov 2019 12:31:16 +0000 (12:31 +0000)
committerBernd Schmidt <bernds@gcc.gnu.org>
Mon, 25 Nov 2019 12:31:16 +0000 (12:31 +0000)
* 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
cbranch<mode>4.
(cstoresi4, cstoreqi4, cstorehi4): Replace expanders with
cstore<mode>4.
(cmp<mode>_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<mode>_68881, tst<mode>_cf, cmpdi_internal,
cmpdi, unnamed cmpsi/cmphi/cmpqi patterns, cmpsi_cf,
cmp<mode>_68881, cmp<mode>_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 cbranch<mode>4, cstore<mode>4): 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.
(cbranch<mode>4_insn, cbranch<mode>4_insn_rev,
cbranch<mode>4_insn_cf, cbranch<mode>4_insn_cf_rev,
cstore<mode>4_insn, cstore<mode>4_insn_cf for integer modes)
New patterns.
(cbranch<mode>4_insn_68881, cbranch<mode>4_insn_rev_68881):
(cbranch<mode>4_insn_cf, cbranch<mode>4_insn_rev_cf,
cstore<mode>4_insn_68881, cstore<mode>4_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<mode>_insn, cstore_bftst<mode>_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

gcc/ChangeLog
gcc/config/m68k/m68k-protos.h
gcc/config/m68k/m68k.c
gcc/config/m68k/m68k.h
gcc/config/m68k/m68k.md
gcc/config/m68k/predicates.md
gcc/recog.c
gcc/recog.h
gcc/rtl.h
gcc/rtlanal.c

index 6dee39e..b0957b0 100644 (file)
@@ -1,3 +1,166 @@
+2019-11-25  Bernd Schmidt  <bernds_cb1@t-online.de>
+
+       * 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
+       cbranch<mode>4.
+       (cstoresi4, cstoreqi4, cstorehi4): Replace expanders with
+       cstore<mode>4.
+       (cmp<mode>_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<mode>_68881, tst<mode>_cf, cmpdi_internal,
+       cmpdi, unnamed cmpsi/cmphi/cmpqi patterns, cmpsi_cf,
+       cmp<mode>_68881, cmp<mode>_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 cbranch<mode>4, cstore<mode>4): 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.
+       (cbranch<mode>4_insn, cbranch<mode>4_insn_rev,
+       cbranch<mode>4_insn_cf, cbranch<mode>4_insn_cf_rev,
+       cstore<mode>4_insn, cstore<mode>4_insn_cf for integer modes)
+       New patterns.
+       (cbranch<mode>4_insn_68881, cbranch<mode>4_insn_rev_68881):
+       (cbranch<mode>4_insn_cf, cbranch<mode>4_insn_rev_cf,
+       cstore<mode>4_insn_68881, cstore<mode>4_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<mode>_insn, cstore_bftst<mode>_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  <rguenther@suse.de>
 
        * tree-vect-slp.c (vect_detect_hybrid_slp_stmts): Add assertion.
index abd920e..a88d903 100644 (file)
@@ -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);
index 1030dfa..8d010eb 100644 (file)
@@ -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);
 \f
 /* 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);
 }
 \f
-/* 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;
 }
+\f
+/* 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_<mode>.  */
 
 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;
 }
 \f
 /* 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";
 }
-\f
-/* 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 ();
     }
 }
 \f
@@ -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";
 }
 
index fc65e52..39955b0 100644 (file)
@@ -671,36 +671,6 @@ __transfer_from_trampoline ()                                      \
 #define FUNCTION_MODE QImode
 
 \f
-/* 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)
-\f
 /* Control the assembler format that we output.  */
 
 #define ASM_APP_ON "#APP\n"
@@ -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
index 31e8767..25e0b73 100644 (file)
 ;; 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")
   DONE;
 })
 \f
-;; 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<mode>_68881"
-  [(set (cc0)
-       (compare (match_operand:FP 0 "general_operand" "f<FP:dreg>m")
-                (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%.<FP:prec> %0";
-}
-  [(set_attr "type" "ftst")])
-
-(define_insn "tst<mode>_cf"
-  [(set (cc0)
-       (compare (match_operand:FP 0 "general_operand" "f<FP:dreg><Q>U")
-                (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%.<FP:prec> %0";
-}
-  [(set_attr "type" "ftst")])
-
-\f
-;; 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"
          (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 "cbranch<mode>4"
+  [(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 "cstore<mode>4"
+  [(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
 ;; 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 "cbranch<mode>4_insn"
+  [(set (pc)
+       (if_then_else (match_operator 0 "ordered_comparison_operator"
+                      [(match_operand:CMPMODE 1 "nonimmediate_operand" "<cmp1_constraints>")
+                       (match_operand:CMPMODE 2 "general_operand" "<cmp2_constraints>")])
+                     (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_<mode> (operands[1], operands[2], code);
+  return m68k_output_branch_integer (code);
+}
+  [(set_attr "flags_valid" "set")])
+
+(define_insn "cbranch<mode>4_insn_rev"
+  [(set (pc)
+       (if_then_else (match_operator 0 "ordered_comparison_operator"
+                      [(match_operand:CMPMODE 1 "nonimmediate_operand" "<cmp1_constraints>")
+                       (match_operand:CMPMODE 2 "general_operand" "<cmp2_constraints>")])
+                     (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_<mode> (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 "cbranch<mode>4_insn_cf"
+  [(set (pc)
        (if_then_else (match_operator 0 "ordered_comparison_operator"
-                       [(cc0) (const_int 0)])
+                      [(match_operand:CMPMODE 1 "nonimmediate_operand" "<cmp1_cf_constraints>")
+                       (match_operand:CMPMODE 2 "<cmp2_cf_predicate>" "<cmp2_cf_constraints>")])
                      (label_ref (match_operand 3 ""))
                      (pc)))]
-  ""
-  "")
+  "TARGET_COLDFIRE"
+{
+  rtx_code code = GET_CODE (operands[0]);
+  code = m68k_output_compare_<mode> (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 "cbranch<mode>4_insn_cf_rev"
+  [(set (pc)
+       (if_then_else (match_operator 0 "ordered_comparison_operator"
+                      [(match_operand:CMPMODE 1 "nonimmediate_operand" "<cmp1_cf_constraints>")
+                       (match_operand:CMPMODE 2 "<cmp2_cf_predicate>" "<cmp2_cf_constraints>")])
+                     (pc)
+                     (label_ref (match_operand 3 ""))))]
+  "TARGET_COLDFIRE"
+{
+  rtx_code code = GET_CODE (operands[0]);
+  code = m68k_output_compare_<mode> (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 "cstore<mode>4_insn"
+  [(set (match_operand:QI 0 "register_operand" "<scc0_constraints>")
+       (match_operator:QI 1 "ordered_comparison_operator"
+        [(match_operand:CMPMODE 2 "nonimmediate_operand" "<cmp1_constraints>")
+         (match_operand:CMPMODE 3 "general_operand" "<cmp2_constraints>")]))]
   "!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_<mode> (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 "cstore<mode>4_insn_cf"
+  [(set (match_operand:QI 0 "register_operand" "<scc0_cf_constraints>")
+       (match_operator:QI 1 "ordered_comparison_operator"
+        [(match_operand:CMPMODE 2 "nonimmediate_operand" "<cmp1_cf_constraints>")
+         (match_operand:CMPMODE 3 "<cmp2_cf_predicate>" "<cmp2_cf_constraints>")]))]
+  "TARGET_COLDFIRE"
+{
+  rtx_code code = GET_CODE (operands[1]);
+  code = m68k_output_compare_<mode> (operands[2], operands[3], code);
+  return m68k_output_scc (code);
+}
+  [(set_attr "flags_valid" "set")])
+
+;; ColdFire/5200 only allows "<Q>" 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<mode>_insn"
+  [(set (pc)
+       (if_then_else (match_operator 0 "ordered_comparison_operator"
+                      [(zero_extract:SI (match_operand:BTST 1 "<btst_predicate>" "<btst_constraint>")
+                                        (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<mode>_insn"
+  [(set (match_operand:QI 0 "register_operand" "=d")
+       (match_operator:QI 1 "ordered_comparison_operator"
+        [(zero_extract:SI (match_operand:BTST 2 "<btst_predicate>" "<btst_constraint>")
+                          (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 "cbranch<mode>4"
-  [(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 "cstore<mode>4"
-  [(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<mode>_68881"
-  [(set (cc0)
-       (compare (match_operand:FP 0 "fp_src_operand" "f,f,<FP:dreg>mF")
-                (match_operand:FP 1 "fp_src_operand" "f,<FP:dreg>mF,f")))]
+(define_insn "cbranch<mode>4_insn_68881"
+  [(set (pc)
+       (if_then_else (match_operator 0 "comparison_operator"
+                      [(match_operand:FP 1 "fp_src_operand" "f,f,<FP:dreg>mF,f<FP:dreg>m")
+                       (match_operand:FP 2 "fp_src_operand" "f,<FP:dreg>mF,f,H")])
+                     (label_ref (match_operand 3 ""))
+                     (pc)))]
   "TARGET_68881
-   && (register_operand (operands[0], <MODE>mode)
-       || register_operand (operands[1], <MODE>mode))"
-  "@
-   fcmp%.x %1,%0
-   fcmp%.<FP:prec> %f1,%0
-   fcmp%.<FP:prec> %0,%f1"
-  [(set_attr "type" "fcmp")])
-
-(define_insn "*cmp<mode>_cf"
-  [(set (cc0)
-       (compare (match_operand:FP 0 "fp_src_operand" "f,f,<FP:dreg><Q>U")
-                (match_operand:FP 1 "fp_src_operand" "f,<FP:dreg><Q>U,f")))]
-  "TARGET_COLDFIRE_FPU
-   && (register_operand (operands[0], <MODE>mode)
-       || register_operand (operands[1], <MODE>mode))"
-  "@
-   fcmp%.d %1,%0
-   fcmp%.<FP:prec> %f1,%0
-   fcmp%.<FP:prec> %0,%f1"
-  [(set_attr "type" "fcmp")])
-\f
-;; Recognizers for btst instructions.
-
-;; ColdFire/5200 only allows "<Q>" 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>mode)
+       || register_operand (operands[2], <MODE>mode)
+       || const0_operand (operands[2], <MODE>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 "cbranch<mode>4_insn_cf"
+  [(set (pc)
+       (if_then_else (match_operator 0 "comparison_operator"
+                      [(match_operand:FP 1 "fp_src_operand" "f,f,<FP:dreg><Q>U,f<FP:dreg><Q>U")
+                       (match_operand:FP 2 "fp_src_operand" "f,<FP:dreg><Q>U,f,H")])
+                     (label_ref (match_operand 3 ""))
+                     (pc)))]
+  "TARGET_COLDFIRE_FPU
+   && (register_operand (operands[1], <MODE>mode)
+       || register_operand (operands[2], <MODE>mode)
+       || const0_operand (operands[2], <MODE>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 "cbranch<mode>4_insn_rev_68881"
+  [(set (pc)
+       (if_then_else (match_operator 0 "comparison_operator"
+                      [(match_operand:FP 1 "fp_src_operand" "f,f,<FP:dreg>mF,f<FP:dreg>m")
+                       (match_operand:FP 2 "fp_src_operand" "f,<FP:dreg>mF,f,H")])
+                     (pc)
+                     (label_ref (match_operand 3 ""))))]
+  "TARGET_68881
+   && (register_operand (operands[1], <MODE>mode)
+       || register_operand (operands[2], <MODE>mode)
+       || const0_operand (operands[2], <MODE>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 "cbranch<mode>4_insn_rev_cf"
+  [(set (pc)
+       (if_then_else (match_operator 0 "comparison_operator"
+                      [(match_operand:FP 1 "fp_src_operand" "f,f,<FP:dreg><Q>U,f<FP:dreg><Q>U")
+                       (match_operand:FP 2 "fp_src_operand" "f,<FP:dreg><Q>U,f,H")])
+                     (pc)
+                     (label_ref (match_operand 3 ""))))]
+  "TARGET_COLDFIRE_FPU
+   && (register_operand (operands[1], <MODE>mode)
+       || register_operand (operands[2], <MODE>mode)
+       || const0_operand (operands[2], <MODE>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 "cstore<mode>4_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,<FP:dreg>mF,f<FP:dreg>m")
+         (match_operand:FP 3 "fp_src_operand" "f,<FP:dreg>mF,f,H")]))]
+  "TARGET_HARD_FLOAT && !(TUNE_68060 || TARGET_COLDFIRE_FPU)
+   && (register_operand (operands[2], <MODE>mode)
+       || register_operand (operands[3], <MODE>mode)
+       || const0_operand (operands[3], <MODE>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 "cstore<mode>4_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" "f<FP:dreg><Q>U")
+         (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);
-})
-
-\f
 ;; move instructions
 
 ;; A special case in which it is not desirable
   "!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
   "!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"
   [(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<Q>,g,U")
        (match_operand:HI 1 "general_operand" "g,r<Q>,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" ""))
   [(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" "")
   [(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<Q>,dm,U,d*a")
        (match_operand:QI 1 "general_src_operand" "dmi,d<Q>,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" ""))
   [(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"))
       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<Q>,g,U")
         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")
       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<>")
   "!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")
   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")
   "!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")))])
 \f
 ;; zero extension instructions
 
         (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";
         (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";
    (clobber (match_scratch:SI 2 "=X,d,d,d"))]
   ""
 {
-  CC_STATUS_INIT;
-
   if (which_alternative == 0)
     /* Handle alternative 0.  */
     {
             (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)
     {
       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";
     {
       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";
    (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,%!";
 })
 
    (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,%!";
 })
 
    (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,%!";
 })
 
    (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]))
                 (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
                 (match_operand:DI 2 "register_operand" "0")))]
   "TARGET_COLDFIRE"
 {
-  CC_STATUS_INIT;
   return "add%.l %1,%R0\;negx%.l %0\;neg%.l %0";
 })
 
         (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
   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,
          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<Q>")
 
 
   "! 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")
          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]))
        {
        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
                 (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
              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"))
                 (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
              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")
        }
     }
   return "add%.b %2,%0";
-})
+}
+  [(set_attr "flags_valid" "noov")])
 
 (define_insn ""
   [(set (strict_low_part (match_operand:QI 0 "nonimmediate_operand" "+m,d"))
    (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]))
             (const_int 32))))]
   ""
 {
-  CC_STATUS_INIT;
   if (GET_CODE (operands[1]) == REG)
     operands[1] = gen_rtx_REG (SImode, REGNO (operands[1]) + 1);
   else
   else
     {
       gcc_assert (GET_CODE (operands[0]) == MEM);
-      CC_STATUS_INIT;
       if (GET_CODE (XEXP (operands[0], 0)) == POST_INC)
        {
          operands[1]
          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")
        (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 "sub<mode>3"
   [(set (match_operand:FP 0 "nonimmediate_operand" "")
          (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")
          (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
          (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")
          (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 "mul<mode>3"
   [(set (match_operand:FP 0 "nonimmediate_operand" "")
 
 (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" "d<Q>U")))
-   (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"
 {
    (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"
 {
 
 (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" "d<Q>U")))
-   (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"
 {
    (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"
 {
 })
 
 (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"
 {
     "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"
 {
       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 "";
 })
   "!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")
        (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"))
 {
   int byte_mode;
 
-  CC_STATUS_INIT;
   if (GET_CODE (operands[0]) == REG)
     operands[0] = gen_rtx_REG (SImode, REGNO (operands[0]) + 1);
   else
   "! TARGET_COLDFIRE"
 {
   return output_iorsi3 (operands);
-})
+}
+  [(set_attr "flags_valid" "set")])
 
 (define_insn "iorsi3_5200"
   [(set (match_operand:SI 0 "nonimmediate_operand" "=m,d")
   "TARGET_COLDFIRE"
 {
   return output_iorsi3 (operands);
-})
+}
+  [(set_attr "flags_valid" "set")])
 
 (define_insn "iorhi3"
   [(set (match_operand:HI 0 "nonimmediate_operand" "=m,d")
        (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.
             (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
 {
   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,
   "!TARGET_COLDFIRE"
 {
   return output_xorsi3 (operands);
-})
+}
+  [(set_attr "flags_valid" "set")])
 
 (define_insn "xorsi3_5200"
   [(set (match_operand:SI 0 "nonimmediate_operand" "=dm,d")
   "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")])
 \f
 ;; negation instructions
 
        (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.
 
   [(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")])
 \f
 ;; one complement instructions
   [(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")
   [(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")])
 \f
 ;; arithmetic shift instructions
 ;; We don't need the shift memory by 1 bit instruction
     (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)
        (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.
 
    && 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";
 })
   ""
 {
   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.
 
   "!TARGET_COLDFIRE"
 {
   operands[1] = gen_rtx_REG (SImode, REGNO (operands[0]) + 1);
-  CC_STATUS_INIT;
   return "asr%.l #1,%0\;roxr%.l #1,%1";
 })
 
                     (const_int 32)))]
   ""
 {
-  CC_STATUS_INIT;
   if (TARGET_68020)
     return "move%.l %1,%R0\;smi %0\;extb%.l %0";
   else
    (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);
        || (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)
   ""
   "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")])
 \f
 ;; logical shift instructions
 
                     (const_int 1)))]
   "!TARGET_COLDFIRE"
 {
-  CC_STATUS_INIT;
   return "lsr%.l #1,%0\;roxr%.l #1,%R0";
 })
 
                     (const_int 16)))]
   "!TUNE_68060"
 {
-  CC_STATUS_INIT;
   return "clr%.w %0\;swap %0";
 })
 
   ""
   "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")])
 \f
 ;; rotate instructions
 
                   (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")
     }
   else
     return "rol%.l %2,%0";
-})
+}
+  [(set_attr "flags_valid" "yes")])
 
 (define_insn "rotlhi3"
   [(set (match_operand:HI 0 "register_operand" "=d")
     }
   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"))
     }
   else
     return "rol%.w %1,%0";
-})
+}
+  [(set_attr "flags_valid" "yes")])
 
 (define_insn "rotlqi3"
   [(set (match_operand:QI 0 "register_operand" "=d")
     }
   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"))
     }
   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")
        (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")
                (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
                [(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"
                                   (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"
                                   (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"
                                   (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
            (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
                [(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
    && (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";
 
        (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}";
-})
-\f
-;; 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}";
-})
-\f
-(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";
-})
-\f
-;; 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")])
-\f
-;; 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}";
+})
+\f
+(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]);
+})
 \f
 ;; Unconditional and other jump instructions
 (define_insn "jump"
                 (const_int -1)))]
   "!TARGET_COLDFIRE"
 {
-  CC_STATUS_INIT;
   if (DATA_REG_P (operands[0]))
     return "dbra %0,%l1";
   if (GET_CODE (operands[0]) == MEM)
                 (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)
                 (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)
                 (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)
 (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)]
 ;;
 ;; 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_<CMPMODE:mode> (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_<CMPMODE:mode> (operands[4], operands[5], code);
+  output_dbcc_and_branch (operands, code);
   return "";
 })
-
 \f
 (define_insn "extendsfxf2"
   [(set (match_operand:XF 0 "nonimmediate_operand" "=fm,f")
     {
       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";
     {
       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";
     return "fcos%.<FP:prec> %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 "ctrap<mode>4"
   [(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" "<cmp1_constraints>")
+             (match_operand:CMPMODE 2 "general_operand" "<cmp2_constraints>")])
+             (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_<mode> (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 "ctrap<mode>4_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" "<cmp1_cf_constraints>")
+             (match_operand:CMPMODE 2 "general_operand" "<cmp2_cf_constraints>")])
+             (match_operand:SI 3 "const1_operand" ""))]
+  "TARGET_68020 && TARGET_COLDFIRE"
+{
+  rtx_code code = GET_CODE (operands[0]);
+  code = m68k_output_compare_<mode> (operands[1], operands[2], code);
+  switch (code)
   {
   case EQ:  return "trapeq";
   case NE:  return "trapne";
 (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])
    && 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]));")
 (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
    && (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)))]
   "
 {
 }")
 
 (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
    && (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
    && (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)))]
   "
 {
   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
    && (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)); }")
 
 ;; 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])
    && (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)))]
   "")
index ad29788..9e4c8ba 100644 (file)
          && (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")
   (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")))
 
 ;; 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
 
 (define_predicate "swap_peephole_relational_operator"
   (match_code "gtu,leu,gt,le"))
+
+(define_predicate "address_reg_operand"
+  (match_test ("ADDRESS_REG_P (op)")))
index 9e9cca7..0482818 100644 (file)
@@ -923,23 +923,6 @@ validate_simplify_insn (rtx_insn *insn)
   return ((num_changes_pending () > 0) && (apply_change_group () > 0));
 }
 \f
-/* 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)));
-}
-\f
 /* 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
index 71d88e3..69238cf 100644 (file)
@@ -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);
index 1369e66..be27937 100644 (file)
--- 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);
index 720aa09..241a35b 100644 (file)
@@ -3021,64 +3021,6 @@ may_trap_or_fault_p (const_rtx x)
   return may_trap_p_1 (x, 1);
 }
 \f
-/* 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;
-}
-\f
 /* Replace any occurrence of FROM in X with TO.  The function does
    not enter into CONST_DOUBLE for the replace.