]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
cris.md: Group related constants together, with comments local.
authorHans-Peter Nilsson <hp@gcc.gnu.org>
Sat, 15 Dec 2007 21:38:19 +0000 (21:38 +0000)
committerHans-Peter Nilsson <hp@gcc.gnu.org>
Sat, 15 Dec 2007 21:38:19 +0000 (21:38 +0000)
* gcc/config/cris/cris.md: Group related constants together, with
comments local.
(CRIS_UNSPEC_PLT_GOTREL, CRIS_UNSPEC_PLT_PCREL, CRIS_UNSPEC_PCREL)
(CRIS_UNSPEC_CASESI): New constants.
(CRIS_UNSPEC_PLT): Remove constant.
(CRIS_ACR_REGNUM): New constant.
("slottable"): New attr alternatives "has_return_slot" and
"has_call_slot".
("cc"): New attr alternatives "noov32" and "rev".
((eq_attr "slottable" "has_call_slot"))
((eq_attr "slottable" "has_return_slot")): New define_delays.
("movdi", "movsi"): Adjust operands for CRIS v32.
("tstdi", "cmpdi", "adddi3", "subdi3", "uminsi3")
("indirect_jump"): Ditto.  Make define_expand.
("*tstdi_non_v32", "*tstdi_v32", "*tst<mode>_cmp")
("*tst<mode>_non_cmp", "*cmpdi_non_v32", "*cmpdi_v32")
("*movdi_v32", "*adddi3_non_v32", "*adddi3_v32")
("*addsi3_non_v32", "*addsi3_v32", "*addhi3_non_v32")
("*addhi3_v32", "*addqi3_non_v32", "*addqi3_v32")
("*subdi3_non_v32", "*subdi3_v32", "*subsi3_non_v32")
("*subsi3_v32", "*sub<mode>3_nonv32", "*sub<mode>3_v32")
("*andqi3_non_v32", "*andqi3_v32", "*iorsi3_non_v32")
("*iorsi3_v32", "*iorhi3_non_v32", "*iorhi3_v32")
("*iorqi3_non_v32", "*iorqi3_v32", "*uminsi3_non_v32")
("*uminsi3_v32", "*indirect_jump_non_v32", "*indirect_jump_v32")
("*expanded_call_v32", "*expanded_call_value_v32"): New patterns,
for the corresponding standard name.
("tst<mode>"): Limit to BW and make define_expand.
("tstsi"): Make separate insn, adjusting for CRIS v32.
("*cmp_swapext<mode>"): Adjust for v32.  Specify "rev" for attr "cc".
("cmpsi", "cmp<mode>"): Remove special cases for zero.  Specify
attr "cc".
("*btst"): Don't match for TARGET_CCINIT.  Replace test of
register with compatible "cmpq 0".  Specify attr "cc".
("*movdi_insn_non_v32"): New pattern, replacing "*movdi_insn" and
define_split.
(define_split for DI move): Match CRIS v32 only.
("*movsi_got_load", "*movsi_internal", "*addi"): Adjust for CRIS
v32.
("load_multiple", "store_multiple", "*addsbw_v32", "*addubw_v32")
("*adds<mode>_v32", "*addu<mode>_v32", "*bound<mode>_v32")
("*casesi_jump_v32", "*expanded_andsi_v32", "*expanded_andhi_v32")
("*extop<mode>si_v32", "*extopqihi_v32", "*andhi_lowpart_v32")
("*andqi_lowpart_v32", "cris_casesi_v32"): New patterns.
("add<mode>3"): Make addsi3, addhi3 and addqi3 define_expand.
("sub<mode>3"): Ditto subsi3, subhi3 and subqi3.
("ior<mode>3"): Ditto iorsi3, iorhi3 and iorqi3.
("*extopqihi_non_v32"): Replace "*extopqihi".
("*extop<mode>si_non_v32"): Replace "*extop<mode>si".
("*addxqihi_swap_non_v32"): Rename from "*extopqihi_swap", make
non-v32 only.
("*extop<mode>si_swap_non_v32"): Ditto "*extop<mode>si_swap".
("*expanded_andsi_non_v32"): Ditto "*expanded_andsi".
("*expanded_andhi_non_v32"): Ditto "*expanded_andhi".
("*andhi_lowpart_non_v32"): Ditto "*andhi_lowpart".
("*andqi_lowpart_non_v32"): Ditto "*andqi_lowpart".
("*expanded_call_non_v32"): Ditto "*expanded_call".  Change from
"cris_general_operand_or_plt_symbol" to "general_operand".
("*expanded_call_value_non_v32") Ditto "*expanded_call_value".
("*casesi_adds_w", "mstep_shift", "mstep_mul")
("*expanded_call_side", "*expanded_call_value_side")
(op-extend-split, op-extend-split-rx=rz, op-extend-split-swapped)
(op-extend-split-swapped-rx=rz, op-extend, op-split-rx=rz)
(op-split-swapped, op-split-swapped-rx=rz): Make non-v32 only.
("dstep_mul", "xorsi3", "one_cmplsi2", "<shlr>si3")
("*expanded_<shlr><mode>", "*<shlr><mode>_lowpart", "ashl<mode>3")
("*ashl<mode>_lowpart", "abssi2", "clzsi2", "bswapsi2", "cris_swap_bits"): Specify "noov32" for
attr "cc".
("<su>mulsi3_highpart"): Ditto.  Correct operand 0 to
register_operand.
("andqi3"): Make define_expand.
("*return_expanded"): For attr "slottable", change from "has_slot"
to "has_return_slot".
("cris_casesi_non_v32"): New pattern, old contents of "casesi".
("casesi"): Divert into "cris_casesi_v32" and
"cris_casesi_non_v32".
(moversideqi, movemsideqi, mover2side): Require
TARGET_SIDE_EFFECT_PREFIXES.
(gotplt-to-plt, gotplt-to-plt-side): Change from CRIS_UNSPEC_PLT
to CRIS_UNSPEC_PLT_GOTREL.

From-SVN: r130971

gcc/config/cris/cris.md

index e248d4307edd759b6f2eacad1af577c027feeb64..1200a2283cb9d962d972c839efdad3466bbd47e0 100644 (file)
 ;; [rX=gotless_symbol].
 ;; The movsi for a gotless symbol could be split (post reload).
 \f
