OSDN Git Service

* config/rx/rx.md (return): Define pattern.
[pf3gnuchains/gcc-fork.git] / gcc / config / rx / rx.md
index 0e76a5e..92768c6 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 ])
-
 ;; This code iterator is used for sign- and zero- extensions.
 (define_mode_iterator small_int_modes [(HI "") (QI "")])
 
+;; This code iterator is used for max and min operations.
+(define_mode_iterator int_modes [(SI "") (HI "") (QI "")])
+
 ;; We do not handle DFmode here because it is either
 ;; the same as SFmode, or if -m64bit-doubles is active
 ;; then all operations on doubles have to be handled by
 (define_mode_iterator register_modes
   [(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)
+   (CC_REG                16)
 
    (UNSPEC_LOW_REG         0)
    (UNSPEC_HIGH_REG        1)
@@ -54,6 +43,7 @@
    (UNSPEC_RTE             10)
    (UNSPEC_RTFI            11)
    (UNSPEC_NAKED           12)
+   (UNSPEC_CONST           13)
    
    (UNSPEC_MOVSTR          20)
    (UNSPEC_MOVMEM          21)
    (UNSPEC_BUILTIN_SAT     49)
    (UNSPEC_BUILTIN_SETPSW  50)
    (UNSPEC_BUILTIN_WAIT           51)
+
+   (UNSPEC_PID_ADDR       52)
   ]
 )
 
-;; Condition code settings:
-;;   none     - insn does not affect the condition code bits
-;;   set_zs   - insn sets z,s to usable values;
-;;   set_zso  - insn sets z,s,o to usable values;
-;;   set_zsoc - insn sets z,s,o,c to usable values;
-;;   clobber  - value of cc0 is unknown
-(define_attr "cc" "none,set_zs,set_zso,set_zsoc,clobber" (const_string "none"))
-
 (define_attr "length" "" (const_int 8))
 
 (include "predicates.md")
 (define_insn_reservation "throughput_18_latency_18"  1
   (eq_attr "timings" "1818") "throughput*18")
 
+;; ----------------------------------------------------------------------------
+
 ;; Comparisons
 
-(define_expand "cbranchsi4"
-  [(set (cc0) (compare:CC (match_operand:SI 1 "register_operand")
-                         (match_operand:SI 2 "rx_source_operand")))
-   (set (pc)
-       (if_then_else (match_operator:SI  0 "comparison_operator"
-                                         [(cc0) (const_int 0)])
-                     (label_ref (match_operand 3 ""))
-                     (pc)))]
-  ""
-  ""
-)
+;; Note - we do not specify the two instructions necessary to perform
+;; a compare-and-branch in the cbranchsi4 pattern because that would
+;; allow the comparison to be moved away from the jump before the reload
+;; pass has completed.  That would be problematical because reload can
+;; generate ADDSI3 instructions which would corrupt the PSW flags.
 
-(define_expand "cbranchsf4"
-  [(set (cc0) (compare:CC (match_operand:SF 1 "register_operand")
-                         (match_operand:SF 2 "rx_source_operand")))
-   (set (pc)
-       (if_then_else (match_operator:SI  0 "comparison_operator"
-                                         [(cc0) (const_int 0)])
-                     (label_ref (match_operand 3 ""))
-                     (pc)))]
-  "ALLOW_RX_FPU_INSNS && ! flag_non_call_exceptions"
+(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)))]
   ""
 )
 
