;; GCC machine description for CRIS cpu cores.
;; Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004
;; 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)
;; any later version.
;;
;; GCC is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;; 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, 59 Temple Place - Suite 330,
;; Boston, MA 02111-1307, USA.

;; 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
;; for the operand that is orthogonal.  However, this did not work on
;; gcc-2.7.2 (and probably not on gcc-2.8.1), relating to that when a
;; constant is substituted into an operand, the actual mode must be
;; deduced from the pattern.  There is reasonable hope that that has been
;; fixed, so FIXME: try again.

;; You will notice that three-operand alternatives ("=r", "r", "!To")
;; are marked with a "!" constraint modifier to avoid being reloaded
;; into.  This is because gcc would otherwise prefer to use the constant
;; pool and its offsettable address instead of reloading to an
;; ("=r", "0", "i") alternative.  Also, the constant-pool support was not
;; only suboptimal but also buggy in 2.7.2, ??? maybe only in 2.6.3.

;; All insns that look like (set (...) (plus (...) (reg:SI 8)))
;; get problems when reloading r8 (frame pointer) to r14 + offs (stack
;; pointer).  Thus the instructions that get into trouble have specific
;; checks against matching frame_pointer_rtx.
;; ??? 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).

;; UNSPEC Usage:
;; 0 PLT reference from call expansion: operand 0 is the address,
;;   the mode is VOIDmode.  Always wrapped in CONST.

;; We need an attribute to define whether an instruction can be put in
;; a branch-delay slot or not, and whether it has a delay slot.
;;
;; Branches and return instructions have a delay slot, and cannot
;; themselves be put in a delay slot.  This has changed *for short
;; branches only* between architecture variants, but the possible win
;; is presumed negligible compared to the added complexity of the machine
;; description: one would have to add always-correct infrastructure to
;; distinguish short branches.
;;
;; Whether an instruction can be put in a delay slot depends on the
;; instruction (all short instructions except jumps and branches)
;; and the addressing mode (must not be prefixed or referring to pc).
;; 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 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
;; it being wrong for non-branch and return instructions.
;;  The default could depend on the kind of insn and the addressing
;; mode, but that would need more attributes and hairier, more error
;; prone code.
;;
;;  There is an extra constraint, 'Q', which recognizes indirect reg,
;; except when the reg is pc.  The constraints 'Q' and '>' together match
;; all possible memory operands that are slottable.
;;  For other operands, you need to check if it has a valid "slottable"
;; quick-immediate operand, where the particular signedness-variation
;; may match the constraints 'I' or 'J'.), and include it in the
;; 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"))

;; We also need attributes to sanely determine the condition code
;; state.  See cris_notice_update_cc for how this is used.

(define_attr "cc" "none,clobber,normal" (const_string "normal"))

;; A branch or return has one delay-slot.  The instruction in the
;; delay-slot is always executed, independent of whether the branch is
;; taken or not.  Note that besides setting "slottable" to "has_slot",
;; there also has to be a "%#" at the end of a "delayed" instruction
;; output pattern (for "jump" this means "ba %l0%#"), so print_operand can
;; catch it and print a "nop" if necessary.  This method was stolen from
;; sparc.md.

(define_delay (eq_attr "slottable" "has_slot")
  [(eq_attr "slottable" "yes") (nil) (nil)])

;; Test insns.

;; DImode
;;
;; Allow register and offsettable mem operands only; post-increment is
;; not worth the trouble.

(define_insn "tstdi"
  [(set (cc0)
	(match_operand:DI 0 "nonimmediate_operand" "r,o"))]
  ""
  "test.d %M0\;ax\;test.d %H0")

;; No test insns with side-effect on the mem addressing.
;;
;; See note on cmp-insns with side-effects (or lack of them)

;; Normal named test patterns from SI on.
;; FIXME: Seems they should change to be in order smallest..largest.

(define_insn "tstsi"
  [(set (cc0)
	(match_operand:SI 0 "nonimmediate_operand" "r,Q>,m"))]
  ""
  "test.d %0"
  [(set_attr "slottable" "yes,yes,no")])

(define_insn "tsthi"
  [(set (cc0)
	(match_operand:HI 0 "nonimmediate_operand" "r,Q>,m"))]
  ""
  "test.w %0"
  [(set_attr "slottable" "yes,yes,no")])

(define_insn "tstqi"
  [(set (cc0)
	(match_operand:QI 0 "nonimmediate_operand" "r,Q>,m"))]
  ""
  "test.b %0"
  [(set_attr "slottable" "yes,yes,no")])

;; 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.

;; Compare insns.

;; 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")))]
  ""
  "@
   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")

;; Note that compare insns with side effect addressing mode (e.g.):
;;
;; cmp.S [rx=ry+i],rz;
;; cmp.S [%3=%1+%2],%0
;;
;; are *not* usable for gcc since the reloader *does not accept*
;; cc0-changing insns with side-effects other than setting the condition
;; codes.  The reason is that the reload stage *may* cause another insn to
;; be output after the main instruction, in turn invalidating cc0 for the
;; insn using the test.  (This does not apply to the CRIS case, since a
;; reload for output -- move to memory -- does not change the condition
;; code.  Unfortunately we have no way to describe that at the moment.  I
;; think code would improve being in the order of one percent faster.

;; We have cmps and cmpu (compare reg w. sign/zero extended mem).
;; These are mostly useful for compares in SImode, using 8 or 16-bit
;; constants, but sometimes gcc will find its way to use it for other
;; (memory) operands.  Avoid side-effect patterns, though (see above).
;;
;; FIXME: These could have an anonymous mode for operand 1.

;; QImode

(define_insn "*cmp_extsi"
  [(set (cc0)
	(compare
	 (match_operand:SI 0 "register_operand" "r,r")
	 (match_operator:SI 2 "cris_extend_operator"
			 [(match_operand:QI 1 "memory_operand" "Q>,m")])))]
  ""
  "cmp%e2.%s1 %1,%0"
  [(set_attr "slottable" "yes,no")])

;; HImode
(define_insn "*cmp_exthi"
  [(set (cc0)
	(compare
	 (match_operand:SI 0 "register_operand" "r,r")
	 (match_operator:SI 2 "cris_extend_operator"
			 [(match_operand:HI 1 "memory_operand" "Q>,m")])))]
  ""
  "cmp%e2.%s1 %1,%0"
  [(set_attr "slottable" "yes,no")])

;; Swap operands; it seems the canonical look (if any) is not enforced.
;;
;; FIXME: Investigate that.
;; FIXME: These could have an anonymous mode for operand 1.

;; QImode

(define_insn "*cmp_swapextqi"
  [(set (cc0)
	(compare
	 (match_operator:SI 2 "cris_extend_operator"
			    [(match_operand:QI 0 "memory_operand" "Q>,m")])
	 (match_operand:SI 1 "register_operand" "r,r")))]
  ""
  "cmp%e2.%s0 %0,%1" ; The function cris_notice_update_cc knows about
		     ; swapped operands to compares.
  [(set_attr "slottable" "yes,no")])

;; HImode

(define_insn "*cmp_swapexthi"
  [(set (cc0)
	(compare
	 (match_operator:SI 2 "cris_extend_operator"
			    [(match_operand:HI 0 "memory_operand" "Q>,m")])
	 (match_operand:SI 1 "register_operand" "r,r")))]
  ""
  "cmp%e2.%s0 %0,%1" ; The function cris_notice_update_cc knows about
		     ; swapped operands to compares.
  [(set_attr "slottable" "yes,no")])

;; 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")))]
  ""
  "@
   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 "cmphi"
  [(set (cc0)
	(compare (match_operand:HI 0 "nonimmediate_operand" "r,r,Q>,Q>,r,m,m")
		 (match_operand:HI 1 "general_operand" "r,Q>,M,r,g,M,r")))]
  ""
  "@
   cmp.w %1,%0
   cmp.w %1,%0
   test.w %0
   cmp.w %0,%1
   cmp.w %1,%0
   test.w %0
   cmp.w %0,%1"
  [(set_attr "slottable" "yes,yes,yes,yes,no,no,no")])

(define_insn "cmpqi"
  [(set (cc0)
	(compare
	 (match_operand:QI 0 "nonimmediate_operand" "r,r,r,Q>,Q>,r,m,m")
	 (match_operand:QI 1 "general_operand" "r,Q>,M,M,r,g,M,r")))]
  ""
  "@
   cmp.b %1,%0
   cmp.b %1,%0
   test.b %0
   test.b %0
   cmp.b %0,%1
   cmp.b %1,%0
   test.b %0
   cmp.b %0,%1"
  [(set_attr "slottable" "yes,yes,yes,yes,yes,no,no,no")])

;; Pattern matching the BTST insn.
;; It is useful for "if (i & val)" constructs, where val is an exact
;; power of 2, or if val + 1 is a power of two, where we check for a bunch
;; 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")))]
  ;; 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)
   && (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))"

;; The 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)".
;;
;; 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.
;; GCC should handle that, but it's a matter of easily-added belts while
;; having suspenders.

  "@
   btstq (%1-1),%0
   test.d %0
   btstq %2,%0
   clearf nz
   btst %2,%0
   clearf nz
   cmpq %p0,%2"
 [(set_attr "slottable" "yes")])

;; Move insns.

;; The whole mandatory movdi family is here; expander, "anonymous"
;; recognizer and splitter.  We're forced to have a movdi pattern,
;; although GCC should be able to split it up itself.  Normally it can,
;; but if other insns have DI operands (as is the case here), reload
;; must be able to generate or match a movdi.  many testcases fail at
;; -O3 or -fssa if we don't have this.  FIXME: Fix GCC...  See
;; <URL:http://gcc.gnu.org/ml/gcc-patches/2000-04/msg00104.html>.
;; However, a patch from Richard Kenner (similar to the cause of
;; discussion at the URL above), indicates otherwise.  See
;; <URL:http://gcc.gnu.org/ml/gcc-patches/2000-04/msg00554.html>.
;; The truth has IMO is not been decided yet, so check from time to
;; time by disabling the movdi patterns.

