OSDN Git Service

* config/rx/rx.md (return): Define pattern.
[pf3gnuchains/gcc-fork.git] / gcc / config / rx / rx.md
index 7629a88..92768c6 100644 (file)
@@ -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
@@ -70,6 +73,8 @@
    (UNSPEC_BUILTIN_SAT     49)
    (UNSPEC_BUILTIN_SETPSW  50)
    (UNSPEC_BUILTIN_WAIT           51)
+
+   (UNSPEC_PID_ADDR       52)
   ]
 )
 
        (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)]
   ""
        (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 (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"
      (clobber (reg:CC CC_REG))])]
   ""
 {
-  /* ??? Support other conditions via cstore into a temporary?  */
-  if (GET_CODE (operands[1]) != EQ && GET_CODE (operands[1]) != NE)
-    FAIL;
-  /* One operand must be a constant.  */
-  if (!CONSTANT_P (operands[2]) && !CONSTANT_P (operands[3]))
+  /* 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")
+  [(set (match_operand:SI     0 "register_operand" "=r,r,r")
        (if_then_else:SI
-         (match_operator 5 "rx_z_comparison_operator"
-          [(match_operand:SI 3 "register_operand"  "r,r")
-           (match_operand:SI 4 "rx_source_operand" "riQ,riQ")])
-         (match_operand:SI   1 "nonmemory_operand" "i,ri")
-         (match_operand:SI   2 "nonmemory_operand" "ri,i")))
+         (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])"
+  "(CONSTANT_P (operands[1]) || CONSTANT_P (operands[2]))
+    || (REG_P (operands[1]) && REG_P (operands[2]))"
   "#"
   "&& reload_completed"
   [(const_int 0)]
   op1 = operands[1];
   op2 = operands[2];
 
-  /* If OP2 is the constant, reverse the sense of the move.  */
-  if (!CONSTANT_P (operands[1]))
+  /* 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))
+  if (! rtx_equal_p (op0, op2))
     emit_move_insn (op0, op2);
 
   x = gen_rtx_fmt_ee (cmp_code, VOIDmode, flags, const0_rtx);
            [(reg CC_REG) (const_int 0)])
          (match_operand:SI 1 "immediate_operand" "Sint08,Sint16,Sint24,i")
          (match_dup 0)))]
-  "reload_completed"
-{
-  if (GET_CODE (operands[2]) == EQ)
-    return "stz\t%1, %0";
-  else
-    return "stnz\t%1, %0";
-}
+  "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 "*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_attr "length" "2,3")]
 )
 
-(define_insn "addsi3"
+(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")))
          (match_operand:SI   2 "rx_source_operand" "r,Sint08,Sint16,Sint24,i,Q")))
     (clobber (reg:CC CC_REG))]
   "reload_completed"
-  "adc %2,%0"
+  "adc\t%2, %0"
   [(set_attr "timings" "11,11,11,11,11,33")
    (set_attr "length"   "3,4,5,6,7,6")]
 )
            (match_dup 2))
          (const_int 0)))]
   "reload_completed && rx_match_ccmode (insn, CC_ZSCmode)"
-  "adc %2,%0"
+  "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)))]
+  ""
+  [(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")
 })
 
 (define_insn_and_split "adddi3_internal"
-  [(set (match_operand:SI          0 "register_operand"  "=r")
+  [(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")
   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")]
 )
 
   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")]
 )
 
    (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")
    (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"
 )
 
 (define_insn "*bitset_in_memory"
-  [(set (match_operand:QI                    0 "memory_operand" "+Q")
+  [(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%1, %0.B"
   [(set_attr "length" "3")
-   (set_attr "timings" "34")]
+   (set_attr "timings" "33")]
 )
 
 (define_insn "*bitinvert"
 )
 
 (define_insn "*bitinvert_in_memory"
-  [(set (match_operand:QI 0 "memory_operand" "+Q")
+  [(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)))]
 )
 
 (define_insn "*bitclr_in_memory"
-  [(set (match_operand:QI 0 "memory_operand" "+Q")
+  [(set (match_operand:QI 0 "rx_restricted_mem_operand" "+Q")
        (and:QI (not:QI
                  (ashift:QI
                    (const_int 1)
   ""
   "bclr\t%1, %0.B"
   [(set_attr "length" "3")
-   (set_attr "timings" "34")]
+   (set_attr "timings" "33")]
 )
 
 (define_insn "*insv_imm"
     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));
   "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)))]
+  ""
+  ""
+)