OSDN Git Service

* config/cris/cris.md ("*movdi_insn", "*mov_sidesisf_biap")
[pf3gnuchains/gcc-fork.git] / gcc / config / cris / cris.md
index 2ec2502..7c56727 100644 (file)
@@ -1,5 +1,6 @@
 ;; GCC machine description for CRIS cpu cores.
-;; Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
+;; Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
+;; Free Software Foundation, Inc.
 ;; Contributed by Axis Communications.
 
 ;; This file is part of GCC.
@@ -31,7 +32,7 @@
 ;; There are several instructions that are orthogonal in size, and seems
 ;; they could be matched by a single pattern without a specified size
 ;; for the operand that is orthogonal.  However, this did not work on
-;; gcc-2.7.2 (and problably not on gcc-2.8.1), relating to that when a
+;; gcc-2.7.2 (and probably not on gcc-2.8.1), relating to that when a
 ;; constant is substituted into an operand, the actual mode must be
 ;; deduced from the pattern.  There is reasonable hope that that has been
 ;; fixed, so FIXME: try again.
 ;; UNSPEC Usage:
 ;; 0 PLT reference from call expansion: operand 0 is the address,
 ;;   the mode is VOIDmode.  Always wrapped in CONST.
+;; 1 Stack frame deallocation barrier.
+;; 2 The address of the global offset table as a source operand.
+
+(define_constants
+  [(CRIS_UNSPEC_PLT 0)
+   (CRIS_UNSPEC_FRAME_DEALLOC 1)
+   (CRIS_UNSPEC_GOT 2)])
+
+;; Register numbers.
+(define_constants
+  [(CRIS_GOT_REGNUM 0)
+   (CRIS_STATIC_CHAIN_REGNUM 7)
+   (CRIS_FP_REGNUM 8)
+   (CRIS_SP_REGNUM 14)
+   (CRIS_SRP_REGNUM 16)
+   (CRIS_AP_REGNUM 17)
+   (CRIS_MOF_REGNUM 18)]
+)
 
 ;; We need an attribute to define whether an instruction can be put in
 ;; a branch-delay slot or not, and whether it has a delay slot.
@@ -77,7 +96,7 @@
 ;; The possible values are "yes", "no" and "has_slot".  Yes/no means if
 ;; the insn is slottable or not.  Has_slot means that the insn is a
 ;; return insn or branch insn (which are not considered slottable since
-;; that is generally true).  Having the semmingly illogical value
+;; that is generally true).  Having the seemingly illogical value
 ;; "has_slot" means we do not have to add another attribute just to say
 ;; that an insn has a delay-slot, since it also infers that it is not
 ;; slottable.  Better names for the attribute were found to be longer and
 ;; mode, but that would need more attributes and hairier, more error
 ;; prone code.
 ;;
-;;  There is an extra constraint, 'Q', which recognizes indirect reg,
-;; except when the reg is pc.  The constraints 'Q' and '>' together match
-;; all possible memory operands that are slottable.
+;;  There is an extra memory constraint, 'Q', which recognizes an indirect
+;; register.  The constraints 'Q' and '>' together match all possible
+;; memory operands that are slottable.
 ;;  For other operands, you need to check if it has a valid "slottable"
 ;; quick-immediate operand, where the particular signedness-variation
 ;; may match the constraints 'I' or 'J'.), and include it in the
 
 (define_attr "cc" "none,clobber,normal" (const_string "normal"))
 
+;; At the moment, this attribute is just used to help bb-reorder do its
+;; work; the default 0 doesn't help it.  Many insns have other lengths,
+;; though none are shorter.
+(define_attr "length" "" (const_int 2))
+
 ;; A branch or return has one delay-slot.  The instruction in the
 ;; delay-slot is always executed, independent of whether the branch is
 ;; taken or not.  Note that besides setting "slottable" to "has_slot",
 (define_delay (eq_attr "slottable" "has_slot")
   [(eq_attr "slottable" "yes") (nil) (nil)])
 \f
+;; Operand and operator predicates.
+
+(include "predicates.md")
+\f
 ;; Test insns.
 
 ;; DImode
 (define_insn "cmpsi"
   [(set (cc0)
        (compare
-        (match_operand:SI 0 "nonimmediate_operand" "r,r,r,r,Q>,Q>,r,r,m,m")
-        (match_operand:SI 1 "general_operand" "I,r,Q>,M,M,r,P,g,M,r")))]
+        (match_operand:SI 0 "nonimmediate_operand" "r,r,r, r,Q>,Q>,r,r,m,m")
+        (match_operand:SI 1 "general_operand"      "I,r,Q>,M,M, r, P,g,M,r")))]
   ""
   "@
    cmpq %1,%0
 
 (define_insn "cmphi"
   [(set (cc0)
-       (compare (match_operand:HI 0 "nonimmediate_operand" "r,r,Q>,Q>,r,m,m")
-                (match_operand:HI 1 "general_operand" "r,Q>,M,r,g,M,r")))]
+       (compare (match_operand:HI 0 "nonimmediate_operand" "r,r, r,Q>,Q>,r,m,m")
+                (match_operand:HI 1 "general_operand"      "r,Q>,M,M, r, g,M,r")))]
   ""
   "@
    cmp.w %1,%0
    cmp.w %1,%0
    test.w %0
+   test.w %0
    cmp.w %0,%1
    cmp.w %1,%0
    test.w %0
    cmp.w %0,%1"
-  [(set_attr "slottable" "yes,yes,yes,yes,no,no,no")])
+  [(set_attr "slottable" "yes,yes,yes,yes,yes,no,no,no")])
 
 (define_insn "cmpqi"
   [(set (cc0)
        (compare
-        (match_operand:QI 0 "nonimmediate_operand" "r,r,r,Q>,Q>,r,m,m")
-        (match_operand:QI 1 "general_operand" "r,Q>,M,M,r,g,M,r")))]
+        (match_operand:QI 0 "nonimmediate_operand" "r,r, r,Q>,Q>,r,m,m")
+        (match_operand:QI 1 "general_operand"      "r,Q>,M,M, r, g,M,r")))]
   ""
   "@
    cmp.b %1,%0
 ;; of zeros starting at bit 0).
 
 ;; SImode.  This mode is the only one needed, since gcc automatically