-;; The TST instruction is not used as it does not set the Carry flag,
-;; so for example, the LessThan comparison cannot be tested.
-;;
-;; (define_insn "tstsi"
-;;   [(set (cc0)
-;;         (match_operand:SI 0 "rx_source_operand"  "r,i,Q")))]
-;;   ""
-;;   {
-;;     rx_float_compare_mode = false;
-;;     return "tst\t%Q0";
-;;   }
-;;   [(set_attr "cc" "set_zs")
-;;    (set_attr "timings" "11,11,33")
-;;    (set_attr "length" "3,7,6")]
-;; )
-
-(define_insn "cmpsi"
-  [(set (cc0) (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;
-    return "cmp\t%Q1, %Q0";
-  }
-  [(set_attr "cc" "set_zsoc")
-   (set_attr "timings" "11,11,11,11,11,11,33")
+(define_insn_and_split "*cbranchsi4"
+  [(set (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)]
+{
+  rx_split_cbranch (CCmode, GET_CODE (operands[3]),
+                   operands[0], operands[1], operands[2]);
+  DONE;
+})
+
+(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"
+  "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 (cc0)
-       (compare:CC (match_operand:SF 0 "register_operand"  "r,r,r")
-                   (match_operand:SF 1 "rx_source_operand" "r,i,Q")))]
-  "ALLOW_RX_FPU_INSNS && ! flag_non_call_exceptions"
-  {
-    rx_float_compare_mode = true;
-    return "fcmp\t%1, %0";
-  }
-  [(set_attr "cc" "set_zso")
-   (set_attr "timings" "11,11,33")
-   (set_attr "length" "3,7,5")]
+;; Canonical method for representing TST.
+(define_insn_and_split "*cbranchsi4_tst"
+  [(set (pc)
+       (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)]
+{
+  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 "*cbranchsi4_tst_ext"
+  [(set (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)))]
+  ""
+  "#"
+  "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")]
 )
 
-;; Flow Control Instructions:
-
-(define_expand "b<code>"
+(define_expand "cbranchsf4"
   [(set (pc)
-        (if_then_else (most_cond (cc0) (const_int 0))
-                      (label_ref (match_operand 0))
-                      (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 "*conditional_branch"
+(define_insn_and_split "*cbranchsf4"
   [(set (pc)
-       (if_then_else (match_operator           1 "comparison_operator"
-                                               [(cc0) (const_int 0)])
-                     (label_ref (match_operand 0 "" ""))
-                     (pc)))]
-  ""
-  {
-    return rx_gen_cond_branch_template (operands[1], false);
-  }
-  [(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.
-   (set_attr "cc" "clobber")] ;; FIXME: This clobber is wrong.
+       (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)]
+{
+  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")]
 )
 
-(define_insn "*reveresed_conditional_branch"
+;; Flow Control Instructions:
+
+(define_insn "*conditional_branch"
   [(set (pc)
-       (if_then_else (match_operator 1 "comparison_operator"
-                                     [(cc0) (const_int 0)])
-                     (pc)
-                     (label_ref (match_operand 0 "" ""))))]
-  ""
-  {
-    return rx_gen_cond_branch_template (operands[1], true);
-  }
+       (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.
-   (set_attr "cc" "clobber")] ;; FIXME: This clobber is wrong.
+   (set_attr "timings" "33")] ;; The timing assumes that the branch is taken.
 )
 
+;; ----------------------------------------------------------------------------
+
 (define_insn "jump"
-  [(set (pc) (label_ref (match_operand 0 "" "")))]
+  [(set (pc)
+       (label_ref (match_operand 0 "" "")))]
   ""
   "bra\t%0"
   [(set_attr "length" "4")
-   (set_attr "timings" "33")
-   (set_attr "cc" "clobber")] ;; FIXME: This clobber is wrong.
+   (set_attr "timings" "33")]
 )
 
 (define_insn "indirect_jump"
-  [(set (pc) (match_operand:SI 0 "register_operand" "r"))]
+  [(set (pc)
+       (match_operand:SI 0 "register_operand" "r"))]
   ""
   "jmp\t%0"
   [(set_attr "length" "2")
-   (set_attr "timings" "33")
-   (set_attr "cc" "clobber")] ;; FIXME: This clobber is wrong.
+   (set_attr "timings" "33")]
 )
 
 (define_insn "tablejump"
-  [(set (pc) (match_operand:SI     0 "register_operand" "r"))
+  [(set (pc)
+       (match_operand:SI          0 "register_operand" "r"))
    (use (label_ref (match_operand  1 "" "")))]
   ""
-  { return flag_pic ? (TARGET_AS100_SYNTAX ? "\n?:\tbra\t%0"
-                                          : "\n1:\tbra\t%0")
-                                          : "jmp\t%0";
+  { return TARGET_PID ? (TARGET_AS100_SYNTAX ? "\n?:\tbra\t%0"
+                                            : "\n1:\tbra\t%0")
+                                            : "\n1:jmp\t%0";
   }
-  [(set_attr "cc" "clobber") ;; FIXME: This clobber is wrong.
-   (set_attr "timings" "33")
+  [(set_attr "timings" "33")
    (set_attr "length" "2")]
 )
 
+(define_expand "return"
+  [(return)]
+  ""
+  "rx_expand_epilogue (false); DONE;"
+)
+
 (define_insn "simple_return"
   [(return)]
   ""
    (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")))])]
+  [(match_parallel 1 "rx_rtsd_vector"
+     [(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))]
   ""
   "@
   jsr\t%0
 
     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))]
   ""
   "@
   jsr\t%1
   {
     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"
        (match_operand:register_modes 1 "general_operand"))]
   ""
   {
-    if (MEM_P (operand0) && MEM_P (operand1))
-      operands[1] = copy_to_mode_reg (<register_modes:MODE>mode, operand1);
+    if (MEM_P (operands[0]) && MEM_P (operands[1]))
+      operands[1] = copy_to_mode_reg (<register_modes:MODE>mode, operands[1]);
+    operands[0] = rx_maybe_pidify_operand (operands[0], 0);
+    operands[1] = rx_maybe_pidify_operand (operands[1], 0);
+    if (GET_CODE (operands[0]) != REG
+       && GET_CODE (operands[1]) == PLUS)
+      operands[1] = copy_to_mode_reg (<register_modes:MODE>mode, operands[1]);
+    if (GET_CODE (operands[1]) == PLUS && GET_MODE (operands[1]) == SImode)
+      {
+        emit_insn (gen_addsi3 (operands[0], XEXP (operands[1], 0), XEXP (operands[1], 1)));
+        DONE;
+      }
+    if (CONST_INT_P (operand1)
+        && ! rx_is_legitimate_constant (<register_modes:MODE>mode, operand1))
+      FAIL;
   }
 )
 
 (define_insn "*mov<register_modes:mode>_internal"
   [(set (match_operand:register_modes
-        0 "nonimmediate_operand" "=r,r,r,r,r,r,m,Q,Q,Q,Q")
+        0 "nonimmediate_operand" "=r,r,r,r,r,r,m,Q,Q,Q,Q,r")
        (match_operand:register_modes
-        1 "general_operand" "Int08,Sint16,Sint24,i,r,m,r,Int08,Sint16,Sint24,i"))]
+        1 "general_operand" "Int08,Sint16,Sint24,i,r,m,r,Int08,Sint16,Sint24,i,RpdaRpid"))]
   ""
   { return rx_gen_move_template (operands, false); }
-  [(set_attr "length" "3,4,5,6,2,4,6,5,6,7,8")
-   (set_attr "timings" "11,11,11,11,11,12,11,11,11,11,11")]
+  [(set_attr "length" "3,4,5,6,2,4,6,5,6,7,8,8")
+   (set_attr "timings" "11,11,11,11,11,12,11,11,11,11,11,11")]
 )
 
 (define_insn "extend<small_int_modes:mode>si2"
 )
 
 (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")))])]
+  [(match_parallel 1 "rx_store_multiple_vector"
+     [(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")))])]
+  [(match_parallel 1 "rx_load_multiple_vector"
+     [(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.
 )
 
-(define_insn "cstoresi4"
-  [(set (match_operand:SI  0 "register_operand" "=r,r,r,r,r,r,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")]))]
+(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")
+          (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 "cc" "set_zsoc")
-   (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"
-  [(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")))]
-  ""
-  {
-    if (GET_CODE (operands[1]) != EQ && GET_CODE (operands[1]) != NE)
-      FAIL;
-    if (! CONST_INT_P (operands[3]))
-      FAIL;
-  }
-)
+  [(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 "nonmemory_operand")))
+     (clobber (reg:CC CC_REG))])]
+  ""
+{
+  /* One operand must be a constant or a register, the other must be a register.  */
+  if (   ! CONSTANT_P (operands[2])
+      && ! CONSTANT_P (operands[3])
+      && ! (REG_P (operands[2]) && REG_P (operands[3])))
+    FAIL;
+})
 
-(define_insn "*movsieq"
+(define_insn_and_split "*movsicc"
   [(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")))]
-  ""
-  "@
-  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 "cc"      "set_zsoc")
-   (set_attr "length"  "13,19,15")
-   (set_attr "timings" "22,33,33")]
+       (if_then_else:SI
+         (match_operator     5 "comparison_operator"
+          [(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" "i,ri,r")
+         (match_operand:SI   2 "nonmemory_operand" "ri,i,r")))
+   (clobber (reg:CC CC_REG))]
+  "(CONSTANT_P (operands[1]) || CONSTANT_P (operands[2]))
+    || (REG_P (operands[1]) && REG_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.
+     Likewise if both operands are registers but OP1 == OP0.  */
+  if ((! CONSTANT_P (operands[1]) && CONSTANT_P (operands[2]))
+      || (REG_P (operands[1]) && REG_P (operands[2])
+          && rtx_equal_p (op0, op1)))
+    {
+      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
+   && ((GET_CODE (operands[2]) == EQ) || (GET_CODE (operands[2]) == NE))"
+  {
+    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 "*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")))]
-  ""
-  "@
-  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 "cc"      "set_zsoc")
-   (set_attr "length"  "13,19,15")
-   (set_attr "timings" "22,33,33")]
+(define_insn "*stcc_reg"
+  [(set (match_operand:SI 0 "register_operand" "+r,r,r,r,r,r")
+       (if_then_else:SI
+         (match_operator 2 "comparison_operator"
+           [(reg CC_REG) (const_int 0)])
+         (match_operand:SI 1 "nonmemory_operand"
+                             "r,Uint04,Sint08,Sint16,Sint24,i")
+         (match_dup 0)))]
+  "reload_completed"
+  {
+    PUT_CODE (operands[2], reverse_condition (GET_CODE (operands[2])));
+    return "b%B2 1f\n\tmov %1, %0\n1:";
+  }
+  [(set_attr "length" "3,3,4,5,6,7")]
 )
 
 ;; Arithmetic Instructions
 
 (define_insn "abssi2"
   [(set (match_operand:SI         0 "register_operand" "=r,r")
-        (abs:SI (match_operand:SI 1 "register_operand"  "0,r")))]
+        (abs:SI (match_operand:SI 1 "register_operand"  "0,r")))
+   (clobber (reg:CC CC_REG))]
   ""
   "@
   abs\t%0
   abs\t%1, %0"
-  [(set_attr "cc" "set_zso")
-   (set_attr "length" "2,3")]
+  [(set_attr "length" "2,3")]
+)
+
+(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_REG)
+       (compare (abs:SI (match_dup 1))
+                (const_int 0)))]
+  ;; Note - although the ABS instruction does set the O bit in the processor
+  ;; status word, it does not do so in a way that is comparable with the CMP
+  ;; instruction.  Hence we use CC_ZSmode rather than CC_ZSOmode.
+  "reload_completed && rx_match_ccmode (insn, CC_ZSmode)"
+  "@
+  abs\t%0
+  abs\t%1, %0"
+  [(set_attr "length" "2,3")]
+)
+
+(define_expand "addsi3"
+  [(parallel [(set (match_operand:SI          0 "register_operand"  "")
+       (plus:SI (match_operand:SI 1 "register_operand"  "")
+                (match_operand:SI 2 "rx_source_operand" "")))
+    (clobber (reg:CC CC_REG))])]
+  ""
+  "
+      operands[0] = rx_maybe_pidify_operand (operands[0], 1);
+      operands[1] = rx_maybe_pidify_operand (operands[1], 1);
+      operands[2] = rx_maybe_pidify_operand (operands[2], 1);
+  "
 )
 
-(define_insn "addsi3"
-  [(set (match_operand:SI 0 "register_operand"
-                         "=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,r,r,r,r,r,0")
-                (match_operand:SI
-                 2 "rx_source_operand"
-                 "r,Uint04,Sint08,Sint16,Sint24,i,r,Sint08,Sint16,Sint24,i,Q")))]
+(define_insn "addsi3_internal"
+  [(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")))
+   (clobber (reg:CC CC_REG))]
   ""
   "@
   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 "cc" "set_zsoc")
-   (set_attr "timings" "11,11,11,11,11,11,11,11,11,11,11,33")
-   (set_attr "length" "2,2,3,4,5,6,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_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")]
+)
+
+(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\t%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\t%2, %0"
+  [(set_attr "timings" "11,11,11,11,11,33")
+   (set_attr "length"   "3,4,5,6,7,6")]
+)
+
+;; Peepholes to match:
+;;   (set (reg A) (reg B))
+;;   (set (CC) (compare:CC (reg A/reg B) (const_int 0)))
+;; and replace them with the addsi3_flags pattern, using an add
+;; of zero to copy the register and set the condition code bits.
+(define_peephole2
+  [(set (match_operand:SI 0 "register_operand")
+        (match_operand:SI 1 "register_operand"))
+   (set (reg:CC CC_REG)
+        (compare:CC (match_dup 0)
+                    (const_int 0)))]
   ""
-  "add\t%L2, %L0\n\tadc\t%H2, %H0"
-  [(set_attr "cc" "set_zsoc")
-   (set_attr "timings" "22,22,22,22,22,44")
-   (set_attr "length" "5,7,9,11,13,11")]
+  [(parallel [(set (match_dup 0)
+                  (plus:SI (match_dup 1) (const_int 0)))
+             (set (reg:CC_ZSC CC_REG)
+                  (compare:CC_ZSC (plus:SI (match_dup 1) (const_int 0))
+                                  (const_int 0)))])]
 )
 
+(define_peephole2
+  [(set (match_operand:SI 0 "register_operand")
+        (match_operand:SI 1 "register_operand"))
+   (set (reg:CC CC_REG)
+        (compare:CC (match_dup 1)
+                    (const_int 0)))]
+  ""
+  [(parallel [(set (match_dup 0)
+                  (plus:SI (match_dup 1) (const_int 0)))
+             (set (reg:CC_ZSC CC_REG)
+                  (compare:CC_ZSC (plus:SI (match_dup 1) (const_int 0))
+                                  (const_int 0)))])]
+)
+
+(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,0,Q")
-               (match_operand:SI
-                2 "rx_source_operand"
-                "r,Uint04,Sint08,Sint16,Sint24,i,r,Q,0")))]
+       (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")))
+   (clobber (reg:CC CC_REG))]
   ""
   "@
   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,11,33")
+   (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
-  and\t%Q1, %0"
-  [(set_attr "cc" "set_zs")
-   (set_attr "timings" "11,11,11,11,11,11,11,33,33")
-   (set_attr "length" "2,2,3,4,5,6,3,5,5")]
+  and\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,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 "divsi3"
   [(set (match_operand:SI         0 "register_operand" "=r,r,r,r,r,r")
        (div: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")))]
+               (match_operand:SI 2 "rx_source_operand" "r,Sint08,Sint16,Sint24,i,Q")))
+   (clobber (reg:CC CC_REG))]
   ""
   "div\t%Q2, %0"
-  [(set_attr "cc" "clobber")
-   (set_attr "timings" "1111") ;; Strictly speaking the timing should be
+  [(set_attr "timings" "1111") ;; Strictly speaking the timing should be
                                ;; 2222, but that is a worst case sceanario.
    (set_attr "length" "3,4,5,6,7,6")]
 )
 (define_insn "udivsi3"
   [(set (match_operand:SI          0 "register_operand"  "=r,r,r,r,r,r")
        (udiv: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")))]
+                (match_operand:SI 2 "rx_source_operand"  "r,Sint08,Sint16,Sint24,i,Q")))
+   (clobber (reg:CC CC_REG))]
   ""
   "divu\t%Q2, %0"
-  [(set_attr "cc" "clobber")
-   (set_attr "timings" "1010") ;; Strictly speaking the timing should be
+  [(set_attr "timings" "1010") ;; Strictly speaking the timing should be
                                ;; 2020, but that is a worst case sceanario.
    (set_attr "length" "3,4,5,6,7,6")]
 )
                                  2 "rx_source_operand"
                                  "r,Sint08,Sint16,Sint24,i,Q"))))]
   "! TARGET_BIG_ENDIAN_DATA"
