OSDN Git Service

* config/rx/rx.md (return): Define pattern.
[pf3gnuchains/gcc-fork.git] / gcc / config / rx / rx.md
index c2161a2..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.
@@ -22,6 +22,9 @@
 ;; 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)
@@ -50,6 +43,7 @@
    (UNSPEC_RTE             10)
    (UNSPEC_RTFI            11)
    (UNSPEC_NAKED           12)
+   (UNSPEC_CONST           13)
    
    (UNSPEC_MOVSTR          20)
    (UNSPEC_MOVMEM          21)
@@ -79,6 +73,8 @@
    (UNSPEC_BUILTIN_SAT     49)
    (UNSPEC_BUILTIN_SETPSW  50)
    (UNSPEC_BUILTIN_WAIT           51)
+
+   (UNSPEC_PID_ADDR       52)
   ]
 )
 
 (define_expand "cbranchsf4"
   [(set (pc)
        (if_then_else
-         (match_operator 0 "comparison_operator"
+         (match_operator 0 "rx_fp_comparison_operator"
            [(match_operand:SF 1 "register_operand")
-            (match_operand:SF 2 "register_operand")])
-          (label_ref (match_operand 3 ""))
+            (match_operand:SF 2 "rx_source_operand")])
+         (label_ref (match_operand 3 ""))
          (pc)))]
   "ALLOW_RX_FPU_INSNS"
-{
-  enum rtx_code cmp1, cmp2;
-
-  /* If the comparison needs swapping of operands, do that now.
-     Do not split the comparison in two yet.  */
-  if (rx_split_fp_compare (GET_CODE (operands[0]), &cmp1, &cmp2))
-    {
-      rtx op1, op2;
-
-      if (cmp2 != UNKNOWN)
-       {
-         gcc_assert (cmp1 == UNORDERED);
-         if (cmp2 == GT)
-           cmp1 = UNGT;
-         else if (cmp2 == LE)
-           cmp1 = UNLE;
-         else
-           gcc_unreachable ();
-       }
-
-      op1 = operands[2];
-      op2 = operands[1];
-      operands[0] = gen_rtx_fmt_ee (cmp1, VOIDmode, op1, op2);
-      operands[1] = op1;
-      operands[2] = op2;
-    }
-})
+)
 
 (define_insn_and_split "*cbranchsf4"
   [(set (pc)
        (if_then_else
          (match_operator 3 "rx_fp_comparison_operator"
            [(match_operand:SF  0 "register_operand"  "r")
-            (match_operand:SF  1 "rx_source_operand" "rFiQ")])
+            (match_operand:SF  1 "rx_source_operand" "rFQ")])
          (match_operand        2 "label_ref_operand" "")
          (pc)))]
   "ALLOW_RX_FPU_INSNS"
   "&& reload_completed"
   [(const_int 0)]
 {
-  enum rtx_code cmp0, cmp1, cmp2;
-  rtx flags, lab1, lab2, over, x;
-  bool swap;
-
-  cmp0 = GET_CODE (operands[3]);
-  swap = rx_split_fp_compare (cmp0, &cmp1, &cmp2);
-  gcc_assert (!swap);
-
-  flags = gen_rtx_REG (CC_Fmode, CC_REG);
-  x = gen_rtx_COMPARE (CC_Fmode, operands[0], operands[1]);
-  x = gen_rtx_SET (VOIDmode, flags, x);
-  emit_insn (x);
-
-  over = NULL;
-  lab1 = lab2 = operands[2];
-
-  /* The one case of LTGT needs to be split into cmp1 && cmp2.  */
-  if (cmp0 == LTGT)
-    {
-      over = gen_label_rtx ();
-      lab1 = gen_rtx_LABEL_REF (VOIDmode, over);
-      cmp1 = reverse_condition_maybe_unordered (cmp1);
-    }
-
-  /* Otherwise we split into cmp1 || cmp2.  */
-  x = gen_rtx_fmt_ee (cmp1, VOIDmode, flags, const0_rtx);
-  x = gen_rtx_IF_THEN_ELSE (VOIDmode, x, lab1, pc_rtx);
-  x = gen_rtx_SET (VOIDmode, pc_rtx, x);
-  emit_jump_insn (x);
-
-  if (cmp2 != UNKNOWN)
-    {
-      x = gen_rtx_fmt_ee (cmp2, VOIDmode, flags, const0_rtx);
-      x = gen_rtx_IF_THEN_ELSE (VOIDmode, x, lab2, pc_rtx);
-      x = gen_rtx_SET (VOIDmode, pc_rtx, x);
-      emit_jump_insn (x);
-    }
-
-  if (over)
-    emit_label (over);
+  rx_split_cbranch (CC_Fmode, GET_CODE (operands[3]),
+                   operands[0], operands[1], operands[2]);
   DONE;
 })
 
   [(set (reg:CC_F CC_REG)
        (compare:CC_F
          (match_operand:SF 0 "register_operand"  "r,r,r")
-         (match_operand:SF 1 "rx_source_operand" "r,iF,Q")))]
+         (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")
            [(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.
        (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 "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")))])]
+     [(set (reg:SI SP_REG)
+          (plus:SI (reg:SI SP_REG)
+                   (match_operand:SI 0 "const_int_operand" "n")))])
+   (return)]
   "reload_completed"
   {
     rx_emit_stack_popm (operands, false);
 
     if (! rx_call_operand (dest, Pmode))
       dest = force_reg (Pmode, dest);
-    emit_call_insn (gen_call_internal (dest, operands[1]));
+    emit_call_insn (gen_call_internal (dest));
     DONE;
   }
 )
 
 (define_insn "call_internal"
   [(call (mem:QI (match_operand:SI 0 "rx_call_operand" "r,Symbol"))
-        (match_operand:SI         1 "general_operand" "g,g"))
+        (const_int 0))
    (clobber (reg:CC CC_REG))]
   ""
   "@
 
     if (! rx_call_operand (dest, Pmode))
       dest = force_reg (Pmode, dest);