-;; extends subregs for lower-size modes.  FIXME: Add test-case.
+;; extends subregs for lower-size modes.  FIXME: Add testcase.
 (define_insn "*btst"
   [(set (cc0)
        (zero_extract
 }")
 
 (define_insn "*movdi_insn"
-  [(set (match_operand:DI 0 "nonimmediate_operand" "=r,r,m")
-       (match_operand:DI 1 "general_operand" "r,g,rM"))]
+  [(set (match_operand:DI 0 "nonimmediate_operand" "=r,rx,m")
+       (match_operand:DI 1 "general_operand" "rx,g,rxM"))]
   "register_operand (operands[0], DImode)
    || register_operand (operands[1], DImode)
    || operands[1] == const0_rtx"
 
 ;; SImode
 
-(define_insn "*mov_sidesi_biap"
-  [(set (match_operand:SI 0 "register_operand" "=r,r")
-       (mem:SI (plus:SI
-                (mult:SI (match_operand:SI 1 "register_operand" "r,r")
-                         (match_operand:SI 2 "const_int_operand" "n,n"))
-                (match_operand:SI 3 "register_operand" "r,r"))))
-   (set (match_operand:SI 4 "register_operand" "=*3,r")
+(define_insn "*mov_sidesisf_biap"
+  [(set (match_operand 0 "register_operand" "=r,r,x,x")
+       (mem (plus:SI
+             (mult:SI (match_operand:SI 1 "register_operand" "r,r,r,r")
+                      (match_operand:SI 2 "const_int_operand" "n,n,n,n"))
+             (match_operand:SI 3 "register_operand" "r,r,r,r"))))
+   (set (match_operand:SI 4 "register_operand" "=*3,r,*3,r")
        (plus:SI (mult:SI (match_dup 1)
                          (match_dup 2))
                 (match_dup 3)))]
-  "cris_side_effect_mode_ok (MULT, operands, 4, 3, 1, 2, 0)"
+  "GET_MODE_SIZE (GET_MODE (operands[0])) == UNITS_PER_WORD
+   && cris_side_effect_mode_ok (MULT, operands, 4, 3, 1, 2, 0)"
   "@
    #
-   move.%s0 [%4=%3+%1%T2],%0")
+   move.%s0 [%4=%3+%1%T2],%0
+   #
+   move [%4=%3+%1%T2],%0")
 \f
 ;; move.S1 [rx=ry+i],rz
 ;; avoiding move.S1 [ry=ry+i],rz
   [(set (match_operand:QI 0 "register_operand" "=r,r,r")
        (mem:QI
         (plus:SI (match_operand:SI 1 "cris_bdap_operand" "%r,r,r")
-                 (match_operand:SI 2 "cris_bdap_operand" "r>Ri,r,>Ri"))))
+                 (match_operand:SI 2 "cris_bdap_operand" "r>Rn,r,>Rn"))))
    (set (match_operand:SI 3 "register_operand" "=*1,r,r")
        (plus:SI (match_dup 1)
                 (match_dup 2)))]
   [(set (match_operand:HI 0 "register_operand" "=r,r,r")
        (mem:HI
         (plus:SI (match_operand:SI 1 "cris_bdap_operand" "%r,r,r")
-                 (match_operand:SI 2 "cris_bdap_operand" "r>Ri,r,>Ri"))))
+                 (match_operand:SI 2 "cris_bdap_operand" "r>Rn,r,>Rn"))))
    (set (match_operand:SI 3 "register_operand" "=*1,r,r")
        (plus:SI (match_dup 1)
                 (match_dup 2)))]
 
 ;; SImode
 
-(define_insn "*mov_sidesi"
-  [(set (match_operand:SI 0 "register_operand" "=r,r,r")
-       (mem:SI
-        (plus:SI (match_operand:SI 1 "cris_bdap_operand" "%r,r,r")
-                 (match_operand:SI 2 "cris_bdap_operand" "r>Ri,r,>Ri"))))
-   (set (match_operand:SI 3 "register_operand" "=*1,r,r")
+(define_insn "*mov_sidesisf"
+  [(set (match_operand 0 "register_operand" "=r,r,r,x,x,x")
+       (mem
+        (plus:SI
+         (match_operand:SI 1 "cris_bdap_operand" "%r,r,r,r,r,r")
+         (match_operand:SI 2 "cris_bdap_operand" "r>Rn,r,>Rn,r>Rn,r,>Rn"))))
+   (set (match_operand:SI 3 "register_operand" "=*1,r,r,*1,r,r")
        (plus:SI (match_dup 1)
                 (match_dup 2)))]
-  "cris_side_effect_mode_ok (PLUS, operands, 3, 1, 2, -1, 0)"
-  "*
+  "GET_MODE_SIZE (GET_MODE (operands[0])) == UNITS_PER_WORD
+   && cris_side_effect_mode_ok (PLUS, operands, 3, 1, 2, -1, 0)"
 {
-  if (which_alternative == 0
+  if ((which_alternative == 0 || which_alternative == 3)
       && (GET_CODE (operands[2]) != CONST_INT
          || INTVAL (operands[2]) > 127
          || INTVAL (operands[2]) < -128
          || CONST_OK_FOR_LETTER_P (INTVAL (operands[2]), 'N')
          || CONST_OK_FOR_LETTER_P (INTVAL (operands[2]), 'J')))
-    return \"#\";
-  return \"move.%s0 [%3=%1%S2],%0\";
-}")
+    return "#";
+  if (which_alternative < 3)
+    return "move.%s0 [%3=%1%S2],%0";
+  return "move [%3=%1%S2],%0";
+})
 \f
 ;; Other way around; move to memory.
 
 
 ;; SImode
 
-(define_insn "*mov_sidesi_biap_mem"
-  [(set (mem:SI (plus:SI
-                (mult:SI (match_operand:SI 0 "register_operand" "r,r,r")
-                         (match_operand:SI 1 "const_int_operand" "n,n,n"))
-                (match_operand:SI 2 "register_operand" "r,r,r")))
-       (match_operand:SI 3 "register_operand" "r,r,r"))
-   (set (match_operand:SI 4 "register_operand" "=*2,!3,r")
+(define_insn "*mov_sidesisf_biap_mem"
+  [(set (mem (plus:SI
+             (mult:SI (match_operand:SI 0 "register_operand" "r,r,r,r,r,r")
+                      (match_operand:SI 1 "const_int_operand" "n,n,n,n,n,n"))
+             (match_operand:SI 2 "register_operand" "r,r,r,r,r,r")))
+       (match_operand 3 "register_operand" "r,r,r,x,x,x"))
+   (set (match_operand:SI 4 "register_operand" "=*2,!3,r,*2,!3,r")
        (plus:SI (mult:SI (match_dup 0)
                          (match_dup 1))
                 (match_dup 2)))]
-  "cris_side_effect_mode_ok (MULT, operands, 4, 2, 0, 1, 3)"
+  "GET_MODE_SIZE (GET_MODE (operands[3])) == UNITS_PER_WORD
+   && cris_side_effect_mode_ok (MULT, operands, 4, 2, 0, 1, 3)"
   "@
    #
    #
-   move.%s3 %3,[%4=%2+%0%T1]")
+   move.%s3 %3,[%4=%2+%0%T1]
+   #
+   #
+   move %3,[%4=%2+%0%T1]")
 
 ;; Split for the case above where we're out of luck with register
 ;; allocation (again, the condition isn't checked for that), and we end up
 
 (define_split
   [(parallel
-    [(set (mem (plus:SI
-               (mult:SI (match_operand:SI 0 "register_operand" "")
-                        (match_operand:SI 1 "const_int_operand" ""))
-               (match_operand:SI 2 "register_operand" "")))
+    [(set (match_operator
+          6 "cris_mem_op"
+          [(plus:SI
+            (mult:SI (match_operand:SI 0 "register_operand" "")
+                     (match_operand:SI 1 "const_int_operand" ""))
+            (match_operand:SI 2 "register_operand" ""))])
          (match_operand 3 "register_operand" ""))
      (set (match_operand:SI 4 "register_operand" "")
          (plus:SI (mult:SI (match_dup 0)
                          (match_dup 1))
                 (match_dup 4)))]
   "operands[5]
-     = gen_rtx_MEM (GET_MODE (operands[3]),
-                   gen_rtx_PLUS (SImode,
-                                 gen_rtx_MULT (SImode,
-                                               operands[0], operands[1]),
-                                 operands[2]));")
+     = replace_equiv_address (operands[6],
+                             gen_rtx_PLUS (SImode,
+                                           gen_rtx_MULT (SImode,
+                                                         operands[0],
+                                                         operands[1]),
+                                           operands[2]));")
 \f
 ;; move.s rx,[ry=rz+i]
 ;; FIXME: These could have anonymous mode for operand 2.
 (define_insn "*mov_sideqi_mem"
   [(set (mem:QI
         (plus:SI (match_operand:SI 0 "cris_bdap_operand" "%r,r,r,r")
-                 (match_operand:SI 1 "cris_bdap_operand" "r>Ri,r>Ri,r,>Ri")))
+                 (match_operand:SI 1 "cris_bdap_operand" "r>Rn,r>Rn,r,>Rn")))
        (match_operand:QI 2 "register_operand" "r,r,r,r"))
    (set (match_operand:SI 3 "register_operand" "=*0,!2,r,r")
        (plus:SI (match_dup 0)
 (define_insn "*mov_sidehi_mem"
   [(set (mem:HI
         (plus:SI (match_operand:SI 0 "cris_bdap_operand" "%r,r,r,r")
-                 (match_operand:SI 1 "cris_bdap_operand" "r>Ri,r>Ri,r,>Ri")))
+                 (match_operand:SI 1 "cris_bdap_operand" "r>Rn,r>Rn,r,>Rn")))
        (match_operand:HI 2 "register_operand" "r,r,r,r"))
    (set (match_operand:SI 3 "register_operand" "=*0,!2,r,r")
        (plus:SI (match_dup 0)
 
 ;; SImode
 
-(define_insn "*mov_sidesi_mem"
-  [(set (mem:SI
-        (plus:SI (match_operand:SI 0 "cris_bdap_operand" "%r,r,r,r")
-                 (match_operand:SI 1 "cris_bdap_operand" "r>Ri,r>Ri,r,>Ri")))
-       (match_operand:SI 2 "register_operand" "r,r,r,r"))
-   (set (match_operand:SI 3 "register_operand" "=*0,!2,r,r")
+(define_insn "*mov_sidesisf_mem"
+  [(set (mem
+        (plus:SI
+         (match_operand:SI
+          0 "cris_bdap_operand" "%r,r,r,r,r,r,r,r")
+         (match_operand:SI
+          1 "cris_bdap_operand" "r>Rn,r>Rn,r,>Rn,r>Rn,r>Rn,r,>Rn")))
+       (match_operand 2 "register_operand" "r,r,r,r,x,x,x,x"))
+   (set (match_operand:SI 3 "register_operand" "=*0,!2,r,r,*0,!2,r,r")
        (plus:SI (match_dup 0)
                 (match_dup 1)))]
-  "cris_side_effect_mode_ok (PLUS, operands, 3, 0, 1, -1, 2)"
-  "*
+  "GET_MODE_SIZE (GET_MODE (operands[2])) == UNITS_PER_WORD
+   && cris_side_effect_mode_ok (PLUS, operands, 3, 0, 1, -1, 2)"
 {
-  if (which_alternative == 0
+  if ((which_alternative == 0 || which_alternative == 4)
       && (GET_CODE (operands[1]) != CONST_INT
          || INTVAL (operands[1]) > 127
          || INTVAL (operands[1]) < -128
          || CONST_OK_FOR_LETTER_P (INTVAL (operands[1]), 'N')
          || CONST_OK_FOR_LETTER_P (INTVAL (operands[1]), 'J')))
-    return \"#\";
-  if (which_alternative == 1)
-    return \"#\";
-  return \"move.%s2 %2,[%3=%0%S1]\";
-}")
+    return "#";
+  if (which_alternative == 1 || which_alternative == 5)
+    return "#";
+  if (which_alternative < 4)
+    return "move.%s2 %2,[%3=%0%S1]";
+  return "move %2,[%3=%0%S1]";
+})
 
 ;; Like the biap case, a split where the set in the side-effect gets the
 ;; same register as the input register to the main insn, since the
 
 (define_split
   [(parallel
-    [(set (mem (plus:SI
-               (match_operand:SI 0 "cris_bdap_operand" "")
-               (match_operand:SI 1 "cris_bdap_operand" "")))
+    [(set (match_operator
+          4 "cris_mem_op"
+          [(plus:SI
+            (match_operand:SI 0 "cris_bdap_operand" "")
+            (match_operand:SI 1 "cris_bdap_operand" ""))])
          (match_operand 2 "register_operand" ""))
      (set (match_operand:SI 3 "register_operand" "")
          (plus:SI (match_dup 0) (match_dup 1)))])]
   [(set (match_dup 4) (match_dup 2))
    (set (match_dup 3) (match_dup 0))
    (set (match_dup 3) (plus:SI (match_dup 3) (match_dup 1)))]
-  "operands[4]
-     = gen_rtx_MEM (GET_MODE (operands[2]),
-                   gen_rtx_PLUS (SImode, operands[0], operands[1]));")
+  "")
 \f
 ;; Clear memory side-effect patterns.  It is hard to get to the mode if
 ;; the MEM was anonymous, so there will be one for each mode.
 (define_insn "*clear_sidesi"
   [(set (mem:SI
         (plus:SI (match_operand:SI 0 "cris_bdap_operand" "%r,r,r")
-                 (match_operand:SI 1 "cris_bdap_operand" "r>Ri,r,>Ri")))
+                 (match_operand:SI 1 "cris_bdap_operand" "r>Rn,r,>Rn")))
        (const_int 0))
    (set (match_operand:SI 2 "register_operand" "=*0,r,r")
        (plus:SI (match_dup 0)
 (define_insn "*clear_sidehi"
   [(set (mem:HI
         (plus:SI (match_operand:SI 0 "cris_bdap_operand" "%r,r,r")
-                 (match_operand:SI 1 "cris_bdap_operand" "r>Ri,r,>Ri")))
+                 (match_operand:SI 1 "cris_bdap_operand" "r>Rn,r,>Rn")))
        (const_int 0))
    (set (match_operand:SI 2 "register_operand" "=*0,r,r")
        (plus:SI (match_dup 0)
 (define_insn "*clear_sideqi"
   [(set (mem:QI
         (plus:SI (match_operand:SI 0 "cris_bdap_operand" "%r,r,r")
-                 (match_operand:SI 1 "cris_bdap_operand" "r>Ri,r,>Ri")))
+                 (match_operand:SI 1 "cris_bdap_operand" "r>Rn,r,>Rn")))
        (const_int 0))
    (set (match_operand:SI 2 "register_operand" "=*0,r,r")
        (plus:SI (match_dup 0)
   return \"clear.b [%2=%0%S1]\";
 }")
 \f
-;; To appease test-case gcc.c-torture/execute/920501-2.c (and others) at
+;; To appease testcase gcc.c-torture/execute/920501-2.c (and others) at
 ;; -O0, we need a movdi as a temporary measure.  Here's how things fail:
 ;;  A cmpdi RTX needs reloading (global):
 ;;    (insn 185 326 186 (set (cc0)
 
 (define_insn "*movsi_internal"
   [(set
-    (match_operand:SI 0 "nonimmediate_operand" "=r,r,r,Q>,r,Q>,g,r,r,r,g")
+    (match_operand:SI 0 "nonimmediate_operand" "=r,r, r,Q>,r,Q>,g,r,r, r,g,rQ>,x,  m,x")
     (match_operand:SI 1
     ;; FIXME: We want to put S last, but apparently g matches S.
     ;; It's a bug: an S is not a general_operand and shouldn't match g.
-     "cris_general_operand_or_gotless_symbol" "r,Q>,M,M,I,r,M,n,!S,g,r"))]
+     "cris_general_operand_or_gotless_symbol"   "r,Q>,M,M, I,r, M,n,!S,g,r,x,  rQ>,x,gi"))]
   ""
   "*
 {
     case 10:
       return \"move.d %1,%0\";
 
+    case 11:
+    case 12:
+    case 13:
+    case 14:
+      return \"move %d1,%0\";
+
     case 2:
     case 3:
     case 6:
        }
       return \"move.d %1,%0\";
 
-      case 8:
-       /* FIXME: Try and split this into pieces GCC makes better code of,
-          than this multi-insn pattern.  Synopsis: wrap the GOT-relative
-          symbol into an unspec, and when PIC, recognize the unspec
-          everywhere a symbol is normally recognized.  (The PIC register
-          should be recognized by GCC as pic_offset_table_rtx when needed
-          and similar for PC.)  Each component can then be optimized with
-          the rest of the code; it should be possible to have a constant
-          term added on an unspec.  Don't forget to add a REG_EQUAL (or
-          is it REG_EQUIV) note to the destination.  It might not be
-          worth it.  Measure.
-
-          Note that the 'v' modifier makes PLT references be output as
-          sym:PLT rather than [rPIC+sym:GOTPLT].  */
-       return \"move.d %v1,%0\;add.d %P1,%0\";
+    case 8:
+      /* FIXME: Try and split this into pieces GCC makes better code of,
+        than this multi-insn pattern.  Synopsis: wrap the GOT-relative
+        symbol into an unspec, and when PIC, recognize the unspec
+        everywhere a symbol is normally recognized.  (The PIC register
+        should be recognized by GCC as pic_offset_table_rtx when needed
+        and similar for PC.)  Each component can then be optimized with
+        the rest of the code; it should be possible to have a constant
+        term added on an unspec.  Don't forget to add a REG_EQUAL (or
+        is it REG_EQUIV) note to the destination.  It might not be
+        worth it.  Measure.
+
+        Note that the 'v' modifier makes PLT references be output as
+        sym:PLT rather than [rPIC+sym:GOTPLT].  */
+      if (GET_CODE (operands[1]) == UNSPEC
+         && XINT (operands[1], 1) == CRIS_UNSPEC_GOT)
+       {
+         /* We clobber cc0 rather than set it to GOT.  Should not
+             matter, though.  */
+         CC_STATUS_INIT;
+         if (REGNO (operands[0]) != PIC_OFFSET_TABLE_REGNUM)
+           abort ();
+
+         return \"move.d $pc,%0\;sub.d .:GOTOFF,%0\";
+       }
+
+      return \"move.d %v1,%0\;add.d %P1,%0\";
 
     default:
       return \"BOGUS: %1 to %0\";
     }
 }"
-  [(set_attr "slottable" "yes,yes,yes,yes,yes,yes,no,no,no,no,no")])
+  [(set_attr "slottable" "yes,yes,yes,yes,yes,yes,no,no,no,no,no,yes,yes,no,no")
+   (set_attr "cc" "*,*,*,*,*,*,*,*,*,*,*,none,none,none,none")])
 \f
 ;; Extend operations with side-effect from mem to register, using
 ;; MOVS/MOVU.  These are from mem to register only.
         4 "cris_extend_operator"
         [(mem:QI (plus:SI
                   (match_operand:SI 1 "cris_bdap_operand" "%r,r,r")
-                  (match_operand:SI 2 "cris_bdap_operand" "r>Ri,r,>Ri")))]))
+                  (match_operand:SI 2 "cris_bdap_operand" "r>Rn,r,>Rn")))]))
    (set (match_operand:SI 3 "register_operand" "=*1,r,r")
        (plus:SI (match_dup 1)
                 (match_dup 2)))]
         4 "cris_extend_operator"
         [(mem:QI (plus:SI
                   (match_operand:SI 1 "cris_bdap_operand" "%r,r,r")
-                  (match_operand:SI 2 "cris_bdap_operand" "r>Ri,r,>Ri")))]))
+                  (match_operand:SI 2 "cris_bdap_operand" "r>Rn,r,>Rn")))]))
    (set (match_operand:SI 3 "register_operand" "=*1,r,r")
        (plus:SI (match_dup 1)
                 (match_dup 2)))]
         4 "cris_extend_operator"
         [(mem:HI (plus:SI
                   (match_operand:SI 1 "cris_bdap_operand" "%r,r,r")
-                  (match_operand:SI 2 "cris_bdap_operand" "r>Ri,r,>Ri")))]))
+                  (match_operand:SI 2 "cris_bdap_operand" "r>Rn,r,>Rn")))]))
    (set (match_operand:SI 3 "register_operand" "=*1,r,r")
        (plus:SI (match_dup 1)
                 (match_dup 2)))]
 
 (define_insn "movhi"
   [(set
-    (match_operand:HI 0 "nonimmediate_operand" "=r,r,r,Q>,r,Q>,r,r,r,g,g,r")
-    (match_operand:HI 1 "general_operand" "r,Q>,M,M,I,r,L,O,n,M,r,g"))]
+    (match_operand:HI 0 "nonimmediate_operand" "=r,r, r,Q>,r,Q>,r,r,r,g,g,r,r,x")
+    (match_operand:HI 1 "general_operand"      "r,Q>,M,M, I,r, L,O,n,M,r,g,x,r"))]
   ""
   "*
 {
     case 10:
     case 11:
       return \"move.w %1,%0\";
+    case 12:
+    case 13:
+      return \"move %1,%0\";
     case 2:
     case 3:
     case 9:
       return \"BOGUS: %1 to %0\";
   }
 }"
-  [(set_attr "slottable" "yes,yes,yes,yes,yes,yes,no,yes,no,no,no,no")
-   (set (attr "cc")
-       (if_then_else (eq_attr "alternative" "7")
-                     (const_string "clobber")
-                     (const_string "normal")))])
+  [(set_attr "slottable" "yes,yes,yes,yes,yes,yes,no,yes,no,no,no,no,yes,yes")
+   (set_attr "cc" "*,*,none,none,*,none,*,clobber,*,none,none,*,none,none")])
 
 (define_insn "movstricthi"
   [(set
     (strict_low_part
-     (match_operand:HI 0 "nonimmediate_operand" "+r,r,r,Q>,Q>,g,r,g"))
-    (match_operand:HI 1 "general_operand" "r,Q>,M,M,r,M,g,r"))]
+     (match_operand:HI 0 "nonimmediate_operand" "+r,r, r,Q>,Q>,g,r,g"))
+    (match_operand:HI 1 "general_operand"       "r,Q>,M,M, r, M,g,r"))]
   ""
   "@
    move.w %1,%0
    move.w %1,%0
    move.w %1,%0"
   [(set_attr "slottable" "yes,yes,yes,yes,yes,no,no,no")])