-  "@
-  emul\t%Q2, %0
-  emul\t%Q2, %0
-  emul\t%Q2, %0
-  emul\t%Q2, %0
-  emul\t%Q2, %0
-  emul\t%Q2, %0"
+  "emul\t%Q2, %0"
   [(set_attr "length" "3,4,5,6,7,6")   
    (set_attr "timings" "22,22,22,22,22,44")]
 )
 ;; mulsidi3 pattern.  Immediate mode addressing is not supported
 ;; because gcc cannot handle the expression: (zero_extend (const_int)).
 (define_insn "umulsidi3"
-  [(set (match_operand:DI                          0 "register_operand"
-                                                  "=r,r")
-        (mult:DI (zero_extend:DI (match_operand:SI 1 "register_operand"
-                                                  "%0,0"))
-                 (zero_extend:DI (match_operand:SI 2 "rx_compare_operand"
-                                                  "r,Q"))))]
+  [(set (match_operand:DI                          0 "register_operand"         "=r,r")
+        (mult:DI (zero_extend:DI (match_operand:SI 1 "register_operand"  "%0,0"))
+                 (zero_extend:DI (match_operand:SI 2 "rx_compare_operand" "r,Q"))))]
   "! TARGET_BIG_ENDIAN_DATA"
-  "@
-  emulu\t%Q2, %0
-  emulu\t%Q2, %0"
+  "emulu\t%Q2, %0"
   [(set_attr "length" "3,6")
    (set_attr "timings" "22,44")]
 )
                 (match_operand:SI 2 "rx_source_operand"
                                   "r,Sint08,Sint16,Sint24,i,Q")))]
   ""
