]> git.ipfire.org Git - thirdparty/gcc.git/blobdiff - gcc/config/cris/cris.md
Update copyright years.
[thirdparty/gcc.git] / gcc / config / cris / cris.md
index 9fcc4b01e4b6f8ab6dedb5a20eff240d959dcb57..c15395bd84c495290b43ccb96c9f53664abd03c5 100644 (file)
@@ -1,13 +1,12 @@
 ;; GCC machine description for CRIS cpu cores.
-;; Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
-;; Free Software Foundation, Inc.
+;; Copyright (C) 1998-2024 Free Software Foundation, Inc.
 ;; Contributed by Axis Communications.
 
 ;; This file is part of GCC.
 ;;
 ;; GCC is free software; you can redistribute it and/or modify
 ;; it under the terms of the GNU General Public License as published by
-;; the Free Software Foundation; either version 2, or (at your option)
+;; the Free Software Foundation; either version 3, or (at your option)
 ;; any later version.
 ;;
 ;; GCC is distributed in the hope that it will be useful,
 ;; GNU General Public License for more details.
 ;;
 ;; You should have received a copy of the GNU General Public License
-;; along with GCC; see the file COPYING.  If not, write to
-;; the Free Software Foundation, 51 Franklin Street, Fifth Floor,
-;; Boston, MA 02110-1301, USA.
+;; along with GCC; see the file COPYING3.  If not see
+;; <http://www.gnu.org/licenses/>.
 
 ;; The original PO technology requires these to be ordered by speed,
 ;; so that assigner will pick the fastest.
 
 ;; See files "md.texi" and "rtl.def" for documentation on define_insn,
 ;; match_*, et. al.
-;;
-;; The function cris_notice_update_cc in cris.c handles condition code
-;; updates for most instructions, helped by the "cc" attribute.
 
 ;; There are several instructions that are orthogonal in size, and seems
 ;; they could be matched by a single pattern without a specified size
 ;; ??? But it should be re-checked for gcc > 2.7.2
 ;; FIXME: This changed some time ago (from 2000-03-16) for gcc-2.9x.
 
-;; FIXME: When PIC, all [rX=rY+S] could be enabled to match
-;; [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)
-   (CRIS_UNSPEC_GOT 2)
-   (CRIS_UNSPEC_GOTREL 3)
-   (CRIS_UNSPEC_GOTREAD 4)
-   (CRIS_UNSPEC_PLTGOTREAD 5)])
+(define_c_enum ""
+  [
+   ;; Stack frame deallocation barrier.
+   CRIS_UNSPEC_FRAME_DEALLOC
+  ])
 
 ;; Register numbers.
 (define_constants
-  [(CRIS_GOT_REGNUM 0)
-   (CRIS_STATIC_CHAIN_REGNUM 7)
-   (CRIS_FP_REGNUM 8)
+  [(CRIS_STATIC_CHAIN_REGNUM 7)
+   (CRIS_REAL_FP_REGNUM 8)
    (CRIS_SP_REGNUM 14)
    (CRIS_SRP_REGNUM 16)
    (CRIS_MOF_REGNUM 17)
    (CRIS_AP_REGNUM 18)
-   (CRIS_CC0_REGNUM 19)]
+   (CRIS_CC0_REGNUM 19)
+   (CRIS_FP_REGNUM 20)]
 )
 
 ;; We need an attribute to define whether an instruction can be put in
 ;; 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", and "has_return_slot".
+;; Yes/no tells whether the insn is slottable or not.
+;; 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"
+  (const_string "no"))
 
 ;; We also need attributes to sanely determine the condition code
-;; state.  See cris_notice_update_cc for how this is used.
-
+;; state.  This attribute isn't used as-is, just as a template,
+;; effectively a dummy except in a substitution setting CRIS_CC0_REGNUM
+;; to a specific value.
 (define_attr "cc" "none,clobber,normal" (const_string "normal"))
 
+;; The attribute "_enabled" is appended to "cc", forming "cc_enabled" to
+;; pick out certain alternatives when generating a useful
+;; condition-code-setting.  See the "enabled" attribute.
+(define_attr "cc_enabled" "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
+;; 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)])
+
+;; 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")
+       (not (match_test "dead_or_set_regno_p (insn, CRIS_SRP_REGNUM)")))
+   (nil) (nil)])
+
+;; Enable choosing particular instructions.  The discriminator choice
+;; "v0" stands for "pre-v10", for brevity.
+(define_attr "cpu_variant" "default,v0,v10" (const_string "default"))
+
+(define_attr "enabled" "no,yes"
+  (if_then_else
+   (and
+    (eq_attr "cc_enabled" "normal")
+    (ior
+     (eq_attr "cpu_variant" "default")
+     (and (eq_attr "cpu_variant" "v10")
+         (match_test "TARGET_HAS_MUL_INSNS"))
+     (and (eq_attr "cpu_variant" "v0")
+         (not (match_test "TARGET_HAS_MUL_INSNS")))))
+   (const_string "yes")
+   (const_string "no")))
 \f
 ;; Iterator definitions.
 
 ;; For the "usual" pattern size alternatives.
-(define_mode_macro BWD [SI HI QI])
-(define_mode_macro WD [SI HI])
-(define_mode_macro BW [HI QI])
+(define_mode_iterator BWD [SI HI QI])
+(define_mode_iterator BWDD [DI SI HI QI])
+
+;; To be able to refer to the same mode_attr for both a multi-mode
+;; and a mode-specific pattern, we use some singleton iterators.
+(define_mode_iterator DI_ [DI])
+(define_mode_iterator SI_ [SI])
+
+(define_mode_iterator WD [SI HI])
+(define_mode_iterator BW [HI QI])
+
+; Another "BW" for use where an independent iteration is needed.
+(define_mode_iterator BW2 [HI QI])
+
 (define_mode_attr S [(SI "HI") (HI "QI")])
 (define_mode_attr s [(SI "hi") (HI "qi")])
 (define_mode_attr m [(SI ".d") (HI ".w") (QI ".b")])
 (define_mode_attr nbitsm1 [(SI "31") (HI "15") (QI "7")])
 
 ;; For the sign_extend+zero_extend variants.
-(define_code_macro szext [sign_extend zero_extend])
+(define_code_iterator szext [sign_extend zero_extend])
 (define_code_attr u [(sign_extend "") (zero_extend "u")])
 (define_code_attr su [(sign_extend "s") (zero_extend "u")])
 
+;; For extended-operand variants.
+(define_code_iterator plusminus [plus minus])
+(define_code_attr addsub [(plus "add") (minus "sub")])
+
+;; Similar, other cases also matching bound/umin.
+(define_code_iterator plusminusumin [plus minus umin])
+
+;; Ditto, commutative operators (i.e. not minus).
+(define_code_iterator plusumin [plus umin])
+
+;; For opsplit1.
+(define_code_iterator splitop [and plus])
+
+;; The addsubbo and nd code-attributes form a hack.  We need to output
+;; "addu.b", "subu.b" but "bound.b" (no "u"-suffix) which means we'd
+;; need to refer to one iterator from the next.  But, that can't be
+;; done.  Instead output the "u" for unsigned as the "u" in "bound",
+;; i.e. the mnemonic as three parts including the extend-letter, and
+;; with an empty third part for "add" and "sub".
+(define_code_attr addsubbo [(plus "add") (minus "sub") (umin "bo")])
+(define_code_attr nd [(plus "") (minus "") (umin "nd")])
+
 ;; For the shift variants.
-(define_code_macro shift [ashiftrt lshiftrt ashift])
-(define_code_macro shiftrt [ashiftrt lshiftrt])
+(define_code_iterator shift [ashiftrt lshiftrt ashift])
+(define_code_iterator shiftrt [ashiftrt lshiftrt])
 (define_code_attr shlr [(ashiftrt "ashr") (lshiftrt "lshr") (ashift "ashl")])
 (define_code_attr slr [(ashiftrt "asr") (lshiftrt "lsr") (ashift "lsl")])
 
-(define_code_macro ncond [eq ne gtu ltu geu leu])
-(define_code_macro ocond [gt le])
-(define_code_macro rcond [lt ge])
+;; Compares, branches, cbranch, cstore.  Conditions gt and le are CC_NZVC.
+;; Others start out as CCmode and can degenerate to CC_NZmode.
+;; Incidental setters are either CC_NZVCmode or CC_NZmode.  See also
+;; cris-modes.def.
+(define_mode_iterator NZSET [CC_NZ])
+(define_mode_iterator NZUSE [CC CC_NZ CC_NZVC])
+(define_mode_iterator NZVCSET [CC CC_NZVC CC_NZ])
+(define_mode_iterator NZVCUSE [CC_NZVC])
+(define_mode_iterator ZnNNZSET [CC_ZnN CC_NZ])
+(define_mode_iterator ZnNNZUSE [CC CC_ZnN CC_NZ CC_NZVC])
+
+;; All conditions.
+(define_code_iterator cond [eq ne gtu ltu geu leu gt le lt ge])
+
+;; Just equal and not equal.
+(define_code_iterator zcond [eq ne])
+
+;; Conditions that look only at Z and/or N (or can do with that).
+(define_code_iterator nzcond [eq ne gtu leu lt ge])
+
+;; The complement of nzcond within cond; conditions that look (also) on V
+;; or C.
+(define_code_iterator nzvccond [geu ltu gt le])
+
+;; Within nzcond, those that give different opcodes when operands are
+;; reversed or that can ignore V or C.  Also, the complement of zcond
+;; within nzcond.
+(define_code_iterator rnzcond [gtu leu lt ge])
+
+;; CRIS condition mnemonic.
 (define_code_attr CC [(eq "eq") (ne "ne") (gt "gt") (gtu "hi") (lt "lt")
                      (ltu "lo") (ge "ge") (geu "hs") (le "le") (leu "ls")])
+
+;; CRIS reverse condition mnemonic.
 (define_code_attr rCC [(eq "ne") (ne "eq") (gt "le") (gtu "ls") (lt "ge")
                       (ltu "hs") (ge "lt") (geu "lo") (le "gt") (leu "hi")])
-(define_code_attr oCC [(lt "mi") (ge "pl")])
-(define_code_attr roCC [(lt "pl") (ge "mi")])
 
-;; Operand and operator predicates.
+;; Mnemomic for the CRIS condition when V or C can be ignored.
+(define_code_attr oCC [(lt "mi") (ge "pl") (gtu "eq") (ltu "ne")])
 
-(include "predicates.md")
-\f
-;; Test insns.
+;; Reverse of oCC.
+(define_code_attr roCC [(lt "pl") (ge "mi") (gtu "eq") (ltu "ne")])
 
-;; DImode
-;;
-;; Allow register and offsettable mem operands only; post-increment is
-;; not worth the trouble.
+;; CC_Z_IN_NOT_N, a.k.a. CC_ZnNmode.
+(define_code_attr znnCC [(eq "pl") (ne "mi")])
 
-(define_insn "tstdi"
-  [(set (cc0)
-       (match_operand:DI 0 "nonimmediate_operand" "r,o"))]
-  ""
-  "test.d %M0\;ax\;test.d %H0")
+;;; ...and the reverse
+(define_code_attr rznnCC [(eq "mi") (ne "pl")])
 
-;; No test insns with side-effect on the mem addressing.
-;;
-;; See note on cmp-insns with side-effects (or lack of them)
+;; Required unoptimized CCmode, different for nzcond and nzvccond.
+(define_code_attr xCC [(eq "CC") (ne "CC") (gtu "CC") (ltu "CC_NZVC")
+                      (geu "CC_NZVC") (leu "CC") (lt "CC") (ge "CC")
+                      (gt "CC_NZVC") (le "CC_NZVC")])
 
-;; Normal named test patterns from SI on.
-;; FIXME: Seems they should change to be in order smallest..largest.
+;; Substitutions to describe condition-code settings.
 
-(define_insn "tst<mode>"
-  [(set (cc0)
-       (match_operand:BWD 0 "nonimmediate_operand" "r,Q>,m"))]
-  ""
-  "test<m> %0"
-  [(set_attr "slottable" "yes,yes,no")])
+(define_subst_attr "setnz" "setnz_subst" "" "_setnz")
+(define_subst_attr "ccnz" "setnz_subst" "" "_enabled")
+(define_subst_attr "anz" "setnz_subst" "" "*")
+
+(define_subst "setnz_subst"
+  [(set (match_operand 0)
+       (match_operand 1))
+   (clobber (reg:CC CRIS_CC0_REGNUM))]
+  "reload_completed"
+  [(set (reg:CC_NZ CRIS_CC0_REGNUM)
+       (compare:CC_NZ (match_dup 1) (const_int 0)))
+   (set (match_dup 0) (match_dup 1))])
+
+(define_subst_attr "setnzvc" "setnzvc_subst" "" "_setnzvc")
+(define_subst_attr "ccnzvc" "setnzvc_subst" "" "_enabled")
+(define_subst_attr "anzvc" "setnzvc_subst" "" "*")
+
+(define_subst "setnzvc_subst"
+  [(set (match_operand 0)
+       (match_operand 1))
+   (clobber (reg:CC CRIS_CC0_REGNUM))]
+  "reload_completed"
+  [(set (reg:CC_NZVC CRIS_CC0_REGNUM)
+       (compare:CC_NZVC (match_dup 1) (const_int 0)))
+   (set (match_dup 0) (match_dup 1))])
+
+(define_subst_attr "setcc" "setcc_subst" "" "_setcc")
+(define_subst_attr "cccc" "setcc_subst" "" "_enabled")
+(define_subst_attr "acc" "setcc_subst" "" "*")
+
+(define_subst "setcc_subst"
+  [(set (match_operand 0)
+       (match_operand 1))
+   (clobber (reg:CC CRIS_CC0_REGNUM))]
+  "reload_completed"
+  [(set (reg:CC CRIS_CC0_REGNUM)
+       (compare:CC (match_dup 1) (const_int 0)))
+   (set (match_dup 0) (match_dup 1))])
+
+;; Operand and operator predicates.
 
+(include "predicates.md")
+(include "constraints.md")
+\f
 ;; 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
 ;; zeroness.
 ;;
-;; FIXME: Do that some time; check next_cc0_user to determine if
-;; zero or negative is tested for.
+;; FIXME: Do that some time.
 \f
 ;; Compare insns.
 