+
+(define_expand "reload_inhi"
+  [(set (match_operand:HI 2 "register_operand" "=r")
+       (match_operand:HI 1 "memory_operand" "m"))
+   (set (match_operand:HI 0 "register_operand" "=x")
+       (match_dup 2))]
+  ""
+  "")
+
+(define_expand "reload_outhi"
+  [(set (match_operand:HI 2 "register_operand" "=r")
+       (match_operand:HI 1 "register_operand" "x"))
+   (set (match_operand:HI 0 "memory_operand" "=m")
+       (match_dup 2))]
+  ""
+  "")
 \f
 (define_insn "movqi"
-  [(set (match_operand:QI 0 "nonimmediate_operand" "=r,Q>,r,r,Q>,r,g,g,r,r")
-       (match_operand:QI 1 "general_operand" "r,r,Q>,M,M,I,M,r,O,g"))]
+  [(set (match_operand:QI 0 "nonimmediate_operand" "=r,Q>,r, r,Q>,r,g,g,r,r,r,x")
+       (match_operand:QI 1 "general_operand"       "r,r, Q>,M,M, I,M,r,O,g,x,r"))]
   ""
   "@
    move.b %1,%0
    clear.b %0
    move.b %1,%0
    moveq %b1,%0
-   move.b %1,%0"
-  [(set_attr "slottable" "yes,yes,yes,yes,yes,yes,no,no,yes,no")
-   (set (attr "cc")
-       (if_then_else (eq_attr "alternative" "8")
-                     (const_string "clobber")
-                     (const_string "normal")))])
+   move.b %1,%0
+   move %1,%0
+   move %1,%0"
+  [(set_attr "slottable" "yes,yes,yes,yes,yes,yes,no,no,yes,no,yes,yes")
+   (set_attr "cc" "*,*,*,*,*,*,*,*,clobber,*,none,none")])
 
 (define_insn "movstrictqi"
   [(set (strict_low_part
-        (match_operand:QI 0 "nonimmediate_operand" "+r,Q>,r,r,Q>,g,g,r"))
-       (match_operand:QI 1 "general_operand" "r,r,Q>,M,M,M,r,g"))]
+        (match_operand:QI 0 "nonimmediate_operand" "+r,Q>,r, r,Q>,g,g,r"))
+       (match_operand:QI 1 "general_operand"        "r,r, Q>,M,M, M,r,g"))]
   ""
   "@
    move.b %1,%0
    move.b %1,%0"
   [(set_attr "slottable" "yes,yes,yes,yes,yes,no,no,no")])
 
+(define_expand "reload_inqi"
+  [(set (match_operand:QI 2 "register_operand" "=r")
+       (match_operand:QI 1 "memory_operand" "m"))
+   (set (match_operand:QI 0 "register_operand" "=x")
+       (match_dup 2))]
+  ""
+  "")
+
+(define_expand "reload_outqi"
+  [(set (match_operand:QI 2 "register_operand" "=r")
+       (match_operand:QI 1 "register_operand" "x"))
+   (set (match_operand:QI 0 "memory_operand" "=m")
+       (match_dup 2))]
+  ""
+  "")
+
 ;; The valid "quick" bit-patterns are, except for 0.0, denormalized
 ;; values REALLY close to 0, and some NaN:s (I think; their exponent is
 ;; all ones); the worthwhile one is "0.0".
 ;; It will use clear, so we know ALL types of immediate 0 never change cc.
 
 (define_insn "movsf"
-  [(set (match_operand:SF 0 "nonimmediate_operand" "=r,Q>,r,r,Q>,g,g,r")
-       (match_operand:SF 1 "general_operand" "r,r,Q>,G,G,G,r,g"))]
+  [(set (match_operand:SF 0 "nonimmediate_operand" "=r,Q>,r, r,Q>,g,g,r,r,x,Q>,m,x, x")
+       (match_operand:SF 1 "general_operand"       "r,r, Q>,G,G, G,r,g,x,r,x, x,Q>,g"))]
   ""
   "@
    move.d %1,%0
    clear.d %0
    clear.d %0
    move.d %1,%0
-   move.d %1,%0"
-  [(set_attr "slottable" "yes,yes,yes,yes,yes,no,no,no")])
+   move.d %1,%0
+   move %1,%0
+   move %1,%0
+   move %1,%0
+   move %1,%0
+   move %1,%0
+   move %1,%0"
+  [(set_attr "slottable" "yes,yes,yes,yes,yes,no,no,no,yes,yes,yes,no,yes,no")])
+
+;; Note that the memory layout of the registers is the reverse of that
+;; of the standard patterns "load_multiple" and "store_multiple".
+(define_insn "*cris_load_multiple"
+  [(match_parallel 0 "cris_load_multiple_op"
+                  [(set (match_operand:SI 1 "register_operand" "=r,r")
+                        (match_operand:SI 2 "memory_operand" "Q,m"))])]
+  ""
+  "movem %O0,%o0"
+  [(set_attr "cc" "none")
+   (set_attr "slottable" "yes,no")
+   ;; Not true, but setting the length to 0 causes return sequences (ret
+   ;; movem) to have the cost they had when (return) included the movem
+   ;; and reduces the performance penalty taken for needing to emit an
+   ;; epilogue (in turn copied by bb-reorder) instead of return patterns.
+   ;; FIXME: temporary change until all insn lengths are correctly
+   ;; described.  FIXME: have better target control over bb-reorder.
+   (set_attr "length" "0")])
+
+(define_insn "*cris_store_multiple"
+  [(match_parallel 0 "cris_store_multiple_op"
+                  [(set (match_operand:SI 2 "memory_operand" "=Q,m")
+                        (match_operand:SI 1 "register_operand" "r,r"))])]
+  ""
+  "movem %o0,%O0"
+  [(set_attr "cc" "none")
+   (set_attr "slottable" "yes,no")])
 \f
 
 ;; Sign- and zero-extend insns with standard names.
   "movs.b %1,%0"
   [(set_attr "slottable" "yes,yes,no")])
 
-;; To do a byte->word exension, extend to dword, exept that the top half
+;; To do a byte->word extension, extend to dword, exept that the top half
 ;; of the register will be clobbered.  FIXME: Perhaps this is not needed.
 
 (define_insn "extendqihi2"
         [(match_operand:QI 1 "register_operand" "0,0,0")
          (mem:QI (plus:SI
                   (match_operand:SI 2 "cris_bdap_operand" "%r,r,r")
-                  (match_operand:SI 3 "cris_bdap_operand" "r>Ri,r,>Ri")))]))
+                  (match_operand:SI 3 "cris_bdap_operand" "r>Rn,r,>Rn")))]))
    (set (match_operand:SI 4 "register_operand" "=*2,r,r")
        (plus:SI (match_dup 2)
                 (match_dup 3)))]
         [(match_operand:HI 1 "register_operand" "0,0,0")
          (mem:HI (plus:SI
                   (match_operand:SI 2 "cris_bdap_operand" "%r,r,r")
-                  (match_operand:SI 3 "cris_bdap_operand" "r>Ri,r,>Ri")))]))
+                  (match_operand:SI 3 "cris_bdap_operand" "r>Rn,r,>Rn")))]))
    (set (match_operand:SI 4 "register_operand" "=*2,r,r")
        (plus:SI (match_dup 2)
                 (match_dup 3)))]
         [(match_operand:SI 1 "register_operand" "0,0,0")
          (mem:SI (plus:SI
                   (match_operand:SI 2 "cris_bdap_operand" "%r,r,r")
-                  (match_operand:SI 3 "cris_bdap_operand" "r>Ri,r,>Ri")))]))
+                  (match_operand:SI 3 "cris_bdap_operand" "r>Rn,r,>Rn")))]))
    (set (match_operand:SI 4 "register_operand" "=*2,r,r")
        (plus:SI (match_dup 2)
                 (match_dup 3)))]
         5 "cris_commutative_orth_op"
         [(mem:QI
           (plus:SI (match_operand:SI 2 "cris_bdap_operand" "%r,r,r")
-                   (match_operand:SI 3 "cris_bdap_operand" "r>Ri,r,>Ri")))
+                   (match_operand:SI 3 "cris_bdap_operand" "r>Rn,r,>Rn")))
          (match_operand:QI 1 "register_operand" "0,0,0")]))
    (set (match_operand:SI 4 "register_operand" "=*2,r,r")
        (plus:SI (match_dup 2)
         5 "cris_commutative_orth_op"
         [(mem:HI
           (plus:SI (match_operand:SI 2 "cris_bdap_operand" "%r,r,r")
-                   (match_operand:SI 3 "cris_bdap_operand" "r>Ri,r,>Ri")))
+                   (match_operand:SI 3 "cris_bdap_operand" "r>Rn,r,>Rn")))
          (match_operand:HI 1 "register_operand" "0,0,0")]))
    (set (match_operand:SI 4 "register_operand" "=*2,r,r")
        (plus:SI (match_dup 2)
         5 "cris_commutative_orth_op"
         [(mem:SI
           (plus:SI (match_operand:SI 2 "cris_bdap_operand" "%r,r,r")
-                   (match_operand:SI 3 "cris_bdap_operand" "r>Ri,r,>Ri")))
+                   (match_operand:SI 3 "cris_bdap_operand" "r>Rn,r,>Rn")))
          (match_operand:SI 1 "register_operand" "0,0,0")]))
    (set (match_operand:SI 4 "register_operand" "=*2,r,r")
        (plus:SI (match_dup 2)
    add.d %M2,%M1,%M0\;ax\;add.d %H2,%H1,%H0")
 
 (define_insn "addsi3"
-  [(set (match_operand:SI 0 "register_operand" "=r,r,r,r,r,r,r,r")
+  [(set (match_operand:SI 0 "register_operand"  "=r,r, r,r,r,r,r,  r")
        (plus:SI
-        (match_operand:SI 1 "register_operand" "%0,0,0,0,0,0,r,r")
-        (match_operand:SI 2 "general_operand" "r,Q>,J,N,n,g,!To,0")))]
+        (match_operand:SI 1 "register_operand" "%0,0, 0,0,0,0,r,  r")
+        (match_operand:SI 2 "general_operand"   "r,Q>,J,N,n,g,!To,0")))]
 
 ;; The last constraint is due to that after reload, the '%' is not
 ;; honored, and canonicalization doesn't care about keeping the same
  [(set_attr "slottable" "yes,yes,yes,yes,no,no,no,yes")])
 \f
 (define_insn "addhi3"
-  [(set (match_operand:HI 0 "register_operand" "=r,r,r,r,r,r")
-       (plus:HI (match_operand:HI 1 "register_operand" "%0,0,0,0,0,r")
-                (match_operand:HI 2 "general_operand" "r,Q>,J,N,g,!To")))]
+  [(set (match_operand:HI 0 "register_operand"         "=r,r, r,r,r,r")
+       (plus:HI (match_operand:HI 1 "register_operand" "%0,0, 0,0,0,r")
+                (match_operand:HI 2 "general_operand"   "r,Q>,J,N,g,!To")))]
   ""
   "@
    add.w %2,%0
    (set_attr "cc" "normal,normal,clobber,clobber,normal,normal")])
 
 (define_insn "addqi3"
-  [(set (match_operand:QI 0 "register_operand" "=r,r,r,r,r,r,r")
-       (plus:QI (match_operand:QI 1 "register_operand" "%0,0,0,0,0,0,r")
-                (match_operand:QI 2 "general_operand" "r,Q>,J,N,O,g,!To")))]
+  [(set (match_operand:QI 0 "register_operand"         "=r,r, r,r,r,r,r")
+       (plus:QI (match_operand:QI 1 "register_operand" "%0,0, 0,0,0,0,r")
+                (match_operand:QI 2 "general_operand"   "r,Q>,J,N,O,g,!To")))]
   ""
   "@
    add.b %2,%0
    sub.d %M2,%M1,%M0\;ax\;sub.d %H2,%H1,%H0")
 
 (define_insn "subsi3"
-  [(set (match_operand:SI 0 "register_operand" "=r,r,r,r,r,r,r,r")
+  [(set (match_operand:SI 0 "register_operand" "=r,r, r,r,r,r,r,r")
        (minus:SI
-        (match_operand:SI 1 "register_operand" "0,0,0,0,0,0,0,r")
-        (match_operand:SI 2 "general_operand" "r,Q>,J,N,P,n,g,!To")))]
+        (match_operand:SI 1 "register_operand" "0,0, 0,0,0,0,0,r")
+        (match_operand:SI 2 "general_operand"  "r,Q>,J,N,P,n,g,!To")))]
   ""
 
 ;; This does not do the optimal: "addu.w 65535,r0" when %2 is negative.
   [(set_attr "slottable" "yes,yes,yes,yes,no,no,no,no")])
 \f
 (define_insn "subhi3"
-  [(set (match_operand:HI 0 "register_operand" "=r,r,r,r,r,r")
-       (minus:HI (match_operand:HI 1 "register_operand" "0,0,0,0,0,r")
-                 (match_operand:HI 2 "general_operand" "r,Q>,J,N,g,!To")))]
+  [(set (match_operand:HI 0 "register_operand"         "=r,r, r,r,r,r")
+       (minus:HI (match_operand:HI 1 "register_operand" "0,0, 0,0,0,r")
+                 (match_operand:HI 2 "general_operand"  "r,Q>,J,N,g,!To")))]
   ""
   "@
    sub.w %2,%0
    (set_attr "cc" "normal,normal,clobber,clobber,normal,normal")])
 
 (define_insn "subqi3"
-  [(set (match_operand:QI 0 "register_operand" "=r,r,r,r,r,r")
-       (minus:QI (match_operand:QI 1 "register_operand" "0,0,0,0,0,r")
-                 (match_operand:QI 2 "general_operand" "r,Q>,J,N,g,!To")))]
+  [(set (match_operand:QI 0 "register_operand"         "=r,r, r,r,r,r")
+       (minus:QI (match_operand:QI 1 "register_operand" "0,0, 0,0,0,r")
+                 (match_operand:QI 2 "general_operand"  "r,Q>,J,N,g,!To")))]
   ""
   "@
    sub.b %2,%0
           6 "cris_extend_operator"
           [(mem:QI
             (plus:SI (match_operand:SI 2 "cris_bdap_operand" "%r,r,r")
-                     (match_operand:SI 3 "cris_bdap_operand" "r>Ri,r,>Ri")
+                     (match_operand:SI 3 "cris_bdap_operand" "r>Rn,r,>Rn")
                      ))])]))
    (set (match_operand:SI 4 "register_operand" "=*2,r,r")
        (plus:SI (match_dup 2)
           6 "cris_extend_operator"
           [(mem:QI
             (plus:SI (match_operand:SI 2 "cris_bdap_operand" "%r,r,r")
-                     (match_operand:SI 3 "cris_bdap_operand" "r>Ri,r,>Ri")
+                     (match_operand:SI 3 "cris_bdap_operand" "r>Rn,r,>Rn")
                      ))])]))
    (set (match_operand:SI 4 "register_operand" "=*2,r,r")
        (plus:SI (match_dup 2)
           6 "cris_extend_operator"
           [(mem:HI
             (plus:SI (match_operand:SI 2 "cris_bdap_operand" "%r,r,r")
-                     (match_operand:SI 3 "cris_bdap_operand" "r>Ri,r,>Ri")
+                     (match_operand:SI 3 "cris_bdap_operand" "r>Rn,r,>Rn")
                      ))])]))
    (set (match_operand:SI 4 "register_operand" "=*2,r,r")
        (plus:SI (match_dup 2)
          5 "cris_extend_operator"
          [(mem:QI (plus:SI
                    (match_operand:SI 2 "cris_bdap_operand" "%r,r,r")
-                   (match_operand:SI 3 "cris_bdap_operand" "r>Ri,r,>Ri")))])
+                   (match_operand:SI 3 "cris_bdap_operand" "r>Rn,r,>Rn")))])
         (match_operand:HI 1 "register_operand" "0,0,0")))
    (set (match_operand:SI 4 "register_operand" "=*2,r,r")
        (plus:SI (match_dup 2)
           5 "cris_extend_operator"
           [(mem:QI (plus:SI
                     (match_operand:SI 2 "cris_bdap_operand" "%r,r,r")
-                    (match_operand:SI 3 "cris_bdap_operand" "r>Ri,r,>Ri")))])
+                    (match_operand:SI 3 "cris_bdap_operand" "r>Rn,r,>Rn")))])
          (match_operand:SI 1 "register_operand" "0,0,0")]))
    (set (match_operand:SI 4 "register_operand" "=*2,r,r")
        (plus:SI (match_dup 2)
           5 "cris_extend_operator"
           [(mem:HI (plus:SI
                     (match_operand:SI 2 "cris_bdap_operand" "%r,r,r")
-                    (match_operand:SI 3 "cris_bdap_operand" "r>Ri,r,>Ri")))])
+                    (match_operand:SI 3 "cris_bdap_operand" "r>Rn,r,>Rn")))])
          (match_operand:SI 1 "register_operand" "0,0,0")]))
    (set (match_operand:SI 4 "register_operand" "=*2,r,r")
        (plus:SI (match_dup 2)
 (define_insn "umulhisi3"
   [(set (match_operand:SI 0 "register_operand" "=r")
        (mult:SI
-        (zero_extend:SI (match_operand:HI 1 "register_operand" "0"))
-        (zero_extend:SI (match_operand:HI 2 "register_operand" "r"))))]
+        (zero_extend:SI (match_operand:HI 1 "register_operand" "%0"))
+        (zero_extend:SI (match_operand:HI 2 "register_operand" "r"))))
+   (clobber (match_scratch:SI 3 "=h"))]
   "TARGET_HAS_MUL_INSNS"