-  "@
-  min\t%Q2, %0
-  min\t%Q2, %0
-  min\t%Q2, %0
-  min\t%Q2, %0
-  min\t%Q2, %0
-  min\t%Q2, %0"
+  "min\t%Q2, %0"
+  [(set_attr "length"  "3,4,5,6,7,6")
+   (set_attr "timings" "11,11,11,11,11,33")]
+)
+
+(define_insn "umax<small_int_modes:mode>3_u"
+  [(set (match_operand:SI          0 "register_operand" "=r,r,r,r,r,r")
+       (smax:SI (match_operand:SI 1 "register_operand" "%0,0,0,0,0,0")
+                (zero_extend:SI (match_operand:small_int_modes 2 "rx_minmaxex_operand"
+                                                               "r,Sint08,Sint16,Sint24,i,Q"))))]
+  ""
+  "max\t%R2, %0"
+  [(set_attr "length"  "3,4,5,6,7,6")
+   (set_attr "timings" "11,11,11,11,11,33")]
+)
+
+(define_insn "umin<small_int_modes:mode>3_ur"
+  [(set (match_operand:SI          0 "register_operand" "=r,r,r,r,r,r")
+       (smin:SI (zero_extend:SI (match_operand:small_int_modes 2 "rx_minmaxex_operand"
+                                                               "r,Sint08,Sint16,Sint24,i,Q"))
+                (match_operand:SI 1 "register_operand" "%0,0,0,0,0,0")))]
+  ""
+  "min\t%R2, %0"
   [(set_attr "length"  "3,4,5,6,7,6")
    (set_attr "timings" "11,11,11,11,11,33")]
 )
 