-    emit_call_insn (gen_call_value_internal (operands[0], dest, operands[2]));
+    emit_call_insn (gen_call_value_internal (operands[0], dest));
     DONE;
   }
 )
 (define_insn "call_value_internal"
   [(set (match_operand                  0 "register_operand" "=r,r")
        (call (mem:QI (match_operand:SI 1 "rx_call_operand"   "r,Symbol"))
-             (match_operand:SI         2 "general_operand"   "g,g")))
+             (const_int 0)))
    (clobber (reg:CC CC_REG))]
   ""
   "@
   {
     if (MEM_P (operands[0]))
       operands[0] = XEXP (operands[0], 0);
+    emit_call_insn (gen_sibcall_internal (operands[0]));
+    DONE;
   }
 )
 
 (define_insn "sibcall_internal"
   [(call (mem:QI (match_operand:SI 0 "rx_symbolic_call_operand" "Symbol"))
-        (match_operand:SI         1 "general_operand"          "g"))
+        (const_int 0))
    (return)]
   ""
   "bra\t%A0"
   {
     if (MEM_P (operands[1]))
       operands[1] = XEXP (operands[1], 0);
+    emit_call_insn (gen_sibcall_value_internal (operands[0], operands[1]));
+    DONE;
   }
 )
 
 (define_insn "sibcall_value_internal"
  [(set (match_operand                  0 "register_operand"         "=r")
        (call (mem:QI (match_operand:SI 1 "rx_symbolic_call_operand" "Symbol"))
-            (match_operand:SI         2 "general_operand"          "g")))
+            (const_int 0)))
   (return)]
   ""
   "bra\t%A1"
        (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")))])]
+     [(set (reg:SI SP_REG)
+          (minus:SI (reg:SI SP_REG)
+                    (match_operand:SI 0 "const_int_operand" "n")))])]
   "reload_completed"
   {
     rx_emit_stack_pushm (operands);
 )
 
 (define_insn "stack_pop"
-  [(set:SI (match_operand:SI 0 "register_operand" "=r")
-          (mem:SI (reg:SI SP_REG)))
-   (set:SI (reg:SI SP_REG)
-          (plus:SI (reg:SI SP_REG)
-                   (const_int 4)))]
+  [(set (match_operand:SI 0 "register_operand" "=r")
+       (mem:SI (reg:SI SP_REG)))
+   (set (reg:SI SP_REG)
+       (plus:SI (reg:SI SP_REG)
+                (const_int 4)))]
   ""
   "pop\t%0"
   [(set_attr "length" "2")
 
 (define_insn "stack_popm"
   [(match_parallel 1 "rx_load_multiple_vector"
-                  [(set:SI (reg:SI SP_REG)
-                           (plus:SI (reg:SI SP_REG)
-                                    (match_operand:SI 0 "const_int_operand" "n")))])]
+     [(set (reg:SI SP_REG)
+          (plus:SI (reg:SI SP_REG)
+                   (match_operand:SI 0 "const_int_operand" "n")))])]
   "reload_completed"
   {
     rx_emit_stack_popm (operands, true);
    (set_attr "timings" "45")] ;; The timing is a guesstimate average timing.
 )
 
-;; FIXME: Add memory destination options ?
-(define_insn "cstoresi4"
-  [(set (match_operand:SI   0 "register_operand" "=r,r,r,r,r,r,r")
+(define_insn_and_split "cstoresi4"
+  [(set (match_operand:SI   0 "register_operand" "=r")
        (match_operator:SI  1 "comparison_operator"
-        [(match_operand:SI 2 "register_operand"  "r,r,r,r,r,r,r")
-         (match_operand:SI 3 "rx_source_operand" "r,Uint04,Int08,Sint16,Sint24,i,Q")]))
-   (clobber (reg:CC CC_REG))] ;; Because the cc flags are set based on comparing ops 2 & 3 not the value in op 0.
+         [(match_operand:SI 2 "register_operand"  "r")
+          (match_operand:SI 3 "rx_source_operand" "riQ")]))
+   (clobber (reg:CC CC_REG))]
   ""
-  {
-    rx_float_compare_mode = false;
-    return "cmp\t%Q3, %Q2\n\tsc%B1.L\t%0";
-  }
-  [(set_attr "timings" "22,22,22,22,22,22,44")
-   (set_attr "length"  "5,5,6,7,8,9,8")]
+  "#"
+  "reload_completed"
+  [(const_int 0)]
+{
+  rtx flags, x;
+
+  flags = gen_rtx_REG (CCmode, CC_REG);
+  x = gen_rtx_COMPARE (CCmode, operands[2], operands[3]);
+  x = gen_rtx_SET (VOIDmode, flags, x);
+  emit_insn (x);
+
+  x = gen_rtx_fmt_ee (GET_CODE (operands[1]), SImode, flags, const0_rtx);
+  x = gen_rtx_SET (VOIDmode, operands[0], x);
+  emit_insn (x);
+  DONE;
+})
+
+(define_insn "*sccc"
+  [(set (match_operand:SI 0 "register_operand" "=r")
+       (match_operator:SI 1 "comparison_operator"
+         [(reg CC_REG) (const_int 0)]))]
+  "reload_completed"
+  "sc%B1.L\t%0"
+  [(set_attr "length" "3")]
 )
 
