]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
Import these patches from the mainline:
authorNick Clifton <nickc@redhat.com>
Wed, 2 Feb 2011 14:31:55 +0000 (14:31 +0000)
committerNick Clifton <nickc@gcc.gnu.org>
Wed, 2 Feb 2011 14:31:55 +0000 (14:31 +0000)
2011-01-31  Nick Clifton  <nickc@redhat.com>

* config/rx/rx.c (rx_get_stack_layout): Only save call clobbered
registers inside interrupt handlers if the handler is not a leaf
function.

2011-01-25  Nick Clifton  <nickc@redhat.com>

* config/rx/rx.h (LIBCALL_VALUE): Do not promote complex types.
* config/rx/rx.c (rx_function_value): Likewise.
(rx_promote_function_mode): Likewise.
(gen_safe_add): Place an outsized immediate value inside an UNSPEC
in order to make it legitimate.
* config/rx/rx.md (adddi3_internal): If the second operand is a
MEM make sure that the first operand is the same as the result
register.
(addsi3_unspec): Delete.
(subdi3): Do not accept immediate operands.
(subdi3_internal): Likewise.

2011-01-24  Richard Henderson  <rth@redhat.com>

* config/rx/predicates.md (rx_fp_comparison_operator): Don't accept
compound unordered comparisons.
* config/rx/rx.c (rx_split_fp_compare): Remove.
* config/rx/rx-protos.h: Update.
* config/rx/rx.md (gcc_conds, rx_conds): Remove.
(cbranchsf4): Don't call rx_split_fp_compare.
(*cbranchsf4): Use rx_split_cbranch.
(*cmpsf): Don't accept "i" constraint.
(*conditional_branch): Only valid after reload.
(cstoresf4): Merge expander with insn.  Don't call
rx_split_fp_compare.

2011-01-22  Nick Clifton  <nickc@redhat.com>

* config/rx/rx.md (cstoresf4): Pass comparison operator to
rx_split_fp_compare.

2011-01-22  Nick Clifton  <nickc@redhat.com>

* config/rx/rx.md (UNSPEC_CONST): New.
(deallocate_and_return): Wrap the amount popped off the stack in
an UNSPEC_CONST in order to stop it being rejected by
-mmax-constant-size.
(pop_and_return): Add a "(return)" rtx.
(call): Drop the immediate operand.
(call_internal): Likewise.
(call_value): Likewise.
(call_value_internal): Likewise.
(sibcall_internal): Likewise.
(sibcall_value_internal): Likewise.
(sibcall): Likewise.  Generate an explicit call using
sibcall_internal.
(sibcall_value): Likewise.
(mov<>): FAIL if a constant operand is not legitimate.
(addsi3_unpsec): New pattern.

* config/rx/rx.c (rx_print_operand_address): Handle UNPSEC
CONSTs.
(ok_for_max_constant): New function.
(gen_safe_add): New function.
(rx_expand_prologue): Use gen_safe_add.
(rx_expand_epilogue): Likewise.
(rx_is_legitimate_constant): Use ok_for_max_constant.  Handle
UNSPEC CONSTs.

2011-01-17  Richard Henderson  <rth@redhat.com>

* config/rx/predicates.md (rx_constshift_operand): Use match_test.
(rx_restricted_mem_operand): New.
(rx_shift_operand): Use register_operand.
(rx_source_operand, rx_compare_operand): Likewise.
* config/rx/rx.md (addsi3_flags): New expander.
(adddi3): Rewrite as expander.
(adc_internal, *adc_flags, adddi3_internal): New patterns.
(subsi3_flags): New expander.
(subdi3): Rewrite as expander.
(sbb_internal, *sbb_flags, subdi3_internal): New patterns.

* config/rx/rx.c (RX_BUILTIN_SAT): Remove.
(rx_init_builtins): Remove sat builtin.
(rx_expand_builtin): Likewise.
* config/rx/rx.md (ssaddsi3): New.
(*sat): Rename from sat.  Represent the CC_REG input.

* config/rx/predicates.md (rshift_operator): New.
* config/rx/rx.c (rx_expand_insv): Remove.
* config/rx/rx-protos.h: Update.
* config/rx/rx.md (*bitset): Rename from bitset.  Swap the ashift
operand to the canonical position.
(*bitset_in_memory, *bitinvert, *bitinvert_in_memory): Similarly.
(*bitclr, *bitclr_in_memory): Similarly.
(*insv_imm, rx_insv_reg, *insv_cond, *bmcc, *insv_cond_lt): New.
(insv): Retain the zero_extract in the expansion.

* config/rx/rx.md (bswapsi2): Use = not + for output reload.
(bswaphi2, bitinvert, revw): Likewise.

* config/rx/rx.c (gen_rx_store_vector): Use VOIDmode for gen_rtx_SET.
(gen_rx_rtsd_vector, gen_rx_popm_vector): Likewise.
* config/rx/rx.md (pop_and_return): Use VOIDmode for SET.
(stack_push, stack_pushm, stack_pop, stack_popm): Likewise.
(bitset, bitset_in_memory): Likewise.
(bitinvert, bitinvert_in_memory): Likewise.
(bitclr, bitclr_in_memory): Likewise.
(insv, sync_lock_test_and_setsi, movstr, rx_movstr): Likewise.
(rx_strend, rx_cmpstrn): Likewise.
(rx_setmem): Likewise.  Make the source BLKmode to match the dest.
(bitop peep2 patterns): Remove.

* config/rx/rx.c (rx_match_ccmode): New.
* config/rx/rx-protos.h: Update.
* config/rx/rx.md (abssi2): Clobber, don't set flags.
(addsi3, adddi3, andsi3, negsi2, one_cmplsi2, iorsi3): Likewise.
(rotlsi3, rotrsi3, ashrsi3, lshrsi3, ashlsi3): Likewise.
(subsi3, subdi3, xorsi3, addsf3, divsf3, mulsf3, subsf3): Likewise.
(fix_truncsfsi2, floatsisf2): Likewise.
(*abssi2_flags, *addsi3_flags, *andsi3_flags, *negsi2_flags): New.
(*one_cmplsi2_flags, *iorsi3_flags, *rotlsi3_flags): New.
(*rotrsi3_flags, *ashrsi3_flags, *lshrsi3_flags, *ashlsi3_flags): New.
(*subsi3_flags, *xorsi3_flags): New.

* config/rx/rx.md (cstoresf4, *cstoresf4): New patterns.

* config/rx/rx.c (rx_print_operand): Remove workaround for
unsplit comparison operations.

* config/rx/rx.md (movsicc): Split after reload.
(*movsicc): Merge *movsieq and *movsine via match_operator.
(*stcc): New pattern.

* config/rx/rx.c (rx_float_compare_mode): Remove.
* config/rx/rx.h (rx_float_compare_mode): Remove.
* config/rx/rx.md (cstoresi4): Split after reload.
(*sccc): New pattern.

* config/rx/predicates.md (label_ref_operand): New.
(rx_z_comparison_operator): New.
(rx_zs_comparison_operator): New.
(rx_fp_comparison_operator): New.
* config/rx/rx.c (rx_print_operand) [B]: Examine comparison modes.
Validate that the flags are set properly for the comparison.
(rx_gen_cond_branch_template): Remove.
(rx_cc_modes_compatible): Remove.
(mode_from_flags): New.
(flags_from_code): Rename from flags_needed_for_conditional.
(rx_cc_modes_compatible): Re-write in terms of flags_from_mode.
(rx_select_cc_mode): Likewise.
(rx_split_fp_compare): New.
(rx_split_cbranch): New.
* config/rx/rx.md (most_cond, zs_cond): Remove iterators.
(*cbranchsi4): Use match_operator and rx_split_cbranch.
(*cbranchsf4): Similarly.
(*cbranchsi4_tst): Rename from *tstbranchsi4_<code>.  Use
match_operator and rx_split_cbranch.
(*cbranchsi4_tst_ext): Combine *tstbranchsi4m_eq and
tstbranchsi4m_ne.  Use match_operator and rx_split_cbranch.
(*cmpsi): Rename from cmpsi.
(*tstsi): Rename from tstsi.
(*cmpsf): Rename from cmpsf; use CC_Fmode.
(*conditional_branch): Rename from conditional_branch.
(*reveresed_conditional_branch): Remove.
(b<code>): Remove expander.
* config/rx/rx-protos.h: Update.

* config/rx/rx.c (rx_compare_redundant): Remove.
* config/rx/rx.md (cmpsi): Don't use it.
* config/rx/rx-protos.h: Update.

* config/rx/rx-modes.def (CC_F): New mode.
* config/rx/rx.c (rx_select_cc_mode): New.
* config/rx/rx.h (SELECT_CC_MODE): Use it.
* config/rx/rx-protos.h: Update.

From-SVN: r169526

gcc/ChangeLog
gcc/config/rx/predicates.md
gcc/config/rx/rx-modes.def
gcc/config/rx/rx-protos.h
gcc/config/rx/rx.c
gcc/config/rx/rx.h
gcc/config/rx/rx.md

index 27c16ea23b5c6a0e73bcb26f29c5d5396001a671..0a67267d10de8c5664a213f0976e011a6785fdf7 100644 (file)
@@ -1,3 +1,181 @@
+2011-02-02  Nick Clifton  <nickc@redhat.com>
+
+       Import these patches from the mainline:
+       2011-01-31  Nick Clifton  <nickc@redhat.com>
+
+       * config/rx/rx.c (rx_get_stack_layout): Only save call clobbered
+       registers inside interrupt handlers if the handler is not a leaf
+       function.
+
+       2011-01-25  Nick Clifton  <nickc@redhat.com>
+
+       * config/rx/rx.h (LIBCALL_VALUE): Do not promote complex types.
+       * config/rx/rx.c (rx_function_value): Likewise.
+       (rx_promote_function_mode): Likewise.
+       (gen_safe_add): Place an outsized immediate value inside an UNSPEC
+       in order to make it legitimate.
+       * config/rx/rx.md (adddi3_internal): If the second operand is a
+       MEM make sure that the first operand is the same as the result
+       register.
+       (addsi3_unspec): Delete.
+       (subdi3): Do not accept immediate operands.
+       (subdi3_internal): Likewise.
+
+       2011-01-24  Richard Henderson  <rth@redhat.com>
+
+       * config/rx/predicates.md (rx_fp_comparison_operator): Don't accept
+       compound unordered comparisons.
+       * config/rx/rx.c (rx_split_fp_compare): Remove.
+       * config/rx/rx-protos.h: Update.
+       * config/rx/rx.md (gcc_conds, rx_conds): Remove.
+       (cbranchsf4): Don't call rx_split_fp_compare.
+       (*cbranchsf4): Use rx_split_cbranch.
+       (*cmpsf): Don't accept "i" constraint.
+       (*conditional_branch): Only valid after reload.
+       (cstoresf4): Merge expander with insn.  Don't call
+       rx_split_fp_compare.
+
+       2011-01-22  Nick Clifton  <nickc@redhat.com>
+
+       * config/rx/rx.md (cstoresf4): Pass comparison operator to
+       rx_split_fp_compare.
+
+       2011-01-22  Nick Clifton  <nickc@redhat.com>
+
+       * config/rx/rx.md (UNSPEC_CONST): New.
+       (deallocate_and_return): Wrap the amount popped off the stack in
+       an UNSPEC_CONST in order to stop it being rejected by
+       -mmax-constant-size.
+       (pop_and_return): Add a "(return)" rtx.
+       (call): Drop the immediate operand.
+       (call_internal): Likewise.
+       (call_value): Likewise.
+       (call_value_internal): Likewise.
+       (sibcall_internal): Likewise.
+       (sibcall_value_internal): Likewise.
+       (sibcall): Likewise.  Generate an explicit call using
+       sibcall_internal.
+       (sibcall_value): Likewise.
+       (mov<>): FAIL if a constant operand is not legitimate.
+       (addsi3_unpsec): New pattern.
+
+       * config/rx/rx.c (rx_print_operand_address): Handle UNPSEC
+       CONSTs.
+       (ok_for_max_constant): New function.
+       (gen_safe_add): New function.
+       (rx_expand_prologue): Use gen_safe_add.
+       (rx_expand_epilogue): Likewise.
+       (rx_is_legitimate_constant): Use ok_for_max_constant.  Handle
+       UNSPEC CONSTs.
+
+       2011-01-17  Richard Henderson  <rth@redhat.com>
+
+       * config/rx/predicates.md (rx_constshift_operand): Use match_test.
+       (rx_restricted_mem_operand): New.
+       (rx_shift_operand): Use register_operand.
+       (rx_source_operand, rx_compare_operand): Likewise.
+       * config/rx/rx.md (addsi3_flags): New expander.
+       (adddi3): Rewrite as expander.
+       (adc_internal, *adc_flags, adddi3_internal): New patterns.
+       (subsi3_flags): New expander.
+       (subdi3): Rewrite as expander.
+       (sbb_internal, *sbb_flags, subdi3_internal): New patterns.
+
+       * config/rx/rx.c (RX_BUILTIN_SAT): Remove.
+       (rx_init_builtins): Remove sat builtin.
+       (rx_expand_builtin): Likewise.
+       * config/rx/rx.md (ssaddsi3): New.
+       (*sat): Rename from sat.  Represent the CC_REG input.
+
+       * config/rx/predicates.md (rshift_operator): New.
+       * config/rx/rx.c (rx_expand_insv): Remove.
+       * config/rx/rx-protos.h: Update.
+       * config/rx/rx.md (*bitset): Rename from bitset.  Swap the ashift
+       operand to the canonical position.
+       (*bitset_in_memory, *bitinvert, *bitinvert_in_memory): Similarly.
+       (*bitclr, *bitclr_in_memory): Similarly.
+       (*insv_imm, rx_insv_reg, *insv_cond, *bmcc, *insv_cond_lt): New.
+       (insv): Retain the zero_extract in the expansion.
+
+       * config/rx/rx.md (bswapsi2): Use = not + for output reload.
+       (bswaphi2, bitinvert, revw): Likewise.
+
+       * config/rx/rx.c (gen_rx_store_vector): Use VOIDmode for gen_rtx_SET.
+       (gen_rx_rtsd_vector, gen_rx_popm_vector): Likewise.
+       * config/rx/rx.md (pop_and_return): Use VOIDmode for SET.
+       (stack_push, stack_pushm, stack_pop, stack_popm): Likewise.
+       (bitset, bitset_in_memory): Likewise.
+       (bitinvert, bitinvert_in_memory): Likewise.
+       (bitclr, bitclr_in_memory): Likewise.
+       (insv, sync_lock_test_and_setsi, movstr, rx_movstr): Likewise.
+       (rx_strend, rx_cmpstrn): Likewise.
+       (rx_setmem): Likewise.  Make the source BLKmode to match the dest.
+       (bitop peep2 patterns): Remove.
+
+       * config/rx/rx.c (rx_match_ccmode): New.
+       * config/rx/rx-protos.h: Update.
+       * config/rx/rx.md (abssi2): Clobber, don't set flags.
+       (addsi3, adddi3, andsi3, negsi2, one_cmplsi2, iorsi3): Likewise.
+       (rotlsi3, rotrsi3, ashrsi3, lshrsi3, ashlsi3): Likewise.
+       (subsi3, subdi3, xorsi3, addsf3, divsf3, mulsf3, subsf3): Likewise.
+       (fix_truncsfsi2, floatsisf2): Likewise.
+       (*abssi2_flags, *addsi3_flags, *andsi3_flags, *negsi2_flags): New.
+       (*one_cmplsi2_flags, *iorsi3_flags, *rotlsi3_flags): New.
+       (*rotrsi3_flags, *ashrsi3_flags, *lshrsi3_flags, *ashlsi3_flags): New.
+       (*subsi3_flags, *xorsi3_flags): New.
+
+       * config/rx/rx.md (cstoresf4, *cstoresf4): New patterns.
+
+       * config/rx/rx.c (rx_print_operand): Remove workaround for
+       unsplit comparison operations.
+
+       * config/rx/rx.md (movsicc): Split after reload.
+       (*movsicc): Merge *movsieq and *movsine via match_operator.
+       (*stcc): New pattern.
+
+       * config/rx/rx.c (rx_float_compare_mode): Remove.
+       * config/rx/rx.h (rx_float_compare_mode): Remove.
+       * config/rx/rx.md (cstoresi4): Split after reload.
+       (*sccc): New pattern.
+
+       * config/rx/predicates.md (label_ref_operand): New.
+       (rx_z_comparison_operator): New.
+       (rx_zs_comparison_operator): New.
+       (rx_fp_comparison_operator): New.
+       * config/rx/rx.c (rx_print_operand) [B]: Examine comparison modes.
+       Validate that the flags are set properly for the comparison.
+       (rx_gen_cond_branch_template): Remove.
+       (rx_cc_modes_compatible): Remove.
+       (mode_from_flags): New.
+       (flags_from_code): Rename from flags_needed_for_conditional.
+       (rx_cc_modes_compatible): Re-write in terms of flags_from_mode.
+       (rx_select_cc_mode): Likewise.
+       (rx_split_fp_compare): New.
+       (rx_split_cbranch): New.
+       * config/rx/rx.md (most_cond, zs_cond): Remove iterators.
+       (*cbranchsi4): Use match_operator and rx_split_cbranch.
+       (*cbranchsf4): Similarly.
+       (*cbranchsi4_tst): Rename from *tstbranchsi4_<code>.  Use
+       match_operator and rx_split_cbranch.
+       (*cbranchsi4_tst_ext): Combine *tstbranchsi4m_eq and
+       tstbranchsi4m_ne.  Use match_operator and rx_split_cbranch.
+       (*cmpsi): Rename from cmpsi.
+       (*tstsi): Rename from tstsi.
+       (*cmpsf): Rename from cmpsf; use CC_Fmode.
+       (*conditional_branch): Rename from conditional_branch.
+       (*reveresed_conditional_branch): Remove.
+       (b<code>): Remove expander.
+       * config/rx/rx-protos.h: Update.
+
+       * config/rx/rx.c (rx_compare_redundant): Remove.
+       * config/rx/rx.md (cmpsi): Don't use it.
+       * config/rx/rx-protos.h: Update.
+
+       * config/rx/rx-modes.def (CC_F): New mode.
+       * config/rx/rx.c (rx_select_cc_mode): New.
+       * config/rx/rx.h (SELECT_CC_MODE): Use it.
+       * config/rx/rx-protos.h: Update.
+
 2011-02-01  Richard Guenther  <rguenther@suse.de>
 
        PR tree-optimization/47541
 2011-01-30  Gerald Pfeifer  <gerald@pfeifer.com>
 
        * doc/install.texi: Update copyright years.