+(define_insn "umax<small_int_modes:mode>3_ur"
+  [(set (match_operand:SI          0 "register_operand" "=r,r,r,r,r,r")
+       (smax:SI (zero_extend:SI (match_operand:small_int_modes 2 "rx_minmaxex_operand"
+                                                               "r,Sint08,Sint16,Sint24,i,Q"))
+                (match_operand:SI 1 "register_operand" "%0,0,0,0,0,0")))]
+  ""
+  "max\t%R2, %0"
+  [(set_attr "length"  "3,4,5,6,7,6")
+   (set_attr "timings" "11,11,11,11,11,33")]
+)
+
+(define_expand "umax<small_int_modes:mode>3"
+  [(set (match_dup 4)
+       (zero_extend:SI (match_operand:small_int_modes 1 "register_operand" "%0,0,0,0,0,0")))
+   (set (match_dup 3)
+       (smax:SI (match_dup 4)
+                (match_operand:small_int_modes 2 "rx_source_operand"
+                                               "r,Sint08,Sint16,Sint24,i,Q")))
+   (set (match_operand:small_int_modes          0 "register_operand" "=r,r,r,r,r,r")
+       (match_dup 6))
+   ]
+  ""
+  "operands[3] = gen_reg_rtx (SImode);
+   operands[4] = gen_reg_rtx (SImode);
+   operands[5] = gen_reg_rtx (SImode);
+   operands[6] = gen_rtx_SUBREG (GET_MODE (operands[0]), operands[3],
+     TARGET_BIG_ENDIAN_DATA ? (GET_MODE (operands[0]) == HImode ? 2 : 3) : 0);
+   if (GET_CODE (operands[2]) != CONST_INT)
+     {
+       emit_move_insn (operands[5], gen_rtx_ZERO_EXTEND (SImode, operands[2]));
+       operands[2] = operands[5];
+     }
+  "
+)
+
+(define_expand "umin<small_int_modes:mode>3"
+  [(set (match_dup 4)
+       (zero_extend:SI (match_operand:small_int_modes 1 "register_operand" "%0,0,0,0,0,0")))
+   (set (match_dup 3)
+       (smin:SI (match_dup 4)
+                (match_operand:small_int_modes 2 "rx_source_operand"
+                                               "r,Sint08,Sint16,Sint24,i,Q")))
+   (set (match_operand:small_int_modes          0 "register_operand" "=r,r,r,r,r,r")
+       (match_dup 6))
+   ]
+  ""
+  "operands[3] = gen_reg_rtx (SImode);
+   operands[4] = gen_reg_rtx (SImode);
+   operands[5] = gen_reg_rtx (SImode);
+   operands[6] = gen_rtx_SUBREG (GET_MODE (operands[0]), operands[3],
+     TARGET_BIG_ENDIAN_DATA ? (GET_MODE (operands[0]) == HImode ? 2 : 3) : 0);
+   if (GET_CODE (operands[2]) != CONST_INT)
+     {
+       emit_move_insn (operands[5], gen_rtx_ZERO_EXTEND (SImode, operands[2]));
+       operands[2] = operands[5];
+     }
+   "
+)
+
 (define_insn "mulsi3"
   [(set (match_operand:SI          0 "register_operand" "=r,r,r,r,r,r,r,r,r")
-        (mult:SI (match_operand:SI 1 "register_operand" "%0,0,0,0,0,0,0,Q,r")
+        (mult:SI (match_operand:SI 1 "register_operand" "%0,0,0,0,0,0,0,r,r")
                  (match_operand:SI 2 "rx_source_operand"
                                   "r,Uint04,Sint08,Sint16,Sint24,i,Q,0,r")))]
   ""
   "@
+  mul\t%2, %0
+  mul\t%2, %0
+  mul\t%2, %0
+  mul\t%2, %0
+  mul\t%2, %0
   mul\t%Q2, %0
   mul\t%Q2, %0
-  mul\t%Q2, %0
-  mul\t%Q2, %0
-  mul\t%Q2, %0
-  mul\t%Q2, %0
-  mul\t%Q2, %0
-  mul\t%Q1, %0
-  mul\t%Q2, %1, %0"
-  [(set_attr "length"  "2,2,3,4,5,6,5,5,3")
-   (set_attr "timings" "11,11,11,11,11,11,33,33,11")]
+  mul\t%1, %0
+  mul\t%2, %1, %0"
+  [(set_attr "length"  "2,2,3,4,5,6,5,2,3")
+   (set_attr "timings" "11,11,11,11,11,11,33,11,11")]
 )
 
 (define_insn "negsi2"
   [(set (match_operand:SI         0 "register_operand" "=r,r")
-        (neg:SI (match_operand:SI 1 "register_operand"  "0,r")))]
-  ;; The NEG instruction does not comply with -fwrapv semantics.
-  ;; See gcc.c-torture/execute/pr22493-1.c for an example of this.
-  "! flag_wrapv"
+        (neg:SI (match_operand:SI 1 "register_operand"  "0,r")))
+   (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")))]
+       (not:SI (match_operand:SI 1 "register_operand"  "0,r")))
+   (clobber (reg:CC CC_REG))]
   ""
   "@
   not\t%0
   not\t%1, %0"
-  [(set_attr "cc" "set_zs")
-   (set_attr "length" "2,3")]
+  [(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,0,Q")
-               (match_operand:SI 2 "rx_source_operand"
-                                 "r,Uint04,Sint08,Sint16,Sint24,i,r,Q,0")))]
+       (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")))
+   (clobber (reg:CC CC_REG))]
   ""
   "@
   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 "*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%Q1, %0"
-  [(set_attr "cc" "set_zs")
-   (set_attr "timings" "11,11,11,11,11,11,11,33,33")
-   (set_attr "length"  "2,2,3,4,5,6,3,5,5")]
+  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")))]
+                  (match_operand:SI 2 "rx_shift_operand" "rn")))
+   (clobber (reg:CC CC_REG))]
   ""
   "rotl\t%2, %0"
-  [(set_attr "cc" "set_zs")
-   (set_attr "length" "3")]
+  [(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")))]
+                    (match_operand:SI 2 "rx_shift_operand" "rn")))
+   (clobber (reg:CC CC_REG))]
   ""
   "rotr\t%2, %0"
-  [(set_attr "cc" "set_zs")
-   (set_attr "length" "3")]
+  [(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")))]
+                    (match_operand:SI 2 "rx_shift_operand"  "r,n,n")))
+   (clobber (reg:CC CC_REG))]
   ""
   "@
   shar\t%2, %0
   shar\t%2, %0
   shar\t%2, %1, %0"
-  [(set_attr "cc" "set_zsoc")
-   (set_attr "length" "3,2,3")]
+  [(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")))]
+                    (match_operand:SI 2 "rx_shift_operand"  "r,n,n")))
+   (clobber (reg:CC CC_REG))]
   ""
   "@
   shlr\t%2, %0
   shlr\t%2, %0
   shlr\t%2, %1, %0"
-  [(set_attr "cc" "set_zsoc")
-   (set_attr "length" "3,2,3")]
+  [(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")))]
+                  (match_operand:SI 2 "rx_shift_operand"  "r,n,n")))
+   (clobber (reg:CC CC_REG))]
   ""
   "@
   shll\t%2, %0
   shll\t%2, %0
   shll\t%2, %1, %0"
-  [(set_attr "cc" "set_zsoc")
-   (set_attr "length" "3,2,3")]
+  [(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")))]
+                 (match_operand:SI 2 "rx_source_operand" "r,Uint04,n,r,Q")))
+   (clobber (reg:CC CC_REG))]
   ""
   "@
   sub\t%2, %0
   add\t%N2, %0
   sub\t%2, %1, %0
   sub\t%Q2, %0"