-  "mulu.w %2,%0"
-  [(set_attr "slottable" "yes")
+  "%!mulu.w %2,%0"
+  [(set (attr "slottable")
+       (if_then_else (ne (symbol_ref "TARGET_MUL_BUG") (const_int 0))
+                     (const_string "no")
+                     (const_string "yes")))
    ;; Just N unusable here, but let's be safe.
    (set_attr "cc" "clobber")])
 
 (define_insn "umulqihi3"
   [(set (match_operand:HI 0 "register_operand" "=r")
        (mult:HI
-        (zero_extend:HI (match_operand:QI 1 "register_operand" "0"))
-        (zero_extend:HI (match_operand:QI 2 "register_operand" "r"))))]
+        (zero_extend:HI (match_operand:QI 1 "register_operand" "%0"))
+        (zero_extend:HI (match_operand:QI 2 "register_operand" "r"))))
+   (clobber (match_scratch:SI 3 "=h"))]
   "TARGET_HAS_MUL_INSNS"
-  "mulu.b %2,%0"
-  [(set_attr "slottable" "yes")
+  "%!mulu.b %2,%0"
+  [(set (attr "slottable")
+       (if_then_else (ne (symbol_ref "TARGET_MUL_BUG") (const_int 0))
+                     (const_string "no")
+                     (const_string "yes")))
    ;; Not exactly sure, but let's be safe.
    (set_attr "cc" "clobber")])
 
 
 (define_insn "mulsi3"
   [(set (match_operand:SI 0 "register_operand" "=r")
-       (mult:SI (match_operand:SI 1 "register_operand" "0")
-                (match_operand:SI 2 "register_operand" "r")))]
+       (mult:SI (match_operand:SI 1 "register_operand" "%0")
+                (match_operand:SI 2 "register_operand" "r")))
+   (clobber (match_scratch:SI 3 "=h"))]
   "TARGET_HAS_MUL_INSNS"
-  "muls.d %2,%0"
-  [(set_attr "slottable" "yes")
+  "%!muls.d %2,%0"
+  [(set (attr "slottable")
+       (if_then_else (ne (symbol_ref "TARGET_MUL_BUG") (const_int 0))
+                     (const_string "no")
+                     (const_string "yes")))
    ;; Just N unusable here, but let's be safe.
    (set_attr "cc" "clobber")])
 \f
 (define_insn "mulqihi3"
   [(set (match_operand:HI 0 "register_operand" "=r")
        (mult:HI
-        (sign_extend:HI (match_operand:QI 1 "register_operand" "0"))
-        (sign_extend:HI (match_operand:QI 2 "register_operand" "r"))))]
+        (sign_extend:HI (match_operand:QI 1 "register_operand" "%0"))
+        (sign_extend:HI (match_operand:QI 2 "register_operand" "r"))))
+   (clobber (match_scratch:SI 3 "=h"))]
   "TARGET_HAS_MUL_INSNS"
-  "muls.b %2,%0"
-  [(set_attr "slottable" "yes")
+  "%!muls.b %2,%0"
+  [(set (attr "slottable")
+       (if_then_else (ne (symbol_ref "TARGET_MUL_BUG") (const_int 0))
+                     (const_string "no")
+                     (const_string "yes")))
    (set_attr "cc" "clobber")])
 
 (define_insn "mulhisi3"
   [(set (match_operand:SI 0 "register_operand" "=r")
        (mult:SI
-        (sign_extend:SI (match_operand:HI 1 "register_operand" "0"))
-        (sign_extend:SI (match_operand:HI 2 "register_operand" "r"))))]
+        (sign_extend:SI (match_operand:HI 1 "register_operand" "%0"))
+        (sign_extend:SI (match_operand:HI 2 "register_operand" "r"))))
+   (clobber (match_scratch:SI 3 "=h"))]
   "TARGET_HAS_MUL_INSNS"
-  "muls.w %2,%0"
-  [(set_attr "slottable" "yes")
+  "%!muls.w %2,%0"
+  [(set (attr "slottable")
+       (if_then_else (ne (symbol_ref "TARGET_MUL_BUG") (const_int 0))
+                     (const_string "no")
+                     (const_string "yes")))
    ;; Just N unusable here, but let's be safe.
    (set_attr "cc" "clobber")])
 
 (define_insn "mulsidi3"
   [(set (match_operand:DI 0 "register_operand" "=r")
        (mult:DI
-        (sign_extend:DI (match_operand:SI 1 "register_operand" "0"))
-        (sign_extend:DI (match_operand:SI 2 "register_operand" "r"))))]
+        (sign_extend:DI (match_operand:SI 1 "register_operand" "%0"))
+        (sign_extend:DI (match_operand:SI 2 "register_operand" "r"))))
+   (clobber (match_scratch:SI 3 "=h"))]
   "TARGET_HAS_MUL_INSNS"
-  "muls.d %2,%M0\;move $mof,%H0")
+  "%!muls.d %2,%M0\;move $mof,%H0")
 
 (define_insn "umulsidi3"
   [(set (match_operand:DI 0 "register_operand" "=r")
        (mult:DI
-        (zero_extend:DI (match_operand:SI 1 "register_operand" "0"))
-        (zero_extend:DI (match_operand:SI 2 "register_operand" "r"))))]
+        (zero_extend:DI (match_operand:SI 1 "register_operand" "%0"))
+        (zero_extend:DI (match_operand:SI 2 "register_operand" "r"))))
+   (clobber (match_scratch:SI 3 "=h"))]
   "TARGET_HAS_MUL_INSNS"