-       
+
 2011-01-30  Gerald Pfeifer  <gerald@pfeifer.com>
 
        * doc/install.texi (Binaries): Remove outdated reference for
        Motorola 68HC11/68HC12 downloads.
 
 2011-01-30  Gerald Pfeifer  <gerald@pfeifer.com>
-       
+
        * doc/extend.texi (Thread-Local): Adjust reference to Ulrich
        Drepper's paper.
 
index d8def87d6e8b47758420afb457becbe8cacdfa96..5b33c1c52b37ee4f2f94cd74a5a5db177de897fa 100644 (file)
@@ -1,5 +1,5 @@
 ;; Predicate definitions for Renesas RX.
-;; Copyright (C) 2008, 2009 Free Software Foundation, Inc.
+;; Copyright (C) 2008, 2009, 2011 Free Software Foundation, Inc.
 ;; Contributed by Red Hat.
 ;;
 ;; This file is part of GCC.
 ;; Only small integers or a value in a register are permitted.
 
 (define_predicate "rx_shift_operand"
-  (match_code "const_int,reg")
-  {
-    if (CONST_INT_P (op))
-      return IN_RANGE (INTVAL (op), 0, 31);
-    return true;
-  }
+  (ior (match_operand 0 "register_operand")
+       (and (match_code "const_int")
+           (match_test "IN_RANGE (INTVAL (op), 0, 31)")))
 )
 
 (define_predicate "rx_constshift_operand"
-  (match_code "const_int")
-  {
-    return IN_RANGE (INTVAL (op), 0, 31);
-  }
+  (and (match_code "const_int")
+       (match_test "IN_RANGE (INTVAL (op), 0, 31)"))
+)
+
+(define_predicate "rx_restricted_mem_operand"
+  (and (match_code "mem")
+       (match_test "rx_is_restricted_memory_address (XEXP (op, 0), mode)"))
 )
 
 ;; Check that the operand is suitable as the source operand
 ;; and a restricted subset of memory addresses are allowed.
 
 (define_predicate "rx_source_operand"
-  (match_code "const_int,const_double,const,symbol_ref,label_ref,reg,mem")
-  {
-    if (CONSTANT_P (op))
-      return rx_is_legitimate_constant (op);
-
-    if (! MEM_P (op))
-      return true;
-      
-    /* Do not allow size conversions whilst accessing memory.  */
-    if (GET_MODE (op) != mode)
-      return false;
-
-    return rx_is_restricted_memory_address (XEXP (op, 0), mode);
-  }
+  (ior (match_operand 0 "register_operand")
+       (match_operand 0 "immediate_operand")
+       (match_operand 0 "rx_restricted_mem_operand"))
 )
 
 ;; Check that the operand is suitable as the source operand
 ;; CONST_INTs are not.
 
 (define_predicate "rx_compare_operand"
-  (match_code "subreg,reg,mem")
-  {
-    if (GET_CODE (op) == SUBREG)
-      return REG_P (XEXP (op, 0));
-    
-    if (! MEM_P (op))
-      return true;
-
-    return rx_is_restricted_memory_address (XEXP (op, 0), mode);
-  }
+  (ior (match_operand 0 "register_operand")
+       (match_operand 0 "rx_restricted_mem_operand"))
 )
 
 ;; Return true if OP is a store multiple operation.  This looks like:
   element = XVECEXP (op, 0, count - 1);
   return GET_CODE (element) == RETURN;
 })
+
+(define_predicate "label_ref_operand"
+  (match_code "label_ref")
+)
+
+(define_predicate "rx_z_comparison_operator"
+  (match_code "eq,ne")
+)
+
+(define_predicate "rx_zs_comparison_operator"
+  (match_code "eq,ne")
+)
+
+;; GT and LE omitted due to operand swap required.
+(define_predicate "rx_fp_comparison_operator"
+  (match_code "eq,ne,lt,ge,ordered,unordered")
+)
+
+(define_predicate "rshift_operator"
+  (match_code "ashiftrt,lshiftrt")
+)
index 781d93366c6f3c32bb36e842421e2ed4f3585bfb..31e3225c677430097ca3e59f74de1314adcbcd24 100644 (file)
@@ -1,5 +1,6 @@
-/* Definitions of target machine for GNU compiler, for RX.
-   Copyright (C) 2010 by Nick Clifton (nickc@redhat.com).
+/* Definitions of target specific machine modes for the RX.
+   Copyright (C) 2008, 2009, 2010 Free Software Foundation, Inc.
+   Contributed by Red Hat.
 
    This file is part of GCC.
 
@@ -20,3 +21,5 @@
 CC_MODE (CC_ZS);
 CC_MODE (CC_ZSO);
 CC_MODE (CC_ZSC);
+
+CC_MODE (CC_F);                /* fcmp */
index 2ebf1d8f3253afc2d57ae4dcebd319ae8aae615a..2d291c1ad958296272a71ab7835b145ac0ed0d10 100644 (file)
@@ -1,5 +1,5 @@
 /* Exported function prototypes from the Renesas RX backend.
-   Copyright (C) 2008, 2009, 2010 Free Software Foundation, Inc.
+   Copyright (C) 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
    Contributed by Red Hat.
 
    This file is part of GCC.
@@ -35,15 +35,17 @@ extern bool         rx_compare_redundant (rtx);
 extern void             rx_emit_stack_popm (rtx *, bool);
 extern void             rx_emit_stack_pushm (rtx *);
 extern void            rx_expand_epilogue (bool);
-extern bool            rx_expand_insv (rtx *);
 extern const char *    rx_gen_cond_branch_template (rtx, bool);
 extern char *          rx_gen_move_template (rtx *, bool);
 extern bool            rx_is_legitimate_constant (rtx);
 extern bool            rx_is_mode_dependent_addr (rtx);
 extern bool            rx_is_restricted_memory_address (rtx, Mmode);
+extern bool            rx_match_ccmode (rtx, Mmode);
 extern void            rx_notice_update_cc (rtx body, rtx insn);
 extern void            rx_print_operand (FILE *, rtx, int);
 extern void            rx_print_operand_address (FILE *, rtx);
+extern Mmode           rx_select_cc_mode (enum rtx_code, rtx, rtx);
+extern void            rx_split_cbranch (Mmode, enum rtx_code, rtx, rtx, rtx);
 #endif
 
 #ifdef TREE_CODE
index 77e3fcfc47851e42e8f298283f54574ae4673dd1..d1d17f9c65651bb0e3de7e17492b32f928fd3f76 100644 (file)
@@ -1,5 +1,5 @@
 /* Subroutines used for code generation on Renesas RX processors.
-   Copyright (C) 2008, 2009, 2010 Free Software Foundation, Inc.
+   Copyright (C) 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
    Contributed by Red Hat.
 
    This file is part of GCC.
 #include "target-def.h"
 #include "langhooks.h"
 \f
+#define CC_FLAG_S      (1 << 0)
+#define CC_FLAG_Z      (1 << 1)
+#define CC_FLAG_O      (1 << 2)
+#define CC_FLAG_C      (1 << 3)
+#define CC_FLAG_FP     (1 << 4)        /* Fake, to differentiate CC_Fmode.  */
+
 enum rx_cpu_types  rx_cpu_type = RX600;
 \f
 /* Return true if OP is a reference to an object in a small data area.  */
@@ -312,9 +318,18 @@ rx_print_operand_address (FILE * file, rtx addr)
        break;
       }
 
+    case CONST:
+      if (GET_CODE (XEXP (addr, 0)) == UNSPEC)
+       {
+         addr = XEXP (addr, 0);
+         gcc_assert (XINT (addr, 1) == UNSPEC_CONST);
+      
+         addr = XVECEXP (addr, 0, 0);
+         gcc_assert (CONST_INT_P (addr));
+       }
+      /* Fall through.  */
     case LABEL_REF:
     case SYMBOL_REF:
-    case CONST:
       fprintf (file, "#");
     default:
       output_addr_const (file, addr);
@@ -351,8 +366,75 @@ rx_assemble_integer (rtx x, unsigned int size, int is_aligned)
   return true;
 }
 
+/* Convert a CC_MODE to the set of flags that it represents.  */
+
+static unsigned int
+flags_from_mode (enum machine_mode mode)
+{
+  switch (mode)
+    {
+    case CC_ZSmode:
+      return CC_FLAG_S | CC_FLAG_Z;
+    case CC_ZSOmode:
+      return CC_FLAG_S | CC_FLAG_Z | CC_FLAG_O;
+    case CC_ZSCmode:
+      return CC_FLAG_S | CC_FLAG_Z | CC_FLAG_C;
+    case CCmode:
+      return CC_FLAG_S | CC_FLAG_Z | CC_FLAG_O | CC_FLAG_C;
+    case CC_Fmode:
+      return CC_FLAG_FP;
+    default:
+      gcc_unreachable ();
+    }
+}
+
+/* Convert a set of flags to a CC_MODE that can implement it.  */
+
+static enum machine_mode
+mode_from_flags (unsigned int f)
+{
+  if (f & CC_FLAG_FP)
+    return CC_Fmode;
+  if (f & CC_FLAG_O)
+    {
+      if (f & CC_FLAG_C)
+       return CCmode;
+      else
+       return CC_ZSOmode;
+    }
+  else if (f & CC_FLAG_C)
+    return CC_ZSCmode;
+  else
+    return CC_ZSmode;
+}
+
+/* Convert an RTX_CODE to the set of flags needed to implement it.
+   This assumes an integer comparison.  */
 
-int rx_float_compare_mode;
+static unsigned int
+flags_from_code (enum rtx_code code)
+{
+  switch (code)
+    {
+    case LT:
+    case GE:
+      return CC_FLAG_S | CC_FLAG_O;
+    case GT:
+    case LE:
+      return CC_FLAG_S | CC_FLAG_O | CC_FLAG_Z;
+    case GEU:
+    case LTU:
+      return CC_FLAG_C;
+    case GTU:
+    case LEU:
+      return CC_FLAG_C | CC_FLAG_Z;
+    case EQ:
+    case NE:
+      return CC_FLAG_Z;
+    default:
+      gcc_unreachable ();
+    }
+}
 
 /* Handles the insertion of a single operand into the assembler output.
    The %<letter> directives supported are:
@@ -393,21 +475,48 @@ rx_print_operand (FILE * file, rtx op, int letter)
       break;
 
     case 'B':
-      switch (GET_CODE (op))
-       {
-       case LT:  fprintf (file, "lt"); break;
-       case GE:  fprintf (file, "ge"); break;
-       case GT:  fprintf (file, "gt"); break;
-       case LE:  fprintf (file, "le"); break;
-       case GEU: fprintf (file, "geu"); break;
-       case LTU: fprintf (file, "ltu"); break;
-       case GTU: fprintf (file, "gtu"); break;
-       case LEU: fprintf (file, "leu"); break;
-       case EQ:  fprintf (file, "eq"); break;
-       case NE:  fprintf (file, "ne"); break;
-       default:  debug_rtx (op); gcc_unreachable ();
-       }
-      break;
+      {
+       enum rtx_code code = GET_CODE (op);
+       enum machine_mode mode = GET_MODE (XEXP (op, 0));
+       const char * ret;
+
+       if (mode == CC_Fmode)
+         {
+           /* C flag is undefined, and O flag carries unordered.  None of the
+              branch combinations that include O use it helpfully.  */
+           switch (code)
+             {
+             case ORDERED:     ret = "no";             break;
+             case UNORDERED:   ret = "o";              break;
+             case LT:          ret = "n";              break;
+             case GE:          ret = "pz";             break;
+             case EQ:          ret = "eq";             break;
+             case NE:          ret = "ne";             break;
+             default:          gcc_unreachable ();
+             }
+         }
+       else
+         {
+           switch (code)
+             {
+             case LT:          ret = "lt";             break;
+             case GE:          ret = "ge";             break;
+             case GT:          ret = "gt";             break;
+             case LE:          ret = "le";             break;
+             case GEU:         ret = "geu";            break;
+             case LTU:         ret = "ltu";            break;
+             case GTU:         ret = "gtu";            break;
+             case LEU:         ret = "leu";            break;
+             case EQ:          ret = "eq";             break;
+             case NE:          ret = "ne";             break;
+             default:          gcc_unreachable ();
+             }
+           gcc_assert ((flags_from_code (code)
+                        & ~flags_from_mode (mode)) == 0);
+         }
+       fputs (ret, file);
+       break;
+      }
 
     case 'C':
       gcc_assert (CONST_INT_P (op));
@@ -698,51 +807,6 @@ rx_gen_move_template (rtx * operands, bool is_movu)
           extension, src_template, dst_template);
   return out_template;
 }
-
-/* Returns an assembler template for a conditional branch instruction.  */
-
-const char *
-rx_gen_cond_branch_template (rtx condition, bool reversed)
-{
-  enum rtx_code code = GET_CODE (condition);
-
-  if (reversed)
-    {
-      if (rx_float_compare_mode)
-       code = reverse_condition_maybe_unordered (code);
-      else
-       code = reverse_condition (code);
-    }
-
-  /* We do not worry about encoding the branch length here as GAS knows
-     how to choose the smallest version, and how to expand a branch that
-     is to a destination that is out of range.  */
-
-  switch (code)
-    {
-    case UNEQ:     return "bo\t1f\n\tbeq\t%0\n1:";
-    case LTGT:     return "bo\t1f\n\tbne\t%0\n1:";
-    case UNLT:      return "bo\t1f\n\tbn\t%0\n1:";
-    case UNGE:      return "bo\t1f\n\tbpz\t%0\n1:";
-    case UNLE:      return "bo\t1f\n\tbgt\t1f\n\tbra\t%0\n1:";
-    case UNGT:      return "bo\t1f\n\tble\t1f\n\tbra\t%0\n1:";
-    case UNORDERED: return "bo\t%0";
-    case ORDERED:   return "bno\t%0";
-
-    case LT:        return rx_float_compare_mode ? "bn\t%0" : "blt\t%0";
-    case GE:        return rx_float_compare_mode ? "bpz\t%0" : "bge\t%0";
-    case GT:        return "bgt\t%0";
-    case LE:        return "ble\t%0";
-    case GEU:       return "bgeu\t%0";
-    case LTU:       return "bltu\t%0";
-    case GTU:       return "bgtu\t%0";
-    case LEU:       return "bleu\t%0";
-    case EQ:        return "beq\t%0";
-    case NE:        return "bne\t%0";
-    default:
-      gcc_unreachable ();
-    }
-}
 \f
 /* Return VALUE rounded up to the next ALIGNMENT boundary.  */
 
@@ -825,7 +889,9 @@ rx_function_value (const_tree ret_type,
 
   /* RX ABI specifies that small integer types are
      promoted to int when returned by a function.  */
-  if (GET_MODE_SIZE (mode) > 0 && GET_MODE_SIZE (mode) < 4)
+  if (GET_MODE_SIZE (mode) > 0
+      && GET_MODE_SIZE (mode) < 4
+      && ! COMPLEX_MODE_P (mode))
     return gen_rtx_REG (SImode, FUNC_RETURN_REGNUM);
     
   return gen_rtx_REG (mode, FUNC_RETURN_REGNUM);
@@ -843,6 +909,7 @@ rx_promote_function_mode (const_tree type ATTRIBUTE_UNUSED,
 {
   if (for_return != 1
       || GET_MODE_SIZE (mode) >= 4
+      || COMPLEX_MODE_P (mode)
       || GET_MODE_SIZE (mode) < 1)
     return mode;
 
@@ -1083,7 +1150,13 @@ rx_get_stack_layout (unsigned int * lowest,
 
   for (save_mask = high = low = 0, reg = 1; reg < CC_REGNUM; reg++)
     {
-      if (df_regs_ever_live_p (reg)
+      if ((df_regs_ever_live_p (reg)
+          /* Always save all call clobbered registers inside non-leaf
+             interrupt handlers, even if they are not live - they may
+             be used in (non-interrupt aware) routines called from this one.  */
+          || (call_used_regs[reg]
+              && is_interrupt_func (NULL_TREE)
+              && ! current_function_is_leaf))
          && (! call_used_regs[reg]
              /* Even call clobbered registered must
                 be pushed inside interrupt handlers.  */
@@ -1238,6 +1311,59 @@ mark_frame_related (rtx insn)
     }
 }
 
+static bool
+ok_for_max_constant (HOST_WIDE_INT val)
+{
+  if (rx_max_constant_size == 0  || rx_max_constant_size == 4)
+    /* If there is no constraint on the size of constants
+       used as operands, then any value is legitimate.  */
+    return true;
+
+  /* rx_max_constant_size specifies the maximum number
+     of bytes that can be used to hold a signed value.  */
+  return IN_RANGE (val, (-1 << (rx_max_constant_size * 8)),
+                       ( 1 << (rx_max_constant_size * 8)));
+}
+
+/* Generate an ADD of SRC plus VAL into DEST.
+   Handles the case where VAL is too big for max_constant_value.
+   Sets FRAME_RELATED_P on the insn if IS_FRAME_RELATED is true.  */
+
+static void
+gen_safe_add (rtx dest, rtx src, rtx val, bool is_frame_related)
+{
+  rtx insn;
+
+  if (val == NULL_RTX || INTVAL (val) == 0)
+    {
+      gcc_assert (dest != src);
+
+      insn = emit_move_insn (dest, src);
+    }
+  else if (ok_for_max_constant (INTVAL (val)))
+    insn = emit_insn (gen_addsi3 (dest, src, val));
+  else
+    {
+      /* Wrap VAL in an UNSPEC so that rx_is_legitimate_constant
+        will not reject it.  */
+      val = gen_rtx_CONST (SImode, gen_rtx_UNSPEC (SImode, gen_rtvec (1, val), UNSPEC_CONST));
+      insn = emit_insn (gen_addsi3 (dest, src, val));
+
+      if (is_frame_related)
+       /* We have to provide our own frame related note here
+          as the dwarf2out code cannot be expected to grok
+          our unspec.  */
+       add_reg_note (insn, REG_FRAME_RELATED_EXPR,
+                     gen_rtx_SET (SImode, dest,
+                                  gen_rtx_PLUS (SImode, src, val)));
+      return;
+    }
+
+  if (is_frame_related)
+    RTX_FRAME_RELATED_P (insn) = 1;
+  return;
+}
+
 void
 rx_expand_prologue (void)
 {
@@ -1323,23 +1449,12 @@ rx_expand_prologue (void)
          emit_insn (gen_stack_pushm (GEN_INT (2 * UNITS_PER_WORD),
                                      gen_rx_store_vector (acc_low, acc_high)));
        }
-
-      frame_size += 2 * UNITS_PER_WORD;
     }
 
   /* If needed, set up the frame pointer.  */
   if (frame_pointer_needed)
-    {
-      if (frame_size)
-       insn = emit_insn (gen_addsi3 (frame_pointer_rtx, stack_pointer_rtx,
-                                     GEN_INT (- (HOST_WIDE_INT) frame_size)));
-      else
-       insn = emit_move_insn (frame_pointer_rtx, stack_pointer_rtx);
-
-      RTX_FRAME_RELATED_P (insn) = 1;
-    }
-
-  insn = NULL_RTX;
+    gen_safe_add (frame_pointer_rtx, stack_pointer_rtx,
+                 GEN_INT (- (HOST_WIDE_INT) frame_size), true);
 
   /* Allocate space for the outgoing args.
      If the stack frame has not already been set up then handle this as well.  */
@@ -1348,29 +1463,26 @@ rx_expand_prologue (void)
       if (frame_size)
        {
          if (frame_pointer_needed)
-           insn = emit_insn (gen_addsi3 (stack_pointer_rtx, frame_pointer_rtx,
-                                         GEN_INT (- (HOST_WIDE_INT)
-                                                  stack_size)));
+           gen_safe_add (stack_pointer_rtx, frame_pointer_rtx,
+                         GEN_INT (- (HOST_WIDE_INT) stack_size), true);
          else
-           insn = emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx,
-                                         GEN_INT (- (HOST_WIDE_INT)
-                                                  (frame_size + stack_size))));
+           gen_safe_add (stack_pointer_rtx, stack_pointer_rtx,
+                         GEN_INT (- (HOST_WIDE_INT) (frame_size + stack_size)),
+                         true);
        }
       else
-       insn = emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx,
-                                     GEN_INT (- (HOST_WIDE_INT) stack_size)));
+       gen_safe_add (stack_pointer_rtx, stack_pointer_rtx,
+                     GEN_INT (- (HOST_WIDE_INT) stack_size), true);
     }
   else if (frame_size)
     {
       if (! frame_pointer_needed)
-       insn = emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx,
-                                     GEN_INT (- (HOST_WIDE_INT) frame_size)));
+       gen_safe_add (stack_pointer_rtx, stack_pointer_rtx,
+                     GEN_INT (- (HOST_WIDE_INT) frame_size), true);
       else