-  [(set_attr "cc" "set_zsoc")
-   (set_attr "timings" "11,11,11,11,33")
+  [(set_attr "timings" "11,11,11,11,33")
    (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")))]
-  ""
-  "sub\t%L2, %L0\n\tsbb\t%H2, %H0"
-  [(set_attr "cc" "set_zsoc")
-   (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")))]
+                                 "r,Sint08,Sint16,Sint24,i,Q")))
+   (clobber (reg:CC CC_REG))]
   ""
-  "@
-  xor\t%Q2, %0
-  xor\t%Q2, %0
-  xor\t%Q2, %0
-  xor\t%Q2, %0
-  xor\t%Q2, %0
-  xor\t%Q2, %0"
-  [(set_attr "cc" "set_zs")
-   (set_attr "timings" "11,11,11,11,11,33")
+  "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
+;; A set of peepholes to catch extending loads followed by arithmetic operations.
+;; We use iterators where possible to reduce the amount of typing and hence the
+;; possibilities for typos.
+
+(define_code_iterator extend_types [(zero_extend "") (sign_extend "")])
+(define_code_attr     letter       [(zero_extend "R") (sign_extend "Q")])
+
+(define_code_iterator memex_commutative [(plus "") (and "") (ior "") (xor "")])
+(define_code_iterator memex_noncomm     [(div "") (udiv "") (minus "")])
+(define_code_iterator memex_nocc        [(smax "") (smin "") (mult "")])
+
+(define_code_attr     op                [(plus "add") (and "and") (div "div") (udiv "divu") (smax "max") (smin "min") (mult "mul") (ior "or") (minus "sub") (xor "xor")])
+
+(define_peephole2
+  [(set (match_operand:SI                               0 "register_operand")
+       (extend_types:SI (match_operand:small_int_modes 1 "rx_restricted_mem_operand")))
+   (parallel [(set (match_operand:SI                    2 "register_operand")
+                  (memex_commutative:SI (match_dup 0)
+                                        (match_dup 2)))
+             (clobber (reg:CC CC_REG))])]
+  "peep2_regno_dead_p (2, REGNO (operands[0])) && (optimize < 3 || optimize_size)"
+  [(parallel [(set:SI (match_dup 2)
+                     (memex_commutative:SI (match_dup 2)
+                                           (extend_types:SI (match_dup 1))))
+             (clobber (reg:CC CC_REG))])]
+)
+
+(define_peephole2
+  [(set (match_operand:SI                               0 "register_operand")
+       (extend_types:SI (match_operand:small_int_modes 1 "rx_restricted_mem_operand")))
+   (parallel [(set (match_operand:SI                    2 "register_operand")
+                  (memex_commutative:SI (match_dup 2)
+                                        (match_dup 0)))
+             (clobber (reg:CC CC_REG))])]
+  "peep2_regno_dead_p (2, REGNO (operands[0])) && (optimize < 3 || optimize_size)"
+  [(parallel [(set:SI (match_dup 2)
+                     (memex_commutative:SI (match_dup 2)
+                                           (extend_types:SI (match_dup 1))))
+             (clobber (reg:CC CC_REG))])]
+)
+
+(define_peephole2
+  [(set (match_operand:SI                               0 "register_operand")
+       (extend_types:SI (match_operand:small_int_modes 1 "rx_restricted_mem_operand")))
+   (parallel [(set (match_operand:SI                    2 "register_operand")
+                  (memex_noncomm:SI (match_dup 2)
+                                    (match_dup 0)))
+             (clobber (reg:CC CC_REG))])]
+  "peep2_regno_dead_p (2, REGNO (operands[0])) && (optimize < 3 || optimize_size)"
+  [(parallel [(set:SI (match_dup 2)
+                     (memex_noncomm:SI (match_dup 2)
+                                       (extend_types:SI (match_dup 1))))
+             (clobber (reg:CC CC_REG))])]
+)
+
+(define_peephole2
+  [(set (match_operand:SI                               0 "register_operand")
+       (extend_types:SI (match_operand:small_int_modes 1 "rx_restricted_mem_operand")))
+   (set (match_operand:SI                               2 "register_operand")
+       (memex_nocc:SI (match_dup 0)
+                      (match_dup 2)))]
+  "peep2_regno_dead_p (2, REGNO (operands[0])) && (optimize < 3 || optimize_size)"
+  [(set:SI (match_dup 2)
+          (memex_nocc:SI (match_dup 2)
+                         (extend_types:SI (match_dup 1))))]
+)
+
+(define_peephole2
+  [(set (match_operand:SI                               0 "register_operand")
+       (extend_types:SI (match_operand:small_int_modes 1 "rx_restricted_mem_operand")))
+   (set (match_operand:SI                               2 "register_operand")
+       (memex_nocc:SI (match_dup 2)
+                      (match_dup 0)))]
+  "peep2_regno_dead_p (2, REGNO (operands[0])) && (optimize < 3 || optimize_size)"
+  [(set:SI (match_dup 2)
+          (memex_nocc:SI (match_dup 2)
+                         (extend_types:SI (match_dup 1))))]
+)
+
+(define_insn "<memex_commutative:code>si3_<extend_types:code><small_int_modes:mode>"
+  [(set (match_operand:SI                                                     0 "register_operand" "=r")
+       (memex_commutative:SI (match_operand:SI                               1 "register_operand" "%0")
+                             (extend_types:SI (match_operand:small_int_modes 2 "rx_restricted_mem_operand" "Q"))))
+   (clobber (reg:CC CC_REG))]
+  "(optimize < 3 || optimize_size)"
+  "<memex_commutative:op>\t%<extend_types:letter>2, %0"
+  [(set_attr "timings" "33")
+   (set_attr "length"  "5")] ;; This length is corrected in rx_adjust_insn_length
+)
+
+(define_insn "<memex_noncomm:code>si3_<extend_types:code><small_int_modes:mode>"
+  [(set (match_operand:SI                                                 0 "register_operand" "=r")
+       (memex_noncomm:SI (match_operand:SI                               1 "register_operand" "0")
+                          (extend_types:SI (match_operand:small_int_modes 2 "rx_restricted_mem_operand" "Q"))))
+   (clobber (reg:CC CC_REG))]
+  "(optimize < 3 || optimize_size)"
+  "<memex_noncomm:op>\t%<extend_types:letter>2, %0"
+  [(set_attr "timings" "33")
+   (set_attr "length"  "5")] ;; This length is corrected in rx_adjust_insn_length
+)
+
+(define_insn "<memex_nocc:code>si3_<extend_types:code><small_int_modes:mode>"
+  [(set (match_operand:SI                                              0 "register_operand" "=r")
+       (memex_nocc:SI (match_operand:SI                               1 "register_operand" "%0")
+                      (extend_types:SI (match_operand:small_int_modes 2 "rx_restricted_mem_operand" "Q"))))]
+  "(optimize < 3 || optimize_size)"
+  "<memex_nocc:op>\t%<extend_types:letter>2, %0"
+  [(set_attr "timings" "33")
+   (set_attr "length"  "5")] ;; This length is corrected in rx_adjust_insn_length
+)
+
+(define_peephole2
+  [(set (match_operand:SI                               0 "register_operand")
+       (extend_types:SI (match_operand:small_int_modes 1 "rx_restricted_mem_operand")))
+   (set (reg:CC CC_REG)
+       (compare:CC (match_operand:SI                   2 "register_operand")
+                   (match_dup 0)))]
+  "peep2_regno_dead_p (2, REGNO (operands[0])) && (optimize < 3 || optimize_size)"
+  [(set (reg:CC CC_REG)
+       (compare:CC (match_dup 2)
+                   (extend_types:SI (match_dup 1))))]
+)
+
+;; Convert:
+;;   (set (reg1) (sign_extend (mem))
+;;   (set (reg2) (zero_extend (reg1))
+;; into
+;;   (set (reg2) (zero_extend (mem)))
+(define_peephole2
+  [(set (match_operand:SI                              0 "register_operand")
+       (sign_extend:SI (match_operand:small_int_modes 1 "memory_operand")))
+   (set (match_operand:SI                              2 "register_operand")
+       (zero_extend:SI (match_operand:small_int_modes 3 "register_operand")))]
+  "REGNO (operands[0]) == REGNO (operands[3])
+   && (REGNO (operands[0]) == REGNO (operands[2])
+       || peep2_regno_dead_p (2, REGNO (operands[0])))"
+  [(set (match_dup 2)
+       (zero_extend:SI (match_dup 1)))]
+)
+
+;; Remove the redundant sign extension from:
+;;   (set (reg) (extend (mem)))
+;;   (set (reg) (extend (reg)))
+(define_peephole2
+  [(set (match_operand:SI                               0 "register_operand")
+       (extend_types:SI (match_operand:small_int_modes 1 "memory_operand")))
+   (set (match_dup 0)
+       (extend_types:SI (match_operand:small_int_modes 2 "register_operand")))]
+  "REGNO (operands[0]) == REGNO (operands[2])"
+  [(set (match_dup 0) (extend_types:SI (match_dup 1)))]
+)
+
+(define_insn "comparesi3_<extend_types:code><small_int_modes:mode>"
+  [(set (reg:CC CC_REG)
+       (compare:CC (match_operand:SI                               0 "register_operand" "=r")
+                   (extend_types:SI (match_operand:small_int_modes 1 "rx_restricted_mem_operand" "Q"))))]
+  "(optimize < 3 || optimize_size)"
+  "cmp\t%<extend_types:letter>1, %0"
+  [(set_attr "timings" "33")
+   (set_attr "length"  "5")] ;; This length is corrected in rx_adjust_insn_length
+)
+\f
 ;; Floating Point Instructions
 
 (define_insn "addsf3"
   [(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")))]
+                (match_operand:SF 2 "rx_source_operand"  "r,F,Q")))
+   (clobber (reg:CC CC_REG))]
   "ALLOW_RX_FPU_INSNS"
-  "@
-  fadd\t%2, %0
-  fadd\t%2, %0
-  fadd\t%2, %0"
-  [(set_attr "cc" "set_zs")
-   (set_attr "timings" "44,44,66")
+  "fadd\t%2, %0"
+  [(set_attr "timings" "44,44,66")
    (set_attr "length" "3,7,5")]
 )
 
 (define_insn "divsf3"
   [(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")))]
+               (match_operand:SF 2 "rx_source_operand" "r,F,Q")))
+   (clobber (reg:CC CC_REG))]
   "ALLOW_RX_FPU_INSNS"
   "fdiv\t%2, %0"
-  [(set_attr "cc" "set_zs")
-   (set_attr "timings" "1616,1616,1818")
+  [(set_attr "timings" "1616,1616,1818")
    (set_attr "length" "3,7,5")]
 )
 
 (define_insn "mulsf3"
   [(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")))]
+               (match_operand:SF  2 "rx_source_operand" "r,F,Q")))
+   (clobber (reg:CC CC_REG))]
   "ALLOW_RX_FPU_INSNS"
-  "@
-  fmul\t%2, %0
-  fmul\t%2, %0
-  fmul\t%2, %0"
-  [(set_attr "cc" "set_zs")
-   (set_attr "timings" "33,33,55")
+  "fmul\t%2, %0"
+  [(set_attr "timings" "33,33,55")
    (set_attr "length"  "3,7,5")]
 )
 
 (define_insn "subsf3"
   [(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")))]
+                 (match_operand:SF 2 "rx_source_operand" "r,F,Q")))
+   (clobber (reg:CC CC_REG))]
   "ALLOW_RX_FPU_INSNS"
-  "fsub\t%2, %0"
-  [(set_attr "cc" "set_zs")
-   (set_attr "timings" "44,44,66")
+  "fsub\t%Q2, %0"
+  [(set_attr "timings" "44,44,66")
    (set_attr "length" "3,7,5")]
 )
 
 (define_insn "fix_truncsfsi2"
   [(set (match_operand:SI         0 "register_operand"  "=r,r")
-       (fix:SI (match_operand:SF 1 "rx_compare_operand" "r,Q")))]
+       (fix:SI (match_operand:SF 1 "rx_compare_operand" "r,Q")))
+   (clobber (reg:CC CC_REG))]
   "ALLOW_RX_FPU_INSNS"
-  "ftoi\t%1, %0"
-  [(set_attr "cc" "set_zs")
-   (set_attr "timings" "22,44")
+  "ftoi\t%Q1, %0"
+  [(set_attr "timings" "22,44")
    (set_attr "length" "3,5")]
 )
 
 (define_insn "floatsisf2"
   [(set (match_operand:SF           0 "register_operand"  "=r,r")
-       (float:SF (match_operand:SI 1 "rx_compare_operand" "r,Q")))]
+       (float:SF (match_operand:SI 1 "rx_compare_operand" "r,Q")))
+   (clobber (reg:CC CC_REG))]
   "ALLOW_RX_FPU_INSNS"
-  "itof\t%1, %0"
-  [(set_attr "cc" "set_zs")
-   (set_attr "timings" "22,44")
+  "itof\t%Q1, %0"
+  [(set_attr "timings" "22,44")
    (set_attr "length" "3,6")]
 )
 \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 "rx_restricted_mem_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_attr "timings" "33")]
 )
 
-;; (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 "rx_restricted_mem_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")))]
   ""