-  "mulu.d %2,%M0\;move $mof,%H0")
-
-;; This pattern would probably not be needed if we add "mof" in its own
-;; register class (and open a can of worms about /not/ pairing it with a
-;; "normal" register).  Having multiple register classes here, and
-;; applicable to the v10 variant only, seems worse than having these two
-;; patterns with multi-insn contents for now (may change; having a free
-;; call-clobbered register is worth some trouble).
+  "%!mulu.d %2,%M0\;move $mof,%H0")
+
+;; These two patterns may be expressible by other means, perhaps by making
+;; [u]?mulsidi3 a define_expand.
+
+;; Due to register allocation braindamage, the clobber 1,2 alternatives
+;; cause a move into the clobbered register *before* the insn, then
+;; after the insn, mof is moved too, rather than the clobber assigned
+;; the last mof target.  This became apparent when making MOF and SRP
+;; visible registers, with the necessary tweak to smulsi3_highpart.
+;; Because these patterns are used in division by constants, that damage
+;; is visible (ipps regression tests).  Therefore the last two
+;; alternatives, "helping" reload to avoid an unnecessary move, but
+;; punished by force of one "?".  Check code from "int d (int a) {return
+;; a / 1000;}" and unsigned.  FIXME: Comment above was for 3.2, revisit.
 
 (define_insn "smulsi3_highpart"
-  [(set (match_operand:SI 0 "nonimmediate_operand" "=r,r,m")
+  [(set (match_operand:SI 0 "nonimmediate_operand" "=h,h,?r,?r")
        (truncate:SI
         (lshiftrt:DI
          (mult:DI
-          (sign_extend:DI (match_operand:SI 1 "register_operand" "%0,r,r"))
-          (sign_extend:DI (match_operand:SI 2 "register_operand" "r,r,r")))
+          (sign_extend:DI (match_operand:SI 1 "register_operand" "r,r,0,r"))
+          (sign_extend:DI (match_operand:SI 2 "register_operand" "r,r,r,0")))
          (const_int 32))))
-   (clobber (match_scratch:SI 3 "=X,1,1"))]
+   (clobber (match_scratch:SI 3 "=1,2,h,h"))]
   "TARGET_HAS_MUL_INSNS"
-  "muls.d %2,%1\;move $mof,%0"
-  [(set_attr "cc" "clobber")])
+  "@
+   %!muls.d %2,%1
+   %!muls.d %1,%2
+   %!muls.d %2,%1\;move $mof,%0
+   %!muls.d %1,%2\;move $mof,%0"
+  [(set_attr "slottable" "yes,yes,no,no")
+   (set_attr "cc" "clobber")])
 
 (define_insn "umulsi3_highpart"
-  [(set (match_operand:SI 0 "nonimmediate_operand" "=r,r,m")
+  [(set (match_operand:SI 0 "register_operand" "=h,h,?r,?r")
        (truncate:SI
         (lshiftrt:DI
          (mult:DI
-          (zero_extend:DI (match_operand:SI 1 "register_operand" "%0,r,r"))
-          (zero_extend:DI (match_operand:SI 2 "register_operand" "r,r,r")))
+          (zero_extend:DI (match_operand:SI 1 "register_operand" "r,r,0,r"))
+          (zero_extend:DI (match_operand:SI 2 "register_operand" "r,r,r,0")))
          (const_int 32))))
-   (clobber (match_scratch:SI 3 "=X,1,1"))]
+   (clobber (match_scratch:SI 3 "=1,2,h,h"))]
   "TARGET_HAS_MUL_INSNS"
-  "mulu.d %2,%1\;move $mof,%0"
-  [(set_attr "cc" "clobber")])
+  "@
+   %!mulu.d %2,%1
+   %!mulu.d %1,%2
+   %!mulu.d %2,%1\;move $mof,%0
+   %!mulu.d %1,%2\;move $mof,%0"
+  [(set_attr "slottable" "yes,yes,no,no")
+   (set_attr "cc" "clobber")])
 \f
 ;; Divide and modulus instructions.  CRIS only has a step instruction.
 
 
 (define_insn "*andsi_movu"
   [(set (match_operand:SI 0 "register_operand" "=r,r,r")
-       (and:SI (match_operand:SI 1 "nonimmediate_operand" "%r,Q>,m")
+       (and:SI (match_operand:SI 1 "nonimmediate_operand" "%r,Q,To")
                (match_operand:SI 2 "const_int_operand" "n,n,n")))]
-  "INTVAL (operands[2]) == 255 || INTVAL (operands[2]) == 65535"
+  "(INTVAL (operands[2]) == 255 || INTVAL (operands[2]) == 65535)
+   && (GET_CODE (operands[1]) != MEM || ! MEM_VOLATILE_P (operands[1]))"
   "movu.%z2 %1,%0"
   [(set_attr "slottable" "yes,yes,no")])
 
 (define_insn "*andsi_clear"
-  [(set (match_operand:SI 0 "nonimmediate_operand" "=r,r,Q>,Q>,m,m")
+  [(set (match_operand:SI 0 "nonimmediate_operand" "=r,r,Q,Q,To,To")
        (and:SI (match_operand:SI 1 "nonimmediate_operand" "%0,0,0,0,0,0")
                (match_operand:SI 2 "const_int_operand" "P,n,P,n,P,n")))]
-  "INTVAL (operands[2]) == -65536 || INTVAL (operands[2]) == -256"
+  "(INTVAL (operands[2]) == -65536 || INTVAL (operands[2]) == -256)
+   && (GET_CODE (operands[0]) != MEM || ! MEM_VOLATILE_P (operands[0]))"
   "@
    cLear.b %0
    cLear.w %0
 ;; improved reload pass.
 
 (define_insn "*expanded_andsi"
-  [(set (match_operand:SI 0 "register_operand" "=r,r,r,r,r")
-       (and:SI (match_operand:SI 1 "register_operand" "%0,0,0,0,r")
-               (match_operand:SI 2 "general_operand" "I,r,Q>,g,!To")))]
+  [(set (match_operand:SI 0 "register_operand"        "=r,r,r, r,r")
+       (and:SI (match_operand:SI 1 "register_operand" "%0,0,0, 0,r")
+               (match_operand:SI 2 "general_operand"   "I,r,Q>,g,!To")))]
   ""
   "@
    andq %2,%0
 
 (define_insn "*andhi_movu"
   [(set (match_operand:HI 0 "register_operand" "=r,r,r")
-       (and:HI (match_operand:HI 1 "nonimmediate_operand" "r,Q>,m")
+       (and:HI (match_operand:HI 1 "nonimmediate_operand" "r,Q,To")
                (const_int 255)))]
-  ""
+  "GET_CODE (operands[1]) != MEM || ! MEM_VOLATILE_P (operands[1])"
   "mOvu.b %1,%0"
   [(set_attr "slottable" "yes,yes,no")])
 
-(define_insn "*andhi_clear_signed"
-  [(set (match_operand:HI 0 "nonimmediate_operand" "=r,Q>,m")
+(define_insn "*andhi_clear"
+  [(set (match_operand:HI 0 "nonimmediate_operand" "=r,Q,To")
        (and:HI (match_operand:HI 1 "nonimmediate_operand" "0,0,0")
                (const_int -256)))]
-  ""
-  "cLear.b %0"
-  [(set_attr "slottable" "yes,yes,no")
-   (set_attr "cc" "none")])
-
-;; FIXME: Either this or the pattern above should be redundant.
-(define_insn "*andhi_clear_unsigned"
-  [(set (match_operand:HI 0 "nonimmediate_operand" "=r,Q>,m")
-       (and:HI (match_operand:HI 1 "nonimmediate_operand" "0,0,0")
-               (const_int 65280)))]
-  ""
+  "GET_CODE (operands[0]) != MEM || ! MEM_VOLATILE_P (operands[0])"
   "cLear.b %0"
   [(set_attr "slottable" "yes,yes,no")
    (set_attr "cc" "none")])
 ;; Catch-all andhi3 pattern.
 
 (define_insn "*expanded_andhi"
-  [(set (match_operand:HI 0 "register_operand" "=r,r,r,r,r,r,r")
-       (and:HI (match_operand:HI 1 "register_operand" "%0,0,0,0,0,0,r")
-               (match_operand:HI 2 "general_operand" "I,r,Q>,L,O,g,!To")))]
+  [(set (match_operand:HI 0 "register_operand"        "=r,r,r, r,r,r,r")
+       (and:HI (match_operand:HI 1 "register_operand" "%0,0,0, 0,0,0,r")
+               (match_operand:HI 2 "general_operand"   "I,r,Q>,L,O,g,!To")))]
 
 ;; Sidenote: the tightening from "general_operand" to
 ;; "register_operand" for operand 1 actually increased the register
 
 (define_insn "*andhi_lowpart"
   [(set (strict_low_part
-        (match_operand:HI 0 "register_operand" "=r,r,r,r,r,r"))
-       (and:HI (match_operand:HI 1 "register_operand" "%0,0,0,0,0,r")
-               (match_operand:HI 2 "general_operand" "r,Q>,L,O,g,!To")))]
+        (match_operand:HI 0 "register_operand"        "=r,r, r,r,r,r"))
+       (and:HI (match_operand:HI 1 "register_operand" "%0,0, 0,0,0,r")
+               (match_operand:HI 2 "general_operand"   "r,Q>,L,O,g,!To")))]
   ""
   "@
    and.w %2,%0
    (set_attr "cc" "normal,normal,normal,clobber,normal,normal")])
 \f
 (define_insn "andqi3"
-  [(set (match_operand:QI 0 "register_operand" "=r,r,r,r,r,r")
-       (and:QI (match_operand:QI 1 "register_operand" "%0,0,0,0,0,r")
-               (match_operand:QI 2 "general_operand" "I,r,Q>,O,g,!To")))]
+  [(set (match_operand:QI 0 "register_operand"        "=r,r,r, r,r,r")
+       (and:QI (match_operand:QI 1 "register_operand" "%0,0,0, 0,0,r")
+               (match_operand:QI 2 "general_operand"   "I,r,Q>,O,g,!To")))]
   ""
   "@
    andq %2,%0
 
 (define_insn "*andqi_lowpart"
   [(set (strict_low_part
-        (match_operand:QI 0 "register_operand" "=r,r,r,r,r"))
-       (and:QI (match_operand:QI 1 "register_operand" "%0,0,0,0,r")
-               (match_operand:QI 2 "general_operand" "r,Q>,O,g,!To")))]
+        (match_operand:QI 0 "register_operand"        "=r,r, r,r,r"))
+       (and:QI (match_operand:QI 1 "register_operand" "%0,0, 0,0,r")
+               (match_operand:QI 2 "general_operand"   "r,Q>,O,g,!To")))]
   ""
   "@
    and.b %2,%0
 ;; with andsi3.
 
 (define_insn "iorsi3"
-  [(set (match_operand:SI 0 "register_operand" "=r,r,r,r,r,r")
-       (ior:SI (match_operand:SI 1 "register_operand" "%0,0,0,0,0,r")
-               (match_operand:SI 2 "general_operand" "I,r,Q>,n,g,!To")))]
+  [(set (match_operand:SI 0 "register_operand"        "=r,r,r, r,r,r")
+       (ior:SI (match_operand:SI 1 "register_operand" "%0,0,0, 0,0,r")
+               (match_operand:SI 2 "general_operand"  "I, r,Q>,n,g,!To")))]
   ""
   "@
    orq %2,%0
    (set_attr "cc" "normal,normal,normal,clobber,normal,normal")])
 
 (define_insn "iorhi3"
-  [(set (match_operand:HI 0 "register_operand" "=r,r,r,r,r,r,r")
-       (ior:HI (match_operand:HI 1 "register_operand" "%0,0,0,0,0,0,r")
-               (match_operand:HI 2 "general_operand" "I,r,Q>,L,O,g,!To")))]
+  [(set (match_operand:HI 0 "register_operand"        "=r,r,r, r,r,r,r")
+       (ior:HI (match_operand:HI 1 "register_operand" "%0,0,0, 0,0,0,r")
+               (match_operand:HI 2 "general_operand"   "I,r,Q>,L,O,g,!To")))]
   ""
   "@
    orq %2,%0
    (set_attr "cc" "clobber,normal,normal,normal,clobber,normal,normal")])
 
 (define_insn "iorqi3"
-  [(set (match_operand:QI 0 "register_operand" "=r,r,r,r,r,r")
-       (ior:QI (match_operand:QI 1 "register_operand" "%0,0,0,0,0,r")
-               (match_operand:QI 2 "general_operand" "I,r,Q>,O,g,!To")))]
+  [(set (match_operand:QI 0 "register_operand"        "=r,r,r, r,r,r")
+       (ior:QI (match_operand:QI 1 "register_operand" "%0,0,0, 0,0,r")
+               (match_operand:QI 2 "general_operand"   "I,r,Q>,O,g,!To")))]
   ""
   "@
    orq %2,%0
 ;; normal code too.
 
 (define_insn "uminsi3"
-  [(set (match_operand:SI 0 "register_operand" "=r,r,r,r")
-       (umin:SI  (match_operand:SI 1 "register_operand" "%0,0,0,r")
-                 (match_operand:SI 2 "general_operand" "r,Q>,g,!STo")))]
+  [(set (match_operand:SI 0 "register_operand"          "=r,r, r,r")
+       (umin:SI  (match_operand:SI 1 "register_operand" "%0,0, 0,r")
+                 (match_operand:SI 2 "general_operand"   "r,Q>,g,!STo")))]
   ""
   "*
 {
   "jump %0")
 
 ;; Return insn.  Used whenever the epilogue is very simple; if it is only
-;; a single ret or jump [sp+] or a contiguous sequence of movem:able saved
-;; registers.  No allocated stack space is allowed.
+;; a single ret or jump [sp+].  No allocated stack space or saved
+;; registers are allowed.
 ;; Note that for this pattern, although named, it is ok to check the
 ;; context of the insn in the test, not only compiler switches.
 
-(define_insn "return"
+(define_expand "return"
   [(return)]
   "cris_simple_epilogue ()"
-  "*
-{
-  int i;
+  "cris_expand_return (cris_return_address_on_stack ()); DONE;")
 
-  /* Just needs to hold a 'movem [sp+],rN'.  */
-  char rd[sizeof (\"movem [$sp+],$r99\")];
-
-  /* Try to avoid reorg.c surprises; avoid emitting invalid code, prefer
-     crashing.  This test would have avoided invalid code for target/7042.  */
-  if (current_function_epilogue_delay_list != NULL)
-    abort ();
-
-  *rd = 0;
-
-  /* Start from the last call-saved register.  We know that we have a
-     simple epilogue, so we just have to find the last register in the
-     movem sequence.  */
-  for (i = 8; i >= 0; i--)
-    if (regs_ever_live[i]
-       || (i == PIC_OFFSET_TABLE_REGNUM
-           && current_function_uses_pic_offset_table))
-      break;
-
-  if (i >= 0)
-    sprintf (rd, \"movem [$sp+],$%s\", reg_names [i]);
-
-  if (regs_ever_live[CRIS_SRP_REGNUM])
-    {
-      if (*rd)
-       output_asm_insn (rd, operands);
-      return \"jump [$sp+]\";
-    }
-
-  if (*rd)
-    {
-      output_asm_insn (\"reT\", operands);
-      output_asm_insn (rd, operands);
-      return \"\";
-    }
-
-  return \"ret%#\";
-}"
+(define_insn "*return_expanded"
+  [(return)]
+  ""
+{
+  return cris_return_address_on_stack_for_return ()
+    ? "jump [$sp+]" : "ret%#";
+}
   [(set (attr "slottable")
-       (if_then_else
-        (ne (symbol_ref "regs_ever_live[CRIS_SRP_REGNUM]") (const_int 0))
-        (const_string "no")         ; If jump then not slottable.
-        (if_then_else
-         (ne (symbol_ref
-              "(regs_ever_live[0]
-                || (flag_pic != 0 && regs_ever_live[1])
-                || (PIC_OFFSET_TABLE_REGNUM == 0
-                    && cris_cfun_uses_pic_table ()))")
-             (const_int 0))
-         (const_string "no") ; ret+movem [sp+],rx: slot already filled.
-         (const_string "has_slot")))) ; If ret then need to fill a slot.
-   (set_attr "cc" "none")])
+       (if_then_else
+        (ne (symbol_ref
+             "(cris_return_address_on_stack_for_return ())")
+            (const_int 0))
+        (const_string "no")
+        (const_string "has_slot")))])
+
+(define_expand "prologue"
+  [(const_int 0)]
+  "TARGET_PROLOGUE_EPILOGUE"
+  "cris_expand_prologue (); DONE;")
+
+;; Note that the (return) from the expander itself is always the last
+;; insn in the epilogue.
+(define_expand "epilogue"
+  [(const_int 0)]
+  "TARGET_PROLOGUE_EPILOGUE"
+  "cris_expand_epilogue (); DONE;")
 \f
 ;; Conditional branches.
 
 (define_expand "call"
   [(parallel [(call (match_operand:QI 0 "cris_mem_call_operand" "")
                    (match_operand 1 "general_operand" ""))
-             ;; 16 is the srp (can't use the symbolic name here)
-             (clobber (reg:SI 16))])]
+             (clobber (reg:SI CRIS_SRP_REGNUM))])]
   ""
   "
 {
 
       /* It might be that code can be generated that jumps to 0 (or to a
         specific address).  Don't abort on that.  At least there's a
-        test-case.  */
+        testcase.  */
       if (CONSTANT_ADDRESS_P (op0) && GET_CODE (op0) != CONST_INT)
        {
          if (no_new_pseudos)
               for the symbol cause bad recombinatorial effects?  */
            op0 = force_reg (Pmode,
                             gen_rtx_CONST
-                            (VOIDmode,
+                            (Pmode,
                              gen_rtx_UNSPEC (VOIDmode,
-                                             gen_rtvec (1, op0), 0)));
+                                             gen_rtvec (1, op0),
+                                             CRIS_UNSPEC_PLT)));
          else
            abort ();
 
-         operands[0] = gen_rtx_MEM (GET_MODE (operands[0]), op0);
+         operands[0] = replace_equiv_address (operands[0], op0);
        }
     }
 }")
 
 ;; Accept *anything* as operand 1.  Accept operands for operand 0 in
-;; order of preference (Q includes r, but r is shorter, faster)
+;; order of preference.
 
 (define_insn "*expanded_call"
   [(call (mem:QI (match_operand:SI
                  0 "cris_general_operand_or_plt_symbol" "r,Q>,g,S"))
         (match_operand 1 "" ""))
-   (clobber (reg:SI 16))] ;; 16 is the srp (can't use symbolic name)
+   (clobber (reg:SI CRIS_SRP_REGNUM))]
   "! TARGET_AVOID_GOTPLT"
   "jsr %0")
 
   [(call (mem:QI (match_operand:SI
                  0 "cris_general_operand_or_plt_symbol" "r,Q>,g"))
         (match_operand 1 "" ""))
-   (clobber (reg:SI 16))] ;; 16 is the srp (can't use symbolic name)
+   (clobber (reg:SI CRIS_SRP_REGNUM))]
   "TARGET_AVOID_GOTPLT"
   "jsr %0")
 
   [(parallel [(set (match_operand 0 "" "")
                   (call (match_operand:QI 1 "cris_mem_call_operand" "")
                         (match_operand 2 "" "")))
-             ;; 16 is the srp (can't use symbolic name)
-             (clobber (reg:SI 16))])]
+             (clobber (reg:SI CRIS_SRP_REGNUM))])]
   ""
   "
 {
 
       /* It might be that code can be generated that jumps to 0 (or to a
         specific address).  Don't abort on that.  At least there's a
-        test-case.  */
+        testcase.  */
       if (CONSTANT_ADDRESS_P (op1) && GET_CODE (op1) != CONST_INT)
        {
          if (no_new_pseudos)
               for the symbol cause bad recombinatorial effects?  */
            op1 = force_reg (Pmode,
                             gen_rtx_CONST
-                            (VOIDmode,
+                            (Pmode,
                              gen_rtx_UNSPEC (VOIDmode,
-                                             gen_rtvec (1, op1), 0)));
+                                             gen_rtvec (1, op1),
+                                             CRIS_UNSPEC_PLT)));
          else
            abort ();
 
-         operands[1] = gen_rtx_MEM (GET_MODE (operands[1]), op1);
+         operands[1] = replace_equiv_address (operands[1], op1);
        }
     }
 }")
        (call (mem:QI (match_operand:SI
                       1 "cris_general_operand_or_plt_symbol" "r,Q>,g,S"))
              (match_operand 2 "" "")))
-   (clobber (reg:SI 16))]
+   (clobber (reg:SI CRIS_SRP_REGNUM))]
   "! TARGET_AVOID_GOTPLT"
   "Jsr %1"
   [(set_attr "cc" "clobber")])
        (call (mem:QI (match_operand:SI
                       1 "cris_general_operand_or_plt_symbol" "r,Q>,g"))
              (match_operand 2 "" "")))
-   (clobber (reg:SI 16))]
+   (clobber (reg:SI CRIS_SRP_REGNUM))]
   "TARGET_AVOID_GOTPLT"
   "Jsr %1"
   [(set_attr "cc" "clobber")])
   "nop"
   [(set_attr "cc" "none")])
 \f
+;; We need to stop accesses to the stack after the memory is
+;; deallocated.  Unfortunately, reorg doesn't look at naked clobbers,
+;; e.g. (insn ... (clobber (mem:BLK (stack_pointer_rtx)))) and we don't
+;; want to use a naked (unspec_volatile) as that would stop any
+;; scheduling in the epilogue.  Hence we model it as a "real" insn that
+;; sets the memory in an unspecified manner.  FIXME: Unfortunately it
+;; still has the effect of an unspec_volatile.
+(define_insn "cris_frame_deallocated_barrier"
+  [(set (mem:BLK (reg:SI CRIS_SP_REGNUM))
+       (unspec:BLK [(const_int 0)] CRIS_UNSPEC_FRAME_DEALLOC))]
+  ""
+  ""
+  [(set_attr "length" "0")])
+
 ;; We expand on casesi so we can use "bound" and "add offset fetched from
 ;; a table to pc" (adds.w [pc+%0.w],pc).
 
 (define_split
   [(parallel
     [(set (match_operand 0 "register_operand" "")
-          (mem (plus:SI
-                (mult:SI (match_operand:SI 1 "register_operand" "")
-                         (match_operand:SI 2 "const_int_operand" ""))
-                (match_operand:SI 3 "register_operand" ""))))
+         (match_operator
+          6 "cris_mem_op"
+          [(plus:SI
+            (mult:SI (match_operand:SI 1 "register_operand" "")
+                     (match_operand:SI 2 "const_int_operand" ""))
+            (match_operand:SI 3 "register_operand" ""))]))
      (set (match_operand:SI 4 "register_operand" "")
-          (plus:SI (mult:SI (match_dup 1)
-                            (match_dup 2))
+         (plus:SI (mult:SI (match_dup 1)
+                           (match_dup 2))
                    (match_dup 3)))])]
   "REG_P (operands[3]) && REG_P (operands[4])
    && REGNO (operands[3]) == REGNO (operands[4])"
   [(set (match_dup 4) (plus:SI (mult:SI (match_dup 1) (match_dup 2))
-                               (match_dup 3)))
+                              (match_dup 3)))
    (set (match_dup 0) (match_dup 5))]