-;; 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.
-;; 3 The address of a global-offset-table-relative symbol + offset.
-;; 4 The offset within GOT of a symbol.
-;; 5 The offset within GOT of a symbol that has a PLT.
-
-(define_constants ; FIXME: reorder sanely.
-  [(CRIS_UNSPEC_PLT 0)
-   (CRIS_UNSPEC_FRAME_DEALLOC 1)
+
+(define_constants
+  [
+   ;; PLT reference from call expansion: operand 0 is the address,
+   ;; the mode is VOIDmode.  Always wrapped in CONST.
+   ;; The value is relative to the GOT.
+   (CRIS_UNSPEC_PLT_GOTREL 0)
+
+   ;; PLT reference from call expansion: operand 0 is the address,
+   ;; the mode is VOIDmode.  Always wrapped in CONST.
+   ;; The value is relative to the PC.  It's arch-dependent whether
+   ;; the offset counts from the start or the end of the current item.
+   (CRIS_UNSPEC_PLT_PCREL 1)
+
+   ;; The address of the global offset table as a source operand.
    (CRIS_UNSPEC_GOT 2)
+
+   ;; The offset from the global offset table to the operand.
    (CRIS_UNSPEC_GOTREL 3)
-   (CRIS_UNSPEC_GOTREAD 4)
-   (CRIS_UNSPEC_PLTGOTREAD 5)
-   (CRIS_UNSPEC_SWAP_BITS 6)])
+
+   ;; The PC-relative offset to the operand.  It's arch-dependent whether
+   ;; the offset counts from the start or the end of the current item.
+   (CRIS_UNSPEC_PCREL 4)
+
+   ;; The index into the global offset table of a symbol, while
+   ;; also generating a GOT entry for the symbol.
+   (CRIS_UNSPEC_GOTREAD 5)
+
+   ;; Similar to CRIS_UNSPEC_GOTREAD, but also generating a PLT entry.
+   (CRIS_UNSPEC_PLTGOTREAD 6)
+
+   ;; Condition for v32 casesi jump, since it needs to have if_then_else
+   ;; form with register as one branch and default label as other.
+   ;; Operand 0 is const_int 0.
+   (CRIS_UNSPEC_CASESI 7)
+
+   ;; Stack frame deallocation barrier.
+   (CRIS_UNSPEC_FRAME_DEALLOC 8)
+
+   ;; Swap all 32 bits of the operand; 31 <=> 0, 30 <=> 1...
+   (CRIS_UNSPEC_SWAP_BITS 9)
+  ])
 
 ;; Register numbers.
 (define_constants
    (CRIS_STATIC_CHAIN_REGNUM 7)
    (CRIS_FP_REGNUM 8)
    (CRIS_SP_REGNUM 14)
+   (CRIS_ACR_REGNUM 15)
    (CRIS_SRP_REGNUM 16)
    (CRIS_MOF_REGNUM 17)
    (CRIS_AP_REGNUM 18)
 ;; In short, any "slottable" instruction must be 16 bit and not refer
 ;; to pc, or alter it.
 ;;
-;; 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 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
-;; not add readability to the machine description.
+;; The possible values are "yes", "no", "has_slot", "has_return_slot"
+;; and "has_call_slot".
+;; Yes/no tells whether the insn is slottable or not.  Has_call_slot means
+;; that the insn is a call insn, which for CRIS v32 has a delay-slot.
+;; Of special concern is that no RTX_FRAME_RELATED insn must go in that
+;; call delay slot, as it's located in the address *after* the call insn,
+;; and the unwind machinery doesn't know about delay slots.
+;; Has_slot means that the insn is a branch insn (which are
+;; not considered slottable since 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 not add readability to the machine
+;; description.
+;; Has_return_slot is similar, for the return insn.
 ;;
 ;; The default that is defined here for this attribute is "no", not
 ;; slottable, not having a delay-slot, so there's no need to worry about
 ;; constraint pattern for the slottable pattern.  An alternative using
 ;; only "r" constraints is most often slottable.
 
-(define_attr "slottable" "no,yes,has_slot" (const_string "no"))
+(define_attr "slottable" "no,yes,has_slot,has_return_slot,has_call_slot"
+  (const_string "no"))
 
 ;; We also need attributes to sanely determine the condition code
 ;; state.  See cris_notice_update_cc for how this is used.
 
-(define_attr "cc" "none,clobber,normal" (const_string "normal"))
+(define_attr "cc" "none,clobber,normal,noov32,rev" (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
+;; A branch 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",
 ;; there also has to be a "%#" at the end of a "delayed" instruction
 
 (define_delay (eq_attr "slottable" "has_slot")
   [(eq_attr "slottable" "yes") (nil) (nil)])
+
+;; We can't put prologue insns in call-insn delay-slots when
+;; DWARF2 unwind info is emitted, because the unwinder matches the
+;; address after the insn.  It must see the return address of a call at
+;; a position at least *one byte after* the insn, or it'll think that
+;; the insn hasn't been executed.  If the insn is in a delay-slot of a
+;; call, it's just *exactly* after the insn.
+
+(define_delay (eq_attr "slottable" "has_call_slot")
+  [(and (eq_attr "slottable" "yes")
+       (ior (eq (symbol_ref "RTX_FRAME_RELATED_P (insn)")
+                (const_int 0))
+            (eq (symbol_ref "flag_exceptions")
+                (const_int 0))))
+   (nil) (nil)])
+
+;; The insn in the return insn slot must not be the
+;; return-address-register restore.  FIXME: Use has_slot and express
+;; as a parallel with a use of the return-address-register (currently
+;; only SRP).  However, this requires an amount of fixing tests for
+;; naked RETURN in middle-end.
+(define_delay (eq_attr "slottable" "has_return_slot")
+  [(and (eq_attr "slottable" "yes")
+       (eq (symbol_ref "dead_or_set_regno_p (insn, CRIS_SRP_REGNUM)")
+           (const_int 0)))
+   (nil) (nil)])
+
 \f
 ;; Iterator definitions.
 
 ;; Allow register and offsettable mem operands only; post-increment is
 ;; not worth the trouble.
 
-(define_insn "tstdi"
+(define_expand "tstdi"
+  [(set (cc0) (match_operand:DI 0 "nonimmediate_operand"))]
+  ""
+{
+  if (TARGET_V32 && MEM_P (operands[0]))
+    operands[0] = force_reg (DImode, operands[0]);
+})
+
+(define_insn "*tstdi_non_v32"
   [(set (cc0)
        (match_operand:DI 0 "nonimmediate_operand" "r,o"))]
-  ""
+  "!TARGET_V32"
   "test.d %M0\;ax\;test.d %H0")
 
+(define_insn "*tstdi_v32"
+  [(set (cc0)
+       (match_operand:DI 0 "register_operand" "r"))]
+  "TARGET_V32"
+  "cmpq 0,%M0\;ax\;cmpq 0,%H0")
+
 ;; No test insns with side-effect on the mem addressing.
 ;;
 ;; See note on cmp-insns with side-effects (or lack of them)
 
 ;; Normal named test patterns from SI on.
-;; FIXME: Seems they should change to be in order smallest..largest.
 
-(define_insn "tst<mode>"
+(define_insn "tstsi"
   [(set (cc0)
-       (match_operand:BWD 0 "nonimmediate_operand" "r,Q>,m"))]
+       (match_operand:SI 0 "nonimmediate_operand" "r,Q>,m"))]
   ""
-  "test<m> %0"
+{
+  if (which_alternative == 0 && TARGET_V32)
+    return "cmpq 0,%0";
+  return "test.d %0";
+}
   [(set_attr "slottable" "yes,yes,no")])
 
+(define_expand "tst<mode>"
+  [(set (cc0)
+       (match_operand:BW 0 "nonimmediate_operand"))]
+  ""
+  "")
+
+(define_insn "*tst<mode>_cmp"
+  [(set (cc0)
+       (match_operand:BW 0 "nonimmediate_operand" "r,Q>,m"))]
+  "cris_cc0_user_requires_cmp (insn)"
+  "@
+   cmp<m> 0,%0
+   test<m> %0
+   test<m> %0"
+  [(set_attr "slottable" "no,yes,no")])
+
+(define_insn "*tst<mode>_non_cmp"
+  [(set (cc0)
+       (match_operand:BW 0 "nonimmediate_operand" "r,Q>,m"))]
+  "!cris_cc0_user_requires_cmp (insn)"
+  "@
+   move<m> %0,%0
+   test<m> %0
+   test<m> %0"
+  [(set_attr "slottable" "yes,yes,no")
+   (set_attr "cc" "noov32,*,*")])
+
 ;; It seems that the position of the sign-bit and the fact that 0.0 is
 ;; all 0-bits would make "tstsf" a straight-forward implementation;
 ;; either "test.d" it for positive/negative or "btstq 30,r" it for
 ;; DImode for anything else but a structure/block-mode.  Just do the
 ;; obvious stuff for the straight-forward constraint letters.
 
-(define_insn "cmpdi"
+(define_expand "cmpdi"
+  [(set (cc0)
+       (compare (match_operand:DI 0 "nonimmediate_operand" "")
+                (match_operand:DI 1 "general_operand" "")))]
+  ""
+{
+  if (TARGET_V32 && !REG_P (operands[0]))
+    operands[0] = force_reg (DImode, operands[0]);
+  if (TARGET_V32 && MEM_P (operands[1]))
+    operands[1] = force_reg (DImode, operands[1]);
+})
+
+(define_insn "*cmpdi_non_v32"
   [(set (cc0)
        (compare (match_operand:DI 0 "nonimmediate_operand" "r,r,r,r,r,r,o")
                 (match_operand:DI 1 "general_operand" "K,I,P,n,r,o,r")))]
-  ""
+  "!TARGET_V32"
   "@
    cmpq %1,%M0\;ax\;cmpq 0,%H0
    cmpq %1,%M0\;ax\;cmpq -1,%H0
    cmp.d %M1,%M0\;ax\;cmp.d %H1,%H0
    cmp.d %M0,%M1\;ax\;cmp.d %H0,%H1")
 
+(define_insn "*cmpdi_v32"
+  [(set (cc0)
+       (compare (match_operand:DI 0 "register_operand"  "r,r,r,r,r")
+                (match_operand:DI 1 "nonmemory_operand" "K,I,P,n,r")))]
+  "TARGET_V32"
+  "@
+   cmpq %1,%M0\;ax\;cmpq 0,%H0
+   cmpq %1,%M0\;ax\;cmpq -1,%H0
+   cmp%e1.%z1 %1,%M0\;ax\;cmpq %H1,%H0
+   cmp.d %M1,%M0\;ax\;cmp.d %H1,%H0
+   cmp.d %M1,%M0\;ax\;cmp.d %H1,%H0")
+
 ;; Note that compare insns with side effect addressing mode (e.g.):
 ;;
 ;; cmp.S [rx=ry+i],rz;
                            [(match_operand:BW 0 "memory_operand" "Q>,m")])
         (match_operand:SI 1 "register_operand" "r,r")))]
   ""
-  "cmp%e2<m> %0,%1" ; The function cris_notice_update_cc knows about
-                    ; swapped operands to compares.
-  [(set_attr "slottable" "yes,no")])
+  "cmp%e2<m> %0,%1"
+  [(set_attr "slottable" "yes,no")
+   (set_attr "cc" "rev")])
 \f
-;; The "normal" compare patterns, from SI on.
+;; The "normal" compare patterns, from SI on.  Special-cases with zero
+;; should not happen.
 
 (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, Q>,r,r,m")
+        (match_operand:SI 1 "general_operand"      "I,r,Q>,r, P,g,r")))]
   ""
   "@
    cmpq %1,%0
    cmp.d %1,%0
    cmp.d %1,%0
-   test.d %0
-   test.d %0
    cmp.d %0,%1
    cmp%e1.%z1 %1,%0
    cmp.d %1,%0
-   test.d %0
    cmp.d %0,%1"
-  [(set_attr "slottable" "yes,yes,yes,yes,yes,yes,no,no,no,no")])
+  [(set_attr "slottable" "yes,yes,yes,yes,no,no,no")
+   (set_attr "cc" "normal,normal,normal,rev,normal,normal,rev")])
 
 (define_insn "cmp<mode>"
   [(set (cc0)
-       (compare
-        (match_operand:BW 0 "nonimmediate_operand" "r,r, r,Q>,Q>,r,m,m")
-        (match_operand:BW 1 "general_operand"      "r,Q>,M,M, r, g,M,r")))]
+       (compare (match_operand:BW 0 "nonimmediate_operand" "r,r, Q>,r,m")
+                (match_operand:BW 1 "general_operand"      "r,Q>,r, g,r")))]
   ""
   "@
    cmp<m> %1,%0
    cmp<m> %1,%0
-   test<m> %0
-   test<m> %0
    cmp<m> %0,%1
    cmp<m> %1,%0
-   test<m> %0
    cmp<m> %0,%1"
-  [(set_attr "slottable" "yes,yes,yes,yes,yes,no,no,no")])
+  [(set_attr "slottable" "yes,yes,yes,no,no")
+   (set_attr "cc" "normal,normal,rev,normal,rev")])
 \f
 ;; Pattern matching the BTST insn.
 ;; It is useful for "if (i & val)" constructs, where val is an exact
         (match_operand:SI 1 "const_int_operand" "K,n,K,n,K,n,n")
         (match_operand:SI 2 "nonmemory_operand" "M,M,K,n,r,r,r")))]
   ;; Either it is a single bit, or consecutive ones starting at 0.
+  ;; The btst ones depend on stuff in NOTICE_UPDATE_CC.
   "CONST_INT_P (operands[1])
    && (operands[1] == const1_rtx || operands[2] == const0_rtx)
    && (REG_S_P (operands[0])
        || (operands[1] == const1_rtx
           && REG_S_P (operands[2])
           && CONST_INT_P (operands[0])
-          && exact_log2 (INTVAL (operands[0])) >= 0))"
+          && exact_log2 (INTVAL (operands[0])) >= 0))
+   && !TARGET_CCINIT"
 
-;; The last "&&" condition above should be caught by some kind of
+;; The next-to-last "&&" condition above should be caught by some kind of
 ;; canonicalization in gcc, but we can easily help with it here.
 ;;  It results from expressions of the type
 ;; "power_of_2_value & (1 << y)".
 
   "@
    btstq (%1-1),%0
-   test.d %0
+   cmpq 0,%0
    btstq %2,%0
    clearf nz
    btst %2,%0
    clearf nz
    cmpq %p0,%2"
- [(set_attr "slottable" "yes")])
+ [(set_attr "slottable" "yes")
+  (set_attr "cc" "noov32")])
 \f
 ;; Move insns.
 
        (match_operand:DI 1 "general_operand" ""))]
   ""
 {
-  if (MEM_P (operands[0]) && operands[1] != const0_rtx)
+  if (MEM_P (operands[0])
+      && operands[1] != const0_rtx
+      && (!TARGET_V32 || (!REG_P (operands[1]) && can_create_pseudo_p ())))
     operands[1] = copy_to_mode_reg (DImode, operands[1]);
 
   /* Some other ports (as of 2001-09-10 for example mcore and romp) also
     }
 })
 
-(define_insn "*movdi_insn"
+(define_insn_and_split "*movdi_insn_non_v32"
   [(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"
-  "#")
+       (match_operand:DI 1 "general_operand"      "rx,g,rxM"))]
+  "(register_operand (operands[0], DImode)
+    || register_operand (operands[1], DImode)
+    || operands[1] == const0_rtx)
+   && !TARGET_V32"
+  "#"
+  "&& reload_completed"
+  [(match_dup 2)]
+  "operands[2] = cris_split_movdx (operands);")
 
+;; Overlapping (but non-identical) source memory address and destination
+;; register would be a compiler bug, so we don't have to specify that.
+(define_insn "*movdi_v32"
+  [(set
+    (match_operand:DI 0 "nonimmediate_operand" "=r,rx,&r,>, m,r,x,m")
+    (match_operand:DI 1 "general_operand"     "rxi,r>,m, rx,r,m,m,x"))]
+  "TARGET_V32"
+{
+  switch (which_alternative)
+    {
+      /* FIXME: 1) Use autoincrement where possible.  2) Have peephole2,
+        particularly for cases where the address register is dead.  */
+    case 5:
+      if (REGNO (operands[0]) == REGNO (XEXP (operands[1], 0)))
+       return "addq 4,%L1\;move.d %1,%H0\;subq 4,%L1\;move.d %1,%M0";
+      gcc_assert (REGNO (operands[0]) + 1 == REGNO (XEXP (operands[1], 0)));
+      return "move.d [%L1+],%M0\;move.d [%L1],%H0";
+    case 2:
+      /* We could do away with the addq if we knew the address-register
+        isn't ACR.  If we knew the address-register is dead, we could do
+        away with the subq too.  */
+      return "move.d [%L1],%M0\;addq 4,%L1\;move.d [%L1],%H0\;subq 4,%L1";
+    case 4:
+      return "move.d %M1,[%L0]\;addq 4,%L0\;move.d %H1,[%L0]\;subq 4,%L0";
+    case 6:
+      return "move [%L1],%M0\;addq 4,%L1\;move [%L1],%H0\;subq 4,%L1";
+    case 7:
+      return "move %M1,[%L0]\;addq 4,%L0\;move %H1,[%L0]\;subq 4,%L0";
+
+    default:
+      return "#";
+    }
+}
+  ;; The non-split cases clobber cc0 because of their adds and subs.
+  ;; Beware that NOTICE_UPDATE_CC is called before the forced split happens.
+  [(set_attr "cc" "*,*,clobber,*,clobber,clobber,*,*")])
+
+;; Much like "*movdi_insn_non_v32".  Overlapping registers and constants
+;; is handled so much better in cris_split_movdx.
 (define_split
   [(set (match_operand:DI 0 "nonimmediate_operand" "")
        (match_operand:DI 1 "general_operand" ""))]
-  "reload_completed"
+  "TARGET_V32
+   && reload_completed
+   && (!MEM_P (operands[0]) || !REG_P (XEXP (operands[0], 0)))
+   && (!MEM_P (operands[1]) || !REG_P (XEXP (operands[1], 0)))"
   [(match_dup 2)]
   "operands[2] = cris_split_movdx (operands);")
 \f
 ;;
 ;; move.S1 [rx=ry+rz.S],rw avoiding when rx is ry, or rw is rx
 ;; FIXME: These could have anonymous mode for operand 0.
+;; FIXME: Special registers' alternatives too.
 
 (define_insn "*mov_side<mode>_biap"
   [(set (match_operand:BW 0 "register_operand" "=r,r")
      offset?  */
     if (flag_pic
        && CONSTANT_ADDRESS_P (operands[1])
-       && !cris_valid_pic_const (operands[1]))
+       && !cris_valid_pic_const (operands[1], false))
       {
        enum cris_pic_symbol_type t = cris_pic_symbol_type_of (operands[1]);
 
               destination register for the symbol.  It might not be
               worth it.  Measure.  */
            current_function_uses_pic_offset_table = 1;
-           if (t == cris_gotrel_symbol)
+           if (t == cris_rel_symbol)
              {
                /* Change a "move.d sym(+offs),rN" into (allocate register rM)
+                  for pre-v32:
+                  "move.d (const (plus (unspec [sym]
+                   CRIS_UNSPEC_GOTREL) offs)),rM" "add.d rPIC,rM,rN"
+                  and for v32:
                   "move.d (const (plus (unspec [sym]
-                   CRIS_UNSPEC_GOTREL) offs)),rM" "add.d rPIC,rM,rN"  */
+                   CRIS_UNSPEC_PCREL) offs)),rN".  */
                rtx tem, rm, rn = operands[0];
                rtx sym = GET_CODE (operands[1]) != CONST
                  ? operands[1] : get_related_value (operands[1]);
                HOST_WIDE_INT offs = get_integer_term (operands[1]);
 
                gcc_assert (can_create_pseudo_p ());
-               tem = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, sym),
-                                     CRIS_UNSPEC_GOTREL);
-               if (offs != 0)
-                 tem = plus_constant (tem, offs);
-               rm = gen_reg_rtx (Pmode);
-               emit_move_insn (rm, gen_rtx_CONST (Pmode, tem));
-               if (expand_binop (Pmode, add_optab, rm, pic_offset_table_rtx,
-                                 rn, 0, OPTAB_LIB_WIDEN) != rn)
-                 internal_error ("expand_binop failed in movsi gotrel");
+
+               if (TARGET_V32)
+                 {
+                   tem = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, sym),
+                                         CRIS_UNSPEC_PCREL);
+                   if (offs != 0)
+                     tem = plus_constant (tem, offs);
+                   rm = rn;
+                   emit_move_insn (rm, gen_rtx_CONST (Pmode, tem));
+                 }
+               else
+                 {
+                   /* We still uses GOT-relative addressing for
+                      pre-v32.  */
+                   current_function_uses_pic_offset_table = 1;
+                   tem = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, sym),
+                                         CRIS_UNSPEC_GOTREL);
+                   if (offs != 0)
+                     tem = plus_constant (tem, offs);
+                   rm = gen_reg_rtx (Pmode);
+                   emit_move_insn (rm, gen_rtx_CONST (Pmode, tem));
+                   if (expand_binop (Pmode, add_optab, rm, pic_offset_table_rtx,
+                                     rn, 0, OPTAB_LIB_WIDEN) != rn)
+                     internal_error ("expand_binop failed in movsi gotrel");
+                 }
                DONE;
              }
            else if (t == cris_got_symbol)
                   aliases other same symbols is unimportant.  */
                set_mem_alias_set (mem, new_alias_set ());
                MEM_NOTRAP_P (mem) = 1;
+
+               /* We can set the GOT memory read of a non-called symbol
+                  to readonly, but not that of a call symbol, as those
+                  are subject to lazy evaluation and usually have the value
+                  changed from the first call to the second (but
+                  constant thereafter).  */
                MEM_READONLY_P (mem) = 1;
                emit_move_insn (rn, mem);
                DONE;
 (define_insn "*movsi_got_load"
   [(set (reg:SI CRIS_GOT_REGNUM) (unspec:SI [(const_int 0)] CRIS_UNSPEC_GOT))]
   "flag_pic"
-  "move.d $pc,%:\;sub.d .:GOTOFF,%:"
+{
+  return TARGET_V32
+    ? "lapc _GLOBAL_OFFSET_TABLE_,%:"
+    : "move.d $pc,%:\;sub.d .:GOTOFF,%:";
+}
   [(set_attr "cc" "clobber")])
 
 (define_insn "*movsi_internal"
   [(set
-    (match_operand:SI 0 "nonimmediate_operand" "=r,r, r,Q>,r,Q>,g,r,r, r,g,rQ>,x,  m,x")
+    (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 "cris_general_operand_or_pic_source"
+                      "r,Q>,M,M, I,r, M,n,!S,g,r,x,  rQ>,x,gi"))]
     ;; Note that we prefer not to use the S alternative (if for some reason
-    ;; it competes with others), but g matches S.
-    (match_operand:SI 1 "general_operand"      "r,Q>,M,M, I,r, M,n,!S,g,r,x,  rQ>,x,gi"))]
+    ;; it competes with others) above, but g matches S.
   ""
 {
   /* Better to have c-switch here; it is worth it to optimize the size of
      letters.  FIXME: Check again.  It seems this could shrink a bit.  */
   switch (which_alternative)
     {
+    case 9:
+      if (TARGET_V32)
+       {
+        if (!flag_pic
+            && (GET_CODE (operands[1]) == SYMBOL_REF
+                || GET_CODE (operands[1]) == LABEL_REF
+                || GET_CODE (operands[1]) == CONST))
+          {
+            /* FIXME: Express this through (set_attr cc none) instead,
+               since we can't express the ``none'' at this point.  FIXME:
+               Use lapc for everything except const_int and when next cc0
+               user would want the flag setting.  */
+            CC_STATUS_INIT;
+            return "lapc %1,%0";
+          }
+        if (flag_pic == 1
+            && GET_CODE (operands[1]) == CONST
+            && GET_CODE (XEXP (operands[1], 0)) == UNSPEC
+            && XINT (XEXP (operands[1], 0), 1) == CRIS_UNSPEC_GOTREAD)
+          return "movu.w %1,%0";
+       }
+       /* FALLTHROUGH */
     case 0:
     case 1:
     case 5:
-    case 9:
     case 10:
       return "move.d %1,%0";
 
        tem = XEXP (tem, 0);
        if (GET_CODE (tem) == PLUS
            && GET_CODE (XEXP (tem, 0)) == UNSPEC
-           && XINT (XEXP (tem, 0), 1) == CRIS_UNSPEC_GOTREL
+           && (XINT (XEXP (tem, 0), 1) == CRIS_UNSPEC_GOTREL
+               || XINT (XEXP (tem, 0), 1) == CRIS_UNSPEC_PCREL)
            && CONST_INT_P (XEXP (tem, 1)))
          tem = XEXP (tem, 0);
        gcc_assert (GET_CODE (tem) == UNSPEC);
               indexed addressing mode.  */
            if (flag_pic == 1)
              return "movs.w %1,%0";
+           return "move.d %1,%0";
+
          case CRIS_UNSPEC_GOTREL:
-         case CRIS_UNSPEC_PLT:
+         case CRIS_UNSPEC_PLT_GOTREL:
+           gcc_assert (!TARGET_V32);
            return "move.d %1,%0";
 
+         case CRIS_UNSPEC_PCREL:
+         case CRIS_UNSPEC_PLT_PCREL:
+           gcc_assert (TARGET_V32);
+           return "lapc %1,%0";
+
          default:
            gcc_unreachable ();
          }
    move %1,%0
    move %1,%0"
   [(set_attr "slottable" "yes,yes,yes,yes,yes,no,no,no,yes,yes,yes,no,yes,no")])
+\f
+;; Movem patterns.  Primarily for use in function prologue and epilogue.
+;; The V32 variants have an ordering matching the expectations of the
+;; standard names "load_multiple" and "store_multiple"; pre-v32 movem
+;; store R0 in the highest memory location.
+
+(define_expand "load_multiple"
+  [(match_operand:SI 0 "register_operand" "")
+   (match_operand:SI 1 "memory_operand" "")
+   (match_operand:SI 2 "const_int_operand" "")]
+  "TARGET_V32"
+{
+  rtx indreg;
+
+  /* Apparently the predicate isn't checked, so we need to do so
+     manually.  Once happened for libstdc++-v3 locale_facets.tcc.  */
+  if (!MEM_P (operands[1]))
+    FAIL;
+
+  indreg = XEXP (operands[1], 0);
+
+  if (GET_CODE (indreg) == POST_INC)
+    indreg = XEXP (indreg, 0);
+  if (!REG_P (indreg)
+      || GET_CODE (operands[2]) != CONST_INT
+      || !REG_P (operands[0])
+      || REGNO (operands[0]) != 0
+      || INTVAL (operands[2]) > CRIS_SP_REGNUM
+      || (int) REGNO (indreg) < INTVAL (operands[2]))
+    FAIL;
+  gcc_unreachable ();
+  emit_insn (cris_gen_movem_load (operands[1], operands[2], 0));
+  DONE;
+})
+
+(define_expand "store_multiple"
+  [(match_operand:SI 0 "memory_operand" "")
+   (match_operand:SI 1 "register_operand" "")
+   (match_operand:SI 2 "const_int_operand" "")]
+  "TARGET_V32"
+{
+  rtx indreg;
+
+  /* See load_multiple.  */
+  if (!MEM_P (operands[0]))
+    FAIL;
+
+  indreg = XEXP (operands[0], 0);
+
+  if (GET_CODE (indreg) == POST_INC)
+    indreg = XEXP (indreg, 0);
+  if (!REG_P (indreg)
+      || GET_CODE (operands[2]) != CONST_INT
+      || !REG_P (operands[1])
+      || REGNO (operands[1]) != 0
+      || INTVAL (operands[2]) > CRIS_SP_REGNUM
+      || (int) REGNO (indreg) < INTVAL (operands[2]))
+    FAIL;
+  gcc_unreachable ();
+  cris_emit_movem_store (operands[0], operands[2], 0, false);
+  DONE;
+})
 
-;; 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")
 ;; Note that for the 'P' constraint, the high part can be -1 or 0.  We
 ;; output the insn through the 'A' output modifier as "adds.w" and "addq",
 ;; respectively.
-(define_insn "adddi3"
+(define_expand "adddi3"
+  [(set (match_operand:DI 0 "register_operand")
+       (plus:DI (match_operand:DI 1 "register_operand")
+                (match_operand:DI 2 "general_operand")))]
+  ""
+{
+  if (MEM_P (operands[2]) && TARGET_V32)
+    operands[2] = force_reg (DImode, operands[2]);
+})
+
+(define_insn "*adddi3_non_v32"
   [(set (match_operand:DI 0 "register_operand" "=r,r,r,&r,&r")
        (plus:DI (match_operand:DI 1 "register_operand" "%0,0,0,0,r")
                 (match_operand:DI 2 "general_operand" "J,N,P,g,!To")))]
-  ""
+  "!TARGET_V32"
   "@
    addq %2,%M0\;ax\;addq 0,%H0
    subq %n2,%M0\;ax\;subq 0,%H0
    add.d %M2,%M0\;ax\;add.d %H2,%H0
    add.d %M2,%M1,%M0\;ax\;add.d %H2,%H1,%H0")
 
-(define_insn "addsi3"
+; It seems no use allowing a memory operand for this one, because we'd
+; need a scratch register for incrementing the address.
+(define_insn "*adddi3_v32"
+  [(set (match_operand:DI 0 "register_operand" "=r,r,r,r,r")
+       (plus:DI (match_operand:DI 1 "register_operand" "%0,0,0,0,0")
+                (match_operand:DI 2 "nonmemory_operand" "J,N,P,r,n")))]
+  "TARGET_V32"
+  "@
+   addq %2,%M0\;addc 0,%H0
+   subq %n2,%M0\;ax\;subq 0,%H0
+   add%e2.%z2 %2,%M0\;addc %H2,%H0
+   add.d %M2,%M0\;addc %H2,%H0
+   add.d %M2,%M0\;addc %H2,%H0")
+
+(define_expand "add<mode>3"
+  [(set (match_operand:BWD 0 "register_operand")
+       (plus:BWD
+        (match_operand:BWD 1 "register_operand")
+        (match_operand:BWD 2 "general_operand")))]
+  ""
+  "")
+
+(define_insn "*addsi3_non_v32"
   [(set (match_operand:SI 0 "register_operand"  "=r,r, r,r,r,r, r,r,  r")
        (plus:SI
         (match_operand:SI 1 "register_operand" "%0,0, 0,0,0,0, 0,r,  r")
 ;; register as in destination.  This will happen after insn splitting.
 ;; gcc <= 2.7.2.  FIXME: Check for gcc-2.9x
 
- ""
+ "!TARGET_V32"
 {
   switch (which_alternative)
     {
        tem = XEXP (tem, 0);
        if (GET_CODE (tem) == PLUS
            && GET_CODE (XEXP (tem, 0)) == UNSPEC
+           /* We don't allow CRIS_UNSPEC_PCREL here; we can't have a
+              pc-relative operand in an add insn.  */
            && XINT (XEXP (tem, 0), 1) == CRIS_UNSPEC_GOTREL
            && CONST_INT_P (XEXP (tem, 1)))
          tem = XEXP (tem, 0);
               indexed addressing mode.  */
            if (flag_pic == 1)
              return "adds.w %2,%0";
-           /* Fall through.  */
-         case CRIS_UNSPEC_PLT:
+           return "add.d %2,%0";
+
+         case CRIS_UNSPEC_PLT_GOTREL:
          case CRIS_UNSPEC_GOTREL:
            return "add.d %2,%0";
          default:
          }
       }
     case 6:
-      return "add.d %2,%0";
+      return "add%u2 %2,%0";
     case 7:
       return "add.d %2,%1,%0";
     case 8:
     }
 }
  [(set_attr "slottable" "yes,yes,yes,yes,no,no,no,no,yes")])
+
+; FIXME: Check what's best: having the three-operand ACR alternative
+; before or after the corresponding-operand2 alternative.  Check for
+; *all* insns.  FIXME: constant constraint letter for -128..127.
+(define_insn "*addsi3_v32"
+  [(set (match_operand:SI 0 "register_operand"  "=r,!a,r,!a, r,r,!a,r,!a,r,r,r,!a")
+       (plus:SI
+        (match_operand:SI 1 "register_operand" "%0,r, 0, r, 0,0,r, 0,r, 0,0,0,r")
+        (match_operand:SI 2 "general_operand"  "r, r, Q>,Q>,J,N,NJ,L,L, P,n,g,g")))]
+  "TARGET_V32"
+  "@
+   add.d %2,%0
+   addi %2.b,%1,%0
+   add.d %2,%0
+   addo.d %2,%1,%0
+   addq %2,%0
+   subq %n2,%0
+   addoq %2,%1,%0
+   adds.w %2,%0
+   addo %2,%1,%0
+   addu.w %2,%0
+   add.d %2,%0
+   add%u2 %2,%0
+   addo.%Z2 %2,%1,%0"
+  [(set_attr "slottable" "yes,yes,yes,yes,yes,yes,yes,no,no,no,no,no,no")
+   (set_attr "cc" "*,none,*,none,*,*,none,*,*,*,*,*,none")])
 \f
-(define_insn "addhi3"
+(define_insn "*addhi3_non_v32"
   [(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")))]
-  ""
+  "!TARGET_V32"
   "@
    add.w %2,%0
    add.w %2,%0
   [(set_attr "slottable" "yes,yes,yes,yes,no,no")
    (set_attr "cc" "normal,normal,clobber,clobber,normal,normal")])
 
-(define_insn "addqi3"
+(define_insn "*addhi3_v32"
+  [(set (match_operand:HI 0 "register_operand" "=r, !a,r,!a, r,r,!a,r,!a")
+       (plus:HI
+        (match_operand:HI 1 "register_operand" "%0,r, 0, r, 0,0,r, 0,r")
+        (match_operand:HI 2 "general_operand"  "r, r, Q>,Q>,J,N,NJ,g,g")))]
+  "TARGET_V32"
+  "@
+   add.w %2,%0
+   addi %2.b,%1,%0
+   add.w %2,%0
+   addo.w %2,%1,%0
+   addq %2,%0
+   subq %n2,%0
+   addoq %2,%1,%0
+   add.w %2,%0
+   addo.w %2,%1,%0"
+  [(set_attr "slottable" "yes,yes,yes,yes,yes,yes,yes,no,no")
+   (set_attr "cc" "*,none,*,none,clobber,clobber,none,*,none")])
+
+(define_insn "*addqi3_non_v32"
   [(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")))]
-  ""
+  "!TARGET_V32"
   "@
    add.b %2,%0
    add.b %2,%0
    add.b %2,%1,%0"
   [(set_attr "slottable" "yes,yes,yes,yes,yes,no,no")
    (set_attr "cc" "normal,normal,clobber,clobber,clobber,normal,normal")])
+
+(define_insn "*addqi3_v32"
+  [(set (match_operand:QI 0 "register_operand"  "=r,!a,r,!a, r,r,!a,r,r,!a")
+       (plus:QI
+        (match_operand:QI 1 "register_operand" "%0,r, 0, r, 0,0,r, 0,0,r")
+        (match_operand:QI 2 "general_operand"   "r,r, Q>,Q>,J,N,NJ,O,g,g")))]
+  "TARGET_V32"
+  "@
+   add.b %2,%0
+   addi %2.b,%1,%0
+   add.b %2,%0
+   addo.b %2,%1,%0
+   addq %2,%0
+   subq %n2,%0
+   addoq %2,%1,%0
+   subQ -%b2,%0
+   add.b %2,%0
+   addo.b %2,%1,%0"
+  [(set_attr "slottable" "yes,yes,yes,yes,yes,yes,yes,yes,no,no")
+   (set_attr "cc" "*,none,*,none,clobber,clobber,none,clobber,*,none")])
 \f
 ;; Subtract.
 ;;
 ;; Note that for the 'P' constraint, the high part can be -1 or 0.  We
 ;; output the insn through the 'D' output modifier as "subs.w" and "subq",
 ;; respectively.
-(define_insn "subdi3"
+(define_expand "subdi3"
+  [(set (match_operand:DI 0 "register_operand")
+       (minus:DI (match_operand:DI 1 "register_operand")
+                 (match_operand:DI 2 "general_operand")))]
+  ""
+{
+  if (TARGET_V32 && MEM_P (operands[2]))
+    operands[2] = force_reg (DImode, operands[2]);
+})
+
+(define_insn "*subdi3_non_v32"
   [(set (match_operand:DI 0 "register_operand" "=r,r,r,&r,&r")
        (minus:DI (match_operand:DI 1 "register_operand" "0,0,0,0,r")
                  (match_operand:DI 2 "general_operand" "J,N,P,g,!To")))]
-  ""
+  "!TARGET_V32"
   "@
    subq %2,%M0\;ax\;subq 0,%H0
    addq %n2,%M0\;ax\;addq 0,%H0
    sub.d %M2,%M0\;ax\;sub.d %H2,%H0
    sub.d %M2,%M1,%M0\;ax\;sub.d %H2,%H1,%H0")
 
-(define_insn "subsi3"
+(define_insn "*subdi3_v32"
+  [(set (match_operand:DI 0 "register_operand" "=r,r,r,&r")
+       (minus:DI (match_operand:DI 1 "register_operand" "0,0,0,0")
+                 (match_operand:DI 2 "nonmemory_operand" "J,N,P,r")))]
+  "TARGET_V32"
+  "@
+   subq %2,%M0\;ax\;subq 0,%H0
+   addq %n2,%M0\;ax\;addq 0,%H0
+   sub%e2.%z2 %2,%M0\;ax\;%D2 %H2,%H0
+   sub.d %M2,%M0\;ax\;sub.d %H2,%H0")
+
+(define_expand "sub<mode>3"
+  [(set (match_operand:BWD 0 "register_operand")
+       (minus:BWD
+        (match_operand:BWD 1 "register_operand")
+        (match_operand:BWD 2 "general_operand")))]
+  ""
+  "")
+
+(define_insn "*subsi3_non_v32"
   [(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")))]
-  ""
+  "!TARGET_V32"
 
 ;; This does not do the optimal: "addu.w 65535,r0" when %2 is negative.
 ;; But then again, %2 should not be negative.
    sub.d %2,%0
    sub.d %2,%1,%0"
   [(set_attr "slottable" "yes,yes,yes,yes,no,no,no,no")])
+
+(define_insn "*subsi3_v32"
+  [(set (match_operand:SI 0 "register_operand" "=r,r,r,r,r,r,r")
+       (minus:SI
+        (match_operand:SI 1 "register_operand" "0,0,0,0,0,0,0")
+        (match_operand:SI 2 "general_operand" "r,Q>,J,N,P,n,g")))]
+  "TARGET_V32"
+  "@
+   sub.d %2,%0
+   sub.d %2,%0
+   subq %2,%0
+   addq %n2,%0
+   sub%e2.%z2 %2,%0
+   sub.d %2,%0
+   sub.d %2,%0"
+  [(set_attr "slottable" "yes,yes,yes,yes,no,no,no")])
 \f
-(define_insn "sub<mode>3"
+(define_insn "*sub<mode>3_nonv32"
   [(set (match_operand:BW 0 "register_operand"         "=r,r, r,r,r,r")
        (minus:BW (match_operand:BW 1 "register_operand" "0,0, 0,0,0,r")
                  (match_operand:BW 2 "general_operand"  "r,Q>,J,N,g,!To")))]
-  ""
+  "!TARGET_V32"
   "@
    sub<m> %2,%0
    sub<m> %2,%0
    sub<m> %2,%1,%0"
   [(set_attr "slottable" "yes,yes,yes,yes,no,no")
    (set_attr "cc" "normal,normal,clobber,clobber,normal,normal")])
+
+(define_insn "*sub<mode>3_v32"
+  [(set (match_operand:BW 0 "register_operand" "=r,r,r,r,r")
+       (minus:BW (match_operand:BW 1 "register_operand" "0,0,0,0,0")
+                 (match_operand:BW 2 "general_operand" "r,Q>,J,N,g")))]
+  "TARGET_V32"
+  "@
+   sub<m> %2,%0
+   sub<m> %2,%0
+   subq %2,%0
+   addq %n2,%0
+   sub<m> %2,%0"
+  [(set_attr "slottable" "yes,yes,yes,yes,no")
+   (set_attr "cc" "normal,normal,clobber,clobber,normal")])
 \f
 ;; CRIS has some add/sub-with-sign/zero-extend instructions.
 ;;  Although these perform sign/zero-extension to SImode, they are
 \f
 
 ;; As with op.S we may have to add special pattern to match commuted
-;; operands to adds/addu  and bound
+;; operands to adds/addu and bound
 ;;
 ;; adds/addu/bound [rx=ry+rz.S]
 
 ;; QImode to HImode
 ;; FIXME: GCC should widen.
 
-(define_insn "*extopqihi"
+(define_insn "*extopqihi_non_v32"
   [(set (match_operand:HI 0 "register_operand" "=r,r,r,r")
        (match_operator:HI
         3 "cris_additive_operand_extend_operator"
          (match_operator:HI
           4 "cris_extend_operator"
           [(match_operand:QI 2 "nonimmediate_operand" "r,Q>,m,!To")])]))]
-  "GET_MODE_SIZE (GET_MODE (operands[0])) <= UNITS_PER_WORD
+  "!TARGET_V32 && GET_MODE_SIZE (GET_MODE (operands[0])) <= UNITS_PER_WORD
    && (operands[1] != frame_pointer_rtx || GET_CODE (operands[3]) != PLUS)"
   "@
    %x3%E4.%m4 %2,%0
   [(set_attr "slottable" "yes,yes,no,no")
    (set_attr "cc" "clobber")])
 
+(define_insn "*extopqihi_v32"
+  [(set (match_operand:HI 0 "register_operand" "=r,r")
+       (match_operator:HI
+        3 "cris_additive_operand_extend_operator"
+        [(match_operand:HI 1 "register_operand" "0,0")
+         (match_operator:HI
+          4 "cris_extend_operator"
+          [(match_operand:QI 2 "nonimmediate_operand" "r,m")])]))]
+  "TARGET_V32"
+  "%x3%e4.%m4 %2,%0"
+  [(set_attr "slottable" "yes")
+   (set_attr "cc" "clobber")])
+
 ;; QImode to SImode
 
-(define_insn "*extop<mode>si"
+(define_insn "*extop<mode>si_non_v32"
   [(set (match_operand:SI 0 "register_operand" "=r,r,r,r")
        (match_operator:SI
         3 "cris_operand_extend_operator"
          (match_operator:SI
           4 "cris_extend_operator"
           [(match_operand:BW 2 "nonimmediate_operand" "r,Q>,m,!To")])]))]
-  "(GET_CODE (operands[3]) != UMIN || GET_CODE (operands[4]) == ZERO_EXTEND)
+  "!TARGET_V32
+   && (GET_CODE (operands[3]) != UMIN || GET_CODE (operands[4]) == ZERO_EXTEND)
    && GET_MODE_SIZE (GET_MODE (operands[0])) <= UNITS_PER_WORD
    && (operands[1] != frame_pointer_rtx || GET_CODE (operands[3]) != PLUS)"
   "@
    %x3%E4<m> %2,%0
    %x3%E4<m> %2,%1,%0"
   [(set_attr "slottable" "yes,yes,no,no")])
-\f
 
+(define_insn "*extop<mode>si_v32"
+  [(set (match_operand:SI 0 "register_operand" "=r,r")
+       (match_operator:SI
+        3 "cris_additive_operand_extend_operator"
+        [(match_operand:SI 1 "register_operand" "0,0")
+         (match_operator:SI
+          4 "cris_extend_operator"
+          [(match_operand:BW 2 "nonimmediate_operand" "r,m")])]))]
+  "TARGET_V32"
+  "%x3%e4.%m4 %2,%0"
+  [(set_attr "slottable" "yes")])
+\f
 ;; As with the side-effect patterns, may have to have swapped operands for add.
-;; FIXME: *should* be redundant to gcc.
+;; For commutative operands, these are the canonical forms.
 
 ;; QImode to HImode
 
-(define_insn "*extopqihi_swap"
+(define_insn "*addxqihi_swap_non_v32"
   [(set (match_operand:HI 0 "register_operand" "=r,r,r,r")
        (plus:HI
         (match_operator:HI
          3 "cris_extend_operator"
          [(match_operand:QI 2 "nonimmediate_operand" "r,Q>,m,!To")])
         (match_operand:HI 1 "register_operand" "0,0,0,r")))]
-  "operands[1] != frame_pointer_rtx"
+  "!TARGET_V32 && operands[1] != frame_pointer_rtx"
   "@
    add%e3.b %2,%0
    add%e3.b %2,%0
   [(set_attr "slottable" "yes,yes,no,no")
    (set_attr "cc" "clobber")])
 
-(define_insn "*extop<mode>si_swap"
+;; A case for v32, to catch the "addo" insn in addition to "adds".  We
+;; only care to match the canonical form; there should be no other.
+
+(define_insn "*addsbw_v32"
+  [(set (match_operand:HI 0 "register_operand" "=r,r,!a")
+       (plus:HI
+        (sign_extend:HI
+         (match_operand:QI 2 "nonimmediate_operand" "r,m,m"))
+        (match_operand:HI 1 "register_operand" "0,0,r")))]
+  "TARGET_V32"
+  "@
+   adds.b %2,%0
+   adds.b %2,%0
+   addo.b %2,%1,%0"
+  [(set_attr "slottable" "yes")
+   (set_attr "cc" "clobber,clobber,none")])
+
+(define_insn "*addubw_v32"
+  [(set (match_operand:HI 0 "register_operand" "=r,r")
+       (plus:HI
+        (zero_extend:HI
+         (match_operand:QI 2 "nonimmediate_operand" "r,m"))
+        (match_operand:HI 1 "register_operand" "0,0")))]
+  "TARGET_V32"
+  "addu.b %2,%0"
+  [(set_attr "slottable" "yes")
+   (set_attr "cc" "clobber")])
+
+(define_insn "*extop<mode>si_swap_non_v32"
   [(set (match_operand:SI 0 "register_operand" "=r,r,r,r")
        (match_operator:SI
         4 "cris_plus_or_bound_operator"
           3 "cris_extend_operator"
           [(match_operand:BW 2 "nonimmediate_operand" "r,Q>,m,!To")])
          (match_operand:SI 1 "register_operand" "0,0,0,r")]))]
-  "(GET_CODE (operands[4]) != UMIN || GET_CODE (operands[3]) == ZERO_EXTEND)
+  "!TARGET_V32
+   && (GET_CODE (operands[4]) != UMIN || GET_CODE (operands[3]) == ZERO_EXTEND)
    && operands[1] != frame_pointer_rtx"
   "@
    %x4%E3<m> %2,%0
    %x4%E3<m> %2,%0
    %x4%E3<m> %2,%1,%0"
   [(set_attr "slottable" "yes,yes,no,no")])
+
+(define_insn "*adds<mode>_v32"
+  [(set (match_operand:SI 0 "register_operand" "=r,r,!a")
+       (plus:SI
+        (sign_extend:SI
+         (match_operand:BW 2 "nonimmediate_operand" "r,m,m"))
+        (match_operand:SI 1 "register_operand" "0,0,r")))]
+  "TARGET_V32"
+  "@
+   adds<m> %2,%0
+   adds<m> %2,%0
+   addo<m> %2,%1,%0"
+  [(set_attr "slottable" "yes")
+   (set_attr "cc" "*,*,none")])
+
+(define_insn "*addu<mode>_v32"
+  [(set (match_operand:SI 0 "register_operand" "=r,r")
+       (plus:SI
+        (zero_extend:SI
+          (match_operand:BW 2 "nonimmediate_operand" "r,m"))
+        (match_operand:SI 1 "register_operand" "0,0")))]
+  "TARGET_V32 && operands[1] != frame_pointer_rtx"
+  "addu<m> %2,%0"
+  [(set_attr "slottable" "yes")])
+
+(define_insn "*bound<mode>_v32"
+  [(set (match_operand:SI 0 "register_operand" "=r")
+       (umin:SI
+        (zero_extend:SI
+         (match_operand:BW 2 "register_operand" "r"))
+        (match_operand:SI 1 "register_operand" "0")))]
+  "TARGET_V32 && operands[1] != frame_pointer_rtx"
+  "bound<m> %2,%0"
+  [(set_attr "slottable" "yes")])
 \f
 ;; This is the special case when we use what corresponds to the
 ;; instruction above in "casesi".  Do *not* change it to use the generic
                  (pc))
         (label_ref (match_operand 2 "" ""))))
    (use (label_ref (match_operand 3 "" "")))]
-
-  "operands[0] != frame_pointer_rtx"
-
+  "!TARGET_V32 && operands[0] != frame_pointer_rtx"
   "adds.w [$pc+%0.w],$pc"
   [(set_attr "cc" "clobber")])
+
+;; For V32, we just have a jump, but we need to mark the table as used,
+;; and the jump insn must have the if_then_else form expected by core
+;; GCC.  Since we don't want to prolong the lifetime of the original
+;; index value, we compare against "unspec 0".  It's a pity we have to
+;; jump through to get the default label in place and to keep the jump
+;; table around.  FIXME: Look into it some time.
+
+(define_insn "*casesi_jump_v32"
+  [(set (pc)
+       (if_then_else
+        (ltu (unspec [(const_int 0)] CRIS_UNSPEC_CASESI)
+             (match_operand:SI 0 "const_int_operand" "n"))
+        (match_operand:SI 1 "register_operand" "r")
+        (label_ref (match_operand 2 "" ""))))
+   (use (label_ref (match_operand 3 "" "")))]
+  "TARGET_V32"
+  "jump %1%#"
+  [(set_attr "cc" "clobber")
+   (set_attr "slottable" "has_slot")])
 \f
 ;; Multiply instructions.
 
 
 ;; The addi insn as it is normally used.
 
+;; Make the the ACR alternative taste bad enough to not choose it as a
+;; preference to avoid spilling problems (unwind-dw2-fde.c at build).
+;; FIXME: Revisit for new register allocator.
+
 (define_insn "*addi"
-  [(set (match_operand:SI 0 "register_operand" "=r")
+  [(set (match_operand:SI 0 "register_operand" "=r,!a")
        (plus:SI
-        (mult:SI (match_operand:SI 2 "register_operand" "r")
-                 (match_operand:SI 3 "const_int_operand" "n"))
-        (match_operand:SI 1 "register_operand" "0")))]
+        (mult:SI (match_operand:SI 2 "register_operand" "r,r")
+                 (match_operand:SI 3 "const_int_operand" "n,n"))
+        (match_operand:SI 1 "register_operand" "0,r")))]
   "operands[0] != frame_pointer_rtx
    && operands[1] != frame_pointer_rtx
    && CONST_INT_P (operands[3])
    && (INTVAL (operands[3]) == 1
        || INTVAL (operands[3]) == 2 || INTVAL (operands[3]) == 4)"
-  "addi %2%T3,%0"
+  "@
+   addi %2%T3,%0
+   addi %2%T3,%1,%0"
   [(set_attr "slottable" "yes")
    (set_attr "cc" "none")])
 
                  (match_operand:SI 2 "register_operand" "r"))
         (ashift:SI (match_operand:SI 3 "register_operand" "0")
                    (const_int 1))))]
-  ""
+  "!TARGET_V32"
   "mstep %2,%0"
   [(set_attr "slottable" "yes")])
 
                  (match_operand:SI 2 "register_operand" "r"))
         (mult:SI (match_operand:SI 3 "register_operand" "0")
                  (const_int 2))))]
-  "operands[0] != frame_pointer_rtx
+  "!TARGET_V32
+   && operands[0] != frame_pointer_rtx
    && operands[1] != frame_pointer_rtx
    && operands[2] != frame_pointer_rtx
    && operands[3] != frame_pointer_rtx"
 ;; a / 1000;}" and unsigned.  FIXME: Comment above was for 3.2, revisit.
 
 (define_insn "<su>mulsi3_highpart"
-  [(set (match_operand:SI 0 "nonimmediate_operand" "=h,h,?r,?r")
+  [(set (match_operand:SI 0 "register_operand" "=h,h,?r,?r")
        (truncate:SI
         (lshiftrt:DI
          (mult:DI
                        (const_int 1))))]
   ""
   "dstep %2,%0"
-  [(set_attr "slottable" "yes")])
+  [(set_attr "slottable" "yes")
+   (set_attr "cc" "noov32")])
 
 ;; Here's a variant with mult instead of ashift.
 ;;
    && operands[2] != frame_pointer_rtx
    && operands[3] != frame_pointer_rtx"
   "dstep %2,%0"
-  [(set_attr "slottable" "yes")])
+  [(set_attr "slottable" "yes")
+   (set_attr "cc" "noov32")])
 \f
 ;; Logical operators.
 
 ;; pressure (worse code).  That will hopefully change with an
 ;; improved reload pass.
 
-(define_insn "*expanded_andsi"
+(define_insn "*expanded_andsi_non_v32"
   [(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")))]
-  ""
+  "!TARGET_V32"
   "@
    andq %2,%0
    and.d %2,%0
    and.d %2,%0
    and.d %2,%1,%0"
   [(set_attr "slottable" "yes,yes,yes,no,no")])
+
+(define_insn "*expanded_andsi_v32"
+  [(set (match_operand:SI 0 "register_operand" "=r,r,r,r")
+       (and:SI (match_operand:SI 1 "register_operand" "%0,0,0,0")
+               (match_operand:SI 2 "general_operand" "I,r,Q>,g")))]
+  "TARGET_V32"
+  "@
+   andq %2,%0
+   and.d %2,%0
+   and.d %2,%0
+   and.d %2,%0"
+  [(set_attr "slottable" "yes,yes,yes,no")
+   (set_attr "cc" "noov32")])
 \f
 ;; For both QI and HI we may use the quick patterns.  This results in
 ;; useless condition codes, but that is used rarely enough for it to
 
 ;; Catch-all andhi3 pattern.
 
-(define_insn "*expanded_andhi"
+(define_insn "*expanded_andhi_non_v32"
   [(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")))]
 ;; pressure (worse code).  That will hopefully change with an
 ;; improved reload pass.
 
-  ""
+  "!TARGET_V32"
   "@
    andq %2,%0
    and.w %2,%0
   [(set_attr "slottable" "yes,yes,yes,no,yes,no,no")
    (set_attr "cc" "clobber,normal,normal,normal,clobber,normal,normal")])
 
+(define_insn "*expanded_andhi_v32"
+  [(set (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,0")
+               (match_operand:HI 2 "general_operand" "I,r,Q>,L,O,g")))]
+  "TARGET_V32"
+  "@
+   andq %2,%0
+   and.w %2,%0
+   and.w %2,%0
+   and.w %2,%0
+   anDq %b2,%0
+   and.w %2,%0"
+  [(set_attr "slottable" "yes,yes,yes,no,yes,no")
+   (set_attr "cc" "clobber,noov32,noov32,noov32,clobber,noov32")])
+
 ;; A strict_low_part pattern.
 
-(define_insn "*andhi_lowpart"
+(define_insn "*andhi_lowpart_non_v32"
   [(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")))]
-  ""
+  "!TARGET_V32"
   "@
    and.w %2,%0
    and.w %2,%0
    and.w %2,%1,%0"
   [(set_attr "slottable" "yes,yes,no,yes,no,no")
    (set_attr "cc" "normal,normal,normal,clobber,normal,normal")])
+
+(define_insn "*andhi_lowpart_v32"
+  [(set (strict_low_part
+        (match_operand:HI 0 "register_operand" "=r,r,r,r,r"))
+       (and:HI (match_operand:HI 1 "register_operand" "%0,0,0,0,0")
+               (match_operand:HI 2 "general_operand" "r,Q>,L,O,g")))]
+  "TARGET_V32"
+  "@
+   and.w %2,%0
+   and.w %2,%0
+   and.w %2,%0
+   anDq %b2,%0
+   and.w %2,%0"
+  [(set_attr "slottable" "yes,yes,no,yes,no")
+   (set_attr "cc" "noov32,noov32,noov32,clobber,noov32")])
 \f
-(define_insn "andqi3"
+(define_expand "andqi3"
+  [(set (match_operand:QI 0 "register_operand")
+       (and:QI (match_operand:QI 1 "register_operand")
+               (match_operand:QI 2 "general_operand")))]
+  ""
+  "")
+
+(define_insn "*andqi3_non_v32"
   [(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")))]
-  ""
+  "!TARGET_V32"
   "@
    andq %2,%0
    and.b %2,%0
   [(set_attr "slottable" "yes,yes,yes,yes,no,no")
    (set_attr "cc" "clobber,normal,normal,clobber,normal,normal")])
 
-(define_insn "*andqi_lowpart"
+(define_insn "*andqi3_v32"
+  [(set (match_operand:QI 0 "register_operand" "=r,r,r,r,r")
+       (and:QI (match_operand:QI 1 "register_operand" "%0,0,0,0,0")
+               (match_operand:QI 2 "general_operand" "I,r,Q>,O,g")))]
+  "TARGET_V32"
+  "@
+   andq %2,%0
+   and.b %2,%0
+   and.b %2,%0
+   andQ %b2,%0
+   and.b %2,%0"
+  [(set_attr "slottable" "yes,yes,yes,yes,no")
+   (set_attr "cc" "clobber,noov32,noov32,clobber,noov32")])
+
+(define_insn "*andqi_lowpart_non_v32"
   [(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")))]
-  ""
+  "!TARGET_V32"
   "@
    and.b %2,%0
    and.b %2,%0
    and.b %2,%1,%0"
   [(set_attr "slottable" "yes,yes,yes,no,no")
    (set_attr "cc" "normal,normal,clobber,normal,normal")])
+
+(define_insn "*andqi_lowpart_v32"
+  [(set (strict_low_part
+        (match_operand:QI 0 "register_operand" "=r,r,r,r"))
+       (and:QI (match_operand:QI 1 "register_operand" "%0,0,0,0")
+               (match_operand:QI 2 "general_operand" "r,Q>,O,g")))]
+  "TARGET_V32"
+  "@
+   and.b %2,%0
+   and.b %2,%0
+   andQ %b2,%0
+   and.b %2,%0"
+  [(set_attr "slottable" "yes,yes,yes,no")
+   (set_attr "cc" "noov32,noov32,clobber,noov32")])
 \f
 ;; Bitwise or.
 
 ;; It seems there's no need to jump through hoops to get good code such as
 ;; with andsi3.
 
-(define_insn "iorsi3"
+(define_expand "ior<mode>3"
+  [(set (match_operand:BWD 0 "register_operand")
+       (ior:BWD (match_operand:BWD 1 "register_operand")
+                (match_operand:BWD 2 "general_operand")))]
+  ""
+  "")
+
+(define_insn "*iorsi3_non_v32"
   [(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")))]
-  ""
+  "!TARGET_V32"
   "@
    orq %2,%0
    or.d %2,%0
   [(set_attr "slottable" "yes,yes,yes,no,no,no")
    (set_attr "cc" "normal,normal,normal,clobber,normal,normal")])
 
-(define_insn "iorhi3"
+(define_insn "*iorsi3_v32"
+  [(set (match_operand:SI 0 "register_operand" "=r,r,r,r,r")
+       (ior:SI (match_operand:SI 1 "register_operand" "%0,0,0,0,0")
+               (match_operand:SI 2 "general_operand" "I,r,Q>,n,g")))]
+  "TARGET_V32"
+  "@
+   orq %2,%0
+   or.d %2,%0
+   or.d %2,%0
+   oR.%s2 %2,%0
+   or.d %2,%0"
+  [(set_attr "slottable" "yes,yes,yes,no,no")
+   (set_attr "cc" "noov32,noov32,noov32,clobber,noov32")])
+
+(define_insn "*iorhi3_non_v32"
   [(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")))]
-  ""
+  "!TARGET_V32"
   "@
    orq %2,%0
    or.w %2,%0
   [(set_attr "slottable" "yes,yes,yes,no,yes,no,no")
    (set_attr "cc" "clobber,normal,normal,normal,clobber,normal,normal")])
 
-(define_insn "iorqi3"
+(define_insn "*iorhi3_v32"
+  [(set (match_operand:HI 0 "register_operand" "=r,r,r,r,r,r")
+       (ior:HI (match_operand:HI 1 "register_operand" "%0,0,0,0,0,0")
+               (match_operand:HI 2 "general_operand" "I,r,Q>,L,O,g")))]
+  "TARGET_V32"
+  "@
+   orq %2,%0
+   or.w %2,%0
+   or.w %2,%0
+   or.w %2,%0
+   oRq %b2,%0
+   or.w %2,%0"
+  [(set_attr "slottable" "yes,yes,yes,no,yes,no")
+   (set_attr "cc" "clobber,noov32,noov32,noov32,clobber,noov32")])
+
+(define_insn "*iorqi3_non_v32"
   [(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")))]
-  ""
+  "!TARGET_V32"
   "@
    orq %2,%0
    or.b %2,%0
    or.b %2,%1,%0"
   [(set_attr "slottable" "yes,yes,yes,yes,no,no")
    (set_attr "cc" "clobber,normal,normal,clobber,normal,normal")])
+
+(define_insn "*iorqi3_v32"
+  [(set (match_operand:QI 0 "register_operand" "=r,r,r,r,r")
+       (ior:QI (match_operand:QI 1 "register_operand" "%0,0,0,0,0")
+               (match_operand:QI 2 "general_operand" "I,r,Q>,O,g")))]
+  "TARGET_V32"
+  "@
+   orq %2,%0
+   or.b %2,%0
+   or.b %2,%0
+   orQ %b2,%0
+   or.b %2,%0"
+  [(set_attr "slottable" "yes,yes,yes,yes,no")
+   (set_attr "cc" "clobber,noov32,noov32,clobber,noov32")])
 \f
 ;; Exclusive-or
 
                (match_operand:SI 2 "register_operand" "r")))]
   ""
   "xor %2,%0"
-  [(set_attr "slottable" "yes")])
+  [(set_attr "slottable" "yes")
+   (set_attr "cc" "noov32")])
 
 (define_insn "xor<mode>3"
   [(set (match_operand:BW 0 "register_operand" "=r")
        (not:SI (match_operand:SI 1 "register_operand" "0")))]
   ""
   "not %0"
-  [(set_attr "slottable" "yes")])
+  [(set_attr "slottable" "yes")
+   (set_attr "cc" "noov32")])
 
 (define_insn "one_cmpl<mode>2"
   [(set (match_operand:BW 0 "register_operand" "=r")
 
   return "<slr>q %2,%0";
 }
-  [(set_attr "slottable" "yes")])
+  [(set_attr "slottable" "yes")
+   (set_attr "cc" "noov32")])
 
 ;; Since gcc gets lost, and forgets to zero-extend the source (or mask
 ;; the destination) when it changes shifts of lower modes into SImode,
                    (match_operand:BW 2 "register_operand" "r")))]
   ""
   "<slr><m> %2,%0"
-  [(set_attr "slottable" "yes")])
+  [(set_attr "slottable" "yes")
+   (set_attr "cc" "noov32")])
 
 (define_insn "*<shlr><mode>_lowpart"
   [(set (strict_low_part (match_operand:BW 0 "register_operand" "+r"))
                    (match_operand:BW 1 "register_operand" "r")))]
   ""
   "<slr><m> %1,%0"
-  [(set_attr "slottable" "yes")])
+  [(set_attr "slottable" "yes")
+   (set_attr "cc" "noov32")])
 \f
 ;; Arithmetic/logical shift left.
 
        ? "lslq %2,%0" : "lsl<m> %2,%0");
 }
   [(set_attr "slottable" "yes")
-   (set_attr "cc" "normal,clobber")])
+   (set_attr "cc" "noov32,clobber")])
 
 ;; A strict_low_part matcher.
 
                   (match_operand:HI 1 "register_operand" "r")))]
   ""
   "lsl<m> %1,%0"
-  [(set_attr "slottable" "yes")])
+  [(set_attr "slottable" "yes")
+   (set_attr "cc" "noov32")])
 \f
 ;; Various strange insns that gcc likes.
 
        (abs:SI (match_operand:SI 1 "register_operand" "r")))]
   ""
   "abs %1,%0"
-  [(set_attr "slottable" "yes")])
+  [(set_attr "slottable" "yes")
+   (set_attr "cc" "noov32")])
 
 ;; FIXME: GCC should be able to do these expansions itself.
 
        (clz:SI (match_operand:SI 1 "register_operand" "r")))]
   "TARGET_HAS_LZ"
   "lz %1,%0"
-  [(set_attr "slottable" "yes")])
+  [(set_attr "slottable" "yes")
+   (set_attr "cc" "noov32")])
 
 (define_insn "bswapsi2"
   [(set (match_operand:SI 0 "register_operand" "=r")
         (bswap:SI (match_operand:SI 1 "register_operand" "0")))]
   "TARGET_HAS_SWAP"
   "swapwb %0"
-  [(set_attr "slottable" "yes")])
+  [(set_attr "slottable" "yes")
+   (set_attr "cc" "noov32")])
 
 ;; This instruction swaps all bits in a register.
 ;; That means that the most significant bit is put in the place
                   CRIS_UNSPEC_SWAP_BITS))]
   "TARGET_HAS_SWAP"
   "swapwbr %0"
-  [(set_attr "slottable" "yes")])
+  [(set_attr "slottable" "yes")
+   (set_attr "cc" "noov32")])
 
 ;; Implement ctz using two instructions, one for bit swap and one for clz.
 ;; Defines a scratch register to avoid clobbering input.
 ;; operation supported by gcc.  Used in casesi, but used now and then in
 ;; normal code too.
 
-(define_insn "uminsi3"
+(define_expand "uminsi3"
+  [(set (match_operand:SI 0 "register_operand" "")
+       (umin:SI  (match_operand:SI 1 "register_operand" "")
+                 (match_operand:SI 2 "general_operand" "")))]
+  ""
+{
+  if (MEM_P (operands[2]) && TARGET_V32)
+    operands[2] = force_reg (SImode, operands[2]);
+})
+
+(define_insn "*uminsi3_non_v32"
   [(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,!To")))]
-  ""
+  "!TARGET_V32"
 {
   if (CONST_INT_P (operands[2]))
     {
   return "bound.d %2,%0";
 }
  [(set_attr "slottable" "yes,yes,no,no")])
+
+(define_insn "*uminsi3_v32"
+  [(set (match_operand:SI 0 "register_operand" "=r,r")
+       (umin:SI  (match_operand:SI 1 "register_operand" "%0,0")
+                 (match_operand:SI 2 "nonmemory_operand" "r,i")))]
+  "TARGET_V32"
+{
+  if (GET_CODE (operands[2]) == CONST_INT)
+    {
+      /* Constant operands are zero-extended, so only 32-bit operands
+        may be negative.  */
+      if (INTVAL (operands[2]) >= 0)
+       {
+         if (INTVAL (operands[2]) < 256)
+           return "bound.b %2,%0";
+
+         if (INTVAL (operands[2]) < 65536)
+           return "bound.w %2,%0";
+       }
+    }
+
+  return "bound.d %2,%0";
+}
+ [(set_attr "slottable" "yes,no")])
 \f
 ;; Jump and branch insns.
 
 ;; jmp_uses_reg_or_mem used by computed_jump_p.  Perhaps it is a kludge to
 ;; change from general_operand to nonimmediate_operand (at least the docs
 ;; should be changed), but then again the pattern is called indirect_jump.
-(define_insn "indirect_jump"
-  [(set (pc) (match_operand:SI 0 "nonimmediate_operand" "rm"))]
+(define_expand "indirect_jump"
+  [(set (pc) (match_operand:SI 0 "nonimmediate_operand"))]
   ""
+{
+  if (TARGET_V32 && MEM_P (operands[0]))
+    operands[0] = force_reg (SImode, operands[0]);
+})
+
+(define_insn "*indirect_jump_non_v32"
+  [(set (pc) (match_operand:SI 0 "nonimmediate_operand" "rm"))]
+  "!TARGET_V32"
   "jump %0")
 
+(define_insn "*indirect_jump_v32"
+  [(set (pc) (match_operand:SI 0 "register_operand" "r"))]
+  "TARGET_V32"
+  "jump %0%#"
+  [(set_attr "slottable" "has_slot")])
+
 ;; Return insn.  Used whenever the epilogue is very simple; if it is only
 ;; a single ret or jump [sp+].  No allocated stack space or saved
 ;; registers are allowed.
              "(cris_return_address_on_stack_for_return ())")
             (const_int 0))
         (const_string "no")
-        (const_string "has_slot")))])
+        (const_string "has_return_slot")))])
 
 (define_expand "prologue"
   [(const_int 0)]
 ;; Accept *anything* as operand 1.  Accept operands for operand 0 in
 ;; order of preference.
 
-(define_insn "*expanded_call"
-  [(call (mem:QI (match_operand:SI
-                 0 "cris_general_operand_or_plt_symbol" "r,Q>,g"))
+(define_insn "*expanded_call_non_v32"
+  [(call (mem:QI (match_operand:SI 0 "general_operand" "r,Q>,g"))
         (match_operand 1 "" ""))
    (clobber (reg:SI CRIS_SRP_REGNUM))]
-  ""
+  "!TARGET_V32"
   "jsr %0")
 
+(define_insn "*expanded_call_v32"
+  [(call
+    (mem:QI
+     (match_operand:SI 0 "cris_nonmemory_operand_or_callable_symbol" "n,r,U,i"))
+    (match_operand 1 "" ""))
+   (clobber (reg:SI CRIS_SRP_REGNUM))]
+  "TARGET_V32"
+  "@
+   jsr %0%#
+   jsr %0%#
+   bsr %0%#
+   bsr %0%#"
+  [(set_attr "slottable" "has_call_slot")])
+
 ;; Parallel when calculating and reusing address of indirect pointer
 ;; with simple offset.  (Makes most sense with PIC.)  It looks a bit
 ;; wrong not to have the clobber last, but that's the way combine
    (set (match_operand:SI 3 "register_operand" "=*0,r,r")
        (plus:SI (match_dup 0)
                 (match_dup 1)))]
-  "! TARGET_AVOID_GOTPLT"
+  "!TARGET_AVOID_GOTPLT && !TARGET_V32"
   "jsr [%3=%0%S1]")
 
 (define_expand "call_value"
 ;;  We also accept a PLT symbol.  We output it as [rPIC+sym:GOTPLT] rather
 ;; than requiring getting rPIC + sym:PLT into a register.
 
-(define_insn "*expanded_call_value"
+(define_insn "*expanded_call_value_non_v32"
   [(set (match_operand 0 "nonimmediate_operand" "=g,g,g")
-       (call (mem:QI (match_operand:SI
-                      1 "cris_general_operand_or_plt_symbol" "r,Q>,g"))
+       (call (mem:QI (match_operand:SI 1 "general_operand" "r,Q>,g"))
              (match_operand 2 "" "")))
    (clobber (reg:SI CRIS_SRP_REGNUM))]
-  ""
+  "!TARGET_V32"
   "Jsr %1"
   [(set_attr "cc" "clobber")])
 
    (set (match_operand:SI 4 "register_operand" "=*1,r,r")
        (plus:SI (match_dup 1)
                 (match_dup 2)))]
-  "! TARGET_AVOID_GOTPLT"
+  "!TARGET_AVOID_GOTPLT && !TARGET_V32"
   "Jsr [%4=%1%S2]"
   [(set_attr "cc" "clobber")])
 
+(define_insn "*expanded_call_value_v32"
+  [(set
+    (match_operand 0 "nonimmediate_operand" "=g,g,g,g")
+    (call
+     (mem:QI
+      (match_operand:SI 1 "cris_nonmemory_operand_or_callable_symbol" "n,r,U,i"))
+     (match_operand 2 "" "")))
+   (clobber (reg:SI 16))]
+  "TARGET_V32"
+  "@
+   Jsr %1%#
+   Jsr %1%#
+   Bsr %1%#
+   Bsr %1%#"
+  [(set_attr "cc" "clobber")
+   (set_attr "slottable" "has_call_slot")])
+
 ;; Used in debugging.  No use for the direct pattern; unfilled
 ;; delayed-branches are taken care of by other means.
 
 ;; this expansion, you must change the macro ASM_OUTPUT_CASE_END
 ;; accordingly, to add the default case at the end of the jump-table.
 
-(define_expand "casesi"
+(define_expand "cris_casesi_non_v32"
   [(set (match_dup 5) (match_operand:SI 0 "general_operand" ""))
    (set (match_dup 6)
        (minus:SI (match_dup 5)
   operands[6] = gen_reg_rtx (SImode);
   operands[7] = gen_reg_rtx (SImode);
 })
+
+;; FIXME: Check effect of not JUMP_TABLES_IN_TEXT_SECTION.
+(define_expand "cris_casesi_v32"
+  [(set (match_dup 5) (match_operand:SI 0 "general_operand"))
+   (set (match_dup 6)
+       (minus:SI (match_dup 5)
+                (match_operand:SI 1 "const_int_operand")))
+   (set (match_dup 7)
+       (umin:SI (match_dup 6)
+               (match_operand:SI 2 "const_int_operand")))
+   (set (match_dup 8) (match_dup 11))
+   (set (match_dup 9)
+       (plus:SI (mult:SI (match_dup 7) (const_int 2))
+               (match_dup 8)))
+   (set (match_dup 10)
+       (plus:SI (sign_extend:SI (mem:HI (match_dup 9)))
+               (match_dup 9)))
+   (parallel
+    [(set (pc)
+        (if_then_else
+         (ltu (unspec [(const_int 0)] CRIS_UNSPEC_CASESI) (match_dup 2))
+         (match_dup 10)
+         (label_ref (match_operand 4 "" ""))))
+     (use (label_ref (match_dup 3)))])]
+  "TARGET_V32"
+{
+  int i;
+  rtx xlabel = gen_rtx_LABEL_REF (VOIDmode, operands[3]);
+  for (i = 5; i <= 10; i++)
+    operands[i] = gen_reg_rtx (SImode);
+  operands[2] = plus_constant (operands[2], 1);
+
+  /* Don't forget to decorate labels too, for PIC.  */
+  operands[11] = flag_pic
+    ? gen_rtx_CONST (Pmode,
+                   gen_rtx_UNSPEC (Pmode, gen_rtvec (1, xlabel),
+                                   CRIS_UNSPEC_PCREL))
+    : xlabel;
+})
+
+(define_expand "casesi"
+  [(match_operand:SI 0 "general_operand")
+   (match_operand:SI 1 "const_int_operand")
+   (match_operand:SI 2 "const_int_operand")
+   (match_operand 3 "" "")
+   (match_operand 4 "" "")]
+  ""
+{
+  if (TARGET_V32)
+    emit_insn (gen_cris_casesi_v32 (operands[0], operands[1], operands[2],
+                                   operands[3], operands[4]));
+  else
+    emit_insn (gen_cris_casesi_non_v32 (operands[0], operands[1], operands[2],
+                                       operands[3], operands[4]));
+  DONE;
+})
 \f
 ;; Split-patterns.  Some of them have modes unspecified.  This
 ;; should always be ok; if for no other reason sparc.md has it as
 ;;  move ry,rz
 ;;  op [rx],rz
 ;; Lose if rz=ry or rx=rz.
-;; Call this op-extend-split
+;; Call this op-extend-split.
+;; Do not match for V32; the addo and addi shouldn't be split
+;; up.
 
 (define_split
   [(set (match_operand 0 "register_operand" "")
          (match_operator
           3 "cris_extend_operator"
           [(match_operand 2 "memory_operand" "")])]))]
-  "REG_P (operands[0])
+  "!TARGET_V32
+   && REG_P (operands[0])
    && REG_P (operands[1])
    && REGNO (operands[1]) != REGNO (operands[0])
    && GET_MODE_SIZE (GET_MODE (operands[0])) <= UNITS_PER_WORD
          (match_operator
           3 "cris_extend_operator"
           [(match_operand 2 "memory_operand" "")])]))]
-  "REG_P (operands[0])
+  "!TARGET_V32
+   && REG_P (operands[0])
    && REG_P (operands[1])
    && REGNO (operands[1]) != REGNO (operands[0])
    && GET_MODE_SIZE (GET_MODE (operands[0])) <= UNITS_PER_WORD
           3 "cris_extend_operator"
           [(match_operand 2 "memory_operand" "")])
          (match_operand 1 "register_operand" "")]))]
-  "REG_P (operands[0])
+  "!TARGET_V32
+   && REG_P (operands[0])
    && REG_P (operands[1])
    && REGNO (operands[1]) != REGNO (operands[0])
    && GET_MODE_SIZE (GET_MODE (operands[0])) <= UNITS_PER_WORD
           3 "cris_extend_operator"
           [(match_operand 2 "memory_operand" "")])
          (match_operand 1 "register_operand" "")]))]
-  "REG_P (operands[0])
+  "!TARGET_V32
+   && REG_P (operands[0])
    && REG_P (operands[1])
    && REGNO (operands[1]) != REGNO (operands[0])
    && GET_MODE_SIZE (GET_MODE (operands[0])) <= UNITS_PER_WORD
         3 "cris_orthogonal_operator"
         [(match_operand 1 "register_operand" "")
          (match_operand 2 "memory_operand" "")]))]
-  "REG_P (operands[0])
+  "!TARGET_V32
+   && REG_P (operands[0])
    && REG_P (operands[1])
    && REGNO (operands[1]) != REGNO (operands[0])
    && GET_MODE_SIZE (GET_MODE (operands[0])) <= UNITS_PER_WORD
         3 "cris_commutative_orth_op"
         [(match_operand 2 "memory_operand" "")
          (match_operand 1 "register_operand" "")]))]
-  "REG_P (operands[0])
+  "!TARGET_V32
+   && REG_P (operands[0])
    && REG_P (operands[1])
    && REGNO (operands[1]) != REGNO (operands[0])
    && GET_MODE_SIZE (GET_MODE (operands[0])) <= UNITS_PER_WORD
         3 "cris_commutative_orth_op"
         [(match_operand 1 "register_operand" "")
          (match_operand 2 "memory_operand" "")]))]
-  "REG_P (operands[0]) && REG_P (operands[1])
+  "!TARGET_V32
+   && REG_P (operands[0]) && REG_P (operands[1])
    && REGNO (operands[1]) != REGNO (operands[0])
    && GET_MODE_SIZE (GET_MODE (operands[0])) <= UNITS_PER_WORD
    && REG_P (XEXP (operands[2], 0))
         3 "cris_orthogonal_operator"
         [(match_operand 2 "memory_operand" "")
          (match_operand 1 "register_operand" "")]))]
-  "REG_P (operands[0]) && REG_P (operands[1])
+  "!TARGET_V32
+   && REG_P (operands[0]) && REG_P (operands[1])
    && REGNO (operands[1]) != REGNO (operands[0])
    && GET_MODE_SIZE (GET_MODE (operands[0])) <= UNITS_PER_WORD
    && REG_P (XEXP (operands[2], 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)"
+   && (INTVAL (operands[2]) >= -128 && INTVAL (operands[2]) < 128)
+   && TARGET_SIDE_EFFECT_PREFIXES"
   [(parallel
     [(set (match_dup 3) (match_dup 5))
      (set (match_dup 0) (plus:SI (match_dup 1) (match_dup 2)))])]
    && (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)"
+   && (INTVAL (operands[2]) >= -128 && INTVAL (operands[2]) < 128)
+   && TARGET_SIDE_EFFECT_PREFIXES"
   [(parallel
     [(set (match_dup 5) (match_dup 4))
      (set (match_dup 0) (plus:SI (match_dup 1) (match_dup 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]) <= 127"
+   && INTVAL (operands[2]) <= 127
+   && TARGET_SIDE_EFFECT_PREFIXES"
   [(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)))])]
        (unspec:SI [(match_operand:SI 2 "cris_general_operand_or_symbol" "")]
                   CRIS_UNSPEC_PLTGOTREAD)))]))]
   "flag_pic
-   && cris_valid_pic_const (XEXP (XEXP (operands[1], 0), 1))
+   && cris_valid_pic_const (XEXP (XEXP (operands[1], 0), 1), true)
    && REGNO_REG_CLASS (REGNO (operands[0])) == REGNO_REG_CLASS (0)"
-  [(set (match_dup 0) (const:SI (unspec:SI [(match_dup 2)] CRIS_UNSPEC_PLT)))
+  [(set (match_dup 0) (const:SI (unspec:SI [(match_dup 2)] CRIS_UNSPEC_PLT_GOTREL)))
    (set (match_dup 0) (plus:SI (match_dup 0) (reg:SI CRIS_GOT_REGNUM)))]
   "")
 
                    (match_operand 4 "" ""))
              (clobber (reg:SI CRIS_SRP_REGNUM))])]
   "flag_pic
-   && cris_valid_pic_const (XEXP (XEXP (operands[1], 0), 1))
+   && cris_valid_pic_const (XEXP (XEXP (operands[1], 0), 1), true)
    && peep2_reg_dead_p (2, operands[0])"
   [(parallel [(call (mem:QI (match_dup 1))
                    (match_dup 4))
                         (match_operand 4 "" "")))
              (clobber (reg:SI CRIS_SRP_REGNUM))])]
   "flag_pic
-   && cris_valid_pic_const (XEXP (XEXP (operands[1], 0), 1))
+   && cris_valid_pic_const (XEXP (XEXP (operands[1], 0), 1), true)
    && peep2_reg_dead_p (2, operands[0])"
   [(parallel [(set (match_dup 5)
                   (call (mem:QI (match_dup 1))
                   (const:SI
                    (unspec:SI [(match_dup 2)] CRIS_UNSPEC_PLTGOTREAD))))])]
   "flag_pic
-   && cris_valid_pic_const (XEXP (XEXP (operands[1], 0), 1))
+   && cris_valid_pic_const (XEXP (XEXP (operands[1], 0), 1), true)
    && REGNO_REG_CLASS (REGNO (operands[0])) == REGNO_REG_CLASS (0)"
   [(set (match_dup 3)
        (const:SI (unspec:SI [(match_dup 2)] CRIS_UNSPEC_PLTGOTREAD)))
    (set (match_dup 3) (plus:SI (match_dup 3) (reg:SI CRIS_GOT_REGNUM)))
-   (set (match_dup 0) (const:SI (unspec:SI [(match_dup 2)] CRIS_UNSPEC_PLT)))
+   (set (match_dup 0)
+       (const:SI (unspec:SI [(match_dup 2)] CRIS_UNSPEC_PLT_GOTREL)))
    (set (match_dup 0) (plus:SI (match_dup 0) (reg:SI CRIS_GOT_REGNUM)))]
   "")
 \f