+;; These are used for compare insn, cbranch and cstore.
+;; FIXME: Port-local reversing of operands is not done.  Still needed?
+;; (It shouldn't be; it should be done as part of register allocation.)
+(define_mode_attr sCC_destc
+ [(DI "r, r,r,r,r,r,r") (SI "r,r, r,  r,r,r") (HI "r, r,  r,r") (QI "r, r,  r,r")])
+(define_mode_attr cmp_op0c
+ [(DI "rm,r,r,r,r,r,r") (SI "r,r, rQ>,r,r,m") (HI "r, rQ>,r,m") (QI "r, rQ>,r,m")])
+(define_mode_attr cmp_op1c
+ [(DI "M,Kc,I,P,n,r,o") (SI "I,rQ>,M, P,g,M") (HI "rQ>,M, g,M") (QI "rQ>,M, g,M")])
+
 ;; We could optimize the sizes of the immediate operands for various
 ;; cases, but that is not worth it because of the very little usage of
 ;; DImode for anything else but a structure/block-mode.  Just do the
 ;; obvious stuff for the straight-forward constraint letters.
 
-(define_insn "cmpdi"
-  [(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")))]
-  ""
+(define_insn "*cmpdi<NZVCSET:mode>"
+  [(set (reg:NZVCSET CRIS_CC0_REGNUM)
+       (compare:NZVCSET
+        (match_operand:DI_ 0 "nonimmediate_operand" "<cmp_op0c>")
+        (match_operand:DI_ 1 "general_operand" "<cmp_op1c>")))]
+  "reload_completed"
   "@
+   test.d %M0\;ax\;test.d %H0
    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
-   cmp.d %M1,%M0\;ax\;cmp.d %H1,%H0
-   cmp.d %M0,%M1\;ax\;cmp.d %H0,%H1")
+   cmp.d %M1,%M0\;ax\;cmp.d %H1,%H0")
 
 ;; Note that compare insns with side effect addressing mode (e.g.):
 ;;
 ;; constants, but sometimes gcc will find its way to use it for other
 ;; (memory) operands.  Avoid side-effect patterns, though (see above).
 
-(define_insn "*cmp_ext<mode>"
-  [(set (cc0)
-       (compare
+(define_insn "*cmp_ext<BW:mode><NZVCSET:mode>"
+  [(set (reg:NZVCSET CRIS_CC0_REGNUM)
+       (compare:NZVCSET
         (match_operand:SI 0 "register_operand" "r,r")
         (match_operator:SI 2 "cris_extend_operator"
                         [(match_operand:BW 1 "memory_operand" "Q>,m")])))]
-  ""
+  "reload_completed"
   "cmp%e2<m> %1,%0"
   [(set_attr "slottable" "yes,no")])
-
-;; Swap operands; it seems the canonical look (if any) is not enforced.
-;;
-;; FIXME: Investigate that.
-
-(define_insn "*cmp_swapext<mode>"
-  [(set (cc0)
-       (compare
-        (match_operator:SI 2 "cris_extend_operator"
-                           [(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")])
 \f
-;; The "normal" compare patterns, from SI on.
-
-(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")))]
-  ""
+;; The "normal" compare patterns, from SI on.  Special-cases with zero
+;; are covered above.
+
+(define_insn "*cmpsi<NZVCSET:mode>"
+  [(set (reg:NZVCSET CRIS_CC0_REGNUM)
+       (compare:NZVCSET
+        (match_operand:SI_ 0 "nonimmediate_operand" "<cmp_op0c>")
+        (match_operand:SI_ 1 "general_operand" "<cmp_op1c>")))]
+  "reload_completed"
   "@
    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")])
-
-(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")))]
-  ""
+   test.d %0"
+  [(set_attr "slottable" "yes,yes,yes,no,no,no")])
+
+(define_insn "*cmp<BW:mode><NZVCSET:mode>"
+  [(set (reg:NZVCSET CRIS_CC0_REGNUM)
+       (compare:NZVCSET
+        (match_operand:BW 0 "nonimmediate_operand" "<cmp_op0c>")
+        (match_operand:BW 1 "general_operand" "<cmp_op1c>")))]
+  "reload_completed"
   "@
-   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")])
+   test<m> %0"
+  [(set_attr "slottable" "yes,yes,no,no")])
 \f
 ;; Pattern matching the BTST insn.
 ;; It is useful for "if (i & val)" constructs, where val is an exact
 ;; 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 testcase.
-(define_insn "*btst"
-  [(set (cc0)
-       (zero_extract
-        (match_operand:SI 0 "nonmemory_operand" "r,r,r,r,r,r,n")
-        (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")))]
+;; extends subregs for lower-size modes.
+(define_insn "*btst<mode>"
+  [(set (reg:ZnNNZSET CRIS_CC0_REGNUM)
+       (compare:ZnNNZSET
+        (zero_extract:SI
+         (match_operand:SI 0 "nonmemory_operand" "r, r,r, r,r, r,Kp")
+         (match_operand:SI 1 "const_int_operand" "Kc,n,Kc,n,Kc,n,n")
+         (match_operand:SI 2 "nonmemory_operand" "M, M,Kc,n,r, r,r"))
+        (const_int 0)))]
   ;; Either it is a single bit, or consecutive ones starting at 0.
-  "GET_CODE (operands[1]) == CONST_INT
-   && (operands[1] == const1_rtx || operands[2] == const0_rtx)
+  "reload_completed
+   && CONST_INT_P (operands[1])
+   && ((operands[1] == const1_rtx && <MODE>mode == CC_ZnNmode)
+       || (operands[2] == const0_rtx && <MODE>mode == CC_NZmode))
    && (REG_S_P (operands[0])
        || (operands[1] == const1_rtx
           && REG_S_P (operands[2])
-          && GET_CODE (operands[0]) == CONST_INT
-          && exact_log2 (INTVAL (operands[0])) >= 0))"
+          && CONST_INT_P (operands[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)".
+;; "power_of_2_value & (1 << y)".  FIXME: Add testcase.
 ;;
 ;; Since there may be codes with tests in on bits (in constant position)
 ;; beyond the size of a word, handle that by assuming those bits are 0.
 
   "@
    btstq (%1-1),%0
-   test.d %0
+   cmpq 0,%0
    btstq %2,%0
    clearf nz
    btst %2,%0
 ;; insn with pseudos that need more reloading.  The question is where.
 
 (define_expand "movdi"
-  [(set (match_operand:DI 0 "nonimmediate_operand" "")
-       (match_operand:DI 1 "general_operand" ""))]
+  [(parallel
+    [(set (match_operand:DI 0 "nonimmediate_operand")
+         (match_operand:DI 1 "general_operand"))
+     (clobber (reg:CC CRIS_CC0_REGNUM))])]
   ""
 {
-  if (GET_CODE (operands[0]) == MEM && operands[1] != const0_rtx)
+  if (MEM_P (operands[0])
+      && operands[1] != const0_rtx
+      && 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
      gcc.c-torture/execute/961213-1.c shows that CSE2 gets confused by the
      resulting subreg sets when using the construct from mcore (as of FSF
      CVS, version -r 1.5), and it believes that the high part (the last one
-     emitted) is the final value.  This construct from romp seems more
-     robust, especially considering the head comments from
-     emit_no_conflict_block.  */
-  if ((GET_CODE (operands[1]) == CONST_INT
-       || GET_CODE (operands[1]) == CONST_DOUBLE)
+     emitted) is the final value.  */
+  if ((CONST_INT_P (operands[1]) || GET_CODE (operands[1]) == CONST_DOUBLE)
       && ! reload_completed
-      && ! reload_in_progress)
+      && ! lra_in_progress)
     {
       rtx insns;
       rtx op0 = operands[0];
       insns = get_insns ();
       end_sequence ();
 
-      emit_no_conflict_block (insns, op0, op1, 0, op1);
+      emit_insn (insns);
       DONE;
     }
 })
 
-(define_insn "*movdi_insn"
+(define_insn_and_split "*movdi_insn"
   [(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"
-  "#")
-
-(define_split
-  [(set (match_operand:DI 0 "nonimmediate_operand" "")
-       (match_operand:DI 1 "general_operand" ""))]
-  "reload_completed"
+       (match_operand:DI 1 "general_operand"      "rx,g,rxM"))
+   (clobber (reg:CC CRIS_CC0_REGNUM))]
+  "(register_operand (operands[0], DImode)
+    || register_operand (operands[1], DImode)
+    || operands[1] == const0_rtx)"
+  "#"
+  "&& reload_completed"
   [(match_dup 2)]
   "operands[2] = cris_split_movdx (operands);")
 \f
-;; Side-effect patterns for move.S1 [rx=ry+rx.S2],rw
-;; and move.S1 [rx=ry+i],rz
-;;  Then movs.S1 and movu.S1 for both modes.
-;;
-;; 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.
-
-(define_insn "*mov_side<mode>_biap"
-  [(set (match_operand:BW 0 "register_operand" "=r,r")
-       (mem:BW (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")
-       (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)"
-  "@
-   #
-   move<m> [%4=%3+%1%T2],%0")
-
-(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)))]
-  "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 [%4=%3+%1%T2],%0")
-\f
-;; move.S1 [rx=ry+i],rz
-;; avoiding move.S1 [ry=ry+i],rz
-;; and      move.S1 [rz=ry+i],rz
-;; Note that "i" is allowed to be a register.
-
-(define_insn "*mov_side<mode>"
-  [(set (match_operand:BW 0 "register_operand" "=r,r,r,r,r")
-       (mem:BW
-        (plus:SI (match_operand:SI 1 "cris_bdap_operand" "%r,r,r,R,R")
-                 (match_operand:SI 2 "cris_bdap_operand" "r>Rn,r,>Rn,r,r"))))
-   (set (match_operand:SI 3 "register_operand" "=*1,r,r,*2,r")
-       (plus:SI (match_dup 1)
-                (match_dup 2)))]
-  "cris_side_effect_mode_ok (PLUS, operands, 3, 1, 2, -1, 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 "#";
-  if (which_alternative == 4)
-    return "move<m> [%3=%2%S1],%0";
-  return "move<m> [%3=%1%S2],%0";
-})
-
-(define_insn "*mov_sidesisf"
-  [(set (match_operand 0 "register_operand" "=r,r,r,x,x,x,r,r,x,x")
-       (mem
-        (plus:SI
-         (match_operand:SI 1 "cris_bdap_operand" "%r,r,r,r,r,r,R,R,R,R")
-         (match_operand:SI 2 "cris_bdap_operand" "r>Rn,r,>Rn,r>Rn,r,>Rn,r,r,r,r"))))
-   (set (match_operand:SI 3 "register_operand" "=*1,r,r,*1,r,r,*2,r,*2,r")
-       (plus:SI (match_dup 1)
-                (match_dup 2)))]
-  "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
-       || which_alternative == 3
-       || which_alternative == 6
-       || which_alternative == 8)
-      && (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 "#";
-  if (which_alternative < 3)
-    return "move.%s0 [%3=%1%S2],%0";
-  if (which_alternative == 7)
-    return "move.%s0 [%3=%2%S1],%0";
-  if (which_alternative == 9)
-    return "move [%3=%2%S1],%0";
-  return "move [%3=%1%S2],%0";
-})
-\f
-;; Other way around; move to memory.
-
-;; Note that the condition (which for side-effect patterns is usually a
-;; call to cris_side_effect_mode_ok), isn't consulted for register
-;; allocation preferences -- constraints is the method for that.  The
-;; drawback is that we can't exclude register allocation to cause
-;; "move.s rw,[rx=ry+rz.S]" when rw==rx without also excluding rx==ry or
-;; rx==rz if we use an earlyclobber modifier for the constraint for rx.
-;; Instead of that, we recognize and split the cases where dangerous
-;; register combinations are spotted: where a register is set in the
-;; side-effect, and used in the main insn.  We don't handle the case where
-;; the set in the main insn overlaps the set in the side-effect; that case
-;; must be handled in gcc.  We handle just the case where the set in the
-;; side-effect overlaps the input operand of the main insn (i.e. just
-;; moves to memory).
-
-;;
-;; move.s rz,[ry=rx+rw.S]
-
-(define_insn "*mov_side<mode>_biap_mem"
-  [(set (mem:BW (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:BW 3 "register_operand" "r,r,r"))
-   (set (match_operand:SI 4 "register_operand" "=*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)"
-  "@
-   #
-   #
-   move<m> %3,[%4=%2+%0%T1]")
-
-(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)))]
-  "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 %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
-;; with the set in the side-effect getting the same register as the input
-;; register.
-
-(define_split
-  [(parallel
-    [(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 2)))])]
-  "reload_completed && reg_overlap_mentioned_p (operands[4], operands[3])"
-  [(set (match_dup 5) (match_dup 3))
-   (set (match_dup 4) (match_dup 2))
-   (set (match_dup 4)
-       (plus:SI (mult:SI (match_dup 0)
-                         (match_dup 1))
-                (match_dup 4)))]
-  "operands[5]
-     = 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.
-
-;; QImode
-
-(define_insn "*mov_side<mode>_mem"
-  [(set (mem:BW
-        (plus:SI (match_operand:SI 0 "cris_bdap_operand" "%r,r,r,r,R,R,R")
-                 (match_operand:SI 1 "cris_bdap_operand" "r>Rn,r>Rn,r,>Rn,r,r,r")))
-       (match_operand:BW 2 "register_operand" "r,r,r,r,r,r,r"))
-   (set (match_operand:SI 3 "register_operand" "=*0,!*2,r,r,*1,!*2,r")
-       (plus:SI (match_dup 0)
-                (match_dup 1)))]
-  "cris_side_effect_mode_ok (PLUS, operands, 3, 0, 1, -1, 2)"
-{
-  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 || which_alternative == 5)
-    return "#";
-  if (which_alternative == 6)
-    return "move.%s2 %2,[%3=%1%S0]";
-  return "move<m> %2,[%3=%0%S1]";
-})
-
-;; SImode
-
-(define_insn "*mov_sidesisf_mem"
-  [(set (mem
-        (plus:SI
-         (match_operand:SI
-          0 "cris_bdap_operand"
-                               "%r,  r,   r,r,  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,r,  r,r, r")))
-       (match_operand 2 "register_operand"
-                               "r,   r,   r,r,  x,   x,x,  r,r,  r,x, x"))
-   (set (match_operand:SI 3 "register_operand"
-                               "=*0,!2,   r,r,  *0,  r,r, *1,!*2,r,*1,r")
-       (plus:SI (match_dup 0)
-                (match_dup 1)))]
-  "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 || 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
-      || which_alternative == 7
-      || which_alternative == 8
-      || which_alternative == 10)
-    return "#";
-  if (which_alternative < 4)
-    return "move.%s2 %2,[%3=%0%S1]";
-  if (which_alternative == 9)
-    return "move.%s2 %2,[%3=%1%S0]";
-  if (which_alternative == 11)
-    return "move %2,[%3=%1%S0]";
-  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
-;; condition isn't checked at register allocation.
-
-(define_split
-  [(parallel
-    [(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)))])]
-  "reload_completed && reg_overlap_mentioned_p (operands[3], operands[2])"
-  [(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)))]
-  "")
-\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.
-
-;;  clear.[bwd] [ry=rx+rw.s2]
-
-(define_insn "*clear_side<mode>_biap"
-  [(set (mem:BWD (plus:SI
-                 (mult:SI (match_operand:SI 0 "register_operand" "r,r")
-                          (match_operand:SI 1 "const_int_operand" "n,n"))
-                 (match_operand:SI 2 "register_operand" "r,r")))
-       (const_int 0))
-   (set (match_operand:SI 3 "register_operand" "=*2,r")
-       (plus:SI (mult:SI (match_dup 0)
-                         (match_dup 1))
-                (match_dup 2)))]
-  "cris_side_effect_mode_ok (MULT, operands, 3, 2, 0, 1, -1)"
-  "@
-   #
-   clear<m> [%3=%2+%0%T1]")
-
-;; clear.[bwd] [ry=rz+i]
-
-(define_insn "*clear_side<mode>"
-  [(set (mem:BWD
-        (plus:SI (match_operand:SI 0 "cris_bdap_operand" "%r,r,r,R,R")
-                 (match_operand:SI 1 "cris_bdap_operand" "r>Rn,r,>Rn,r,r")))
-       (const_int 0))
-   (set (match_operand:SI 2 "register_operand" "=*0,r,r,*1,r")
-       (plus:SI (match_dup 0)
-                (match_dup 1)))]
-  "cris_side_effect_mode_ok (PLUS, operands, 2, 0, 1, -1, -1)"
-{
-  if ((which_alternative == 0 || which_alternative == 3)
-      && (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 == 4)
-    return "clear<m> [%2=%1%S0]";
-  return "clear<m> [%2=%0%S1]";
-})
-\f
 ;; Normal move patterns from SI on.
 
 (define_expand "movsi"
-  [(set
-    (match_operand:SI 0 "nonimmediate_operand" "")
-    (match_operand:SI 1 "cris_general_operand_or_symbol" ""))]
+  [(parallel
+    [(set
+      (match_operand:SI 0 "nonimmediate_operand")
+      (match_operand:SI 1 "general_operand"))
+     (clobber (reg:CC CRIS_CC0_REGNUM))])]
   ""
 {
   /* If the output goes to a MEM, make sure we have zero or a register as
      input.  */
-  if (GET_CODE (operands[0]) == MEM
+  if (MEM_P (operands[0])
       && ! REG_S_P (operands[1])
       && operands[1] != const0_rtx
-      && ! no_new_pseudos)
+      && can_create_pseudo_p ())
     operands[1] = force_reg (SImode, operands[1]);
 
-  /* If we're generating PIC and have an incoming symbol, validize it to a
-     general operand or something that will match a special pattern.
-
-     FIXME: Do we *have* to recognize anything that would normally be a
-     valid symbol?  Can we exclude global PIC addresses with an added
-     offset?  */
-    if (flag_pic
-       && CONSTANT_ADDRESS_P (operands[1])
-       && !cris_valid_pic_const (operands[1]))
-      {
-       enum cris_pic_symbol_type t = cris_pic_symbol_type_of (operands[1]);
-
-       gcc_assert (t != cris_no_symbol);
-
-       if (! REG_S_P (operands[0]))
-         {
-           /* We must have a register as destination for what we're about to
-              do, and for the patterns we generate.  */
-           CRIS_ASSERT (!no_new_pseudos);
-           operands[1] = force_reg (SImode, operands[1]);
-         }
-       else
-         {
-           /* FIXME: add a REG_EQUAL (or is it REG_EQUIV) note to the
-              destination register for the symbol.  It might not be
-              worth it.  Measure.  */
-           current_function_uses_pic_offset_table = 1;
-           if (t == cris_gotrel_symbol)
-             {
-               /* Change a "move.d sym(+offs),rN" into (allocate register rM)
-                  "move.d (const (plus (unspec [sym]
-                   CRIS_UNSPEC_GOTREL) offs)),rM" "add.d rPIC,rM,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 (! no_new_pseudos);
-               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)
-             {
-               /* Change a "move.d sym,rN" into (allocate register rM, rO)
-                  "move.d (const (unspec [sym] CRIS_UNSPEC_GOTREAD)),rM"
-                  "add.d rPIC,rM,rO", "move.d [rO],rN" with
-                  the memory access marked as read-only.  */
-               rtx tem, mem, rm, ro, rn = operands[0];
-               gcc_assert (! no_new_pseudos);
-               tem = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, operands[1]),
-                                     CRIS_UNSPEC_GOTREAD);
-               rm = gen_reg_rtx (Pmode);
-               emit_move_insn (rm, gen_rtx_CONST (Pmode, tem));
-               ro = gen_reg_rtx (Pmode);
-               if (expand_binop (Pmode, add_optab, rm, pic_offset_table_rtx,
-                                 ro, 0, OPTAB_LIB_WIDEN) != ro)
-                 internal_error ("expand_binop failed in movsi got");
-               mem = gen_rtx_MEM (Pmode, ro);
-
-               /* This MEM doesn't alias anything.  Whether it
-                  aliases other same symbols is unimportant.  */
-               set_mem_alias_set (mem, new_alias_set ());
-               MEM_NOTRAP_P (mem) = 1;
-               MEM_READONLY_P (mem) = 1;
-               emit_move_insn (rn, mem);
-               DONE;
-             }
-           else
-             {
-               /* We get here when we have to change something that would
-                  be recognizable if it wasn't PIC.  A ``sym'' is ok for
-                  PIC symbols both with and without a GOT entry.  And ``sym
-                  + offset'' is ok for local symbols, so the only thing it
-                  could be, is a global symbol with an offset.  Check and
-                  abort if not.  */
-               rtx reg = gen_reg_rtx (Pmode);
-               rtx sym = get_related_value (operands[1]);
-               HOST_WIDE_INT offs = get_integer_term (operands[1]);
-
-               gcc_assert (! no_new_pseudos
-                           && t == cris_got_symbol_needing_fixup
-                           && sym != NULL_RTX && offs != 0);
-
-               emit_move_insn (reg, sym);
-               if (expand_binop (SImode, add_optab, reg,
-                                 GEN_INT (offs), operands[0], 0,
-                                 OPTAB_LIB_WIDEN) != operands[0])
-                 internal_error ("expand_binop failed in movsi got+offs");
-               DONE;
-             }
-         }
-      }
+   /* At post-reload time, we'll get here for e.g. split multi-mode insns
+      with a memory destination.  Go directly to the clobber-less variant.
+      FIXME: Also applies to special-register source or destination.  */
+   if (reload_completed
+       && (MEM_P (operands[0]) || operands[1] == const0_rtx))
+     {
+        emit_insn (gen_rtx_SET (operands[0], operands[1]));
+        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,%:"
-  [(set_attr "cc" "clobber")])
-
-(define_insn "*movsi_internal"
+;; We provide CC, CC_NZ and CC_NZVC variants, as moves clear V and C
+;; and the result is thus usable in a compare against 0.
+(define_insn "*movsi_internal<setcc><setnz><setnzvc>"
   [(set
-    (match_operand:SI 0 "nonimmediate_operand" "=r,r, r,Q>,r,Q>,g,r,r, r,g,rQ>,x,  m,x")
-    ;; 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"))]
-  ""
+    (match_operand:SI 0 "nonimmediate_operand"
+                     "=r,r, r,Q>,r,Q>,g,r,r,g,rQ>,x,  m,x, Q>,r,g")
+    (match_operand:SI 1 "general_operand"
+                      "r,Q>,M,M, I,r, M,n,g,r,x,  rQ>,x,gi,r, g,r"))
+   (clobber (reg:CC CRIS_CC0_REGNUM))]
+  ;; Avoid matching insns we know must be reloaded.  Without one
+  ;; operand being a (pseudo-)register, reload chooses
+  ;; reload-registers suboptimally.
+  "REG_S_P (operands[0]) || REG_S_P (operands[1]) || operands[1] == const0_rtx"
 {
   /* Better to have c-switch here; it is worth it to optimize the size of
      move insns.  The alternative would be to try to find more constraint
     case 0:
     case 1:
     case 5:
+    case 8:
     case 9:
-    case 10:
+    case 14:
+    case 15:
+    case 16:
       return "move.d %1,%0";
 
+    case 10:
     case 11:
     case 12:
     case 13:
-    case 14:
-      return "move %d1,%0";
+      return "move %1,%0";
 
     case 2:
     case 3:
        }
       return "move.d %1,%0";
 
-    case 8:
-      {
-       rtx tem = operands[1];
-       gcc_assert (GET_CODE (tem) == CONST);
-       tem = XEXP (tem, 0);
-       if (GET_CODE (tem) == PLUS
-           && GET_CODE (XEXP (tem, 0)) == UNSPEC
-           && XINT (XEXP (tem, 0), 1) == CRIS_UNSPEC_GOTREL
-           && GET_CODE (XEXP (tem, 1)) == CONST_INT)
-         tem = XEXP (tem, 0);
-       gcc_assert (GET_CODE (tem) == UNSPEC);
-       switch (XINT (tem, 1))
-         {
-         case CRIS_UNSPEC_GOTREAD:
-         case CRIS_UNSPEC_PLTGOTREAD:
-           /* Using sign-extend mostly to be consistent with the
-              indexed addressing mode.  */
-           if (flag_pic == 1)
-             return "movs.w %1,%0";
-         case CRIS_UNSPEC_GOTREL:
-         case CRIS_UNSPEC_PLT:
-           return "move.d %1,%0";
-
-         default:
-           gcc_unreachable ();
-         }
-      }
     default:
-      return "BOGUS: %1 to %0";
+      gcc_unreachable ();
     }
 }
-  [(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.
-;;
-;; [rx=ry+rz.S]
-;;
-;; QImode to HImode
-;;
-;; FIXME: Can we omit extend to HImode, since GCC should truncate for
-;; HImode by itself?  Perhaps use only anonymous modes?
-
-(define_insn "*ext_sideqihi_biap"
-  [(set (match_operand:HI 0 "register_operand" "=r,r")
-       (match_operator:HI
-        5 "cris_extend_operator"
-        [(mem:QI (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")
-       (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)"
-  "@
-   #
-   mov%e5.%m5 [%4=%3+%1%T2],%0")
-
-(define_insn "*ext_side<mode>si_biap"
-  [(set (match_operand:SI 0 "register_operand" "=r,r")
-       (match_operator:SI
-        5 "cris_extend_operator"
-        [(mem:BW (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")
-       (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)"
-  "@
-   #
-   mov%e5<m> [%4=%3+%1%T2],%0")
-\f
-;; Same but [rx=ry+i]
-
-;; QImode to HImode
-
-(define_insn "*ext_sideqihi"
-  [(set (match_operand:HI 0 "register_operand" "=r,r,r,r,r")
-       (match_operator:HI
-        4 "cris_extend_operator"
-        [(mem:QI (plus:SI
-                  (match_operand:SI 1 "cris_bdap_operand" "%r,r,r,R,R")
-                  (match_operand:SI 2 "cris_bdap_operand" "r>Rn,r,>Rn,r,r")))]))
-   (set (match_operand:SI 3 "register_operand" "=*1,r,r,*2,r")
-       (plus:SI (match_dup 1)
-                (match_dup 2)))]
-  "cris_side_effect_mode_ok (PLUS, operands, 3, 1, 2, -1, 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 "#";
-  if (which_alternative == 4)
-    return "mov%e4.%m4 [%3=%2%S1],%0";
-  return "mov%e4.%m4 [%3=%1%S2],%0";
-})
-
-(define_insn "*ext_side<mode>si"
-  [(set (match_operand:SI 0 "register_operand" "=r,r,r,r,r")
-       (match_operator:SI
-        4 "cris_extend_operator"
-        [(mem:BW (plus:SI
-                  (match_operand:SI 1 "cris_bdap_operand" "%r,r,r,R,R")
-                  (match_operand:SI 2 "cris_bdap_operand" "r>Rn,r,>Rn,r,r")))]))
-   (set (match_operand:SI 3 "register_operand" "=*1,r,r,*2,r")
-       (plus:SI (match_dup 1)
-                (match_dup 2)))]
-  "cris_side_effect_mode_ok (PLUS, operands, 3, 1, 2, -1, 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 "#";
-  if (which_alternative == 4)
-    return "mov%e4<m> [%3=%2%S1],%0";
-  return "mov%e4<m> [%3=%1%S2],%0";
-})
+  [(set_attr "cpu_variant" "*,*,*,*,*,v0,*,*,v0,v0,*,*,*,*,v10,v10,v10")
+   (set_attr "slottable" "yes,yes,yes,yes,yes,yes,no,no,no,no,yes,yes,no,no,yes,no,no")
+   (set_attr "cc<cccc><ccnz><ccnzvc>"
+            "*,*,none,none,*,none,none,*,*,none,none,none,none,none,none,*,none")])
 \f
 ;; FIXME: See movsi.
 
-(define_insn "movhi"
+(define_insn "<acc><anz><anzvc>movhi<setcc><setnz><setnzvc>"
   [(set
     (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"))]
+    (match_operand:HI 1 "general_operand"      "r,Q>,M,M, I,r, L,O,n,M,r,g,x,r"))
+   (clobber (reg:CC CRIS_CC0_REGNUM))]
   ""
 {
   switch (which_alternative)
   }
 }
   [(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")])
+   (set_attr "cc<cccc><ccnz><ccnzvc>" "*,*,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 1 "general_operand"       "r,Q>,M,M, r, M,g,r"))
+   (clobber (reg:CC CRIS_CC0_REGNUM))]
   ""
   "@
    move.w %1,%0
   ""
   "")
 \f
-(define_insn "movqi"
+(define_insn "<acc><anz><anzvc>movqi<setcc><setnz><setnzvc>"
   [(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"))]
+       (match_operand:QI 1 "general_operand"       "r,r, Q>,M,M, I,M,r,O,g,x,r"))
+   (clobber (reg:CC CRIS_CC0_REGNUM))]
   ""
   "@
    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")])
+   (set_attr "cc<cccc><ccnz><ccnzvc>"
+            "*,none,*,none,none,*,none,none,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 1 "general_operand"        "r,r, Q>,M,M, M,r,g"))
+   (clobber (reg:CC CRIS_CC0_REGNUM))]
   ""
   "@
    move.b %1,%0
 
 (define_insn "movsf"
   [(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"))]
+       (match_operand:SF 1 "general_operand"       "r,r, Q>,G,G, G,r,g,x,r,x, x,Q>,g"))
+   (clobber (reg:CC CRIS_CC0_REGNUM))]
   ""
   "@
    move.d %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".
+;; Post-reload, for memory destinations, split the clobber-variant and
+;; get rid of the clobber.
+
+(define_split ;; "*mov_tomem<mode>_split"
+  [(set (match_operand:BWD 0 "memory_operand")
+       (match_operand:BWD 1 "nonmemory_operand"))
+   (clobber (reg:CC CRIS_CC0_REGNUM))]
+  "reload_completed"
+  [(set (match_dup 0) (match_dup 1))]
+  "")
+
+;; Exclude moving special-registers to memory from matching for
+;; less-than-SImode, as they are SImode only (or actually, the size of
+;; the register, but the ones free for "x" are naturally SImode; see
+;; special measures taken for reload).
+;; This might be a belt-and-suspenders thing, as a move from special
+;; register to memory in less-than-SImode should not have made it here.
+
+(define_mode_attr mov_tomem_enabled
+  [(SI "yes,yes,yes,yes,yes,yes")
+   (HI "yes,yes,no,yes,yes,no")
+   (QI "yes,yes,no,yes,yes,no")])
+
+(define_insn "*mov_tomem<mode>"
+  [(set (match_operand:BWD 0 "memory_operand"   "=Q>,Q>,Q>,m,m,m")
+       (match_operand:BWD 1 "nonmemory_operand" "M, r, x, M,r,x"))]
+  "reload_completed"
+  "@
+   clear<m> %0
+   move<m> %1,%0
+   move %1,%0
+   clear<m> %0
+   move<m> %1,%0
+   move %1,%0"
+  [(set_attr "slottable" "yes,yes,yes,no,no,no")
+   (set_attr "enabled" "<mov_tomem_enabled>")])
+
+(define_split ;; "*mov_fromzero<mode>_split"
+  [(set (match_operand:BWD 0 "register_operand") (const_int 0))
+   (clobber (reg:CC CRIS_CC0_REGNUM))]
+  "reload_completed
+   && REGNO(operands[0]) <= CRIS_LAST_GENERAL_REGISTER"
+  [(set (match_dup 0) (const_int 0))]
+  "")
+
+(define_insn "*mov_fromzero<mode>"
+  [(set (match_operand:BWD 0 "register_operand" "=r") (const_int 0))]
+  "reload_completed"
+  "clear<m> %0"
+  [(set_attr "slottable" "yes")])
+\f
+;; Movem patterns.  Primarily for use in function prologue and epilogue.
+;; Unfortunately, movem stores R0 in the highest memory location, thus
+;; the opposite of the expectation for the standard names "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")
 
 (define_insn "extendsidi2"
   [(set (match_operand:DI 0 "register_operand" "=r")
-       (sign_extend:DI (match_operand:SI 1 "general_operand" "g")))]
+       (sign_extend:DI (match_operand:SI 1 "general_operand" "g")))
+   (clobber (reg:CC CRIS_CC0_REGNUM))]
   ""
   "move.d %1,%M0\;smi %H0\;neg.d %H0,%H0")
 
 (define_insn "extend<mode>di2"
   [(set (match_operand:DI 0 "register_operand" "=r")
-       (sign_extend:DI (match_operand:BW 1 "general_operand" "g")))]
+       (sign_extend:DI (match_operand:BW 1 "general_operand" "g")))
+   (clobber (reg:CC CRIS_CC0_REGNUM))]
   ""
   "movs<m> %1,%M0\;smi %H0\;neg.d %H0,%H0")
 
-(define_insn "extend<mode>si2"
+(define_insn "<acc><anz><anzvc>extend<mode>si2<setcc><setnz><setnzvc>"
   [(set (match_operand:SI 0 "register_operand" "=r,r,r")
-       (sign_extend:SI (match_operand:BW 1 "general_operand" "r,Q>,g")))]
+       (sign_extend:SI (match_operand:BW 1 "general_operand" "r,Q>,g")))
+   (clobber (reg:CC CRIS_CC0_REGNUM))]
   ""
   "movs<m> %1,%0"
   [(set_attr "slottable" "yes,yes,no")])
 
-;; To do a byte->word extension, extend to dword, exept that the top half
+;; To do a byte->word extension, extend to dword, except that the top half
 ;; of the register will be clobbered.  FIXME: Perhaps this is not needed.
 
 (define_insn "extendqihi2"
   [(set (match_operand:HI 0 "register_operand" "=r,r,r")
-       (sign_extend:HI (match_operand:QI 1 "general_operand" "r,Q>,g")))]
+       (sign_extend:HI (match_operand:QI 1 "general_operand" "r,Q>,g")))
+   (clobber (reg:CC CRIS_CC0_REGNUM))]
   ""
   "movs.b %1,%0"
   [(set_attr "slottable" "yes,yes,no")])
 ;; Zero-extend.  The DImode ones are synthesized by gcc, so we don't
 ;; specify them here.
 
-(define_insn "zero_extend<mode>si2"
+(define_insn "<acc><anz><anzvc>zero_extend<mode>si2<setcc><setnz><setnzvc>"
   [(set (match_operand:SI 0 "register_operand" "=r,r,r")
        (zero_extend:SI
-        (match_operand:BW 1 "nonimmediate_operand" "r,Q>,m")))]
+        (match_operand:BW 1 "nonimmediate_operand" "r,Q>,m")))
+   (clobber (reg:CC CRIS_CC0_REGNUM))]
   ""
   "movu<m> %1,%0"
   [(set_attr "slottable" "yes,yes,no")])
 (define_insn "zero_extendqihi2"
   [(set (match_operand:HI 0 "register_operand" "=r,r,r")
        (zero_extend:HI
-        (match_operand:QI 1 "nonimmediate_operand" "r,Q>,m")))]
+        (match_operand:QI 1 "nonimmediate_operand" "r,Q>,m")))
+   (clobber (reg:CC CRIS_CC0_REGNUM))]
   ""
   "movu.b %1,%0"
   [(set_attr "slottable" "yes,yes,no")])
 \f
-;; All kinds of arithmetic and logical instructions.
-;;
-;; First, anonymous patterns to match addressing modes with
-;; side-effects.
-;;
-;; op.S [rx=ry+I],rz; (add, sub, or, and, bound).
-;;
-;; [rx=ry+rz.S]
-
-(define_insn "*op_side<mode>_biap"
-  [(set (match_operand:BWD 0 "register_operand" "=r,r")
-       (match_operator:BWD
-        6 "cris_orthogonal_operator"
-        [(match_operand:BWD 1 "register_operand" "0,0")
-         (mem:BWD (plus:SI
-                   (mult:SI (match_operand:SI 2 "register_operand" "r,r")
-                            (match_operand:SI 3 "const_int_operand" "n,n"))
-                   (match_operand:SI 4 "register_operand" "r,r")))]))
-   (set (match_operand:SI 5 "register_operand" "=*4,r")
-       (plus:SI (mult:SI (match_dup 2)
-                         (match_dup 3))
-                (match_dup 4)))]
-  "cris_side_effect_mode_ok (MULT, operands, 5, 4, 2, 3, 0)"
-  "@
-   #
-   %x6<m> [%5=%4+%2%T3],%0")
-\f
-;; [rx=ry+i] ([%4=%2+%3])
-
-(define_insn "*op_side<mode>"
-  [(set (match_operand:BWD 0 "register_operand" "=r,r,r,r,r")
-       (match_operator:BWD
-        5 "cris_orthogonal_operator"
-        [(match_operand:BWD 1 "register_operand" "0,0,0,0,0")
-         (mem:BWD (plus:SI
-                  (match_operand:SI 2 "cris_bdap_operand" "%r,r,r,R,R")
-                  (match_operand:SI 3 "cris_bdap_operand" "r>Rn,r,>Rn,r,r")))]))
-   (set (match_operand:SI 4 "register_operand" "=*2,r,r,*3,r")
-       (plus:SI (match_dup 2)
-                (match_dup 3)))]
-  "cris_side_effect_mode_ok (PLUS, operands, 4, 2, 3, -1, 0)"
-{
-  if ((which_alternative == 0 || which_alternative == 3)
-      && (GET_CODE (operands[3]) != CONST_INT
-         || INTVAL (operands[3]) > 127
-         || INTVAL (operands[3]) < -128
-         || CONST_OK_FOR_LETTER_P (INTVAL (operands[3]), 'N')
-         || CONST_OK_FOR_LETTER_P (INTVAL (operands[3]), 'J')))
-    return "#";
-  if (which_alternative == 4)
-    return "%x5.%s0 [%4=%3%S2],%0";
-  return "%x5<m> [%4=%2%S3],%0";
-})
-\f
-;; To match all cases for commutative operations we may have to have the
-;; following pattern for add, or & and.  I do not know really, but it does
-;; not break anything.
-;;
-;; FIXME: This really ought to be checked.
-;;
-;; op.S [rx=ry+I],rz;
-;;
-;; [rx=ry+rz.S]
-
-(define_insn "*op_swap_side<mode>_biap"
-  [(set (match_operand:BWD 0 "register_operand" "=r,r")
-       (match_operator:BWD
-        6 "cris_commutative_orth_op"
-        [(mem:BWD (plus:SI
-                  (mult:SI (match_operand:SI 2 "register_operand" "r,r")
-                           (match_operand:SI 3 "const_int_operand" "n,n"))
-                  (match_operand:SI 4 "register_operand" "r,r")))
-         (match_operand:BWD 1 "register_operand" "0,0")]))
-   (set (match_operand:SI 5 "register_operand" "=*4,r")
-       (plus:SI (mult:SI (match_dup 2)
-                         (match_dup 3))
-                (match_dup 4)))]
-  "cris_side_effect_mode_ok (MULT, operands, 5, 4, 2, 3, 0)"
-  "@
-   #
-   %x6<m> [%5=%4+%2%T3],%0")
-\f
-;; [rx=ry+i] ([%4=%2+%3])
-;; FIXME: These could have anonymous mode for operand 0.
-
-;; QImode
-
-(define_insn "*op_swap_side<mode>"
-  [(set (match_operand:BWD 0 "register_operand" "=r,r,r,r,r")
-       (match_operator:BWD
-        5 "cris_commutative_orth_op"
-        [(mem:BWD
-          (plus:SI (match_operand:SI 2 "cris_bdap_operand" "%r,r,r,R,R")
-                   (match_operand:SI 3 "cris_bdap_operand" "r>Rn,r,>Rn,r,r")))
-         (match_operand:BWD 1 "register_operand" "0,0,0,0,0")]))
-   (set (match_operand:SI 4 "register_operand" "=*2,r,r,*3,r")
-       (plus:SI (match_dup 2)
-                (match_dup 3)))]
-  "cris_side_effect_mode_ok (PLUS, operands, 4, 2, 3, -1, 0)"
-{
-  if ((which_alternative == 0 || which_alternative == 3)
-      && (GET_CODE (operands[3]) != CONST_INT
-         || INTVAL (operands[3]) > 127
-         || INTVAL (operands[3]) < -128
-         || CONST_OK_FOR_LETTER_P (INTVAL (operands[3]), 'N')
-         || CONST_OK_FOR_LETTER_P (INTVAL (operands[3]), 'J')))
-    return "#";
-  if (which_alternative == 4)
-    return "%x5<m> [%4=%3%S2],%0";
-  return "%x5<m> [%4=%2%S3],%0";
-})
-\f
 ;; Add operations, standard names.
 
 ;; 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"
+  [(parallel
+    [(set (match_operand:DI 0 "register_operand")
+         (plus:DI (match_operand:DI 1 "register_operand")
+                  (match_operand:DI 2 "general_operand")))
+     (clobber (reg:CC CRIS_CC0_REGNUM))])]
+  ""
+  "")
+
+(define_insn "*adddi3<setnz>"
   [(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")))]
+                (match_operand:DI 2 "general_operand" "J,N,P,g,!To")))
+   (clobber (reg:CC CRIS_CC0_REGNUM))]
   ""
   "@
    addq %2,%M0\;ax\;addq 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"
-  [(set (match_operand:SI 0 "register_operand"  "=r,r, r,r,r,r, r,r,  r")
+(define_expand "add<mode>3"
+  [(parallel
+    [(set (match_operand:BWD 0 "register_operand")
+         (plus:BWD
+          (match_operand:BWD 1 "register_operand")
+          (match_operand:BWD 2 "general_operand")))
+     (clobber (reg:CC CRIS_CC0_REGNUM))])]
+  ""
+  "")
+
+(define_insn "*addsi3<setnz>"
+  [(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, 0,r,  r")
-        (match_operand:SI 2 "general_operand"   "r,Q>,J,N,n,!S,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")))
+   (clobber (reg:CC CRIS_CC0_REGNUM))]
 
 ;; The last constraint is due to that after reload, the '%' is not
 ;; honored, and canonicalization doesn't care about keeping the same
 ;; register as in destination.  This will happen after insn splitting.
-;; gcc <= 2.7.2.  FIXME: Check for gcc-2.9x
 
  ""
 {
        }
       return "add.d %2,%0";
     case 5:
-      {
-       rtx tem = operands[2];
-       gcc_assert (GET_CODE (tem) == CONST);
-       tem = XEXP (tem, 0);
-       if (GET_CODE (tem) == PLUS
-           && GET_CODE (XEXP (tem, 0)) == UNSPEC
-           && XINT (XEXP (tem, 0), 1) == CRIS_UNSPEC_GOTREL
-           && GET_CODE (XEXP (tem, 1)) == CONST_INT)
-         tem = XEXP (tem, 0);
-       gcc_assert (GET_CODE (tem) == UNSPEC);
-       switch (XINT (tem, 1))
-         {
-         case CRIS_UNSPEC_GOTREAD:
-         case CRIS_UNSPEC_PLTGOTREAD:
-           /* Using sign-extend mostly to be consistent with the
-              indexed addressing mode.  */
-           if (flag_pic == 1)
-             return "adds.w %2,%0";
-           /* Fall through.  */
-         case CRIS_UNSPEC_PLT:
-         case CRIS_UNSPEC_GOTREL:
-           return "add.d %2,%0";
-         default:
-           gcc_unreachable ();
-         }
-      }
-    case 6:
       return "add.d %2,%0";
-    case 7:
+    case 6:
       return "add.d %2,%1,%0";
-    case 8:
+    case 7:
       return "add.d %1,%0";
     default:
       return "BOGUS addsi %2+%1 to %0";
     }
 }
- [(set_attr "slottable" "yes,yes,yes,yes,no,no,no,no,yes")])
+ [(set_attr "slottable" "yes,yes,yes,yes,no,no,no,yes")])
 \f
-(define_insn "addhi3"
+(define_insn "*addhi3<setnz>"
   [(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")))]
+                (match_operand:HI 2 "general_operand"   "r,Q>,J,N,g,!To")))
+   (clobber (reg:CC CRIS_CC0_REGNUM))]
   ""
   "@
    add.w %2,%0
    add.w %2,%0
    add.w %2,%1,%0"
   [(set_attr "slottable" "yes,yes,yes,yes,no,no")
-   (set_attr "cc" "normal,normal,clobber,clobber,normal,normal")])
+   (set_attr "cc<ccnz>" "normal,normal,clobber,clobber,normal,normal")])
 
-(define_insn "addqi3"
+(define_insn "*addqi3<setnz>"
   [(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")))]
+                (match_operand:QI 2 "general_operand"   "r,Q>,J,N,O,g,!To")))
+   (clobber (reg:CC CRIS_CC0_REGNUM))]
   ""
   "@
    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")])
+   (set_attr "cc<ccnz>" "normal,normal,clobber,clobber,clobber,normal,normal")])
 \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"
+  [(parallel
+    [(set (match_operand:DI 0 "register_operand")
+         (minus:DI (match_operand:DI 1 "register_operand")
+                   (match_operand:DI 2 "general_operand")))
+     (clobber (reg:CC CRIS_CC0_REGNUM))])]
+  ""
+  "")
+
+(define_insn "*subdi3<setnz>"
   [(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")))]
+                 (match_operand:DI 2 "general_operand" "J,N,P,g,!To")))
+   (clobber (reg:CC CRIS_CC0_REGNUM))]
   ""
   "@
    subq %2,%M0\;ax\;subq 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_expand "sub<mode>3"
+  [(parallel
+    [(set (match_operand:BWD 0 "register_operand")
+         (minus:BWD
+          (match_operand:BWD 1 "register_operand")
+          (match_operand:BWD 2 "general_operand")))
+     (clobber (reg:CC CRIS_CC0_REGNUM))])]
+  ""
+  "")
+
+(define_insn "*subsi3<setnz>"
   [(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 2 "general_operand"  "r,Q>,J,N,P,n,g,!To")))
+   (clobber (reg:CC CRIS_CC0_REGNUM))]
   ""
 
 ;; This does not do the optimal: "addu.w 65535,r0" when %2 is negative.
    sub.d %2,%1,%0"
   [(set_attr "slottable" "yes,yes,yes,yes,no,no,no,no")])
 \f
-(define_insn "sub<mode>3"
+(define_insn "*sub<mode>3<setnz>"
   [(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")))]
+                 (match_operand:BW 2 "general_operand"  "r,Q>,J,N,g,!To")))
+   (clobber (reg:CC CRIS_CC0_REGNUM))]
   ""
   "@
    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")])
-\f
-;; CRIS has some add/sub-with-sign/zero-extend instructions.
-;;  Although these perform sign/zero-extension to SImode, they are
-;; equally applicable for the HImode case.
-;; FIXME: Check; GCC should handle the widening.
-;;  Note that these must be located after the normal add/sub patterns,
-;; so not to get constants into any less specific operands.
-;;
-;; Extend with add/sub and side-effect.
-;;
-;; ADDS/SUBS/ADDU/SUBU and BOUND, which needs a check for zero_extend
-;;
-;; adds/subs/addu/subu bound [rx=ry+rz.S]
-
-;; QImode to HImode
-;; FIXME: GCC should widen.
-
-(define_insn "*extopqihi_side_biap"
-  [(set (match_operand:HI 0 "register_operand" "=r,r")
-       (match_operator:HI
-        6 "cris_additive_operand_extend_operator"
-        [(match_operand:HI 1 "register_operand" "0,0")
-         (match_operator:HI
-          7 "cris_extend_operator"
-          [(mem:QI (plus:SI
-                    (mult:SI (match_operand:SI 2 "register_operand" "r,r")
-                             (match_operand:SI 3 "const_int_operand" "n,n"))
-                    (match_operand:SI 4 "register_operand" "r,r")))])]))
-   (set (match_operand:SI 5 "register_operand" "=*4,r")
-       (plus:SI (mult:SI (match_dup 2)
-                         (match_dup 3))
-                (match_dup 4)))]
-  "cris_side_effect_mode_ok (MULT, operands, 5, 4, 2, 3, 0)"
-  "@
-   #
-   %x6%e7.%m7 [%5=%4+%2%T3],%0")
-
-(define_insn "*extop<mode>si_side_biap"
-  [(set (match_operand:SI 0 "register_operand" "=r,r")
-       (match_operator:SI
-        6 "cris_operand_extend_operator"
-        [(match_operand:SI 1 "register_operand" "0,0")
-         (match_operator:SI
-          7 "cris_extend_operator"
-          [(mem:BW (plus:SI
-                    (mult:SI (match_operand:SI 2 "register_operand" "r,r")
-                             (match_operand:SI 3 "const_int_operand" "n,n"))
-                    (match_operand:SI 4 "register_operand" "r,r")))])]))
-   (set (match_operand:SI 5 "register_operand" "=*4,r")
-       (plus:SI (mult:SI (match_dup 2)
-                         (match_dup 3))
-                (match_dup 4)))]
-  "(GET_CODE (operands[6]) != UMIN || GET_CODE (operands[7]) == ZERO_EXTEND)
-   && cris_side_effect_mode_ok (MULT, operands, 5, 4, 2, 3, 0)"
-  "@
-   #
-   %x6%e7<m> [%5=%4+%2%T3],%0")
-\f
-
-;; [rx=ry+i]
-
-;; QImode to HImode
-
-(define_insn "*extopqihi_side"
-  [(set (match_operand:HI 0 "register_operand" "=r,r,r,r,r")
-       (match_operator:HI
-        5 "cris_additive_operand_extend_operator"
-        [(match_operand:HI 1 "register_operand" "0,0,0,0,0")
-         (match_operator:HI
-          6 "cris_extend_operator"
-          [(mem:QI
-            (plus:SI (match_operand:SI 2 "cris_bdap_operand" "%r,r,r,R,R")
-                     (match_operand:SI 3 "cris_bdap_operand" "r>Rn,r,>Rn,r,r")
-                     ))])]))
-   (set (match_operand:SI 4 "register_operand" "=*2,r,r,*3,r")
-       (plus:SI (match_dup 2)
-                (match_dup 3)))]
-  "cris_side_effect_mode_ok (PLUS, operands, 4, 2, 3, -1, 0)"
-{
-  if ((which_alternative == 0 || which_alternative == 3)
-      && (GET_CODE (operands[3]) != CONST_INT
-         || INTVAL (operands[3]) > 127
-         || INTVAL (operands[3]) < -128
-         || CONST_OK_FOR_LETTER_P (INTVAL (operands[3]), 'N')
-         || CONST_OK_FOR_LETTER_P (INTVAL (operands[3]), 'J')))
-    return "#";
-  if (which_alternative == 4)
-    return "%x5%E6.%m6 [%4=%3%S2],%0";
-  return "%x5%E6.%m6 [%4=%2%S3],%0";
-})
-
-(define_insn "*extop<mode>si_side"
-  [(set (match_operand:SI 0 "register_operand" "=r,r,r,r,r")
-       (match_operator:SI
-        5 "cris_operand_extend_operator"
-        [(match_operand:SI 1 "register_operand" "0,0,0,0,0")
-         (match_operator:SI
-          6 "cris_extend_operator"
-          [(mem:BW
-            (plus:SI (match_operand:SI 2 "cris_bdap_operand" "%r,r,r,R,R")
-                     (match_operand:SI 3 "cris_bdap_operand" "r>Rn,r,>Rn,r,r")
-                     ))])]))
-   (set (match_operand:SI 4 "register_operand" "=*2,r,r,*3,r")
-       (plus:SI (match_dup 2)
-                (match_dup 3)))]
-  "(GET_CODE (operands[5]) != UMIN || GET_CODE (operands[6]) == ZERO_EXTEND)
-   && cris_side_effect_mode_ok (PLUS, operands, 4, 2, 3, -1, 0)"
-{
-  if ((which_alternative == 0 || which_alternative == 3)
-      && (GET_CODE (operands[3]) != CONST_INT
-         || INTVAL (operands[3]) > 127
-         || INTVAL (operands[3]) < -128
-         || CONST_OK_FOR_LETTER_P (INTVAL (operands[3]), 'N')
-         || CONST_OK_FOR_LETTER_P (INTVAL (operands[3]), 'J')))
-    return "#";
-  if (which_alternative == 4)
-    return "%x5%E6<m> [%4=%3%S2],%0";
-  return "%x5%E6<m> [%4=%2%S3],%0";
-})
-\f
-
-;; As with op.S we may have to add special pattern to match commuted
-;; operands to adds/addu  and bound
-;;
-;; adds/addu/bound [rx=ry+rz.S]
-
-;; QImode to HImode
-;; FIXME: GCC should widen.
-
-(define_insn "*extopqihi_swap_side_biap"
-  [(set (match_operand:HI 0 "register_operand" "=r,r")
-       (plus:HI
-        (match_operator:HI
-         6 "cris_extend_operator"
-         [(mem:QI (plus:SI
-                   (mult:SI (match_operand:SI 2 "register_operand" "r,r")
-                            (match_operand:SI 3 "const_int_operand" "n,n"))
-                   (match_operand:SI 4 "register_operand" "r,r")))])
-        (match_operand:HI 1 "register_operand" "0,0")))
-   (set (match_operand:SI 5 "register_operand" "=*4,r")
-       (plus:SI (mult:SI (match_dup 2)
-                         (match_dup 3))
-                (match_dup 4)))]
-  "cris_side_effect_mode_ok (MULT, operands, 5, 4, 2, 3, 0)"
-  "@
-   #
-   add%e6.b [%5=%4+%2%T3],%0")
-
-(define_insn "*extop<mode>si_swap_side_biap"
-  [(set (match_operand:SI 0 "register_operand" "=r,r")
-       (match_operator:SI
-        7 "cris_plus_or_bound_operator"
-        [(match_operator:SI
-          6 "cris_extend_operator"
-          [(mem:BW (plus:SI
-                    (mult:SI (match_operand:SI 2 "register_operand" "r,r")
-                             (match_operand:SI 3 "const_int_operand" "n,n"))
-                    (match_operand:SI 4 "register_operand" "r,r")))])
-         (match_operand:SI 1 "register_operand" "0,0")]))
-   (set (match_operand:SI 5 "register_operand" "=*4,r")
-       (plus:SI (mult:SI (match_dup 2)
-                         (match_dup 3))
-                (match_dup 4)))]
-  "(GET_CODE (operands[7]) != UMIN || GET_CODE (operands[6]) == ZERO_EXTEND)
-   && cris_side_effect_mode_ok (MULT, operands, 5, 4, 2, 3, 0)"
-  "@
-   #
-   %x7%E6<m> [%5=%4+%2%T3],%0")
-\f
-;; [rx=ry+i]
-;; FIXME: GCC should widen.
-
-;; QImode to HImode
-
-(define_insn "*extopqihi_swap_side"
-  [(set (match_operand:HI 0 "register_operand" "=r,r,r,r,r")
-       (plus:HI
-        (match_operator:HI
-         5 "cris_extend_operator"
-         [(mem:QI (plus:SI
-                   (match_operand:SI 2 "cris_bdap_operand" "%r,r,r,R,R")
-                   (match_operand:SI 3 "cris_bdap_operand" "r>Rn,r,>Rn,r,r")))])
-        (match_operand:HI 1 "register_operand" "0,0,0,0,0")))
-   (set (match_operand:SI 4 "register_operand" "=*2,r,r,*3,r")
-       (plus:SI (match_dup 2)
-                (match_dup 3)))]
-  "cris_side_effect_mode_ok (PLUS, operands, 4, 2, 3, -1, 0)"
-{
-  if ((which_alternative == 0 || which_alternative == 3)
-      && (GET_CODE (operands[3]) != CONST_INT
-         || INTVAL (operands[3]) > 127
-         || INTVAL (operands[3]) < -128
-         || CONST_OK_FOR_LETTER_P (INTVAL (operands[3]), 'N')
-         || CONST_OK_FOR_LETTER_P (INTVAL (operands[3]), 'J')))
-    return "#";
-  if (which_alternative == 4)
-    return "add%e5.b [%4=%3%S2],%0";
-  return "add%e5.b [%4=%2%S3],%0";
-})
-
-(define_insn "*extop<mode>si_swap_side"
-  [(set (match_operand:SI 0 "register_operand" "=r,r,r,r,r")
-       (match_operator:SI
-        6 "cris_plus_or_bound_operator"
-        [(match_operator:SI
-          5 "cris_extend_operator"
-          [(mem:BW (plus:SI
-                    (match_operand:SI 2 "cris_bdap_operand" "%r,r,r,R,R")
-                    (match_operand:SI 3 "cris_bdap_operand" "r>Rn,r,>Rn,r,r")))])
-         (match_operand:SI 1 "register_operand" "0,0,0,0,0")]))
-   (set (match_operand:SI 4 "register_operand" "=*2,r,r,*3,r")
-       (plus:SI (match_dup 2)
-                (match_dup 3)))]
-  "(GET_CODE (operands[6]) != UMIN || GET_CODE (operands[5]) == ZERO_EXTEND)
-   && cris_side_effect_mode_ok (PLUS, operands, 4, 2, 3, -1, 0)"
-{
-  if ((which_alternative == 0 || which_alternative == 3)
-      && (GET_CODE (operands[3]) != CONST_INT
-         || INTVAL (operands[3]) > 127
-         || INTVAL (operands[3]) < -128
-         || CONST_OK_FOR_LETTER_P (INTVAL (operands[3]), 'N')
-         || CONST_OK_FOR_LETTER_P (INTVAL (operands[3]), 'J')))
-    return "#";
-  if (which_alternative == 4)
-    return \"%x6%E5.%m5 [%4=%3%S2],%0\";
-  return "%x6%E5<m> [%4=%2%S3],%0";
-})
+   (set_attr "cc<ccnz>" "normal,normal,clobber,clobber,normal,normal")])
 \f
 ;; Extend versions (zero/sign) of normal add/sub (no side-effects).
 
 ;; QImode to HImode
 ;; FIXME: GCC should widen.
 
-(define_insn "*extopqihi"
+(define_insn "*<addsub><su>qihi"
   [(set (match_operand:HI 0 "register_operand" "=r,r,r,r")
-       (match_operator:HI
-        3 "cris_additive_operand_extend_operator"
-        [(match_operand:HI 1 "register_operand" "0,0,0,r")
-         (match_operator:HI
-          4 "cris_extend_operator"
-          [(match_operand:QI 2 "nonimmediate_operand" "r,Q>,m,!To")])]))]
+       (plusminus:HI
+        (match_operand:HI 1 "register_operand" "0,0,0,r")
+        (szext:HI (match_operand:QI 2 "nonimmediate_operand" "r,Q>,m,!To"))))
+   (clobber (reg:CC CRIS_CC0_REGNUM))]
   "GET_MODE_SIZE (GET_MODE (operands[0])) <= UNITS_PER_WORD
-   && (operands[1] != frame_pointer_rtx || GET_CODE (operands[3]) != PLUS)"
+   && (operands[1] != frame_pointer_rtx || <plusminus:CODE> != PLUS)"
   "@
-   %x3%E4.%m4 %2,%0
-   %x3%E4.%m4 %2,%0
-   %x3%E4.%m4 %2,%0
-   %x3%E4.%m4 %2,%1,%0"
+   <addsub><su>.b %2,%0
+   <addsub><su>.b %2,%0
+   <addsub><su>.b %2,%0
+   <addsub><su>.b %2,%1,%0"
   [(set_attr "slottable" "yes,yes,no,no")
    (set_attr "cc" "clobber")])
 
-;; QImode to SImode
-
-(define_insn "*extop<mode>si"
+;; FIXME: bound is actually also <setnzvc>, but is so rarely used in this
+;; form that it's not worthwhile to make that distinction.
+(define_insn "*<addsubbo><su><nd><mode>si<setnz>"
   [(set (match_operand:SI 0 "register_operand" "=r,r,r,r")
-       (match_operator:SI
-        3 "cris_operand_extend_operator"
-        [(match_operand:SI 1 "register_operand" "0,0,0,r")
-         (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)
-   && GET_MODE_SIZE (GET_MODE (operands[0])) <= UNITS_PER_WORD
-   && (operands[1] != frame_pointer_rtx || GET_CODE (operands[3]) != PLUS)"
+       (plusminusumin:SI
+        (match_operand:SI 1 "register_operand" "0,0,0,r")
+        (szext:SI (match_operand:BW 2 "nonimmediate_operand" "r,Q>,m,!To"))))
+   (clobber (reg:CC CRIS_CC0_REGNUM))]
+  "(<plusminusumin:CODE> != UMIN || <szext:CODE> == ZERO_EXTEND)
+   && (operands[1] != frame_pointer_rtx || <plusminusumin:CODE> != PLUS)"
   "@
-   %x3%E4<m> %2,%0
-   %x3%E4<m> %2,%0
-   %x3%E4<m> %2,%0
-   %x3%E4<m> %2,%1,%0"
+   <addsubbo><su><nd><m> %2,%0
+   <addsubbo><su><nd><m> %2,%0
+   <addsubbo><su><nd><m> %2,%0
+   <addsubbo><su><nd><m> %2,%1,%0"
   [(set_attr "slottable" "yes,yes,no,no")])
 \f
-
-;; As with the side-effect patterns, may have to have swapped operands for add.
-;; FIXME: *should* be redundant to gcc.
+;; We may have swapped operands for add or bound.
+;; For commutative operands, these are the canonical forms.
 
 ;; QImode to HImode
 
-(define_insn "*extopqihi_swap"
+(define_insn "*add<su>qihi_swap"
   [(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")))]
+        (szext:HI (match_operand:QI 2 "nonimmediate_operand" "r,Q>,m,!To"))
+        (match_operand:HI 1 "register_operand" "0,0,0,r")))
+   (clobber (reg:CC CRIS_CC0_REGNUM))]
   "operands[1] != frame_pointer_rtx"
   "@
-   add%e3.b %2,%0
-   add%e3.b %2,%0
-   add%e3.b %2,%0
-   add%e3.b %2,%1,%0"
+   add<su>.b %2,%0
+   add<su>.b %2,%0
+   add<su>.b %2,%0
+   add<su>.b %2,%1,%0"
   [(set_attr "slottable" "yes,yes,no,no")
    (set_attr "cc" "clobber")])
 
-(define_insn "*extop<mode>si_swap"
+(define_insn "*<addsubbo><su><nd><mode>si<setnz>_swap"
   [(set (match_operand:SI 0 "register_operand" "=r,r,r,r")
-       (match_operator:SI
-        4 "cris_plus_or_bound_operator"
-        [(match_operator:SI
-          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)
+       (plusumin:SI
+        (szext:SI (match_operand:BW 2 "nonimmediate_operand" "r,Q>,m,!To"))
+        (match_operand:SI 1 "register_operand" "0,0,0,r")))
+   (clobber (reg:CC CRIS_CC0_REGNUM))]
+  "(<plusumin:CODE> != UMIN || <szext:CODE> == ZERO_EXTEND)
    && operands[1] != frame_pointer_rtx"
   "@
-   %x4%E3<m> %2,%0
-   %x4%E3<m> %2,%0
-   %x4%E3<m> %2,%0
-   %x4%E3<m> %2,%1,%0"
+   <addsubbo><su><nd><m> %2,%0
+   <addsubbo><su><nd><m> %2,%0
+   <addsubbo><su><nd><m> %2,%0
+   <addsubbo><su><nd><m> %2,%1,%0"
   [(set_attr "slottable" "yes,yes,no,no")])
 \f
 ;; This is the special case when we use what corresponds to the
                             (pc))))
                  (pc))
         (label_ref (match_operand 2 "" ""))))
-   (use (label_ref (match_operand 3 "" "")))]
-
+   (use (label_ref (match_operand 3 "" "")))
+   (clobber (reg:CC CRIS_CC0_REGNUM))]
   "operands[0] != frame_pointer_rtx"
-
   "adds.w [$pc+%0.w],$pc"
   [(set_attr "cc" "clobber")])
 \f
   [(set (match_operand:SI 0 "register_operand" "=r")
        (mult:SI
         (match_operand:SI 1 "register_operand" "%0")
-        (match_operand:SI 2 "const_int_operand" "n")))]
+        (match_operand:SI 2 "const_int_operand" "n")))
+   (clobber (reg:CC CRIS_CC0_REGNUM))]
   "operands[0] != frame_pointer_rtx
    && operands[1] != frame_pointer_rtx
-   && GET_CODE (operands[2]) == CONST_INT
+   && CONST_INT_P (operands[2])
    && (INTVAL (operands[2]) == 2
        || INTVAL (operands[2]) == 4 || INTVAL (operands[2]) == 3
        || INTVAL (operands[2]) == 5)"
 (define_insn "*addi"
   [(set (match_operand:SI 0 "register_operand" "=r")
        (plus:SI
-        (mult:SI (match_operand:SI 2 "register_operand" "r")
-                 (match_operand:SI 3 "const_int_operand" "n"))
+        (ashift:SI (match_operand:SI 2 "register_operand" "r")
+                   (match_operand:SI 3 "const_int_operand" "n"))
         (match_operand:SI 1 "register_operand" "0")))]
   "operands[0] != frame_pointer_rtx
    && operands[1] != frame_pointer_rtx
-   && GET_CODE (operands[3]) == CONST_INT
-   && (INTVAL (operands[3]) == 1
-       || INTVAL (operands[3]) == 2 || INTVAL (operands[3]) == 4)"
+   && CONST_INT_P (operands[3])
+   && (INTVAL (operands[3]) == 1 || INTVAL (operands[3]) == 2)"
   "addi %2%T3,%0"
   [(set_attr "slottable" "yes")
    (set_attr "cc" "none")])
 
-;; The mstep instruction.  Probably not useful by itself; it's to
-;; non-linear wrt. the other insns.  We used to expand to it, so at least
-;; it's correct.
-
-(define_insn "mstep_shift"
+;; The mult-vs-ashift canonicalization-cleanup plagues us: nothing in
+;; reload transforms a "scaled multiplication" into an ashift in a
+;; reloaded address; it's passed as-is and expected to be recognized,
+;; or else we get a tell-tale "unrecognizable insn".
+;; On top of that, we *should* match the bare insn, as a *matching
+;; pattern* (as opposed to e.g. a reload_load_address expander
+;; changing the mul into an ashift), so can_reload_into will re-use
+;; registers in the reloaded expression instead of allocating a new
+;; register.
+(define_insn_and_split "*addi_reload"
   [(set (match_operand:SI 0 "register_operand" "=r")
-       (if_then_else:SI
-        (lt:SI (cc0) (const_int 0))
-        (plus:SI (ashift:SI (match_operand:SI 1 "register_operand" "0")
-                            (const_int 1))
-                 (match_operand:SI 2 "register_operand" "r"))
-        (ashift:SI (match_operand:SI 3 "register_operand" "0")
-                   (const_int 1))))]
+       (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")))]
+  "operands[0] != frame_pointer_rtx
+   && operands[1] != frame_pointer_rtx
+   && CONST_INT_P (operands[3])
+   && (INTVAL (operands[3]) == 2 || INTVAL (operands[3]) == 4)
+   && (lra_in_progress || reload_completed)"
+  "#"
+  "&& 1"
+  [(set (match_dup 0)
+       (plus:SI (ashift:SI (match_dup 2) (match_dup 3)) (match_dup 1)))]
+  "operands[3] = operands[3] == const2_rtx ? const1_rtx : const2_rtx;")
+
+;; This pattern is usually generated after reload, so a '%' is
+;; ineffective; use explicit combinations.
+(define_insn "*addi_b_<mode>"
+  [(set (match_operand:BWD 0 "register_operand" "=r,r")
+       (plus:BWD
+        (match_operand:BWD 1 "register_operand" "0,r")
+        (match_operand:BWD 2 "register_operand" "r,0")))]
   ""
-  "mstep %2,%0"
+  "@
+   addi %2.b,%0
+   addi %1.b,%0"
   [(set_attr "slottable" "yes")])
 
-;; When illegitimate addresses are legitimized, sometimes gcc forgets
-;; to canonicalize the multiplications.
-;;
-;; FIXME: Check gcc > 2.7.2, remove and possibly fix in gcc.
+;; Strip the dccr clobber from addM3 with register operands, if the
+;; next instruction isn't using it.
+;; Not clobbering dccr may let cmpelim match a later compare with a
+;; previous operation of interest.  This has to run before cmpelim so it
+;; can't be a peephole2.  See gcc.target/cris/pr93372-45.c for a
+;; test-case.
+(define_split ;; "*add<mode>3_addi"
+  [(parallel
+    [(set (match_operand:BWD 0 "register_operand")
+         (plus:BWD
+          (match_operand:BWD 1 "register_operand")
+          (match_operand:BWD 2 "register_operand")))
+     (clobber (reg:CC CRIS_CC0_REGNUM))])]
+  "reload_completed"
+  [(set (match_dup 0) (plus:BWD (match_dup 1) (match_dup 2)))]
+{
+  rtx reg = operands[0];
+  rtx_insn *i = next_nonnote_nondebug_insn_bb (curr_insn);
+  rtx x, src, dest;
+
+  while (i != NULL_RTX && (!INSN_P (i) || DEBUG_INSN_P (i)))
+    i = next_nonnote_nondebug_insn_bb (i);
+
+  /* We don't want to strip the clobber if the next insn possibly uses the
+     zeroness of the result.  Preferably fail only if we see a compare insn
+     that looks eliminable and with the register "reg" compared.  With some
+     effort we could also check for an equality test (EQ, NE) in the post-split
+     user, just not for now.  */
+  if (i == NULL_RTX)
+    FAIL;
+
+  x = single_set (i);
+
+  /* We explicitly need to bail on a BARRIER, but that's implied by a failing
+     single_set test.  */
+  if (x == NULL_RTX)
+    FAIL;
+
+  src = SET_SRC (x);
+  dest = SET_DEST (x);
+
+  /* Bail on (post-split) eliminable compares.  */
+  if (REG_P (dest) && REGNO (dest) == CRIS_CC0_REGNUM
+      && GET_CODE (src) == COMPARE)
+    {
+      rtx cop0 = XEXP (src, 0);
 
-(define_insn "mstep_mul"
-  [(set (match_operand:SI 0 "register_operand" "=r")
-       (if_then_else:SI
-        (lt:SI (cc0) (const_int 0))
-        (plus:SI (mult:SI (match_operand:SI 1 "register_operand" "0")
-                          (const_int 2))
-                 (match_operand:SI 2 "register_operand" "r"))
-        (mult:SI (match_operand:SI 3 "register_operand" "0")
-                 (const_int 2))))]
-  "operands[0] != frame_pointer_rtx
-   && operands[1] != frame_pointer_rtx
-   && operands[2] != frame_pointer_rtx
-   && operands[3] != frame_pointer_rtx"
-  "mstep %2,%0"
-  [(set_attr "slottable" "yes")])
+      if (REG_P (cop0) && REGNO (cop0) == REGNO (reg)
+         && XEXP (src, 1) == const0_rtx)
+       FAIL;
+    }
+
+  /* Bail out if we see a (pre-split) cbranch or cstore where the comparison
+     looks eliminable and uses the destination register in this addition.  We
+     don't need to look very deep: a single_set which is a parallel clobbers
+     something, and (one of) that something, is always CRIS_CC0_REGNUM here.
+     Also, the entities we're looking for are two-element parallels.  A
+     split-up cbranch or cstore doesn't clobber CRIS_CC0_REGNUM.  A cbranch has
+     if_then_else as its source with a comparison operator as the condition,
+     and a cstore has a source with the comparison operator directly.  That
+     also matches dstep, so look for pc as destination for the if_then_else.
+     We error on the safe side if we happen to catch other conditional entities
+     and FAIL, that just means the split won't happen.  */
+  if (GET_CODE (PATTERN (i)) == PARALLEL && XVECLEN (PATTERN (i), 0) == 2)
+    {
+      rtx cmp
+       = (GET_CODE (src) == IF_THEN_ELSE && dest == pc_rtx
+          ? XEXP (src, 0)
+          : (COMPARISON_P (src) ? src : NULL_RTX));
+      gcc_assert (cmp == NULL_RTX || COMPARISON_P (cmp));
+
+      if (cmp && REG_P (XEXP (cmp, 0)) && XEXP (cmp, 1) == const0_rtx
+         && REGNO (XEXP (cmp, 0)) == REGNO (reg))
+       FAIL;
+    }
+})
 
 (define_insn "<u>mul<s><mode>3"
   [(set (match_operand:WD 0 "register_operand" "=r")
        (mult:WD
         (szext:WD (match_operand:<S> 1 "register_operand" "%0"))
         (szext:WD (match_operand:<S> 2 "register_operand" "r"))))
-   (clobber (match_scratch:SI 3 "=h"))]
+   (clobber (match_scratch:SI 3 "=h"))
+   (clobber (reg:CC CRIS_CC0_REGNUM))]
   "TARGET_HAS_MUL_INSNS"
   "%!mul<su><mm> %2,%0"
   [(set (attr "slottable")
-       (if_then_else (ne (symbol_ref "TARGET_MUL_BUG") (const_int 0))
+       (if_then_else (match_test "TARGET_MUL_BUG")
                      (const_string "no")
                      (const_string "yes")))
    ;; For umuls.[bwd] it's just N unusable here, but let's be safe.
   [(set (match_operand:SI 0 "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"))]
+   (clobber (match_scratch:SI 3 "=h"))
+   (clobber (reg:CC CRIS_CC0_REGNUM))]
   "TARGET_HAS_MUL_INSNS"
   "%!muls.d %2,%0"
   [(set (attr "slottable")
-       (if_then_else (ne (symbol_ref "TARGET_MUL_BUG") (const_int 0))
+       (if_then_else (match_test "TARGET_MUL_BUG")
                      (const_string "no")
                      (const_string "yes")))
    ;; Just N unusable here, but let's be safe.
 
 ;; When needed, we can get the high 32 bits from the overflow
 ;; register.  We don't care to split and optimize these.
-;;
-;; Note that cc0 is still valid after the move-from-overflow-register
-;; insn; no special precaution need to be taken in cris_notice_update_cc.
 
 (define_insn "<u>mulsidi3"
   [(set (match_operand:DI 0 "register_operand" "=r")
        (mult:DI
         (szext:DI (match_operand:SI 1 "register_operand" "%0"))
         (szext:DI (match_operand:SI 2 "register_operand" "r"))))
-   (clobber (match_scratch:SI 3 "=h"))]
+   (clobber (match_scratch:SI 3 "=h"))
+   (clobber (reg:CC CRIS_CC0_REGNUM))]
   "TARGET_HAS_MUL_INSNS"
   "%!mul<su>.d %2,%M0\;move $mof,%H0")
 
 ;; 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
           (szext:DI (match_operand:SI 1 "register_operand" "r,r,0,r"))
           (szext:DI (match_operand:SI 2 "register_operand" "r,r,r,0")))
          (const_int 32))))
-   (clobber (match_scratch:SI 3 "=1,2,h,h"))]
+   (clobber (match_scratch:SI 3 "=1,2,h,h"))
+   (clobber (reg:CC CRIS_CC0_REGNUM))]
   "TARGET_HAS_MUL_INSNS"
   "@
    %!mul<su>.d %2,%1
                        (const_int 1))
                   (match_operand:SI 4 "register_operand" "2"))
         (ashift:SI (match_operand:SI 5 "register_operand" "0")
-                       (const_int 1))))]
+                       (const_int 1))))
+   (clobber (reg:CC CRIS_CC0_REGNUM))]
   ""
   "dstep %2,%0"
   [(set_attr "slottable" "yes")])
                            (const_int 2))
                   (match_operand:SI 4 "register_operand" "2"))
         (mult:SI (match_operand:SI 5 "register_operand" "0")
-                 (const_int 2))))]
+                 (const_int 2))))
+   (clobber (reg:CC CRIS_CC0_REGNUM))]
   "operands[0] != frame_pointer_rtx
    && operands[1] != frame_pointer_rtx
    && operands[2] != frame_pointer_rtx
 ;; FIXME: This should be made obsolete.
 
 (define_expand "andsi3"
-  [(set (match_operand:SI 0 "nonimmediate_operand"        "")
-       (and:SI (match_operand:SI 1 "nonimmediate_operand" "")
-               (match_operand:SI 2 "general_operand"    "")))]
+  [(parallel
+    [(set (match_operand:SI 0 "nonimmediate_operand")
+         (and:SI (match_operand:SI 1 "nonimmediate_operand")
+                 (match_operand:SI 2 "general_operand")))
+     (clobber (reg:CC CRIS_CC0_REGNUM))])]
   ""
 {
-  if (! (GET_CODE (operands[2]) == CONST_INT
+  if (! (CONST_INT_P (operands[2])
         && (((INTVAL (operands[2]) == -256
               || INTVAL (operands[2]) == -65536)
              && rtx_equal_p (operands[1], operands[0]))
          reg1 = reg0;
        }
 
-      emit_insn (gen_rtx_SET (SImode, reg0,
-                         gen_rtx_AND (SImode, reg1, operands[2])));
+      cris_emit_insn (gen_rtx_SET (reg0, gen_rtx_AND (SImode, reg1,
+                                                     operands[2])));
 
       /* Make sure we get the right *final* destination.  */
       if (! REG_P (operands[0]))
 (define_insn "*andsi_movu"
   [(set (match_operand:SI 0 "register_operand" "=r,r,r")
        (and:SI (match_operand:SI 1 "nonimmediate_operand" "%r,Q,To")
-               (match_operand:SI 2 "const_int_operand" "n,n,n")))]
+               (match_operand:SI 2 "const_int_operand" "n,n,n")))
+   (clobber (reg:CC CRIS_CC0_REGNUM))]
   "(INTVAL (operands[2]) == 255 || INTVAL (operands[2]) == 65535)
-   && (GET_CODE (operands[1]) != MEM || ! MEM_VOLATILE_P (operands[1]))"
+   && !side_effects_p (operands[1])"
   "movu.%z2 %1,%0"
   [(set_attr "slottable" "yes,yes,no")])
 
+;; FIXME: Remember, this does *not* actually affect condition codes;
+;; get rid of the clobber.
 (define_insn "*andsi_clear"
   [(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")))]
+               (match_operand:SI 2 "const_int_operand" "P,n,P,n,P,n")))
+   (clobber (reg:CC CRIS_CC0_REGNUM))]
   "(INTVAL (operands[2]) == -65536 || INTVAL (operands[2]) == -256)
-   && (GET_CODE (operands[0]) != MEM || ! MEM_VOLATILE_P (operands[0]))"
+   && !side_effects_p (operands[0])"
   "@
    cLear.b %0
    cLear.w %0
 ;; pressure (worse code).  That will hopefully change with an
 ;; improved reload pass.
 
-(define_insn "*expanded_andsi"
+(define_insn "*expanded_andsi<setcc><setnz><setnzvc>"
   [(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")))]
+               (match_operand:SI 2 "general_operand"   "I,r,Q>,g,!To")))
+   (clobber (reg:CC CRIS_CC0_REGNUM))]
   ""
   "@
    andq %2,%0
 \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
-;; normally be a win (could check ahead for use of cc0, but seems to be
-;; more pain than win).
+;; normally be a win (could check ahead for use of CRIS_CC0_REGNUM, but
+;; seems to be more pain than win).
 
 ;; FIXME: See note for andsi3
 
 (define_expand "andhi3"
-  [(set (match_operand:HI 0 "nonimmediate_operand" "")
-       (and:HI (match_operand:HI 1 "nonimmediate_operand" "")
-               (match_operand:HI 2 "general_operand"  "")))]
+  [(parallel
+    [(set (match_operand:HI 0 "nonimmediate_operand")
+       (and:HI (match_operand:HI 1 "nonimmediate_operand")
+               (match_operand:HI 2 "general_operand")))
+     (clobber (reg:CC CRIS_CC0_REGNUM))])]
   ""
 {
-  if (! (GET_CODE (operands[2]) == CONST_INT
+  if (! (CONST_INT_P (operands[2])
         && (((INTVAL (operands[2]) == -256
               || INTVAL (operands[2]) == 65280)
              && rtx_equal_p (operands[1], operands[0]))
          reg1 = reg0;
        }
 
-      emit_insn (gen_rtx_SET (HImode, reg0,
-                         gen_rtx_AND (HImode, reg1, operands[2])));
+      cris_emit_insn (gen_rtx_SET (reg0, gen_rtx_AND (HImode, reg1,
+                                                     operands[2])));
 
       /* Make sure we get the right destination.  */
       if (! REG_P (operands[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,To")
-               (const_int 255)))]
-  "GET_CODE (operands[1]) != MEM || ! MEM_VOLATILE_P (operands[1])"
+               (const_int 255)))
+   (clobber (reg:CC CRIS_CC0_REGNUM))]
+  "!side_effects_p (operands[1])"
   "mOvu.b %1,%0"
   [(set_attr "slottable" "yes,yes,no")])
 
 (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)))]
-  "GET_CODE (operands[0]) != MEM || ! MEM_VOLATILE_P (operands[0])"
+               (const_int -256)))
+   (clobber (reg:CC CRIS_CC0_REGNUM))]
+  "!side_effects_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")))]
+(define_insn "*expanded_andhi<setcc><setnz><setnzvc>"
+  [(set (match_operand:HI 0 "register_operand"        "=r,r, r,r, r,r,r,r")
+       (and:HI (match_operand:HI 1 "register_operand" "%0,0, 0,0, 0,0,0,r")
+               (match_operand:HI 2 "general_operand"   "I,Kc,r,Q>,L,O,g,!To")))
+               ;; The "Kc" alternative above, is there to match for cmpelim;
+               ;; it will be dominated by the "I" alternative at other times.
+   (clobber (reg:CC CRIS_CC0_REGNUM))]
 
 ;; Sidenote: the tightening from "general_operand" to
 ;; "register_operand" for operand 1 actually increased the register
 
   ""
   "@
+   andq %2,%0
    andq %2,%0
    and.w %2,%0
    and.w %2,%0
    anDq %b2,%0
    and.w %2,%0
    and.w %2,%1,%0"
-  [(set_attr "slottable" "yes,yes,yes,no,yes,no,no")
-   (set_attr "cc" "clobber,normal,normal,normal,clobber,normal,normal")])
+  [(set_attr "slottable" "yes,yes,yes,yes,no,yes,no,no")
+   (set_attr "cc<cccc><ccnz><ccnzvc>"
+            "clobber,normal,normal,normal,normal,clobber,normal,normal")])
 
 ;; A strict_low_part pattern.
 
+;; Note the use of (match_dup 0) for the first operand of the operation
+;; here.  Reload can't handle an operand pair where one is read-write
+;; and must match a read, like in:
+;; (insn 80 79 81 4
+;;  (set (strict_low_part
+;;        (subreg:QI (reg/v:SI 0 r0 [orig:36 data ] [36]) 0))
+;;       (and:QI
+;;        (subreg:QI (reg:SI 15 acr [orig:27 D.7531 ] [27]) 0)
+;;        (const_int -64 [0xf..fc0]))) x.c:126 147 {*andqi_lowpart_v32}
+;;  (nil))
+;; (Note: the example is obsolete.)
+;; In theory, it could reload this as a movstrictqi of the register
+;; operand at the and:QI to the destination register and change the
+;; and:QI operand to the same as the read-write output operand and the
+;; result would be recognized, but it doesn't recognize that's a valid
+;; reload for a strict_low_part-destination; it just sees a "+" at the
+;; destination constraints.  Better than adding complexity to reload is
+;; to follow the lead of m68k (see comment that begins with "These insns
+;; must use MATCH_DUP") since prehistoric times and make it just a
+;; match_dup.  FIXME: a sanity-check in gen* to refuse an insn with
+;; input-constraints matching input-output-constraints, e.g. "+r" <- "0".
+
 (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"))
+       (and:HI (match_dup 0)
+               (match_operand:HI 1 "general_operand"   "r,Q>,g")))
+   (clobber (reg:CC CRIS_CC0_REGNUM))]
   ""
   "@
-   and.w %2,%0
-   and.w %2,%0
-   and.w %2,%0
-   anDq %b2,%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")])
+   and.w %1,%0
+   and.w %1,%0
+   and.w %1,%0"
+  [(set_attr "slottable" "yes,yes,no")])
 \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")))]
+(define_expand "andqi3"
+  [(parallel
+    [(set (match_operand:QI 0 "register_operand")
+         (and:QI (match_operand:QI 1 "register_operand")
+                 (match_operand:QI 2 "general_operand")))
+     (clobber (reg:CC CRIS_CC0_REGNUM))])]
+  ""
+  "")
+
+(define_insn "*andqi3<setcc><setnz><setnzvc>"
+  [(set (match_operand:QI 0 "register_operand"        "=r,r, r,r, r,r,r")
+       (and:QI (match_operand:QI 1 "register_operand" "%0,0, 0,0, 0,0,r")
+               (match_operand:QI 2 "general_operand"   "I,Kc,r,Q>,O,g,!To")))
+   (clobber (reg:CC CRIS_CC0_REGNUM))]
   ""
   "@
+   andq %2,%0
    andq %2,%0
    and.b %2,%0
    and.b %2,%0
    andQ %b2,%0
    and.b %2,%0
    and.b %2,%1,%0"
-  [(set_attr "slottable" "yes,yes,yes,yes,no,no")
-   (set_attr "cc" "clobber,normal,normal,clobber,normal,normal")])
+  [(set_attr "slottable" "yes,yes,yes,yes,yes,no,no")
+   (set_attr "cc<cccc><ccnz><ccnzvc>"
+            "clobber,normal,normal,normal,clobber,normal,normal")])
 
 (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"))
+       (and:QI (match_dup 0)
+               (match_operand:QI 1 "general_operand"   "r,Q>,g")))
+   (clobber (reg:CC CRIS_CC0_REGNUM))]
   ""
   "@
-   and.b %2,%0
-   and.b %2,%0
-   andQ %b2,%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")])
+   and.b %1,%0
+   and.b %1,%0
+   and.b %1,%0"
+  [(set_attr "slottable" "yes,yes,no")])
 \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"
+  [(parallel
+    [(set (match_operand:BWD 0 "register_operand")
+         (ior:BWD (match_operand:BWD 1 "register_operand")
+                  (match_operand:BWD 2 "general_operand")))
+     (clobber (reg:CC CRIS_CC0_REGNUM))])]
+  ""
+  "")
+
+(define_insn "*iorsi3<setcc><setnz><setnzvc>"
   [(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")))]
+               (match_operand:SI 2 "general_operand"  "I, r,Q>,n,g,!To")))
+   (clobber (reg:CC CRIS_CC0_REGNUM))]
   ""
   "@
    orq %2,%0
    or.d %2,%0
    or.d %2,%1,%0"
   [(set_attr "slottable" "yes,yes,yes,no,no,no")
-   (set_attr "cc" "normal,normal,normal,clobber,normal,normal")])
+   (set_attr "cc<cccc><ccnz><ccnzvc>"
+            "normal,normal,normal,clobber,normal,normal")])
 
-(define_insn "iorhi3"
+(define_insn "*iorhi3<setcc><setnz><setnzvc>"
   [(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")))]
+               (match_operand:HI 2 "general_operand"   "I,r,Q>,L,O,g,!To")))
+   (clobber (reg:CC CRIS_CC0_REGNUM))]
   ""
   "@
    orq %2,%0
    or.w %2,%0
    or.w %2,%1,%0"
   [(set_attr "slottable" "yes,yes,yes,no,yes,no,no")
-   (set_attr "cc" "clobber,normal,normal,normal,clobber,normal,normal")])
+   (set_attr "cc<cccc><ccnz><ccnzvc>"
+            "clobber,normal,normal,normal,clobber,normal,normal")])
 
-(define_insn "iorqi3"
+(define_insn "*iorqi3<setcc><setnz><setnzvc>"
   [(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")))]
+               (match_operand:QI 2 "general_operand"   "I,r,Q>,O,g,!To")))
+   (clobber (reg:CC CRIS_CC0_REGNUM))]
   ""
   "@
    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")])
+   (set_attr "cc<cccc><ccnz><ccnzvc>"
+            "clobber,normal,normal,clobber,normal,normal")])
 \f
 ;; Exclusive-or
 
 ;; See comment about "anddi3" for xordi3 - no need for such a pattern.
 ;; FIXME: Do we really need the shorter variants?
 
-(define_insn "xorsi3"
+(define_insn "<acc><anz><anzvc>xorsi3<setcc><setnz><setnzvc>"
   [(set (match_operand:SI 0 "register_operand" "=r")
        (xor:SI (match_operand:SI 1 "register_operand" "%0")
-               (match_operand:SI 2 "register_operand" "r")))]
+               (match_operand:SI 2 "register_operand" "r")))
+   (clobber (reg:CC CRIS_CC0_REGNUM))]
   ""
   "xor %2,%0"
   [(set_attr "slottable" "yes")])
 (define_insn "xor<mode>3"
   [(set (match_operand:BW 0 "register_operand" "=r")
        (xor:BW (match_operand:BW 1 "register_operand" "%0")
-               (match_operand:BW 2 "register_operand" "r")))]
+               (match_operand:BW 2 "register_operand" "r")))
+   (clobber (reg:CC CRIS_CC0_REGNUM))]
   ""
   "xor %2,%0"
   [(set_attr "slottable" "yes")
 ;; example.
 
 (define_expand "negsf2"
-  [(set (match_dup 2)
-        (match_dup 3))
-   (parallel [(set (match_operand:SF 0 "register_operand" "=r")
-                   (neg:SF (match_operand:SF 1
-                            "register_operand" "0")))
-              (use (match_dup 2))])]
+  [(parallel
+    [(set (match_dup 2) (match_dup 3))
+     (clobber (reg:CC CRIS_CC0_REGNUM))])
+   (parallel [(set (match_operand:SF 0 "register_operand")
+                  (neg:SF (match_operand:SF 1 "register_operand")))
+             (use (match_dup 2))
+             (clobber (reg:CC CRIS_CC0_REGNUM))])]
   ""
 {
   operands[2] = gen_reg_rtx (SImode);
 (define_insn "*expanded_negsf2"
   [(set (match_operand:SF 0 "register_operand" "=r")
        (neg:SF (match_operand:SF 1 "register_operand" "0")))
-   (use (match_operand:SI 2 "register_operand" "r"))]
+   (use (match_operand:SI 2 "register_operand" "r"))
+   (clobber (reg:CC CRIS_CC0_REGNUM))]
   ""
   "xor %2,%0"
   [(set_attr "slottable" "yes")])
 ;; No "negdi2" although we could make one up that may be faster than
 ;; the one in libgcc.
 
-(define_insn "neg<mode>2"
+(define_insn "<anz>neg<mode>2<setnz>"
   [(set (match_operand:BWD 0 "register_operand" "=r")
-       (neg:BWD (match_operand:BWD 1 "register_operand" "r")))]
+       (neg:BWD (match_operand:BWD 1 "register_operand" "r")))
+   (clobber (reg:CC CRIS_CC0_REGNUM))]
   ""
   "neg<m> %1,%0"
   [(set_attr "slottable" "yes")])
 ;; See comment on anddi3 - no need for a DImode pattern.
 ;; See also xor comment.
 
-(define_insn "one_cmplsi2"
+(define_insn "<acc><anz><anzvc>one_cmplsi2<setcc><setnz><setnzvc>"
   [(set (match_operand:SI 0 "register_operand" "=r")
-       (not:SI (match_operand:SI 1 "register_operand" "0")))]
+       (not:SI (match_operand:SI 1 "register_operand" "0")))
+   (clobber (reg:CC CRIS_CC0_REGNUM))]
   ""
   "not %0"
   [(set_attr "slottable" "yes")])
 
 (define_insn "one_cmpl<mode>2"
   [(set (match_operand:BW 0 "register_operand" "=r")
-       (not:BW (match_operand:BW 1 "register_operand" "0")))]
+       (not:BW (match_operand:BW 1 "register_operand" "0")))
+   (clobber (reg:CC CRIS_CC0_REGNUM))]
   ""
   "not %0"
   [(set_attr "slottable" "yes")
 \f
 ;; Arithmetic/Logical shift right (and SI left).
 
-(define_insn "<shlr>si3"
+(define_insn "<acc><anz><anzvc><shlr>si3<setcc><setnz><setnzvc>"
   [(set (match_operand:SI 0 "register_operand" "=r")
        (shift:SI (match_operand:SI 1 "register_operand" "0")
-                 (match_operand:SI 2 "nonmemory_operand" "Kr")))]
+                 (match_operand:SI 2 "nonmemory_operand" "Kcr")))
+   (clobber (reg:CC CRIS_CC0_REGNUM))]
   ""
 {
   if (REG_S_P (operands[2]))
 ;; FIXME: Can't parametrize sign_extend and zero_extend (before
 ;; mentioning "shiftrt"), so we need two patterns.
 (define_expand "ashr<mode>3"
-  [(set (match_dup 3)
-       (sign_extend:SI (match_operand:BW 1 "nonimmediate_operand" "")))
-   (set (match_dup 4)
-       (zero_extend:SI (match_operand:BW 2 "nonimmediate_operand" "")))
-   (set (match_dup 5) (ashiftrt:SI (match_dup 3) (match_dup 4)))
-   (set (match_operand:BW 0 "general_operand" "")
-       (subreg:BW (match_dup 5) 0))]
+  [(parallel
+    [(set (match_dup 3)
+         (sign_extend:SI (match_operand:BW 1 "nonimmediate_operand")))
+     (clobber (reg:CC CRIS_CC0_REGNUM))])
+   (parallel
+    [(set (match_dup 4)
+         (zero_extend:SI (match_operand:BW 2 "nonimmediate_operand")))
+     (clobber (reg:CC CRIS_CC0_REGNUM))])
+   (parallel
+    [(set (match_dup 5) (ashiftrt:SI (match_dup 3) (match_dup 4)))
+     (clobber (reg:CC CRIS_CC0_REGNUM))])
+   (parallel
+    [(set (match_operand:BW 0 "general_operand")
+         (subreg:BW (match_dup 5) 0))
+     (clobber (reg:CC CRIS_CC0_REGNUM))])]
   ""
 {
   int i;
 })
 
 (define_expand "lshr<mode>3"
-  [(set (match_dup 3)
-       (zero_extend:SI (match_operand:BW 1 "nonimmediate_operand" "")))
-   (set (match_dup 4)
-       (zero_extend:SI (match_operand:BW 2 "nonimmediate_operand" "")))
-   (set (match_dup 5) (lshiftrt:SI (match_dup 3) (match_dup 4)))
-   (set (match_operand:BW 0 "general_operand" "")
-       (subreg:BW (match_dup 5) 0))]
+  [(parallel
+    [(set (match_dup 3)
+         (zero_extend:SI (match_operand:BW 1 "nonimmediate_operand")))
+     (clobber (reg:CC CRIS_CC0_REGNUM))])
+   (parallel
+    [(set (match_dup 4)
+         (zero_extend:SI (match_operand:BW 2 "nonimmediate_operand")))
+     (clobber (reg:CC CRIS_CC0_REGNUM))])
+   (parallel
+    [(set (match_dup 5) (lshiftrt:SI (match_dup 3) (match_dup 4)))
+     (clobber (reg:CC CRIS_CC0_REGNUM))])
+   (parallel
+    [(set (match_operand:BW 0 "general_operand")
+         (subreg:BW (match_dup 5) 0))
+     (clobber (reg:CC CRIS_CC0_REGNUM))])]
   ""
 {
   int i;
 (define_insn "*expanded_<shlr><mode>"
   [(set (match_operand:BW 0 "register_operand" "=r")
        (shiftrt:BW (match_operand:BW 1 "register_operand" "0")
-                   (match_operand:BW 2 "register_operand" "r")))]
+                   (match_operand:BW 2 "register_operand" "r")))
+   (clobber (reg:CC CRIS_CC0_REGNUM))]
   ""
   "<slr><m> %2,%0"
   [(set_attr "slottable" "yes")])
 (define_insn "*<shlr><mode>_lowpart"
   [(set (strict_low_part (match_operand:BW 0 "register_operand" "+r"))
        (shiftrt:BW (match_dup 0)
-                   (match_operand:BW 1 "register_operand" "r")))]
+                   (match_operand:BW 1 "register_operand" "r")))
+   (clobber (reg:CC CRIS_CC0_REGNUM))]
   ""
   "<slr><m> %1,%0"
   [(set_attr "slottable" "yes")])
 (define_insn "ashl<mode>3"
   [(set (match_operand:BW 0 "register_operand" "=r,r")
        (ashift:BW (match_operand:BW 1 "register_operand" "0,0")
-                  (match_operand:BW 2 "nonmemory_operand" "r,K")))]
+                  (match_operand:BW 2 "nonmemory_operand" "r,Kc")))
+   (clobber (reg:CC CRIS_CC0_REGNUM))]
   ""
 {
   return
-    (GET_CODE (operands[2]) == CONST_INT
-     && INTVAL (operands[2]) > <nbitsm1>)
+    (CONST_INT_P (operands[2]) && INTVAL (operands[2]) > <nbitsm1>)
     ? "moveq 0,%0"
     : (CONSTANT_P (operands[2])
        ? "lslq %2,%0" : "lsl<m> %2,%0");
 }
   [(set_attr "slottable" "yes")
-   (set_attr "cc" "normal,clobber")])
+   (set_attr "cc" "*,clobber")])
 
 ;; A strict_low_part matcher.
 
 (define_insn "*ashl<mode>_lowpart"
   [(set (strict_low_part (match_operand:BW 0 "register_operand" "+r"))
        (ashift:BW (match_dup 0)
-                  (match_operand:HI 1 "register_operand" "r")))]
+                  (match_operand:HI 1 "register_operand" "r")))
+   (clobber (reg:CC CRIS_CC0_REGNUM))]
   ""
   "lsl<m> %1,%0"
   [(set_attr "slottable" "yes")])
 
 (define_insn "abssf2"
   [(set (match_operand:SF 0 "register_operand" "=r")
-       (abs:SF (match_operand:SF 1 "register_operand" "0")))]
+       (abs:SF (match_operand:SF 1 "register_operand" "0")))
+   (clobber (reg:CC CRIS_CC0_REGNUM))]
   ""
   "lslq 1,%0\;lsrq 1,%0")
 
 (define_insn "abssi2"
   [(set (match_operand:SI 0 "register_operand" "=r")
-       (abs:SI (match_operand:SI 1 "register_operand" "r")))]
+       (abs:SI (match_operand:SI 1 "register_operand" "r")))
+   (clobber (reg:CC CRIS_CC0_REGNUM))]
   ""
   "abs %1,%0"
   [(set_attr "slottable" "yes")])
 ;; FIXME: GCC should be able to do these expansions itself.
 
 (define_expand "abs<mode>2"
-  [(set (match_dup 2)
-       (sign_extend:SI (match_operand:BW 1 "general_operand" "")))
-   (set (match_dup 3) (abs:SI (match_dup 2)))
-   (set (match_operand:BW 0 "register_operand" "")
-       (subreg:BW (match_dup 3) 0))]
+  [(parallel
+    [(set (match_dup 2)
+         (sign_extend:SI (match_operand:BW 1 "general_operand")))
+     (clobber (reg:CC CRIS_CC0_REGNUM))])
+   (parallel
+    [(set (match_dup 3) (abs:SI (match_dup 2)))
+     (clobber (reg:CC CRIS_CC0_REGNUM))])
+   (parallel
+    [(set (match_operand:BW 0 "register_operand")
+         (subreg:BW (match_dup 3) 0))
+     (clobber (reg:CC CRIS_CC0_REGNUM))])]
   ""
   "operands[2] = gen_reg_rtx (SImode); operands[3] = gen_reg_rtx (SImode);")
-\f
+
+(define_insn "<acc><anz><anzvc>clzsi2<setcc><setnz><setnzvc>"
+  [(set (match_operand:SI 0 "register_operand" "=r")
+       (clz:SI (match_operand:SI 1 "register_operand" "r")))
+   (clobber (reg:CC CRIS_CC0_REGNUM))]
+  "TARGET_HAS_LZ"
+  "lz %1,%0"
+  [(set_attr "slottable" "yes")])
+
+(define_insn "<acc><anz><anzvc>bswapsi2<setcc><setnz><setnzvc>"
+  [(set (match_operand:SI 0 "register_operand" "=r")
+       (bswap:SI (match_operand:SI 1 "register_operand" "0")))
+   (clobber (reg:CC CRIS_CC0_REGNUM))]
+  "TARGET_HAS_SWAP"
+  "swapwb %0"
+  [(set_attr "slottable" "yes")])
+
+;; This instruction swaps all bits in a register.
+;; That means that the most significant bit is put in the place
+;; of the least significant bit, and so on.
+
+(define_insn "cris_swap_bits"
+  [(set (match_operand:SI 0 "register_operand" "=r")
+       (bitreverse:SI (match_operand:SI 1 "register_operand" "0")))
+   (clobber (reg:CC CRIS_CC0_REGNUM))]
+  "TARGET_HAS_SWAP"
+  "swapwbr %0"
+  [(set_attr "slottable" "yes")])
+
+;; Implement ctz using two instructions, one for bit swap and one for clz.
+;; Defines a scratch register to avoid clobbering input.
+
+(define_expand "ctzsi2"
+  [(parallel
+    [(set (match_dup 2)
+         (match_operand:SI 1 "register_operand"))
+     (clobber (reg:CC CRIS_CC0_REGNUM))])
+   (parallel
+    [(set (match_dup 2) (bitreverse:SI (match_dup 2)))
+     (clobber (reg:CC CRIS_CC0_REGNUM))])
+   (parallel
+    [(set (match_operand:SI 0 "register_operand")
+         (clz:SI (match_dup 2)))
+     (clobber (reg:CC CRIS_CC0_REGNUM))])]
+  "TARGET_HAS_LZ && TARGET_HAS_SWAP"
+  "operands[2] = gen_reg_rtx (SImode);")
+
 ;; Bound-insn.  Defined to be the same as an unsigned minimum, which is an
 ;; operation supported by gcc.  Used in casesi, but used now and then in
 ;; normal code too.
 
-(define_insn "uminsi3"
+(define_expand "uminsi3"
+  [(parallel
+    [(set (match_operand:SI 0 "register_operand")
+         (umin:SI  (match_operand:SI 1 "register_operand")
+                   (match_operand:SI 2 "general_operand")))
+     (clobber (reg:CC CRIS_CC0_REGNUM))])]
+  ""
+  "")
+
+(define_insn "*uminsi3<setcc><setnz><setnzvc>"
   [(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")))]
+                 (match_operand:SI 2 "general_operand"   "r,Q>,g,!To")))
+   (clobber (reg:CC CRIS_CC0_REGNUM))]
   ""
 {
-  if (GET_CODE (operands[2]) == CONST_INT)
+  if (CONST_INT_P (operands[2]))
     {
       /* Constant operands are zero-extended, so only 32-bit operands
         may be negative.  */
 ;; 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"
+(define_expand "indirect_jump"
+  [(set (pc) (match_operand:SI 0 "nonimmediate_operand"))]
+  ""
+  "")
+
+(define_insn "*indirect_jump"
   [(set (pc) (match_operand:SI 0 "nonimmediate_operand" "rm"))]
   ""
   "jump %0")
 }
   [(set (attr "slottable")
        (if_then_else
-        (ne (symbol_ref
-             "(cris_return_address_on_stack_for_return ())")
-            (const_int 0))
+        (match_test "cris_return_address_on_stack_for_return ()")
         (const_string "no")
-        (const_string "has_slot")))])
+        (const_string "has_return_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 "cbranch<mode>4"
+  [(parallel
+    [(set (pc)
+         (if_then_else
+          (match_operator 0 "ordered_comparison_operator"
+           [(match_operand:BWDD 1 "nonimmediate_operand")
+            (match_operand:BWDD 2 "general_operand")])
+          (label_ref (match_operand 3 ""))
+          (pc)))
+     (clobber (reg:CC CRIS_CC0_REGNUM))])]
+  ""
+  "cris_reduce_compare (&operands[0], &operands[1], &operands[2]);")
+
+(define_insn_and_split "*cbranch<mode><code>4"
+  [(set (pc)
+       (if_then_else
+        (cond
+         (match_operand:BWDD 0 "nonimmediate_operand" "<cmp_op0c>")
+         (match_operand:BWDD 1 "general_operand" "<cmp_op1c>"))
+        (label_ref (match_operand 2 ""))
+        (pc)))
+   (clobber (reg:CC CRIS_CC0_REGNUM))]
+  ""
+  "#"
+  "&& reload_completed"
+  [(set (reg:<xCC> CRIS_CC0_REGNUM)
+       (compare:<xCC> (match_dup 0) (match_dup 1)))
+   (set (pc)
+       (if_then_else (cond (reg:<xCC> CRIS_CC0_REGNUM) (const_int 0))
+                     (label_ref (match_dup 2))
+                     (pc)))]
+  "")
+
+;; Test a single bit at operand[0] against 0/non-0.
+(define_insn_and_split "*cbranch<mode>4_btstrq1_<CC>"
+  [(set (pc)
+       (if_then_else
+        (zcond
+         (zero_extract:BWD
+          (match_operand:BWD 0 "register_operand" "r,r")
+          (const_int 1)
+          (match_operand:SI 1 "nonmemory_operand" "Kc,r"))
+         (const_int 0))
+        (label_ref (match_operand 2 ""))
+        (pc)))
+   (clobber (reg:CC CRIS_CC0_REGNUM))]
+  ""
+  "#"
+  "&& reload_completed"
+  [(set (reg:CC_ZnN CRIS_CC0_REGNUM)
+       (compare:CC_ZnN
+        (zero_extract:SI (match_dup 0) (const_int 1) (match_dup 1))
+        (const_int 0)))
+   (set (pc)
+       (if_then_else (zcond (reg:CC_ZnN CRIS_CC0_REGNUM) (const_int 0))
+                     (label_ref (match_dup 2))
+                     (pc)))]
+  "")
+
+;; Test a field of bits starting at bit 0 against 0/non-0.
+(define_insn_and_split "*cbranch<mode>4_btstqb0_<CC>"
+  [(set (pc)
+       (if_then_else
+        (zcond
+         (zero_extract:BWD
+          (match_operand:BWD 0 "register_operand" "r")
+          (match_operand 1 "const_int_operand" "Kc")
+          (const_int 0))
+         (const_int 0))
+        (label_ref (match_operand 2 ""))
+        (pc)))
+   (clobber (reg:CC CRIS_CC0_REGNUM))]
+  ""
+  "#"
+  "&& reload_completed"
+  [(set (reg:CC_NZ CRIS_CC0_REGNUM)
+       (compare:CC_NZ
+        (zero_extract:SI (match_dup 0) (match_dup 1) (const_int 0))
+        (const_int 0)))
+   (set (pc)
+       (if_then_else (zcond (reg:CC_NZ CRIS_CC0_REGNUM) (const_int 0))
+                     (label_ref (match_dup 2))
+                     (pc)))]
+  "")
+
+
 ;; We suffer from the same overflow-bit-gets-in-the-way problem as
 ;; e.g. m68k, so we have to check if overflow bit is set on all "signed"
 ;; conditions.
 
-(define_insn "b<ncond:code>"
+(define_insn "*b<zcond:code><mode>"
   [(set (pc)
-       (if_then_else (ncond (cc0)
+       (if_then_else (zcond (reg:ZnNNZUSE CRIS_CC0_REGNUM)
                             (const_int 0))
                      (label_ref (match_operand 0 "" ""))
                      (pc)))]
-  ""
-  "b<CC> %l0%#"
+  "reload_completed"
+{
+  return <MODE>mode == CC_ZnNmode ? "b<znnCC> %l0%#" : "b<CC> %l0%#";
+}
   [(set_attr "slottable" "has_slot")])
 
-(define_insn "b<ocond:code>"
+(define_insn "*b<nzvccond:code><mode>"
   [(set (pc)
-       (if_then_else (ocond (cc0)
+       (if_then_else (nzvccond (reg:NZVCUSE CRIS_CC0_REGNUM)
                             (const_int 0))
                      (label_ref (match_operand 0 "" ""))
                      (pc)))]
-  ""
-{
-  return
-    (cc_prev_status.flags & CC_NO_OVERFLOW)
-    ? 0 : "b<CC> %l0%#";
-}
+  "reload_completed"
+  "b<CC> %l0%#"
   [(set_attr "slottable" "has_slot")])
 
-(define_insn "b<rcond:code>"
+(define_insn "*b<rnzcond:code><mode>"
   [(set (pc)
-       (if_then_else (rcond (cc0)
+       (if_then_else (rnzcond (reg:NZUSE CRIS_CC0_REGNUM)
                             (const_int 0))
                      (label_ref (match_operand 0 "" ""))
                      (pc)))]
-  ""
+  "reload_completed"
 {
-  return
-    (cc_prev_status.flags & CC_NO_OVERFLOW)
-    ? "b<oCC> %l0%#" : "b<CC> %l0%#";
+  return <MODE>mode == CC_NZmode ? "b<oCC> %l0%#": "b<CC> %l0%#";
 }
   [(set_attr "slottable" "has_slot")])
 \f
 ;; Reversed anonymous patterns to the ones above, as mandated.
 
-(define_insn "*b<ncond:code>_reversed"
+(define_insn "*b<nzcond:code>_reversed<mode>"
   [(set (pc)
-       (if_then_else (ncond (cc0)
-                            (const_int 0))
+       (if_then_else (nzcond (reg:ZnNNZUSE CRIS_CC0_REGNUM)
+                             (const_int 0))
                      (pc)
                      (label_ref (match_operand 0 "" ""))))]
-  ""
-  "b<rCC> %l0%#"
+  "reload_completed"
+{
+  return <MODE>mode == CC_ZnNmode ? "b<rznnCC> %l0%#" : "b<rCC> %l0%#";
+}
   [(set_attr "slottable" "has_slot")])
 
-(define_insn "*b<ocond:code>_reversed"
+(define_insn "*b<nzvccond:code>_reversed<mode>"
   [(set (pc)
-       (if_then_else (ocond (cc0)
+       (if_then_else (nzvccond (reg:NZVCUSE CRIS_CC0_REGNUM)
                             (const_int 0))
                      (pc)
                      (label_ref (match_operand 0 "" ""))))]
-  ""
-{
-  return
-    (cc_prev_status.flags & CC_NO_OVERFLOW)
-    ? 0 : "b<rCC> %l0%#";
-}
+  "reload_completed"
+  "b<rCC> %l0%#"
   [(set_attr "slottable" "has_slot")])
 
-(define_insn "*b<rcond:code>_reversed"
+(define_insn "*b<rnzcond:code>_reversed<mode>"
   [(set (pc)
-       (if_then_else (rcond (cc0)
+       (if_then_else (rnzcond (reg:NZUSE CRIS_CC0_REGNUM)
                             (const_int 0))
                      (pc)
                      (label_ref (match_operand 0 "" ""))))]
-  ""
+  "reload_completed"
 {
-  return
-    (cc_prev_status.flags & CC_NO_OVERFLOW)
-    ? "b<roCC> %l0%#" : "b<rCC> %l0%#";
+  return <MODE>mode == CC_NZmode ? "b<roCC> %l0%#" : "b<rCC> %l0%#";
 }
   [(set_attr "slottable" "has_slot")])
 \f
 ;; Set on condition: sCC.
 
+(define_expand "cstore<mode>4"
+  [(parallel
+    [(set (match_operand:SI 0 "register_operand")
+         (match_operator:SI 1 "ordered_comparison_operator"
+          [(match_operand:BWDD 2 "nonimmediate_operand")
+           (match_operand:BWDD 3 "general_operand")]))
+     (clobber (reg:CC CRIS_CC0_REGNUM))])]
+  ""
+  "cris_reduce_compare (&operands[1], &operands[2], &operands[3]);")
+
+(define_insn_and_split "*cstore<mode><code>4"
+  [(set (match_operand:SI 0 "register_operand" "=<sCC_destc>")
+       (cond:SI
+        (match_operand:BWDD 1 "nonimmediate_operand" "<cmp_op0c>")
+        (match_operand:BWDD 2 "general_operand" "<cmp_op1c>")))
+   (clobber (reg:CC CRIS_CC0_REGNUM))]
+  ""
+  "#"
+  "&& reload_completed"
+  [(set (reg:<xCC> CRIS_CC0_REGNUM)
+       (compare:<xCC> (match_dup 1) (match_dup 2)))
+   (set (match_dup 0)
+       (cond:SI (reg:<xCC> CRIS_CC0_REGNUM) (const_int 0)))]
+  "")
+
 ;; Like bCC, we have to check the overflow bit for
 ;; signed conditions.
 
-(define_insn "s<ncond:code>"
+(define_insn "*s<nzcond:code><mode>"
   [(set (match_operand:SI 0 "register_operand" "=r")
-       (ncond:SI (cc0) (const_int 0)))]
-  ""
+       (nzcond:SI (reg:NZUSE CRIS_CC0_REGNUM) (const_int 0)))]
+  "reload_completed"
   "s<CC> %0"
   [(set_attr "slottable" "yes")
    (set_attr "cc" "none")])
 
-(define_insn "s<rcond:code>"
+(define_insn "*s<rnzcond:code><mode>"
   [(set (match_operand:SI 0 "register_operand" "=r")
-       (rcond:SI (cc0) (const_int 0)))]
-  ""
+       (rnzcond:SI (reg:NZUSE CRIS_CC0_REGNUM) (const_int 0)))]
+  "reload_completed"
 {
-  return
-    (cc_prev_status.flags & CC_NO_OVERFLOW)
-    ? "s<oCC> %0" : "s<CC> %0";
+  return <MODE>mode == CC_NZmode ? "s<oCC> %0" : "s<CC> %0";
 }
   [(set_attr "slottable" "yes")
    (set_attr "cc" "none")])
 
-(define_insn "s<ocond:code>"
+(define_insn "*s<nzvccond:code><mode>"
   [(set (match_operand:SI 0 "register_operand" "=r")
-       (ocond:SI (cc0) (const_int 0)))]
-  ""
-{
-  return
-    (cc_prev_status.flags & CC_NO_OVERFLOW)
-    ? 0 : "s<CC> %0";
-}
+       (nzvccond:SI (reg:NZVCUSE CRIS_CC0_REGNUM) (const_int 0)))]
+  "reload_completed"
+  "s<CC> %0"
   [(set_attr "slottable" "yes")
    (set_attr "cc" "none")])
 \f
 ;; instructions is a different issue.
 
 (define_expand "call"
-  [(parallel [(call (match_operand:QI 0 "cris_mem_call_operand" "")
-                   (match_operand 1 "general_operand" ""))
+  [(parallel [(call (match_operand:SI 0 "indirect_operand")
+                   (match_operand 1 "general_operand"))
              (clobber (reg:SI CRIS_SRP_REGNUM))])]
   ""
 {
-  gcc_assert (GET_CODE (operands[0]) == MEM);
-  if (flag_pic)
-    cris_expand_pic_call_address (&operands[0]);
+  operands[1] = const0_rtx;
 })
 
-;; Accept *anything* as operand 1.  Accept operands for operand 0 in
-;; order of preference.
+;; 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"))
-        (match_operand 1 "" ""))
+  [(call (mem:QI (match_operand:SI 0 "general_operand" "r,Q>,g"))
+        (const_int 0))
    (clobber (reg:SI CRIS_SRP_REGNUM))]
   ""
   "jsr %0")
 
-;; 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
-;; generates it (except it doesn' look into the *inner* mem, so this
-;; just matches a peephole2).  FIXME: investigate that.
-(define_insn "*expanded_call_side"
-  [(call (mem:QI
-         (mem:SI
-          (plus:SI (match_operand:SI 0 "cris_bdap_operand" "%r,  r,r")
-                   (match_operand:SI 1 "cris_bdap_operand" "r>Rn,r,>Rn"))))
-        (match_operand 2 "" ""))
-   (clobber (reg:SI CRIS_SRP_REGNUM))
-   (set (match_operand:SI 3 "register_operand" "=*0,r,r")
-       (plus:SI (match_dup 0)
-                (match_dup 1)))]
-  "! TARGET_AVOID_GOTPLT"
-  "jsr [%3=%0%S1]")
-
 (define_expand "call_value"
-  [(parallel [(set (match_operand 0 "" "")
-                  (call (match_operand:QI 1 "cris_mem_call_operand" "")
-                        (match_operand 2 "" "")))
+  [(parallel [(set (match_operand 0 "")
+                  (call (match_operand:SI 1 "indirect_operand")
+                        (match_operand 2 "")))
              (clobber (reg:SI CRIS_SRP_REGNUM))])]
   ""
 {
-  gcc_assert (GET_CODE (operands[1]) == MEM);
-  if (flag_pic)
-    cris_expand_pic_call_address (&operands[1]);
+  operands[2] = const0_rtx;
 })
 
-;; Accept *anything* as operand 2.  The validity other than "general" of
+;; The validity other than "general" of
 ;; operand 0 will be checked elsewhere.  Accept operands for operand 1 in
 ;; order of preference (Q includes r, but r is shorter, faster).
 ;;  We also accept a PLT symbol.  We output it as [rPIC+sym:GOTPLT] rather
 
 (define_insn "*expanded_call_value"
   [(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"))
-             (match_operand 2 "" "")))
+       (call (mem:QI (match_operand:SI 1 "general_operand" "r,Q>,g"))
+             (const_int 0)))
    (clobber (reg:SI CRIS_SRP_REGNUM))]
   ""
   "Jsr %1"
   [(set_attr "cc" "clobber")])
 
-;; See similar call special-case.
-(define_insn "*expanded_call_value_side"
-  [(set (match_operand 0 "nonimmediate_operand" "=g,g,g")
-       (call
-        (mem:QI
-         (mem:SI
-          (plus:SI (match_operand:SI 1 "cris_bdap_operand" "%r,  r,r")
-                   (match_operand:SI 2 "cris_bdap_operand" "r>Rn,r,>Rn"))))
-             (match_operand 3 "" "")))
-   (clobber (reg:SI CRIS_SRP_REGNUM))
-   (set (match_operand:SI 4 "register_operand" "=*1,r,r")
-       (plus:SI (match_dup 1)
-                (match_dup 2)))]
-  "! TARGET_AVOID_GOTPLT"
-  "Jsr [%4=%1%S2]"
-  [(set_attr "cc" "clobber")])
-
 ;; Used in debugging.  No use for the direct pattern; unfilled
 ;; delayed-branches are taken care of by other means.
 
   ""
   "nop"
   [(set_attr "cc" "none")])
+
+;; Same as the gdb trap breakpoint: would cause a SIGTRAP for
+;; cris-linux* and will work in freestanding environments with
+;; sufficient framework.
+(define_insn "trap"
+  [(trap_if (const_int 1) (const_int 8))]
+  "TARGET_TRAP_USING_BREAK8"
+  "break 8")
 \f
 ;; We need to stop accesses to the stack after the memory is
 ;; deallocated.  Unfortunately, reorg doesn't look at naked clobbers,
 ;; accordingly, to add the default case at the end of the jump-table.
 
 (define_expand "casesi"
-  [(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" "n")))
-   (set (match_dup 7)
-       (umin:SI (match_dup 6)
-                (match_operand:SI 2 "const_int_operand" "n")))
+  [(parallel
+    [(set (match_dup 5) (match_operand:SI 0 "general_operand"))
+     (clobber (reg:CC CRIS_CC0_REGNUM))])
+   (parallel
+    [(set (match_dup 6)
+         (minus:SI (match_dup 5)
+                   (match_operand:SI 1 "const_int_operand")))
+     (clobber (reg:CC CRIS_CC0_REGNUM))])
+   (parallel
+    [(set (match_dup 7)
+         (umin:SI (match_dup 6)
+                  (match_operand:SI 2 "const_int_operand")))
+     (clobber (reg:CC CRIS_CC0_REGNUM))])
    (parallel
     [(set (pc)
          (if_then_else
                      (plus:SI (mult:SI (match_dup 7) (const_int 2))
                               (pc))))
                    (pc))
-          (label_ref (match_operand 4 "" ""))))
-     (use (label_ref (match_operand 3 "" "")))])]
+          (label_ref (match_operand 4 ""))))
+     (use (label_ref (match_operand 3 "")))
+     (clobber (reg:CC CRIS_CC0_REGNUM))])]
   ""
 {
-  operands[2] = plus_constant (operands[2], 1);
+  operands[2] = plus_constant (SImode, operands[2], 1);
   operands[5] = gen_reg_rtx (SImode);
   operands[6] = gen_reg_rtx (SImode);
   operands[7] = gen_reg_rtx (SImode);
 })
-\f
-;; Split-patterns.  Some of them have modes unspecified.  This
-;; should always be ok; if for no other reason sparc.md has it as
-;; well.
-;;
-;; When register_operand is specified for an operand, we can get a
-;; subreg as well (Axis-990331), so don't just assume that REG_P is true
-;; for a register_operand and that REGNO can be used as is.  It is best to
-;; guard with REG_P, unless it is worth it to adjust for the subreg case.
-
-;; op [rx + 0],ry,rz
-;; The index to rx is optimized into zero, and gone.
-
-;; First, recognize bound [rx],ry,rz; where [rx] is zero-extended,
-;; and add/sub [rx],ry,rz, with zero or sign-extend on [rx].
-;; Split this into:
-;;  move ry,rz
-;;  op [rx],rz
-;; Lose if rz=ry or rx=rz.
-;; Call this op-extend-split
-
-(define_split
-  [(set (match_operand 0 "register_operand" "")
-       (match_operator
-        4 "cris_operand_extend_operator"
-        [(match_operand 1 "register_operand" "")
-         (match_operator
-          3 "cris_extend_operator"
-          [(match_operand 2 "memory_operand" "")])]))]
-  "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))
-   && REGNO (XEXP (operands[2], 0)) != REGNO (operands[0])"
-  [(set (match_dup 0)
-       (match_dup 1))
-   (set (match_dup 0)
-       (match_op_dup
-        4 [(match_dup 0)
-           (match_op_dup 3 [(match_dup 2)])]))]
-  "")
-
-;; As op-extend-split, but recognize and split op [rz],ry,rz into
-;;  ext [rz],rz
-;;  op ry,rz
-;; Do this for plus or bound only, being commutative operations, since we
-;; have swapped the operands.
-;; Call this op-extend-split-rx=rz
-
-(define_split
-  [(set (match_operand 0 "register_operand" "")
-       (match_operator
-        4 "cris_plus_or_bound_operator"
-        [(match_operand 1 "register_operand" "")
-         (match_operator
-          3 "cris_extend_operator"
-          [(match_operand 2 "memory_operand" "")])]))]
-  "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))
-   && REGNO (XEXP (operands[2], 0)) == REGNO (operands[0])"
-  [(set (match_dup 0)
-       (match_op_dup 3 [(match_dup 2)]))
-   (set (match_dup 0)
-       (match_op_dup
-        4 [(match_dup 0)
-           (match_dup 1)]))]
-  "")
 
-;; As the op-extend-split, but swapped operands, and only for
-;; plus or bound, being the commutative extend-operators.  FIXME: Why is
-;; this needed?  Is it?
-;; Call this op-extend-split-swapped
-
-(define_split
-  [(set (match_operand 0 "register_operand" "")
-       (match_operator
-        4 "cris_plus_or_bound_operator"
-        [(match_operator
-          3 "cris_extend_operator"
-          [(match_operand 2 "memory_operand" "")])
-         (match_operand 1 "register_operand" "")]))]
-  "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))
-   && REGNO (XEXP (operands[2], 0)) != REGNO (operands[0])"
-  [(set (match_dup 0)
-       (match_dup 1))
-   (set (match_dup 0)
-       (match_op_dup
-        4 [(match_dup 0)
-           (match_op_dup 3 [(match_dup 2)])]))]
-  "")
-
-;; As op-extend-split-rx=rz, but swapped operands, only for plus or
-;; bound.  Call this op-extend-split-swapped-rx=rz.
-
-(define_split
-  [(set (match_operand 0 "register_operand" "")
-       (match_operator
-        4 "cris_plus_or_bound_operator"
-        [(match_operator
-          3 "cris_extend_operator"
-          [(match_operand 2 "memory_operand" "")])
-         (match_operand 1 "register_operand" "")]))]
-  "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))
-   && REGNO (XEXP (operands[2], 0)) == REGNO (operands[0])"
-  [(set (match_dup 0)
-       (match_op_dup 3 [(match_dup 2)]))
-   (set (match_dup 0)
-       (match_op_dup
-        4 [(match_dup 0)
-           (match_dup 1)]))]
-  "")
-
-;; As op-extend-split, but the mem operand is not extended.
+(include "sync.md")
+\f
+;; Various peephole optimizations.
 ;;
-;; op [rx],ry,rz changed into
-;;  move ry,rz
-;;  op [rx],rz
-;; lose if ry=rz or rx=rz
-;; Call this op-extend.
-
-(define_split
-  [(set (match_operand 0 "register_operand" "")
-       (match_operator
-        3 "cris_orthogonal_operator"
-        [(match_operand 1 "register_operand" "")
-         (match_operand 2 "memory_operand" "")]))]
-  "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))
-   && REGNO (XEXP (operands[2], 0)) != REGNO (operands[0])"
-  [(set (match_dup 0)
-       (match_dup 1))
-   (set (match_dup 0)
-       (match_op_dup
-        3 [(match_dup 0)
-           (match_dup 2)]))]
-  "")
-
-;; As op-extend-split-rx=rz, non-extended.
-;; Call this op-split-rx=rz
-
-(define_split
-  [(set (match_operand 0 "register_operand" "")
-       (match_operator
-        3 "cris_commutative_orth_op"
-        [(match_operand 2 "memory_operand" "")
-         (match_operand 1 "register_operand" "")]))]
-  "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))
-   && REGNO (XEXP (operands[2], 0)) != REGNO (operands[0])"
-  [(set (match_dup 0)
-       (match_dup 1))
-   (set (match_dup 0)
-       (match_op_dup
-        3 [(match_dup 0)
-           (match_dup 2)]))]
-  "")
+;; Do not add patterns that you do not know will be matched.
+;; Please also add a self-contained testcase.
 
-;; As op-extend-split-swapped, nonextended.
-;; Call this op-split-swapped.
-
-(define_split
-  [(set (match_operand 0 "register_operand" "")
-       (match_operator
-        3 "cris_commutative_orth_op"
-        [(match_operand 1 "register_operand" "")
-         (match_operand 2 "memory_operand" "")]))]
-  "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))
-   && REGNO (XEXP (operands[2], 0)) == REGNO (operands[0])"
-  [(set (match_dup 0)
-       (match_dup 2))
-   (set (match_dup 0)
-       (match_op_dup
-        3 [(match_dup 0)
-           (match_dup 1)]))]
-  "")
+;; 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.  Or combine being over-eager
+;; to canonicalize to "and", and ignorant on the benefits of the right
+;; mixture of "and" and "zero-extend".
 
-;; As op-extend-split-swapped-rx=rz, non-extended.
-;; Call this op-split-swapped-rx=rz.
-
-(define_split
-  [(set (match_operand 0 "register_operand" "")
-       (match_operator
-        3 "cris_orthogonal_operator"
-        [(match_operand 2 "memory_operand" "")
-         (match_operand 1 "register_operand" "")]))]
-  "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))
-   && REGNO (XEXP (operands[2], 0)) == REGNO (operands[0])"
-  [(set (match_dup 0)
-       (match_dup 2))
-   (set (match_dup 0)
-       (match_op_dup
-        3 [(match_dup 0)
-           (match_dup 1)]))]
-  "")
-\f
-;; Splits for all cases in side-effect insns where (possibly after reload
-;; and register allocation) rx and ry in [rx=ry+i] are equal.
+;; Testcase for the following peephole: gcc.target/cris/peep2-movulsr.c
 
-;; move.S1 [rx=rx+rz.S2],ry
+;; Where equivalent and where the "and" argument doesn't fit "andq" but
+;; is 16 bits or smaller, replace the "and" with a zero-extend preceding
+;; the shift.  A zero-extend is shorter and faster than "and" with a
+;; 32-bit argument.
 
-(define_split
-  [(parallel
-    [(set (match_operand 0 "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))
-                   (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)))
-   (set (match_dup 0) (match_dup 5))]
-  "operands[5] = replace_equiv_address (operands[6], operands[3]);")
-
-;; move.S1 [rx=rx+i],ry
-
-(define_split
+(define_peephole2 ; movulsr
   [(parallel
-    [(set (match_operand 0 "register_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[1])
-    || 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] = replace_equiv_address (operands[5], operands[3]);")
-
-;; move.S1 ry,[rx=rx+rz.S2]
-
-(define_split
-  [(parallel
-    [(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 2)))])]
-  "REG_P (operands[2]) && REG_P (operands[4])
-   && REGNO (operands[4]) == REGNO (operands[2])"
-  [(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] = replace_equiv_address (operands[6], operands[4]);")
-
-;; move.S1 ry,[rx=rx+i]
-
-(define_split
-  [(parallel
-    [(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[0])
-    || 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] = replace_equiv_address (operands[6], operands[3]);")
-
-;; clear.[bwd] [rx=rx+rz.S2]
-
-(define_split
-  [(parallel
-    [(set (mem:BWD (plus:SI
-                   (mult:SI (match_operand:SI 0 "register_operand" "")
-                            (match_operand:SI 1 "const_int_operand" ""))
-                   (match_operand:SI 2 "register_operand" "")))
-          (const_int 0))
-     (set (match_operand:SI 3 "register_operand" "")
-          (plus:SI (mult:SI (match_dup 0)
-                            (match_dup 1))
-                   (match_dup 2)))])]
-  "REG_P (operands[2]) && REG_P (operands[3])
-   && REGNO (operands[3]) == REGNO (operands[2])"
-  [(set (match_dup 3) (plus:SI (mult:SI (match_dup 0) (match_dup 1))
-                               (match_dup 2)))
-   (set (mem:BWD (match_dup 3)) (const_int 0))]
-  "")
-
-;; clear.[bwd] [rx=rx+i]
-
-(define_split
+    [(set (match_operand:SI 0 "register_operand")
+         (lshiftrt:SI (match_dup 0)
+                      (match_operand:SI 1 "const_int_operand")))
+     (clobber (reg:CC CRIS_CC0_REGNUM))])
+   (parallel
+    [(set (match_dup 0)
+         (and:SI (match_dup 0)
+                 (match_operand 2 "const_int_operand")))
+     (clobber (reg:CC CRIS_CC0_REGNUM))])]
+  "INTVAL (operands[2]) > 31 && INTVAL (operands[2]) <= 0xffff
+   && (((INTVAL (operands[2]) <= 0xff ? 0xff : 0xffff) >> INTVAL (operands[1]))
+       == INTVAL (operands[2]))"
   [(parallel
-    [(set (mem:BWD
-          (plus:SI (match_operand:SI 0 "cris_bdap_operand" "")
-                   (match_operand:SI 1 "cris_bdap_operand" "")))
-          (const_int 0))
-     (set (match_operand:SI 2 "register_operand" "")
-          (plus:SI (match_dup 0)
-                   (match_dup 1)))])]
-  "(rtx_equal_p (operands[0], operands[2])
-    || rtx_equal_p (operands[2], operands[1]))"
-  [(set (match_dup 2) (plus:SI (match_dup 0) (match_dup 1)))
-   (set (mem:BWD (match_dup 2)) (const_int 0))]
-  "")
-
-;; mov(s|u).S1 [rx=rx+rz.S2],ry
+    ;; The zero-extend is expressed as an "and", only because that's easier
+    ;; than messing with zero-extend of a subreg.
+    [(set (match_dup 0) (and:SI (match_dup 0) (match_dup 3)))
+     (clobber (reg:CC CRIS_CC0_REGNUM))])
+   (parallel
+    [(set (match_dup 0) (lshiftrt:SI (match_dup 0) (match_dup 1)))
+     (clobber (reg:CC CRIS_CC0_REGNUM))])]
+{
+  operands[3]
+    = INTVAL (operands[2]) <= 0xff ? GEN_INT (0xff) :  GEN_INT (0xffff);
+})
 
-(define_split
-  [(parallel
-    [(set (match_operand 0 "register_operand" "")
-         (match_operator
-           5 "cris_extend_operator"
-           [(mem (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))
-                   (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)))
-   (set (match_dup 0) (match_op_dup 5 [(match_dup 6)]))]
-  "operands[6] = replace_equiv_address (XEXP (operands[5], 0), operands[4]);")
-
-;; mov(s|u).S1 [rx=rx+i],ry
-
-(define_split
+;; Avoid, after opsplit1 with AND (below), sequences of:
+;;  lsrq N,R
+;;  lslq M,R
+;;  lsrq M,R
+;; (N < M), where we can fold the first lsrq into the lslq-lsrq, like:
+;;  lslq M-N,R
+;;  lsrq M,R
+;; We have to match this before opsplit1 below and before other peephole2s of
+;; lesser value, since peephole2 matching resumes at the first generated insn,
+;; and thus wouldn't match a pattern of the three shifts after opsplit1/AND.
+;; Note that this lsrandsplit1 is in turn of lesser value than movulsr, since
+;; that one doesn't require the same operand for source and destination, but
+;; they happen to be the same hard-register at peephole2 time even if
+;; naturally separated like in peep2-movulsr2.c, thus this placement.  (Source
+;; and destination will be re-separated and the move optimized out in
+;; cprop_hardreg at time of this writing.)
+;; Testcase: gcc.target/cris/peep2-lsrandsplit1.c
+(define_peephole2 ; lsrandsplit1
   [(parallel
-    [(set (match_operand 0 "register_operand" "")
-         (match_operator
-           4 "cris_extend_operator"
-           [(mem (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[1], operands[3])
-    || 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] = replace_equiv_address (XEXP (operands[4], 0), operands[3]);")
-
-;; op.S1 [rx=rx+i],ry
-
-(define_split
-  [(parallel
-    [(set (match_operand 0 "register_operand" "")
-         (match_operator
-           5 "cris_orthogonal_operator"
-           [(match_operand 1 "register_operand" "")
-            (mem (plus:SI
-                  (match_operand:SI 2 "cris_bdap_operand" "")
-                  (match_operand:SI 3 "cris_bdap_operand" "")))]))
-     (set (match_operand:SI 4 "register_operand" "")
-          (plus:SI (match_dup 2)
-                   (match_dup 3)))])]
-  "(rtx_equal_p (operands[4], operands[2])
-    || 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] = replace_equiv_address (XEXP (operands[5], 1), operands[4]);")
-
-;; op.S1 [rx=rx+rz.S2],ry
-
-(define_split
-  [(parallel
-    [(set (match_operand 0 "register_operand" "")
-         (match_operator
-           6 "cris_orthogonal_operator"
-           [(match_operand 1 "register_operand" "")
-            (mem (plus:SI
-                  (mult:SI (match_operand:SI 2 "register_operand" "")
-                           (match_operand:SI 3 "const_int_operand" ""))
-                  (match_operand:SI 4 "register_operand" "")))]))
-     (set (match_operand:SI 5 "register_operand" "")
-          (plus:SI (mult:SI (match_dup 2)
-                            (match_dup 3))
-                  (match_dup 4)))])]
-  "REG_P (operands[4])
-   && REG_P (operands[5])
-   && REGNO (operands[5]) == REGNO (operands[4])"
-  [(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] = replace_equiv_address (XEXP (operands[6], 1), operands[5]);")
-
-;; op.S1 [rx=rx+rz.S2],ry (swapped)
-
-(define_split
-  [(parallel
-    [(set (match_operand 0 "register_operand" "")
-         (match_operator
-           6 "cris_commutative_orth_op"
-           [(mem (plus:SI
-                  (mult:SI (match_operand:SI 2 "register_operand" "")
-                           (match_operand:SI 3 "const_int_operand" ""))
-                  (match_operand:SI 4 "register_operand" "")))
-            (match_operand 1 "register_operand" "")]))
-     (set (match_operand:SI 5 "register_operand" "")
-          (plus:SI (mult:SI (match_dup 2)
-                            (match_dup 3))
-                   (match_dup 4)))])]
-  "REG_P (operands[4])
-   && REG_P (operands[5])
-   && REGNO (operands[5]) == REGNO (operands[4])"
-  [(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] = replace_equiv_address (XEXP (operands[6], 0), operands[5]);")
-
-;; op.S1 [rx=rx+i],ry (swapped)
-
-(define_split
-  [(parallel
-    [(set (match_operand 0 "register_operand" "")
-         (match_operator
-           5 "cris_commutative_orth_op"
-           [(mem
-             (plus:SI (match_operand:SI 2 "cris_bdap_operand" "")
-                      (match_operand:SI 3 "cris_bdap_operand" "")))
-            (match_operand 1 "register_operand" "")]))
-     (set (match_operand:SI 4 "register_operand" "")
-         (plus:SI (match_dup 2)
-                   (match_dup 3)))])]
-  "(rtx_equal_p (operands[4], operands[2])
-    || 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] = replace_equiv_address (XEXP (operands[5], 0), operands[4]);")
-
-;; op(s|u).S1 [rx=rx+rz.S2],ry
-
-(define_split
-  [(parallel
-    [(set (match_operand 0 "register_operand" "")
-         (match_operator
-           6 "cris_operand_extend_operator"
-           [(match_operand 1 "register_operand" "")
-            (match_operator
-             7 "cris_extend_operator"
-             [(mem (plus:SI
-                    (mult:SI (match_operand:SI 2 "register_operand" "")
-                             (match_operand:SI 3 "const_int_operand" ""))
-                    (match_operand:SI 4 "register_operand" "")))])]))
-     (set (match_operand:SI 5 "register_operand" "")
-          (plus:SI (mult:SI (match_dup 2)
-                            (match_dup 3))
-                   (match_dup 4)))])]
-  "REG_P (operands[4])
-   && REG_P (operands[5])
-   && REGNO (operands[5]) == REGNO (operands[4])"
-  [(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_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
-
-(define_split
-  [(parallel
-    [(set (match_operand 0 "register_operand" "")
-         (match_operator
-           5 "cris_operand_extend_operator"
-           [(match_operand 1 "register_operand" "")
-            (match_operator
-             6 "cris_extend_operator"
-             [(mem
-               (plus:SI (match_operand:SI 2 "cris_bdap_operand" "")
-                        (match_operand:SI 3 "cris_bdap_operand" "")
-                        ))])]))
-     (set (match_operand:SI 4 "register_operand" "")
-          (plus:SI (match_dup 2)
-                   (match_dup 3)))])]
-  "(rtx_equal_p (operands[4], operands[2])
-    || 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_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)
-
-(define_split
-  [(parallel
-    [(set (match_operand 0 "register_operand" "")
-         (match_operator
-           7 "cris_plus_or_bound_operator"
-           [(match_operator
-             6 "cris_extend_operator"
-             [(mem (plus:SI
-                    (mult:SI (match_operand:SI 2 "register_operand" "")
-                             (match_operand:SI 3 "const_int_operand" ""))
-                    (match_operand:SI 4 "register_operand" "")))])
-            (match_operand 1 "register_operand" "")]))
-     (set (match_operand:SI 5 "register_operand" "")
-          (plus:SI (mult:SI (match_dup 2)
-                            (match_dup 3))
-                   (match_dup 4)))])]
-  "REG_P (operands[4]) && REG_P (operands[5])
-   && REGNO (operands[5]) == REGNO (operands[4])"
-  [(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_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)
-
-(define_split
+    [(set (match_operand:SI 0 "register_operand")
+         (lshiftrt:SI
+          (match_operand:SI 1 "register_operand")
+          (match_operand:SI 2 "const_int_operand")))
+     (clobber (reg:CC CRIS_CC0_REGNUM))])
+   (parallel
+    [(set (match_operand 3 "register_operand")
+         (and
+          (match_operand 4 "register_operand")
+          (match_operand 5 "const_int_operand")))
+     (clobber (reg:CC CRIS_CC0_REGNUM))])]
+  "REGNO (operands[0]) == REGNO (operands[1])
+   && REGNO (operands[0]) == REGNO (operands[3])
+   && REGNO (operands[0]) == REGNO (operands[4])
+   && (INTVAL (operands[2])
+       < (clz_hwi (INTVAL (operands[5])) - (HOST_BITS_PER_WIDE_INT - 32)))
+   && cris_splittable_constant_p (INTVAL (operands[5]), AND, SImode,
+                                 optimize_function_for_speed_p (cfun)) == 2"
+  ;; We're guaranteed by the above hw_clz test (certainly non-zero) and the
+  ;; test for a two-insn return-value from cris_splittable_constant_p, that
+  ;; the cris_splittable_constant_p AND-replacement would be lslq-lsrq.
   [(parallel
-    [(set (match_operand 0 "register_operand" "")
-         (match_operator
-           6 "cris_plus_or_bound_operator"
-           [(match_operator
-             5 "cris_extend_operator"
-            [(mem (plus:SI
-                   (match_operand:SI 2 "cris_bdap_operand" "")
-                   (match_operand:SI 3 "cris_bdap_operand" "")))])
-            (match_operand 1 "register_operand" "")]))
-     (set (match_operand:SI 4 "register_operand" "")
-          (plus:SI (match_dup 2)
-                   (match_dup 3)))])]
-  "(rtx_equal_p (operands[4], operands[2])
-    || 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_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.
-
-;; If we have a
-;;  move [indirect_ref],rx
-;; where indirect ref = {const, [r+], [r]}, it costs as much as
-;;  move indirect_ref,rx
-;;  move [rx],rx
-;; Take care not to allow indirect_ref = register.
-
-;; We're not allowed to generate copies of registers with different mode
-;; until after reload; copying pseudos upsets reload.  CVS as of
-;; 2001-08-24, unwind-dw2-fde.c, _Unwind_Find_FDE ICE in
-;; cselib_invalidate_regno.
-
-(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)))
-   && 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] = replace_equiv_address (operands[1], operands[2]);
-   operands[4] = XEXP (operands[1], 0);")
-
-;; As the above, but MOVS and MOVU.
-
-(define_split
-  [(set (match_operand 0 "register_operand" "")
-       (match_operator
-        4 "cris_extend_operator"
-        [(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)))"
-  [(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] = replace_equiv_address (XEXP (operands[4], 0), operands[2]);
-   operands[5] = XEXP (operands[1], 0);")
-\f
-;; Various peephole optimizations.
-;;
-;; Watch out: when you exchange one set of instructions for another, the
-;; condition codes setting must be the same, or you have to CC_INIT or
-;; whatever is appropriate, in the pattern before you emit the
-;; assembly text.  This is best done here, not in cris_notice_update_cc,
-;; 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 testcase.
+    [(set (match_dup 0) (ashift:SI (match_dup 0) (match_dup 9)))
+     (clobber (reg:CC CRIS_CC0_REGNUM))])
+   (parallel
+    [(set (match_dup 0) (lshiftrt:SI (match_dup 0) (match_dup 10)))
+     (clobber (reg:CC CRIS_CC0_REGNUM))])]
+{
+  HOST_WIDE_INT shiftval
+    = clz_hwi (INTVAL (operands[5])) - (HOST_BITS_PER_WIDE_INT - 32);
+  operands[9] = GEN_INT (shiftval - INTVAL (operands[2]));
+  operands[10] = GEN_INT (shiftval);
+})
 
-;; 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
+;; Testcase for the following four peepholes: gcc.target/cris/peep2-xsrand.c
 
-(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" "")))
-   (set (match_dup 0)
+(define_peephole2 ; asrandb
+  [(parallel
+    [(set (match_operand:SI 0 "register_operand")
+         (ashiftrt:SI (match_dup 0)
+                      (match_operand:SI 1 "const_int_operand")))
+     (clobber (reg:CC CRIS_CC0_REGNUM))])
+   (parallel
+    [(set (match_dup 0)
        (and:SI (match_dup 0)
-               (match_operand 2 "const_int_operand" "")))]
+               (match_operand 2 "const_int_operand")))
+     (clobber (reg:CC CRIS_CC0_REGNUM))])]
   "INTVAL (operands[2]) > 31
    && INTVAL (operands[2]) < 255
    && 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.
+       & ((HOST_WIDE_INT) (HOST_WIDE_INT_M1U
+                          << (32 - INTVAL (operands[1]))))) == 0"
+  [(parallel
+    [(set (match_dup 0) (lshiftrt:SI (match_dup 0) (match_dup 1)))
+     (clobber (reg:CC CRIS_CC0_REGNUM))])
+   (parallel
+    [(set (match_dup 3) (and:QI (match_dup 3) (match_dup 4)))
+     (clobber (reg:CC CRIS_CC0_REGNUM))])]
 {
   operands[3] = gen_rtx_REG (QImode, REGNO (operands[0]));
   operands[4] = GEN_INT (trunc_int_for_mode (INTVAL (operands[2]), QImode));
 })
 
-(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" "")))
-   (set (match_dup 0)
-       (and:SI (match_dup 0) (match_operand 2 "const_int_operand" "")))]
+(define_peephole2 ; asrandw
+  [(parallel
+    [(set (match_operand:SI 0 "register_operand")
+         (ashiftrt:SI (match_dup 0)
+                      (match_operand:SI 1 "const_int_operand")))
+     (clobber (reg:CC CRIS_CC0_REGNUM))])
+   (parallel
+    [(set (match_dup 0)
+       (and:SI (match_dup 0) (match_operand 2 "const_int_operand")))
+     (clobber (reg:CC CRIS_CC0_REGNUM))])]
   "INTVAL (operands[2]) > 31
    && INTVAL (operands[2]) < 65535
    && INTVAL (operands[2]) != 255
    && 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.
+       & ((HOST_WIDE_INT) (HOST_WIDE_INT_M1U
+                          << (32 - INTVAL (operands[1]))))) == 0"
+  [(parallel
+    [(set (match_dup 0) (lshiftrt:SI (match_dup 0) (match_dup 1)))
+     (clobber (reg:CC CRIS_CC0_REGNUM))])
+   (parallel
+    [(set (match_dup 3) (and:HI (match_dup 3) (match_dup 4)))
+     (clobber (reg:CC CRIS_CC0_REGNUM))])]
 {
   operands[3] = gen_rtx_REG (HImode, REGNO (operands[0]));
   operands[4] = GEN_INT (trunc_int_for_mode (INTVAL (operands[2]), HImode));
 })
 
-(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" "")))
-   (set (match_dup 0)
-       (and:SI (match_dup 0) (match_operand 2 "const_int_operand" "")))]
+(define_peephole2 ; lsrandb
+  [(parallel
+    [(set (match_operand:SI 0 "register_operand")
+         (lshiftrt:SI (match_dup 0)
+                      (match_operand:SI 1 "const_int_operand")))
+     (clobber (reg:CC CRIS_CC0_REGNUM))])
+   (parallel
+    [(set (match_dup 0)
+         (and:SI (match_dup 0) (match_operand 2 "const_int_operand")))
+     (clobber (reg:CC CRIS_CC0_REGNUM))])]
   "INTVAL (operands[2]) > 31
    && INTVAL (operands[2]) < 255
    && INTVAL (operands[1]) > 23"
-  [(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.
+  [(parallel
+    [(set (match_dup 0) (lshiftrt:SI (match_dup 0) (match_dup 1)))
+     (clobber (reg:CC CRIS_CC0_REGNUM))])
+   (parallel
+    [(set (match_dup 3) (and:QI (match_dup 3) (match_dup 4)))
+     (clobber (reg:CC CRIS_CC0_REGNUM))])]
 {
   operands[3] = gen_rtx_REG (QImode, REGNO (operands[0]));
   operands[4] = GEN_INT (trunc_int_for_mode (INTVAL (operands[2]), QImode));
 })
 
-(define_peephole2 ; lsrandw (peephole casesi+34)
-  [(set (match_operand:SI 0 "register_operand" "")
+(define_peephole2 ; lsrandw
+  [(parallel
+    [(set (match_operand:SI 0 "register_operand")
        (lshiftrt:SI (match_dup 0)
-                    (match_operand:SI 1 "const_int_operand" "")))
-   (set (match_dup 0)
-       (and:SI (match_dup 0) (match_operand 2 "const_int_operand" "")))]
+                    (match_operand:SI 1 "const_int_operand")))
+     (clobber (reg:CC CRIS_CC0_REGNUM))])
+   (parallel
+    [(set (match_dup 0)
+       (and:SI (match_dup 0) (match_operand 2 "const_int_operand")))
+     (clobber (reg:CC CRIS_CC0_REGNUM))])]
   "INTVAL (operands[2]) > 31 && INTVAL (operands[2]) < 65535
    && INTVAL (operands[2]) != 255
    && INTVAL (operands[1]) > 15"
-  [(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.
+  [(parallel
+    [(set (match_dup 0) (lshiftrt:SI (match_dup 0) (match_dup 1)))
+     (clobber (reg:CC CRIS_CC0_REGNUM))])
+   (parallel
+    [(set (match_dup 3) (and:HI (match_dup 3) (match_dup 4)))
+     (clobber (reg:CC CRIS_CC0_REGNUM))])]
 {
   operands[3] = gen_rtx_REG (HImode, REGNO (operands[0]));
   operands[4] = GEN_INT (trunc_int_for_mode (INTVAL (operands[2]), HImode));
 })
-\f
-
-;; Change
-;;  add.d n,rx
-;;  move [rx],ry
-;; into
-;;  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.  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_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
-;;  op.d [rx],ry
-;; into:
-;;  op.d [rx=rx+n],ry
-;; Saves when n = [-128..127].
-;;
-;; Splitting and joining combinations for side-effect modes are slightly
-;; 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.
-;; 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"
-  [(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_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" "")
-                (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)"
-  [(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 above but to memory.
-;; FIXME: Split movemside and moverside into variants and prune
-;; the ones that don't trig.
-;; No stable test-case.
-
-(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" "")
-                (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, 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];
 
-  /* 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_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"
-  [(set (match_dup 2) (match_dup 4))]
-  "operands[4] = replace_equiv_address (operands[3], operands[1]);")
-
-;;   move.d [r10+16],r9
-;;   and.d r12,r9
-;; change to
-;;   and.d [r10+16],r12,r9
-;; With generalization of the operation, the size and the addressing mode.
-;;  This seems to be the result of a quirk in register allocation
-;; missing the three-operand cases when having different predicates.
-;; Maybe that it matters that it is a commutative operation.
-;;  This pattern helps that situation, but there's still the increased
-;; 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_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" "")
-         (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"
-  [(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];")
-
-;;  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
-;; where reg_32 is the destination of the "three-address" code optimally.
+;; There seems to be no other way to make GCC (including 4.8/trunk at
+;; r186932) optimally reload an instruction that looks like
+;;   and.d reg_or_mem,const_32__65535,other_reg
+;; where other_reg is the destination.
 ;; It should be:
-;;   movu.b some_byte,reg_32
-;;   and.b const,reg_32
-;; but is turns into:
-;;   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_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" "")))]
+;;   movu.[bw] reg_or_mem,reg_32
+;;   and.[bw] trunc_int_for_mode([bw], const_32__65535),reg_32 ;; or andq
+;; but it turns into:
+;;   move.d reg_or_mem,reg_32
+;;   and.d const_32__65535,reg_32
+;; Fix it with these two peephole2's.
+;; Testcases: gcc.target/cris/peep2-andu1.c gcc.target/cris/peep2-andu2.c
+
+(define_peephole2 ; andu
+  [(parallel
+    [(set (match_operand:SI 0 "register_operand")
+         (match_operand:SI 1 "nonimmediate_operand"))
+     (clobber (reg:CC CRIS_CC0_REGNUM))])
+   (parallel
+    [(set (match_operand:SI 2 "register_operand")
+         (and:SI (match_dup 0)
+                 (match_operand:SI 3 "const_int_operand")))
+     (clobber (reg:CC CRIS_CC0_REGNUM))])]
    ;; 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))]
+   && !satisfies_constraint_I (operands[3])
+   && !side_effects_p (operands[1])
+   && (!REG_P (operands[1])
+       || REGNO (operands[1]) <= CRIS_LAST_GENERAL_REGISTER)"
+  [(parallel
+    [(set (match_dup 0) (match_dup 4))
+     (clobber (reg:CC CRIS_CC0_REGNUM))])
+   (parallel
+    [(set (match_dup 5) (match_dup 6))
+     (clobber (reg:CC CRIS_CC0_REGNUM))])]
 {
-  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;
+  machine_mode zmode = INTVAL (operands[3]) <= 255 ? QImode : HImode;
+  machine_mode amode
+    = satisfies_constraint_O (operands[3]) ? SImode : zmode;
   rtx op1
     = (REG_S_P (operands[1])
        ? gen_rtx_REG (zmode, REGNO (operands[1]))
                                                ? QImode : amode)));
 })
 
-;; Try and avoid GOTPLT reads escaping a call: transform them into
-;; PLT.  Curiously (but thankfully), peepholes for instructions
-;; *without side-effects* that just feed a call (or call_value) are
-;; not matched neither in a build or test-suite, so those patterns are
-;; omitted.
-
-;; A "normal" move where we don't check the consumer.
-
-(define_peephole2 ; gotplt-to-plt
-  [(set
-    (match_operand:SI 0 "register_operand" "")
-    (match_operator:SI
-     1 "cris_mem_op"
-     [(plus:SI
-       (reg:SI CRIS_GOT_REGNUM)
-       (const:SI
-       (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))
-   && 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) (plus:SI (match_dup 0) (reg:SI CRIS_GOT_REGNUM)))]
-  "")
+;; Since r186861, gcc.target/cris/peep2-andu2.c trigs this pattern, with which
+;; we fix up e.g.:
+;;  movu.b 254,$r9.
+;;  and.d $r10,$r9
+;; into:
+;;  movu.b $r10,$r9
+;;  andq -2,$r9.
+;; Only do this for values fitting the quick immediate operand.
+(define_peephole2 ; andqu
+  [(parallel
+    [(set (match_operand:SI 0 "register_operand")
+         (match_operand:SI 1 "const_int_operand"))
+     (clobber (reg:CC CRIS_CC0_REGNUM))])
+   (parallel
+    [(set (match_dup 0)
+         (and:SI (match_dup 0) (match_operand:SI 2 "nonimmediate_operand")))
+     (clobber (reg:CC CRIS_CC0_REGNUM))])]
+   ;; Since the size of the memory access will be made different here,
+   ;; don't do this for a volatile access or a post-incremented address.
+  "satisfies_constraint_O (operands[1])
+   && !side_effects_p (operands[2])
+   && !reg_overlap_mentioned_p (operands[0], operands[2])"
+  [(parallel
+    [(set (match_dup 0) (match_dup 3))
+     (clobber (reg:CC CRIS_CC0_REGNUM))])
+   (parallel
+    [(set (match_dup 0) (and:SI (match_dup 0) (match_dup 4)))
+     (clobber (reg:CC CRIS_CC0_REGNUM))])]
+{
+  machine_mode zmode = INTVAL (operands[1]) <= 255 ? QImode : HImode;
+  rtx op1
+    = (REG_S_P (operands[2])
+       ? gen_rtx_REG (zmode, REGNO (operands[2]))
+       : adjust_address (operands[2], zmode, 0));
+  operands[3] = gen_rtx_ZERO_EXTEND (SImode, op1);
+  operands[4] = GEN_INT (trunc_int_for_mode (INTVAL (operands[1]), QImode));
+})
 
-;; And one set with a side-effect getting the PLTGOT offset.
-;; First call and call_value variants.
+;; Somewhat similar to andqu, but a different range and expansion,
+;; intended to feed the output into opsplit1 with AND:
+;;  move.d 0x7ffff,$r10
+;;  and.d $r11,$r10
+;; into:
+;;  move.d $r11,$r10
+;;  and.d 0x7ffff,$r10
+;; which opsplit1/AND will change into:
+;;  move.d $r11,$r10 (unaffected by opsplit1/AND; shown only for context)
+;;  lslq 13,$r10
+;;  lsrq 13,$r10
+;; thereby winning in space, but in time only if the 0x7ffff happened to
+;; be unaligned in the code.
+(define_peephole2 ; movandsplit1
+  [(parallel
+    [(set (match_operand 0 "register_operand")
+         (match_operand 1 "const_int_operand"))
+     (clobber (reg:CC CRIS_CC0_REGNUM))])
+   (parallel
+    [(set (match_operand 2 "register_operand")
+         (and (match_operand 3 "register_operand")
+              (match_operand 4 "register_operand")))
+     (clobber (reg:CC CRIS_CC0_REGNUM))])]
+  "REGNO (operands[0]) == REGNO (operands[2])
+   && REGNO (operands[0]) == REGNO (operands[3])
+   && cris_splittable_constant_p (INTVAL (operands[1]), AND,
+                                 GET_MODE (operands[2]),
+                                 optimize_function_for_speed_p (cfun))"
+  [(parallel
+    [(set (match_dup 2) (match_dup 4))
+     (clobber (reg:CC CRIS_CC0_REGNUM))])
+   (parallel
+    [(set (match_dup 2) (match_dup 5))
+     (clobber (reg:CC CRIS_CC0_REGNUM))])]
+{
+  operands[5] = gen_rtx_AND (GET_MODE (operands[2]), operands[2], operands[1]);
+})
 
-(define_peephole2 ; gotplt-to-plt-side-call
+;; Large (read: non-quick) numbers can sometimes be AND:ed by other means.
+;; Testcase: gcc.target/cris/peep2-andsplit1.c
+;; 
+;; Another case is add<ext> N,rx with -126..-64,64..126: it has the same
+;; size and execution time as two addq or subq, but addq and subq can fill
+;; a delay-slot.
+(define_peephole2 ; opsplit1
   [(parallel
-    [(set
-      (match_operand:SI 0 "register_operand" "")
-      (match_operator:SI
-       1 "cris_mem_op"
-       [(plus:SI
-        (reg:SI CRIS_GOT_REGNUM)
-        (const:SI
-         (unspec:SI [(match_operand:SI
-                      2 "cris_general_operand_or_symbol" "")]
-                    CRIS_UNSPEC_PLTGOTREAD)))]))
-     (set (match_operand:SI 3 "register_operand" "")
-         (plus:SI (reg:SI CRIS_GOT_REGNUM)
-                  (const:SI
-                   (unspec:SI [(match_dup 2)] CRIS_UNSPEC_PLTGOTREAD))))])
-  (parallel [(call (mem:QI (match_dup 0))
-                   (match_operand 4 "" ""))
-             (clobber (reg:SI CRIS_SRP_REGNUM))])]
-  "flag_pic
-   && cris_valid_pic_const (XEXP (XEXP (operands[1], 0), 1))
-   && peep2_reg_dead_p (2, operands[0])"
-  [(parallel [(call (mem:QI (match_dup 1))
-                   (match_dup 4))
-             (clobber (reg:SI CRIS_SRP_REGNUM))
-             (set (match_dup 3)
-                  (plus:SI (reg:SI CRIS_GOT_REGNUM)
-                           (const:SI
-                            (unspec:SI [(match_dup 2)]
-                                       CRIS_UNSPEC_PLTGOTREAD))))])]
-  "")
+    [(set (match_operand 0 "register_operand")
+         (splitop
+          (match_operand 1 "register_operand")
+          (match_operand 2 "const_int_operand")))
+     (clobber (reg:CC CRIS_CC0_REGNUM))])]
+   ;; Operands 0 and 1 can be separate identical objects, at least
+   ;; after matching peepholes above.  */
+  "REGNO (operands[0]) == REGNO (operands[1])
+   && cris_splittable_constant_p (INTVAL (operands[2]), <CODE>,
+                                 GET_MODE (operands[0]),
+                                 optimize_function_for_speed_p (cfun))"
+  [(const_int 0)]
+{
+  cris_split_constant (INTVAL (operands[2]), <CODE>, GET_MODE (operands[0]),
+                      optimize_function_for_speed_p (cfun),
+                      true, operands[0], operands[0]);
+  DONE;
+})
 
-(define_peephole2 ; gotplt-to-plt-side-call-value
+;; Fix a decomposed szext: fuse it with the memory operand of the
+;; load.  This is typically the sign-extension part of a decomposed
+;; "indirect offset" address.
+(define_peephole2 ; lra_szext_decomposed
   [(parallel
-    [(set
-      (match_operand:SI 0 "register_operand" "")
-      (match_operator:SI
-       1 "cris_mem_op"
-       [(plus:SI
-        (reg:SI CRIS_GOT_REGNUM)
-        (const:SI
-         (unspec:SI [(match_operand:SI
-                      2 "cris_general_operand_or_symbol" "")]
-                    CRIS_UNSPEC_PLTGOTREAD)))]))
-     (set (match_operand:SI 3 "register_operand" "")
-         (plus:SI (reg:SI CRIS_GOT_REGNUM)
-                  (const:SI
-                   (unspec:SI [(match_dup 2)] CRIS_UNSPEC_PLTGOTREAD))))])
-   (parallel [(set (match_operand 5 "" "")
-                  (call (mem:QI (match_dup 0))
-                        (match_operand 4 "" "")))
-             (clobber (reg:SI CRIS_SRP_REGNUM))])]
-  "flag_pic
-   && cris_valid_pic_const (XEXP (XEXP (operands[1], 0), 1))
-   && peep2_reg_dead_p (2, operands[0])"
-  [(parallel [(set (match_dup 5)
-                  (call (mem:QI (match_dup 1))
-                        (match_dup 4)))
-             (clobber (reg:SI CRIS_SRP_REGNUM))
-             (set (match_dup 3)
-                  (plus:SI (reg:SI CRIS_GOT_REGNUM)
-                           (const:SI
-                            (unspec:SI [(match_dup 2)]
-                                       CRIS_UNSPEC_PLTGOTREAD))))])]
-  "")
+    [(set (match_operand:BW 0 "register_operand")
+         (match_operand:BW 1 "memory_operand"))
+     (clobber (reg:CC CRIS_CC0_REGNUM))])
+   (parallel
+    [(set (match_operand:SI 2 "register_operand") (szext:SI (match_dup 0)))
+     (clobber (reg:CC CRIS_CC0_REGNUM))])]
+  "REGNO (operands[0]) == REGNO (operands[2])
+   || peep2_reg_dead_p (2, operands[0])"
+  [(parallel
+    [(set (match_dup 2) (szext:SI (match_dup 1)))
+     (clobber (reg:CC CRIS_CC0_REGNUM))])])
 
-(define_peephole2 ; gotplt-to-plt-side
+;; Re-compose a decomposed "indirect offset" address for a szext
+;; operation.  The non-clobbering "addi" is generated by LRA.
+;; This and lra_szext_decomposed is covered by cris/rld-legit1.c.
+(define_peephole2 ; lra_szext_decomposed_indirect_with_offset
+  [(parallel
+    [(set (match_operand:SI 0 "register_operand")
+         (sign_extend:SI (mem:BW (match_operand:SI 1 "register_operand"))))
+     (clobber (reg:CC CRIS_CC0_REGNUM))])
+   (set (match_dup 0)
+       (plus:SI (match_dup 0) (match_operand:SI 2 "register_operand")))
+   (parallel
+    [(set (match_operand:SI 3 "register_operand")
+         (szext:SI (mem:BW2 (match_dup 0))))
+     (clobber (reg:CC CRIS_CC0_REGNUM))])]
+  "(REGNO (operands[0]) == REGNO (operands[3])
+    || peep2_reg_dead_p (3, operands[0]))
+   && (REGNO (operands[0]) == REGNO (operands[1])
+       || peep2_reg_dead_p (3, operands[0]))"
   [(parallel
     [(set
-      (match_operand:SI 0 "register_operand" "")
-      (match_operator:SI
-       1 "cris_mem_op"
-       [(plus:SI
-        (reg:SI CRIS_GOT_REGNUM)
-        (const:SI
-         (unspec:SI [(match_operand:SI
-                      2 "cris_general_operand_or_symbol" "")]
-                    CRIS_UNSPEC_PLTGOTREAD)))]))
-     (set (match_operand:SI 3 "register_operand" "")
-         (plus:SI (reg:SI CRIS_GOT_REGNUM)
-                  (const:SI
-                   (unspec:SI [(match_dup 2)] CRIS_UNSPEC_PLTGOTREAD))))])]
-  "flag_pic
-   && cris_valid_pic_const (XEXP (XEXP (operands[1], 0), 1))
-   && 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) (plus:SI (match_dup 0) (reg:SI CRIS_GOT_REGNUM)))]
-  "")
+      (match_dup 3)
+      (szext:SI
+       (mem:BW2 (plus:SI (szext:SI (mem:BW (match_dup 1))) (match_dup 2)))))
+     (clobber (reg:CC CRIS_CC0_REGNUM))])])
+
+;; Add operations with similar or same decomposed addresses here, when
+;; encountered - but only when covered by mentioned test-cases for at
+;; least one of the cases generalized in the pattern.
 \f
 ;; Local variables:
 ;; mode:emacs-lisp