-  "operands[5] = gen_rtx_MEM (GET_MODE (operands[0]), operands[3]);")
+  "operands[5] = replace_equiv_address (operands[6], operands[3]);")
 
 ;; move.S1 [rx=rx+i],ry
 
 (define_split
   [(parallel
     [(set (match_operand 0 "register_operand" "")
-          (mem
-           (plus:SI (match_operand:SI 1 "cris_bdap_operand" "")
-                    (match_operand:SI 2 "cris_bdap_operand" ""))))
+         (match_operator
+          5 "cris_mem_op"
+          [(plus:SI (match_operand:SI 1 "cris_bdap_operand" "")
+                    (match_operand:SI 2 "cris_bdap_operand" ""))]))
      (set (match_operand:SI 3 "register_operand" "")
           (plus:SI (match_dup 1)
                    (match_dup 2)))])]
     || rtx_equal_p (operands[3], operands[2]))"
   [(set (match_dup 3) (plus:SI (match_dup 1) (match_dup 2)))
    (set (match_dup 0) (match_dup 4))]
-  "operands[4] = gen_rtx_MEM (GET_MODE (operands[0]), operands[3]);")
+  "operands[4] = replace_equiv_address (operands[5], operands[3]);")
 
 ;; move.S1 ry,[rx=rx+rz.S2]
 
 (define_split
   [(parallel
-    [(set (mem (plus:SI
-                (mult:SI (match_operand:SI 0 "register_operand" "")
-                         (match_operand:SI 1 "const_int_operand" ""))
-                (match_operand:SI 2 "register_operand" "")))
-          (match_operand 3 "register_operand" ""))
+    [(set (match_operator
+          6 "cris_mem_op"
+          [(plus:SI
+            (mult:SI (match_operand:SI 0 "register_operand" "")
+                     (match_operand:SI 1 "const_int_operand" ""))
+            (match_operand:SI 2 "register_operand" ""))])
+         (match_operand 3 "register_operand" ""))
      (set (match_operand:SI 4 "register_operand" "")
           (plus:SI (mult:SI (match_dup 0)
                             (match_dup 1))
   [(set (match_dup 4) (plus:SI (mult:SI (match_dup 0) (match_dup 1))
                                (match_dup 2)))
    (set (match_dup 5) (match_dup 3))]
-  "operands[5] = gen_rtx_MEM (GET_MODE (operands[3]), operands[4]);")
+  "operands[5] = replace_equiv_address (operands[6], operands[4]);")
 
 ;; move.S1 ry,[rx=rx+i]
 
 (define_split
   [(parallel
-    [(set (mem
-          (plus:SI (match_operand:SI 0 "cris_bdap_operand" "")
-                   (match_operand:SI 1 "cris_bdap_operand" "")))
-          (match_operand 2 "register_operand" ""))
+    [(set (match_operator
+          6 "cris_mem_op"
+          [(plus:SI (match_operand:SI 0 "cris_bdap_operand" "")
+                    (match_operand:SI 1 "cris_bdap_operand" ""))])
+         (match_operand 2 "register_operand" ""))
      (set (match_operand:SI 3 "register_operand" "")
           (plus:SI (match_dup 0)
                   (match_dup 1)))])]
     || rtx_equal_p (operands[3], operands[1]))"
   [(set (match_dup 3) (plus:SI (match_dup 0) (match_dup 1)))
    (set (match_dup 5) (match_dup 2))]
-  "operands[5] = gen_rtx_MEM (GET_MODE (operands[2]), operands[3]);")
+  "operands[5] = replace_equiv_address (operands[6], operands[3]);")
 
 ;; clear.d [rx=rx+rz.S2]
 
   [(set (match_dup 4) (plus:SI (mult:SI (match_dup 1) (match_dup 2))
                                (match_dup 3)))
    (set (match_dup 0) (match_op_dup 5 [(match_dup 6)]))]
-  "operands[6] = gen_rtx_MEM (GET_MODE (XEXP (operands[5],0)),
-                          operands[4]);")
+  "operands[6] = replace_equiv_address (XEXP (operands[5], 0), operands[4]);")
 
 ;; mov(s|u).S1 [rx=rx+i],ry
 
     || rtx_equal_p (operands[2], operands[3]))"
   [(set (match_dup 3) (plus:SI (match_dup 1) (match_dup 2)))
    (set (match_dup 0) (match_op_dup 4 [(match_dup 5)]))]
-  "operands[5] = gen_rtx_MEM (GET_MODE (XEXP (operands[4], 0)),
-                         operands[3]);")
+  "operands[5] = replace_equiv_address (XEXP (operands[4], 0), operands[3]);")
 
 ;; op.S1 [rx=rx+i],ry
 
     || rtx_equal_p (operands[4], operands[3]))"
   [(set (match_dup 4) (plus:SI (match_dup 2) (match_dup 3)))
    (set (match_dup 0) (match_op_dup 5 [(match_dup 1) (match_dup 6)]))]
-  "operands[6] = gen_rtx_MEM (GET_MODE (operands[0]), operands[4]);")
+  "operands[6] = replace_equiv_address (XEXP (operands[5], 1), operands[4]);")
 
 ;; op.S1 [rx=rx+rz.S2],ry
 
   [(set (match_dup 5) (plus:SI (mult:SI (match_dup 2) (match_dup 3))
                                (match_dup 4)))
    (set (match_dup 0) (match_op_dup 6 [(match_dup 1) (match_dup 7)]))]
-  "operands[7] = gen_rtx_MEM (GET_MODE (operands[0]), operands[5]);")
+  "operands[7] = replace_equiv_address (XEXP (operands[6], 1), operands[5]);")
 
 ;; op.S1 [rx=rx+rz.S2],ry (swapped)
 
   [(set (match_dup 5) (plus:SI (mult:SI (match_dup 2) (match_dup 3))
                               (match_dup 4)))
    (set (match_dup 0) (match_op_dup 6 [(match_dup 7) (match_dup 1)]))]
-  "operands[7] = gen_rtx_MEM (GET_MODE (operands[0]), operands[5]);")
+  "operands[7] = replace_equiv_address (XEXP (operands[6], 0), operands[5]);")
 
 ;; op.S1 [rx=rx+i],ry (swapped)
 
     || rtx_equal_p (operands[4], operands[3]))"
   [(set (match_dup 4) (plus:SI (match_dup 2) (match_dup 3)))
    (set (match_dup 0) (match_op_dup 5 [(match_dup 6) (match_dup 1)]))]
-  "operands[6] = gen_rtx_MEM (GET_MODE (operands[0]), operands[4]);")
+  "operands[6] = replace_equiv_address (XEXP (operands[5], 0), operands[4]);")
 
 ;; op(s|u).S1 [rx=rx+rz.S2],ry
 
   [(set (match_dup 5) (plus:SI (mult:SI (match_dup 2) (match_dup 3))
                               (match_dup 4)))
    (set (match_dup 0) (match_op_dup 6 [(match_dup 1) (match_dup 8)]))]
-  "operands[8] = gen_rtx (GET_CODE (operands[7]), GET_MODE (operands[7]),
-                         gen_rtx_MEM (GET_MODE (XEXP (operands[7], 0)),
-                                  operands[5]));")
+  "operands[8] = gen_rtx_fmt_e (GET_CODE (operands[7]), GET_MODE (operands[7]),
+                               replace_equiv_address (XEXP (operands[7], 0),
+                                                      operands[5]));")
 
 ;; op(s|u).S1 [rx=rx+i],ry
 
     || rtx_equal_p (operands[4], operands[3]))"
   [(set (match_dup 4) (plus:SI (match_dup 2) (match_dup 3)))
    (set (match_dup 0) (match_op_dup 5 [(match_dup 1) (match_dup 7)]))]
-  "operands[7] = gen_rtx (GET_CODE (operands[6]), GET_MODE (operands[6]),
-                          gen_rtx_MEM (GET_MODE (XEXP (operands[6], 0)),
-                                   operands[4]));")
+  "operands[7] = gen_rtx_fmt_e (GET_CODE (operands[6]), GET_MODE (operands[6]),
+                               replace_equiv_address (XEXP (operands[6], 0),
+                                                      operands[4]));")
 
 ;; op(s|u).S1 [rx=rx+rz.S2],ry (swapped, plus or bound)
 
   [(set (match_dup 5) (plus:SI (mult:SI (match_dup 2) (match_dup 3))
                               (match_dup 4)))
    (set (match_dup 0) (match_op_dup 6 [(match_dup 8) (match_dup 1)]))]
-  "operands[8] = gen_rtx (GET_CODE (operands[6]), GET_MODE (operands[6]),
-                         gen_rtx_MEM (GET_MODE (XEXP (operands[6], 0)),
-                                  operands[5]));")
+  "operands[8] = gen_rtx_fmt_e (GET_CODE (operands[6]), GET_MODE (operands[6]),
+                               replace_equiv_address (XEXP (operands[6], 0),
+                                                      operands[5]));")
 
 ;; op(s|u).S1 [rx=rx+i],ry (swapped, plus or bound)
 
     || rtx_equal_p (operands[4], operands[3]))"
   [(set (match_dup 4) (plus:SI (match_dup 2) (match_dup 3)))
    (set (match_dup 0) (match_op_dup 6 [(match_dup 7) (match_dup 1)]))]
-  "operands[7] = gen_rtx (GET_CODE (operands[5]), GET_MODE (operands[5]),
-                         gen_rtx_MEM (GET_MODE (XEXP (operands[5], 0)),
-                                  operands[4]));")
+  "operands[7] = gen_rtx_fmt_e (GET_CODE (operands[5]), GET_MODE (operands[5]),
+                               replace_equiv_address (XEXP (operands[5], 0),
+                                                      operands[4]));")
 \f
 ;; Splits for addressing prefixes that have no side-effects, so we can
 ;; fill a delay slot.  Never split if we lose something, though.
 ;; 2001-08-24, unwind-dw2-fde.c, _Unwind_Find_FDE ICE in
 ;; cselib_invalidate_regno.
 
-(define_split
+(define_split ; indir_to_reg_split
   [(set (match_operand 0 "register_operand" "")
        (match_operand 1 "indirect_operand" ""))]
   "reload_completed
    && REG_P (operands[0])
    && GET_MODE_SIZE (GET_MODE (operands[0])) <= UNITS_PER_WORD
    && (GET_CODE (XEXP (operands[1], 0)) == MEM
-       || CONSTANT_P (XEXP (operands[1], 0)))"
+       || CONSTANT_P (XEXP (operands[1], 0)))
+   && REGNO (operands[0]) < CRIS_LAST_GENERAL_REGISTER"
   [(set (match_dup 2) (match_dup 4))
    (set (match_dup 0) (match_dup 3))]
   "operands[2] = gen_rtx_REG (Pmode, REGNO (operands[0]));
-   operands[3] = gen_rtx_MEM (GET_MODE (operands[0]), operands[2]);
+   operands[3] = replace_equiv_address (operands[1], operands[2]);
    operands[4] = XEXP (operands[1], 0);")
 
 ;; As the above, but MOVS and MOVU.
   [(set (match_dup 2) (match_dup 5))
    (set (match_dup 0) (match_op_dup 4 [(match_dup 3)]))]
   "operands[2] = gen_rtx_REG (Pmode, REGNO (operands[0]));
-   operands[3] = gen_rtx_MEM (GET_MODE (XEXP (operands[4], 0)), operands[2]);
+   operands[3] = replace_equiv_address (XEXP (operands[4], 0), operands[2]);
    operands[5] = XEXP (operands[1], 0);")
 \f
 ;; Various peephole optimizations.
 ;; to keep changes local to their cause.
 ;;
 ;; Do not add patterns that you do not know will be matched.
-;; Please also add a self-contained test-case.
+;; Please also add a self-contained testcase.
 
 ;; We have trouble with and:s and shifts.  Maybe something is broken in
 ;; gcc?  Or it could just be that bit-field insn expansion is a bit
 ;; suboptimal when not having extzv insns.
+;; Testcase for the following four peepholes: gcc.dg/cris-peep2-xsrand.c
 
-(define_peephole
-  [(set (match_operand 0 "register_operand" "=r")
+(define_peephole2 ; asrandb (peephole casesi+31)
+  [(set (match_operand:SI 0 "register_operand" "")
        (ashiftrt:SI (match_dup 0)
-                    (match_operand:SI 1 "const_int_operand" "n")))
+                    (match_operand:SI 1 "const_int_operand" "")))
    (set (match_dup 0)
        (and:SI (match_dup 0)
-               (match_operand 2 "const_int_operand" "n")))]
+               (match_operand 2 "const_int_operand" "")))]
   "INTVAL (operands[2]) > 31
    && INTVAL (operands[2]) < 255
-   && INTVAL (operands[1]) > 23"
-
-;; The m flag should be ignored, because this will be a *byte* "and"
-;; operation.
-
-  "*
+   && INTVAL (operands[1]) > 23
+   /* Check that the and-operation enables us to use logical-shift.  */
+   && (INTVAL (operands[2])
+         & ((HOST_WIDE_INT) -1 << (32 - INTVAL (operands[1])))) == 0"
+  [(set (match_dup 0) (lshiftrt:SI (match_dup 0) (match_dup 1)))
+   (set (match_dup 3) (and:QI (match_dup 3) (match_dup 4)))]
+  ;; FIXME: CC0 is valid except for the M bit.
 {
-  cc_status.flags |= CC_NOT_NEGATIVE;
+  operands[3] = gen_rtx_REG (QImode, REGNO (operands[0]));
+  operands[4] = GEN_INT (trunc_int_for_mode (INTVAL (operands[2]), QImode));
+})
 
-  return \"lsrq %1,%0\;and.b %2,%0\";
-}")
-
-(define_peephole
-  [(set (match_operand 0 "register_operand" "=r")
+(define_peephole2 ; asrandw (peephole casesi+32)
+  [(set (match_operand:SI 0 "register_operand" "")
        (ashiftrt:SI (match_dup 0)
-                    (match_operand:SI 1 "const_int_operand" "n")))
+                    (match_operand:SI 1 "const_int_operand" "")))
    (set (match_dup 0)
-       (and:SI (match_dup 0)
-               (match_operand 2 "const_int_operand" "n")))]
+       (and:SI (match_dup 0) (match_operand 2 "const_int_operand" "")))]
   "INTVAL (operands[2]) > 31
    && INTVAL (operands[2]) < 65535
    && INTVAL (operands[2]) != 255