-       insn = emit_move_insn (stack_pointer_rtx, frame_pointer_rtx);
+       gen_safe_add (stack_pointer_rtx, frame_pointer_rtx, NULL_RTX,
+                     true);
     }
-
-  if (insn != NULL_RTX)
-    RTX_FRAME_RELATED_P (insn) = 1;
 }
 
 static void
@@ -1548,8 +1660,8 @@ rx_expand_epilogue (bool is_sibcall)
     {
       /* Cannot use the special instructions - deconstruct by hand.  */
       if (total_size)
-       emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx,
-                              GEN_INT (total_size)));
+       gen_safe_add (stack_pointer_rtx, stack_pointer_rtx,
+                     GEN_INT (total_size), false);
 
       if (MUST_SAVE_ACC_REGISTER)
        {
@@ -1640,8 +1752,8 @@ rx_expand_epilogue (bool is_sibcall)
          return;
        }
 
-      emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx,
-                            GEN_INT (total_size)));
+      gen_safe_add (stack_pointer_rtx, stack_pointer_rtx,
+                   GEN_INT (total_size), false);
     }
 
   if (low)
@@ -1918,7 +2030,7 @@ rx_expand_builtin_mvtipl (rtx arg)
   if (rx_cpu_type == RX610)
     return NULL_RTX;
 
-  if (! CONST_INT_P (arg) || ! IN_RANGE (arg, 0, (1 << 4) - 1))
+  if (! CONST_INT_P (arg) || ! IN_RANGE (INTVAL (arg), 0, (1 << 4) - 1))
     return NULL_RTX;
 
   emit_insn (gen_mvtipl (arg));
@@ -1987,6 +2099,31 @@ rx_expand_builtin_round (rtx arg, rtx target)
   return target;
 }
 
+static int
+valid_psw_flag (rtx op, const char *which)
+{
+  static int mvtc_inform_done = 0;
+
+  if (GET_CODE (op) == CONST_INT)
+    switch (INTVAL (op))
+      {
+      case 0: case 'c': case 'C':
+      case 1: case 'z': case 'Z':
+      case 2: case 's': case 'S':
+      case 3: case 'o': case 'O':
+      case 8: case 'i': case 'I':
+      case 9: case 'u': case 'U':
+       return 1;
+      }
+
+  error ("__builtin_rx_%s takes 'C', 'Z', 'S', 'O', 'I', or 'U'", which);
+  if (!mvtc_inform_done)
+    error ("use __builtin_rx_mvtc (0, ... ) to write arbitrary values to PSW");
+  mvtc_inform_done = 1;
+
+  return 0;
+}
+
 static rtx
 rx_expand_builtin (tree exp,
                   rtx target,
@@ -2002,10 +2139,14 @@ rx_expand_builtin (tree exp,
   switch (fcode)
     {
     case RX_BUILTIN_BRK:     emit_insn (gen_brk ()); return NULL_RTX;
-    case RX_BUILTIN_CLRPSW:  return rx_expand_void_builtin_1_arg
-       (op, gen_clrpsw, false);
-    case RX_BUILTIN_SETPSW:  return rx_expand_void_builtin_1_arg
-       (op, gen_setpsw, false);
+    case RX_BUILTIN_CLRPSW:  
+      if (! valid_psw_flag (op, "clrpsw"))
+       return NULL_RTX;
+      return rx_expand_void_builtin_1_arg (op, gen_clrpsw, false);
+      if (! valid_psw_flag (op, "setpsw"))
+       return NULL_RTX;
+      return rx_expand_void_builtin_1_arg (op, gen_setpsw, false);
+    case RX_BUILTIN_SETPSW:  
     case RX_BUILTIN_INT:     return rx_expand_void_builtin_1_arg
        (op, gen_int, false);
     case RX_BUILTIN_MACHI:   return rx_expand_builtin_mac (exp, gen_machi);
@@ -2211,7 +2352,6 @@ rx_set_optimization_options (void)
        error ("Changing the FPU insns/math optimizations pairing is not supported");
     }
 }
-
 \f
 static bool
 rx_allocate_stack_slots_for_args (void)
@@ -2258,50 +2398,10 @@ rx_file_start (void)
 static bool
 rx_is_ms_bitfield_layout (const_tree record_type ATTRIBUTE_UNUSED)
 {
-  return TRUE;
+  /* The packed attribute overrides the MS behaviour.  */
+  return ! TYPE_PACKED (record_type);
 }
 
-/* Try to generate code for the "isnv" pattern which inserts bits
-   into a word.
-     operands[0] => Location to be altered.
-     operands[1] => Number of bits to change.
-     operands[2] => Starting bit.
-     operands[3] => Value to insert.
-   Returns TRUE if successful, FALSE otherwise.  */
-
-bool
-rx_expand_insv (rtx * operands)
-{
-  if (INTVAL (operands[1]) != 1
-      || ! CONST_INT_P (operands[3]))
-    return false;
-
-  if (MEM_P (operands[0])
-      && INTVAL (operands[2]) > 7)
-    return false;
-
-  switch (INTVAL (operands[3]))
-    {
-    case 0:
-      if (MEM_P (operands[0]))
-       emit_insn (gen_bitclr_in_memory (operands[0], operands[0],
-                                        operands[2]));
-      else
-       emit_insn (gen_bitclr (operands[0], operands[0], operands[2]));
-      break;
-    case 1:
-    case -1:
-      if (MEM_P (operands[0]))
-       emit_insn (gen_bitset_in_memory (operands[0], operands[0],
-                                        operands[2]));
-      else
-       emit_insn (gen_bitset (operands[0], operands[0], operands[2]));
-      break;
-   default:
-      return false;
-    }
-  return true;
-}
 \f
 /* Returns true if X a legitimate constant for an immediate
    operand on the RX.  X is already known to satisfy CONSTANT_P.  */
@@ -2309,8 +2409,6 @@ rx_expand_insv (rtx * operands)
 bool
 rx_is_legitimate_constant (rtx x)
 {
-  HOST_WIDE_INT val;
-
   switch (GET_CODE (x))
     {
     case CONST:
@@ -2333,7 +2431,9 @@ rx_is_legitimate_constant (rtx x)
        case SYMBOL_REF:
          return true;
 
-         /* One day we may have to handle UNSPEC constants here.  */
+       case UNSPEC:
+         return XINT (x, 1) == UNSPEC_CONST;
+
        default:
          /* FIXME: Can this ever happen ?  */
          abort ();
@@ -2353,17 +2453,7 @@ rx_is_legitimate_constant (rtx x)
       break;
     }
 
-  if (rx_max_constant_size == 0  || rx_max_constant_size == 4)
-    /* If there is no constraint on the size of constants
-       used as operands, then any value is legitimate.  */
-    return true;
-
-  val = INTVAL (x);
-
-  /* rx_max_constant_size specifies the maximum number
-     of bytes that can be used to hold a signed value.  */
-  return IN_RANGE (val, (-1 << (rx_max_constant_size * 8)),
-                       ( 1 << (rx_max_constant_size * 8)));
+  return ok_for_max_constant (INTVAL (x));
 }
 
 static int
@@ -2487,211 +2577,83 @@ rx_trampoline_init (rtx tramp, tree fndecl, rtx chain)
     }
 }
 
+/* Return a CC_MODE of which both M1 and M2 are subsets.  */
+
 static enum machine_mode
 rx_cc_modes_compatible (enum machine_mode m1, enum machine_mode m2)
 {
-  if (m1 == CCmode)
-    return m2;
-  if (m2 == CCmode)
-    return m1;
+  unsigned f;
+
+  /* Early out for identical modes.  */
   if (m1 == m2)
     return m1;
-  if (m1 == CC_ZSmode)
-    return m1;
-  if (m2 == CC_ZSmode)
-    return m2;
-  return VOIDmode;   
+
+  /* There's no valid combination for FP vs non-FP.  */
+  f = flags_from_mode (m1) | flags_from_mode (m2);
+  if (f & CC_FLAG_FP)
+    return VOIDmode;
+
+  /* Otherwise, see what mode can implement all the flags.  */
+  return mode_from_flags (f);
 }
 
-#define CC_FLAG_S (1 << 0)
-#define CC_FLAG_Z (1 << 1)
-#define CC_FLAG_O (1 << 2)
-#define CC_FLAG_C (1 << 3)
+/* Return the minimal CC mode needed to implement (CMP_CODE X Y).  */
 
-static unsigned int
-flags_needed_for_conditional (rtx conditional)
+enum machine_mode
+rx_select_cc_mode (enum rtx_code cmp_code, rtx x, rtx y ATTRIBUTE_UNUSED)
 {
-  switch (GET_CODE (conditional))
-    {
-    case LE:
-    case GT:   return CC_FLAG_S | CC_FLAG_Z | CC_FLAG_O;
-
-    case LEU:
-    case GTU:  return CC_FLAG_Z | CC_FLAG_C;
+  if (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT)
+    return CC_Fmode;
 
-    case LT:
-    case GE:   return CC_FLAG_S | CC_FLAG_O;
+  return mode_from_flags (flags_from_code (cmp_code));
+}
 
-    case LTU:
-    case GEU:  return CC_FLAG_C;
+/* Split the conditional branch.  Emit (COMPARE C1 C2) into CC_REG with
+   CC_MODE, and use that in branches based on that compare.  */
 
-    case EQ:
-    case NE:   return CC_FLAG_Z;
+void
+rx_split_cbranch (enum machine_mode cc_mode, enum rtx_code cmp1,
+                 rtx c1, rtx c2, rtx label)
+{
+  rtx flags, x;
 
-    default:   gcc_unreachable ();
-    }
-}
+  flags = gen_rtx_REG (cc_mode, CC_REG);
+  x = gen_rtx_COMPARE (cc_mode, c1, c2);
+  x = gen_rtx_SET (VOIDmode, flags, x);
+  emit_insn (x);
 
-static unsigned int
-flags_from_mode (enum machine_mode mode)
-{
-  switch (mode)
-    {
-    case CCmode:     return CC_FLAG_S | CC_FLAG_Z | CC_FLAG_O | CC_FLAG_C;
-    case CC_ZSmode:  return CC_FLAG_S | CC_FLAG_Z;
-    case CC_ZSOmode: return CC_FLAG_S | CC_FLAG_Z | CC_FLAG_O;
-    case CC_ZSCmode: return CC_FLAG_S | CC_FLAG_Z | CC_FLAG_C;
-    default:         gcc_unreachable ();
-    }
+  x = gen_rtx_fmt_ee (cmp1, VOIDmode, flags, const0_rtx);
+  x = gen_rtx_IF_THEN_ELSE (VOIDmode, x, label, pc_rtx);
+  x = gen_rtx_SET (VOIDmode, pc_rtx, x);
+  emit_jump_insn (x);
 }
 
-/* Returns true if a compare insn is redundant because it
-   would only set flags that are already set correctly.  */
+/* A helper function for matching parallels that set the flags.  */
 
 bool