+  "bclr\t%1, %0"
+  [(set_attr "length" "3")]
 )
-  
-;; (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_in_memory"
+  [(set (match_operand:QI 0 "rx_restricted_mem_operand" "+Q")
+       (and:QI (not:QI
+                 (ashift:QI
+                   (const_int 1)
+                   (match_operand:QI 1 "nonmemory_operand" "ri")))
+               (match_dup 0)))]
   ""
+  "bclr\t%1, %0.B"
+  [(set_attr "length" "3")
+   (set_attr "timings" "33")]
 )
 
-(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")))))]
+(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" ""))]
   ""
-  "bclr\t%2, %0"
+{
+  if (INTVAL (operands[2]) & 1)
+    return "bset\t%1, %0";
+  else
+    return "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_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))]
   ""
-  "bclr\t%2, %0.B"
-  [(set_attr "length" "3")
-   (set_attr "timings" "34")]
+  "#"
+  "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")]
 )
 
-;; (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)))))]
-)
-  
-;; (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)))))]
+;; 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))]
+  ""
+  "#"
+  ""
+  [(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: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
-  ""
-  {
-    if (rx_expand_insv (operands))
+  [(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))
-   (clobber (reg:SI 3))
-  ]
+   (clobber (reg:SI 3))]
   ""
   "smovu"
   [(set_attr "length" "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))
    (clobber (reg:SI 3))
-  ]
+   (clobber (reg:CC CC_REG))
+   ]
   ""
   "mov\t%1, r1\n\tmov\t#0, r2\n\tsuntil.b\n\tmov\tr1, %0\n\tsub\t#1, %0"
   [(set_attr "length" "10")
-   (set_attr "cc" "clobber")
    (set_attr "timings" "1111")] ;; The timing is a guesstimate.
 )
 
     rtx addr2 = gen_rtx_REG (SImode, 2);
     rtx len   = gen_rtx_REG (SImode, 3);
 