-   && INTVAL (operands[1]) > 15"
-
-;; The m flag should be ignored, because this will be a *word* "and"
-;; operation.
-
-  "*
+   && INTVAL (operands[1]) > 15
+   /* Check that the and-operation enables us to use logical-shift.  */
+   && (INTVAL (operands[2])
+       & ((HOST_WIDE_INT) -1 << (32 - INTVAL (operands[1])))) == 0"
+  [(set (match_dup 0) (lshiftrt:SI (match_dup 0) (match_dup 1)))
+   (set (match_dup 3) (and:HI (match_dup 3) (match_dup 4)))]
+  ;; FIXME: CC0 is valid except for the M bit.
 {
-  cc_status.flags |= CC_NOT_NEGATIVE;
-
-  return \"lsrq %1,%0\;and.w %2,%0\";
-}")
+  operands[3] = gen_rtx_REG (HImode, REGNO (operands[0]));
+  operands[4] = GEN_INT (trunc_int_for_mode (INTVAL (operands[2]), HImode));
+})
 
-(define_peephole
-  [(set (match_operand 0 "register_operand" "=r")
+(define_peephole2 ; lsrandb (peephole casesi+33)
+  [(set (match_operand:SI 0 "register_operand" "")
        (lshiftrt:SI (match_dup 0)
-                    (match_operand:SI 1 "const_int_operand" "n")))
+                    (match_operand:SI 1 "const_int_operand" "")))
    (set (match_dup 0)
-       (and:SI (match_dup 0)
-               (match_operand 2 "const_int_operand" "n")))]
+       (and:SI (match_dup 0) (match_operand 2 "const_int_operand" "")))]
   "INTVAL (operands[2]) > 31
    && INTVAL (operands[2]) < 255
    && INTVAL (operands[1]) > 23"
-
-;; The m flag should be ignored, because this will be a *byte* "and"
-;; operation.
-
-  "*
+  [(set (match_dup 0) (lshiftrt:SI (match_dup 0) (match_dup 1)))
+   (set (match_dup 3) (and:QI (match_dup 3) (match_dup 4)))]
+  ;; FIXME: CC0 is valid except for the M bit.
 {
-  cc_status.flags |= CC_NOT_NEGATIVE;
-
-  return \"lsrq %1,%0\;and.b %2,%0\";
-}")
+  operands[3] = gen_rtx_REG (QImode, REGNO (operands[0]));
+  operands[4] = GEN_INT (trunc_int_for_mode (INTVAL (operands[2]), QImode));
+})
 
-(define_peephole
-  [(set (match_operand 0 "register_operand" "=r")
+(define_peephole2 ; lsrandw (peephole casesi+34)
+  [(set (match_operand:SI 0 "register_operand" "")
        (lshiftrt:SI (match_dup 0)
-                    (match_operand:SI 1 "const_int_operand" "n")))
+                    (match_operand:SI 1 "const_int_operand" "")))
    (set (match_dup 0)
-       (and:SI (match_dup 0)
-               (match_operand 2 "const_int_operand" "n")))]
+       (and:SI (match_dup 0) (match_operand 2 "const_int_operand" "")))]
   "INTVAL (operands[2]) > 31 && INTVAL (operands[2]) < 65535
    && INTVAL (operands[2]) != 255
    && INTVAL (operands[1]) > 15"
-
-;; The m flag should be ignored, because this will be a *word* "and"
-;; operation.
-
-  "*
+  [(set (match_dup 0) (lshiftrt:SI (match_dup 0) (match_dup 1)))
+   (set (match_dup 3) (and:HI (match_dup 3) (match_dup 4)))]
+  ;; FIXME: CC0 is valid except for the M bit.
 {
-  cc_status.flags |= CC_NOT_NEGATIVE;
-
-  return \"lsrq %1,%0\;and.w %2,%0\";
-}")
+  operands[3] = gen_rtx_REG (HImode, REGNO (operands[0]));
+  operands[4] = GEN_INT (trunc_int_for_mode (INTVAL (operands[2]), HImode));
+})
 \f
 
 ;; Change
 ;;  move [rx=rx+n],ry
 ;; when -128 <= n <= 127.
 ;; This will reduce the size of the assembler code for n = [-128..127],
-;; and speed up accordingly.
-
-(define_peephole
-  [(set (match_operand:SI 0 "register_operand" "=r")
-       (plus:SI (match_operand:SI 1 "register_operand" "0")
-                (match_operand:SI 2 "const_int_operand" "n")))
-   (set (match_operand 3 "register_operand" "=r")
-       (mem (match_dup 0)))]
-  "GET_MODE (operands[3]) != DImode
-    && REGNO (operands[3]) != REGNO (operands[0])
-    && (BASE_P (operands[1]) || BASE_P (operands[2]))
-    && ! CONST_OK_FOR_LETTER_P (INTVAL (operands[2]), 'J')
-    && ! CONST_OK_FOR_LETTER_P (INTVAL (operands[2]), 'N')
-    && (INTVAL (operands[2]) >= -128 && INTVAL (operands[2]) < 128)"
-  "move.%s3 [%0=%1%S2],%3")
+;; and speed up accordingly.  Don't match if the previous insn is
+;; (set rx rz) because that combination is matched by another peephole.
+;; No stable test-case.
+
+(define_peephole2 ; moversideqi (peephole casesi+35)
+  [(set (match_operand:SI 0 "register_operand" "")
+       (plus:SI (match_operand:SI 1 "register_operand" "")
+                (match_operand:SI 2 "const_int_operand" "")))
+   (set (match_operand 3 "register_operand" "")
+       (match_operator 4 "cris_mem_op" [(match_dup 0)]))]
+  "GET_MODE_SIZE (GET_MODE (operands[4])) <= UNITS_PER_WORD
+   && REGNO (operands[3]) != REGNO (operands[0])
+   && (BASE_P (operands[1]) || BASE_P (operands[2]))
+   && ! CONST_OK_FOR_LETTER_P (INTVAL (operands[2]), 'J')
+   && ! CONST_OK_FOR_LETTER_P (INTVAL (operands[2]), 'N')
+   && (INTVAL (operands[2]) >= -128 && INTVAL (operands[2]) < 128)"
+  [(parallel
+    [(set (match_dup 3) (match_dup 5))
+     (set (match_dup 0) (plus:SI (match_dup 1) (match_dup 2)))])]
+  ;; Checking the previous insn is a bit too awkward for the condition.
+{
+  rtx prev = prev_nonnote_insn (curr_insn);
+  if (prev != NULL_RTX)
+    {
+      rtx set = single_set (prev);
+      if (set != NULL_RTX
+         && REG_S_P (SET_DEST (set))
+         && REGNO (SET_DEST (set)) == REGNO (operands[0])
+         && REG_S_P (SET_SRC (set)))
+       FAIL;
+    }
+  operands[5]
+    = replace_equiv_address (operands[4],
+                            gen_rtx_PLUS (SImode,
+                                          operands[1], operands[2]));
+})
 
 ;; Vice versa: move ry,[rx=rx+n]
 
-(define_peephole
-  [(set (match_operand:SI 0 "register_operand" "=r")
-       (plus:SI (match_operand:SI 1 "register_operand" "0")
-                (match_operand:SI 2 "const_int_operand" "n")))
-   (set (mem (match_dup 0))
-       (match_operand 3 "register_operand" "=r"))]
-  "GET_MODE (operands[3]) != DImode
-    && REGNO (operands[3]) != REGNO (operands[0])
-    && (BASE_P (operands[1]) || BASE_P (operands[2]))
-    && ! CONST_OK_FOR_LETTER_P (INTVAL (operands[2]), 'J')
-    && ! CONST_OK_FOR_LETTER_P (INTVAL (operands[2]), 'N')
-    && (INTVAL (operands[2]) >= -128 && INTVAL (operands[2]) < 128)"
-  "move.%s3 %3,[%0=%1%S2]"
-  [(set_attr "cc" "none")])
+(define_peephole2 ; movemsideqi (peephole casesi+36)
+  [(set (match_operand:SI 0 "register_operand" "")
+       (plus:SI (match_operand:SI 1 "register_operand" "")
+                (match_operand:SI 2 "const_int_operand" "")))
+   (set (match_operator 3 "cris_mem_op" [(match_dup 0)])
+       (match_operand 4 "register_operand" ""))]
+  "GET_MODE_SIZE (GET_MODE (operands[4])) <= UNITS_PER_WORD
+   && REGNO (operands[4]) != REGNO (operands[0])
+   && (BASE_P (operands[1]) || BASE_P (operands[2]))
+   && ! CONST_OK_FOR_LETTER_P (INTVAL (operands[2]), 'J')
+   && ! CONST_OK_FOR_LETTER_P (INTVAL (operands[2]), 'N')
+   && (INTVAL (operands[2]) >= -128 && INTVAL (operands[2]) < 128)"
+  [(parallel
+    [(set (match_dup 5) (match_dup 4))
+     (set (match_dup 0) (plus:SI (match_dup 1) (match_dup 2)))])]
+  "operands[5]
+     = replace_equiv_address (operands[3],
+                             gen_rtx_PLUS (SImode,
+                                           operands[1], operands[2]));")
 \f
 ;; As above, change:
 ;;  add.d n,rx
 ;; out of hand.  They probably will not save the time they take typing in,
 ;; not to mention the bugs that creep in.  FIXME: Get rid of as many of
 ;; the splits and peepholes as possible.
-
-(define_peephole
-  [(set (match_operand:SI 0 "register_operand" "=r")
-       (plus:SI (match_operand:SI 1 "register_operand" "0")
-                (match_operand:SI 2 "const_int_operand" "n")))
-   (set (match_operand 3 "register_operand" "=r")
-       (match_operator 4 "cris_orthogonal_operator"
-                          [(match_dup 3)
-                           (mem (match_dup 0))]))]
+;; No stable test-case.
+
+(define_peephole2 ; mover2side (peephole casesi+37)
+  [(set (match_operand:SI 0 "register_operand" "")
+       (plus:SI (match_operand:SI 1 "register_operand" "")
+                (match_operand:SI 2 "const_int_operand" "")))
+   (set (match_operand 3 "register_operand" "")
+         (match_operator 4 "cris_orthogonal_operator"
+                         [(match_dup 3)
+                          (match_operator
+                           5 "cris_mem_op" [(match_dup 0)])]))]
+  ;; FIXME: What about DFmode?
+  ;; Change to GET_MODE_SIZE (GET_MODE (operands[3])) <= UNITS_PER_WORD?
   "GET_MODE (operands[3]) != DImode
-    && REGNO (operands[0]) != REGNO (operands[3])
-    && ! CONST_OK_FOR_LETTER_P (INTVAL (operands[2]), 'J')
-    && ! CONST_OK_FOR_LETTER_P (INTVAL (operands[2]), 'N')
-    && INTVAL (operands[2]) >= -128
-    && INTVAL (operands[2]) <= 127"
-  "%x4.%s3 [%0=%1%S2],%3")
+   && REGNO (operands[0]) != REGNO (operands[3])
+   && ! CONST_OK_FOR_LETTER_P (INTVAL (operands[2]), 'J')
+   && ! CONST_OK_FOR_LETTER_P (INTVAL (operands[2]), 'N')
+   && INTVAL (operands[2]) >= -128
+   && INTVAL (operands[2]) <= 127"
+  [(parallel
+    [(set (match_dup 3) (match_op_dup 4 [(match_dup 3) (match_dup 6)]))
+     (set (match_dup 0) (plus:SI (match_dup 1) (match_dup 2)))])]
+  "operands[6]
+     = replace_equiv_address (operands[5],
+                             gen_rtx_PLUS (SImode,
+                                           operands[1], operands[2]));")
 
 ;; Sometimes, for some reason the pattern
 ;;  move x,rx
 ;;  add y,rx
 ;;  move [rx],rz
 ;; will occur.  Solve this, and likewise for to-memory.
+;; No stable test-case.
 
-(define_peephole
-  [(set (match_operand:SI 0 "register_operand" "=r,r,r,r")
-       (match_operand:SI 1 "cris_bdap_biap_operand" "r,>Ri,r,>Ri"))
+(define_peephole2 ; moverside (peephole casesi+38)
+  [(set (match_operand:SI 0 "register_operand" "")
+       (match_operand:SI 1 "cris_bdap_biap_operand" ""))
    (set (match_dup 0)
-       (plus:SI (match_operand:SI 2 "cris_bdap_biap_operand" "0,0,r>Ri,r")
-                (match_operand:SI 3 "cris_bdap_biap_operand" "r>Ri,r,0,0")))
-   (set (match_operand 4 "register_operand" "=r,r,r,r")
-       (mem (match_dup 0)))]
+       (plus:SI (match_operand:SI 2 "cris_bdap_biap_operand" "")
+                (match_operand:SI 3 "cris_bdap_biap_operand" "")))
+   (set (match_operand 4 "register_operand" "")
+       (match_operator 5 "cris_mem_op" [(match_dup 0)]))]
   "(rtx_equal_p (operands[2], operands[0])
     || rtx_equal_p (operands[3], operands[0]))
    && cris_side_effect_mode_ok (PLUS, operands, 0,
-                                (REG_S_P (operands[1])
-                                 ? 1
-                                 : (rtx_equal_p (operands[2], operands[0])
-                                    ? 3 : 2)),
-                                (! REG_S_P (operands[1])
-                                 ? 1
-                                 : (rtx_equal_p (operands[2], operands[0])
-                                    ? 3 : 2)),
-                                -1, 4)"
-  "@
-   move.%s4 [%0=%1%S3],%4
-   move.%s4 [%0=%3%S1],%4
-   move.%s4 [%0=%1%S2],%4
-   move.%s4 [%0=%2%S1],%4")
-
-;; As above but to memory.
-
-(define_peephole
-  [(set (match_operand:SI 0 "register_operand" "=r,r,r,r")
-       (match_operand:SI 1 "cris_bdap_biap_operand" "r,>Ri,r,>Ri"))
-   (set (match_dup 0)
-       (plus:SI (match_operand:SI 2 "cris_bdap_biap_operand" "0,0,r>Ri,r")
-                (match_operand:SI 3 "cris_bdap_biap_operand" "r>Ri,r,0,0")))
-   (set (mem (match_dup 0))
-       (match_operand 4 "register_operand" "=r,r,r,r"))]
-  "(rtx_equal_p (operands[2], operands[0])
-    || rtx_equal_p (operands[3], operands[0]))
-   && cris_side_effect_mode_ok (PLUS, operands, 0,
-                                (REG_S_P (operands[1])
-                                 ? 1
-                                 : (rtx_equal_p (operands[2], operands[0])
-                                    ? 3 : 2)),
-                                (! REG_S_P (operands[1])
-                                   ? 1
-                                 : (rtx_equal_p (operands[2], operands[0])
-                                    ? 3 : 2)),
-                                -1, 4)"
-  "@
-   move.%s4 %4,[%0=%1%S3]
-   move.%s4 %4,[%0=%3%S1]
-   move.%s4 %4,[%0=%1%S2]
-   move.%s4 %4,[%0=%2%S1]"
-  [(set_attr "cc" "none")])
+                               (REG_S_P (operands[1])
+                                ? 1
+                                : (rtx_equal_p (operands[2], operands[0])
+                                   ? 3 : 2)),
+                               (! REG_S_P (operands[1])
+                                ? 1
+                                : (rtx_equal_p (operands[2], operands[0])
+                                   ? 3 : 2)),
+                               -1, 4)"
+  [(parallel
+    [(set (match_dup 4) (match_dup 6))
+     (set (match_dup 0) (plus:SI (match_dup 7) (match_dup 8)))])]
+{
+  rtx otherop
+    = rtx_equal_p (operands[2], operands[0]) ? operands[3] : operands[2];
 
+  /* Make sure we have canonical RTX so we match the insn pattern -
+     not a constant in the first operand.  We also require the order
+     (plus reg mem) to match the final pattern.  */
+  if (CONSTANT_P (otherop) || MEM_P (otherop))
+    {
+      operands[7] = operands[1];
+      operands[8] = otherop;
+    }
+  else
+    {
+      operands[7] = otherop;
+      operands[8] = operands[1];
+    }
+  operands[6]
+    = replace_equiv_address (operands[5],
+                            gen_rtx_PLUS (SImode,
+                                          operands[7], operands[8]));
+})
 