+(define_insn_and_split "cstoresf4"
+  [(set (match_operand:SI 0 "register_operand" "=r")
+       (match_operator:SI 1 "rx_fp_comparison_operator"
+        [(match_operand:SF 2 "register_operand" "r")
+         (match_operand:SF 3 "rx_source_operand" "rFQ")]))]
+  "ALLOW_RX_FPU_INSNS"
+  "#"
+  "reload_completed"
+  [(const_int 0)]
+{
+  rtx flags, x;
+
+  flags = gen_rtx_REG (CC_Fmode, CC_REG);
+  x = gen_rtx_COMPARE (CC_Fmode, operands[2], operands[3]);
+  x = gen_rtx_SET (VOIDmode, flags, x);
+  emit_insn (x);
+
+  x = gen_rtx_fmt_ee (GET_CODE (operands[1]), SImode, flags, const0_rtx);
+  x = gen_rtx_SET (VOIDmode, operands[0], x);
+  emit_insn (x);
+  DONE;
+})
+
 (define_expand "movsicc"
   [(parallel
     [(set (match_operand:SI                  0 "register_operand")
          (if_then_else:SI (match_operand:SI 1 "comparison_operator")
                           (match_operand:SI 2 "nonmemory_operand")
-                          (match_operand:SI 3 "immediate_operand")))
-     (clobber (reg:CC CC_REG))])] ;; See cstoresi4
+                          (match_operand:SI 3 "nonmemory_operand")))
+     (clobber (reg:CC CC_REG))])]
   ""