+    /* Do not use when the source or destination are volatile - the SMOVF
+       instruction will read and write in word sized blocks, which may be
+       outside of the valid address range.  */
+    if (MEM_P (operands[0]) && MEM_VOLATILE_P (operands[0]))
+      FAIL;
+    if (MEM_P (operands[1]) && MEM_VOLATILE_P (operands[1]))
+      FAIL;
+
     if (REG_P (operands[0]) && (REGNO (operands[0]) == 2
                                      || REGNO (operands[0]) == 3))
       FAIL;
     if (REG_P (operands[2]) && (REGNO (operands[2]) == 1
                                      || REGNO (operands[2]) == 2))
       FAIL;
+
     emit_move_insn (addr1, force_operand (XEXP (operands[0], 0), NULL_RTX));
     emit_move_insn (addr2, force_operand (XEXP (operands[1], 0), NULL_RTX));
     emit_move_insn (len, force_operand (operands[2], NULL_RTX));
 )
 
 (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_expand "cmpstrnsi"
-  [(set (match_operand:SI
-        0 "register_operand") ;; Result
-       (unspec_volatile:SI [(match_operand:BLK
-                             1 "memory_operand") ;; String1
-                            (match_operand:BLK
-                             2 "memory_operand")] ;; String2
+  [(set (match_operand:SI                       0 "register_operand")   ;; Result
+       (unspec_volatile:SI [(match_operand:BLK 1 "memory_operand")     ;; String1
+                            (match_operand:BLK 2 "memory_operand")]    ;; String2
                            UNSPEC_CMPSTRN))
-   (use (match_operand:SI
-        3 "register_operand")) ;; Max Length
-   (match_operand:SI
-    4 "immediate_operand")] ;; Known Align
+   (use (match_operand:SI                       3 "register_operand"))  ;; Max Length
+   (match_operand:SI                            4 "immediate_operand")] ;; Known Align
   ""
   {
     rtx str1 = gen_rtx_REG (SImode, 1);
 )
 
 (define_expand "cmpstrsi"
-  [(set (match_operand:SI
-        0 "register_operand") ;; Result
-       (unspec_volatile:SI [(match_operand:BLK
-                             1 "memory_operand")  ;; String1
-                            (match_operand:BLK
-                             2 "memory_operand")] ;; String2
+  [(set (match_operand:SI                       0 "register_operand")   ;; Result
+       (unspec_volatile:SI [(match_operand:BLK 1 "memory_operand")     ;; String1
+                            (match_operand:BLK 2 "memory_operand")]    ;; String2
                            UNSPEC_CMPSTRN))
-   (match_operand:SI
-    3 "immediate_operand")] ;; Known Align
+   (match_operand:SI                            3 "immediate_operand")] ;; Known Align
   ""
   {
     rtx str1 = gen_rtx_REG (SImode, 1);
 )
 
 (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))]
+   (clobber (reg:SI 3))
+   (clobber (reg:CC CC_REG))]
   ""
   "scmpu               ; Perform the string comparison
    mov     #-1, %0      ; Set up -1 result (which cannot be created
 
 ;; 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))]
   ""
 (define_insn "lrintsf2"
   [(set (match_operand:SI             0 "register_operand"  "=r,r")
        (unspec:SI [(match_operand:SF 1 "rx_compare_operand" "r,Q")]
-                  UNSPEC_BUILTIN_ROUND))]
+                  UNSPEC_BUILTIN_ROUND))
+   (clobber (reg:CC CC_REG))]
   ""
   "round\t%1, %0"
-  [(set_attr "cc" "set_zs")
-   (set_attr "timings" "22,44")   
+  [(set_attr "timings" "22,44")   
    (set_attr "length" "3,5")]
 )
 
-;; Saturate to 32-bits
-(define_insn "sat"
-  [(set (match_operand:SI             0 "register_operand" "=r")
-       (unspec:SI [(match_operand:SI 1 "register_operand"  "0")]
-                  UNSPEC_BUILTIN_SAT))]
-  ""
-  "sat\t%0"
-  [(set_attr "length" "2")]
-)
-
 ;;---------- Control Registers ------------------------
 
 ;; Clear Processor Status Word
 (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 (cc0))]
+   (clobber (reg:CC CC_REG))]
   ""
   "clrpsw\t%F0"
-  [(set_attr "length" "2")
-   (set_attr "cc" "clobber")]
+  [(set_attr "length" "2")]
 )
 
 ;; 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 (cc0))]
+   (clobber (reg:CC CC_REG))]
   ""
   "setpsw\t%F0"
-  [(set_attr "length" "2")
-   (set_attr "cc" "clobber")]
+  [(set_attr "length" "2")]
 )
 
 ;; 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"
   "nop"
   [(set_attr "length" "1")]
 )
+
+(define_expand "pid_addr"
+  [(plus:SI (match_operand:SI 0)
+           (const:SI (unspec:SI [(match_operand:SI 1)] UNSPEC_PID_ADDR)))]
+  ""
+  ""
+)