-rx_compare_redundant (rtx cmp)
-{
-  unsigned int flags_needed;
-  unsigned int flags_set;
-  rtx next;
-  rtx prev;
-  rtx source;
-  rtx dest;
-  static rtx cc_reg = NULL_RTX;
-
-  if (cc_reg == NULL_RTX)
-    cc_reg = gen_rtx_REG (CCmode, CC_REGNUM);
-
-  /* We can only eliminate compares against 0.  */
-  if (GET_CODE (XEXP (SET_SRC (PATTERN (cmp)), 1)) != CONST_INT
-      || INTVAL (XEXP (SET_SRC (PATTERN (cmp)), 1)) != 0)
-    return false;
-
-  /* Locate the branch insn that follows the
-     compare and which tests the bits in the PSW.  */
-  next = cmp;
-  do
-    {
-      /* If we have found an insn that sets or clobbers the CC
-        register and it was not the IF_THEN_ELSE insn that we
-        are looking for, then the comparison is redundant.  */
-      if (next != cmp && reg_mentioned_p (cc_reg, PATTERN (next)))
-       return true;
-
-      next = next_nonnote_insn (next);
-
-      /* If we run out of insns without finding the
-        user then the comparison is unnecessary.  */
-      if (next == NULL_RTX)
-       return true;
-
-      /* If we have found another comparison
-        insn then the first one is redundant.  */
-      if (INSN_P (next)
-         && GET_CODE (PATTERN (next)) == SET
-         && REG_P (SET_DEST (PATTERN (next)))
-         && REGNO (SET_DEST (PATTERN (next))) == CC_REGNUM)
-       return true;
+rx_match_ccmode (rtx insn, enum machine_mode cc_mode)
+{
+  rtx op1, flags;
+  enum machine_mode flags_mode;
 
-      /* If we have found another arithmetic/logic insn that
-        sets the PSW flags then the comparison is redundant.  */
-      if (INSN_P (next)
-         && GET_CODE (PATTERN (next)) == PARALLEL
-         && GET_CODE (XVECEXP (PATTERN (next), 0, 1)) == SET
-         && REG_P (SET_DEST (XVECEXP (PATTERN (next), 0, 1)))
-         && REGNO (SET_DEST (XVECEXP (PATTERN (next), 0, 1))) == CC_REGNUM)
-       return true;
+  gcc_assert (XVECLEN (PATTERN (insn), 0) == 2);
 
-      /* If we have found an unconditional branch then the
-        PSW flags might be carried along with the jump, so
-        the comparison is necessary.  */
-      if (INSN_P (next) && JUMP_P (next))
-       {
-         if (GET_CODE (PATTERN (next)) != SET)
-           /* If the jump does not involve setting the PC
-              then it is a return of some kind, and we know
-              that the comparison is not used.  */
-           return true;
+  op1 = XVECEXP (PATTERN (insn), 0, 1);
+  gcc_assert (GET_CODE (SET_SRC (op1)) == COMPARE);
 
-         if (GET_CODE (SET_SRC (PATTERN (next))) != IF_THEN_ELSE)
-           return false;
-       }
-    }
-  while (! INSN_P (next)
-        || DEBUG_INSN_P (next)
-        || GET_CODE (PATTERN (next)) != SET
-        || GET_CODE (SET_SRC (PATTERN (next))) != IF_THEN_ELSE);
-
-  flags_needed = flags_needed_for_conditional (XEXP (SET_SRC (PATTERN (next)), 0));
-
-  /* Now look to see if there was a previous
-     instruction which set the PSW bits.  */
-  source = XEXP (SET_SRC (PATTERN (cmp)), 0);
-  prev = cmp;
-  do
-    {
-      /* If this insn uses/sets/clobbers the CC register
-        and it is not the insn that we are looking for
-        below, then we must need the comparison.  */
-      if (prev != cmp && reg_mentioned_p (cc_reg, PATTERN (prev)))
-       return false;
-
-      prev = prev_nonnote_insn (prev);
+  flags = SET_DEST (op1);
+  flags_mode = GET_MODE (flags);
 
-      if (prev == NULL_RTX)
-       return false;
-
-      /* If we encounter an insn which changes the contents of
-        the register which is the source of the comparison then
-        we will definitely need the comparison.  */
-      if (INSN_P (prev)
-         && GET_CODE (PATTERN (prev)) == SET
-         && rtx_equal_p (SET_DEST (PATTERN (prev)), source))
-       {
-         /* Unless this instruction is a simple register move
-            instruction.  In which case we can continue our
-            scan backwards, but now using the *source* of this
-            set instruction.  */
-         if (REG_P (SET_SRC (PATTERN (prev))))
-           source = SET_SRC (PATTERN (prev));
-         /* We can also survive a sign-extension if the test is
-            for EQ/NE.  Note the same does not apply to zero-
-            extension as this can turn a non-zero bit-pattern
-            into zero.  */
-         else if (flags_needed == CC_FLAG_Z
-                  && GET_CODE (SET_SRC (PATTERN (prev))) == SIGN_EXTEND)
-           source = XEXP (SET_SRC (PATTERN (prev)), 0);
-         else
-           return false;
-       }
+  if (GET_MODE (SET_SRC (op1)) != flags_mode)
+    return false;
+  if (GET_MODE_CLASS (flags_mode) != MODE_CC)
+    return false;
 
-      /* A label means a possible branch into the
-        code here, so we have to stop scanning.  */
-      if (LABEL_P (prev))
-       return false;
-    }
-  while (! INSN_P (prev)
-        || DEBUG_INSN_P (prev)
-        || GET_CODE (PATTERN (prev)) != PARALLEL
-        || GET_CODE (XVECEXP (PATTERN (prev), 0, 1)) != SET
-        || ! REG_P (SET_DEST (XVECEXP (PATTERN (prev), 0, 1)))
-        || REGNO (SET_DEST (XVECEXP (PATTERN (prev), 0, 1))) != CC_REGNUM);
-
-  flags_set = flags_from_mode (GET_MODE (SET_DEST (XVECEXP (PATTERN (prev), 0, 1))));
-
-  dest = SET_DEST (XVECEXP (PATTERN (prev), 0, 0));
-  /* The destination of the previous arithmetic/logic instruction
-     must match the source in the comparison operation.  For registers
-     we ignore the mode as there may have been a sign-extension involved.  */
-  if (! rtx_equal_p (source, dest))
-    {
-      if (REG_P (source) && REG_P (dest) && REGNO (dest) == REGNO (source))
-       ;
-      else
-       return false;
-    }
+  /* Ensure that the mode of FLAGS is compatible with CC_MODE.  */
+  if (flags_from_mode (flags_mode) & ~flags_from_mode (cc_mode))
+    return false;
 
-  return ((flags_set & flags_needed) == flags_needed);
+  return true;
 }
 \f
 #undef  TARGET_FUNCTION_VALUE
index fae30a0a028d28574c6bfc80af31ffec98731468..85e911916cf3fb0e52559bea130a5b6620bbf128 100644 (file)
@@ -1,5 +1,5 @@
 /* GCC backend definitions for the Renesas RX processor.
-   Copyright (C) 2008, 2009, 2010 Free Software Foundation, Inc.
+   Copyright (C) 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
    Contributed by Red Hat.
 
    This file is part of GCC.
       builtin_define ("__RX__");               \
       builtin_assert ("cpu=RX");               \
       if (rx_cpu_type == RX610)                        \
-        builtin_assert ("machine=RX610");      \
+       {                                       \
+          builtin_define ("__RX610__");                \
+          builtin_assert ("machine=RX610");    \
+       }                                       \
      else                                      \
         builtin_assert ("machine=RX600");      \
                                                \
@@ -144,6 +147,10 @@ extern enum rx_cpu_types  rx_cpu_type;
 #define SIZE_TYPE                      "long unsigned int"
 #undef  PTRDIFF_TYPE
 #define PTRDIFF_TYPE                   "long int"
+#undef  WCHAR_TYPE
+#define WCHAR_TYPE                     "long int"
+#undef  WCHAR_TYPE_SIZE
+#define WCHAR_TYPE_SIZE                        BITS_PER_WORD
 #define POINTERS_EXTEND_UNSIGNED       1
 #define FUNCTION_MODE                  QImode
 #define CASE_VECTOR_MODE               Pmode
@@ -260,6 +267,7 @@ enum reg_class
 
 #define LIBCALL_VALUE(MODE)                            \
   gen_rtx_REG (((GET_MODE_CLASS (MODE) != MODE_INT     \
+                 || COMPLEX_MODE_P (MODE)              \
                 || GET_MODE_SIZE (MODE) >= 4)          \
                ? (MODE)                                \
                : SImode),                              \
@@ -354,7 +362,7 @@ typedef unsigned int CUMULATIVE_ARGS;
   {                                                            \
     "r0",  "r1",  "r2",   "r3",   "r4",   "r5",   "r6",   "r7",        \
       "r8",  "r9",  "r10",  "r11",  "r12",  "r13",  "r14",  "r15", "cc"        \
-  };
+  }
 
 #define ADDITIONAL_REGISTER_NAMES      \
 {                                      \
@@ -616,8 +624,6 @@ typedef unsigned int CUMULATIVE_ARGS;
 #define PRINT_OPERAND_ADDRESS(FILE, ADDR)      \
   rx_print_operand_address (FILE, ADDR)
 \f
-extern int rx_float_compare_mode;
-\f
 /* This is a version of REG_P that also returns TRUE for SUBREGs.  */
 #define RX_REG_P(rtl) (REG_P (rtl) || GET_CODE (rtl) == SUBREG)
 
@@ -655,12 +661,5 @@ extern int rx_float_compare_mode;
 #define REGISTER_MOVE_COST(MODE, FROM, TO)    2
 #define MEMORY_MOVE_COST(MODE, REGCLASS, IN) (2 + memory_move_secondary_cost (MODE, REGCLASS, IN))
   
-#define SELECT_CC_MODE(OP,X,Y)                                         \
-  (GET_MODE_CLASS (GET_MODE (X)) == MODE_FLOAT ? CC_ZSmode :           \
-    (GET_CODE (X) == PLUS || GET_CODE (X) == MINUS ? CC_ZSCmode :      \
-    (GET_CODE (X) == ABS ? CC_ZSOmode :                                        \
-    (GET_CODE (X) == AND || GET_CODE (X) == NOT || GET_CODE (X) == IOR \
-     || GET_CODE (X) == XOR || GET_CODE (X) == ROTATE                  \
-     || GET_CODE (X) == ROTATERT || GET_CODE (X) == ASHIFTRT           \
-     || GET_CODE (X) == LSHIFTRT || GET_CODE (X) == ASHIFT ? CC_ZSmode : \
-     CCmode))))
+#define SELECT_CC_MODE(OP,X,Y)  rx_select_cc_mode ((OP), (X), (Y))
+
index 370f959e16a2874cb3596993e46d3cb3be6a4d2f..c33fa2f0b772cc329ed8632b418d4017b670c048 100644 (file)
@@ -1,5 +1,5 @@
 ;;  Machine Description for Renesas RX processors
-;;  Copyright (C) 2008, 2009, 2010 Free Software Foundation, Inc.
+;;  Copyright (C) 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
 ;;  Contributed by Red Hat.
 
 ;; This file is part of GCC.
 ;; <http://www.gnu.org/licenses/>.
 \f
 
-;; This code iterator allows all branch instructions to
-;; be generated from a single define_expand template.
-(define_code_iterator most_cond [eq ne gt ge lt le gtu geu ltu leu
-                                unordered ordered ])
-
-;; Likewise, but only the ones that use Z or S.
-(define_code_iterator zs_cond [eq ne gtu geu ltu leu ])
-
 ;; This code iterator is used for sign- and zero- extensions.
 (define_mode_iterator small_int_modes [(HI "") (QI "")])
 
   [(SF "ALLOW_RX_FPU_INSNS") (SI "") (HI "") (QI "")])
 
 
-;; Used to map RX condition names to GCC
-;; condition names for builtin instructions.
-(define_code_iterator gcc_conds [eq ne gt ge lt le gtu geu ltu leu
-                               unge unlt uneq ltgt])
-(define_code_attr rx_conds [(eq "eq") (ne "ne") (gt "gt") (ge "ge") (lt "lt")
-                           (le "le") (gtu "gtu") (geu "geu") (ltu "ltu")
-                           (leu "leu") (unge "pz") (unlt "n") (uneq "o")
-                           (ltgt "no")])
-
 (define_constants
   [
    (SP_REG 0)
@@ -58,6 +41,7 @@
    (UNSPEC_RTE             10)
    (UNSPEC_RTFI            11)
    (UNSPEC_NAKED           12)
+   (UNSPEC_CONST           13)
    
    (UNSPEC_MOVSTR          20)
    (UNSPEC_MOVMEM          21)
 (define_insn_reservation "throughput_18_latency_18"  1
   (eq_attr "timings" "1818") "throughput*18")
 
+;; ----------------------------------------------------------------------------
+
 ;; Comparisons
 
 ;; Note - we do not specify the two instructions necessary to perform
 
 (define_expand "cbranchsi4"
   [(set (pc)
-       (if_then_else (match_operator 0 "comparison_operator"
-                                     [(match_operand:SI 1 "register_operand")
-                                      (match_operand:SI 2 "rx_source_operand")])
-                     (label_ref (match_operand 3 ""))
-                     (pc)))
-   ]
-  ""
+       (if_then_else
+         (match_operator 0 "comparison_operator"
+           [(match_operand:SI 1 "register_operand")
+            (match_operand:SI 2 "rx_source_operand")])
+         (label_ref (match_operand 3 ""))
+         (pc)))]
   ""
 )
 
-(define_insn_and_split "*cbranchsi4_<code>"
+(define_insn_and_split "*cbranchsi4"
   [(set (pc)
-       (if_then_else (most_cond (match_operand:SI  0 "register_operand"  "r")
-                                   (match_operand:SI  1 "rx_source_operand" "riQ"))
-                     (label_ref (match_operand        2 "" ""))
-                     (pc)))
-   ]
+       (if_then_else
+         (match_operator 3 "comparison_operator"
+           [(match_operand:SI  0 "register_operand"  "r")
+            (match_operand:SI  1 "rx_source_operand" "riQ")])
+         (match_operand        2 "label_ref_operand" "")
+         (pc)))]
   ""
   "#"
   "reload_completed"
   [(const_int 0)]
-  "
-  /* We contstruct the split by hand as otherwise the JUMP_LABEL
-     attribute is not set correctly on the jump insn.  */
-  emit_insn (gen_cmpsi (operands[0], operands[1]));
-  
-  emit_jump_insn (gen_conditional_branch (operands[2],
-                gen_rtx_fmt_ee (<most_cond:CODE>, CCmode,
-                                gen_rtx_REG (CCmode, CC_REG), const0_rtx)));
-  "
-)
+{
+  rx_split_cbranch (CCmode, GET_CODE (operands[3]),
+                   operands[0], operands[1], operands[2]);
+  DONE;
+})
 
-;; -----------------------------------------------------------------------------
-;; These two are the canonical TST/branch insns.  However, GCC
-;; generates a wide variety of tst-like patterns, we catch those
-;; below.
-(define_insn_and_split "*tstbranchsi4_<code>"
-  [(set (pc)
-       (if_then_else (zs_cond (and:SI (match_operand:SI  0 "register_operand"  "r")
-                                      (match_operand:SI  1 "rx_source_operand" "riQ"))
-                              (const_int 0))
-                     (label_ref (match_operand 2 "" ""))
-                     (pc)))
-   ]
-  ""
-  "#"
+(define_insn "*cmpsi"
+  [(set (reg:CC CC_REG)
+       (compare:CC (match_operand:SI 0 "register_operand"  "r,r,r,r,r,r,r")
+                   (match_operand:SI 1 "rx_source_operand" "r,Uint04,Int08,Sint16,Sint24,i,Q")))]
   "reload_completed"
-  [(const_int 0)]
-  "
-  emit_insn (gen_tstsi (operands[0], operands[1]));
-  
-  emit_jump_insn (gen_conditional_branch (operands[2],
-                gen_rtx_fmt_ee (<zs_cond:CODE>, CCmode,
-                                gen_rtx_REG (CCmode, CC_REG), const0_rtx)));
-  "
+  "cmp\t%Q1, %0"
+  [(set_attr "timings" "11,11,11,11,11,11,33")
+   (set_attr "length"  "2,2,3,4,5,6,5")]
 )
 
-;; Inverse of above
-(define_insn_and_split "*tstbranchsi4_<code>"
+;; Canonical method for representing TST.
+(define_insn_and_split "*cbranchsi4_tst"
   [(set (pc)
-       (if_then_else (zs_cond (and:SI (match_operand:SI  0 "register_operand"  "r")
-                                      (match_operand:SI  1 "rx_source_operand" "riQ"))
-                              (const_int 0))
-                     (pc)
-                     (label_ref (match_operand 2 "" ""))))
-   ]
+       (if_then_else
+         (match_operator 3 "rx_zs_comparison_operator"
+           [(and:SI (match_operand:SI  0 "register_operand"  "r")
+                    (match_operand:SI  1 "rx_source_operand" "riQ"))
+            (const_int 0)])
+         (match_operand 2 "label_ref_operand" "")
+         (pc)))]
   ""
   "#"
   "reload_completed"
   [(const_int 0)]
-  "
-  emit_insn (gen_tstsi (operands[0], operands[1]));
-  
-  emit_jump_insn (gen_conditional_branch (operands[2],
-                gen_rtx_fmt_ee (reverse_condition (<zs_cond:CODE>), CCmode,
-                                gen_rtx_REG (CCmode, CC_REG), const0_rtx)));
-  "
-)
+{
+  rx_split_cbranch (CC_ZSmode, GET_CODE (operands[3]),
+                   XEXP (operands[3], 0), XEXP (operands[3], 1),
+                   operands[2]);
+  DONE;
+})
 
 ;; Various other ways that GCC codes "var & const"
-
-(define_insn_and_split "*tstbranchsi4m_eq"
+(define_insn_and_split "*cbranchsi4_tst_ext"
   [(set (pc)
-       (if_then_else (eq (zero_extract:SI (match_operand:SI  0 "register_operand"  "r")
-                                          (match_operand  1 "rx_constshift_operand" "i")
-                                          (match_operand  2 "rx_constshift_operand" "i"))
-                         (const_int 0))
-                     (label_ref (match_operand        3 "" ""))
-                     (pc)))
-   ]
-  ""
-  "#"
-  ""
-  [(set (pc)
-       (if_then_else (eq (and:SI (match_dup  0)
-                                 (match_dup 4))
-                         (const_int 0))
-                     (label_ref (match_dup 3))
-                     (pc)))
-   ]
-  "operands[4] = GEN_INT (((1 << INTVAL (operands[1]))-1) << INTVAL (operands[2]));"
-)
-
-(define_insn_and_split "*tstbranchsi4m_ne"
-  [(set (pc)
-       (if_then_else (ne (zero_extract:SI (match_operand:SI  0 "register_operand"  "r")
-                                          (match_operand  1 "rx_constshift_operand" "i")
-                                          (match_operand  2 "rx_constshift_operand" "i"))
-                         (const_int 0))
-                     (label_ref (match_operand        3 "" ""))
-                     (pc)))
-   ]
+       (if_then_else
+         (match_operator 4 "rx_z_comparison_operator"
+           [(zero_extract:SI
+               (match_operand:SI 0 "register_operand" "r")
+               (match_operand:SI 1 "rx_constshift_operand" "")
+               (match_operand:SI 2 "rx_constshift_operand" ""))
+            (const_int 0)])
+         (match_operand 3 "label_ref_operand" "")
+         (pc)))]
   ""
   "#"
-  ""
-  [(set (pc)
-       (if_then_else (ne (and:SI (match_dup  0)
-                                 (match_dup 4))
-                         (const_int 0))
-                     (label_ref (match_dup 3))
-                     (pc)))
-   ]
-  "operands[4] = GEN_INT (((1 << INTVAL (operands[1]))-1) << INTVAL (operands[2]));"
+  "reload_completed"
+  [(const_int 0)]
+{
+  HOST_WIDE_INT mask;
+  rtx x;
+
+  mask = 1;
+  mask <<= INTVAL (operands[1]);
+  mask -= 1;
+  mask <<= INTVAL (operands[2]);
+  x = gen_rtx_AND (SImode, operands[0], gen_int_mode (mask, SImode));
+
+  rx_split_cbranch (CC_ZSmode, GET_CODE (operands[4]),
+                   x, const0_rtx, operands[3]);
+  DONE;
+})
+
+(define_insn "*tstsi"
+  [(set (reg:CC_ZS CC_REG)
+       (compare:CC_ZS
+         (and:SI (match_operand:SI 0 "register_operand"  "r,r,r")
+                 (match_operand:SI 1 "rx_source_operand" "r,i,Q"))
+         (const_int 0)))]
+  "reload_completed"
+  "tst\t%Q1, %0"
+  [(set_attr "timings" "11,11,33")
+   (set_attr "length"  "3,7,6")]
 )
 
-;; -----------------------------------------------------------------------------
-
 (define_expand "cbranchsf4"
   [(set (pc)
-       (if_then_else (match_operator 0 "comparison_operator"
-                                     [(match_operand:SF 1 "register_operand")
-                                      (match_operand:SF 2 "rx_source_operand")])
-                     (label_ref (match_operand 3 ""))
-                     (pc)))
-   ]
+       (if_then_else
+         (match_operator 0 "rx_fp_comparison_operator"
+           [(match_operand:SF 1 "register_operand")
+            (match_operand:SF 2 "rx_source_operand")])
+         (label_ref (match_operand 3 ""))
+         (pc)))]
   "ALLOW_RX_FPU_INSNS"
-  ""
 )
 
-(define_insn_and_split "*cbranchsf4_<code>"
+(define_insn_and_split "*cbranchsf4"
   [(set (pc)
-       (if_then_else (most_cond (match_operand:SF  0 "register_operand"  "r")
-                                (match_operand:SF  1 "rx_source_operand" "rFiQ"))
-                     (label_ref (match_operand        2 "" ""))
-                     (pc)))
-   ]
+       (if_then_else
+         (match_operator 3 "rx_fp_comparison_operator"
+           [(match_operand:SF  0 "register_operand"  "r")
+            (match_operand:SF  1 "rx_source_operand" "rFQ")])
+         (match_operand        2 "label_ref_operand" "")
+         (pc)))]
   "ALLOW_RX_FPU_INSNS"
   "#"
   "&& reload_completed"
   [(const_int 0)]
-  "
-  /* We contstruct the split by hand as otherwise the JUMP_LABEL
-     attribute is not set correctly on the jump insn.  */
-  emit_insn (gen_cmpsf (operands[0], operands[1]));
-  
-  emit_jump_insn (gen_conditional_branch (operands[2],
-                gen_rtx_fmt_ee (<most_cond:CODE>, CCmode,
-                                gen_rtx_REG (CCmode, CC_REG), const0_rtx)));
-  "
-)
-
-(define_insn "tstsi"
-  [(set (reg:CC_ZS CC_REG)
-       (compare:CC_ZS (and:SI (match_operand:SI 0 "register_operand"  "r,r,r")
-                              (match_operand:SI 1 "rx_source_operand" "r,i,Q"))
-                      (const_int 0)))]
-  ""
-  {
-    rx_float_compare_mode = false;
-    return "tst\t%Q1, %0";
-  }
-  [(set_attr "timings" "11,11,33")
-   (set_attr "length"   "3,7,6")]
-)
-
-(define_insn "cmpsi"
-  [(set (reg:CC CC_REG)
-       (compare:CC (match_operand:SI 0 "register_operand"  "r,r,r,r,r,r,r")
-                   (match_operand:SI 1 "rx_source_operand" "r,Uint04,Int08,Sint16,Sint24,i,Q")))]
-  ""
-  {
-    rx_float_compare_mode = false;
-    if (rx_compare_redundant (insn))
-      return "; Compare Eliminated: cmp %Q1, %0";
-    return "cmp\t%Q1, %0";
-  }
-  [(set_attr "timings" "11,11,11,11,11,11,33")
-   (set_attr "length"  "2,2,3,4,5,6,5")]
-)
-
-;; This pattern is disabled when -fnon-call-exceptions is active because
-;; it could generate a floating point exception, which would introduce an
-;; edge into the flow graph between this insn and the conditional branch
-;; insn to follow, thus breaking the cc0 relationship.  Run the g++ test
-;; g++.dg/eh/080514-1.C to see this happen.
-(define_insn "cmpsf"
-  [(set (reg:CC_ZSO CC_REG)
-       (compare:CC_ZSO (match_operand:SF 0 "register_operand"  "r,r,r")
-                       (match_operand:SF 1 "rx_source_operand" "r,iF,Q")))]
-  "ALLOW_RX_FPU_INSNS"
-  {
-    rx_float_compare_mode = true;
-    return "fcmp\t%1, %0";
-  }
+{
+  rx_split_cbranch (CC_Fmode, GET_CODE (operands[3]),
+                   operands[0], operands[1], operands[2]);
+  DONE;
+})
+
+(define_insn "*cmpsf"
+  [(set (reg:CC_F CC_REG)
+       (compare:CC_F
+         (match_operand:SF 0 "register_operand"  "r,r,r")
+         (match_operand:SF 1 "rx_source_operand" "r,F,Q")))]
+  "ALLOW_RX_FPU_INSNS && reload_completed"
+  "fcmp\t%1, %0"
   [(set_attr "timings" "11,11,33")
    (set_attr "length" "3,7,5")]
 )
 
 ;; Flow Control Instructions:
 
-(define_expand "b<code>"
+(define_insn "*conditional_branch"
   [(set (pc)
-        (if_then_else (most_cond (reg:CC CC_REG) (const_int 0))
-                      (label_ref (match_operand 0))
-                      (pc)))]
-  ""
-  ""
-)
-
-(define_insn "conditional_branch"
-  [(set (pc)
-       (if_then_else (match_operator           1 "comparison_operator"
-                                               [(reg:CC CC_REG) (const_int 0)])
-                     (label_ref (match_operand 0 "" ""))
-                     (pc)))]
-  ""
-  {
-    return rx_gen_cond_branch_template (operands[1], false);
-  }
+       (if_then_else
+         (match_operator 1 "comparison_operator"
+           [(reg CC_REG) (const_int 0)])
+         (label_ref (match_operand 0 "" ""))
+         (pc)))]
+  "reload_completed"
+  "b%B1\t%0"
   [(set_attr "length" "8")    ;; This length is wrong, but it is
                               ;; too hard to compute statically.
    (set_attr "timings" "33")] ;; The timing assumes that the branch is taken.
 )
 
-(define_insn "*reveresed_conditional_branch"
-  [(set (pc)
-       (if_then_else (match_operator 1 "comparison_operator"
-                                     [(reg:CC CC_REG) (const_int 0)])
-                     (pc)
-                     (label_ref (match_operand 0 "" ""))))]
-  ""
-  {
-    return rx_gen_cond_branch_template (operands[1], true);
-  }
-  [(set_attr "length" "8")    ;; This length is wrong, but it is
-                              ;; too hard to compute statically.
-   (set_attr "timings" "33")] ;; The timing assumes that the branch is taken.
-)
+;; ----------------------------------------------------------------------------
 
 (define_insn "jump"
   [(set (pc)
    (set_attr "timings" "55")]
 )
 
+;; Unspec used so that the constant will not be invalid
+;; if -mmax-constant-size has been specified.
 (define_insn "deallocate_and_return"
   [(set (reg:SI SP_REG)
        (plus:SI (reg:SI SP_REG)
-                (match_operand:SI 0 "immediate_operand" "i")))
+                (const:SI (unspec:SI [(match_operand 0 "const_int_operand" "n")] UNSPEC_CONST))))
    (return)]
   ""
   "rtsd\t%0"
 
 (define_insn "pop_and_return"
   [(match_parallel 1 "rx_rtsd_vector"
-                  [(set:SI (reg:SI SP_REG)
-                           (plus:SI (reg:SI SP_REG)
-                                    (match_operand:SI 0 "const_int_operand" "n")))])]
+     [(set (reg:SI SP_REG)
+          (plus:SI (reg:SI SP_REG)
+                   (match_operand:SI 0 "const_int_operand" "n")))])
+   (return)]
   "reload_completed"
   {
     rx_emit_stack_popm (operands, false);
 
     if (! rx_call_operand (dest, Pmode))
       dest = force_reg (Pmode, dest);
-    emit_call_insn (gen_call_internal (dest, operands[1]));
+    emit_call_insn (gen_call_internal (dest));
     DONE;
   }
 )
 
 (define_insn "call_internal"
   [(call (mem:QI (match_operand:SI 0 "rx_call_operand" "r,Symbol"))
-        (match_operand:SI         1 "general_operand" "g,g"))
+        (const_int 0))
    (clobber (reg:CC CC_REG))]
   ""
   "@
 
     if (! rx_call_operand (dest, Pmode))
       dest = force_reg (Pmode, dest);
-    emit_call_insn (gen_call_value_internal (operands[0], dest, operands[2]));
+    emit_call_insn (gen_call_value_internal (operands[0], dest));
     DONE;
   }
 )
 (define_insn "call_value_internal"
   [(set (match_operand                  0 "register_operand" "=r,r")
        (call (mem:QI (match_operand:SI 1 "rx_call_operand"   "r,Symbol"))
-             (match_operand:SI         2 "general_operand"   "g,g")))
+             (const_int 0)))
    (clobber (reg:CC CC_REG))]
   ""
   "@
   {
     if (MEM_P (operands[0]))
       operands[0] = XEXP (operands[0], 0);
+    emit_call_insn (gen_sibcall_internal (operands[0]));
+    DONE;
   }
 )
 
 (define_insn "sibcall_internal"
   [(call (mem:QI (match_operand:SI 0 "rx_symbolic_call_operand" "Symbol"))
-        (match_operand:SI         1 "general_operand"          "g"))
+        (const_int 0))
    (return)]
   ""
   "bra\t%A0"
   {
     if (MEM_P (operands[1]))
       operands[1] = XEXP (operands[1], 0);
+    emit_call_insn (gen_sibcall_value_internal (operands[0], operands[1]));
+    DONE;
   }
 )
 
 (define_insn "sibcall_value_internal"
  [(set (match_operand                  0 "register_operand"         "=r")
        (call (mem:QI (match_operand:SI 1 "rx_symbolic_call_operand" "Symbol"))
-            (match_operand:SI         2 "general_operand"          "g")))
+            (const_int 0)))
   (return)]
   ""
   "bra\t%A1"
   {
     if (MEM_P (operand0) && MEM_P (operand1))
       operands[1] = copy_to_mode_reg (<register_modes:MODE>mode, operand1);
+    if (CONST_INT_P (operand1)
+        && ! rx_is_legitimate_constant (operand1))
+      FAIL;
   }
 )
 
 )
 
 (define_insn "stack_push"
-  [(set:SI (reg:SI SP_REG)
-          (minus:SI (reg:SI SP_REG)
-                    (const_int 4)))
-   (set:SI (mem:SI (reg:SI SP_REG))
-          (match_operand:SI 0 "register_operand" "r"))]
+  [(set (reg:SI SP_REG)
+       (minus:SI (reg:SI SP_REG)
+                 (const_int 4)))
+   (set (mem:SI (reg:SI SP_REG))
+       (match_operand:SI 0 "register_operand" "r"))]
   ""
   "push.l\t%0"
   [(set_attr "length" "2")]
 
 (define_insn "stack_pushm"
   [(match_parallel 1 "rx_store_multiple_vector"
-                  [(set:SI (reg:SI SP_REG)
-                           (minus:SI (reg:SI SP_REG)
-                                     (match_operand:SI 0 "const_int_operand" "n")))])]
+     [(set (reg:SI SP_REG)
+          (minus:SI (reg:SI SP_REG)
+                    (match_operand:SI 0 "const_int_operand" "n")))])]
   "reload_completed"
   {
     rx_emit_stack_pushm (operands);
 )
 
 (define_insn "stack_pop"
-  [(set:SI (match_operand:SI 0 "register_operand" "=r")
-          (mem:SI (reg:SI SP_REG)))
-   (set:SI (reg:SI SP_REG)
-          (plus:SI (reg:SI SP_REG)
-                   (const_int 4)))]
+  [(set (match_operand:SI 0 "register_operand" "=r")
+       (mem:SI (reg:SI SP_REG)))
+   (set (reg:SI SP_REG)
+       (plus:SI (reg:SI SP_REG)
+                (const_int 4)))]
   ""
   "pop\t%0"
   [(set_attr "length" "2")
 
 (define_insn "stack_popm"
   [(match_parallel 1 "rx_load_multiple_vector"
-                  [(set:SI (reg:SI SP_REG)
-                           (plus:SI (reg:SI SP_REG)
-                                    (match_operand:SI 0 "const_int_operand" "n")))])]
+     [(set (reg:SI SP_REG)
+          (plus:SI (reg:SI SP_REG)
+                   (match_operand:SI 0 "const_int_operand" "n")))])]
   "reload_completed"
   {
     rx_emit_stack_popm (operands, true);
    (set_attr "timings" "45")] ;; The timing is a guesstimate average timing.
 )
 
-;; FIXME: Add memory destination options ?
-(define_insn "cstoresi4"
-  [(set (match_operand:SI   0 "register_operand" "=r,r,r,r,r,r,r")
+(define_insn_and_split "cstoresi4"
+  [(set (match_operand:SI   0 "register_operand" "=r")
        (match_operator:SI  1 "comparison_operator"
-        [(match_operand:SI 2 "register_operand"  "r,r,r,r,r,r,r")
-         (match_operand:SI 3 "rx_source_operand" "r,Uint04,Int08,Sint16,Sint24,i,Q")]))
-   (clobber (reg:CC CC_REG))] ;; Because the cc flags are set based on comparing ops 2 & 3 not the value in op 0.
+         [(match_operand:SI 2 "register_operand"  "r")
+          (match_operand:SI 3 "rx_source_operand" "riQ")]))
+   (clobber (reg:CC CC_REG))]
   ""
-  {
-    rx_float_compare_mode = false;
-    return "cmp\t%Q3, %Q2\n\tsc%B1.L\t%0";
-  }
-  [(set_attr "timings" "22,22,22,22,22,22,44")
-   (set_attr "length"  "5,5,6,7,8,9,8")]
+  "#"
+  "reload_completed"
+  [(const_int 0)]
+{
+  rtx flags, x;
+
+  flags = gen_rtx_REG (CCmode, CC_REG);
+  x = gen_rtx_COMPARE (CCmode, operands[2], operands[3]);
+  x = gen_rtx_SET (VOIDmode, flags, x);
+  emit_insn (x);
+
+  x = gen_rtx_fmt_ee (GET_CODE (operands[1]), SImode, flags, const0_rtx);
+  x = gen_rtx_SET (VOIDmode, operands[0], x);
+  emit_insn (x);
+  DONE;
+})
+
+(define_insn "*sccc"
+  [(set (match_operand:SI 0 "register_operand" "=r")
+       (match_operator:SI 1 "comparison_operator"
+         [(reg CC_REG) (const_int 0)]))]
+  "reload_completed"
+  "sc%B1.L\t%0"
+  [(set_attr "length" "3")]
 )
 
+(define_insn_and_split "cstoresf4"
+  [(set (match_operand:SI 0 "register_operand" "=r")
+       (match_operator:SI 1 "rx_fp_comparison_operator"
+        [(match_operand:SF 2 "register_operand" "r")
+         (match_operand:SF 3 "rx_source_operand" "rFQ")]))]
+  "ALLOW_RX_FPU_INSNS"
+  "#"
+  "reload_completed"
+  [(const_int 0)]
+{
+  rtx flags, x;
+
+  flags = gen_rtx_REG (CC_Fmode, CC_REG);
+  x = gen_rtx_COMPARE (CC_Fmode, operands[2], operands[3]);
+  x = gen_rtx_SET (VOIDmode, flags, x);
+  emit_insn (x);
+
+  x = gen_rtx_fmt_ee (GET_CODE (operands[1]), SImode, flags, const0_rtx);
+  x = gen_rtx_SET (VOIDmode, operands[0], x);
+  emit_insn (x);
+  DONE;
+})
+
 (define_expand "movsicc"
   [(parallel
     [(set (match_operand:SI                  0 "register_operand")
          (if_then_else:SI (match_operand:SI 1 "comparison_operator")
                           (match_operand:SI 2 "nonmemory_operand")
-                          (match_operand:SI 3 "immediate_operand")))
-     (clobber (reg:CC CC_REG))])] ;; See cstoresi4
+                          (match_operand:SI 3 "nonmemory_operand")))
+     (clobber (reg:CC CC_REG))])]
   ""
-  {
-    if (GET_CODE (operands[1]) != EQ && GET_CODE (operands[1]) != NE)
-      FAIL;
-    if (! CONST_INT_P (operands[3]))
-      FAIL;
-  }
+{
+  /* ??? Support other conditions via cstore into a temporary?  */
+  if (GET_CODE (operands[1]) != EQ && GET_CODE (operands[1]) != NE)
+    FAIL;
+  /* One operand must be a constant.  */
+  if (!CONSTANT_P (operands[2]) && !CONSTANT_P (operands[3]))
+    FAIL;
+})
+
+(define_insn_and_split "*movsicc"
+  [(set (match_operand:SI     0 "register_operand" "=r,r")
+       (if_then_else:SI
+         (match_operator 5 "rx_z_comparison_operator"
+          [(match_operand:SI 3 "register_operand"  "r,r")
+           (match_operand:SI 4 "rx_source_operand" "riQ,riQ")])
+         (match_operand:SI   1 "nonmemory_operand" "i,ri")
+         (match_operand:SI   2 "nonmemory_operand" "ri,i")))
+   (clobber (reg:CC CC_REG))]
+  "CONSTANT_P (operands[1]) || CONSTANT_P (operands[2])"
+  "#"
+  "&& reload_completed"
+  [(const_int 0)]
+{
+  rtx x, flags, op0, op1, op2;
+  enum rtx_code cmp_code;
+
+  flags = gen_rtx_REG (CCmode, CC_REG);
+  x = gen_rtx_COMPARE (CCmode, operands[3], operands[4]);
+  emit_insn (gen_rtx_SET (VOIDmode, flags, x));
+
+  cmp_code = GET_CODE (operands[5]);
+  op0 = operands[0];
+  op1 = operands[1];
+  op2 = operands[2];
+
+  /* If OP2 is the constant, reverse the sense of the move.  */
+  if (!CONSTANT_P (operands[1]))
+    {
+      x = op1, op1 = op2, op2 = x;
+      cmp_code = reverse_condition (cmp_code);
+    }
+
+  /* If OP2 does not match the output, copy it into place.  We have allowed
+     these alternatives so that the destination can legitimately be one of
+     the comparison operands without increasing register pressure.  */
+  if (!rtx_equal_p (op0, op2))
+    emit_move_insn (op0, op2);
+
+  x = gen_rtx_fmt_ee (cmp_code, VOIDmode, flags, const0_rtx);
+  x = gen_rtx_IF_THEN_ELSE (SImode, x, op1, op0);
+  emit_insn (gen_rtx_SET (VOIDmode, op0, x));
+  DONE;
+})
+
+(define_insn "*stcc"
+  [(set (match_operand:SI 0 "register_operand" "+r,r,r,r")
+       (if_then_else:SI
+         (match_operator 2 "rx_z_comparison_operator"
+           [(reg CC_REG) (const_int 0)])
+         (match_operand:SI 1 "immediate_operand" "Sint08,Sint16,Sint24,i")
+         (match_dup 0)))]
+  "reload_completed"
+{
+  if (GET_CODE (operands[2]) == EQ)
+    return "stz\t%1, %0";
+  else
+    return "stnz\t%1, %0";
+}
+  [(set_attr "length" "4,5,6,7")]
 )
 
-(define_insn "*movsieq"
-  [(set (match_operand:SI                      0 "register_operand" "=r,r,r")
-       (if_then_else:SI (eq (match_operand:SI 3 "register_operand"  "r,r,r")
-                            (match_operand:SI 4 "rx_source_operand" "riQ,riQ,riQ"))
-                        (match_operand:SI     1 "nonmemory_operand" "0,i,r")
-                        (match_operand:SI     2 "immediate_operand" "i,i,i")))
-   (clobber (reg:CC CC_REG))] ;; See cstoresi4
-  ""
-  "@
-  cmp\t%Q4, %Q3\n\tstnz\t%2, %0
-  cmp\t%Q4, %Q3\n\tmov.l\t%2, %0\n\tstz\t%1, %0
-  cmp\t%Q4, %Q3\n\tmov.l\t%1, %0\n\tstnz\t%2, %0"
-  [(set_attr "length"  "13,19,15")
-   (set_attr "timings" "22,33,33")]
-)
+;; Arithmetic Instructions
 