+{
+  /* 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_and_split "*movsicc"
+  [(set (match_operand:SI     0 "register_operand" "=r,r,r")
+       (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[1]) != EQ && GET_CODE (operands[1]) != NE)
-      FAIL;
-    if (! CONST_INT_P (operands[3]))
-      FAIL;
+    if (GET_CODE (operands[2]) == EQ)
+      return "stz\t%1, %0";
+    else
+     return "stnz\t%1, %0";
   }
+  [(set_attr "length" "4,5,6,7")]
 )
 
-(define_insn "*movsieq"
-  [(set (match_operand:SI                      0 "register_operand" "=r,r,r")
-       (if_then_else:SI (eq (match_operand:SI 3 "register_operand"  "r,r,r")
-                            (match_operand:SI 4 "rx_source_operand" "riQ,riQ,riQ"))
-                        (match_operand:SI     1 "nonmemory_operand" "0,i,r")
-                        (match_operand:SI     2 "immediate_operand" "i,i,i")))
-   (clobber (reg:CC CC_REG))] ;; See cstoresi4
-  ""
-  "@
-  cmp\t%Q4, %Q3\n\tstnz\t%2, %0
-  cmp\t%Q4, %Q3\n\tmov.l\t%2, %0\n\tstz\t%1, %0
-  cmp\t%Q4, %Q3\n\tmov.l\t%1, %0\n\tstnz\t%2, %0"
-  [(set_attr "length"  "13,19,15")
-   (set_attr "timings" "22,33,33")]
-)
-
-(define_insn "*movsine"
-  [(set (match_operand:SI                      0 "register_operand" "=r,r,r")
-       (if_then_else:SI (ne (match_operand:SI 3 "register_operand"  "r,r,r")
-                            (match_operand:SI 4 "rx_source_operand" "riQ,riQ,riQ"))
-                        (match_operand:SI     1 "nonmemory_operand" "0,i,r")
-                        (match_operand:SI     2 "immediate_operand" "i,i,i")))
-   (clobber (reg:CC CC_REG))] ;; See cstoresi4
-  ""
-  "@
-  cmp\t%Q4, %Q3\n\tstz\t%2, %0
-  cmp\t%Q4, %Q3\n\tmov.l\t%2, %0\n\tstnz\t%1, %0
-  cmp\t%Q4, %Q3\n\tmov.l\t%1, %0\n\tstz\t%2, %0"
-  [(set_attr "length"  "13,19,15")
-   (set_attr "timings" "22,33,33")]
+(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")))
-   (set (reg:CC_ZSO CC_REG)
-       (compare:CC_ZSO (abs:SI (match_dup 1))
-                       (const_int 0)))]
+   (clobber (reg:CC CC_REG))]
   ""
   "@
   abs\t%0
   [(set_attr "length" "2,3")]
 )
 
-(define_insn "addsi3"
+(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_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")))
-   (set (reg:CC_ZSC CC_REG) ;; See subsi3
-       (compare:CC_ZSC (plus:SI (match_dup 1) (match_dup 2))
-                       (const_int 0)))]
+   (clobber (reg:CC CC_REG))]
   ""
   "@
   add\t%2, %0
    (set_attr "length"   "2,2,2,3,4,5,6,2,3,3,4,5,6,5")]
 )
 
-(define_insn "adddi3"
-  [(set (match_operand:DI          0 "register_operand" "=r,r,r,r,r,r")
-       (plus:DI (match_operand:DI 1 "register_operand" "%0,0,0,0,0,0")
-                (match_operand:DI 2 "rx_source_operand"
-                                  "r,Sint08,Sint16,Sint24,i,Q")))
-   (set (reg:CC_ZSC CC_REG) ;; See subsi3
-       (compare:CC_ZSC (plus:DI (match_dup 1) (match_dup 2))
-                       (const_int 0)))]
+(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 "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,r,0")
                (match_operand:SI 2 "rx_source_operand" "r,Uint04,Sint08,Sint16,Sint24,i,0,r,Q")))
-   (set (reg:CC_ZS CC_REG)
-       (compare:CC_ZS (and:SI (match_dup 1) (match_dup 2))
-                      (const_int 0)))]
+   (clobber (reg:CC CC_REG))]
   ""
   "@
   and\t%2, %0
   and\t%1, %0
   and\t%2, %1, %0
   and\t%Q2, %0"
-  [(set_attr "timings" "11,11,11,11,11,11,11,33,33")
+  [(set_attr "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"
+  [(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"
    (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,r,r")
 (define_insn "negsi2"
   [(set (match_operand:SI         0 "register_operand" "=r,r")
         (neg:SI (match_operand:SI 1 "register_operand"  "0,r")))
-   (set (reg:CC CC_REG)
-       (compare:CC (neg:SI (match_dup 1))
-                   (const_int 0)))]
-  ;; The NEG instruction does not comply with -fwrapv semantics.
-  ;; See gcc.c-torture/execute/pr22493-1.c for an example of this.
-  "! flag_wrapv"
+   (clobber (reg:CC CC_REG))]
+  ""
+  "@
+  neg\t%0
+  neg\t%1, %0"
+  [(set_attr "length" "2,3")]
+)
+
+;; Note that the O and C flags are not set as per a normal compare,
+;; and thus are unusable in that context.
+(define_insn "*negsi2_flags"
+  [(set (match_operand:SI         0 "register_operand" "=r,r")
+        (neg:SI (match_operand:SI 1 "register_operand"  "0,r")))
+   (set (reg CC_REG)
+       (compare (neg:SI (match_dup 1))
+                (const_int 0)))]
+  "reload_completed && rx_match_ccmode (insn, CC_ZSmode)"
   "@
   neg\t%0
   neg\t%1, %0"
 (define_insn "one_cmplsi2"
   [(set (match_operand:SI         0 "register_operand" "=r,r")
        (not:SI (match_operand:SI 1 "register_operand"  "0,r")))
-   (set (reg:CC_ZS CC_REG)
-       (compare:CC_ZS (not:SI (match_dup 1))
-                      (const_int 0)))]
+   (clobber (reg:CC CC_REG))]
   ""
   "@
   not\t%0
   [(set_attr "length" "2,3")]
 )
 
+(define_insn "*one_cmplsi2_flags"
+  [(set (match_operand:SI         0 "register_operand" "=r,r")
+       (not:SI (match_operand:SI 1 "register_operand"  "0,r")))
+   (set (reg CC_REG)
+       (compare (not:SI (match_dup 1))
+                (const_int 0)))]
+  "reload_completed && rx_match_ccmode (insn, CC_ZSmode)"
+  "@
+  not\t%0
+  not\t%1, %0"
+  [(set_attr "length" "2,3")]
+)
+
 (define_insn "iorsi3"
   [(set (match_operand:SI         0 "register_operand" "=r,r,r,r,r,r,r,r,r")
        (ior:SI (match_operand:SI 1 "register_operand" "%0,0,0,0,0,0,r,r,0")
                (match_operand:SI 2 "rx_source_operand" "r,Uint04,Sint08,Sint16,Sint24,i,0,r,Q")))
-   (set (reg:CC_ZS CC_REG)
-       (compare:CC_ZS (ior:SI (match_dup 1) (match_dup 2))
-                      (const_int 0)))]
+   (clobber (reg:CC CC_REG))]
   ""
   "@
   or\t%2, %0
    (set_attr "length"  "2,2,3,4,5,6,2,3,5")]
 )
 
-(define_insn "rotlsi3"
-  [(set (match_operand:SI            0 "register_operand" "=r")
-       (rotate:SI (match_operand:SI 1 "register_operand"  "0")
-                  (match_operand:SI 2 "rx_shift_operand" "rn")))
-   (set (reg:CC_ZS CC_REG)
-       (compare:CC_ZS (rotate:SI (match_dup 1) (match_dup 2))
-                      (const_int 0)))]
-  ""
+(define_insn "*iorsi3_flags"
+  [(set (match_operand:SI         0 "register_operand" "=r,r,r,r,r,r,r,r,r")
+       (ior:SI (match_operand:SI 1 "register_operand" "%0,0,0,0,0,0,r,r,0")
+               (match_operand:SI 2 "rx_source_operand" "r,Uint04,Sint08,Sint16,Sint24,i,0,r,Q")))
+   (set (reg CC_REG)
+       (compare (ior:SI (match_dup 1) (match_dup 2))
+                (const_int 0)))]
+  "reload_completed && rx_match_ccmode (insn, CC_ZSmode)"
+  "@
+  or\t%2, %0
+  or\t%2, %0
+  or\t%2, %0
+  or\t%2, %0
+  or\t%2, %0
+  or\t%Q2, %0
+  or\t%1, %0
+  or\t%2, %1, %0
+  or\t%Q2, %0"
+  [(set_attr "timings" "11,11,11,11,11,11,11,11,33")
+   (set_attr "length"  "2,2,3,4,5,6,2,3,5")]
+)
+
+(define_insn "rotlsi3"
+  [(set (match_operand:SI            0 "register_operand" "=r")
+       (rotate:SI (match_operand:SI 1 "register_operand"  "0")
+                  (match_operand:SI 2 "rx_shift_operand" "rn")))
+   (clobber (reg:CC CC_REG))]
+  ""
+  "rotl\t%2, %0"
+  [(set_attr "length" "3")]
+)
+
+(define_insn "*rotlsi3_flags"
+  [(set (match_operand:SI            0 "register_operand" "=r")
+       (rotate:SI (match_operand:SI 1 "register_operand"  "0")
+                  (match_operand:SI 2 "rx_shift_operand" "rn")))
+   (set (reg CC_REG)
+       (compare (rotate:SI (match_dup 1) (match_dup 2))
+                (const_int 0)))]
+  "reload_completed && rx_match_ccmode (insn, CC_ZSmode)"
   "rotl\t%2, %0"
   [(set_attr "length" "3")]
 )
   [(set (match_operand:SI              0 "register_operand" "=r")
        (rotatert:SI (match_operand:SI 1 "register_operand"  "0")
                     (match_operand:SI 2 "rx_shift_operand" "rn")))
-   (set (reg:CC_ZS CC_REG)
-       (compare:CC_ZS (rotatert:SI (match_dup 1) (match_dup 2))
-                      (const_int 0)))]
+   (clobber (reg:CC CC_REG))]
   ""
   "rotr\t%2, %0"
   [(set_attr "length" "3")]
 )
 
+(define_insn "*rotrsi3_flags"
+  [(set (match_operand:SI              0 "register_operand" "=r")
+       (rotatert:SI (match_operand:SI 1 "register_operand"  "0")
+                    (match_operand:SI 2 "rx_shift_operand" "rn")))
+   (set (reg CC_REG)
+       (compare (rotatert:SI (match_dup 1) (match_dup 2))
+                (const_int 0)))]
+  "reload_completed && rx_match_ccmode (insn, CC_ZSmode)"
+  "rotr\t%2, %0"
+  [(set_attr "length" "3")]
+)
+
 (define_insn "ashrsi3"
   [(set (match_operand:SI              0 "register_operand" "=r,r,r")
        (ashiftrt:SI (match_operand:SI 1 "register_operand"  "0,0,r")
                     (match_operand:SI 2 "rx_shift_operand"  "r,n,n")))
-   (set (reg:CC_ZS CC_REG)
-       (compare:CC_ZS (ashiftrt:SI (match_dup 1) (match_dup 2))
-                      (const_int 0)))]
+   (clobber (reg:CC CC_REG))]
   ""
   "@
   shar\t%2, %0
   [(set_attr "length" "3,2,3")]
 )
 
+(define_insn "*ashrsi3_flags"
+  [(set (match_operand:SI              0 "register_operand" "=r,r,r")
+       (ashiftrt:SI (match_operand:SI 1 "register_operand"  "0,0,r")
+                    (match_operand:SI 2 "rx_shift_operand"  "r,n,n")))
+   (set (reg CC_REG)
+       (compare (ashiftrt:SI (match_dup 1) (match_dup 2))
+                (const_int 0)))]
+  "reload_completed && rx_match_ccmode (insn, CC_ZSmode)"
+  "@
+  shar\t%2, %0
+  shar\t%2, %0
+  shar\t%2, %1, %0"
+  [(set_attr "length" "3,2,3")]
+)
+
 (define_insn "lshrsi3"
   [(set (match_operand:SI              0 "register_operand" "=r,r,r")
        (lshiftrt:SI (match_operand:SI 1 "register_operand"  "0,0,r")
                     (match_operand:SI 2 "rx_shift_operand"  "r,n,n")))
-   (set (reg:CC_ZS CC_REG)
-       (compare:CC_ZS (lshiftrt:SI (match_dup 1) (match_dup 2))
-                      (const_int 0)))]
+   (clobber (reg:CC CC_REG))]
   ""
   "@
   shlr\t%2, %0
   [(set_attr "length" "3,2,3")]
 )
 
+(define_insn "*lshrsi3_flags"
+  [(set (match_operand:SI              0 "register_operand" "=r,r,r")
+       (lshiftrt:SI (match_operand:SI 1 "register_operand"  "0,0,r")
+                    (match_operand:SI 2 "rx_shift_operand"  "r,n,n")))
+   (set (reg CC_REG)
+       (compare (lshiftrt:SI (match_dup 1) (match_dup 2))
+                (const_int 0)))]
+  "reload_completed && rx_match_ccmode (insn, CC_ZSmode)"
+  "@
+  shlr\t%2, %0
+  shlr\t%2, %0
+  shlr\t%2, %1, %0"
+  [(set_attr "length" "3,2,3")]
+)
+
 (define_insn "ashlsi3"
   [(set (match_operand:SI            0 "register_operand" "=r,r,r")
        (ashift:SI (match_operand:SI 1 "register_operand"  "0,0,r")
                   (match_operand:SI 2 "rx_shift_operand"  "r,n,n")))
-   (set (reg:CC_ZS CC_REG)
-       (compare:CC_ZS (ashift:SI (match_dup 1) (match_dup 2))
-                      (const_int 0)))]
+   (clobber (reg:CC CC_REG))]
   ""
   "@
   shll\t%2, %0
   [(set_attr "length" "3,2,3")]
 )
 
+(define_insn "*ashlsi3_flags"
+  [(set (match_operand:SI            0 "register_operand" "=r,r,r")
+       (ashift:SI (match_operand:SI 1 "register_operand"  "0,0,r")
+                  (match_operand:SI 2 "rx_shift_operand"  "r,n,n")))
+   (set (reg CC_REG)
+       (compare (ashift:SI (match_dup 1) (match_dup 2))
+                (const_int 0)))]
+  "reload_completed && rx_match_ccmode (insn, CC_ZSmode)"
+  "@
+  shll\t%2, %0
+  shll\t%2, %0
+  shll\t%2, %1, %0"
+  [(set_attr "length" "3,2,3")]
+)
+
+;; Saturate to 32-bits
+(define_insn_and_split "ssaddsi3"
+  [(set (match_operand:SI             0 "register_operand" "=r")
+       (ss_plus:SI (match_operand:SI 1 "register_operand"  "r")
+                   (match_operand:SI 2 "rx_source_operand" "riQ")))
+   (clobber (reg:CC CC_REG))]
+  ""
+  "#"
+  "reload_completed"
+  [(parallel [(set (match_dup 0)
+                  (plus:SI (match_dup 1) (match_dup 2)))
+             (set (reg:CC_ZSC CC_REG)
+                  (compare:CC_ZSC
+                    (plus:SI (match_dup 1) (match_dup 2))
+                    (const_int 0)))])
+   (set (match_dup 0)
+       (unspec:SI [(match_dup 0) (reg:CC CC_REG)] 
+                  UNSPEC_BUILTIN_SAT))]
+   ""
+)
+
+(define_insn "*sat"
+  [(set (match_operand:SI             0 "register_operand" "=r")
+       (unspec:SI [(match_operand:SI 1 "register_operand"  "0")
+                   (reg:CC CC_REG)]
+                  UNSPEC_BUILTIN_SAT))]
+  "reload_completed"
+  "sat\t%0"
+  [(set_attr "length" "2")]
+)
+
 (define_insn "subsi3"
   [(set (match_operand:SI           0 "register_operand" "=r,r,r,r,r")
        (minus:SI (match_operand:SI 1 "register_operand"  "0,0,0,r,0")
                  (match_operand:SI 2 "rx_source_operand" "r,Uint04,n,r,Q")))
-   (set (reg:CC_ZSC CC_REG)
-       ;; Note - we do not acknowledge that the SUB instruction sets the Overflow
-       ;; flag because its interpretation is different from comparing the result
-       ;; against zero.  Compile and run gcc.c-torture/execute/cmpsi-1.c to see this.
-       (compare:CC_ZSC (minus:SI (match_dup 1) (match_dup 2))
-                       (const_int 0)))]
+   (clobber (reg:CC CC_REG))]
   ""
   "@
   sub\t%2, %0
    (set_attr "length" "2,2,6,3,5")]
 )
 
-(define_insn "subdi3"
-  [(set (match_operand:DI           0 "register_operand" "=r,r")
-       (minus:DI (match_operand:DI 1 "register_operand"  "0,0")
-                 (match_operand:DI 2 "rx_source_operand" "r,Q")))
-   (set (reg:CC_ZSC CC_REG) ;; See subsi3
-       (compare:CC_ZSC (minus:DI (match_dup 1) (match_dup 2))
-                       (const_int 0)))]
-  ""
-  "sub\t%L2, %L0\n\tsbb\t%H2, %H0"
-  [(set_attr "timings" "22,44")
-   (set_attr "length" "5,11")]
+;; Note that the O flag is set as if (compare op1 op2) not for
+;; what is described here, (compare op0 0).
+(define_insn "*subsi3_flags"
+  [(set (match_operand:SI           0 "register_operand" "=r,r,r,r,r")
+       (minus:SI (match_operand:SI 1 "register_operand"  "0,0,0,r,0")
+                 (match_operand:SI 2 "rx_source_operand" "r,Uint04,n,r,Q")))
+   (set (reg CC_REG)
+       (compare (minus:SI (match_dup 1) (match_dup 2))
+                (const_int 0)))]
+  "reload_completed && rx_match_ccmode (insn, CC_ZSCmode)"
+  "@
+  sub\t%2, %0
+  sub\t%2, %0
+  add\t%N2, %0
+  sub\t%2, %1, %0
+  sub\t%Q2, %0"
+  [(set_attr "timings" "11,11,11,11,33")
+   (set_attr "length" "2,2,6,3,5")]
+)
+
+;; A helper to expand the above with the CC_MODE filled in.
+(define_expand "subsi3_flags"
+  [(parallel [(set (match_operand:SI 0 "register_operand")
+                  (minus:SI (match_operand:SI 1 "register_operand")
+                            (match_operand:SI 2 "rx_source_operand")))
+             (set (reg:CC_ZSC CC_REG)
+                  (compare:CC_ZSC (minus:SI (match_dup 1) (match_dup 2))
+                                  (const_int 0)))])]
+)
+
+(define_insn "sbb_internal"
+  [(set (match_operand:SI     0 "register_operand"   "=r,r")
+       (minus:SI
+         (minus:SI
+           (match_operand:SI 1 "register_operand"   " 0,0")
+           (match_operand:SI 2 "rx_compare_operand" " r,Q"))
+         (geu:SI (reg:CC CC_REG) (const_int 0))))
+    (clobber (reg:CC CC_REG))]
+  "reload_completed"
+  "sbb\t%2, %0"
+  [(set_attr "timings" "11,33")
+   (set_attr "length"  "3,6")]
+)
+
+(define_insn "*sbb_flags"
+  [(set (match_operand:SI     0 "register_operand"   "=r,r")
+       (minus:SI
+         (minus:SI
+           (match_operand:SI 1 "register_operand"   " 0,0")
+           (match_operand:SI 2 "rx_compare_operand" " r,Q"))
+         (geu:SI (reg:CC CC_REG) (const_int 0))))
+   (set (reg CC_REG)
+       (compare
+         (minus:SI
+           (minus:SI (match_dup 1) (match_dup 2))
+           (geu:SI (reg:CC CC_REG) (const_int 0)))
+         (const_int 0)))]
+  "reload_completed"
+  "sbb\t%2, %0"
+  [(set_attr "timings" "11,33")
+   (set_attr "length"  "3,6")]
 )
 
+(define_expand "subdi3"
+  [(set (match_operand:DI           0 "register_operand")
+       (minus:DI (match_operand:DI 1 "register_operand")
+                 (match_operand:DI 2 "rx_compare_operand")))]
+  ""
+{
+  rtx op0l, op0h, op1l, op1h, op2l, op2h;
+
+  op0l = gen_lowpart (SImode, operands[0]);
+  op1l = gen_lowpart (SImode, operands[1]);
+  op2l = gen_lowpart (SImode, operands[2]);
+  op0h = gen_highpart (SImode, operands[0]);
+  op1h = gen_highpart (SImode, operands[1]);
+  op2h = gen_highpart_mode (SImode, DImode, operands[2]);
+
+  emit_insn (gen_subdi3_internal (op0l, op0h, op1l, op2l, op1h, op2h));
+  DONE;
+})
+
+(define_insn_and_split "subdi3_internal"
+  [(set (match_operand:SI          0 "register_operand"   "=&r,&r")
+       (minus:SI (match_operand:SI 2 "register_operand"  "  0, r")
+                 (match_operand:SI 3 "rx_compare_operand" "rQ, r")))
+   (set (match_operand:SI          1 "register_operand"   "= r, r")
+       (minus:SI
+         (minus:SI
+           (match_operand:SI      4 "register_operand"   "  1, 1")
+           (match_operand:SI      5 "rx_compare_operand" " rQ,rQ"))
+         (geu:SI (match_dup 2) (match_dup 3))))
+   (clobber (reg:CC CC_REG))]
+  ""
+  "#"
+  "reload_completed"
+  [(const_int 0)]
+{
+  emit_insn (gen_subsi3_flags (operands[0], operands[2], operands[3]));
+  emit_insn (gen_sbb_internal (operands[1], operands[4], operands[5]));
+  DONE;
+})
+
 (define_insn "xorsi3"
   [(set (match_operand:SI         0 "register_operand" "=r,r,r,r,r,r")
        (xor:SI (match_operand:SI 1 "register_operand" "%0,0,0,0,0,0")
                (match_operand:SI 2 "rx_source_operand"
                                  "r,Sint08,Sint16,Sint24,i,Q")))
-   (set (reg:CC_ZS CC_REG)
-       (compare:CC_ZS (xor:SI (match_dup 1) (match_dup 2))
-                      (const_int 0)))]
+   (clobber (reg:CC CC_REG))]
   ""
   "xor\t%Q2, %0"
   [(set_attr "timings" "11,11,11,11,11,33")
    (set_attr "length" "3,4,5,6,7,6")]
 )
+
+(define_insn "*xorsi3_flags"
+  [(set (match_operand:SI         0 "register_operand" "=r,r,r,r,r,r")
+       (xor:SI (match_operand:SI 1 "register_operand" "%0,0,0,0,0,0")
+               (match_operand:SI 2 "rx_source_operand"
+                                 "r,Sint08,Sint16,Sint24,i,Q")))
+   (set (reg CC_REG)
+       (compare (xor:SI (match_dup 1) (match_dup 2))
+                (const_int 0)))]
+  "reload_completed && rx_match_ccmode (insn, CC_ZSmode)"
+  "xor\t%Q2, %0"
+  [(set_attr "timings" "11,11,11,11,11,33")
+   (set_attr "length" "3,4,5,6,7,6")]
+)
+\f
+;; 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
 
   [(set (match_operand:SF          0 "register_operand"  "=r,r,r")
        (plus:SF (match_operand:SF 1 "register_operand"  "%0,0,0")
                 (match_operand:SF 2 "rx_source_operand"  "r,F,Q")))
-   (set (reg:CC_ZS CC_REG)
-       (compare:CC_ZS (plus:SF (match_dup 1) (match_dup 2))
-                       (const_int 0)))]
+   (clobber (reg:CC CC_REG))]
   "ALLOW_RX_FPU_INSNS"
   "fadd\t%2, %0"
   [(set_attr "timings" "44,44,66")
   [(set (match_operand:SF         0 "register_operand" "=r,r,r")
        (div:SF (match_operand:SF 1 "register_operand"  "0,0,0")
                (match_operand:SF 2 "rx_source_operand" "r,F,Q")))
-   (set (reg:CC_ZS CC_REG)
-       (compare:CC_ZS (div:SF (match_dup 1) (match_dup 2))
-                       (const_int 0)))]
+   (clobber (reg:CC CC_REG))]
   "ALLOW_RX_FPU_INSNS"
   "fdiv\t%2, %0"
   [(set_attr "timings" "1616,1616,1818")
   [(set (match_operand:SF          0 "register_operand" "=r,r,r")
        (mult:SF (match_operand:SF 1 "register_operand" "%0,0,0")
                (match_operand:SF  2 "rx_source_operand" "r,F,Q")))
-   (set (reg:CC_ZS CC_REG)
-       (compare:CC_ZS (mult:SF (match_dup 1) (match_dup 2))
-                       (const_int 0)))]
+   (clobber (reg:CC CC_REG))]
   "ALLOW_RX_FPU_INSNS"
   "fmul\t%2, %0"
   [(set_attr "timings" "33,33,55")
   [(set (match_operand:SF           0 "register_operand" "=r,r,r")
        (minus:SF (match_operand:SF 1 "register_operand"  "0,0,0")
                  (match_operand:SF 2 "rx_source_operand" "r,F,Q")))
-   (set (reg:CC_ZS CC_REG)
-       (compare:CC_ZS (minus:SF (match_dup 1) (match_dup 2))
-                      (const_int 0)))]
+   (clobber (reg:CC CC_REG))]
   "ALLOW_RX_FPU_INSNS"
   "fsub\t%Q2, %0"
   [(set_attr "timings" "44,44,66")
 (define_insn "fix_truncsfsi2"
   [(set (match_operand:SI         0 "register_operand"  "=r,r")
        (fix:SI (match_operand:SF 1 "rx_compare_operand" "r,Q")))
-   (set (reg:CC_ZS CC_REG)
-       (compare:CC_ZS (fix:SI (match_dup 1))
-                      (const_int 0)))]
+   (clobber (reg:CC CC_REG))]
   "ALLOW_RX_FPU_INSNS"
   "ftoi\t%Q1, %0"
   [(set_attr "timings" "22,44")
 (define_insn "floatsisf2"
   [(set (match_operand:SF           0 "register_operand"  "=r,r")
        (float:SF (match_operand:SI 1 "rx_compare_operand" "r,Q")))
-   (set (reg:CC_ZS CC_REG)
-       (compare:CC_ZS (float:SF (match_dup 1))
-                       (const_int 0)))]
+   (clobber (reg:CC CC_REG))]
   "ALLOW_RX_FPU_INSNS"
   "itof\t%Q1, %0"
   [(set_attr "timings" "22,44")
 )
 \f
 ;; Bit manipulation instructions.
-;; Note - there are two versions of each pattern because the memory
-;; accessing versions use QImode whilst the register accessing
-;; versions use SImode.
-;; The peephole are here because the combiner only looks at a maximum
-;; of three instructions at a time.
-
-(define_insn "bitset"
-  [(set:SI (match_operand:SI                    0 "register_operand" "=r")
-          (ior:SI (match_operand:SI            1 "register_operand" "0")
-                  (ashift:SI (const_int 1)
-                             (match_operand:SI 2 "nonmemory_operand" "ri"))))]
-  ""
-  "bset\t%2, %0"
+
+;; ??? The *_in_memory patterns will not be matched without further help.
+;; At one time we had the insv expander generate them, but I suspect that
+;; in general we get better performance by exposing the register load to
+;; the optimizers.
+;;
+;; An alternate solution would be to re-organize these patterns such
+;; that allow both register and memory operands.  This would allow the
+;; register allocator to spill and not load the register operand.  This
+;; would be possible only for operations for which we have a constant
+;; bit offset, so that we can adjust the address by ofs/8 and replace
+;; the offset in the insn by ofs%8.
+
+(define_insn "*bitset"
+  [(set (match_operand:SI                    0 "register_operand" "=r")
+       (ior:SI (ashift:SI (const_int 1)
+                          (match_operand:SI 1 "rx_shift_operand" "ri"))
+               (match_operand:SI            2 "register_operand" "0")))]
+  ""
+  "bset\t%1, %0"
   [(set_attr "length" "3")]
 )
 
-(define_insn "bitset_in_memory"
-  [(set:QI (match_operand:QI                    0 "memory_operand" "=m")
-          (ior:QI (match_operand:QI            1 "memory_operand" "0")
-                  (ashift:QI (const_int 1)
-                             (match_operand:QI 2 "nonmemory_operand" "ri"))))]
+(define_insn "*bitset_in_memory"
+  [(set (match_operand:QI                    0 "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;
 
-;; (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)))))]
+  /* 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 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
+  [(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
   ""
-  {
-    if (rx_expand_insv (operands))
+{
+  /* We only handle single-bit inserts.  */
+  if (!CONST_INT_P (operands[1]) || INTVAL (operands[1]) != 1)
+    FAIL;
+
+  /* Either the bit to insert or the position must be constant.  */
+  if (CONST_INT_P (operands[3]))
+    operands[3] = GEN_INT (INTVAL (operands[3]) & 1);
+  else if (CONST_INT_P (operands[2]))
+    {
+      emit_insn (gen_rx_insv_reg (operands[0], operands[2], operands[3]));
       DONE;
+    }
+  else
     FAIL;
-  }
-)   
+})
 \f
 ;; Atomic exchange operation.
 
 (define_insn "sync_lock_test_and_setsi"
-  [(set:SI (match_operand:SI 0 "register_operand"   "=r,r")
-          (match_operand:SI 1 "rx_compare_operand" "=r,Q"))
-   (set:SI (match_dup 1)
-          (match_operand:SI 2 "register_operand"    "0,0"))]
+  [(set (match_operand:SI 0 "register_operand"   "=r,r")
+       (match_operand:SI 1 "rx_compare_operand" "=r,Q"))
+   (set (match_dup 1)
+       (match_operand:SI 2 "register_operand"    "0,0"))]
   ""
   "xchg\t%1, %0"
   [(set_attr "length" "3,6")
 ;; Block move functions.
 
 (define_expand "movstr"
-  [(set:SI (match_operand:BLK 1 "memory_operand")    ;; Dest
-          (match_operand:BLK 2 "memory_operand"))   ;; Source
-   (use (match_operand:SI     0 "register_operand")) ;; Updated Dest
+  [(set (match_operand:BLK 1 "memory_operand")    ;; Dest
+       (match_operand:BLK 2 "memory_operand"))   ;; Source
+   (use (match_operand:SI  0 "register_operand")) ;; Updated Dest
   ]
   ""
   {
 )
 
 (define_insn "rx_movstr"
-  [(set:SI (mem:BLK (reg:SI 1))
-          (mem:BLK (reg:SI 2)))
+  [(set (mem:BLK (reg:SI 1))
+       (mem:BLK (reg:SI 2)))
    (unspec_volatile:BLK [(reg:SI 1) (reg:SI 2) (reg:SI 3)] UNSPEC_MOVSTR)
    (clobber (reg:SI 1))
    (clobber (reg:SI 2))
 )
 
 (define_insn "rx_strend"
-  [(set:SI (match_operand:SI                      0 "register_operand" "=r")
-          (unspec_volatile:SI [(match_operand:SI 1 "register_operand"  "r")
+  [(set (match_operand:SI                      0 "register_operand" "=r")
+       (unspec_volatile:SI [(match_operand:SI 1 "register_operand"  "r")
                                (reg:SI 3)] UNSPEC_STRLEN))
    (clobber (reg:SI 1))
    (clobber (reg:SI 2))
     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_insn "rx_cmpstrn"
-  [(set:SI (match_operand:SI 0 "register_operand" "=r")
-          (unspec_volatile:SI [(reg:SI 1) (reg:SI 2) (reg:SI 3)]
-                              UNSPEC_CMPSTRN))
-   (use (match_operand:BLK   1 "memory_operand" "m"))
-   (use (match_operand:BLK   2 "memory_operand" "m"))
+  [(set (match_operand:SI 0 "register_operand" "=r")
+       (unspec_volatile:SI [(reg:SI 1) (reg:SI 2) (reg:SI 3)]
+                           UNSPEC_CMPSTRN))
+   (use (match_operand:BLK 1 "memory_operand" "m"))
+   (use (match_operand:BLK 2 "memory_operand" "m"))
    (clobber (reg:SI 1))
    (clobber (reg:SI 2))
    (clobber (reg:SI 3))
 
 ;; Byte swap (two 16-bit values).
 (define_insn "revw"
-  [(set (match_operand:SI             0 "register_operand" "+r")
+  [(set (match_operand:SI             0 "register_operand" "=r")
        (unspec:SI [(match_operand:SI 1 "register_operand"  "r")]
                   UNSPEC_BUILTIN_REVW))]
   ""
    (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
   "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)))]
+  ""
+  ""
+)