-;; As the move from-memory above, but with an operation.
+;; As above but to memory.
+;; FIXME: Split movemside and moverside into variants and prune
+;; the ones that don't trig.
+;; No stable test-case.
 
-(define_peephole
-  [(set (match_operand:SI 0 "register_operand" "=r,r,r,r")
-       (match_operand:SI 1 "cris_bdap_biap_operand" "r,>Ri,r,>Ri"))
+(define_peephole2 ; movemside (peephole casesi+39)
+  [(set (match_operand:SI 0 "register_operand" "")
+       (match_operand:SI 1 "cris_bdap_biap_operand" ""))
    (set (match_dup 0)
-       (plus:SI (match_operand:SI 2 "cris_bdap_biap_operand" "0,0,r>Ri,r")
-                (match_operand:SI 3 "cris_bdap_biap_operand" "r>Ri,r,0,0")))
-   (set (match_operand 4 "register_operand" "=r,r,r,r")
-       (match_operator 5 "cris_orthogonal_operator"
-                       [(match_dup 3)
-                        (mem (match_dup 0))]))]
+       (plus:SI (match_operand:SI 2 "cris_bdap_biap_operand" "")
+                (match_operand:SI 3 "cris_bdap_biap_operand" "")))
+   (set (match_operator 4 "cris_mem_op" [(match_dup 0)])
+       (match_operand 5 "register_operand" ""))]
   "(rtx_equal_p (operands[2], operands[0])
     || rtx_equal_p (operands[3], operands[0]))
    && cris_side_effect_mode_ok (PLUS, operands, 0,
-                                (REG_S_P (operands[1])
-                                 ? 1
-                                 : (rtx_equal_p (operands[2], operands[0])
-                                    ? 3 : 2)),
-                                (! REG_S_P (operands[1])
-                                 ? 1
-                                 : (rtx_equal_p (operands[2], operands[0])
-                                    ? 3 : 2)),
-                                -1, 4)"
-  "@
-   %x5.%s4 [%0=%1%S3],%4
-   %x5.%s4 [%0=%3%S1],%4
-   %x5.%s4 [%0=%1%S2],%4
-   %x5.%s4 [%0=%2%S1],%4")
-
-;; Same, but with swapped operands (and commutative operation).
+                               (REG_S_P (operands[1])
+                                ? 1
+                                : (rtx_equal_p (operands[2], operands[0])
+                                   ? 3 : 2)),
+                               (! REG_S_P (operands[1])
+                                  ? 1
+                                : (rtx_equal_p (operands[2], operands[0])
+                                   ? 3 : 2)),
+                               -1, 5)"
+  [(parallel
+    [(set (match_dup 6) (match_dup 5))
+     (set (match_dup 0) (plus:SI (match_dup 7) (match_dup 8)))])]
+{
+  rtx otherop
+    = rtx_equal_p (operands[2], operands[0]) ? operands[3] : operands[2];
 
-(define_peephole
-  [(set (match_operand:SI 0 "register_operand" "=r,r,r,r")
-       (match_operand:SI 1 "cris_bdap_biap_operand" "r,>Ri,r,>Ri"))
-   (set (match_dup 0)
-       (plus:SI (match_operand:SI 2 "cris_bdap_biap_operand" "0,0,r>Ri,r")
-                (match_operand:SI 3 "cris_bdap_biap_operand" "r>Ri,r,0,0")))
-   (set (match_operand 4 "register_operand" "=r,r,r,r")
-       (match_operator 5 "cris_commutative_orth_op"
-                       [(mem (match_dup 0))
-                        (match_dup 3)]))]
-  "(rtx_equal_p (operands[2], operands[0])
-    || rtx_equal_p (operands[3], operands[0]))
-   && cris_side_effect_mode_ok (PLUS, operands, 0,
-                          (REG_S_P (operands[1])
-                           ? 1
-                           : (rtx_equal_p (operands[2], operands[0])
-                              ? 3 : 2)),
-                          (! REG_S_P (operands[1])
-                           ? 1
-                           : (rtx_equal_p (operands[2], operands[0])
-                              ? 3 : 2)),
-                          -1, 4)"
-  "@
-   %x5.%s4 [%0=%1%S3],%4
-   %x5.%s4 [%0=%3%S1],%4
-   %x5.%s4 [%0=%1%S2],%4
-   %x5.%s4 [%0=%2%S1],%4")
+  /* Make sure we have canonical RTX so we match the insn pattern -
+     not a constant in the first operand.  We also require the order
+     (plus reg mem) to match the final pattern.  */
+  if (CONSTANT_P (otherop) || MEM_P (otherop))
+    {
+      operands[7] = operands[1];
+      operands[8] = otherop;
+    }
+  else
+    {
+      operands[7] = otherop;
+      operands[8] = operands[1];
+    }
+  operands[6]
+    = replace_equiv_address (operands[4],
+                            gen_rtx_PLUS (SImode,
+                                          operands[7], operands[8]));
+})
 
 ;; Another spotted bad code:
 ;;   move rx,ry
 ;;   move [ry],ry
+;; No stable test-case.
 
-(define_peephole
-  [(set (match_operand:SI 0 "register_operand" "=r")
-       (match_operand:SI 1 "register_operand" "r"))
-   (set (match_operand 2 "register_operand" "=r")
-       (mem (match_dup 0)))]
-  "REGNO (operands[0]) == REGNO (operands[2])
-   && GET_MODE_SIZE (GET_MODE (operands[2])) <= UNITS_PER_WORD"
-  "move.%s2 [%1],%0"
-  [(set_attr "slottable" "yes")])
-
-;; And a simple variant with extended operand.
-
-(define_peephole
-  [(set (match_operand:SI 0 "register_operand" "=r")
-       (match_operand:SI 1 "register_operand" "r"))
-   (set (match_operand 2 "register_operand" "=r")
-       (match_operator 3 "cris_extend_operator" [(mem (match_dup 0))]))]
+(define_peephole2 ; movei (peephole casesi+42)
+  [(set (match_operand:SI 0 "register_operand" "")
+       (match_operand:SI 1 "register_operand" ""))
+   (set (match_operand 2 "register_operand" "")
+       (match_operator 3 "cris_mem_op" [(match_dup 0)]))]
   "REGNO (operands[0]) == REGNO (operands[2])
+   && (REGNO_REG_CLASS (REGNO (operands[0]))
+       == REGNO_REG_CLASS (REGNO (operands[1])))
    && GET_MODE_SIZE (GET_MODE (operands[2])) <= UNITS_PER_WORD"
-  "mov%e3.%m3 [%1],%0"
-  [(set_attr "slottable" "yes")])
-\f
-;; Here are all peepholes that have a saved testcase.
-;; Do not add new peepholes without testcases.
+  [(set (match_dup 2) (match_dup 4))]
+  "operands[4] = replace_equiv_address (operands[3], operands[1]);")
 
-;; peep-1:
 ;;   move.d [r10+16],r9
 ;;   and.d r12,r9
 ;; change to
 ;; register pressure.
 ;;  Note that adding the noncommutative variant did not show any matches
 ;; in ipps and cc1, so it's not here.
+;; No stable test-case.
 
-(define_peephole
-  [(set (match_operand 0 "register_operand" "=r,r,r,r")
-       (mem (plus:SI
-             (match_operand:SI 1 "cris_bdap_biap_operand" "r,r>Ri,r,r>Ri")
-             (match_operand:SI 2 "cris_bdap_biap_operand" "r>Ri,r,r>Ri,r"))))
+(define_peephole2 ; op3 (peephole casesi+44)
+  [(set (match_operand 0 "register_operand" "")
+       (match_operator
+        6 "cris_mem_op"
+        [(plus:SI
+          (match_operand:SI 1 "cris_bdap_biap_operand" "")
+          (match_operand:SI 2 "cris_bdap_biap_operand" ""))]))
    (set (match_dup 0)
-       (match_operator 5 "cris_commutative_orth_op"
-                       [(match_operand 3 "register_operand" "0,0,r,r")
-                        (match_operand 4 "register_operand" "r,r,0,0")]))]
+       (match_operator
+        5 "cris_commutative_orth_op"
+        [(match_operand 3 "register_operand" "")
+         (match_operand 4 "register_operand" "")]))]
   "(rtx_equal_p (operands[3], operands[0])
     || rtx_equal_p (operands[4], operands[0]))
    && ! rtx_equal_p (operands[3], operands[4])
    && (REG_S_P (operands[1]) || REG_S_P (operands[2]))
    && GET_MODE_SIZE (GET_MODE (operands[0])) <= UNITS_PER_WORD"
-  "@
-   %x5.%s0 [%1%S2],%4,%0
-   %x5.%s0 [%2%S1],%4,%0
-   %x5.%s0 [%1%S2],%3,%0
-   %x5.%s0 [%2%S1],%3,%0")
+  [(set (match_dup 0) (match_op_dup 5 [(match_dup 7) (match_dup 6)]))]
+  "operands[7]
+     = rtx_equal_p (operands[3], operands[0]) ? operands[4] : operands[3];")
 
-;; peep-2:
 ;;  I cannot tell GCC (2.1, 2.7.2) how to correctly reload an instruction
 ;; that looks like
 ;;   and.b some_byte,const,reg_32
 ;;   move.b some_byte,reg_32
 ;;   and.d const,reg_32
 ;; Fix it here.
+;; Testcases: gcc.dg/cris-peep2-andu1.c gcc.dg/cris-peep2-andu2.c
 
-(define_peephole
-  [(set (match_operand:SI 0 "register_operand" "=r")
-       (match_operand:SI 1 "nonimmediate_operand" "rm"))
-   (set (match_operand:SI 2 "register_operand" "=0")
+(define_peephole2 ; andu (casesi+45)
+  [(set (match_operand:SI 0 "register_operand" "")
+       (match_operand:SI 1 "nonimmediate_operand" ""))
+   (set (match_operand:SI 2 "register_operand" "")
        (and:SI (match_dup 0)
-               (match_operand:SI 3 "const_int_operand" "n")))]
-
+               (match_operand:SI 3 "const_int_operand" "")))]
    ;; Since the size of the memory access could be made different here,
    ;; don't do this for a mem-volatile access.
-
   "REGNO (operands[2]) == REGNO (operands[0])
    && INTVAL (operands[3]) <= 65535 && INTVAL (operands[3]) >= 0
    && ! CONST_OK_FOR_LETTER_P (INTVAL (operands[3]), 'I')
    && (GET_CODE (operands[1]) != MEM || ! MEM_VOLATILE_P (operands[1]))"
-  "*
+  ;; FIXME: CC0 valid except for M (i.e. CC_NOT_NEGATIVE).
+  [(set (match_dup 0) (match_dup 4))
+   (set (match_dup 5) (match_dup 6))]
 {
-  if (CONST_OK_FOR_LETTER_P (INTVAL (operands[3]), 'O'))
-    return \"movu.%z3 %1,%0\;andq %b3,%0\";
-
-  cc_status.flags |= CC_NOT_NEGATIVE;
-
-  return \"movu.%z3 %1,%0\;and.%z3 %3,%0\";
-}")
-
-;; peep-3
-
-(define_peephole
-  [(set (match_operand 0 "register_operand" "=r")
-       (match_operand 1 "nonimmediate_operand" "rm"))
-   (set (match_operand:SI 2 "register_operand" "=r")
-       (and:SI (subreg:SI (match_dup 0) 0)
-               (match_operand 3 "const_int_operand" "n")))]
-
-   ;; Since the size of the memory access could be made different here,
-   ;; don't do this for a mem-volatile access.
-
-  "REGNO (operands[0]) == REGNO (operands[2])
-   && INTVAL (operands[3]) > 0
-   && INTVAL (operands[3]) <= 65535
-   && ! CONST_OK_FOR_LETTER_P (INTVAL (operands[3]), 'I')
-   && (GET_CODE (operands[1]) != MEM || ! MEM_VOLATILE_P (operands[1]))"
-  "*
-{
-  if (CONST_OK_FOR_LETTER_P (INTVAL (operands[3]), 'O'))
-    return \"movu.%z3 %1,%0\;andq %b3,%0\";
-
-  cc_status.flags |= CC_NOT_NEGATIVE;
-
-  return \"movu.%z3 %1,%0\;and.%z3 %3,%0\";
-}")
+  enum machine_mode zmode = INTVAL (operands[3]) <= 255 ? QImode : HImode;
+  enum machine_mode amode
+    = CONST_OK_FOR_LETTER_P (INTVAL (operands[3]), 'O') ? SImode : zmode;
+  rtx op1
+    = (REG_S_P (operands[1])
+       ? gen_rtx_REG (zmode, REGNO (operands[1]))
+       : adjust_address (operands[1], zmode, 0));
+  operands[4]
+    = gen_rtx_ZERO_EXTEND (SImode, op1);
+  operands[5] = gen_rtx_REG (amode, REGNO (operands[0]));
+  operands[6]
+    = gen_rtx_AND (amode, gen_rtx_REG (amode, REGNO (operands[0])),
+                  GEN_INT (trunc_int_for_mode (INTVAL (operands[3]),
+                                               amode == SImode
+                                               ? QImode : amode)));
+})
 \f
 ;; Local variables:
 ;; mode:emacs-lisp