-(define_insn "*movsine"
-  [(set (match_operand:SI                      0 "register_operand" "=r,r,r")
-       (if_then_else:SI (ne (match_operand:SI 3 "register_operand"  "r,r,r")
-                            (match_operand:SI 4 "rx_source_operand" "riQ,riQ,riQ"))
-                        (match_operand:SI     1 "nonmemory_operand" "0,i,r")
-                        (match_operand:SI     2 "immediate_operand" "i,i,i")))
-   (clobber (reg:CC CC_REG))] ;; See cstoresi4
+(define_insn "abssi2"
+  [(set (match_operand:SI         0 "register_operand" "=r,r")
+        (abs:SI (match_operand:SI 1 "register_operand"  "0,r")))
+   (clobber (reg:CC CC_REG))]
   ""
   "@
-  cmp\t%Q4, %Q3\n\tstz\t%2, %0
-  cmp\t%Q4, %Q3\n\tmov.l\t%2, %0\n\tstnz\t%1, %0
-  cmp\t%Q4, %Q3\n\tmov.l\t%1, %0\n\tstz\t%2, %0"
-  [(set_attr "length"  "13,19,15")
-   (set_attr "timings" "22,33,33")]
+  abs\t%0
+  abs\t%1, %0"
+  [(set_attr "length" "2,3")]
 )
 
-;; Arithmetic Instructions
-
-(define_insn "abssi2"
+(define_insn "*abssi2_flags"
   [(set (match_operand:SI         0 "register_operand" "=r,r")
         (abs:SI (match_operand:SI 1 "register_operand"  "0,r")))
-   (set (reg:CC_ZSO CC_REG)
-       (compare:CC_ZSO (abs:SI (match_dup 1))
-                       (const_int 0)))]
-  ""
+   (set (reg CC_REG)
+       (compare (abs:SI (match_dup 1))
+                (const_int 0)))]
+  "reload_completed && rx_match_ccmode (insn, CC_ZSOmode)"
   "@
   abs\t%0
   abs\t%1, %0"
   [(set (match_operand:SI          0 "register_operand"  "=r,r,r,r,r,r,r,r,r,r,r,r,r,r")
        (plus:SI (match_operand:SI 1 "register_operand"  "%0,0,0,0,0,0,0,r,r,r,r,r,r,0")
                 (match_operand:SI 2 "rx_source_operand" "r,Uint04,NEGint4,Sint08,Sint16,Sint24,i,0,r,Sint08,Sint16,Sint24,i,Q")))
-   (set (reg:CC_ZSC CC_REG) ;; See subsi3
-       (compare:CC_ZSC (plus:SI (match_dup 1) (match_dup 2))
-                       (const_int 0)))]
+   (clobber (reg:CC CC_REG))]
   ""
   "@
   add\t%2, %0
    (set_attr "length"   "2,2,2,3,4,5,6,2,3,3,4,5,6,5")]
 )
 
-(define_insn "adddi3"
-  [(set (match_operand:DI          0 "register_operand" "=r,r,r,r,r,r")
-       (plus:DI (match_operand:DI 1 "register_operand" "%0,0,0,0,0,0")
-                (match_operand:DI 2 "rx_source_operand"
-                                  "r,Sint08,Sint16,Sint24,i,Q")))
-   (set (reg:CC_ZSC CC_REG) ;; See subsi3
-       (compare:CC_ZSC (plus:DI (match_dup 1) (match_dup 2))
-                       (const_int 0)))]
-  ""
-  "add\t%L2, %L0\n\tadc\t%H2, %H0"
-  [(set_attr "timings" "22,22,22,22,22,44")
-   (set_attr "length" "5,7,9,11,13,11")]
+(define_insn "*addsi3_flags"
+  [(set (match_operand:SI          0 "register_operand"  "=r,r,r,r,r,r,r,r,r,r,r,r,r,r")
+       (plus:SI (match_operand:SI 1 "register_operand"  "%0,0,0,0,0,0,0,r,r,r,r,r,r,0")
+                (match_operand:SI 2 "rx_source_operand" "r,Uint04,NEGint4,Sint08,Sint16,Sint24,i,0,r,Sint08,Sint16,Sint24,i,Q")))
+   (set (reg CC_REG)
+       (compare (plus:SI (match_dup 1) (match_dup 2))
+                (const_int 0)))]
+  "reload_completed && rx_match_ccmode (insn, CC_ZSCmode)"
+  "@
+  add\t%2, %0
+  add\t%2, %0
+  sub\t%N2, %0
+  add\t%2, %0
+  add\t%2, %0
+  add\t%2, %0
+  add\t%2, %0
+  add\t%1, %0
+  add\t%2, %1, %0
+  add\t%2, %1, %0
+  add\t%2, %1, %0
+  add\t%2, %1, %0
+  add\t%2, %1, %0
+  add\t%Q2, %0"
+  [(set_attr "timings" "11,11,11,11,11,11,11,11,11,11,11,11,11,33")
+   (set_attr "length"   "2,2,2,3,4,5,6,2,3,3,4,5,6,5")]
 )
 
+;; A helper to expand the above with the CC_MODE filled in.
+(define_expand "addsi3_flags"
+  [(parallel [(set (match_operand:SI 0 "register_operand")
+                  (plus:SI (match_operand:SI 1 "register_operand")
+                           (match_operand:SI 2 "rx_source_operand")))
+             (set (reg:CC_ZSC CC_REG)
+                  (compare:CC_ZSC (plus:SI (match_dup 1) (match_dup 2))
+                                  (const_int 0)))])]
+)
+
+(define_insn "adc_internal"
+  [(set (match_operand:SI     0 "register_operand"  "=r,r,r,r,r,r")
+       (plus:SI
+         (plus:SI
+           (ltu:SI (reg:CC CC_REG) (const_int 0))
+           (match_operand:SI 1 "register_operand"  "%0,0,0,0,0,0"))
+         (match_operand:SI   2 "rx_source_operand" "r,Sint08,Sint16,Sint24,i,Q")))
+    (clobber (reg:CC CC_REG))]
+  "reload_completed"
+  "adc %2,%0"
+  [(set_attr "timings" "11,11,11,11,11,33")
+   (set_attr "length"   "3,4,5,6,7,6")]
+)
+
+(define_insn "*adc_flags"
+  [(set (match_operand:SI     0 "register_operand"  "=r,r,r,r,r,r")
+       (plus:SI
+         (plus:SI
+           (ltu:SI (reg:CC CC_REG) (const_int 0))
+           (match_operand:SI 1 "register_operand"  "%0,0,0,0,0,0"))
+         (match_operand:SI   2 "rx_source_operand" "r,Sint08,Sint16,Sint24,i,Q")))
+   (set (reg CC_REG)
+       (compare 
+         (plus:SI
+           (plus:SI
+             (ltu:SI (reg:CC CC_REG) (const_int 0))
+             (match_dup 1))
+           (match_dup 2))
+         (const_int 0)))]
+  "reload_completed && rx_match_ccmode (insn, CC_ZSCmode)"
+  "adc %2,%0"
+  [(set_attr "timings" "11,11,11,11,11,33")
+   (set_attr "length"   "3,4,5,6,7,6")]
+)
+
+(define_expand "adddi3"
+  [(set (match_operand:DI          0 "register_operand")
+       (plus:DI (match_operand:DI 1 "register_operand")
+                (match_operand:DI 2 "rx_source_operand")))]
+  ""
+{
+  rtx op0l, op0h, op1l, op1h, op2l, op2h;
+
+  op0l = gen_lowpart (SImode, operands[0]);
+  op1l = gen_lowpart (SImode, operands[1]);
+  op2l = gen_lowpart (SImode, operands[2]);
+  op0h = gen_highpart (SImode, operands[0]);
+  op1h = gen_highpart (SImode, operands[1]);
+  op2h = gen_highpart_mode (SImode, DImode, operands[2]);
+
+  emit_insn (gen_adddi3_internal (op0l, op0h, op1l, op2l, op1h, op2h));
+  DONE;
+})
+
+(define_insn_and_split "adddi3_internal"
+  [(set (match_operand:SI          0 "register_operand"  "=r")
+       (plus:SI (match_operand:SI 2 "register_operand"  "r")
+                (match_operand:SI 3 "rx_source_operand" "riQ")))
+   (set (match_operand:SI          1 "register_operand"  "=r")
+       (plus:SI
+         (plus:SI
+           (ltu:SI (plus:SI (match_dup 2) (match_dup 3)) (match_dup 2))
+           (match_operand:SI      4 "register_operand"  "%1"))
+         (match_operand:SI        5 "rx_source_operand" "riQ")))
+   (clobber (match_scratch:SI      6                     "=&r"))
+   (clobber (reg:CC CC_REG))]
+  ""
+  "#"
+  "reload_completed"
+  [(const_int 0)]
+{
+  rtx op0l = operands[0];
+  rtx op0h = operands[1];
+  rtx op1l = operands[2];
+  rtx op2l = operands[3];
+  rtx op1h = operands[4];
+  rtx op2h = operands[5];
+  rtx scratch = operands[6];
+  rtx x;
+
+  if (reg_overlap_mentioned_p (op0l, op1h))
+    {
+      emit_move_insn (scratch, op0l);
+      op1h = scratch;
+      if (reg_overlap_mentioned_p (op0l, op2h))
+       op2h = scratch;
+    }
+  else if (reg_overlap_mentioned_p (op0l, op2h))
+    {
+      emit_move_insn (scratch, op0l);
+      op2h = scratch;
+    }
+
+  if (rtx_equal_p (op0l, op1l))
+    ;
+  /* It is preferable that op0l == op1l...  */
+  else if (rtx_equal_p (op0l, op2l))
+    x = op1l, op1l = op2l, op2l = x;
+  /* ... but it is only a requirement if op2l == MEM.  */
+  else if (MEM_P (op2l))
+    {
+      /* Let's hope that we still have a scratch register free.  */
+      gcc_assert (op1h != scratch);
+      emit_move_insn (scratch, op2l);
+      op2l = scratch;
+    }
+
+  emit_insn (gen_addsi3_flags (op0l, op1l, op2l));
+
+  if (rtx_equal_p (op0h, op1h))
+    ;
+  else if (rtx_equal_p (op0h, op2h))
+    x = op1h, op1h = op2h, op2h = x;
+  else
+    {
+      emit_move_insn (op0h, op1h);
+      op1h = op0h;
+    }
+  emit_insn (gen_adc_internal (op0h, op1h, op2h));
+  DONE;
+})
+
 (define_insn "andsi3"
   [(set (match_operand:SI         0 "register_operand"  "=r,r,r,r,r,r,r,r,r")
        (and:SI (match_operand:SI 1 "register_operand"  "%0,0,0,0,0,0,r,r,0")
                (match_operand:SI 2 "rx_source_operand" "r,Uint04,Sint08,Sint16,Sint24,i,0,r,Q")))
-   (set (reg:CC_ZS CC_REG)
-       (compare:CC_ZS (and:SI (match_dup 1) (match_dup 2))
-                      (const_int 0)))]
+   (clobber (reg:CC CC_REG))]
   ""
   "@
   and\t%2, %0
    (set_attr "length" "2,2,3,4,5,6,2,5,5")]
 )
 
+(define_insn "*andsi3_flags"
+  [(set (match_operand:SI         0 "register_operand"  "=r,r,r,r,r,r,r,r,r")
+       (and:SI (match_operand:SI 1 "register_operand"  "%0,0,0,0,0,0,r,r,0")
+               (match_operand:SI 2 "rx_source_operand" "r,Uint04,Sint08,Sint16,Sint24,i,0,r,Q")))
+   (set (reg CC_REG)
+       (compare (and:SI (match_dup 1) (match_dup 2))
+                (const_int 0)))]
+  "reload_completed && rx_match_ccmode (insn, CC_ZSmode)"
+  "@
+  and\t%2, %0
+  and\t%2, %0
+  and\t%2, %0
+  and\t%2, %0
+  and\t%2, %0
+  and\t%2, %0
+  and\t%1, %0
+  and\t%2, %1, %0
+  and\t%Q2, %0"
+  [(set_attr "timings" "11,11,11,11,11,11,11,33,33")
+   (set_attr "length" "2,2,3,4,5,6,2,5,5")]
+)
+
 ;; Byte swap (single 32-bit value).
 (define_insn "bswapsi2"
-  [(set (match_operand:SI           0 "register_operand" "+r")
+  [(set (match_operand:SI           0 "register_operand" "=r")
        (bswap:SI (match_operand:SI 1 "register_operand"  "r")))]
   ""
   "revl\t%1, %0"
 
 ;; Byte swap (single 16-bit value).  Note - we ignore the swapping of the high 16-bits.
 (define_insn "bswaphi2"
-  [(set (match_operand:HI           0 "register_operand" "+r")
+  [(set (match_operand:HI           0 "register_operand" "=r")
        (bswap:HI (match_operand:HI 1 "register_operand"  "r")))]
   ""
   "revw\t%1, %0"
 (define_insn "negsi2"
   [(set (match_operand:SI         0 "register_operand" "=r,r")
         (neg:SI (match_operand:SI 1 "register_operand"  "0,r")))
-   (set (reg:CC CC_REG)
-       (compare:CC (neg:SI (match_dup 1))
-                   (const_int 0)))]
-  ;; The NEG instruction does not comply with -fwrapv semantics.
-  ;; See gcc.c-torture/execute/pr22493-1.c for an example of this.
-  "! flag_wrapv"
+   (clobber (reg:CC CC_REG))]
+  ""
+  "@
+  neg\t%0
+  neg\t%1, %0"
+  [(set_attr "length" "2,3")]
+)
+
+;; Note that the O and C flags are not set as per a normal compare,
+;; and thus are unusable in that context.
+(define_insn "*negsi2_flags"
+  [(set (match_operand:SI         0 "register_operand" "=r,r")
+        (neg:SI (match_operand:SI 1 "register_operand"  "0,r")))
+   (set (reg CC_REG)
+       (compare (neg:SI (match_dup 1))
+                (const_int 0)))]
+  "reload_completed && rx_match_ccmode (insn, CC_ZSmode)"
   "@
   neg\t%0
   neg\t%1, %0"
 (define_insn "one_cmplsi2"
   [(set (match_operand:SI         0 "register_operand" "=r,r")
        (not:SI (match_operand:SI 1 "register_operand"  "0,r")))
-   (set (reg:CC_ZS CC_REG)
-       (compare:CC_ZS (not:SI (match_dup 1))
-                      (const_int 0)))]
+   (clobber (reg:CC CC_REG))]
   ""
   "@
   not\t%0
   [(set_attr "length" "2,3")]
 )
 
+(define_insn "*one_cmplsi2_flags"
+  [(set (match_operand:SI         0 "register_operand" "=r,r")
+       (not:SI (match_operand:SI 1 "register_operand"  "0,r")))
+   (set (reg CC_REG)
+       (compare (not:SI (match_dup 1))
+                (const_int 0)))]
+  "reload_completed && rx_match_ccmode (insn, CC_ZSmode)"
+  "@
+  not\t%0
+  not\t%1, %0"
+  [(set_attr "length" "2,3")]
+)
+
 (define_insn "iorsi3"
   [(set (match_operand:SI         0 "register_operand" "=r,r,r,r,r,r,r,r,r")
        (ior:SI (match_operand:SI 1 "register_operand" "%0,0,0,0,0,0,r,r,0")
                (match_operand:SI 2 "rx_source_operand" "r,Uint04,Sint08,Sint16,Sint24,i,0,r,Q")))
-   (set (reg:CC_ZS CC_REG)
-       (compare:CC_ZS (ior:SI (match_dup 1) (match_dup 2))
-                      (const_int 0)))]
+   (clobber (reg:CC CC_REG))]
   ""
   "@
   or\t%2, %0
    (set_attr "length"  "2,2,3,4,5,6,2,3,5")]
 )
 
+(define_insn "*iorsi3_flags"
+  [(set (match_operand:SI         0 "register_operand" "=r,r,r,r,r,r,r,r,r")
+       (ior:SI (match_operand:SI 1 "register_operand" "%0,0,0,0,0,0,r,r,0")
+               (match_operand:SI 2 "rx_source_operand" "r,Uint04,Sint08,Sint16,Sint24,i,0,r,Q")))
+   (set (reg CC_REG)
+       (compare (ior:SI (match_dup 1) (match_dup 2))
+                (const_int 0)))]
+  "reload_completed && rx_match_ccmode (insn, CC_ZSmode)"
+  "@
+  or\t%2, %0
+  or\t%2, %0
+  or\t%2, %0
+  or\t%2, %0
+  or\t%2, %0
+  or\t%Q2, %0
+  or\t%1, %0
+  or\t%2, %1, %0
+  or\t%Q2, %0"
+  [(set_attr "timings" "11,11,11,11,11,11,11,11,33")
+   (set_attr "length"  "2,2,3,4,5,6,2,3,5")]
+)
+
 (define_insn "rotlsi3"
   [(set (match_operand:SI            0 "register_operand" "=r")
        (rotate:SI (match_operand:SI 1 "register_operand"  "0")
                   (match_operand:SI 2 "rx_shift_operand" "rn")))
-   (set (reg:CC_ZS CC_REG)
-       (compare:CC_ZS (rotate:SI (match_dup 1) (match_dup 2))
-                      (const_int 0)))]
+   (clobber (reg:CC CC_REG))]
   ""
   "rotl\t%2, %0"
   [(set_attr "length" "3")]
 )
 
+(define_insn "*rotlsi3_flags"
+  [(set (match_operand:SI            0 "register_operand" "=r")
+       (rotate:SI (match_operand:SI 1 "register_operand"  "0")
+                  (match_operand:SI 2 "rx_shift_operand" "rn")))
+   (set (reg CC_REG)
+       (compare (rotate:SI (match_dup 1) (match_dup 2))
+                (const_int 0)))]
+  "reload_completed && rx_match_ccmode (insn, CC_ZSmode)"
+  "rotl\t%2, %0"
+  [(set_attr "length" "3")]
+)
+
 (define_insn "rotrsi3"
   [(set (match_operand:SI              0 "register_operand" "=r")
        (rotatert:SI (match_operand:SI 1 "register_operand"  "0")
                     (match_operand:SI 2 "rx_shift_operand" "rn")))
-   (set (reg:CC_ZS CC_REG)
-       (compare:CC_ZS (rotatert:SI (match_dup 1) (match_dup 2))
-                      (const_int 0)))]
+   (clobber (reg:CC CC_REG))]
   ""
   "rotr\t%2, %0"
   [(set_attr "length" "3")]
 )
 
+(define_insn "*rotrsi3_flags"
+  [(set (match_operand:SI              0 "register_operand" "=r")
+       (rotatert:SI (match_operand:SI 1 "register_operand"  "0")
+                    (match_operand:SI 2 "rx_shift_operand" "rn")))
+   (set (reg CC_REG)
+       (compare (rotatert:SI (match_dup 1) (match_dup 2))
+                (const_int 0)))]
+  "reload_completed && rx_match_ccmode (insn, CC_ZSmode)"
+  "rotr\t%2, %0"
+  [(set_attr "length" "3")]
+)
+
 (define_insn "ashrsi3"
   [(set (match_operand:SI              0 "register_operand" "=r,r,r")
        (ashiftrt:SI (match_operand:SI 1 "register_operand"  "0,0,r")
                     (match_operand:SI 2 "rx_shift_operand"  "r,n,n")))
-   (set (reg:CC_ZS CC_REG)
-       (compare:CC_ZS (ashiftrt:SI (match_dup 1) (match_dup 2))
-                      (const_int 0)))]
+   (clobber (reg:CC CC_REG))]
   ""
   "@
   shar\t%2, %0
   [(set_attr "length" "3,2,3")]
 )
 
+(define_insn "*ashrsi3_flags"
+  [(set (match_operand:SI              0 "register_operand" "=r,r,r")
+       (ashiftrt:SI (match_operand:SI 1 "register_operand"  "0,0,r")
+                    (match_operand:SI 2 "rx_shift_operand"  "r,n,n")))
+   (set (reg CC_REG)
+       (compare (ashiftrt:SI (match_dup 1) (match_dup 2))
+                (const_int 0)))]
+  "reload_completed && rx_match_ccmode (insn, CC_ZSmode)"
+  "@
+  shar\t%2, %0
+  shar\t%2, %0
+  shar\t%2, %1, %0"
+  [(set_attr "length" "3,2,3")]
+)
+
 (define_insn "lshrsi3"
   [(set (match_operand:SI              0 "register_operand" "=r,r,r")
        (lshiftrt:SI (match_operand:SI 1 "register_operand"  "0,0,r")
                     (match_operand:SI 2 "rx_shift_operand"  "r,n,n")))
-   (set (reg:CC_ZS CC_REG)
-       (compare:CC_ZS (lshiftrt:SI (match_dup 1) (match_dup 2))
-                      (const_int 0)))]
+   (clobber (reg:CC CC_REG))]
   ""
   "@
   shlr\t%2, %0
   [(set_attr "length" "3,2,3")]
 )
 
+(define_insn "*lshrsi3_flags"
+  [(set (match_operand:SI              0 "register_operand" "=r,r,r")
+       (lshiftrt:SI (match_operand:SI 1 "register_operand"  "0,0,r")
+                    (match_operand:SI 2 "rx_shift_operand"  "r,n,n")))
+   (set (reg CC_REG)
+       (compare (lshiftrt:SI (match_dup 1) (match_dup 2))
+                (const_int 0)))]
+  "reload_completed && rx_match_ccmode (insn, CC_ZSmode)"
+  "@
+  shlr\t%2, %0
+  shlr\t%2, %0
+  shlr\t%2, %1, %0"
+  [(set_attr "length" "3,2,3")]
+)
+
 (define_insn "ashlsi3"
   [(set (match_operand:SI            0 "register_operand" "=r,r,r")
        (ashift:SI (match_operand:SI 1 "register_operand"  "0,0,r")
                   (match_operand:SI 2 "rx_shift_operand"  "r,n,n")))
-   (set (reg:CC_ZS CC_REG)
-       (compare:CC_ZS (ashift:SI (match_dup 1) (match_dup 2))
-                      (const_int 0)))]
+   (clobber (reg:CC CC_REG))]
   ""
   "@
   shll\t%2, %0
   [(set_attr "length" "3,2,3")]
 )
 
+(define_insn "*ashlsi3_flags"
+  [(set (match_operand:SI            0 "register_operand" "=r,r,r")
+       (ashift:SI (match_operand:SI 1 "register_operand"  "0,0,r")
+                  (match_operand:SI 2 "rx_shift_operand"  "r,n,n")))
+   (set (reg CC_REG)
+       (compare (ashift:SI (match_dup 1) (match_dup 2))
+                (const_int 0)))]
+  "reload_completed && rx_match_ccmode (insn, CC_ZSmode)"
+  "@
+  shll\t%2, %0
+  shll\t%2, %0
+  shll\t%2, %1, %0"
+  [(set_attr "length" "3,2,3")]
+)
+
+;; Saturate to 32-bits
+(define_insn_and_split "ssaddsi3"
+  [(set (match_operand:SI             0 "register_operand" "=r")
+       (ss_plus:SI (match_operand:SI 1 "register_operand"  "r")
+                   (match_operand:SI 2 "rx_source_operand" "riQ")))
+   (clobber (reg:CC CC_REG))]
+  ""
+  "#"
+  "reload_completed"
+  [(parallel [(set (match_dup 0)
+                  (plus:SI (match_dup 1) (match_dup 2)))
+             (set (reg:CC_ZSC CC_REG)
+                  (compare:CC_ZSC
+                    (plus:SI (match_dup 1) (match_dup 2))
+                    (const_int 0)))])
+   (set (match_dup 0)
+       (unspec:SI [(match_dup 0) (reg:CC CC_REG)] 
+                  UNSPEC_BUILTIN_SAT))]
+   ""
+)
+
+(define_insn "*sat"
+  [(set (match_operand:SI             0 "register_operand" "=r")
+       (unspec:SI [(match_operand:SI 1 "register_operand"  "0")
+                   (reg:CC CC_REG)]
+                  UNSPEC_BUILTIN_SAT))]
+  "reload_completed"
+  "sat\t%0"
+  [(set_attr "length" "2")]
+)
+
 (define_insn "subsi3"
   [(set (match_operand:SI           0 "register_operand" "=r,r,r,r,r")
        (minus:SI (match_operand:SI 1 "register_operand"  "0,0,0,r,0")
                  (match_operand:SI 2 "rx_source_operand" "r,Uint04,n,r,Q")))
-   (set (reg:CC_ZSC CC_REG)
-       ;; Note - we do not acknowledge that the SUB instruction sets the Overflow
-       ;; flag because its interpretation is different from comparing the result
-       ;; against zero.  Compile and run gcc.c-torture/execute/cmpsi-1.c to see this.
-       (compare:CC_ZSC (minus:SI (match_dup 1) (match_dup 2))
-                       (const_int 0)))]
+   (clobber (reg:CC CC_REG))]
   ""
   "@
   sub\t%2, %0
    (set_attr "length" "2,2,6,3,5")]
 )
 
-(define_insn "subdi3"
-  [(set (match_operand:DI           0 "register_operand" "=r,r")
-       (minus:DI (match_operand:DI 1 "register_operand"  "0,0")
-                 (match_operand:DI 2 "rx_source_operand" "r,Q")))
-   (set (reg:CC_ZSC CC_REG) ;; See subsi3
-       (compare:CC_ZSC (minus:DI (match_dup 1) (match_dup 2))
-                       (const_int 0)))]
-  ""
-  "sub\t%L2, %L0\n\tsbb\t%H2, %H0"
-  [(set_attr "timings" "22,44")
-   (set_attr "length" "5,11")]
+;; Note that the O flag is set as if (compare op1 op2) not for
+;; what is described here, (compare op0 0).
+(define_insn "*subsi3_flags"
+  [(set (match_operand:SI           0 "register_operand" "=r,r,r,r,r")
+       (minus:SI (match_operand:SI 1 "register_operand"  "0,0,0,r,0")
+                 (match_operand:SI 2 "rx_source_operand" "r,Uint04,n,r,Q")))
+   (set (reg CC_REG)
+       (compare (minus:SI (match_dup 1) (match_dup 2))
+                (const_int 0)))]
+  "reload_completed && rx_match_ccmode (insn, CC_ZSCmode)"
+  "@
+  sub\t%2, %0
+  sub\t%2, %0
+  add\t%N2, %0
+  sub\t%2, %1, %0
+  sub\t%Q2, %0"
+  [(set_attr "timings" "11,11,11,11,33")
+   (set_attr "length" "2,2,6,3,5")]
 )
 
+;; A helper to expand the above with the CC_MODE filled in.
+(define_expand "subsi3_flags"
+  [(parallel [(set (match_operand:SI 0 "register_operand")
+                  (minus:SI (match_operand:SI 1 "register_operand")
+                            (match_operand:SI 2 "rx_source_operand")))
+             (set (reg:CC_ZSC CC_REG)
+                  (compare:CC_ZSC (minus:SI (match_dup 1) (match_dup 2))
+                                  (const_int 0)))])]
+)
+
+(define_insn "sbb_internal"
+  [(set (match_operand:SI     0 "register_operand"   "=r,r")
+       (minus:SI
+         (minus:SI
+           (match_operand:SI 1 "register_operand"   " 0,0")
+           (match_operand:SI 2 "rx_compare_operand" " r,Q"))
+         (geu:SI (reg:CC CC_REG) (const_int 0))))
+    (clobber (reg:CC CC_REG))]
+  "reload_completed"
+  "sbb\t%2, %0"
+  [(set_attr "timings" "11,33")
+   (set_attr "length"  "3,6")]
+)
+
+(define_insn "*sbb_flags"
+  [(set (match_operand:SI     0 "register_operand"   "=r,r")
+       (minus:SI
+         (minus:SI
+           (match_operand:SI 1 "register_operand"   " 0,0")
+           (match_operand:SI 2 "rx_compare_operand" " r,Q"))
+         (geu:SI (reg:CC CC_REG) (const_int 0))))
+   (set (reg CC_REG)
+       (compare
+         (minus:SI
+           (minus:SI (match_dup 1) (match_dup 2))
+           (geu:SI (reg:CC CC_REG) (const_int 0)))
+         (const_int 0)))]
+  "reload_completed"
+  "sbb\t%2, %0"
+  [(set_attr "timings" "11,33")
+   (set_attr "length"  "3,6")]
+)
+
+(define_expand "subdi3"
+  [(set (match_operand:DI           0 "register_operand")
+       (minus:DI (match_operand:DI 1 "register_operand")
+                 (match_operand:DI 2 "rx_compare_operand")))]
+  ""
+{
+  rtx op0l, op0h, op1l, op1h, op2l, op2h;
+
+  op0l = gen_lowpart (SImode, operands[0]);
+  op1l = gen_lowpart (SImode, operands[1]);
+  op2l = gen_lowpart (SImode, operands[2]);
+  op0h = gen_highpart (SImode, operands[0]);
+  op1h = gen_highpart (SImode, operands[1]);
+  op2h = gen_highpart_mode (SImode, DImode, operands[2]);
+
+  emit_insn (gen_subdi3_internal (op0l, op0h, op1l, op2l, op1h, op2h));
+  DONE;
+})
+
+(define_insn_and_split "subdi3_internal"
+  [(set (match_operand:SI          0 "register_operand"   "=&r,&r")
+       (minus:SI (match_operand:SI 2 "register_operand"  "  0, r")
+                 (match_operand:SI 3 "rx_compare_operand" "rQ, r")))
+   (set (match_operand:SI          1 "register_operand"   "= r, r")
+       (minus:SI
+         (minus:SI
+           (match_operand:SI      4 "register_operand"   "  1, 1")
+           (match_operand:SI      5 "rx_compare_operand" " rQ,rQ"))
+         (geu:SI (match_dup 2) (match_dup 3))))
+   (clobber (reg:CC CC_REG))]
+  ""
+  "#"
+  "reload_completed"
+  [(const_int 0)]
+{
+  emit_insn (gen_subsi3_flags (operands[0], operands[2], operands[3]));
+  emit_insn (gen_sbb_internal (operands[1], operands[4], operands[5]));
+  DONE;
+})
+
 (define_insn "xorsi3"
   [(set (match_operand:SI         0 "register_operand" "=r,r,r,r,r,r")
        (xor:SI (match_operand:SI 1 "register_operand" "%0,0,0,0,0,0")
                (match_operand:SI 2 "rx_source_operand"
                                  "r,Sint08,Sint16,Sint24,i,Q")))
-   (set (reg:CC_ZS CC_REG)
-       (compare:CC_ZS (xor:SI (match_dup 1) (match_dup 2))
-                      (const_int 0)))]
+   (clobber (reg:CC CC_REG))]
   ""
   "xor\t%Q2, %0"
   [(set_attr "timings" "11,11,11,11,11,33")
    (set_attr "length" "3,4,5,6,7,6")]
 )
+
+(define_insn "*xorsi3_flags"
+  [(set (match_operand:SI         0 "register_operand" "=r,r,r,r,r,r")
+       (xor:SI (match_operand:SI 1 "register_operand" "%0,0,0,0,0,0")
+               (match_operand:SI 2 "rx_source_operand"
+                                 "r,Sint08,Sint16,Sint24,i,Q")))
+   (set (reg CC_REG)
+       (compare (xor:SI (match_dup 1) (match_dup 2))
+                (const_int 0)))]
+  "reload_completed && rx_match_ccmode (insn, CC_ZSmode)"
+  "xor\t%Q2, %0"
+  [(set_attr "timings" "11,11,11,11,11,33")
+   (set_attr "length" "3,4,5,6,7,6")]
+)
 \f
 ;; Floating Point Instructions
 
   [(set (match_operand:SF          0 "register_operand"  "=r,r,r")
        (plus:SF (match_operand:SF 1 "register_operand"  "%0,0,0")
                 (match_operand:SF 2 "rx_source_operand"  "r,F,Q")))
-   (set (reg:CC_ZS CC_REG)
-       (compare:CC_ZS (plus:SF (match_dup 1) (match_dup 2))
-                       (const_int 0)))]
+   (clobber (reg:CC CC_REG))]
   "ALLOW_RX_FPU_INSNS"
   "fadd\t%2, %0"
   [(set_attr "timings" "44,44,66")
   [(set (match_operand:SF         0 "register_operand" "=r,r,r")
        (div:SF (match_operand:SF 1 "register_operand"  "0,0,0")
                (match_operand:SF 2 "rx_source_operand" "r,F,Q")))
-   (set (reg:CC_ZS CC_REG)
-       (compare:CC_ZS (div:SF (match_dup 1) (match_dup 2))
-                       (const_int 0)))]
+   (clobber (reg:CC CC_REG))]
   "ALLOW_RX_FPU_INSNS"
   "fdiv\t%2, %0"
   [(set_attr "timings" "1616,1616,1818")
   [(set (match_operand:SF          0 "register_operand" "=r,r,r")
        (mult:SF (match_operand:SF 1 "register_operand" "%0,0,0")
                (match_operand:SF  2 "rx_source_operand" "r,F,Q")))
-   (set (reg:CC_ZS CC_REG)
-       (compare:CC_ZS (mult:SF (match_dup 1) (match_dup 2))
-                       (const_int 0)))]
+   (clobber (reg:CC CC_REG))]
   "ALLOW_RX_FPU_INSNS"
   "fmul\t%2, %0"
   [(set_attr "timings" "33,33,55")
   [(set (match_operand:SF           0 "register_operand" "=r,r,r")
        (minus:SF (match_operand:SF 1 "register_operand"  "0,0,0")
                  (match_operand:SF 2 "rx_source_operand" "r,F,Q")))
-   (set (reg:CC_ZS CC_REG)
-       (compare:CC_ZS (minus:SF (match_dup 1) (match_dup 2))
-                      (const_int 0)))]
+   (clobber (reg:CC CC_REG))]
   "ALLOW_RX_FPU_INSNS"
   "fsub\t%Q2, %0"
   [(set_attr "timings" "44,44,66")
 (define_insn "fix_truncsfsi2"
   [(set (match_operand:SI         0 "register_operand"  "=r,r")
        (fix:SI (match_operand:SF 1 "rx_compare_operand" "r,Q")))
-   (set (reg:CC_ZS CC_REG)
-       (compare:CC_ZS (fix:SI (match_dup 1))
-                      (const_int 0)))]
+   (clobber (reg:CC CC_REG))]
   "ALLOW_RX_FPU_INSNS"
   "ftoi\t%Q1, %0"
   [(set_attr "timings" "22,44")
 (define_insn "floatsisf2"
   [(set (match_operand:SF           0 "register_operand"  "=r,r")
        (float:SF (match_operand:SI 1 "rx_compare_operand" "r,Q")))
-   (set (reg:CC_ZS CC_REG)
-       (compare:CC_ZS (float:SF (match_dup 1))
-                       (const_int 0)))]
+   (clobber (reg:CC CC_REG))]
   "ALLOW_RX_FPU_INSNS"
   "itof\t%Q1, %0"
   [(set_attr "timings" "22,44")
 )
 \f
 ;; Bit manipulation instructions.
-;; Note - there are two versions of each pattern because the memory
-;; accessing versions use QImode whilst the register accessing
-;; versions use SImode.
-;; The peephole are here because the combiner only looks at a maximum
-;; of three instructions at a time.
-
-(define_insn "bitset"
-  [(set:SI (match_operand:SI                    0 "register_operand" "=r")
-          (ior:SI (match_operand:SI            1 "register_operand" "0")
-                  (ashift:SI (const_int 1)
-                             (match_operand:SI 2 "nonmemory_operand" "ri"))))]
-  ""
-  "bset\t%2, %0"
+
+;; ??? The *_in_memory patterns will not be matched without further help.
+;; At one time we had the insv expander generate them, but I suspect that
+;; in general we get better performance by exposing the register load to
+;; the optimizers.
+;;
+;; An alternate solution would be to re-organize these patterns such
+;; that allow both register and memory operands.  This would allow the
+;; register allocator to spill and not load the register operand.  This
+;; would be possible only for operations for which we have a constant
+;; bit offset, so that we can adjust the address by ofs/8 and replace
+;; the offset in the insn by ofs%8.
+
+(define_insn "*bitset"
+  [(set (match_operand:SI                    0 "register_operand" "=r")
+       (ior:SI (ashift:SI (const_int 1)
+                          (match_operand:SI 1 "rx_shift_operand" "ri"))
+               (match_operand:SI            2 "register_operand" "0")))]
+  ""
+  "bset\t%1, %0"
   [(set_attr "length" "3")]
 )
 
-(define_insn "bitset_in_memory"
-  [(set:QI (match_operand:QI                    0 "memory_operand" "=m")
-          (ior:QI (match_operand:QI            1 "memory_operand" "0")
-                  (ashift:QI (const_int 1)
-                             (match_operand:QI 2 "nonmemory_operand" "ri"))))]
+(define_insn "*bitset_in_memory"
+  [(set (match_operand:QI                    0 "memory_operand" "+Q")
+       (ior:QI (ashift:QI (const_int 1)
+                          (match_operand:QI 1 "nonmemory_operand" "ri"))
+               (match_dup 0)))]
   ""
-  "bset\t%2, %0.B"
+  "bset\t%1, %0.B"
   [(set_attr "length" "3")
    (set_attr "timings" "34")]
 )
 
-;; (set (reg A) (const_int 1))
-;; (set (reg A) (ashift (reg A) (reg B)))
-;; (set (reg C) (ior (reg A) (reg C)))
-(define_peephole2
-  [(set:SI (match_operand:SI 0 "register_operand" "")
-          (const_int 1))
-   (set:SI (match_dup 0)
-          (ashift:SI (match_dup 0)
-                     (match_operand:SI 1 "register_operand" "")))
-   (set:SI (match_operand:SI 2 "register_operand" "")
-          (ior:SI (match_dup 0)
-                  (match_dup 2)))]
-  "dead_or_set_p (insn, operands[0])"
-  [(set:SI (match_dup 2)
-          (ior:SI (match_dup 2)
-                  (ashift:SI (const_int 1)
-                             (match_dup 1))))]
-)
-  
-;; (set (reg A) (const_int 1))
-;; (set (reg A) (ashift (reg A) (reg B)))
-;; (set (reg A) (ior (reg A) (reg C)))
-;; (set (reg C) (reg A)
-(define_peephole2
-  [(set:SI (match_operand:SI 0 "register_operand" "")
-          (const_int 1))
-   (set:SI (match_dup 0)
-          (ashift:SI (match_dup 0)
-                     (match_operand:SI 1 "register_operand" "")))
-   (set:SI (match_dup 0)
-          (ior:SI (match_dup 0)
-                  (match_operand:SI 2 "register_operand" "")))
-   (set:SI (match_dup 2) (match_dup 0))]
-  "dead_or_set_p (insn, operands[0])"
-  [(set:SI (match_dup 2)
-          (ior:SI (match_dup 2)
-                  (ashift:SI (const_int 1)
-                             (match_dup 1))))]
-)
-  
-(define_insn "bitinvert"
-  [(set:SI (match_operand:SI 0 "register_operand" "+r")
-          (xor:SI (match_operand:SI 1 "register_operand" "0")
-                  (ashift:SI (const_int 1)
-                             (match_operand:SI 2 "nonmemory_operand" "ri"))))]
+(define_insn "*bitinvert"
+  [(set (match_operand:SI 0 "register_operand" "=r")
+       (xor:SI (ashift:SI (const_int 1)
+                          (match_operand:SI 1 "rx_shift_operand" "ri"))
+               (match_operand:SI 2 "register_operand" "0")))]
   ""
-  "bnot\t%2, %0"
+  "bnot\t%1, %0"
   [(set_attr "length" "3")]
 )
 
-(define_insn "bitinvert_in_memory"
-  [(set:QI (match_operand:QI 0 "memory_operand" "+m")
-          (xor:QI (match_operand:QI 1 "register_operand" "0")
-                  (ashift:QI (const_int 1)
-                             (match_operand:QI 2 "nonmemory_operand" "ri"))))]
+(define_insn "*bitinvert_in_memory"
+  [(set (match_operand:QI 0 "memory_operand" "+Q")
+       (xor:QI (ashift:QI (const_int 1)
+                          (match_operand:QI 1 "nonmemory_operand" "ri"))
+               (match_dup 0)))]
   ""
-  "bnot\t%2, %0.B"
+  "bnot\t%1, %0.B"
   [(set_attr "length" "5")
    (set_attr "timings" "33")]
 )
 
-;; (set (reg A) (const_int 1))
-;; (set (reg A) (ashift (reg A) (reg B)))
-;; (set (reg C) (xor (reg A) (reg C)))
-(define_peephole2
-  [(set:SI (match_operand:SI 0 "register_operand" "")
-          (const_int 1))
-   (set:SI (match_dup 0)
-          (ashift:SI (match_dup 0)
-                     (match_operand:SI 1 "register_operand" "")))
-   (set:SI (match_operand:SI 2 "register_operand" "")
-          (xor:SI (match_dup 0)
-                  (match_dup 2)))]
-  "dead_or_set_p (insn, operands[0])"
-  [(set:SI (match_dup 2)
-          (xor:SI (match_dup 2)
-                  (ashift:SI (const_int 1)
-                             (match_dup 1))))]
+(define_insn "*bitclr"
+  [(set (match_operand:SI 0 "register_operand" "=r")
+       (and:SI (not:SI
+                 (ashift:SI
+                   (const_int 1)
+                   (match_operand:SI 1 "rx_shift_operand" "ri")))
+               (match_operand:SI 2 "register_operand" "0")))]
   ""
-)
-  
-;; (set (reg A) (const_int 1))
-;; (set (reg A) (ashift (reg A) (reg B)))
-;; (set (reg A) (xor (reg A) (reg C)))
-;; (set (reg C) (reg A))
-(define_peephole2
-  [(set:SI (match_operand:SI 0 "register_operand" "")
-          (const_int 1))
-   (set:SI (match_dup 0)
-          (ashift:SI (match_dup 0)
-                     (match_operand:SI 1 "register_operand" "")))
-   (set:SI (match_dup 0)
-          (xor:SI (match_dup 0)
-                  (match_operand:SI 2 "register_operand" "")))
-   (set:SI (match_dup 2) (match_dup 0))]
-  "dead_or_set_p (insn, operands[0])"
-  [(set:SI (match_dup 2)
-          (xor:SI (match_dup 2)
-                  (ashift:SI (const_int 1)
-                             (match_dup 1))))]
-  ""
-)
-
-(define_insn "bitclr"
-  [(set:SI (match_operand:SI 0 "register_operand" "+r")
-          (and:SI (match_operand:SI 1 "register_operand" "0")
-                  (not:SI (ashift:SI (const_int 1)
-                                     (match_operand:SI 2 "nonmemory_operand" "ri")))))]
-  ""
-  "bclr\t%2, %0"
+  "bclr\t%1, %0"
   [(set_attr "length" "3")]
 )
 
-(define_insn "bitclr_in_memory"
-  [(set:QI (match_operand:QI 0 "memory_operand" "+m")
-          (and:QI (match_operand:QI 1 "memory_operand" "0")
-                  (not:QI (ashift:QI (const_int 1)
-                                     (match_operand:QI 2 "nonmemory_operand" "ri")))))]
+(define_insn "*bitclr_in_memory"
+  [(set (match_operand:QI 0 "memory_operand" "+Q")
+       (and:QI (not:QI
+                 (ashift:QI
+                   (const_int 1)
+                   (match_operand:QI 1 "nonmemory_operand" "ri")))
+               (match_dup 0)))]
   ""
-  "bclr\t%2, %0.B"
+  "bclr\t%1, %0.B"
   [(set_attr "length" "3")
    (set_attr "timings" "34")]
 )
 
-;; (set (reg A) (const_int -2))
-;; (set (reg A) (rotate (reg A) (reg B)))
-;; (set (reg C) (and (reg A) (reg C)))
-(define_peephole2
-  [(set:SI (match_operand:SI 0 "register_operand" "")
-          (const_int -2))
-   (set:SI (match_dup 0)
-          (rotate:SI (match_dup 0)
-                     (match_operand:SI 1 "register_operand" "")))
-   (set:SI (match_operand:SI 2 "register_operand" "")
-          (and:SI (match_dup 0)
-                  (match_dup 2)))]
-  "dead_or_set_p (insn, operands[0])"
-  [(set:SI (match_dup 2)
-          (and:SI (match_dup 2)
-                  (not:SI (ashift:SI (const_int 1)
-                                     (match_dup 1)))))]
+(define_insn "*insv_imm"
+  [(set (zero_extract:SI
+         (match_operand:SI 0 "register_operand" "+r")
+         (const_int 1)
+         (match_operand:SI 1 "rx_shift_operand" "ri"))
+       (match_operand:SI 2 "const_int_operand" ""))]
+  ""
+{
+  if (INTVAL (operands[2]) & 1)
+    return "bset\t%1, %0";
+  else
+    return "bclr\t%1, %0";
+}
+  [(set_attr "length" "3")]
 )
-  
-;; (set (reg A) (const_int -2))
-;; (set (reg A) (rotate (reg A) (reg B)))
-;; (set (reg A) (and (reg A) (reg C)))
-;; (set (reg C) (reg A)
-(define_peephole2
-  [(set:SI (match_operand:SI 0 "register_operand" "")
-          (const_int -2))
-   (set:SI (match_dup 0)
-          (rotate:SI (match_dup 0)
-                     (match_operand:SI 1 "register_operand" "")))
-   (set:SI (match_dup 0)
-          (and:SI (match_dup 0)
-                  (match_operand:SI 2 "register_operand" "")))
-   (set:SI (match_dup 2) (match_dup 0))]
-  "dead_or_set_p (insn, operands[0])"
-  [(set:SI (match_dup 2)
-          (and:SI (match_dup 2)
-                  (not:SI (ashift:SI (const_int 1)
-                                     (match_dup 1)))))]
+
+(define_insn_and_split "rx_insv_reg"
+  [(set (zero_extract:SI
+         (match_operand:SI 0 "register_operand" "+r")
+         (const_int 1)
+         (match_operand:SI 1 "const_int_operand" ""))
+       (match_operand:SI 2 "register_operand" "r"))
+   (clobber (reg:CC CC_REG))]
+  ""
+  "#"
+  "reload_completed"
+  [(set (zero_extract:SI (match_dup 0) (const_int 1) (match_dup 1))
+       (match_dup 3))]
+{
+  rtx flags, x;
+
+  /* Emit tst #1, op2.  */
+  flags = gen_rtx_REG (CC_ZSmode, CC_REG);
+  x = gen_rtx_AND (SImode, operands[2], const1_rtx);
+  x = gen_rtx_COMPARE (CC_ZSmode, x, const0_rtx);
+  x = gen_rtx_SET (VOIDmode, flags, x);
+  emit_insn (x);
+
+  /* Emit bmne.  */
+  operands[3] = gen_rtx_NE (SImode, flags, const0_rtx);
+})
+
+(define_insn_and_split "*insv_cond"
+  [(set (zero_extract:SI
+         (match_operand:SI 0 "register_operand" "+r")
+         (const_int 1)
+         (match_operand:SI 1 "const_int_operand" ""))
+       (match_operator:SI 4 "comparison_operator"
+         [(match_operand:SI 2 "register_operand" "r")
+          (match_operand:SI 3 "rx_source_operand" "riQ")]))
+   (clobber (reg:CC CC_REG))]
+  ""
+  "#"
+  "reload_completed"
+  [(set (zero_extract:SI (match_dup 0) (const_int 1) (match_dup 1))
+       (match_dup 4))]
+{
+  rtx flags, x;
+
+  flags = gen_rtx_REG (CCmode, CC_REG);
+  x = gen_rtx_COMPARE (CCmode, operands[2], operands[3]);
+  x = gen_rtx_SET (VOIDmode, flags, x);
+  emit_insn (x);
+
+  operands[4] = gen_rtx_fmt_ee (GET_CODE (operands[4]), SImode,
+                               flags, const0_rtx);
+})
+
+(define_insn "*bmcc"
+  [(set (zero_extract:SI
+         (match_operand:SI 0 "register_operand" "+r")
+         (const_int 1)
+         (match_operand:SI 1 "const_int_operand" ""))
+       (match_operator:SI 2 "comparison_operator"
+         [(reg CC_REG) (const_int 0)]))]
+  "reload_completed"
+  "bm%B2\t%1, %0"
+  [(set_attr "length" "3")]
 )
 
-(define_expand "insv"
-  [(set:SI (zero_extract:SI (match_operand:SI 0 "nonimmediate_operand") ;; Destination
-                           (match_operand    1 "immediate_operand")    ;; # of bits to set
-                           (match_operand    2 "immediate_operand"))   ;; Starting bit
-          (match_operand                     3 "immediate_operand"))]  ;; Bits to insert
+;; Work around the fact that X=Y<0 is preferentially expanded as a shift.
+(define_insn_and_split "*insv_cond_lt"
+  [(set (zero_extract:SI
+         (match_operand:SI 0 "register_operand" "+r")
+         (const_int 1)
+         (match_operand:SI 1 "const_int_operand" ""))
+       (match_operator:SI 3 "rshift_operator"
+         [(match_operand:SI 2 "register_operand" "r")
+          (const_int 31)]))
+   (clobber (reg:CC CC_REG))]
   ""
-  {
-    if (rx_expand_insv (operands))
+  "#"
+  ""
+  [(parallel [(set (zero_extract:SI (match_dup 0) (const_int 1) (match_dup 1))
+                  (lt:SI (match_dup 2) (const_int 0)))
+             (clobber (reg:CC CC_REG))])]
+  ""
+)
+
+(define_expand "insv"
+  [(set (zero_extract:SI
+         (match_operand:SI 0 "register_operand")       ;; Destination
+         (match_operand:SI 1 "const_int_operand")      ;; # of bits to set
+         (match_operand:SI 2 "nonmemory_operand"))     ;; Starting bit
+       (match_operand:SI   3 "nonmemory_operand"))]    ;; Bits to insert
+  ""
+{
+  /* We only handle single-bit inserts.  */
+  if (!CONST_INT_P (operands[1]) || INTVAL (operands[1]) != 1)
+    FAIL;
+
+  /* Either the bit to insert or the position must be constant.  */
+  if (CONST_INT_P (operands[3]))
+    operands[3] = GEN_INT (INTVAL (operands[3]) & 1);
+  else if (CONST_INT_P (operands[2]))
+    {
+      emit_insn (gen_rx_insv_reg (operands[0], operands[2], operands[3]));
       DONE;
+    }
+  else
     FAIL;
-  }
-)   
+})
 \f
 ;; Atomic exchange operation.
 
 (define_insn "sync_lock_test_and_setsi"
-  [(set:SI (match_operand:SI 0 "register_operand"   "=r,r")
-          (match_operand:SI 1 "rx_compare_operand" "=r,Q"))
-   (set:SI (match_dup 1)
-          (match_operand:SI 2 "register_operand"    "0,0"))]
+  [(set (match_operand:SI 0 "register_operand"   "=r,r")
+       (match_operand:SI 1 "rx_compare_operand" "=r,Q"))
+   (set (match_dup 1)
+       (match_operand:SI 2 "register_operand"    "0,0"))]
   ""
   "xchg\t%1, %0"
   [(set_attr "length" "3,6")
 ;; Block move functions.
 
 (define_expand "movstr"
-  [(set:SI (match_operand:BLK 1 "memory_operand")    ;; Dest
-          (match_operand:BLK 2 "memory_operand"))   ;; Source
-   (use (match_operand:SI     0 "register_operand")) ;; Updated Dest
+  [(set (match_operand:BLK 1 "memory_operand")    ;; Dest
+       (match_operand:BLK 2 "memory_operand"))   ;; Source
+   (use (match_operand:SI  0 "register_operand")) ;; Updated Dest
   ]
   ""
   {
 )
 
 (define_insn "rx_movstr"
-  [(set:SI (mem:BLK (reg:SI 1))
-          (mem:BLK (reg:SI 2)))
+  [(set (mem:BLK (reg:SI 1))
+       (mem:BLK (reg:SI 2)))
    (unspec_volatile:BLK [(reg:SI 1) (reg:SI 2) (reg:SI 3)] UNSPEC_MOVSTR)
    (clobber (reg:SI 1))
    (clobber (reg:SI 2))
 )
 
 (define_insn "rx_strend"
-  [(set:SI (match_operand:SI                      0 "register_operand" "=r")
-          (unspec_volatile:SI [(match_operand:SI 1 "register_operand"  "r")
+  [(set (match_operand:SI                      0 "register_operand" "=r")
+       (unspec_volatile:SI [(match_operand:SI 1 "register_operand"  "r")
                                (reg:SI 3)] UNSPEC_STRLEN))
    (clobber (reg:SI 1))
    (clobber (reg:SI 2))
 )
 
 (define_insn "rx_setmem"
-  [(set:BLK (mem:BLK (reg:SI 1)) (reg 2))
-   (unspec_volatile:BLK [(reg:SI 1) (reg:SI 2) (reg:SI 3)] UNSPEC_SETMEM)
+  [(set (mem:BLK (reg:SI 1))
+       (unspec_volatile:BLK [(reg:SI 1) (reg:SI 2) (reg:SI 3)] UNSPEC_SETMEM))
    (clobber (reg:SI 1))
    (clobber (reg:SI 3))]
   ""
 )
 
 (define_insn "rx_cmpstrn"
-  [(set:SI (match_operand:SI 0 "register_operand" "=r")
-          (unspec_volatile:SI [(reg:SI 1) (reg:SI 2) (reg:SI 3)]
-                              UNSPEC_CMPSTRN))
-   (use (match_operand:BLK   1 "memory_operand" "m"))
-   (use (match_operand:BLK   2 "memory_operand" "m"))
+  [(set (match_operand:SI 0 "register_operand" "=r")
+       (unspec_volatile:SI [(reg:SI 1) (reg:SI 2) (reg:SI 3)]
+                           UNSPEC_CMPSTRN))
+   (use (match_operand:BLK 1 "memory_operand" "m"))
+   (use (match_operand:BLK 2 "memory_operand" "m"))
    (clobber (reg:SI 1))
    (clobber (reg:SI 2))
    (clobber (reg:SI 3))
 
 ;; Byte swap (two 16-bit values).
 (define_insn "revw"
-  [(set (match_operand:SI             0 "register_operand" "+r")
+  [(set (match_operand:SI             0 "register_operand" "=r")
        (unspec:SI [(match_operand:SI 1 "register_operand"  "r")]
                   UNSPEC_BUILTIN_REVW))]
   ""
 
 ;; Clear Processor Status Word
 (define_insn "clrpsw"
-  [(unspec:SI [(match_operand:SI 0 "immediate_operand" "i")]
+  [(unspec_volatile:SI [(match_operand:SI 0 "immediate_operand" "i")]
              UNSPEC_BUILTIN_CLRPSW)
    (clobber (reg:CC CC_REG))]
   ""
 
 ;; Set Processor Status Word
 (define_insn "setpsw"
-  [(unspec:SI [(match_operand:SI 0 "immediate_operand" "i")]
+  [(unspec_volatile:SI [(match_operand:SI 0 "immediate_operand" "i")]
              UNSPEC_BUILTIN_SETPSW)
    (clobber (reg:CC CC_REG))]
   ""
 ;; Move from control register
 (define_insn "mvfc"
   [(set (match_operand:SI             0 "register_operand" "=r")
-       (unspec:SI [(match_operand:SI 1 "immediate_operand" "i")]
+       (unspec_volatile:SI [(match_operand:SI 1 "immediate_operand" "i")]
                   UNSPEC_BUILTIN_MVFC))]
   ""
   "mvfc\t%C1, %0"
 
 ;; Move to control register
 (define_insn "mvtc"
-  [(unspec:SI [(match_operand:SI 0 "immediate_operand" "i,i")
+  [(unspec_volatile:SI [(match_operand:SI 0 "immediate_operand" "i,i")
               (match_operand:SI 1 "nonmemory_operand" "r,i")]
              UNSPEC_BUILTIN_MVTC)]
   ""
 
 ;; Move to interrupt priority level
 (define_insn "mvtipl"
-  [(unspec:SI [(match_operand:SI 0 "immediate_operand" "Uint04")]
+  [(unspec_volatile:SI [(match_operand:SI 0 "immediate_operand" "Uint04")]
              UNSPEC_BUILTIN_MVTIPL)]
   ""
   "mvtipl\t%0"