(define_expand "movdi"
  [(set (match_operand:DI 0 "nonimmediate_operand" "")
	(match_operand:DI 1 "general_operand" ""))]
  ""
  "
{
  if (GET_CODE (operands[0]) == MEM && operands[1] != const0_rtx)
    operands[1] = copy_to_mode_reg (DImode, operands[1]);

  /* Some other ports (as of 2001-09-10 for example mcore and romp) also
     prefer to split up constants early, like this.  The testcase in
     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)
      && ! reload_completed
      && ! reload_in_progress)
    {
      rtx insns;
      rtx op0 = operands[0];
      rtx op1 = operands[1];

      start_sequence ();
      emit_move_insn (operand_subword (op0, 0, 1, DImode),
		      operand_subword (op1, 0, 1, DImode));
      emit_move_insn (operand_subword (op0, 1, 1, DImode),
		      operand_subword (op1, 1, 1, DImode));
      insns = get_insns ();
      end_sequence ();

      emit_no_conflict_block (insns, op0, op1, 0, op1);
      DONE;
    }
}")

(define_insn "*movdi_insn"
  [(set (match_operand:DI 0 "nonimmediate_operand" "=r,r,m")
	(match_operand:DI 1 "general_operand" "r,g,rM"))]
  "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_dup 2)]
  "operands[2] = cris_split_movdx (operands);")

;; 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.

;; QImode

(define_insn "*mov_sideqi_biap"
  [(set (match_operand:QI 0 "register_operand" "=r,r")
	(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)"
  "@
   #
   move.%s0 [%4=%3+%1%T2],%0")

;; HImode

(define_insn "*mov_sidehi_biap"
  [(set (match_operand:HI 0 "register_operand" "=r,r")
	(mem:HI (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.%s0 [%4=%3+%1%T2],%0")

;; SImode

(define_insn "*mov_sidesisf_biap"
  [(set (match_operand 0 "register_operand" "=r,r")
	(mem (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)))]
  "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.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.
;; FIXME: These could have anonymous mode for operand 0.

;; QImode

(define_insn "*mov_sideqi"
  [(set (match_operand:QI 0 "register_operand" "=r,r,r")
	(mem:QI
	 (plus:SI (match_operand:SI 1 "cris_bdap_operand" "%r,r,r")
		  (match_operand:SI 2 "cris_bdap_operand" "r>Rn,r,>Rn"))))
   (set (match_operand:SI 3 "register_operand" "=*1,r,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
      && (GET_CODE (operands[2]) != CONST_INT
	  || INTVAL (operands[2]) > 127
	  || INTVAL (operands[2]) < -128
	  || CONST_OK_FOR_LETTER_P (INTVAL (operands[2]), 'N')
	  || CONST_OK_FOR_LETTER_P (INTVAL (operands[2]), 'J')))
    return \"#\";
  return \"move.%s0 [%3=%1%S2],%0\";
}")

;; HImode

(define_insn "*mov_sidehi"
  [(set (match_operand:HI 0 "register_operand" "=r,r,r")
	(mem:HI
	 (plus:SI (match_operand:SI 1 "cris_bdap_operand" "%r,r,r")
		  (match_operand:SI 2 "cris_bdap_operand" "r>Rn,r,>Rn"))))
   (set (match_operand:SI 3 "register_operand" "=*1,r,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
      && (GET_CODE (operands[2]) != CONST_INT
	  || INTVAL (operands[2]) > 127
	  || INTVAL (operands[2]) < -128
	  || CONST_OK_FOR_LETTER_P (INTVAL (operands[2]), 'N')
	  || CONST_OK_FOR_LETTER_P (INTVAL (operands[2]), 'J')))
    return \"#\";
  return \"move.%s0 [%3=%1%S2],%0\";
}")

;; SImode

(define_insn "*mov_sidesisf"
  [(set (match_operand 0 "register_operand" "=r,r,r")
	(mem
	 (plus:SI (match_operand:SI 1 "cris_bdap_operand" "%r,r,r")
		  (match_operand:SI 2 "cris_bdap_operand" "r>Rn,r,>Rn"))))
   (set (match_operand:SI 3 "register_operand" "=*1,r,r")
	(plus:SI (match_dup 1)
		 (match_dup 2)))]
  "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
      && (GET_CODE (operands[2]) != CONST_INT
	  || INTVAL (operands[2]) > 127
	  || INTVAL (operands[2]) < -128
	  || CONST_OK_FOR_LETTER_P (INTVAL (operands[2]), 'N')
	  || CONST_OK_FOR_LETTER_P (INTVAL (operands[2]), 'J')))
    return \"#\";
  return \"move.%s0 [%3=%1%S2],%0\";
}")

;; 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]
;; FIXME: These could have anonymous mode for operand 3.

;; QImode

(define_insn "*mov_sideqi_biap_mem"
  [(set (mem:QI (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:QI 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.%s3 %3,[%4=%2+%0%T1]")

;; HImode

(define_insn "*mov_sidehi_biap_mem"
  [(set (mem:HI (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:HI 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.%s3 %3,[%4=%2+%0%T1]")

;; SImode

(define_insn "*mov_sidesisf_biap_mem"
  [(set (mem (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 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)))]
  "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]")

;; 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]));")

;; move.s rx,[ry=rz+i]
;; FIXME: These could have anonymous mode for operand 2.

;; QImode

(define_insn "*mov_sideqi_mem"
  [(set (mem:QI
	 (plus:SI (match_operand:SI 0 "cris_bdap_operand" "%r,r,r,r")
		  (match_operand:SI 1 "cris_bdap_operand" "r>Rn,r>Rn,r,>Rn")))
	(match_operand:QI 2 "register_operand" "r,r,r,r"))
   (set (match_operand:SI 3 "register_operand" "=*0,!2,r,r")
	(plus:SI (match_dup 0)
		 (match_dup 1)))]
  "cris_side_effect_mode_ok (PLUS, operands, 3, 0, 1, -1, 2)"
  "*
{
  if (which_alternative == 0
      && (GET_CODE (operands[1]) != CONST_INT
	  || INTVAL (operands[1]) > 127
	  || INTVAL (operands[1]) < -128
	  || CONST_OK_FOR_LETTER_P (INTVAL (operands[1]), 'N')
	  || CONST_OK_FOR_LETTER_P (INTVAL (operands[1]), 'J')))
    return \"#\";
  if (which_alternative == 1)
    return \"#\";
  return \"move.%s2 %2,[%3=%0%S1]\";
}")

;; HImode

(define_insn "*mov_sidehi_mem"
  [(set (mem:HI
	 (plus:SI (match_operand:SI 0 "cris_bdap_operand" "%r,r,r,r")
		  (match_operand:SI 1 "cris_bdap_operand" "r>Rn,r>Rn,r,>Rn")))
	(match_operand:HI 2 "register_operand" "r,r,r,r"))
   (set (match_operand:SI 3 "register_operand" "=*0,!2,r,r")
	(plus:SI (match_dup 0)
		 (match_dup 1)))]
  "cris_side_effect_mode_ok (PLUS, operands, 3, 0, 1, -1, 2)"
  "*
{
  if (which_alternative == 0
      && (GET_CODE (operands[1]) != CONST_INT
	  || INTVAL (operands[1]) > 127
	  || INTVAL (operands[1]) < -128
	  || CONST_OK_FOR_LETTER_P (INTVAL (operands[1]), 'N')
	  || CONST_OK_FOR_LETTER_P (INTVAL (operands[1]), 'J')))
    return \"#\";
  if (which_alternative == 1)
    return \"#\";
  return \"move.%s2 %2,[%3=%0%S1]\";
}")

;; SImode

(define_insn "*mov_sidesisf_mem"
  [(set (mem
	 (plus:SI (match_operand:SI 0 "cris_bdap_operand" "%r,r,r,r")
		  (match_operand:SI 1 "cris_bdap_operand" "r>Rn,r>Rn,r,>Rn")))
	(match_operand 2 "register_operand" "r,r,r,r"))
   (set (match_operand:SI 3 "register_operand" "=*0,!2,r,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
      && (GET_CODE (operands[1]) != CONST_INT
	  || INTVAL (operands[1]) > 127
	  || INTVAL (operands[1]) < -128
	  || CONST_OK_FOR_LETTER_P (INTVAL (operands[1]), 'N')
	  || CONST_OK_FOR_LETTER_P (INTVAL (operands[1]), 'J')))
    return \"#\";
  if (which_alternative == 1)
    return \"#\";
  return \"move.%s2 %2,[%3=%0%S1]\";
}")

;; 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)))]
  "")

;; 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.d [ry=rx+rw.s2]

(define_insn "*clear_sidesi_biap"
  [(set (mem:SI (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.d [%3=%2+%0%T1]")

;; clear.d [ry=rz+i]

(define_insn "*clear_sidesi"
  [(set (mem:SI
	 (plus:SI (match_operand:SI 0 "cris_bdap_operand" "%r,r,r")
		  (match_operand:SI 1 "cris_bdap_operand" "r>Rn,r,>Rn")))
	(const_int 0))
   (set (match_operand:SI 2 "register_operand" "=*0,r,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
      && (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 \"#\";
  return \"clear.d [%2=%0%S1]\";
}")

;;  clear.w [ry=rx+rw.s2]

(define_insn "*clear_sidehi_biap"
  [(set (mem:HI (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.w [%3=%2+%0%T1]")

;; clear.w [ry=rz+i]

(define_insn "*clear_sidehi"
  [(set (mem:HI
	 (plus:SI (match_operand:SI 0 "cris_bdap_operand" "%r,r,r")
		  (match_operand:SI 1 "cris_bdap_operand" "r>Rn,r,>Rn")))
	(const_int 0))
   (set (match_operand:SI 2 "register_operand" "=*0,r,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
      && (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 \"#\";
  return \"clear.w [%2=%0%S1]\";
}")

;;  clear.b [ry=rx+rw.s2]

(define_insn "*clear_sideqi_biap"
  [(set (mem:QI (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.b [%3=%2+%0%T1]")

;; clear.b [ry=rz+i]

(define_insn "*clear_sideqi"
  [(set (mem:QI
	 (plus:SI (match_operand:SI 0 "cris_bdap_operand" "%r,r,r")
		  (match_operand:SI 1 "cris_bdap_operand" "r>Rn,r,>Rn")))
	(const_int 0))
   (set (match_operand:SI 2 "register_operand" "=*0,r,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
      && (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 \"#\";
  return \"clear.b [%2=%0%S1]\";
}")

;; To appease testcase gcc.c-torture/execute/920501-2.c (and others) at
;; -O0, we need a movdi as a temporary measure.  Here's how things fail:
;;  A cmpdi RTX needs reloading (global):
;;    (insn 185 326 186 (set (cc0)
;;	    (compare (mem/f:DI (reg/v:SI 22) 0)
;;		(const_int 1 [0x1]))) 4 {cmpdi} (nil)
;;	(nil))
;; Now, reg 22 is reloaded for input address, and the mem is also moved
;; out of the instruction (into a register), since one of the operands
;; must be a register.  Reg 22 is reloaded (into reg 10), and the mem is
;; moved out and synthesized in SImode parts (reg 9, reg 10 - should be ok
;; wrt. overlap).  The bad things happen with the synthesis in
;; emit_move_insn_1; the location where to substitute reg 10 is lost into
;; two new RTX:es, both still having reg 22.  Later on, the left-over reg
;; 22 is recognized to have an equivalent in memory which is substituted
;; straight in, and we end up with an unrecognizable insn:
;;    (insn 325 324 326 (set (reg:SI 9 r9)
;;    	      (mem/f:SI (mem:SI (plus:SI (reg:SI 8 r8)
;;    			  (const_int -84 [0xffffffac])) 0) 0)) -1 (nil)
;;    	  (nil))
;; which is the first part of the reloaded synthesized "movdi".
;;  The right thing would be to add equivalent replacement locations for
;; insn with pseudos that need more reloading.  The question is where.

;; 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" ""))]
  ""
  "
{
  /* If the output goes to a MEM, make sure we have zero or a register as
     input.  */
  if (GET_CODE (operands[0]) == MEM
      && ! REG_S_P (operands[1])
      && operands[1] != const0_rtx
      && ! no_new_pseudos)
    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_symbol (operands[1]))
    {
      /* We must have a register as destination for what we're about to
	 do, and for the patterns we generate.  */
      if (! REG_S_P (operands[0]))
	{
	  if (no_new_pseudos)
	    abort ();
	  operands[1] = force_reg (SImode, operands[1]);
	}
      else
	{
	  /* Mark a needed PIC setup for a LABEL_REF:s coming in here:
	     they are so rare not-being-branch-targets that we don't mark
	     a function as needing PIC setup just because we have
	     inspected LABEL_REF:s as operands.  It is only in
	     __builtin_setjmp and such that we can get a LABEL_REF
	     assigned to a register.  */
	  if (GET_CODE (operands[1]) == LABEL_REF)
	    current_function_uses_pic_offset_table = 1;

	  /* We don't have to do anything for global PIC operands; they
	     look just like ``[rPIC+sym]''.  */
	  if (! cris_got_symbol (operands[1])
	      /* We don't do anything for local PIC operands; we match
		 that with a special alternative.  */
	      && ! cris_gotless_symbol (operands[1]))
	    {
	      /* 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 sym = get_related_value (operands[1]);
	      HOST_WIDE_INT offs = get_integer_term (operands[1]);

	      if (sym == NULL_RTX || offs == 0)
		abort ();
	      emit_move_insn (operands[0], sym);
	      if (expand_binop (SImode, add_optab, operands[0],
				GEN_INT (offs), operands[0], 0,
				OPTAB_LIB_WIDEN) != operands[0])
		abort ();
	      DONE;
	    }
	}
    }
}")

(define_insn "*movsi_internal"
  [(set
    (match_operand:SI 0 "nonimmediate_operand" "=r,r,r,Q>,r,Q>,g,r,r,r,g")
    (match_operand:SI 1
    ;; FIXME: We want to put S last, but apparently g matches S.
    ;; It's a bug: an S is not a general_operand and shouldn't match g.
     "cris_general_operand_or_gotless_symbol" "r,Q>,M,M,I,r,M,n,!S,g,r"))]
  ""
  "*
{
  /* 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
     letters.  FIXME: Check again.  It seems this could shrink a bit.  */
  switch (which_alternative)
    {
    case 0:
    case 1:
    case 5:
    case 9:
    case 10:
      return \"move.d %1,%0\";

    case 2:
    case 3:
    case 6:
      return \"clear.d %0\";

      /* Constants -32..31 except 0.  */
    case 4:
      return \"moveq %1,%0\";

      /* We can win a little on constants -32768..-33, 32..65535.  */
    case 7:
      if (INTVAL (operands[1]) > 0 && INTVAL (operands[1]) < 65536)
	{
	  if (INTVAL (operands[1]) < 256)
	    return \"movu.b %1,%0\";
	  return \"movu.w %1,%0\";
	}
      else if (INTVAL (operands[1]) >= -32768 && INTVAL (operands[1]) < 32768)
	{
	  if (INTVAL (operands[1]) >= -128 && INTVAL (operands[1]) < 128)
	    return \"movs.b %1,%0\";
	  return \"movs.w %1,%0\";
	}
      return \"move.d %1,%0\";

      case 8:
	/* FIXME: Try and split this into pieces GCC makes better code of,
	   than this multi-insn pattern.  Synopsis: wrap the GOT-relative
	   symbol into an unspec, and when PIC, recognize the unspec
	   everywhere a symbol is normally recognized.  (The PIC register
	   should be recognized by GCC as pic_offset_table_rtx when needed
	   and similar for PC.)  Each component can then be optimized with
	   the rest of the code; it should be possible to have a constant
	   term added on an unspec.  Don't forget to add a REG_EQUAL (or
	   is it REG_EQUIV) note to the destination.  It might not be
	   worth it.  Measure.

	   Note that the 'v' modifier makes PLT references be output as
	   sym:PLT rather than [rPIC+sym:GOTPLT].  */
	return \"move.d %v1,%0\;add.d %P1,%0\";

    default:
      return \"BOGUS: %1 to %0\";
    }
}"
  [(set_attr "slottable" "yes,yes,yes,yes,yes,yes,no,no,no,no,no")])

;; 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")

;; QImode to SImode

(define_insn "*ext_sideqisi_biap"
  [(set (match_operand:SI 0 "register_operand" "=r,r")
	(match_operator:SI
	 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")

;; HImode to SImode

(define_insn "*ext_sidehisi_biap"
  [(set (match_operand:SI 0 "register_operand" "=r,r")
	(match_operator:SI
	 5 "cris_extend_operator"
	 [(mem:HI (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")

;; Same but [rx=ry+i]

;; QImode to HImode

(define_insn "*ext_sideqihi"
  [(set (match_operand:HI 0 "register_operand" "=r,r,r")
	(match_operator:HI
	 4 "cris_extend_operator"
	 [(mem:QI (plus:SI
		   (match_operand:SI 1 "cris_bdap_operand" "%r,r,r")
		   (match_operand:SI 2 "cris_bdap_operand" "r>Rn,r,>Rn")))]))
   (set (match_operand:SI 3 "register_operand" "=*1,r,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
      && (GET_CODE (operands[2]) != CONST_INT
	  || INTVAL (operands[2]) > 127
	  || INTVAL (operands[2]) < -128
	  || CONST_OK_FOR_LETTER_P (INTVAL (operands[2]), 'N')
	  || CONST_OK_FOR_LETTER_P (INTVAL (operands[2]), 'J')))
    return \"#\";
  return \"mov%e4.%m4 [%3=%1%S2],%0\";
}")

;; QImode to SImode

(define_insn "*ext_sideqisi"
  [(set (match_operand:SI 0 "register_operand" "=r,r,r")
	(match_operator:SI
	 4 "cris_extend_operator"
	 [(mem:QI (plus:SI
		   (match_operand:SI 1 "cris_bdap_operand" "%r,r,r")
		   (match_operand:SI 2 "cris_bdap_operand" "r>Rn,r,>Rn")))]))
   (set (match_operand:SI 3 "register_operand" "=*1,r,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
      && (GET_CODE (operands[2]) != CONST_INT
	  || INTVAL (operands[2]) > 127
	  || INTVAL (operands[2]) < -128
	  || CONST_OK_FOR_LETTER_P (INTVAL (operands[2]), 'N')
	  || CONST_OK_FOR_LETTER_P (INTVAL (operands[2]), 'J')))
    return \"#\";
  return \"mov%e4.%m4 [%3=%1%S2],%0\";
}")

;; HImode to SImode

(define_insn "*ext_sidehisi"
  [(set (match_operand:SI 0 "register_operand" "=r,r,r")
	(match_operator:SI
	 4 "cris_extend_operator"
	 [(mem:HI (plus:SI
		   (match_operand:SI 1 "cris_bdap_operand" "%r,r,r")
		   (match_operand:SI 2 "cris_bdap_operand" "r>Rn,r,>Rn")))]))
   (set (match_operand:SI 3 "register_operand" "=*1,r,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
      && (GET_CODE (operands[2]) != CONST_INT
	  || INTVAL (operands[2]) > 127
	  || INTVAL (operands[2]) < -128
	  || CONST_OK_FOR_LETTER_P (INTVAL (operands[2]), 'N')
	  || CONST_OK_FOR_LETTER_P (INTVAL (operands[2]), 'J')))
    return \"#\";
  return \"mov%e4.%m4 [%3=%1%S2],%0\";
}")

;; FIXME: See movsi.

(define_insn "movhi"
  [(set
    (match_operand:HI 0 "nonimmediate_operand" "=r,r,r,Q>,r,Q>,r,r,r,g,g,r")
    (match_operand:HI 1 "general_operand" "r,Q>,M,M,I,r,L,O,n,M,r,g"))]
  ""
  "*
{
  switch (which_alternative)
    {
    case 0:
    case 1:
    case 5:
    case 10:
    case 11:
      return \"move.w %1,%0\";
    case 2:
    case 3:
    case 9:
      return \"clear.w %0\";
    case 4:
      return \"moveq %1,%0\";
    case 6:
    case 8:
      if (INTVAL (operands[1]) < 256 && INTVAL (operands[1]) >= -128)
	{
	  if (INTVAL (operands[1]) > 0)
	    return \"movu.b %1,%0\";
	  return \"movs.b %1,%0\";
	}
      return \"move.w %1,%0\";
    case 7:
      return \"movEq %b1,%0\";
    default:
      return \"BOGUS: %1 to %0\";
  }
}"
  [(set_attr "slottable" "yes,yes,yes,yes,yes,yes,no,yes,no,no,no,no")
   (set (attr "cc")
	(if_then_else (eq_attr "alternative" "7")
		      (const_string "clobber")
		      (const_string "normal")))])

(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"))]
  ""
  "@
   move.w %1,%0
   move.w %1,%0
   clear.w %0
   clear.w %0
   move.w %1,%0
   clear.w %0
   move.w %1,%0
   move.w %1,%0"
  [(set_attr "slottable" "yes,yes,yes,yes,yes,no,no,no")])

(define_insn "movqi"
  [(set (match_operand:QI 0 "nonimmediate_operand" "=r,Q>,r,r,Q>,r,g,g,r,r")
	(match_operand:QI 1 "general_operand" "r,r,Q>,M,M,I,M,r,O,g"))]
  ""
  "@
   move.b %1,%0
   move.b %1,%0
   move.b %1,%0
   clear.b %0
   clear.b %0
   moveq %1,%0
   clear.b %0
   move.b %1,%0
   moveq %b1,%0
   move.b %1,%0"
  [(set_attr "slottable" "yes,yes,yes,yes,yes,yes,no,no,yes,no")
   (set (attr "cc")
	(if_then_else (eq_attr "alternative" "8")
		      (const_string "clobber")
		      (const_string "normal")))])

(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"))]
  ""
  "@
   move.b %1,%0
   move.b %1,%0
   move.b %1,%0
   clear.b %0
   clear.b %0
   clear.b %0
   move.b %1,%0
   move.b %1,%0"
  [(set_attr "slottable" "yes,yes,yes,yes,yes,no,no,no")])

;; The valid "quick" bit-patterns are, except for 0.0, denormalized
;; values REALLY close to 0, and some NaN:s (I think; their exponent is
;; all ones); the worthwhile one is "0.0".
;; It will use clear, so we know ALL types of immediate 0 never change cc.

(define_insn "movsf"
  [(set (match_operand:SF 0 "nonimmediate_operand" "=r,Q>,r,r,Q>,g,g,r")
	(match_operand:SF 1 "general_operand" "r,r,Q>,G,G,G,r,g"))]
  ""
  "@
   move.d %1,%0
   move.d %1,%0
   move.d %1,%0
   clear.d %0
   clear.d %0
   clear.d %0
   move.d %1,%0
   move.d %1,%0"
  [(set_attr "slottable" "yes,yes,yes,yes,yes,no,no,no")])


;; Sign- and zero-extend insns with standard names.
;;  Those for integer source operand are ordered with the widest source
;; type first.

;; Sign-extend.

(define_insn "extendsidi2"
  [(set (match_operand:DI 0 "register_operand" "=r")
	(sign_extend:DI (match_operand:SI 1 "general_operand" "g")))]
  ""
  "move.d %1,%M0\;smi %H0\;neg.d %H0,%H0")

(define_insn "extendhidi2"
  [(set (match_operand:DI 0 "register_operand" "=r")
	(sign_extend:DI (match_operand:HI 1 "general_operand" "g")))]
  ""
  "movs.w %1,%M0\;smi %H0\;neg.d %H0,%H0")

(define_insn "extendhisi2"
  [(set (match_operand:SI 0 "register_operand" "=r,r,r")
	(sign_extend:SI (match_operand:HI 1 "general_operand" "r,Q>,g")))]
  ""
  "movs.w %1,%0"
  [(set_attr "slottable" "yes,yes,no")])

(define_insn "extendqidi2"
  [(set (match_operand:DI 0 "register_operand" "=r")
	(sign_extend:DI (match_operand:QI 1 "general_operand" "g")))]
  ""
  "movs.b %1,%M0\;smi %H0\;neg.d %H0,%H0")

(define_insn "extendqisi2"
  [(set (match_operand:SI 0 "register_operand" "=r,r,r")
	(sign_extend:SI (match_operand:QI 1 "general_operand" "r,Q>,g")))]
  ""
  "movs.b %1,%0"
  [(set_attr "slottable" "yes,yes,no")])

;; To do a byte->word extension, extend to dword, exept that the top half
;; of the register will be clobbered.  FIXME: Perhaps this is not needed.

(define_insn "extendqihi2"
  [(set (match_operand:HI 0 "register_operand" "=r,r,r")
	(sign_extend:HI (match_operand:QI 1 "general_operand" "r,Q>,g")))]
  ""
  "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_extendhisi2"
  [(set (match_operand:SI 0 "register_operand" "=r,r,r")
	(zero_extend:SI
	 (match_operand:HI 1 "nonimmediate_operand" "r,Q>,m")))]
  ""
  "movu.w %1,%0"
  [(set_attr "slottable" "yes,yes,no")])

(define_insn "zero_extendqisi2"
  [(set (match_operand:SI 0 "register_operand" "=r,r,r")
	(zero_extend:SI
	 (match_operand:QI 1 "nonimmediate_operand" "r,Q>,m")))]
  ""
  "movu.b %1,%0"
  [(set_attr "slottable" "yes,yes,no")])

;; Same comment as sign-extend QImode to HImode above applies.

(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")))]
  ""
  "movu.b %1,%0"
  [(set_attr "slottable" "yes,yes,no")])

;; 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]
;; FIXME: These could have anonymous mode for operand 0.

;; QImode

(define_insn "*op_sideqi_biap"
  [(set (match_operand:QI 0 "register_operand" "=r,r")
	(match_operator:QI
	 6 "cris_orthogonal_operator"
	 [(match_operand:QI 1 "register_operand" "0,0")
	  (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.%s0 [%5=%4+%2%T3],%0")

;; HImode

(define_insn "*op_sidehi_biap"
  [(set (match_operand:HI 0 "register_operand" "=r,r")
	(match_operator:HI
	 6 "cris_orthogonal_operator"
	 [(match_operand:HI 1 "register_operand" "0,0")
	  (mem:HI (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.%s0 [%5=%4+%2%T3],%0")

;; SImode

(define_insn "*op_sidesi_biap"
  [(set (match_operand:SI 0 "register_operand" "=r,r")
	(match_operator:SI
	 6 "cris_orthogonal_operator"
	 [(match_operand:SI 1 "register_operand" "0,0")
	  (mem:SI (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.%s0 [%5=%4+%2%T3],%0")

;; [rx=ry+i] ([%4=%2+%3])
;; FIXME: These could have anonymous mode for operand 0.

;; QImode

(define_insn "*op_sideqi"
  [(set (match_operand:QI 0 "register_operand" "=r,r,r")
	(match_operator:QI
	 5 "cris_orthogonal_operator"
	 [(match_operand:QI 1 "register_operand" "0,0,0")
	  (mem:QI (plus:SI
		   (match_operand:SI 2 "cris_bdap_operand" "%r,r,r")
		   (match_operand:SI 3 "cris_bdap_operand" "r>Rn,r,>Rn")))]))
   (set (match_operand:SI 4 "register_operand" "=*2,r,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
      && (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 \"#\";
  return \"%x5.%s0 [%4=%2%S3],%0\";
}")

;; HImode

(define_insn "*op_sidehi"
  [(set (match_operand:HI 0 "register_operand" "=r,r,r")
	(match_operator:HI
	 5 "cris_orthogonal_operator"
	 [(match_operand:HI 1 "register_operand" "0,0,0")
	  (mem:HI (plus:SI
		   (match_operand:SI 2 "cris_bdap_operand" "%r,r,r")
		   (match_operand:SI 3 "cris_bdap_operand" "r>Rn,r,>Rn")))]))
   (set (match_operand:SI 4 "register_operand" "=*2,r,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
      && (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 \"#\";
  return \"%x5.%s0 [%4=%2%S3],%0\";
}")

;; SImode

(define_insn "*op_sidesi"
  [(set (match_operand:SI 0 "register_operand" "=r,r,r")
	(match_operator:SI
	 5 "cris_orthogonal_operator"
	 [(match_operand:SI 1 "register_operand" "0,0,0")
	  (mem:SI (plus:SI
		   (match_operand:SI 2 "cris_bdap_operand" "%r,r,r")
		   (match_operand:SI 3 "cris_bdap_operand" "r>Rn,r,>Rn")))]))
   (set (match_operand:SI 4 "register_operand" "=*2,r,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
      && (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 \"#\";
  return \"%x5.%s0 [%4=%2%S3],%0\";
}")

;; 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]
;; FIXME: These could have anonymous mode for operand 0.

;; QImode

(define_insn "*op_swap_sideqi_biap"
  [(set (match_operand:QI 0 "register_operand" "=r,r")
	(match_operator:QI
	 6 "cris_commutative_orth_op"
	 [(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:QI 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.%s0 [%5=%4+%2%T3],%0")

;; HImode

(define_insn "*op_swap_sidehi_biap"
  [(set (match_operand:HI 0 "register_operand" "=r,r")
	(match_operator:HI
	 6 "cris_commutative_orth_op"
	 [(mem:HI (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)"
  "@
   #
   %x6.%s0 [%5=%4+%2%T3],%0")

;; SImode

(define_insn "*op_swap_sidesi_biap"
  [(set (match_operand:SI 0 "register_operand" "=r,r")
	(match_operator:SI
	 6 "cris_commutative_orth_op"
	 [(mem:SI (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)))]
  "cris_side_effect_mode_ok (MULT, operands, 5, 4, 2, 3, 0)"
  "@
   #
   %x6.%s0 [%5=%4+%2%T3],%0")

;; [rx=ry+i] ([%4=%2+%3])
;; FIXME: These could have anonymous mode for operand 0.

;; QImode

(define_insn "*op_swap_sideqi"
  [(set (match_operand:QI 0 "register_operand" "=r,r,r")
	(match_operator:QI
	 5 "cris_commutative_orth_op"
	 [(mem:QI
	   (plus:SI (match_operand:SI 2 "cris_bdap_operand" "%r,r,r")
		    (match_operand:SI 3 "cris_bdap_operand" "r>Rn,r,>Rn")))
	  (match_operand:QI 1 "register_operand" "0,0,0")]))
   (set (match_operand:SI 4 "register_operand" "=*2,r,r")
	(plus:SI (match_dup 2)
		 (match_dup 3)))]
  "cris_side_effect_mode_ok (PLUS, operands, 4, 2, 3, -1, 0)"
  "*
{
  if (which_alternative == 0
      && (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 \"#\";
  return \"%x5.%s0 [%4=%2%S3],%0\";
}")

;; HImode

(define_insn "*op_swap_sidehi"
  [(set (match_operand:HI 0 "register_operand" "=r,r,r")
	(match_operator:HI
	 5 "cris_commutative_orth_op"
	 [(mem:HI
	   (plus:SI (match_operand:SI 2 "cris_bdap_operand" "%r,r,r")
		    (match_operand:SI 3 "cris_bdap_operand" "r>Rn,r,>Rn")))
	  (match_operand:HI 1 "register_operand" "0,0,0")]))
   (set (match_operand:SI 4 "register_operand" "=*2,r,r")
	(plus:SI (match_dup 2)
		 (match_dup 3)))]
  "cris_side_effect_mode_ok (PLUS, operands, 4, 2, 3, -1, 0)"
  "*
{
  if (which_alternative == 0
      && (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 \"#\";
  return \"%x5.%s0 [%4=%2%S3],%0\";
}")

;; SImode

(define_insn "*op_swap_sidesi"
  [(set (match_operand:SI 0 "register_operand" "=r,r,r")
	(match_operator:SI
	 5 "cris_commutative_orth_op"
	 [(mem:SI
	   (plus:SI (match_operand:SI 2 "cris_bdap_operand" "%r,r,r")
		    (match_operand:SI 3 "cris_bdap_operand" "r>Rn,r,>Rn")))
	  (match_operand:SI 1 "register_operand" "0,0,0")]))
   (set (match_operand:SI 4 "register_operand" "=*2,r,r")
	(plus:SI (match_dup 2)
		 (match_dup 3)))]
  "cris_side_effect_mode_ok (PLUS, operands, 4, 2, 3, -1, 0)"
  "*
{
  if (which_alternative == 0
      && (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 \"#\";
  return \"%x5.%s0 [%4=%2%S3],%0\";
}")

;; 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"
  [(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")))]
  ""
  "@
   addq %2,%M0\;ax\;addq 0,%H0
   subq %n2,%M0\;ax\;subq 0,%H0
   add%e2.%z2 %2,%M0\;ax\;%A2 %H2,%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")
	(plus:SI
	 (match_operand:SI 1 "register_operand" "%0,0,0,0,0,0,r,r")
	 (match_operand:SI 2 "general_operand" "r,Q>,J,N,n,g,!To,0")))]

;; 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

 ""
 "*
{
  switch (which_alternative)
    {
    case 0:
    case 1:
      return \"add.d %2,%0\";
    case 2:
      return \"addq %2,%0\";
    case 3:
      return \"subq %n2,%0\";
    case 4:
      /* 'Known value', but not in -63..63.
	 Check if addu/subu may be used.  */
      if (INTVAL (operands[2]) > 0)
	{
	  if (INTVAL (operands[2]) < 256)
	    return \"addu.b %2,%0\";
	  if (INTVAL (operands[2]) < 65536)
	    return \"addu.w %2,%0\";
	}
      else
	{
	  if (INTVAL (operands[2]) >= -255)
	    return \"subu.b %n2,%0\";
	  if (INTVAL (operands[2]) >= -65535)
	    return \"subu.w %n2,%0\";
	}
      return \"add.d %2,%0\";
    case 6:
      return \"add.d %2,%1,%0\";
    case 5:
      return \"add.d %2,%0\";
    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,yes")])

(define_insn "addhi3"
  [(set (match_operand:HI 0 "register_operand" "=r,r,r,r,r,r")
	(plus:HI (match_operand:HI 1 "register_operand" "%0,0,0,0,0,r")
		 (match_operand:HI 2 "general_operand" "r,Q>,J,N,g,!To")))]
  ""
  "@
   add.w %2,%0
   add.w %2,%0
   addq %2,%0
   subq %n2,%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")])

(define_insn "addqi3"
  [(set (match_operand:QI 0 "register_operand" "=r,r,r,r,r,r,r")
	(plus:QI (match_operand:QI 1 "register_operand" "%0,0,0,0,0,0,r")
		 (match_operand:QI 2 "general_operand" "r,Q>,J,N,O,g,!To")))]
  ""
  "@
   add.b %2,%0
   add.b %2,%0
   addq %2,%0
   subq %n2,%0
   subQ -%b2,%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")])

;; Subtract.
;;
;; Note that because of insn canonicalization these will *seldom* but
;; rarely be used with a known constant as an operand.

;; 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"
  [(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")))]
  ""
  "@
   subq %2,%M0\;ax\;subq 0,%H0
   addq %n2,%M0\;ax\;addq 0,%H0
   sub%e2.%z2 %2,%M0\;ax\;%D2 %H2,%H0
   sub.d %M2,%M0\;ax\;sub.d %H2,%H0
   sub.d %M2,%M1,%M0\;ax\;sub.d %H2,%H1,%H0")

(define_insn "subsi3"
  [(set (match_operand:SI 0 "register_operand" "=r,r,r,r,r,r,r,r")
	(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")))]
  ""

;; This does not do the optimal: "addu.w 65535,r0" when %2 is negative.
;; But then again, %2 should not be negative.

  "@
   sub.d %2,%0
   sub.d %2,%0
   subq %2,%0
   addq %n2,%0
   sub%e2.%z2 %2,%0
   sub.d %2,%0
   sub.d %2,%0
   sub.d %2,%1,%0"
  [(set_attr "slottable" "yes,yes,yes,yes,no,no,no,no")])

(define_insn "subhi3"
  [(set (match_operand:HI 0 "register_operand" "=r,r,r,r,r,r")
	(minus:HI (match_operand:HI 1 "register_operand" "0,0,0,0,0,r")
		  (match_operand:HI 2 "general_operand" "r,Q>,J,N,g,!To")))]
  ""
  "@
   sub.w %2,%0
   sub.w %2,%0
   subq %2,%0
   addq %n2,%0
   sub.w %2,%0
   sub.w %2,%1,%0"
  [(set_attr "slottable" "yes,yes,yes,yes,no,no")
   (set_attr "cc" "normal,normal,clobber,clobber,normal,normal")])

(define_insn "subqi3"
  [(set (match_operand:QI 0 "register_operand" "=r,r,r,r,r,r")
	(minus:QI (match_operand:QI 1 "register_operand" "0,0,0,0,0,r")
		  (match_operand:QI 2 "general_operand" "r,Q>,J,N,g,!To")))]
  ""
  "@
   sub.b %2,%0
   sub.b %2,%0
   subq %2,%0
   addq %2,%0
   sub.b %2,%0
   sub.b %2,%1,%0"
  [(set_attr "slottable" "yes,yes,yes,yes,no,no")
   (set_attr "cc" "normal,normal,clobber,clobber,normal,normal")])

;; 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]
;; FIXME: These could have anonymous mode for operand 0.

;; 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")

;; QImode to SImode

(define_insn "*extopqisi_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: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)))]
  "(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.%m7 [%5=%4+%2%T3],%0")

;; HImode to SImode

(define_insn "*extophisi_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:HI (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.%m7 [%5=%4+%2%T3],%0")


;; [rx=ry+i]
;; FIXME: These could have anonymous mode for operand 0.

;; QImode to HImode

(define_insn "*extopqihi_side"
  [(set (match_operand:HI 0 "register_operand" "=r,r,r")
	(match_operator:HI
	 5 "cris_additive_operand_extend_operator"
	 [(match_operand:HI 1 "register_operand" "0,0,0")
	  (match_operator:HI
	   6 "cris_extend_operator"
	   [(mem:QI
	     (plus:SI (match_operand:SI 2 "cris_bdap_operand" "%r,r,r")
		      (match_operand:SI 3 "cris_bdap_operand" "r>Rn,r,>Rn")
		      ))])]))
   (set (match_operand:SI 4 "register_operand" "=*2,r,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
      && (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 \"#\";
  return \"%x5%e6.%m6 [%4=%2%S3],%0\";
}")

;; QImode to SImode

(define_insn "*extopqisi_side"
  [(set (match_operand:SI 0 "register_operand" "=r,r,r")
	(match_operator:SI
	 5 "cris_operand_extend_operator"
	 [(match_operand:SI 1 "register_operand" "0,0,0")
	  (match_operator:SI
	   6 "cris_extend_operator"
	   [(mem:QI
	     (plus:SI (match_operand:SI 2 "cris_bdap_operand" "%r,r,r")
		      (match_operand:SI 3 "cris_bdap_operand" "r>Rn,r,>Rn")
		      ))])]))
   (set (match_operand:SI 4 "register_operand" "=*2,r,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
      && (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 \"#\";
  return \"%x5%e6.%m6 [%4=%2%S3],%0\";
}")

;; HImode to SImode

(define_insn "*extophisi_side"
  [(set (match_operand:SI 0 "register_operand" "=r,r,r")
	(match_operator:SI
	 5 "cris_operand_extend_operator"
	 [(match_operand:SI 1 "register_operand" "0,0,0")
	  (match_operator:SI
	   6 "cris_extend_operator"
	   [(mem:HI
	     (plus:SI (match_operand:SI 2 "cris_bdap_operand" "%r,r,r")
		      (match_operand:SI 3 "cris_bdap_operand" "r>Rn,r,>Rn")
		      ))])]))
   (set (match_operand:SI 4 "register_operand" "=*2,r,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
      && (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 \"#\";
  return \"%x5%e6.%m6 [%4=%2%S3],%0\";
}")


;; 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")

;; QImode to SImode

(define_insn "*extopqisi_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: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: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.%m6 [%5=%4+%2%T3],%0")

;; HImode to SImode
(define_insn "*extophisi_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:HI (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.%m6 [%5=%4+%2%T3],%0")

;; [rx=ry+i]
;; FIXME: These could have anonymous mode for operand 0.
;; FIXME: GCC should widen.

;; QImode to HImode

(define_insn "*extopqihi_swap_side"
  [(set (match_operand:HI 0 "register_operand" "=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")
		    (match_operand:SI 3 "cris_bdap_operand" "r>Rn,r,>Rn")))])
	 (match_operand:HI 1 "register_operand" "0,0,0")))
   (set (match_operand:SI 4 "register_operand" "=*2,r,r")
	(plus:SI (match_dup 2)
		 (match_dup 3)))]
  "cris_side_effect_mode_ok (PLUS, operands, 4, 2, 3, -1, 0)"
  "*
{
  if (which_alternative == 0
      && (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 \"#\";
  return \"add%e5.b [%4=%2%S3],%0\";
}")

;; QImode to SImode

(define_insn "*extopqisi_swap_side"
  [(set (match_operand:SI 0 "register_operand" "=r,r,r")
	(match_operator:SI
	 6 "cris_plus_or_bound_operator"
	 [(match_operator:SI
	   5 "cris_extend_operator"
	   [(mem:QI (plus:SI
		     (match_operand:SI 2 "cris_bdap_operand" "%r,r,r")
		     (match_operand:SI 3 "cris_bdap_operand" "r>Rn,r,>Rn")))])
	  (match_operand:SI 1 "register_operand" "0,0,0")]))
   (set (match_operand:SI 4 "register_operand" "=*2,r,r")
	(plus:SI (match_dup 2)
		 (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
      && (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 \"#\";
  return \"%x6%e5.%m5 [%4=%2%S3],%0\";
}")

;; HImode to SImode

(define_insn "*extophisi_swap_side"
  [(set (match_operand:SI 0 "register_operand" "=r,r,r")
	(match_operator:SI
	 6 "cris_plus_or_bound_operator"
	 [(match_operator:SI
	   5 "cris_extend_operator"
	   [(mem:HI (plus:SI
		     (match_operand:SI 2 "cris_bdap_operand" "%r,r,r")
		     (match_operand:SI 3 "cris_bdap_operand" "r>Rn,r,>Rn")))])
	  (match_operand:SI 1 "register_operand" "0,0,0")]))
   (set (match_operand:SI 4 "register_operand" "=*2,r,r")
	(plus:SI (match_dup 2)
		 (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
      && (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 \"#\";
  return \"%x6%e5.%m5 [%4=%2%S3],%0\";
}")

;; Extend versions (zero/sign) of normal add/sub (no side-effects).
;; FIXME: These could have anonymous mode for operand 0.

;; QImode to HImode
;; FIXME: GCC should widen.

(define_insn "*extopqihi"
  [(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")])]))]
  "GET_MODE_SIZE (GET_MODE (operands[0])) <= UNITS_PER_WORD
   && (operands[1] != frame_pointer_rtx || GET_CODE (operands[3]) != PLUS)"
  "@
   %x3%e4.%m4 %2,%0
   %x3%e4.%m4 %2,%0
   %x3%e4.%m4 %2,%0
   %x3%e4.%m4 %2,%1,%0"
  [(set_attr "slottable" "yes,yes,no,no")
   (set_attr "cc" "clobber")])

;; QImode to SImode

(define_insn "*extopqisi"
  [(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:QI 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)"
  "@
   %x3%e4.%m4 %2,%0
   %x3%e4.%m4 %2,%0
   %x3%e4.%m4 %2,%0
   %x3%e4.%m4 %2,%1,%0"
  [(set_attr "slottable" "yes,yes,no,no")])

;; HImode to SImode

(define_insn "*extophisi"
  [(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:HI 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)"
  "@
   %x3%e4.%m4 %2,%0
   %x3%e4.%m4 %2,%0
   %x3%e4.%m4 %2,%0
   %x3%e4.%m4 %2,%1,%0"
  [(set_attr "slottable" "yes,yes,no,no")])


;; As with the side-effect patterns, may have to have swapped operands for add.
;; FIXME: *should* be redundant to gcc.

;; QImode to HImode

(define_insn "*extopqihi_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")))]
  "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"
  [(set_attr "slottable" "yes,yes,no,no")
   (set_attr "cc" "clobber")])

;; QImode to SImode

(define_insn "*extopqisi_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:QI 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)
   && operands[1] != frame_pointer_rtx"
  "@
   %x4%e3.%m3 %2,%0
   %x4%e3.%m3 %2,%0
   %x4%e3.%m3 %2,%0
   %x4%e3.%m3 %2,%1,%0"
  [(set_attr "slottable" "yes,yes,no,no")])

;; HImode to SImode

(define_insn "*extophisi_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:HI 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)
   && operands[1] != frame_pointer_rtx"
  "@
   %x4%e3.%m3 %2,%0
   %x4%e3.%m3 %2,%0
   %x4%e3.%m3 %2,%0
   %x4%e3.%m3 %2,%1,%0"
  [(set_attr "slottable" "yes,yes,no,no")])

;; This is the special case when we use what corresponds to the
;; instruction above in "casesi".  Do *not* change it to use the generic
;; pattern and "REG 15" as pc; I did that and it led to madness and
;; maintenance problems: Instead of (as imagined) recognizing and removing
;; or replacing this pattern with something simpler, other variant
;; patterns were recognized or combined, including some prefix variants
;; where the value in pc is not that of the next instruction (which means
;; this instruction actually *is* special and *should* be marked as such).
;; When switching from the "generic pattern match" approach to this simpler
;; approach, there were insignificant differences in gcc, ipps and
;; product code, somehow due to scratching reload behind the ear or
;; something.  Testcase "gcc" looked .01% slower and 4 bytes bigger;
;; product code became .001% smaller but "looked better".  The testcase
;; "ipps" was just different at register allocation).
;;
;; Assumptions in the jump optimizer forces us to use IF_THEN_ELSE in this
;; pattern with the default-label as the else, with the "if" being
;; index-is-less-than the max number of cases plus one.  The default-label
;; is attached to the end of the case-table at time of output.

(define_insn "*casesi_adds_w"
  [(set (pc)
	(if_then_else
	 (ltu (match_operand:SI 0 "register_operand" "r")
	      (match_operand:SI 1 "const_int_operand" "n"))
	 (plus:SI (sign_extend:SI
		   (mem:HI
		    (plus:SI (mult:SI (match_dup 0) (const_int 2))
			     (pc))))
		  (pc))
	 (label_ref (match_operand 2 "" ""))))
   (use (label_ref (match_operand 3 "" "")))]

  "operands[0] != frame_pointer_rtx"

  "adds.w [$pc+%0.w],$pc"
  [(set_attr "cc" "clobber")])

;; Multiply instructions.

;; Sometimes powers of 2 (which are normally canonicalized to a
;; left-shift) appear here, as a result of address reloading.
;; As a special, for values 3 and 5, we can match with an addi, so add those.
;;
;; FIXME: This may be unnecessary now.
;; Explicitly named for convenience of having a gen_... function.

(define_insn "addi_mul"
  [(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")))]
  "operands[0] != frame_pointer_rtx
   && operands[1] != frame_pointer_rtx
   && GET_CODE (operands[2]) == CONST_INT
   && (INTVAL (operands[2]) == 2
       || INTVAL (operands[2]) == 4 || INTVAL (operands[2]) == 3
       || INTVAL (operands[2]) == 5)"
  "*
{
  if (INTVAL (operands[2]) == 2)
    return \"lslq 1,%0\";
  else if (INTVAL (operands[2]) == 4)
    return \"lslq 2,%0\";
  else if (INTVAL (operands[2]) == 3)
    return \"addi %0.w,%0\";
  else if (INTVAL (operands[2]) == 5)
    return \"addi %0.d,%0\";
  return \"BAD: adr_mulsi: %0=%1*%2\";
}"
[(set_attr "slottable" "yes")
 ;; No flags are changed if this insn is "addi", but it does not seem
 ;; worth the trouble to distinguish that to the lslq cases.
 (set_attr "cc" "clobber")])

;; The addi insn as it is normally used.

(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"))
	 (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)"
  "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"
  [(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))))]
  ""
  "mstep %2,%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.

(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")])

(define_insn "umulhisi3"
  [(set (match_operand:SI 0 "register_operand" "=r")
	(mult:SI
	 (zero_extend:SI (match_operand:HI 1 "register_operand" "%0"))
	 (zero_extend:SI (match_operand:HI 2 "register_operand" "r"))))]
  "TARGET_HAS_MUL_INSNS"
  "%!mulu.w %2,%0"
  [(set (attr "slottable")
	(if_then_else (ne (symbol_ref "TARGET_MUL_BUG") (const_int 0))
		      (const_string "no")
		      (const_string "yes")))
   ;; Just N unusable here, but let's be safe.
   (set_attr "cc" "clobber")])

(define_insn "umulqihi3"
  [(set (match_operand:HI 0 "register_operand" "=r")
	(mult:HI
	 (zero_extend:HI (match_operand:QI 1 "register_operand" "%0"))
	 (zero_extend:HI (match_operand:QI 2 "register_operand" "r"))))]
  "TARGET_HAS_MUL_INSNS"
  "%!mulu.b %2,%0"
  [(set (attr "slottable")
	(if_then_else (ne (symbol_ref "TARGET_MUL_BUG") (const_int 0))
		      (const_string "no")
		      (const_string "yes")))
   ;; Not exactly sure, but let's be safe.
   (set_attr "cc" "clobber")])

;; Note that gcc does not make use of such a thing as umulqisi3.  It gets
;; confused and will erroneously use it instead of umulhisi3, failing (at
;; least) gcc.c-torture/execute/arith-rand.c at all optimization levels.
;; Inspection of optab code shows that there must be only one widening
;; multiplication per mode widened to.

(define_insn "mulsi3"
  [(set (match_operand:SI 0 "register_operand" "=r")
	(mult:SI (match_operand:SI 1 "register_operand" "%0")
		 (match_operand:SI 2 "register_operand" "r")))]
  "TARGET_HAS_MUL_INSNS"
  "%!muls.d %2,%0"
  [(set (attr "slottable")
	(if_then_else (ne (symbol_ref "TARGET_MUL_BUG") (const_int 0))
		      (const_string "no")
		      (const_string "yes")))
   ;; Just N unusable here, but let's be safe.
   (set_attr "cc" "clobber")])

;; A few multiply variations.

;; This really extends to SImode, so cc should be considered clobbered.

(define_insn "mulqihi3"
  [(set (match_operand:HI 0 "register_operand" "=r")
	(mult:HI
	 (sign_extend:HI (match_operand:QI 1 "register_operand" "%0"))
	 (sign_extend:HI (match_operand:QI 2 "register_operand" "r"))))]
  "TARGET_HAS_MUL_INSNS"
  "%!muls.b %2,%0"
  [(set (attr "slottable")
	(if_then_else (ne (symbol_ref "TARGET_MUL_BUG") (const_int 0))
		      (const_string "no")
		      (const_string "yes")))
   (set_attr "cc" "clobber")])

(define_insn "mulhisi3"
  [(set (match_operand:SI 0 "register_operand" "=r")
	(mult:SI
	 (sign_extend:SI (match_operand:HI 1 "register_operand" "%0"))
	 (sign_extend:SI (match_operand:HI 2 "register_operand" "r"))))]
  "TARGET_HAS_MUL_INSNS"
  "%!muls.w %2,%0"
  [(set (attr "slottable")
	(if_then_else (ne (symbol_ref "TARGET_MUL_BUG") (const_int 0))
		      (const_string "no")
		      (const_string "yes")))
   ;; Just N unusable here, but let's be safe.
   (set_attr "cc" "clobber")])

;; 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 "mulsidi3"
  [(set (match_operand:DI 0 "register_operand" "=r")
	(mult:DI
	 (sign_extend:DI (match_operand:SI 1 "register_operand" "%0"))
	 (sign_extend:DI (match_operand:SI 2 "register_operand" "r"))))]
  "TARGET_HAS_MUL_INSNS"
  "%!muls.d %2,%M0\;move $mof,%H0")

(define_insn "umulsidi3"
  [(set (match_operand:DI 0 "register_operand" "=r")
	(mult:DI
	 (zero_extend:DI (match_operand:SI 1 "register_operand" "%0"))
	 (zero_extend:DI (match_operand:SI 2 "register_operand" "r"))))]
  "TARGET_HAS_MUL_INSNS"
  "%!mulu.d %2,%M0\;move $mof,%H0")

;; This pattern would probably not be needed if we add "mof" in its own
;; register class (and open a can of worms about /not/ pairing it with a
;; "normal" register).  Having multiple register classes here, and
;; applicable to the v10 variant only, seems worse than having these two
;; patterns with multi-insn contents for now (may change; having a free
;; call-clobbered register is worth some trouble).

(define_insn "smulsi3_highpart"
  [(set (match_operand:SI 0 "nonimmediate_operand" "=r,r,m")
	(truncate:SI
	 (lshiftrt:DI
	  (mult:DI
	   (sign_extend:DI (match_operand:SI 1 "register_operand" "%0,r,r"))
	   (sign_extend:DI (match_operand:SI 2 "register_operand" "r,r,r")))
	  (const_int 32))))
   (clobber (match_scratch:SI 3 "=X,1,1"))]
  "TARGET_HAS_MUL_INSNS"
  "%!muls.d %2,%1\;move $mof,%0"
  [(set_attr "cc" "clobber")])

(define_insn "umulsi3_highpart"
  [(set (match_operand:SI 0 "nonimmediate_operand" "=r,r,m")
	(truncate:SI
	 (lshiftrt:DI
	  (mult:DI
	   (zero_extend:DI (match_operand:SI 1 "register_operand" "%0,r,r"))
	   (zero_extend:DI (match_operand:SI 2 "register_operand" "r,r,r")))
	  (const_int 32))))
   (clobber (match_scratch:SI 3 "=X,1,1"))]
  "TARGET_HAS_MUL_INSNS"
  "%!mulu.d %2,%1\;move $mof,%0"
  [(set_attr "cc" "clobber")])

;; Divide and modulus instructions.  CRIS only has a step instruction.

(define_insn "dstep_shift"
  [(set (match_operand:SI 0 "register_operand" "=r")
	(if_then_else:SI
	 (geu:SI (ashift:SI (match_operand:SI 1 "register_operand" "0")
			    (const_int 1))
	      (match_operand:SI 2 "register_operand" "r"))
	 (minus:SI (ashift:SI (match_operand:SI 3 "register_operand" "0")
			(const_int 1))
		   (match_operand:SI 4 "register_operand" "2"))
	 (ashift:SI (match_operand:SI 5 "register_operand" "0")
			(const_int 1))))]
  ""
  "dstep %2,%0"
  [(set_attr "slottable" "yes")])

;; Here's a variant with mult instead of ashift.
;;
;; FIXME: This should be investigated.  Which one matches through combination?

(define_insn "dstep_mul"
  [(set (match_operand:SI 0 "register_operand" "=r")
	(if_then_else:SI
	 (geu:SI (mult:SI (match_operand:SI 1 "register_operand" "0")
			  (const_int 2))
	      (match_operand:SI 2 "register_operand" "r"))
	 (minus:SI (mult:SI (match_operand:SI 3 "register_operand" "0")
			    (const_int 2))
		   (match_operand:SI 4 "register_operand" "2"))
	 (mult:SI (match_operand:SI 5 "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"
  "dstep %2,%0"
  [(set_attr "slottable" "yes")])

;; Logical operators.

;; Bitwise "and".

;; There is no use in defining "anddi3", because gcc can expand this by
;; itself, and make reasonable code without interference.

;; If the first operand is memory or a register and is the same as the
;; second operand, and the third operand is -256 or -65536, we can use
;; CLEAR instead.  Or, if the first operand is a register, and the third
;; operand is 255 or 65535, we can zero_extend.
;; GCC isn't smart enough to recognize these cases (yet), and they seem
;; to be common enough to be worthwhile.
;; 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"	 "")))]
  ""
  "
{
  if (! (GET_CODE (operands[2]) == CONST_INT
	 && (((INTVAL (operands[2]) == -256
	       || INTVAL (operands[2]) == -65536)
	      && rtx_equal_p (operands[1], operands[0]))
	     || ((INTVAL (operands[2]) == 255
		  || INTVAL (operands[2]) == 65535)
		 && REG_P (operands[0])))))
    {
      /* Make intermediate steps if operand0 is not a register or
	 operand1 is not a register, and hope that the reload pass will
	 make something useful out of it.  Note that the operands are
	 *not* canonicalized.  For the moment, I chicken out on this,
	 because all or most ports do not describe 'and' with
	 canonicalized operands, and I seem to remember magic in reload,
	 checking that operand1 has constraint '%0', in which case
	 operand0 and operand1 must have similar predicates.
	 FIXME: Investigate.  */
      rtx reg0 = REG_P (operands[0]) ? operands[0] : gen_reg_rtx (SImode);
      rtx reg1 = operands[1];

      if (! REG_P (reg1))
	{
	  emit_move_insn (reg0, reg1);
	  reg1 = reg0;
	}

      emit_insn (gen_rtx_SET (SImode, reg0,
			  gen_rtx_AND (SImode, reg1, operands[2])));

      /* Make sure we get the right *final* destination.  */
      if (! REG_P (operands[0]))
	emit_move_insn (operands[0], reg0);

      DONE;
    }
}")

;; Some special cases of andsi3.

(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")))]
  "(INTVAL (operands[2]) == 255 || INTVAL (operands[2]) == 65535)
   && (GET_CODE (operands[1]) != MEM || ! MEM_VOLATILE_P (operands[1]))"
  "movu.%z2 %1,%0"
  [(set_attr "slottable" "yes,yes,no")])

(define_insn "*andsi_clear"
  [(set (match_operand:SI 0 "nonimmediate_operand" "=r,r,Q,Q,To,To")
	(and:SI (match_operand:SI 1 "nonimmediate_operand" "%0,0,0,0,0,0")
		(match_operand:SI 2 "const_int_operand" "P,n,P,n,P,n")))]
  "(INTVAL (operands[2]) == -65536 || INTVAL (operands[2]) == -256)
   && (GET_CODE (operands[0]) != MEM || ! MEM_VOLATILE_P (operands[0]))"
  "@
   cLear.b %0
   cLear.w %0
   cLear.b %0
   cLear.w %0
   cLear.b %0
   cLear.w %0"
  [(set_attr "slottable" "yes,yes,yes,yes,no,no")
   (set_attr "cc" "none")])

;; This is a catch-all pattern, taking care of everything that was not
;; matched in the insns above.
;;
;; Sidenote: the tightening from "nonimmediate_operand" to
;; "register_operand" for operand 1 actually increased the register
;; pressure (worse code).  That will hopefully change with an
;; improved reload pass.

(define_insn "*expanded_andsi"
  [(set (match_operand:SI 0 "register_operand" "=r,r,r,r,r")
	(and:SI (match_operand:SI 1 "register_operand" "%0,0,0,0,r")
		(match_operand:SI 2 "general_operand" "I,r,Q>,g,!To")))]
  ""
  "@
   andq %2,%0
   and.d %2,%0
   and.d %2,%0
   and.d %2,%0
   and.d %2,%1,%0"
  [(set_attr "slottable" "yes,yes,yes,no,no")])

;; 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).

;; 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"  "")))]
  ""
  "
{
  if (! (GET_CODE (operands[2]) == CONST_INT
	 && (((INTVAL (operands[2]) == -256
	       || INTVAL (operands[2]) == 65280)
	      && rtx_equal_p (operands[1], operands[0]))
	     || (INTVAL (operands[2]) == 255
		 && REG_P (operands[0])))))
    {
      /* See comment for andsi3.  */
      rtx reg0 = REG_P (operands[0]) ? operands[0] : gen_reg_rtx (HImode);
      rtx reg1 = operands[1];

      if (! REG_P (reg1))
	{
	  emit_move_insn (reg0, reg1);
	  reg1 = reg0;
	}

      emit_insn (gen_rtx_SET (HImode, reg0,
			  gen_rtx_AND (HImode, reg1, operands[2])));

      /* Make sure we get the right destination.  */
      if (! REG_P (operands[0]))
	emit_move_insn (operands[0], reg0);

      DONE;
    }
}")

;; Some fast andhi3 special cases.

(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])"
  "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])"
  "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")))]

;; Sidenote: the tightening from "general_operand" to
;; "register_operand" for operand 1 actually increased the register
;; pressure (worse code).  That will hopefully change with an
;; improved reload pass.

  ""
  "@
   andq %2,%0
   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,yes,no,yes,no,no")
   (set_attr "cc" "clobber,normal,normal,normal,clobber,normal,normal")])

;; A strict_low_part pattern.

(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")))]
  ""
  "@
   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")])

(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")))]
  ""
  "@
   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")])

(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")))]
  ""
  "@
   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")])

;; Bitwise or.

;; Same comment as anddi3 applies here - no need for such a pattern.

;; It seems there's no need to jump through hoops to get good code such as
;; with andsi3.

(define_insn "iorsi3"
  [(set (match_operand:SI 0 "register_operand" "=r,r,r,r,r,r")
	(ior:SI (match_operand:SI 1 "register_operand" "%0,0,0,0,0,r")
		(match_operand:SI 2 "general_operand" "I,r,Q>,n,g,!To")))]
  ""
  "@
   orq %2,%0
   or.d %2,%0
   or.d %2,%0
   oR.%s2 %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")])

(define_insn "iorhi3"
  [(set (match_operand:HI 0 "register_operand" "=r,r,r,r,r,r,r")
	(ior:HI (match_operand:HI 1 "register_operand" "%0,0,0,0,0,0,r")
		(match_operand:HI 2 "general_operand" "I,r,Q>,L,O,g,!To")))]
  ""
  "@
   orq %2,%0
   or.w %2,%0
   or.w %2,%0
   or.w %2,%0
   oRq %b2,%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")])

(define_insn "iorqi3"
  [(set (match_operand:QI 0 "register_operand" "=r,r,r,r,r,r")
	(ior:QI (match_operand:QI 1 "register_operand" "%0,0,0,0,0,r")
		(match_operand:QI 2 "general_operand" "I,r,Q>,O,g,!To")))]
  ""
  "@
   orq %2,%0
   or.b %2,%0
   or.b %2,%0
   orQ %b2,%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")])

;; Exclusive-or

;; See comment about "anddi3" for xordi3 - no need for such a pattern.

(define_insn "xorsi3"
  [(set (match_operand:SI 0 "register_operand" "=r")
	(xor:SI (match_operand:SI 1 "register_operand" "%0")
		(match_operand:SI 2 "register_operand" "r")))]
  ""
  "xor %2,%0"
  [(set_attr "slottable" "yes")])

(define_insn "xorhi3"
  [(set (match_operand:HI 0 "register_operand" "=r")
	(xor:HI (match_operand:HI 1 "register_operand" "%0")
		(match_operand:HI 2 "register_operand" "r")))]
  ""
  "xor %2,%0"
  [(set_attr "slottable" "yes")
   (set_attr "cc" "clobber")])

(define_insn "xorqi3"
  [(set (match_operand:QI 0 "register_operand" "=r")
	(xor:QI (match_operand:QI 1 "register_operand" "%0")
		(match_operand:QI 2 "register_operand" "r")))]
  ""
  "xor %2,%0"
  [(set_attr "slottable" "yes")
   (set_attr "cc" "clobber")])

;; Negation insns.

;; Questionable use, here mostly as a (slightly usable) define_expand
;; 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))])]
  ""
  "
{
  operands[2] = gen_reg_rtx (SImode);
  operands[3] = GEN_INT (1 << 31);
}")

(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"))]
  ""
  "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 "negsi2"
  [(set (match_operand:SI 0 "register_operand" "=r")
	(neg:SI (match_operand:SI 1 "register_operand" "r")))]
  ""
  "neg.d %1,%0"
  [(set_attr "slottable" "yes")])

(define_insn "neghi2"
  [(set (match_operand:HI 0 "register_operand" "=r")
	(neg:HI (match_operand:HI 1 "register_operand" "r")))]
  ""
  "neg.w %1,%0"
  [(set_attr "slottable" "yes")])

(define_insn "negqi2"
  [(set (match_operand:QI 0 "register_operand" "=r")
	(neg:QI (match_operand:QI 1 "register_operand" "r")))]
  ""
  "neg.b %1,%0"
  [(set_attr "slottable" "yes")])

;; One-complements.

;; See comment on anddi3 - no need for a DImode pattern.

(define_insn "one_cmplsi2"
  [(set (match_operand:SI 0 "register_operand" "=r")
	(not:SI (match_operand:SI 1 "register_operand" "0")))]
  ""
  "not %0"
  [(set_attr "slottable" "yes")])

(define_insn "one_cmplhi2"
  [(set (match_operand:HI 0 "register_operand" "=r")
	(not:HI (match_operand:HI 1 "register_operand" "0")))]
  ""
  "not %0"
  [(set_attr "slottable" "yes")
   (set_attr "cc" "clobber")])

(define_insn "one_cmplqi2"
  [(set (match_operand:QI 0 "register_operand" "=r")
	(not:QI (match_operand:QI 1 "register_operand" "0")))]
  ""
  "not %0"
  [(set_attr "slottable" "yes")
   (set_attr "cc" "clobber")])

;; Arithmetic shift right.

(define_insn "ashrsi3"
  [(set (match_operand:SI 0 "register_operand" "=r")
	(ashiftrt:SI (match_operand:SI 1 "register_operand" "0")
		     (match_operand:SI 2 "nonmemory_operand" "Kr")))]
  ""
  "*
{
  if (REG_S_P (operands[2]))
    return \"asr.d %2,%0\";

  return \"asrq %2,%0\";
}"
  [(set_attr "slottable" "yes")])

;; Since gcc gets lost, and forgets to zero-extend the source (or mask
;; the destination) when it changes shifts of lower modes into SImode,
;; it is better to make these expands an anonymous patterns instead of
;; the more correct define_insns.  This occurs when gcc thinks that is
;; is better to widen to SImode and use immediate shift count.

;; FIXME: Is this legacy or still true for gcc >= 2.7.2?

(define_expand "ashrhi3"
  [(set (match_dup 3)
	(sign_extend:SI (match_operand:HI 1 "nonimmediate_operand" "rm")))
   (set (match_dup 4)
	(zero_extend:SI (match_operand:HI 2 "nonimmediate_operand" "rm")))
   (set (match_dup 5) (ashiftrt:SI (match_dup 3) (match_dup 4)))
   (set (match_operand:HI 0 "general_operand" "=g")
	(subreg:HI (match_dup 5) 0))]
  ""
  "
{
  int i;

  for (i = 3; i < 6; i++)
    operands[i] = gen_reg_rtx (SImode);
}")

(define_insn "*expanded_ashrhi"
  [(set (match_operand:HI 0 "register_operand" "=r")
	(ashiftrt:HI (match_operand:HI 1 "register_operand" "0")
		     (match_operand:HI 2 "register_operand" "r")))]
  ""
  "asr.w %2,%0"
  [(set_attr "slottable" "yes")])

(define_insn "*ashrhi_lowpart"
  [(set (strict_low_part (match_operand:HI 0 "register_operand" "+r"))
	(ashiftrt:HI (match_dup 0)
		     (match_operand:HI 1 "register_operand" "r")))]
  ""
  "asr.w %1,%0"
  [(set_attr "slottable" "yes")])

;; Same comment goes as for "ashrhi3".

(define_expand "ashrqi3"
  [(set (match_dup 3)
	(sign_extend:SI (match_operand:QI 1 "nonimmediate_operand" "g")))
   (set (match_dup 4)
	(zero_extend:SI (match_operand:QI 2 "nonimmediate_operand" "g")))
   (set (match_dup 5) (ashiftrt:SI (match_dup 3) (match_dup 4)))
   (set (match_operand:QI 0 "general_operand" "=g")
	(subreg:QI (match_dup 5) 0))]
  ""
  "
{
  int i;

  for (i = 3; i < 6; i++)
    operands[i] = gen_reg_rtx (SImode);
}")

(define_insn "*expanded_ashrqi"
  [(set (match_operand:QI 0 "register_operand" "=r")
	(ashiftrt:QI (match_operand:QI 1 "register_operand" "0")
		     (match_operand:QI 2 "register_operand" "r")))]
  ""
  "asr.b %2,%0"
  [(set_attr "slottable" "yes")])

;; A strict_low_part matcher.

(define_insn "*ashrqi_lowpart"
  [(set (strict_low_part (match_operand:QI 0 "register_operand" "+r"))
	(ashiftrt:QI (match_dup 0)
		     (match_operand:QI 1 "register_operand" "r")))]
  ""
  "asr.b %1,%0"
  [(set_attr "slottable" "yes")])

;; Logical shift right.

(define_insn "lshrsi3"
  [(set (match_operand:SI 0 "register_operand" "=r")
	(lshiftrt:SI (match_operand:SI 1 "register_operand" "0")
		     (match_operand:SI 2 "nonmemory_operand" "Kr")))]
  ""
  "*
{
  if (REG_S_P (operands[2]))
    return \"lsr.d %2,%0\";

  return \"lsrq %2,%0\";
}"
  [(set_attr "slottable" "yes")])

;; Same comments as for ashrhi3.

(define_expand "lshrhi3"
  [(set (match_dup 3)
	(zero_extend:SI (match_operand:HI 1 "nonimmediate_operand" "g")))
   (set (match_dup 4)
	(zero_extend:SI (match_operand:HI 2 "nonimmediate_operand" "g")))
   (set (match_dup 5) (lshiftrt:SI (match_dup 3) (match_dup 4)))
   (set (match_operand:HI 0 "general_operand" "=g")
	(subreg:HI (match_dup 5) 0))]
  ""
  "
{
  int i;

  for (i = 3; i < 6; i++)
    operands[i] = gen_reg_rtx (SImode);
}")

(define_insn "*expanded_lshrhi"
  [(set (match_operand:HI 0 "register_operand" "=r")
	(lshiftrt:HI (match_operand:HI 1 "register_operand" "0")
		     (match_operand:HI 2 "register_operand" "r")))]
  ""
  "lsr.w %2,%0"
  [(set_attr "slottable" "yes")])

;; A strict_low_part matcher.

(define_insn "*lshrhi_lowpart"
  [(set (strict_low_part (match_operand:HI 0 "register_operand" "+r"))
	(lshiftrt:HI (match_dup 0)
		     (match_operand:HI 1 "register_operand" "r")))]
  ""
  "lsr.w %1,%0"
  [(set_attr "slottable" "yes")])

;; Same comments as for ashrhi3.

(define_expand "lshrqi3"
  [(set (match_dup 3)
	(zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" "g")))
   (set (match_dup 4)
	(zero_extend:SI (match_operand:QI 2 "nonimmediate_operand" "g")))
   (set (match_dup 5) (lshiftrt:SI (match_dup 3) (match_dup 4)))
   (set (match_operand:QI 0 "general_operand" "=g")
	(subreg:QI (match_dup 5) 0))]
  ""
  "
{
  int i;

  for (i = 3; i < 6; i++)
    operands[i] = gen_reg_rtx (SImode);
}")

(define_insn "*expanded_lshrqi"
  [(set (match_operand:QI 0 "register_operand" "=r")
	(lshiftrt:QI (match_operand:QI 1 "register_operand" "0")
		     (match_operand:QI 2 "register_operand" "r")))]
  ""
  "lsr.b %2,%0"
  [(set_attr "slottable" "yes")])

;; A strict_low_part matcher.

(define_insn "*lshrqi_lowpart"
  [(set (strict_low_part (match_operand:QI 0 "register_operand" "+r"))
	(lshiftrt:QI (match_dup 0)
		     (match_operand:QI 1 "register_operand" "r")))]
  ""
  "lsr.b %1,%0"
  [(set_attr "slottable" "yes")])

;; Arithmetic/logical shift left.

(define_insn "ashlsi3"
  [(set (match_operand:SI 0 "register_operand" "=r")
	(ashift:SI (match_operand:SI 1 "register_operand" "0")
		   (match_operand:SI 2 "nonmemory_operand" "Kr")))]
  ""
  "*
{
  if (REG_S_P (operands[2]))
    return \"lsl.d %2,%0\";

  return \"lslq %2,%0\";
}"
  [(set_attr "slottable" "yes")])

;; For narrower modes than SI, we can use lslq although it makes cc
;; unusable.  The win is that we do not have to reload the shift-count
;; into a register.

(define_insn "ashlhi3"
  [(set (match_operand:HI 0 "register_operand" "=r,r")
	(ashift:HI (match_operand:HI 1 "register_operand" "0,0")
		   (match_operand:HI 2 "nonmemory_operand" "r,K")))]
  ""
  "*
{
  return
    (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) > 15)
    ? \"moveq 0,%0\"
    : (CONSTANT_P (operands[2])
       ? \"lslq %2,%0\" : \"lsl.w %2,%0\");
}"
  [(set_attr "slottable" "yes")
   (set_attr "cc" "normal,clobber")])

;; A strict_low_part matcher.

(define_insn "*ashlhi_lowpart"
  [(set (strict_low_part (match_operand:HI 0 "register_operand" "+r"))
	(ashift:HI (match_dup 0)
		   (match_operand:HI 1 "register_operand" "r")))]
  ""
  "lsl.w %1,%0"
  [(set_attr "slottable" "yes")])

(define_insn "ashlqi3"
  [(set (match_operand:QI 0 "register_operand" "=r,r")
	(ashift:QI (match_operand:QI 1 "register_operand" "0,0")
		   (match_operand:QI 2 "nonmemory_operand" "r,K")))]
  ""
  "*
{
  return
    (GET_CODE (operands[2]) == CONST_INT
     && INTVAL (operands[2]) > 7)
    ? \"moveq 0,%0\"
    : (CONSTANT_P (operands[2])
       ? \"lslq %2,%0\" : \"lsl.b %2,%0\");
}"
  [(set_attr "slottable" "yes")
   (set_attr "cc" "normal,clobber")])

;; A strict_low_part matcher.

(define_insn "*ashlqi_lowpart"
  [(set (strict_low_part (match_operand:QI 0 "register_operand" "+r"))
	(ashift:QI (match_dup 0)
		   (match_operand:QI 1 "register_operand" "r")))]
  ""
  "lsl.b %1,%0"
  [(set_attr "slottable" "yes")])

;; Various strange insns that gcc likes.

;; Fortunately, it is simple to construct an abssf (although it may not
;; be very much used in practice).

(define_insn "abssf2"
  [(set (match_operand:SF 0 "register_operand" "=r")
	(abs:SF (match_operand:SF 1 "register_operand" "0")))]
  ""
  "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 %1,%0"
  [(set_attr "slottable" "yes")])

;; FIXME: GCC should be able to do these expansions itself.

(define_expand "abshi2"
  [(set (match_dup 2)
	(sign_extend:SI (match_operand:HI 1 "general_operand" "g")))
   (set (match_dup 3) (abs:SI (match_dup 2)))
   (set (match_operand:HI 0 "register_operand" "=r")
	(subreg:HI (match_dup 3) 0))]
  ""
  "operands[2] = gen_reg_rtx (SImode); operands[3] = gen_reg_rtx (SImode);")

(define_expand "absqi2"
  [(set (match_dup 2)
	(sign_extend:SI (match_operand:QI 1 "general_operand" "g")))
   (set (match_dup 3) (abs:SI (match_dup 2)))
   (set (match_operand:QI 0 "register_operand" "=r")
	(subreg:QI (match_dup 3) 0))]
  ""
  "operands[2] = gen_reg_rtx (SImode); operands[3] = 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"
  [(set (match_operand:SI 0 "register_operand" "=r,r,r,r")
	(umin:SI  (match_operand:SI 1 "register_operand" "%0,0,0,r")
		  (match_operand:SI 2 "general_operand" "r,Q>,g,!STo")))]
  ""
  "*
{
  if (GET_CODE (operands[2]) == CONST_INT)
    {
      if (INTVAL (operands[2]) < 256)
	return \"bound.b %2,%0\";

      if (INTVAL (operands[2]) < 65536)
	return \"bound.w %2,%0\";
    }
  else if (which_alternative == 3)
    return \"bound.d %2,%1,%0\";

  return \"bound.d %2,%0\";
}"
 [(set_attr "slottable" "yes,yes,no,no")])

;; Jump and branch insns.

(define_insn "jump"
  [(set (pc)
	(label_ref (match_operand 0 "" "")))]
  ""
  "ba %l0%#"
  [(set_attr "slottable" "has_slot")])

;; Testcase gcc.c-torture/compile/991213-3.c fails if we allow a constant
;; here, since the insn is not recognized as an indirect jump by
;; jmp_uses_reg_or_mem used by computed_jump_p.  Perhaps it is a kludge to
;; change from general_operand to nonimmediate_operand (at least the docs
;; should be changed), but then again the pattern is called indirect_jump.
(define_insn "indirect_jump"
  [(set (pc) (match_operand:SI 0 "nonimmediate_operand" "rm"))]
  ""
  "jump %0")

;; Return insn.  Used whenever the epilogue is very simple; if it is only
;; a single ret or jump [sp+] or a contiguous sequence of movem:able saved
;; registers.  No allocated stack space is allowed.
;; Note that for this pattern, although named, it is ok to check the
;; context of the insn in the test, not only compiler switches.

(define_insn "return"
  [(return)]
  "cris_simple_epilogue ()"
  "*
{
  int i;

  /* Just needs to hold a 'movem [sp+],rN'.  */
  char rd[sizeof (\"movem [$sp+],$r99\")];

  /* Try to avoid reorg.c surprises; avoid emitting invalid code, prefer
     crashing.  This test would have avoided invalid code for target/7042.  */
  if (current_function_epilogue_delay_list != NULL)
    abort ();

  *rd = 0;

  /* Start from the last call-saved register.  We know that we have a
     simple epilogue, so we just have to find the last register in the
     movem sequence.  */
  for (i = 8; i >= 0; i--)
    if (regs_ever_live[i]
	|| (i == PIC_OFFSET_TABLE_REGNUM
	    && current_function_uses_pic_offset_table))
      break;

  if (i >= 0)
    sprintf (rd, \"movem [$sp+],$%s\", reg_names [i]);

  if (regs_ever_live[CRIS_SRP_REGNUM]
      || cris_return_address_on_stack ())
    {
      if (*rd)
	output_asm_insn (rd, operands);
      return \"jump [$sp+]\";
    }

  if (*rd)
    {
      output_asm_insn (\"reT\", operands);
      output_asm_insn (rd, operands);
      return \"\";
    }

  return \"ret%#\";
}"
  [(set (attr "slottable")
	(if_then_else
	 (ne (symbol_ref
	      "(regs_ever_live[CRIS_SRP_REGNUM]
	        || cris_return_address_on_stack ())")
	     (const_int 0))
	 (const_string "no")	     ; If jump then not slottable.
	 (if_then_else
	  (ne (symbol_ref
	       "(regs_ever_live[0]
		 || (flag_pic != 0 && regs_ever_live[1])
		 || (PIC_OFFSET_TABLE_REGNUM == 0
		     && cris_cfun_uses_pic_table ()))")
	      (const_int 0))
	  (const_string "no") ; ret+movem [sp+],rx: slot already filled.
	  (const_string "has_slot")))) ; If ret then need to fill a slot.
   (set_attr "cc" "none")])

;; Conditional branches.

;; 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 "beq"
  [(set (pc)
	(if_then_else (eq (cc0)
			  (const_int 0))
		      (label_ref (match_operand 0 "" ""))
		      (pc)))]
  ""
  "beq %l0%#"
  [(set_attr "slottable" "has_slot")])

(define_insn "bne"
  [(set (pc)
	(if_then_else (ne (cc0)
			  (const_int 0))
		      (label_ref (match_operand 0 "" ""))
		      (pc)))]
  ""
  "bne %l0%#"
  [(set_attr "slottable" "has_slot")])

(define_insn "bgt"
  [(set (pc)
	(if_then_else (gt (cc0)
			  (const_int 0))
		      (label_ref (match_operand 0 "" ""))
		      (pc)))]
  ""
  "*
{
  return
    (cc_prev_status.flags & CC_NO_OVERFLOW)
    ? 0 : \"bgt %l0%#\";
}"
  [(set_attr "slottable" "has_slot")])

(define_insn "bgtu"
  [(set (pc)
	(if_then_else (gtu (cc0)
			   (const_int 0))
		      (label_ref (match_operand 0 "" ""))
		      (pc)))]
  ""
  "bhi %l0%#"
  [(set_attr "slottable" "has_slot")])

(define_insn "blt"
  [(set (pc)
	(if_then_else (lt (cc0)
			  (const_int 0))
		      (label_ref (match_operand 0 "" ""))
		      (pc)))]
  ""
  "*
{
  return
    (cc_prev_status.flags & CC_NO_OVERFLOW)
    ? \"bmi %l0%#\" : \"blt %l0%#\";
}"
  [(set_attr "slottable" "has_slot")])

(define_insn "bltu"
  [(set (pc)
	(if_then_else (ltu (cc0)
			   (const_int 0))
		      (label_ref (match_operand 0 "" ""))
		      (pc)))]
  ""
  "blo %l0%#"
  [(set_attr "slottable" "has_slot")])

(define_insn "bge"
  [(set (pc)
	(if_then_else (ge (cc0)
			  (const_int 0))
		      (label_ref (match_operand 0 "" ""))
		      (pc)))]
  ""
  "*
{
  return
    (cc_prev_status.flags & CC_NO_OVERFLOW)
    ? \"bpl %l0%#\" : \"bge %l0%#\";
}"
  [(set_attr "slottable" "has_slot")])

(define_insn "bgeu"
  [(set (pc)
	(if_then_else (geu (cc0)
			   (const_int 0))
		      (label_ref (match_operand 0 "" ""))
		      (pc)))]
  ""
  "bhs %l0%#"
  [(set_attr "slottable" "has_slot")])

(define_insn "ble"
  [(set (pc)
	(if_then_else (le (cc0)
			  (const_int 0))
		      (label_ref (match_operand 0 "" ""))
		      (pc)))]
  ""
  "*
{
  return
    (cc_prev_status.flags & CC_NO_OVERFLOW)
    ? 0 : \"ble %l0%#\";
}"
  [(set_attr "slottable" "has_slot")])

(define_insn "bleu"
  [(set (pc)
	(if_then_else (leu (cc0)
			   (const_int 0))
		      (label_ref (match_operand 0 "" ""))
		      (pc)))]
  ""
  "bls %l0%#"
  [(set_attr "slottable" "has_slot")])

;; Reversed anonymous patterns to the ones above, as mandated.

(define_insn "*beq_reversed"
  [(set (pc)
	(if_then_else (eq (cc0)
			  (const_int 0))
		      (pc)
		      (label_ref (match_operand 0 "" ""))))]
  ""
  "bne %l0%#"
  [(set_attr "slottable" "has_slot")])

(define_insn "*bne_reversed"
  [(set (pc)
	(if_then_else (ne (cc0)
			  (const_int 0))
		      (pc)
		      (label_ref (match_operand 0 "" ""))))]
  ""
  "beq %l0%#"
  [(set_attr "slottable" "has_slot")])

(define_insn "*bgt_reversed"
  [(set (pc)
	(if_then_else (gt (cc0)
			  (const_int 0))
		      (pc)
		      (label_ref (match_operand 0 "" ""))))]
  ""
  "*
{
  return
    (cc_prev_status.flags & CC_NO_OVERFLOW)
    ? 0 : \"ble %l0%#\";
}"
  [(set_attr "slottable" "has_slot")])

(define_insn "*bgtu_reversed"
  [(set (pc)
	(if_then_else (gtu (cc0)
			   (const_int 0))
		      (pc)
		      (label_ref (match_operand 0 "" ""))))]
  ""
  "bls %l0%#"
  [(set_attr "slottable" "has_slot")])

(define_insn "*blt_reversed"
  [(set (pc)
	(if_then_else (lt (cc0)
			  (const_int 0))
		      (pc)
		      (label_ref (match_operand 0 "" ""))))]
  ""
  "*
{
  return
    (cc_prev_status.flags & CC_NO_OVERFLOW)
    ? \"bpl %l0%#\" : \"bge %l0%#\";
}"
  [(set_attr "slottable" "has_slot")])

(define_insn "*bltu_reversed"
  [(set (pc)
	(if_then_else (ltu (cc0)
			   (const_int 0))
		      (pc)
		      (label_ref (match_operand 0 "" ""))))]
  ""
  "bhs %l0%#"
  [(set_attr "slottable" "has_slot")])

(define_insn "*bge_reversed"
  [(set (pc)
	(if_then_else (ge (cc0)
			  (const_int 0))
		      (pc)
		      (label_ref (match_operand 0 "" ""))))]
  ""
  "*
{
  return
    (cc_prev_status.flags & CC_NO_OVERFLOW)
    ? \"bmi %l0%#\" : \"blt %l0%#\";
}"
  [(set_attr "slottable" "has_slot")])

(define_insn "*bgeu_reversed"
  [(set (pc)
	(if_then_else (geu (cc0)
			   (const_int 0))
		      (pc)
		      (label_ref (match_operand 0 "" ""))))]
  ""
  "blo %l0%#"
  [(set_attr "slottable" "has_slot")])

(define_insn "*ble_reversed"
  [(set (pc)
	(if_then_else (le (cc0)
			  (const_int 0))
		      (pc)
		      (label_ref (match_operand 0 "" ""))))]
  ""
  "*
{
  return
    (cc_prev_status.flags & CC_NO_OVERFLOW)
    ? 0 : \"bgt %l0%#\";
}"
  [(set_attr "slottable" "has_slot")])

(define_insn "*bleu_reversed"
  [(set (pc)
	(if_then_else (leu (cc0)
			   (const_int 0))
		      (pc)
		      (label_ref (match_operand 0 "" ""))))]
  ""
  "bhi %l0%#"
  [(set_attr "slottable" "has_slot")])

;; Set on condition: sCC.

;; Like bCC, we have to check the overflow bit for
;; signed conditions.

(define_insn "sgeu"
  [(set (match_operand:SI 0 "register_operand" "=r")
	(geu:SI (cc0) (const_int 0)))]
  ""
  "shs %0"
  [(set_attr "slottable" "yes")
   (set_attr "cc" "none")])

(define_insn "sltu"
  [(set (match_operand:SI 0 "register_operand" "=r")
	(ltu:SI (cc0) (const_int 0)))]
  ""
  "slo %0"
  [(set_attr "slottable" "yes")
   (set_attr "cc" "none")])

(define_insn "seq"
  [(set (match_operand:SI 0 "register_operand" "=r")
	(eq:SI (cc0) (const_int 0)))]
  ""
  "seq %0"
  [(set_attr "slottable" "yes")
   (set_attr "cc" "none")])

(define_insn "sge"
  [(set (match_operand:SI 0 "register_operand" "=r")
	(ge:SI (cc0) (const_int 0)))]
  ""
  "*
{
  return
    (cc_prev_status.flags & CC_NO_OVERFLOW)
    ? \"spl %0\" : \"sge %0\";
}"
  [(set_attr "slottable" "yes")
   (set_attr "cc" "none")])

(define_insn "sgt"
  [(set (match_operand:SI 0 "register_operand" "=r")
	(gt:SI (cc0) (const_int 0)))]
  ""
  "*
{
  return
    (cc_prev_status.flags & CC_NO_OVERFLOW)
    ? 0 : \"sgt %0\";
}"
  [(set_attr "slottable" "yes")
   (set_attr "cc" "none")])

(define_insn "sgtu"
  [(set (match_operand:SI 0 "register_operand" "=r")
	(gtu:SI (cc0) (const_int 0)))]
  ""
  "shi %0"
  [(set_attr "slottable" "yes")
   (set_attr "cc" "none")])

(define_insn "sle"
  [(set (match_operand:SI 0 "register_operand" "=r")
	(le:SI (cc0) (const_int 0)))]
  ""
  "*
{
  return
    (cc_prev_status.flags & CC_NO_OVERFLOW)
    ? 0 : \"sle %0\";
}"
  [(set_attr "slottable" "yes")
   (set_attr "cc" "none")])

(define_insn "sleu"
  [(set (match_operand:SI 0 "register_operand" "=r")
	(leu:SI (cc0) (const_int 0)))]
  ""
  "sls %0"
  [(set_attr "slottable" "yes")
   (set_attr "cc" "none")])

(define_insn "slt"
  [(set (match_operand:SI 0 "register_operand" "=r")
	(lt:SI (cc0) (const_int 0)))]
  ""
  "*
{
  return
    (cc_prev_status.flags & CC_NO_OVERFLOW)
    ? \"smi %0\" : \"slt %0\";
}"
  [(set_attr "slottable" "yes")
   (set_attr "cc" "none")])

(define_insn "sne"
  [(set (match_operand:SI 0 "register_operand" "=r")
	(ne:SI (cc0) (const_int 0)))]
  ""
  "sne %0"
  [(set_attr "slottable" "yes")
   (set_attr "cc" "none")])

;; Call insns.

;; We need to make these patterns "expand", since the real operand is
;; hidden in a (mem:QI ) inside operand[0] (call_value: operand[1]),
;; and cannot be checked if it were a "normal" pattern.
;;  Note that "call" and "call_value" are *always* called with a
;; mem-operand for operand 0 and 1 respective.  What happens for combined
;; instructions is a different issue.

(define_expand "call"
  [(parallel [(call (match_operand:QI 0 "cris_mem_call_operand" "")
		    (match_operand 1 "general_operand" ""))
	      ;; 16 is the srp (can't use the symbolic name here)
	      (clobber (reg:SI 16))])]
  ""
  "
{
  rtx op0;

  if (GET_CODE (operands[0]) != MEM)
    abort ();

  if (flag_pic)
    {
      op0 = XEXP (operands[0], 0);

      /* It might be that code can be generated that jumps to 0 (or to a
	 specific address).  Don't abort on that.  At least there's a
	 testcase.  */
      if (CONSTANT_ADDRESS_P (op0) && GET_CODE (op0) != CONST_INT)
	{
	  if (no_new_pseudos)
	    abort ();

	  /* For local symbols (non-PLT), get the plain symbol reference
	     into a register.  For symbols that can be PLT, make them PLT.  */
	  if (cris_gotless_symbol (op0) || GET_CODE (op0) != SYMBOL_REF)
	    op0 = force_reg (Pmode, op0);
	  else if (cris_symbol (op0))
	    /* FIXME: Would hanging a REG_EQUIV/EQUAL on that register
	       for the symbol cause bad recombinatorial effects?  */
	    op0 = force_reg (Pmode,
			     gen_rtx_CONST
			     (VOIDmode,
			      gen_rtx_UNSPEC (VOIDmode,
					      gen_rtvec (1, op0), 0)));
	  else
	    abort ();

	  operands[0] = replace_equiv_address (operands[0], op0);
	}
    }
}")

;; Accept *anything* as operand 1.  Accept operands for operand 0 in
;; order of preference (Q includes r, but r is shorter, faster)

(define_insn "*expanded_call"
  [(call (mem:QI (match_operand:SI
		  0 "cris_general_operand_or_plt_symbol" "r,Q>,g,S"))
	 (match_operand 1 "" ""))
   (clobber (reg:SI 16))] ;; 16 is the srp (can't use symbolic name)
  "! TARGET_AVOID_GOTPLT"
  "jsr %0")

;; Same as above, since can't afford wasting a constraint letter to mean
;; "S unless TARGET_AVOID_GOTPLT".
(define_insn "*expanded_call_no_gotplt"
  [(call (mem:QI (match_operand:SI
		  0 "cris_general_operand_or_plt_symbol" "r,Q>,g"))
	 (match_operand 1 "" ""))
   (clobber (reg:SI 16))] ;; 16 is the srp (can't use symbolic name)
  "TARGET_AVOID_GOTPLT"
  "jsr %0")

(define_expand "call_value"
  [(parallel [(set (match_operand 0 "" "")
		   (call (match_operand:QI 1 "cris_mem_call_operand" "")
			 (match_operand 2 "" "")))
	      ;; 16 is the srp (can't use symbolic name)
	      (clobber (reg:SI 16))])]
  ""
  "
{
  rtx op1;

  if (GET_CODE (operands[1]) != MEM)
    abort ();

  if (flag_pic)
    {
      op1 = XEXP (operands[1], 0);

      /* It might be that code can be generated that jumps to 0 (or to a
	 specific address).  Don't abort on that.  At least there's a
	 testcase.  */
      if (CONSTANT_ADDRESS_P (op1) && GET_CODE (op1) != CONST_INT)
	{
	  if (no_new_pseudos)
	    abort ();

	  if (cris_gotless_symbol (op1))
	    op1 = force_reg (Pmode, op1);
	  else if (cris_symbol (op1))
	    /* FIXME: Would hanging a REG_EQUIV/EQUAL on that register
	       for the symbol cause bad recombinatorial effects?  */
	    op1 = force_reg (Pmode,
			     gen_rtx_CONST
			     (VOIDmode,
			      gen_rtx_UNSPEC (VOIDmode,
					      gen_rtvec (1, op1), 0)));
	  else
	    abort ();

	  operands[1] = replace_equiv_address (operands[1], op1);
	}
    }
}")

;; Accept *anything* as operand 2.  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
;; than requiring getting rPIC + sym:PLT into a register.

(define_insn "*expanded_call_value"
  [(set (match_operand 0 "nonimmediate_operand" "=g,g,g,g")
	(call (mem:QI (match_operand:SI
		       1 "cris_general_operand_or_plt_symbol" "r,Q>,g,S"))
	      (match_operand 2 "" "")))
   (clobber (reg:SI 16))]
  "! TARGET_AVOID_GOTPLT"
  "Jsr %1"
  [(set_attr "cc" "clobber")])

;; Same as above, since can't afford wasting a constraint letter to mean
;; "S unless TARGET_AVOID_GOTPLT".
(define_insn "*expanded_call_value_no_gotplt"
  [(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 "" "")))
   (clobber (reg:SI 16))]
  "TARGET_AVOID_GOTPLT"
  "Jsr %1"
  [(set_attr "cc" "clobber")])

;; Used in debugging.  No use for the direct pattern; unfilled
;; delayed-branches are taken care of by other means.

(define_insn "nop"
  [(const_int 0)]
  ""
  "nop"
  [(set_attr "cc" "none")])

;; We expand on casesi so we can use "bound" and "add offset fetched from
;; a table to pc" (adds.w [pc+%0.w],pc).

;; Note: if you change the "parallel" (or add anything after it) in
;; this expansion, you must change the macro ASM_OUTPUT_CASE_END
;; accordingly, to add the default case at the end of the jump-table.

(define_expand "casesi"
  [(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 (pc)
	  (if_then_else
	   (ltu (match_dup 7) (match_dup 2))
	   (plus:SI (sign_extend:SI
		     (mem:HI
		      (plus:SI (mult:SI (match_dup 7) (const_int 2))
			       (pc))))
		    (pc))
	   (label_ref (match_operand 4 "" ""))))
     (use (label_ref (match_operand 3 "" "")))])]
  ""
  "
{
  operands[2] = plus_constant (operands[2], 1);
  operands[5] = gen_reg_rtx (SImode);
  operands[6] = gen_reg_rtx (SImode);
  operands[7] = gen_reg_rtx (SImode);
}")

;; 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.
;;
;; 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)]))]
  "")

;; 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)]))]
  "")

;; 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)]))]
  "")

;; Splits for all cases in side-effect insns where (possibly after reload
;; and register allocation) rx and ry in [rx=ry+i] are equal.

;; move.S1 [rx=rx+rz.S2],ry

(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
  [(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.d [rx=rx+rz.S2]

(define_split
  [(parallel
    [(set (mem:SI (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:SI (match_dup 3)) (const_int 0))]
  "")

;; clear.w [rx=rx+rz.S2]

(define_split
  [(parallel
    [(set (mem:HI (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:HI (match_dup 3)) (const_int 0))]
  "")

;; clear.b [rx=rx+rz.S2]

(define_split
  [(parallel
    [(set (mem:QI (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:QI (match_dup 3)) (const_int 0))]
  "")

;; clear.d [rx=rx+i]

(define_split
  [(parallel
    [(set (mem:SI
	   (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:SI (match_dup 2)) (const_int 0))]
  "")

;; clear.w [rx=rx+i]

(define_split
  [(parallel
    [(set (mem:HI
	   (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:HI (match_dup 2)) (const_int 0))]
  "")

;; clear.b [rx=rx+i]

(define_split
  [(parallel
    [(set (mem:QI
	   (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:QI (match_dup 2)) (const_int 0))]
  "")

;; mov(s|u).S1 [rx=rx+rz.S2],ry

(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
  [(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
  [(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]));")

;; 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
  [(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)))"
  [(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);")

;; 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.

;; We have trouble with and:s and shifts.  Maybe something is broken in
;; gcc?  Or it could just be that bit-field insn expansion is a bit
;; suboptimal when not having extzv insns.
;; Testcase for the following four peepholes: gcc.dg/cris-peep2-xsrand.c

(define_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)
	(and:SI (match_dup 0)
		(match_operand 2 "const_int_operand" "")))]
  "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.
{
  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" "")))]
  "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.
{
  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" "")))]
  "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.
{
  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" "")
	(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" "")))]
  "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.
{
  operands[3] = gen_rtx_REG (HImode, REGNO (operands[0]));
  operands[4] = GEN_INT (trunc_int_for_mode (INTVAL (operands[2]), HImode));
})


;; 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]));")

;; 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)])]))]
  "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])
   && 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.
;; 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" "")))]
   ;; 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))]
{
  enum machine_mode zmode = INTVAL (operands[3]) <= 255 ? QImode : HImode;
  enum machine_mode amode
    = CONST_OK_FOR_LETTER_P (INTVAL (operands[3]), 'O') ? SImode : zmode;
  rtx op1
    = (REG_S_P (operands[1])
       ? gen_rtx_REG (zmode, REGNO (operands[1]))
       : adjust_address (operands[1], zmode, 0));
  operands[4]
    = gen_rtx_ZERO_EXTEND (SImode, op1);
  operands[5] = gen_rtx_REG (amode, REGNO (operands[0]));
  operands[6]
    = gen_rtx_AND (amode, gen_rtx_REG (amode, REGNO (operands[0])),
		   GEN_INT (trunc_int_for_mode (INTVAL (operands[3]),
						amode == SImode
						? QImode : amode)));
})

;; Local variables:
;; mode:emacs-lisp
;; comment-start: ";; "
;; eval: (set-syntax-table (copy-sequence (syntax-table)))
;; eval: (modify-syntax-entry ?[ "(]")
;; eval: (modify-syntax-entry ?] ")[")
;; eval: (modify-syntax-entry ?{ "(}")
;; eval: (modify-syntax-entry ?} "){")
;; eval: (setq indent-tabs-mode t)
;; End:
