;; Mitsubishi D30V Machine description template
;; Copyright (C) 1997, 1998, 1999, 2000 Free Software Foundation, Inc.
;; Contributed by Cygnus Solutions.
;;
;; This file is part of GNU CC.
;;
;; GNU CC 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.
;;
;; GNU CC 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 GNU CC; see the file COPYING.  If not, write to
;; the Free Software Foundation, 59 Temple Place - Suite 330,
;; Boston, MA 02111-1307, USA.

;;- See file "rtl.def" for documentation on define_insn, match_*, et. al.


;; ::::::::::::::::::::
;; ::
;; :: Constraints
;; ::
;; ::::::::::::::::::::

;; Standard Constraints
;;
;; `m' A memory operand is allowed, with any kind of address that the
;;     machine supports in general.
;;
;; `o' A memory operand is allowed, but only if the address is
;;     "offsettable".  This means that adding a small integer (actually, the
;;     width in bytes of the operand, as determined by its machine mode) may be
;;     added to the address and the result is also a valid memory address.
;;
;; `V' A memory operand that is not offsettable.  In other words,
;;     anything that would fit the `m' constraint but not the `o' constraint.
;;
;; `<' A memory operand with autodecrement addressing (either
;;     predecrement or postdecrement) is allowed.
;;
;; `>' A memory operand with autoincrement addressing (either
;;     preincrement or postincrement) is allowed.
;;
;; `r' A register operand is allowed provided that it is in a general
;;     register.
;;
;; `d', `a', `f', ...
;;     Other letters can be defined in machine-dependent fashion to stand for
;;     particular classes of registers.  `d', `a' and `f' are defined on the
;;     68000/68020 to stand for data, address and floating point registers.
;;
;; `i' An immediate integer operand (one with constant value) is allowed.
;;     This includes symbolic constants whose values will be known only at
;;     assembly time.
;;
;; `n' An immediate integer operand with a known numeric value is allowed.
;;     Many systems cannot support assembly-time constants for operands less
;;     than a word wide.  Constraints for these operands should use `n' rather
;;     than `i'.
;;
;; 'I' First machine-dependent integer constant.
;; 'J' Second machine-dependent integer constant.
;; 'K' Third machine-dependent integer constant.
;; 'L' Fourth machine-dependent integer constant.
;; 'M' Fifth machine-dependent integer constant.
;; 'N' Sixth machine-dependent integer constant.
;; 'O' Seventh machine-dependent integer constant.
;; 'P' Eighth machine-dependent integer constant.
;;
;;     Other letters in the range `I' through `P' may be defined in a
;;     machine-dependent fashion to permit immediate integer operands with
;;     explicit integer values in specified ranges.  For example, on the 68000,
;;     `I' is defined to stand for the range of values 1 to 8.  This is the
;;     range permitted as a shift count in the shift instructions.
;;
;; `E' An immediate floating operand (expression code `const_double') is
;;     allowed, but only if the target floating point format is the same as
;;     that of the host machine (on which the compiler is running).
;;
;; `F' An immediate floating operand (expression code `const_double') is
;;     allowed.
;;
;; 'G' First machine-dependent const_double.
;; 'H' Second machine-dependent const_double.
;;
;; `s' An immediate integer operand whose value is not an explicit
;;     integer is allowed.
;;
;;     This might appear strange; if an insn allows a constant operand with a
;;     value not known at compile time, it certainly must allow any known
;;     value.  So why use `s' instead of `i'?  Sometimes it allows better code
;;     to be generated.
;;
;;     For example, on the 68000 in a fullword instruction it is possible to
;;     use an immediate operand; but if the immediate value is between -128 and
;;     127, better code results from loading the value into a register and
;;     using the register.  This is because the load into the register can be
;;     done with a `moveq' instruction.  We arrange for this to happen by
;;     defining the letter `K' to mean "any integer outside the range -128 to
;;     127", and then specifying `Ks' in the operand constraints.
;;
;; `g' Any register, memory or immediate integer operand is allowed,
;;     except for registers that are not general registers.
;;
;; `X' Any operand whatsoever is allowed, even if it does not satisfy
;;     `general_operand'.  This is normally used in the constraint of a
;;     `match_scratch' when certain alternatives will not actually require a
;;     scratch register.
;;
;; `0' Match operand 0.
;; `1' Match operand 1.
;; `2' Match operand 2.
;; `3' Match operand 3.
;; `4' Match operand 4.
;; `5' Match operand 5.
;; `6' Match operand 6.
;; `7' Match operand 7.
;; `8' Match operand 8.
;; `9' Match operand 9.
;;
;;     An operand that matches the specified operand number is allowed.  If a
;;     digit is used together with letters within the same alternative, the
;;     digit should come last.
;;
;;     This is called a "matching constraint" and what it really means is that
;;     the assembler has only a single operand that fills two roles considered
;;     separate in the RTL insn.  For example, an add insn has two input
;;     operands and one output operand in the RTL, but on most CISC machines an
;;     add instruction really has only two operands, one of them an
;;     input-output operand:
;;
;;          addl #35,r12
;;
;;     Matching constraints are used in these circumstances.  More precisely,
;;     the two operands that match must include one input-only operand and one
;;     output-only operand.  Moreover, the digit must be a smaller number than
;;     the number of the operand that uses it in the constraint.
;;
;;     For operands to match in a particular case usually means that they are
;;     identical-looking RTL expressions.  But in a few special cases specific
;;     kinds of dissimilarity are allowed.  For example, `*x' as an input
;;     operand will match `*x++' as an output operand.  For proper results in
;;     such cases, the output template should always use the output-operand's
;;     number when printing the operand.
;;
;; `p' An operand that is a valid memory address is allowed.  This is for
;;     "load address" and "push address" instructions.
;;
;;     `p' in the constraint must be accompanied by `address_operand' as the
;;     predicate in the `match_operand'.  This predicate interprets the mode
;;     specified in the `match_operand' as the mode of the memory reference for
;;     which the address would be valid.
;;
;; `Q` First non constant, non register machine-dependent insns
;; `R` Second non constant, non register machine-dependent insns
;; `S` Third non constant, non register machine-dependent insns
;; `T` Fourth non constant, non register machine-dependent insns
;; `U` Fifth non constant, non register machine-dependent insns
;;
;;     Letters in the range `Q' through `U' may be defined in a
;;     machine-dependent fashion to stand for arbitrary operand types.  The
;;     machine description macro `EXTRA_CONSTRAINT' is passed the operand as
;;     its first argument and the constraint letter as its second operand.
;;
;;     A typical use for this would be to distinguish certain types of memory
;;     references that affect other insn operands.
;;
;;     Do not define these constraint letters to accept register references
;;     (`reg'); the reload pass does not expect this and would not handle it
;;     properly.

;; Multiple Alternative Constraints
;; `?' Disparage slightly the alternative that the `?' appears in, as a
;;     choice when no alternative applies exactly.  The compiler regards this
;;     alternative as one unit more costly for each `?' that appears in it.
;;
;; `!' Disparage severely the alternative that the `!' appears in.  This
;;     alternative can still be used if it fits without reloading, but if
;;     reloading is needed, some other alternative will be used.

;; Constraint modifiers
;; `=' Means that this operand is write-only for this instruction: the
;;     previous value is discarded and replaced by output data.
;;
;; `+' Means that this operand is both read and written by the
;;     instruction.
;;
;;     When the compiler fixes up the operands to satisfy the constraints, it
;;     needs to know which operands are inputs to the instruction and which are
;;     outputs from it.  `=' identifies an output; `+' identifies an operand
;;     that is both input and output; all other operands are assumed to be
;;     input only.
;;
;; `&' Means (in a particular alternative) that this operand is written
;;     before the instruction is finished using the input operands.  Therefore,
;;     this operand may not lie in a register that is used as an input operand
;;     or as part of any memory address.
;;
;;     `&' applies only to the alternative in which it is written.  In
;;     constraints with multiple alternatives, sometimes one alternative
;;     requires `&' while others do not.
;;
;;     `&' does not obviate the need to write `='.
;;
;; `%' Declares the instruction to be commutative for this operand and the
;;     following operand.  This means that the compiler may interchange the two
;;     operands if that is the cheapest way to make all operands fit the
;;     constraints.  This is often used in patterns for addition instructions
;;     that really have only two operands: the result must go in one of the
;;     arguments.
;;
;; `#' Says that all following characters, up to the next comma, are to be
;;     ignored as a constraint.  They are significant only for choosing
;;     register preferences.
;;
;; `*' Says that the following character should be ignored when choosing
;;     register preferences.  `*' has no effect on the meaning of the
;;     constraint as a constraint, and no effect on reloading.

;; ::::::::::::::::::::
;; ::
;; :: D30V register classes
;; ::
;; ::::::::::::::::::::

;; `a'	Accumulator registers (a0, a1)
;; `b'	Flag registers for speculative execution (f0, f1)
;; `c'	CR registers
;; `d'	GPR registers
;; `e'	Even GPR registers
;; `f'	Any flag registers (f0, f1, ..., c)
;; `l'	CR7, the repeat count
;; `x'	F0
;; `y'	F1
;; `z'	Flag registers other than F0 and F1.

;; ::::::::::::::::::::
;; ::
;; :: D30V special constraints
;; ::
;; ::::::::::::::::::::

;; `G'	Const double with 0 in both low & high part.
;; `H'	Unused.
;; `I'	Signed 6 bit integer constant (>= -32 && <= 31).
;; `J'	Unsigned 5 bit integer constant (>= 0 && <= 31).
;; `K'	Integer constant with 1 bit set (for bset).
;; `L'	Integer constant with 1 bit clear (for bclr).
;; `M'	Integer constant 32.
;; `N'	Integer constant 1.
;; `O'	Integer constant 0.
;; `P'	Integer constant >= 32 && <= 63.
;; `Q'	Short memory operand (can be done in small insn).
;; `R'	Memory operand using a single register for address.
;; `S'	Memory operand to constant address.
;; `T'	Unused.
;; `U'	Unused.

;; ::::::::::::::::::::
;; ::
;; :: Standard operand flags
;; ::
;; ::::::::::::::::::::

;; `='  Output a number unique to each instruction in the compilation.
;; `a'  Substitute an operand as if it were a memory reference.
;; `c'  Omit the syntax that indicates an immediate operand.
;; `l'  Substitute a LABEL_REF into a jump instruction.
;; `n'  Like %cDIGIT, except negate the value before printing.

;; ::::::::::::::::::::
;; ::
;; :: D30V print_operand flags
;; ::
;; ::::::::::::::::::::

;; `.'	Print r0
;; `f'  Print a SF constant as an int.
;; `s'  Subtract 32 and negate.
;; `A'  Print accumulator number without an `a' in front of it.
;; `B'  Print bit offset for BSET, etc. instructions.
;; `E'  Print u if this is zero extend, nothing if this is sign extend.
;; `F'  Emit /{f,t,x}{f,t,x} for executing a false condition.
;; `L'  Print the lower half of a 64 bit item.
;; `M'  Print a memory reference for ld/st instructions.
;; `R'  Return appropriate cmp instruction for relational test.
;; `S'  Subtract 32.
;; `T'  Emit /{f,t,x}{f,t,x} for executing a true condition.
;; `U'  Print the upper half of a 64 bit item.


;; ::::::::::::::::::::
;; ::
;; :: Attributes
;; ::
;; ::::::::::::::::::::

;; The `define_attr' expression is used to define each attribute required by
;; the target machine.  It looks like:
;;
;; (define_attr NAME LIST-OF-VALUES DEFAULT)

;; NAME is a string specifying the name of the attribute being defined.

;; LIST-OF-VALUES is either a string that specifies a comma-separated list of
;; values that can be assigned to the attribute, or a null string to indicate
;; that the attribute takes numeric values.

;; DEFAULT is an attribute expression that gives the value of this attribute
;; for insns that match patterns whose definition does not include an explicit
;; value for this attribute.

;; For each defined attribute, a number of definitions are written to the
;; `insn-attr.h' file.  For cases where an explicit set of values is specified
;; for an attribute, the following are defined:

;; * A `#define' is written for the symbol `HAVE_ATTR_NAME'.
;;
;; * An enumeral class is defined for `attr_NAME' with elements of the
;;   form `UPPER-NAME_UPPER-VALUE' where the attribute name and value are first
;;   converted to upper case.
;;
;; * A function `get_attr_NAME' is defined that is passed an insn and
;;   returns the attribute value for that insn.

;; For example, if the following is present in the `md' file:
;;
;; (define_attr "type" "branch,fp,load,store,arith" ...)
;;
;; the following lines will be written to the file `insn-attr.h'.
;;
;; #define HAVE_ATTR_type
;; enum attr_type {TYPE_BRANCH, TYPE_FP, TYPE_LOAD, TYPE_STORE, TYPE_ARITH};
;; extern enum attr_type get_attr_type ();

;; If the attribute takes numeric values, no `enum' type will be defined and
;; the function to obtain the attribute's value will return `int'.

;; Note, we lie a little bit here to make it simpler to optimize.  We pretend there
;; is a separate long functional unit for long instructions that uses both the IU & MU.

(define_attr "type" "iu,mu,br,br2,either,scarry,lcarry,scmp,lcmp,sload,lload,mul,long,multi,unknown"
  (const_string "unknown"))

;; Length in word units
(define_attr "length" ""
  (cond [(eq_attr "type" "iu,mu,either,scmp,sload,mul,scarry,")
						(const_int 4)
	 (eq_attr "type" "long,lcmp,lload,lcarry")
						(const_int 8)
	 (eq_attr "type" "multi,unknown")	(const_int 64)	;; set higher to give a fudge factor
	 (eq_attr "type" "br")			(if_then_else (and (ge (minus (pc) (match_dup 0))
								       (const_int -1048576))
								   (lt (minus (pc) (match_dup 0))
								       (const_int 1048575)))
							      (const_int 4)
							      (const_int 8))
	 (eq_attr "type" "br2")			(if_then_else (and (ge (minus (pc) (match_dup 0))
								       (const_int -16384))
								   (lt (minus (pc) (match_dup 0))
								       (const_int 16383)))
							      (const_int 4)
							      (const_int 8))]
	(const_int 8)))


;; ::::::::::::::::::::
;; ::
;; :: Function Units
;; ::
;; ::::::::::::::::::::

;; On most RISC machines, there are instructions whose results are not
;; available for a specific number of cycles.  Common cases are instructions
;; that load data from memory.  On many machines, a pipeline stall will result
;; if the data is referenced too soon after the load instruction.

;; In addition, many newer microprocessors have multiple function units,
;; usually one for integer and one for floating point, and often will incur
;; pipeline stalls when a result that is needed is not yet ready.

;; The descriptions in this section allow the specification of how much time
;; must elapse between the execution of an instruction and the time when its
;; result is used.  It also allows specification of when the execution of an
;; instruction will delay execution of similar instructions due to function
;; unit conflicts.

;; For the purposes of the specifications in this section, a machine is divided
;; into "function units", each of which execute a specific class of
;; instructions in first-in-first-out order.  Function units that accept one
;; instruction each cycle and allow a result to be used in the succeeding
;; instruction (usually via forwarding) need not be specified.  Classic RISC
;; microprocessors will normally have a single function unit, which we can call
;; `memory'.  The newer "superscalar" processors will often have function units
;; for floating point operations, usually at least a floating point adder and
;; multiplier.

;; Each usage of a function units by a class of insns is specified with a
;; `define_function_unit' expression, which looks like this:

;; (define_function_unit NAME MULTIPLICITY SIMULTANEITY TEST READY-DELAY
;;   ISSUE-DELAY [CONFLICT-LIST])

;; NAME is a string giving the name of the function unit.

;; MULTIPLICITY is an integer specifying the number of identical units in the
;; processor.  If more than one unit is specified, they will be scheduled
;; independently.  Only truly independent units should be counted; a pipelined
;; unit should be specified as a single unit.  (The only common example of a
;; machine that has multiple function units for a single instruction class that
;; are truly independent and not pipelined are the two multiply and two
;; increment units of the CDC 6600.)

;; SIMULTANEITY specifies the maximum number of insns that can be executing in
;; each instance of the function unit simultaneously or zero if the unit is
;; pipelined and has no limit.

;; All `define_function_unit' definitions referring to function unit NAME must
;; have the same name and values for MULTIPLICITY and SIMULTANEITY.

;; TEST is an attribute test that selects the insns we are describing in this
;; definition.  Note that an insn may use more than one function unit and a
;; function unit may be specified in more than one `define_function_unit'.

;; READY-DELAY is an integer that specifies the number of cycles after which
;; the result of the instruction can be used without introducing any stalls.

;; ISSUE-DELAY is an integer that specifies the number of cycles after the
;; instruction matching the TEST expression begins using this unit until a
;; subsequent instruction can begin.  A cost of N indicates an N-1 cycle delay.
;; A subsequent instruction may also be delayed if an earlier instruction has a
;; longer READY-DELAY value.  This blocking effect is computed using the
;; SIMULTANEITY, READY-DELAY, ISSUE-DELAY, and CONFLICT-LIST terms.  For a
;; normal non-pipelined function unit, SIMULTANEITY is one, the unit is taken
;; to block for the READY-DELAY cycles of the executing insn, and smaller
;; values of ISSUE-DELAY are ignored.

;; CONFLICT-LIST is an optional list giving detailed conflict costs for this
;; unit.  If specified, it is a list of condition test expressions to be
;; applied to insns chosen to execute in NAME following the particular insn
;; matching TEST that is already executing in NAME.  For each insn in the list,
;; ISSUE-DELAY specifies the conflict cost; for insns not in the list, the cost
;; is zero.  If not specified, CONFLICT-LIST defaults to all instructions that
;; use the function unit.

;; Typical uses of this vector are where a floating point function unit can
;; pipeline either single- or double-precision operations, but not both, or
;; where a memory unit can pipeline loads, but not stores, etc.

;; As an example, consider a classic RISC machine where the result of a load
;; instruction is not available for two cycles (a single "delay" instruction is
;; required) and where only one load instruction can be executed
;; simultaneously.  This would be specified as:

;; (define_function_unit "memory" 1 1 (eq_attr "type" "load") 2 0)

;; For the case of a floating point function unit that can pipeline
;; either single or double precision, but not both, the following could be
;; specified:
;;
;; (define_function_unit "fp" 1 0
;;   (eq_attr "type" "sp_fp") 4 4
;;   [(eq_attr "type" "dp_fp")])
;;
;; (define_function_unit "fp" 1 0
;;   (eq_attr "type" "dp_fp") 4 4
;;   [(eq_attr "type" "sp_fp")])

;; Note: The scheduler attempts to avoid function unit conflicts and uses all
;; the specifications in the `define_function_unit' expression.  It has
;; recently come to our attention that these specifications may not allow
;; modeling of some of the newer "superscalar" processors that have insns using
;; multiple pipelined units.  These insns will cause a potential conflict for
;; the second unit used during their execution and there is no way of
;; representing that conflict.  We welcome any examples of how function unit
;; conflicts work in such processors and suggestions for their representation.

(define_function_unit "iu" 1 0
  (eq_attr "type" "iu,either")
  1 1
  [(eq_attr "type" "long,lcmp,lload,multi,unknown")])

(define_function_unit "iu" 1 0
  (eq_attr "type" "scmp,mul,scarry")
  2 1
  [(eq_attr "type" "long,lcmp,lload,multi,unknown")])

(define_function_unit "mu" 1 0
  (eq_attr "type" "mu,br,br2,either")
  1 1
  [(eq_attr "type" "long,lcmp,lload,multi,unknown")])

(define_function_unit "mu" 1 0
  (eq_attr "type" "scarry,scmp,sload")
  2 1
  [(eq_attr "type" "long,lcmp,lload,multi,unknown")])

(define_function_unit "long" 1 0
  (eq_attr "type" "long,multi,unknown")
  1 1
  [(eq_attr "type" "iu,mu,scarry,scmp,sload,mul,br,br2,either")])

(define_function_unit "long" 1 0
  (eq_attr "type" "lcmp,lload,lcarry")
  2 1
  [(eq_attr "type" "iu,mu,scarry,scmp,sload,mul,br,br2,either")])


;; ::::::::::::::::::::
;; ::
;; :: Delay Slots
;; ::
;; ::::::::::::::::::::

;; The insn attribute mechanism can be used to specify the requirements for
;; delay slots, if any, on a target machine.  An instruction is said to require
;; a "delay slot" if some instructions that are physically after the
;; instruction are executed as if they were located before it.  Classic
;; examples are branch and call instructions, which often execute the following
;; instruction before the branch or call is performed.

;; On some machines, conditional branch instructions can optionally "annul"
;; instructions in the delay slot.  This means that the instruction will not be
;; executed for certain branch outcomes.  Both instructions that annul if the
;; branch is true and instructions that annul if the branch is false are
;; supported.

;; Delay slot scheduling differs from instruction scheduling in that
;; determining whether an instruction needs a delay slot is dependent only
;; on the type of instruction being generated, not on data flow between the
;; instructions.  See the next section for a discussion of data-dependent
;; instruction scheduling.

;; The requirement of an insn needing one or more delay slots is indicated via
;; the `define_delay' expression.  It has the following form:
;;
;; (define_delay TEST
;;   [DELAY-1 ANNUL-TRUE-1 ANNUL-FALSE-1
;;    DELAY-2 ANNUL-TRUE-2 ANNUL-FALSE-2
;;    ...])

;; TEST is an attribute test that indicates whether this `define_delay' applies
;; to a particular insn.  If so, the number of required delay slots is
;; determined by the length of the vector specified as the second argument.  An
;; insn placed in delay slot N must satisfy attribute test DELAY-N.
;; ANNUL-TRUE-N is an attribute test that specifies which insns may be annulled
;; if the branch is true.  Similarly, ANNUL-FALSE-N specifies which insns in
;; the delay slot may be annulled if the branch is false.  If annulling is not
;; supported for that delay slot, `(nil)' should be coded.

;; For example, in the common case where branch and call insns require a single
;; delay slot, which may contain any insn other than a branch or call, the
;; following would be placed in the `md' file:

;; (define_delay (eq_attr "type" "branch,call")
;;		 [(eq_attr "type" "!branch,call") (nil) (nil)])

;; Multiple `define_delay' expressions may be specified.  In this case, each
;; such expression specifies different delay slot requirements and there must
;; be no insn for which tests in two `define_delay' expressions are both true.

;; For example, if we have a machine that requires one delay slot for branches
;; but two for calls, no delay slot can contain a branch or call insn, and any
;; valid insn in the delay slot for the branch can be annulled if the branch is
;; true, we might represent this as follows:

;; (define_delay (eq_attr "type" "branch")
;;   [(eq_attr "type" "!branch,call")
;;    (eq_attr "type" "!branch,call")
;;    (nil)])
;;
;; (define_delay (eq_attr "type" "call")
;;   [(eq_attr "type" "!branch,call") (nil) (nil)
;;    (eq_attr "type" "!branch,call") (nil) (nil)])


;; ::::::::::::::::::::
;; ::
;; :: Moves
;; ::
;; ::::::::::::::::::::

;; Wrap moves in define_expand to prevent memory->memory moves from being
;; generated at the RTL level, which generates better code for most machines
;; which can't do mem->mem moves.

;; If operand 0 is a `subreg' with mode M of a register whose own mode is wider
;; than M, the effect of this instruction is to store the specified value in
;; the part of the register that corresponds to mode M.  The effect on the rest
;; of the register is undefined.

;; This class of patterns is special in several ways.  First of all, each of
;; these names *must* be defined, because there is no other way to copy a datum
;; from one place to another.

;; Second, these patterns are not used solely in the RTL generation pass.  Even
;; the reload pass can generate move insns to copy values from stack slots into
;; temporary registers.  When it does so, one of the operands is a hard
;; register and the other is an operand that can need to be reloaded into a
;; register.

;; Therefore, when given such a pair of operands, the pattern must
;; generate RTL which needs no reloading and needs no temporary
;; registers--no registers other than the operands.  For example, if
;; you support the pattern with a `define_expand', then in such a
;; case the `define_expand' mustn't call `force_reg' or any other such
;; function which might generate new pseudo registers.

;; This requirement exists even for subword modes on a RISC machine
;; where fetching those modes from memory normally requires several
;; insns and some temporary registers.  Look in `spur.md' to see how
;; the requirement can be satisfied.

;; During reload a memory reference with an invalid address may be passed as an
;; operand.  Such an address will be replaced with a valid address later in the
;; reload pass.  In this case, nothing may be done with the address except to
;; use it as it stands.  If it is copied, it will not be replaced with a valid
;; address.  No attempt should be made to make such an address into a valid
;; address and no routine (such as `change_address') that will do so may be
;; called.  Note that `general_operand' will fail when applied to such an
;; address.
;;
;; The global variable `reload_in_progress' (which must be explicitly declared
;; if required) can be used to determine whether such special handling is
;; required.
;;
;; The variety of operands that have reloads depends on the rest of
;; the machine description, but typically on a RISC machine these can
;; only be pseudo registers that did not get hard registers, while on
;; other machines explicit memory references will get optional
;; reloads.
;;
;; If a scratch register is required to move an object to or from memory, it
;; can be allocated using `gen_reg_rtx' prior to reload.  But this is
;; impossible during and after reload.  If there are cases needing scratch
;; registers after reload, you must define `SECONDARY_INPUT_RELOAD_CLASS' and
;; perhaps also `SECONDARY_OUTPUT_RELOAD_CLASS' to detect them, and provide
;; patterns `reload_inM' or `reload_outM' to handle them.  *Note Register
;; Classes::.

;; The constraints on a `moveM' must permit moving any hard register to any
;; other hard register provided that `HARD_REGNO_MODE_OK' permits mode M in
;; both registers and `REGISTER_MOVE_COST' applied to their classes returns a
;; value of 2.

;; It is obligatory to support floating point `moveM' instructions
;; into and out of any registers that can hold fixed point values,
;; because unions and structures (which have modes `SImode' or
;; `DImode') can be in those registers and they may have floating
;; point members.

;; There may also be a need to support fixed point `moveM' instructions in and
;; out of floating point registers.  Unfortunately, I have forgotten why this
;; was so, and I don't know whether it is still true.  If `HARD_REGNO_MODE_OK'
;; rejects fixed point values in floating point registers, then the constraints
;; of the fixed point `moveM' instructions must be designed to avoid ever
;; trying to reload into a floating point register.

(define_expand "movqi"
  [(set (match_operand:QI 0 "general_operand" "")
	(match_operand:QI 1 "general_operand" ""))]
  ""
  "
{
  if (!reload_in_progress && !reload_completed
      && !register_operand (operands[0], QImode)
      && !reg_or_0_operand (operands[1], QImode))
    operands[1] = copy_to_mode_reg (QImode, operands[1]);
}")

(define_insn "*movqi_internal"
  [(set (match_operand:QI 0 "move_output_operand" "=d,d,d,d,Q,m,Q,m,d,c")
	(match_operand:QI 1 "move_input_operand" "dI,i,Q,m,d,d,O,O,c,d"))]
  "register_operand (operands[0], QImode) || reg_or_0_operand (operands[1], QImode)"
  "@
    or %0,%.,%1
    or %0,%.,%1
    ldb %0,%M1
    ldb %0,%M1
    stb %1,%M0
    stb %1,%M0
    stb %.,%M0
    stb %.,%M0
    mvfsys %0,%1
    mvtsys %0,%1"
  [(set_attr "length" "4,8,4,8,4,8,4,8,4,4")
   (set_attr "type" "either,long,sload,lload,mu,long,mu,long,mu,mu")])

(define_expand "movhi"
  [(set (match_operand:HI 0 "general_operand" "")
	(match_operand:HI 1 "general_operand" ""))]
  ""
  "
{
  if (!reload_in_progress && !reload_completed
      && !register_operand (operands[0], HImode)
      && !reg_or_0_operand (operands[1], HImode))
    operands[1] = copy_to_mode_reg (HImode, operands[1]);
}")

(define_insn "*movhi_internal"
  [(set (match_operand:HI 0 "move_output_operand" "=d,d,d,d,Q,m,Q,m,d,c")
	(match_operand:HI 1 "move_input_operand" "dI,i,Q,m,d,d,O,O,c,d"))]
  "register_operand (operands[0], HImode) || reg_or_0_operand (operands[1], HImode)"
  "@
    or %0,%.,%1
    or %0,%.,%1
    ldh %0,%M1
    ldh %0,%M1
    sth %1,%M0
    sth %1,%M0
    sth %.,%M0
    sth %.,%M0
    mvfsys %0,%1
    mvtsys %0,%1"
  [(set_attr "length" "4,8,4,8,4,8,4,8,4,4")
   (set_attr "type" "either,long,sload,lload,mu,long,mu,long,mu,mu")])

(define_expand "movsi"
  [(set (match_operand:SI 0 "general_operand" "")
	(match_operand:SI 1 "general_operand" ""))]
  ""
  "
{
  if (!reload_in_progress && !reload_completed
      && !register_operand (operands[0], SImode)
      && !reg_or_0_operand (operands[1], SImode))
    operands[1] = copy_to_mode_reg (SImode, operands[1]);

  /* Convert addressing modes into the appropriate add/sub with the clobbers
     needed.  This is generated by builtin_setjmp in the exception handling. */
  if (GET_CODE (operands[1]) == PLUS)
    {
      emit_insn (gen_addsi3 (operands[0], XEXP (operands[1], 0),
			     XEXP (operands[1], 1)));
      DONE;
    }

  else if (GET_CODE (operands[1]) == MINUS)
    {
      emit_insn (gen_subsi3 (operands[0], XEXP (operands[1], 0),
			     XEXP (operands[1], 1)));
      DONE;
    }
}")

(define_insn "*movsi_internal"
  [(set (match_operand:SI 0 "move_output_operand" "=d,d,d,d,d,Q,m,Q,m,d,c")
	(match_operand:SI 1 "move_input_operand" "dI,F,i,Q,m,d,d,O,O,c,d"))]
  "register_operand (operands[0], SImode) || reg_or_0_operand (operands[1], SImode)"
  "@
    or %0,%.,%1
    or %0,%.,%L1
    or %0,%.,%1
    ldw %0,%M1
    ldw %0,%M1
    stw %1,%M0
    stw %1,%M0
    stw %.,%M0
    stw %.,%M0
    mvfsys %0,%1
    mvtsys %0,%1"
  [(set_attr "length" "4,8,8,4,8,4,8,4,8,4,4")
   (set_attr "type" "either,long,long,sload,lload,mu,long,mu,long,mu,mu")])

(define_expand "movdi"
  [(set (match_operand:DI 0 "general_operand" "")
	(match_operand:DI 1 "general_operand" ""))]
  ""
  "
{
  if (!reload_in_progress && !reload_completed
      && !register_operand (operands[0], DImode)
      && !register_operand (operands[1], DImode))
    operands[1] = copy_to_mode_reg (DImode, operands[1]);
}")

(define_insn "*movdi_internal"
  [(set (match_operand:DI 0 "move_output_operand" "=e,e,e,e,Q,m,e,a,a")
	(match_operand:DI 1 "move_input_operand" "eI,iF,Q,m,e,e,a,e,O"))]
  "register_operand (operands[0], DImode) || register_operand (operands[1], DImode)"
  "* return d30v_move_2words (operands, insn);"
  [(set_attr "length" "8,16,4,8,4,8,8,4,4")
   (set_attr "type" "multi,multi,sload,lload,mu,long,multi,iu,iu")])

(define_split
  [(set (match_operand:DI 0 "gpr_operand" "")
	(match_operand:DI 1 "gpr_or_dbl_const_operand" ""))]
  "reload_completed"
  [(set (match_dup 2) (match_dup 3))
   (set (match_dup 4) (match_dup 5))]
  "
{
  d30v_split_double (operands[0], &operands[2], &operands[4]);
  d30v_split_double (operands[1], &operands[3], &operands[5]);
}")

(define_expand "movsf"
  [(set (match_operand:SF 0 "general_operand" "")
	(match_operand:SF 1 "general_operand" ""))]
  ""
  "
{
  if (!reload_in_progress && !reload_completed
      && !register_operand (operands[0], SFmode)
      && !reg_or_0_operand (operands[1], SFmode))
    operands[1] = copy_to_mode_reg (SFmode, operands[1]);
}")

(define_insn "*movsf_internal"
  [(set (match_operand:SF 0 "move_output_operand" "=d,d,d,d,d,Q,m,Q,m")
	(match_operand:SF 1 "move_input_operand" "d,G,F,Q,m,d,d,G,G"))]
  "register_operand (operands[0], SFmode) || reg_or_0_operand (operands[1], SFmode)"
  "@
    or %0,%.,%1
    or %0,%.,0
    or %0,%.,%f1
    ldw %0,%M1
    ldw %0,%M1
    stw %1,%M0
    stw %1,%M0
    stw %.,%M0
    stw %.,%M0"
  [(set_attr "length" "4,4,8,4,8,4,8,4,8")
   (set_attr "type" "either,either,long,sload,lload,mu,long,mu,long")])

(define_expand "movdf"
  [(set (match_operand:DF 0 "general_operand" "")
	(match_operand:DF 1 "general_operand" ""))]
  ""
  "
{
  if (!reload_in_progress && !reload_completed
      && !register_operand (operands[0], DFmode)
      && !register_operand (operands[1], DFmode))
    operands[1] = copy_to_mode_reg (DFmode, operands[1]);
}")

(define_insn "*movdf_internal"
  [(set (match_operand:DF 0 "move_output_operand" "=e,e,e,e,Q,m,!*e,!*a")
	(match_operand:DF 1 "move_input_operand" "eG,F,Q,m,e,e,!*a,!*e"))]
  "register_operand (operands[0], DFmode) || register_operand (operands[1], DFmode)"
  "* return d30v_move_2words (operands, insn);"
  [(set_attr "length" "8,16,4,8,4,8,8,4")
   (set_attr "type" "multi,multi,sload,lload,mu,long,multi,iu")])

(define_split
  [(set (match_operand:DF 0 "gpr_operand" "")
	(match_operand:DF 1 "gpr_or_dbl_const_operand" ""))]
  "reload_completed"
  [(set (match_dup 2) (match_dup 3))
   (set (match_dup 4) (match_dup 5))]
  "
{
  d30v_split_double (operands[0], &operands[2], &operands[4]);
  d30v_split_double (operands[1], &operands[3], &operands[5]);
}")

(define_expand "movcc"
  [(set (match_operand:CC 0 "general_operand" "")
	(match_operand:CC 1 "general_operand" ""))]
  ""
  "
{
  if (!reload_in_progress && !reload_completed
      && GET_CODE (operands[0]) == MEM
      && GET_CODE (operands[1]) == MEM)
    operands[1] = copy_to_mode_reg (CCmode, operands[1]);
}")

(define_insn "*movcc_internal"
  [(set (match_operand:CC 0 "move_output_operand" "=f,f,f,d,?d,f,d,*d,*d,*Q,*m")
	(match_operand:CC 1 "move_input_operand" "f,O,N,b,f,d,dON,*Q,*m,*d,*d"))]
  "!memory_operand (operands[0], CCmode) || !memory_operand (operands[1], CCmode)"
  "@
    orfg %0,%1,%1
    andfg %0,%0,0
    orfg %0,%0,1
    #
    mvfsys %0,%1
    cmpne %0,%1,0
    or %0,%.,%1
    ldb %0,%M1
    ldb %0,%M1
    stb %1,%M0
    stb %1,%M0"
  [(set_attr "length" "4,4,4,8,4,4,4,4,8,4,8")
   (set_attr "type" "either,either,either,multi,mu,mu,either,sload,lload,mu,long")])

(define_split
  [(set (match_operand:CC 0 "gpr_operand" "")
	(match_operand:CC 1 "br_flag_operand" ""))]
  "reload_completed"
  [(set (match_dup 2)
	(const_int 0))
   (set (match_dup 2)
	(if_then_else:SI (ne:CC (match_dup 1)
				(const_int 0))
			 (const_int 1)
			 (match_dup 2)))]
  "
{
  operands[2] = gen_lowpart (SImode, operands[0]);
}")


;; ::::::::::::::::::::
;; ::
;; :: Conversions
;; ::
;; ::::::::::::::::::::

;; Signed conversions from a smaller integer to a larger integer
(define_insn "extendqihi2"
  [(set (match_operand:HI 0 "gpr_operand" "=d,d,d")
	(sign_extend:HI (match_operand:QI 1 "gpr_or_memory_operand" "d,Q,m")))]
  ""
  "@
    #
    ldb %0,%M1
    ldb %0,%M1"
  [(set_attr "type" "multi,sload,lload")
   (set_attr "length" "16,4,8")])

(define_split
  [(set (match_operand:HI 0 "gpr_operand" "")
	(sign_extend:HI (match_operand:QI 1 "gpr_operand" "")))]
  "reload_completed"
  [(match_dup 2)
   (match_dup 3)]
  "
{
  rtx op0   = gen_lowpart (SImode, operands[0]);
  rtx op1   = gen_lowpart (SImode, operands[1]);
  rtx shift = gen_rtx (CONST_INT, VOIDmode, 24);

  operands[2] = gen_ashlsi3 (op0, op1, shift);
  operands[3] = gen_ashrsi3 (op0, op0, shift);
}")

(define_insn "extendqisi2"
  [(set (match_operand:SI 0 "gpr_operand" "=d,d,d")
	(sign_extend:SI (match_operand:QI 1 "gpr_or_memory_operand" "d,Q,m")))]
  ""
  "@
    #
    ldb %0,%M1
    ldb %0,%M1"
  [(set_attr "type" "multi,sload,lload")
   (set_attr "length" "16,4,8")])

(define_split
  [(set (match_operand:SI 0 "gpr_operand" "")
	(sign_extend:SI (match_operand:QI 1 "gpr_operand" "")))]
  "reload_completed"
  [(match_dup 2)
   (match_dup 3)]
  "
{
  rtx op0   = gen_lowpart (SImode, operands[0]);
  rtx op1   = gen_lowpart (SImode, operands[1]);
  rtx shift = gen_rtx (CONST_INT, VOIDmode, 24);

  operands[2] = gen_ashlsi3 (op0, op1, shift);
  operands[3] = gen_ashrsi3 (op0, op0, shift);
}")

(define_insn "extendhisi2"
  [(set (match_operand:SI 0 "gpr_operand" "=d,d,d")
	(sign_extend:SI (match_operand:HI 1 "gpr_or_memory_operand" "d,Q,m")))]
  ""
  "@
    #
    ldh %0,%M1
    ldh %0,%M1"
  [(set_attr "type" "multi,sload,lload")
   (set_attr "length" "16,4,8")])

(define_split
  [(set (match_operand:SI 0 "gpr_operand" "")
	(sign_extend:SI (match_operand:HI 1 "gpr_operand" "")))]
  "reload_completed"
  [(match_dup 2)
   (match_dup 3)]
  "
{
  rtx op0   = gen_lowpart (SImode, operands[0]);
  rtx op1   = gen_lowpart (SImode, operands[1]);
  rtx shift = gen_rtx (CONST_INT, VOIDmode, 16);

  operands[2] = gen_ashlsi3 (op0, op1, shift);
  operands[3] = gen_ashrsi3 (op0, op0, shift);
}")

(define_insn "extendqidi2"
  [(set (match_operand:DI 0 "gpr_operand" "=e,e,e")
	(sign_extend:DI (match_operand:QI 1 "gpr_or_memory_operand" "d,Q,m")))]
  ""
  "#"
  [(set_attr "length" "12,8,12")
   (set_attr "type" "multi")])

(define_split
  [(set (match_operand:DI 0 "gpr_operand" "")
	(sign_extend:DI (match_operand:QI 1 "gpr_or_memory_operand" "")))]
  "reload_completed"
  [(set (match_dup 2) (sign_extend:SI (match_dup 1)))
   (set (match_dup 3) (ashiftrt:SI (match_dup 2) (const_int 31)))]
  "
{
  d30v_split_double (operands[0], &operands[3], &operands[2]);
}")

(define_insn "extendhidi2"
  [(set (match_operand:DI 0 "gpr_operand" "=e,e,e")
	(sign_extend:DI (match_operand:HI 1 "gpr_or_memory_operand" "d,Q,m")))]
  ""
  "#"
  [(set_attr "length" "12,8,12")
   (set_attr "type" "multi")])

(define_split
  [(set (match_operand:DI 0 "gpr_operand" "")
	(sign_extend:DI (match_operand:HI 1 "gpr_or_memory_operand" "")))]
  "reload_completed"
  [(set (match_dup 2) (sign_extend:SI (match_dup 1)))
   (set (match_dup 3) (ashiftrt:SI (match_dup 2) (const_int 31)))]
  "
{
  d30v_split_double (operands[0], &operands[3], &operands[2]);
}")

(define_insn "extendsidi2"
  [(set (match_operand:DI 0 "gpr_operand" "=e,e,e")
	(sign_extend:DI (match_operand:SI 1 "gpr_or_memory_operand" "d,Q,m")))]
  ""
  "#"
  [(set_attr "length" "8,8,12")
   (set_attr "type" "multi")])

(define_split
  [(set (match_operand:DI 0 "gpr_operand" "")
	(sign_extend:DI (match_operand:SI 1 "gpr_or_memory_operand" "")))]
  "reload_completed"
  [(set (match_dup 2) (match_dup 1))
   (set (match_dup 3) (ashiftrt:SI (match_dup 2) (const_int 31)))]
  "
{
  d30v_split_double (operands[0], &operands[3], &operands[2]);
}")
	
;; Unsigned conversions from a smaller integer to a larger integer

(define_insn "zero_extendqihi2"
  [(set (match_operand:HI 0 "gpr_operand" "=d,d,d")
	(zero_extend:HI (match_operand:QI 1 "gpr_or_memory_operand" "d,Q,m")))]
  ""
  "@
    and %0,%1,0xff
    ldbu %0,%M1
    ldbu %0,%M1"
  [(set_attr "length" "8,4,8")
   (set_attr "type" "long,sload,lload")])

(define_insn "zero_extendqisi2"
  [(set (match_operand:SI 0 "gpr_operand" "=d,d,d")
	(zero_extend:SI (match_operand:QI 1 "gpr_or_memory_operand" "d,Q,m")))]
  ""
  "@
    and %0,%1,0xff
    ldbu %0,%M1
    ldbu %0,%M1"
  [(set_attr "length" "8,4,8")
   (set_attr "type" "long,sload,lload")])

(define_insn "zero_extendhisi2"
  [(set (match_operand:SI 0 "gpr_operand" "=d,d,d")
	(zero_extend:SI (match_operand:HI 1 "gpr_or_memory_operand" "d,Q,m")))]
  ""
  "@
    and %0,%1,0xffff
    ldhu %0,%M1
    ldhu %0,%M1"
  [(set_attr "length" "8,4,8")
   (set_attr "type" "long,sload,lload")])

(define_insn "zero_extendqidi2"
  [(set (match_operand:DI 0 "gpr_operand" "=e,e,e")
	(zero_extend:DI (match_operand:QI 1 "gpr_or_memory_operand" "d,Q,m")))]
  ""
  "#"
  [(set_attr "length" "12,8,12")
   (set_attr "type" "multi")])

(define_split
  [(set (match_operand:DI 0 "gpr_operand" "")
	(zero_extend:DI (match_operand:QI 1 "gpr_or_memory_operand" "")))]
  "reload_completed"
  [(set (match_dup 2) (zero_extend:SI (match_dup 1)))
   (set (match_dup 3) (const_int 0))]
  "
{
  d30v_split_double (operands[0], &operands[3], &operands[2]);
}")

(define_insn "zero_extendhidi2"
  [(set (match_operand:DI 0 "gpr_operand" "=e,e,e")
	(zero_extend:DI (match_operand:HI 1 "gpr_or_memory_operand" "d,Q,m")))]
  ""
  "#"
  [(set_attr "length" "8,8,12")
   (set_attr "type" "multi")])

(define_split
  [(set (match_operand:DI 0 "gpr_operand" "")
	(zero_extend:DI (match_operand:HI 1 "gpr_or_memory_operand" "")))]
  "reload_completed"
  [(set (match_dup 2) (zero_extend:SI (match_dup 1)))
   (set (match_dup 3) (const_int 0))]
  "
{
  d30v_split_double (operands[0], &operands[3], &operands[2]);
}")

(define_insn "zero_extendsidi2"
  [(set (match_operand:DI 0 "gpr_operand" "=e,e,e")
	(zero_extend:DI (match_operand:SI 1 "gpr_or_memory_operand" "d,Q,m")))]
  ""
  "#"
  [(set_attr "length" "8,8,12")
   (set_attr "type" "multi")])

(define_split
  [(set (match_operand:DI 0 "gpr_operand" "")
	(zero_extend:DI (match_operand:SI 1 "gpr_or_memory_operand" "")))]
  "reload_completed"
  [(set (match_dup 2) (match_dup 1))
   (set (match_dup 3) (const_int 0))]
  "
{
  d30v_split_double (operands[0], &operands[3], &operands[2]);
}")


;; ::::::::::::::::::::
;; ::
;; :: 32 bit Integer arithmetic
;; ::
;; ::::::::::::::::::::

;; Addition
(define_expand "addsi3"
  [(parallel [(set (match_operand:SI 0 "gpr_operand" "")
		   (plus:SI (match_operand:SI 1 "gpr_operand" "")
			    (match_operand:SI 2 "gpr_or_constant_operand" "")))
	      (clobber (match_dup 3))
	      (clobber (match_dup 4))
	      (clobber (match_dup 5))])]
  ""
  "
{
  operands[3] = gen_rtx (REG, CCmode, FLAG_CARRY);
  operands[4] = gen_rtx (REG, CCmode, FLAG_OVERFLOW);
  operands[5] = gen_rtx (REG, CCmode, FLAG_ACC_OVER);
}")

(define_insn "*addsi3_internal"
  [(set (match_operand:SI 0 "gpr_operand" "=d,d")
	(plus:SI (match_operand:SI 1 "gpr_operand" "%d,d")
		 (match_operand:SI 2 "gpr_or_constant_operand" "dI,i")))
   (clobber (match_operand:CC 3 "flag_operand" "=f,f"))
   (clobber (match_operand:CC 4 "flag_operand" "=f,f"))
   (clobber (match_operand:CC 5 "flag_operand" "=f,f"))]
  ""
  "add %0,%1,%2"
  [(set_attr "length" "4,8")
   (set_attr "type" "either,long")])

;; Subtraction
(define_expand "subsi3"
  [(parallel [(set (match_operand:SI 0 "gpr_operand" "")
		   (minus:SI (match_operand:SI 1 "reg_or_0_operand" "")
			     (match_operand:SI 2 "gpr_or_constant_operand" "")))
	      (clobber (match_dup 3))
	      (clobber (match_dup 4))
	      (clobber (match_dup 5))])]
  ""
  "
{
  operands[3] = gen_rtx (REG, CCmode, FLAG_CARRY);
  operands[4] = gen_rtx (REG, CCmode, FLAG_OVERFLOW);
  operands[5] = gen_rtx (REG, CCmode, FLAG_ACC_OVER);
}")

(define_insn "*subsi3_internal"
  [(set (match_operand:SI 0 "gpr_operand" "=d,d,d,d")
	(minus:SI (match_operand:SI 1 "reg_or_0_operand" "d,d,O,O")
		  (match_operand:SI 2 "gpr_or_constant_operand" "dI,i,dI,i")))
   (clobber (match_operand:CC 3 "flag_operand" "=f,f,f,f"))
   (clobber (match_operand:CC 4 "flag_operand" "=f,f,f,f"))
   (clobber (match_operand:CC 5 "flag_operand" "=f,f,f,f"))]
  ""
  "@
    sub %0,%1,%2
    sub %0,%1,%2
    sub %0,%.,%2
    sub %0,%.,%2"
  [(set_attr "length" "4,8,4,8")
   (set_attr "type" "either,long,either,long")])

;; Multiplication (same size)
(define_insn "mulsi3"
  [(set (match_operand:SI 0 "gpr_operand" "=d")
	(mult:SI (match_operand:SI 1 "gpr_operand" "%d")
		 (match_operand:SI 2 "gpr_or_signed6_operand" "dI")))]
  ""
  "mul %0,%1,%2"
  [(set_attr "length" "4")
   (set_attr "type" "mul")])

;; Signed multiplication producing 64 bit results from 32 bit inputs
(define_insn "mulsidi3"
  [(set (match_operand:DI 0 "accum_operand" "=a")
	(mult:DI (sign_extend:DI (match_operand:SI 1 "gpr_operand" "d"))
		 (sign_extend:DI (match_operand:SI 2 "gpr_operand" "d"))))]
  ""
  "mulx %0,%1,%2"
  [(set_attr "length" "4")
   (set_attr "type" "mul")])

(define_insn "*mulsidi3_const"
  [(set (match_operand:DI 0 "accum_operand" "=a")
	(mult:DI (sign_extend:DI (match_operand:SI 1 "gpr_operand" "%d"))
		 (match_operand:DI 2 "signed6_operand" "I")))]
  ""
  "mulx %0,%1,%2"
  [(set_attr "length" "4")
   (set_attr "type" "mul")])

;; Signed multiplication producing just the upper 32 bits from a 32x32->64
;; bit multiply.  We specifically allow any integer constant here so
;; allow division by constants to be done by multiplying by a large constant.

(define_expand "smulsi3_highpart"
  [(set (match_dup 3)
	(mult:DI (sign_extend:DI (match_operand:SI 1 "gpr_operand" ""))
		 (match_operand:SI 2 "gpr_or_constant_operand" "")))
   (set (match_operand:SI 0 "gpr_operand" "")
	(truncate:SI (lshiftrt:DI (match_dup 3)
				  (const_int 32))))]
  ""
  "
{
  operands[3] = gen_reg_rtx (DImode);

  if (GET_CODE (operands[2]) == CONST_INT &&
      !IN_RANGE_P (INTVAL (operands[2]), -32, 31))
    operands[2] = force_reg (SImode, operands[2]);

  if (GET_CODE (operands[2]) == REG || GET_CODE (operands[2]) == SUBREG)
    operands[2] = gen_rtx (SIGN_EXTEND, DImode, operands[2]);
}")

(define_insn "*di_highpart"
  [(set (match_operand:SI 0 "gpr_operand" "=d,d")
	(truncate:SI (lshiftrt:DI (match_operand:DI 1 "gpr_or_accum_operand" "e,a")
		      (const_int 32))))]
  ""
  "@
    or %0,%.,%U1
    mvfacc %0,%1,32"
  [(set_attr "length" "4")
   (set_attr "type" "either,iu")])

;; Negation
(define_expand "negsi2"
  [(parallel [(set (match_operand:SI 0 "gpr_operand" "")
		   (neg:SI (match_operand:SI 1 "gpr_operand" "")))
	      (clobber (match_dup 2))
	      (clobber (match_dup 3))
	      (clobber (match_dup 4))])]
  ""
  "
{
  operands[2] = gen_rtx (REG, CCmode, FLAG_CARRY);
  operands[3] = gen_rtx (REG, CCmode, FLAG_OVERFLOW);
  operands[4] = gen_rtx (REG, CCmode, FLAG_ACC_OVER);
}")

(define_insn "*negsi2_internal"
  [(set (match_operand:SI 0 "gpr_operand" "=d")
	(neg:SI (match_operand:SI 1 "gpr_operand" "d")))
   (clobber (match_operand:CC 2 "flag_operand" "=f"))
   (clobber (match_operand:CC 3 "flag_operand" "=f"))
   (clobber (match_operand:CC 4 "flag_operand" "=f"))]
  ""
  "sub %0,%.,%1"
  [(set_attr "length" "4")
   (set_attr "type" "either")])

;; Absolute value
(define_insn "abssi2"
  [(set (match_operand:SI 0 "gpr_operand" "=d")
	(abs:SI (match_operand:SI 1 "gpr_operand" "d")))]
  ""
  "abs %0,%1"
  [(set_attr "length" "4")
   (set_attr "type" "either")])


;; ::::::::::::::::::::
;; ::
;; :: 64 bit Integer arithmetic
;; ::
;; ::::::::::::::::::::

;; Addition
(define_expand "adddi3"
  [(parallel [(set (match_operand:DI 0 "gpr_operand" "")
		   (plus:DI (match_operand:DI 1 "gpr_operand" "")
			    (match_operand:DI 2 "gpr_or_constant_operand" "")))
	      (clobber (match_dup 3))
	      (clobber (match_dup 4))
	      (clobber (match_dup 5))])]
  ""
  "
{
  operands[3] = gen_rtx (REG, CCmode, FLAG_CARRY);
  operands[4] = gen_rtx (REG, CCmode, FLAG_OVERFLOW);
  operands[5] = gen_rtx (REG, CCmode, FLAG_ACC_OVER);
}")

(define_insn "*adddi3_internal"
  [(set (match_operand:DI 0 "gpr_operand" "=e,e,e,e")
	(plus:DI (match_operand:DI 1 "gpr_operand" "%e,e,e,e")
		 (match_operand:DI 2 "gpr_or_constant_operand" "I,i,e,F")))
   (clobber (match_operand:CC 3 "flag_operand" "=f,f,f,f"))
   (clobber (match_operand:CC 4 "flag_operand" "=f,f,f,f"))
   (clobber (match_operand:CC 5 "flag_operand" "=f,f,f,f"))]
  ""
  "#"
  [(set_attr "length" "8,12,8,16")
   (set_attr "type" "multi")])

(define_insn "addsi3_set_carry"
  [(set (match_operand:SI 0 "gpr_operand" "=d,d")
	(plus:SI (match_operand:SI 1 "gpr_operand" "%d,d")
		 (match_operand:SI 2 "gpr_or_constant_operand" "dI,i")))
   (set (match_operand:CC 3 "carry_operand" "=f,f")
	(unspec:CC [(match_dup 1)
		 (match_dup 2)] 1))
   (clobber (match_operand:CC 4 "flag_operand" "=f,f"))
   (clobber (match_operand:CC 5 "flag_operand" "=f,f"))]
  ""
  "add %0,%1,%2"
  [(set_attr "length" "4,8")
   (set_attr "type" "scarry,lcarry")])

(define_insn "addsi3_use_carry"
  [(set (match_operand:SI 0 "gpr_operand" "=d,d")
	(unspec:SI [(match_operand:SI 1 "gpr_operand" "%d,d")
		 (match_operand:SI 2 "gpr_or_constant_operand" "dI,i")
		 (match_operand:CC 3 "carry_operand" "+f,f")] 2))
   (clobber (match_operand:CC 4 "flag_operand" "=f,f"))
   (clobber (match_operand:CC 5 "flag_operand" "=f,f"))]
  ""
  "addc %0,%1,%2"
  [(set_attr "length" "4,8")
   (set_attr "type" "scarry,lcarry")])

(define_split
  [(set (match_operand:DI 0 "gpr_operand" "")
	(plus:DI (match_operand:DI 1 "gpr_operand" "")
		 (match_operand:DI 2 "gpr_or_constant_operand" "")))
   (clobber (match_operand:CC 3 "flag_operand" ""))
   (clobber (match_operand:CC 4 "flag_operand" ""))
   (clobber (match_operand:CC 5 "flag_operand" ""))]
  "reload_completed"
  [(match_dup 6)
   (match_dup 7)]
  "
{
  rtx high[3];
  rtx low[3];

  d30v_split_double (operands[0], &high[0], &low[0]);
  d30v_split_double (operands[1], &high[1], &low[1]);
  d30v_split_double (operands[2], &high[2], &low[2]);

  operands[6] = gen_addsi3_set_carry (low[0], low[1], low[2], operands[3],
				      operands[4], operands[5]);

  operands[7] = gen_addsi3_use_carry (high[0], high[1], high[2], operands[3],
				      operands[4], operands[5]);
}")

;; Subtraction
(define_expand "subdi3"
  [(parallel [(set (match_operand:DI 0 "gpr_operand" "")
		   (minus:DI (match_operand:DI 1 "gpr_operand" "")
			     (match_operand:DI 2 "gpr_or_constant_operand" "")))
	      (clobber (match_dup 3))
	      (clobber (match_dup 4))
	      (clobber (match_dup 5))])]
  ""
  "
{
  operands[3] = gen_rtx (REG, CCmode, FLAG_CARRY);
  operands[4] = gen_rtx (REG, CCmode, FLAG_OVERFLOW);
  operands[5] = gen_rtx (REG, CCmode, FLAG_ACC_OVER);
}")

(define_insn "*subdi3_internal"
  [(set (match_operand:DI 0 "gpr_operand" "=e,e,e,e")
	(minus:DI (match_operand:DI 1 "gpr_operand" "e,e,e,e")
		  (match_operand:DI 2 "gpr_or_constant_operand" "I,i,e,F")))
   (clobber (match_operand:CC 3 "flag_operand" "=f,f,f,f"))
   (clobber (match_operand:CC 4 "flag_operand" "=f,f,f,f"))
   (clobber (match_operand:CC 5 "flag_operand" "=f,f,f,f"))]
  ""
  "#"
  [(set_attr "length" "8,12,8,16")
   (set_attr "type" "multi")])

(define_insn "subsi3_set_carry"
  [(set (match_operand:SI 0 "gpr_operand" "=d,d,d,d")
	(minus:SI (match_operand:SI 1 "reg_or_0_operand" "d,d,O,O")
		  (match_operand:SI 2 "gpr_or_constant_operand" "dI,i,dI,i")))
   (set (match_operand:CC 3 "carry_operand" "=f,f,f,f")
	(unspec:CC [(match_dup 1)
		    (match_dup 2)] 3))
   (clobber (match_operand:CC 4 "flag_operand" "=f,f,f,f"))
   (clobber (match_operand:CC 5 "flag_operand" "=f,f,f,f"))]
  ""
  "@
    sub %0,%1,%2
    sub %0,%1,%2
    sub %0,%.,%2
    sub %0,%.,%2"
  [(set_attr "length" "4,8,4,8")
   (set_attr "type" "scarry,lcarry,scarry,lcarry")])

(define_insn "subsi3_use_carry"
  [(set (match_operand:SI 0 "gpr_operand" "=d,d,d,d")
	(unspec:SI [(match_operand:SI 1 "reg_or_0_operand" "d,d,O,O")
		    (match_operand:SI 2 "gpr_operand" "dI,i,dI,i")
		    (match_operand:CC 3 "carry_operand" "+f,f,f,f")] 4))
   (clobber (match_operand:CC 4 "flag_operand" "=f,f,f,f"))
   (clobber (match_operand:CC 5 "flag_operand" "=f,f,f,f"))]
  ""
  "@
    subb %0,%1,%2
    subb %0,%1,%2
    subb %0,%.,%2
    subb %0,%.,%2"
  [(set_attr "length" "4,8,4,8")
   (set_attr "type" "scarry,lcarry,scarry,lcarry")])

(define_split
  [(set (match_operand:DI 0 "gpr_operand" "")
	(minus:DI (match_operand:DI 1 "gpr_operand" "")
		  (match_operand:DI 2 "gpr_or_constant_operand" "")))
   (clobber (match_operand:CC 3 "flag_operand" ""))
   (clobber (match_operand:CC 4 "flag_operand" ""))
   (clobber (match_operand:CC 5 "flag_operand" ""))]
  "reload_completed"
  [(match_dup 6)
   (match_dup 7)]
  "
{
  rtx high[3];
  rtx low[3];

  d30v_split_double (operands[0], &high[0], &low[0]);
  d30v_split_double (operands[1], &high[1], &low[1]);
  d30v_split_double (operands[2], &high[2], &low[2]);

  operands[6] = gen_subsi3_set_carry (low[0], low[1], low[2], operands[3],
				      operands[4], operands[5]);

  operands[7] = gen_subsi3_use_carry (high[0], high[1], high[2], operands[3],
				      operands[4], operands[5]);
}")

;; Negation
(define_expand "negdi2"
  [(parallel [(set (match_operand:DI 0 "gpr_operand" "")
		   (neg:DI (match_operand:DI 1 "gpr_operand" "")))
	      (clobber (match_dup 2))
	      (clobber (match_dup 3))
	      (clobber (match_dup 4))])]
  ""
  "
{
  operands[2] = gen_rtx (REG, CCmode, FLAG_CARRY);
  operands[3] = gen_rtx (REG, CCmode, FLAG_OVERFLOW);
  operands[4] = gen_rtx (REG, CCmode, FLAG_ACC_OVER);
}")

(define_insn "*negdi2_internal"
  [(set (match_operand:DI 0 "gpr_operand" "=e")
	(neg:DI (match_operand:DI 1 "gpr_operand" "e")))
   (clobber (match_operand:CC 2 "flag_operand" "=f"))
   (clobber (match_operand:CC 3 "flag_operand" "=f"))
   (clobber (match_operand:CC 4 "flag_operand" "=f"))]
  ""
  "#"
  [(set_attr "length" "8")
   (set_attr "type" "multi")])

(define_split
  [(set (match_operand:DI 0 "gpr_operand" "=e")
	(neg:DI (match_operand:DI 1 "gpr_operand" "e")))
   (clobber (match_operand:CC 2 "flag_operand" "=f"))
   (clobber (match_operand:CC 3 "flag_operand" "=f"))
   (clobber (match_operand:CC 4 "flag_operand" "=f"))]
  "reload_completed"
  [(match_dup 5)
   (match_dup 6)]
  "
{
  rtx high[2];
  rtx low[2];
  rtx r0 = const0_rtx;

  d30v_split_double (operands[0], &high[0], &low[0]);
  d30v_split_double (operands[1], &high[1], &low[1]);

  operands[5] = gen_subsi3_set_carry (low[0], r0, low[1], operands[2],
				      operands[3], operands[4]);

  operands[6] = gen_subsi3_use_carry (high[0], r0, high[1], operands[2],
				      operands[3], operands[4]);
}")


;; ::::::::::::::::::::
;; ::
;; :: 32 bit Integer Shifts and Rotates
;; ::
;; ::::::::::::::::::::

;; Arithmetic Shift Left (negate the shift value and use shift right)
(define_expand "ashlsi3"
  [(set (match_operand:SI 0 "gpr_operand" "")
	(ashift:SI (match_operand:SI 1 "gpr_operand" "")
		   (match_operand:SI 2 "gpr_or_unsigned5_operand" "")))]
  ""
  "
{
  if (GET_CODE (operands[2]) != CONST_INT)
    operands[2] = gen_rtx (NEG, SImode, negate_rtx (SImode, operands[2]));
}")

(define_insn "*ashlsi3_constant"
  [(set (match_operand:SI 0 "gpr_operand" "=d")
	(ashift:SI (match_operand:SI 1 "gpr_operand" "d")
		   (match_operand:SI 2 "unsigned5_operand" "J")))]
  ""
  "sra %0,%1,%n2"
  [(set_attr "length" "4")
   (set_attr "type" "either")])

(define_insn "*ashlsi3_register"
  [(set (match_operand:SI 0 "gpr_operand" "=d")
	(ashift:SI (match_operand:SI 1 "gpr_operand" "d")
		   (neg:SI (match_operand:SI 2 "gpr_operand" "d"))))]
  ""
  "sra %0,%1,%2"
  [(set_attr "length" "4")
   (set_attr "type" "either")])

;; Arithmetic Shift Right
(define_insn "ashrsi3"
  [(set (match_operand:SI 0 "gpr_operand" "=d")
	(ashiftrt:SI (match_operand:SI 1 "gpr_operand" "d")
		     (match_operand:SI 2 "gpr_or_unsigned5_operand" "dJ")))]
  ""
  "sra %0,%1,%2"
  [(set_attr "length" "4")])

;; Logical Shift Right
(define_insn "lshrsi3"
  [(set (match_operand:SI 0 "gpr_operand" "=d")
	(lshiftrt:SI (match_operand:SI 1 "gpr_operand" "d")
		     (match_operand:SI 2 "gpr_or_unsigned5_operand" "dJ")))]
  ""
  "srl %0,%1,%2"
  [(set_attr "length" "4")
   (set_attr "type" "either")])

;; Rotate Left (negate the shift value and use rotate right)
(define_expand "rotlsi3"
  [(set (match_operand:SI 0 "gpr_operand" "")
	(rotate:SI (match_operand:SI 1 "gpr_operand" "")
		   (match_operand:SI 2 "gpr_or_unsigned5_operand" "")))]
  ""
  "
{
  if (GET_CODE (operands[2]) != CONST_INT)
    operands[2] = gen_rtx (NEG, SImode, negate_rtx (SImode, operands[2]));
}")

(define_insn "*rotlsi3_constant"
  [(set (match_operand:SI 0 "gpr_operand" "=d")
	(rotate:SI (match_operand:SI 1 "gpr_operand" "d")
		   (match_operand:SI 2 "unsigned5_operand" "J")))]
  ""
  "rot %0,%1,%n2"
  [(set_attr "length" "4")
   (set_attr "type" "either")])

(define_insn "*rotlsi3_register"
  [(set (match_operand:SI 0 "gpr_operand" "=d")
	(rotate:SI (match_operand:SI 1 "gpr_operand" "d")
		   (neg:SI (match_operand:SI 2 "gpr_operand" "d"))))]
  ""
  "rot %0,%1,%2"
  [(set_attr "length" "4")
   (set_attr "type" "either")])

;; Rotate Right
(define_insn "rotrsi3"
  [(set (match_operand:SI 0 "gpr_operand" "=d")
	(rotatert:SI (match_operand:SI 1 "gpr_operand" "d")
		     (match_operand:SI 2 "gpr_or_unsigned5_operand" "dJ")))]
  ""
  "rot %0,%1,%2"
  [(set_attr "length" "4")
   (set_attr "type" "either")])


;; ::::::::::::::::::::
;; ::
;; :: 64 bit Integer Shifts and Rotates
;; ::
;; ::::::::::::::::::::

;; Arithmetic Shift Left
(define_expand "ashldi3"
  [(parallel [(set (match_operand:DI 0 "gpr_operand" "")
		   (ashift:DI (match_operand:DI 1 "gpr_operand" "")
			      (match_operand:SI 2 "gpr_or_unsigned6_operand" "")))
	      (clobber (match_scratch:CC 3 ""))])]
  ""
  "
{
  if (GET_CODE (operands[2]) == CONST_INT)
    {
      if (IN_RANGE_P (INTVAL (operands[2]), 0, 63))
	{
	  emit_insn (gen_ashldi3_constant (operands[0], operands[1], operands[2]));
	  DONE;
	}
      else
	operands[2] = copy_to_mode_reg (SImode, operands[2]);
    }

  operands[2] = gen_rtx (NEG, SImode, negate_rtx (SImode, operands[2]));
}")

(define_insn "ashldi3_constant"
  [(set (match_operand:DI 0 "gpr_operand" "=e,e")
	(ashift:DI (match_operand:DI 1 "gpr_operand" "0,e")
		   (match_operand:SI 2 "unsigned6_operand" "J,P")))]
  ""
  "@
    src %U0,%L0,%n2\;sra %L0,%L0,%n2
    sra %U0,%L1,%s2\;or %L0,%.,0"
  [(set_attr "length" "8")
   (set_attr "type" "multi")])

(define_insn "*ashldi3_register"
  [(set (match_operand:DI 0 "gpr_operand" "=e")
	(ashift:DI (match_operand:DI 1 "gpr_operand" "0")
		   (neg:SI (match_operand:SI 2 "gpr_operand" "d"))))
   (clobber (match_scratch:CC 3 "=b"))]
  ""
  "cmpge %3,%2,-31\;src%T3 %U0,%L0,%2\;sra%T3 %L0,%L0,%2\;sub%F3 %U0,%2,-32\;sra%F3 %U0,%L0,%U0\;or%F3 %L0,%.,0"
  [(set_attr "length" "32")
   (set_attr "type" "multi")])

;; Arithmetic Shift Right
(define_insn "ashrdi3"
  [(set (match_operand:DI 0 "gpr_operand" "=e,e,e")
	(ashiftrt:DI (match_operand:DI 1 "gpr_operand" "0,e,0")
		     (match_operand:SI 2 "gpr_or_unsigned6_operand" "J,P,d")))
   (clobber (match_scratch:CC 3 "=X,X,b"))]
  ""
  "@
    src %L0,%U0,%2\;sra %U0,%U0,%2
    sra %L0,%U1,%S2\;sra %U0,%L0,31
    cmple %3,%2,31\;src%T3 %L0,%U0,%2\;sra%T3 %U0,%U0,%2\;add%F3 %L0,%2,-32\;sra%F3 %L0,%U0,%L0\;sra%F3 %U0,%U0,31"
  [(set_attr "length" "8,8,28")
   (set_attr "type" "multi")])

;; Logical Shift Right

(define_insn "lshrdi3"
  [(set (match_operand:DI 0 "gpr_operand" "=e,e,e")
	(lshiftrt:DI (match_operand:DI 1 "gpr_operand" "0,e,0")
		     (match_operand:SI 2 "gpr_or_unsigned6_operand" "J,P,d")))
   (clobber (match_scratch:CC 3 "=X,X,b"))]
  ""
  "@
    src %L0,%U0,%2\;srl %U0,%U0,%2
    srl %L0,%U1,%S2\;or %U0,%.,0
    cmple %3,%2,31\;src%T3 %L0,%U0,%2\;srl%T3 %U0,%U0,%2\;add%F3 %L0,%2,-32\;srl%F3 %L0,%U0,%L0\;or%F3 %U0,%.,0"
  [(set_attr "length" "8,8,28")
   (set_attr "type" "multi")])


;; ::::::::::::::::::::
;; ::
;; :: 32 Bit Integer Logical operations
;; ::
;; ::::::::::::::::::::

;; Logical AND, 32 bit integers
(define_expand "andsi3"
  [(set (match_operand:SI 0 "gpr_operand" "")
	(and:SI (match_operand:SI 1 "gpr_operand" "")
		(match_operand:SI 2 "gpr_or_constant_operand" "")))]
  ""
  "")

(define_insn "*andsi3_register"
  [(set (match_operand:SI 0 "gpr_operand" "=d")
	(and:SI (match_operand:SI 1 "gpr_operand" "%d")
		(match_operand:SI 2 "gpr_operand" "d")))]
  ""
  "and %0,%1,%2"
  [(set_attr "length" "4")
   (set_attr "type" "either")])

(define_insn "*andsi3_move"
  [(set (match_operand:SI 0 "gpr_operand" "=d,d")
	(and:SI (match_operand:SI 1 "gpr_operand" "%0,d")
		(match_operand:SI 2 "const_int_operand" "n,n")))]
  "((INTVAL (operands[2]) & 0xffffffff) == 0xffffffff)"
  "@
    ; and 0xffffffff to same register
    and %0,%1,-1"
  [(set_attr "length" "0,4")
   (set_attr "type" "either")])

(define_insn "*andsi3_constant"
  [(set (match_operand:SI 0 "gpr_operand" "=d,d,d,d")
	(and:SI (match_operand:SI 1 "gpr_operand" "%d,d,d,d")
		(match_operand:SI 2 "const_int_operand" "L,O,I,i")))]
  ""
  "@
    bclr %0,%1,%B2
    or %0,%.,0
    and %0,%1,%2
    and %0,%1,%2"
  [(set_attr "length" "4,4,4,8")
   (set_attr "type" "either,either,either,long")])

;; Inclusive OR, 32 bit integers
(define_expand "iorsi3"
  [(set (match_operand:SI 0 "gpr_operand" "")
	(ior:SI (match_operand:SI 1 "gpr_operand" "")
		(match_operand:SI 2 "gpr_or_constant_operand" "")))]
  ""
  "")

(define_insn "*iorsi3_register"
  [(set (match_operand:SI 0 "gpr_operand" "=d")
	(ior:SI (match_operand:SI 1 "gpr_operand" "%d")
		(match_operand:SI 2 "gpr_operand" "d")))]
  ""
  "or %0,%1,%2"
  [(set_attr "length" "4")
   (set_attr "type" "either")])

(define_insn "*iorsi3_constant"
  [(set (match_operand:SI 0 "gpr_operand" "=d,d,d,d")
	(ior:SI (match_operand:SI 1 "gpr_operand" "%d,0,d,d")
		(match_operand:SI 2 "const_int_operand" "K,O,I,i")))]
  ""
  "@
    bset %0,%1,%B2
    ; or 0 to same register (%0)
    or %0,%1,%2
    or %0,%1,%2"
  [(set_attr "length" "4,0,4,8")
   (set_attr "type" "either,either,either,long")])

;; Exclusive OR, 32 bit integers
(define_expand "xorsi3"
  [(set (match_operand:SI 0 "gpr_operand" "")
	(xor:SI (match_operand:SI 1 "gpr_operand" "")
		(match_operand:SI 2 "gpr_or_constant_operand" "")))]
  ""
  "")

(define_insn "*xorsi3_register"
  [(set (match_operand:SI 0 "gpr_operand" "=d")
	(xor:SI (match_operand:SI 1 "gpr_operand" "%d")
		(match_operand:SI 2 "gpr_operand" "d")))]
  ""
  "xor %0,%1,%2"
  [(set_attr "length" "4")
   (set_attr "type" "either")])

(define_insn "*xorsi3_constant"
  [(set (match_operand:SI 0 "gpr_operand" "=d,d,d,d")
	(xor:SI (match_operand:SI 1 "gpr_operand" "%d,0,d,d")
		(match_operand:SI 2 "const_int_operand" "K,O,I,i")))]
  ""
  "@
    bnot %0,%1,%B2
    ; xor 0 to same register (%0)
    xor %0,%1,%2
    xor %0,%1,%2"
  [(set_attr "length" "4,0,4,8")
   (set_attr "type" "either,either,either,long")])

;; One's complement, 32 bit integers
(define_insn "one_cmplsi2"
  [(set (match_operand:SI 0 "gpr_operand" "=d")
	(not:SI (match_operand:SI 1 "gpr_operand" "d")))]
  ""
  "not %0,%1"
  [(set_attr "length" "4")
   (set_attr "type" "either")])


;; ::::::::::::::::::::
;; ::
;; :: 64 Bit Integer Logical operations
;; ::
;; ::::::::::::::::::::

;; Logical AND, 64 bit integers
(define_insn "anddi3"
  [(set (match_operand:DI 0 "gpr_operand" "=e,e,&e,e,e,e")
	(and:DI (match_operand:DI 1 "gpr_operand" "%e,0,e,e,e,e")
		(match_operand:DI 2 "gpr_or_dbl_const_operand" "0,e,e,I,i,F")))]
  ""
  "#"
  [(set_attr "length" "8,8,8,8,12,16")
   (set_attr "type" "multi")])

(define_split
  [(set (match_operand:DI 0 "gpr_operand" "")
	(and:DI (match_operand:DI 1 "gpr_operand" "")
		(match_operand:DI 2 "gpr_or_dbl_const_operand" "")))]
  "reload_completed"
  [(set (match_dup 3) (and:SI (match_dup 4) (match_dup 5)))
   (set (match_dup 6) (and:SI (match_dup 7) (match_dup 8)))]
  "
{
  d30v_split_double (operands[0], &operands[3], &operands[6]);
  d30v_split_double (operands[1], &operands[4], &operands[7]);
  d30v_split_double (operands[2], &operands[5], &operands[8]);
}")

;; Includive OR, 64 bit integers
(define_insn "iordi3"
  [(set (match_operand:DI 0 "gpr_operand" "=e,e,&e,e,e,e")
	(ior:DI (match_operand:DI 1 "gpr_operand" "%e,0,e,e,e,e")
		(match_operand:DI 2 "gpr_or_dbl_const_operand" "0,e,e,I,i,F")))]
  ""
  "#"
  [(set_attr "length" "8,8,8,8,12,16")
   (set_attr "type" "multi")])

(define_split
  [(set (match_operand:DI 0 "gpr_operand" "")
	(ior:DI (match_operand:DI 1 "gpr_operand" "")
		(match_operand:DI 2 "gpr_or_dbl_const_operand" "")))]
  "reload_completed"
  [(set (match_dup 3) (ior:SI (match_dup 4) (match_dup 5)))
   (set (match_dup 6) (ior:SI (match_dup 7) (match_dup 8)))]
  "
{
  d30v_split_double (operands[0], &operands[3], &operands[6]);
  d30v_split_double (operands[1], &operands[4], &operands[7]);
  d30v_split_double (operands[2], &operands[5], &operands[8]);
}")

;; Excludive OR, 64 bit integers
(define_insn "xordi3"
  [(set (match_operand:DI 0 "gpr_operand" "=e,e,&e,e,e,e")
	(xor:DI (match_operand:DI 1 "gpr_operand" "%e,0,e,e,e,e")
		(match_operand:DI 2 "gpr_or_dbl_const_operand" "0,e,e,I,i,F")))]
  ""
  "#"
  [(set_attr "length" "8,8,8,8,12,16")
   (set_attr "type" "multi")])

(define_split
  [(set (match_operand:DI 0 "gpr_operand" "")
	(xor:DI (match_operand:DI 1 "gpr_operand" "")
		(match_operand:DI 2 "gpr_or_dbl_const_operand" "")))]
  "reload_completed"
  [(set (match_dup 3) (xor:SI (match_dup 4) (match_dup 5)))
   (set (match_dup 6) (xor:SI (match_dup 7) (match_dup 8)))]
  "
{
  d30v_split_double (operands[0], &operands[3], &operands[6]);
  d30v_split_double (operands[1], &operands[4], &operands[7]);
  d30v_split_double (operands[2], &operands[5], &operands[8]);
}")

;; One's complement, 64 bit integers
(define_insn "one_cmpldi2"
  [(set (match_operand:DI 0 "gpr_operand" "=e,&e")
	(not:DI (match_operand:DI 1 "gpr_operand" "0,e")))]
  ""
  "#"
  [(set_attr "length" "8")
   (set_attr "type" "multi")])

(define_split
  [(set (match_operand:DI 0 "gpr_operand" "")
	(not:DI (match_operand:DI 1 "gpr_operand" "")))]
  "reload_completed"
  [(set (match_dup 3) (not:SI (match_dup 4)))
   (set (match_dup 5) (not:SI (match_dup 6)))]
  "
{
  d30v_split_double (operands[0], &operands[3], &operands[5]);
  d30v_split_double (operands[1], &operands[4], &operands[6]);
}")


;; ::::::::::::::::::::
;; ::
;; :: Multiply and accumulate instructions
;; ::
;; ::::::::::::::::::::

(define_insn "*mac_reg"
  [(set (match_operand:DI 0 "accum_operand" "+a")
	(plus:DI (match_dup 0)
		 (mult:DI (sign_extend:DI (match_operand:SI 1 "gpr_operand" "%d"))
			  (sign_extend:DI (match_operand:SI 2 "gpr_operand" "d")))))]
  ""
  "mac%A0 %.,%1,%2"
  [(set_attr "length" "4")
   (set_attr "type" "mul")])

(define_insn "*mac_const"
  [(set (match_operand:DI 0 "accum_operand" "+a")
	(plus:DI (match_dup 0)
		 (mult:DI (sign_extend:DI (match_operand:SI 1 "gpr_operand" "%d"))
			  (match_operand:DI 2 "signed6_operand" "I"))))]
  ""
  "mac%A0 %.,%1,%2"
  [(set_attr "length" "4")
   (set_attr "type" "mul")])

(define_insn "*macs_reg"
  [(set (match_operand:DI 0 "accum_operand" "+a")
	(plus:DI (match_dup 0)
		 (ashift:DI (mult:DI (sign_extend:DI (match_operand:SI 1 "gpr_operand" "%d"))
				     (sign_extend:DI (match_operand:SI 2 "gpr_operand" "d")))
			    (const_int 1))))]
  ""
  "macs%A0 %.,%1,%2"
  [(set_attr "length" "4")
   (set_attr "type" "mul")])

(define_insn "*macs_const"
  [(set (match_operand:DI 0 "accum_operand" "+a")
	(plus:DI (match_dup 0)
		 (ashift:DI (mult:DI (sign_extend:DI (match_operand:SI 1 "gpr_operand" "%d"))
				     (match_operand:DI 2 "signed6_operand" "I"))
			    (const_int 1))))]
  ""
  "macs%A0 %.,%1,%2"
  [(set_attr "length" "4")
   (set_attr "type" "mul")])

(define_insn "*msub_reg"
  [(set (match_operand:DI 0 "accum_operand" "+a")
	(minus:DI (match_dup 0)
		  (mult:DI (sign_extend:DI (match_operand:SI 1 "gpr_operand" "d"))
			   (sign_extend:DI (match_operand:SI 2 "gpr_operand" "d")))))]
  ""
  "msub%A0 %.,%1,%2"
  [(set_attr "length" "4")
   (set_attr "type" "mul")])

(define_insn "*msub_const"
  [(set (match_operand:DI 0 "accum_operand" "+a")
	(minus:DI (match_dup 0)
		  (mult:DI (sign_extend:DI (match_operand:SI 1 "gpr_operand" "d"))
			   (match_operand:DI 2 "signed6_operand" "I"))))]
  ""
  "msub%A0 %.,%1,%2"
  [(set_attr "length" "4")
   (set_attr "type" "mul")])

(define_insn "*msubs_reg"
  [(set (match_operand:DI 0 "accum_operand" "+a")
	(minus:DI (match_dup 0)
		  (ashift:DI (mult:DI (sign_extend:DI (match_operand:SI 1 "gpr_operand" "d"))
				      (sign_extend:DI (match_operand:SI 2 "gpr_operand" "d")))
			     (const_int 1))))]
  ""
  "msubs%A0 %.,%1,%2"
  [(set_attr "length" "4")
   (set_attr "type" "mul")])

(define_insn "*msubs_const"
  [(set (match_operand:DI 0 "accum_operand" "+a")
	(minus:DI (match_dup 0)
		  (ashift:DI (mult:DI (sign_extend:DI (match_operand:SI 1 "gpr_operand" "d"))
				      (match_operand:DI 2 "signed6_operand" "I"))
			     (const_int 1))))]
  ""
  "msubs%A0 %.,%1,%2"
  [(set_attr "length" "4")
   (set_attr "type" "mul")])


;; ::::::::::::::::::::
;; ::
;; :: Comparisons
;; ::
;; ::::::::::::::::::::

;; Note, we store the operands in the comparison insns, and use them later
;; when generating the branch or scc operation.

;; First the routines called by the machine independent part of the compiler
(define_expand "cmpsi"
  [(set (cc0)
        (compare (match_operand:SI 0 "gpr_operand" "")
  		 (match_operand:SI 1 "gpr_or_constant_operand" "")))]
  ""
  "
{
  d30v_compare_op0 = operands[0];
  d30v_compare_op1 = operands[1];
  DONE;
}")

(define_expand "cmpdi"
  [(set (cc0)
        (compare (match_operand:DI 0 "gpr_operand" "")
  		 (match_operand:DI 1 "nonmemory_operand" "")))]
  ""
  "
{
  d30v_compare_op0 = operands[0];
  d30v_compare_op1 = operands[1];
  DONE;
}")

;; Now, the actual comparisons, generated by the branch and/or scc operations

;; 32 bit integer tests
(define_insn "*srelational"
  [(set (match_operand:CC 0 "flag_operand" "=f,f")
	(match_operator:CC 1 "srelational_si_operator"
			   [(match_operand:SI 2 "gpr_operand" "d,d")
			    (match_operand:SI 3 "gpr_or_constant_operand" "dI,i")]))]
  ""
  "%R1 %0,%2,%3"
  [(set_attr "length" "4,8")
   (set_attr "type" "scmp,lcmp")])

(define_insn "*urelational"
  [(set (match_operand:CC 0 "flag_operand" "=f,f")
	(match_operator:CC 1 "urelational_si_operator"
			   [(match_operand:SI 2 "gpr_operand" "d,d")
			    (match_operand:SI 3 "gpr_or_constant_operand" "dJP,i")]))]
  ""
  "%R1 %0,%2,%3"
  [(set_attr "length" "4,8")
   (set_attr "type" "scmp,lcmp")])

;; Code used after splitting DI compares

(define_insn "*movcccc_signed_true"
  [(set (match_operand:CC 0 "flag_operand" "=f,f")
	(if_then_else:CC (match_operand:CC 1 "br_flag_operand" "f,f")
			 (match_operator:CC 3 "srelational_si_operator"
					    [(match_operand:SI 4 "gpr_operand" "d,d")
					     (match_operand:SI 5 "gpr_or_constant_operand" "dI,i")])
			 (match_dup 0)))]
  ""
  "%R3%T1 %0,%4,%5"
  [(set_attr "length" "4,8")
   (set_attr "type" "scmp,lcmp")])

(define_insn "*movcccc_signed_false"
  [(set (match_operand:CC 0 "flag_operand" "=f,f")
	(if_then_else:CC (match_operand:CC 1 "br_flag_operand" "f,f")
			 (match_dup 0)
			 (match_operator:CC 3 "srelational_si_operator"
					    [(match_operand:SI 4 "gpr_operand" "d,d")
					     (match_operand:SI 5 "gpr_or_constant_operand" "dI,i")])))]
  ""
  "%R3%F1 %0,%4,%5"
  [(set_attr "length" "4,8")
   (set_attr "type" "scmp,lcmp")])

(define_insn "*movcccc_unsigned_true"
  [(set (match_operand:CC 0 "flag_operand" "=f,f")
	(if_then_else:CC (match_operand:CC 1 "br_flag_operand" "f,f")
			 (match_operator:CC 3 "urelational_si_operator"
					    [(match_operand:SI 4 "gpr_operand" "d,d")
					     (match_operand:SI 5 "gpr_or_constant_operand" "dJP,i")])
			 (match_dup 0)))]
  ""
  "%R3%T1 %0,%4,%5"
  [(set_attr "length" "4,8")
   (set_attr "type" "scmp,lcmp")])

(define_insn "*movcccc_unsigned_false"
  [(set (match_operand:CC 0 "flag_operand" "=f,f")
	(if_then_else:CC (match_operand:CC 1 "br_flag_operand" "f,f")
			 (match_dup 0)
			 (match_operator:CC 3 "urelational_si_operator"
					    [(match_operand:SI 4 "gpr_operand" "d,d")
					     (match_operand:SI 5 "gpr_or_constant_operand" "dJP,i")])))]
  ""
  "%R3%F1 %0,%4,%5"
  [(set_attr "length" "4,8")
   (set_attr "type" "scmp,lcmp")])

;; 64 bit integer tests
(define_insn "*eqdi_internal"
  [(set (match_operand:CC 0 "br_flag_operand" "=b,b,b")
	(eq:CC (match_operand:DI 1 "gpr_operand" "e,e,e")
	       (match_operand:DI 2 "gpr_or_dbl_const_operand" "eI,i,F")))]
  ""
  "#"
  [(set_attr "length" "8,12,16")
   (set_attr "type" "multi")])

(define_split
  [(set (match_operand:CC 0 "br_flag_operand" "")
	(eq:CC (match_operand:DI 1 "gpr_operand" "")
	       (match_operand:DI 2 "gpr_or_dbl_const_operand" "")))]
  "reload_completed"
  [(set (match_dup 0)
	(eq:CC (match_dup 3)
	       (match_dup 4)))
   (set (match_dup 0)
	(if_then_else:CC (match_dup 0)
			 (eq:CC (match_dup 5)
				(match_dup 6))
			 (match_dup 0)))]
  "
{
  d30v_split_double (operands[1], &operands[3], &operands[5]);
  d30v_split_double (operands[2], &operands[4], &operands[6]);
}")

(define_insn "*nedi_internal"
  [(set (match_operand:CC 0 "br_flag_operand" "=b,b,b")
	(ne:CC (match_operand:DI 1 "gpr_operand" "e,e,e")
	       (match_operand:DI 2 "gpr_or_dbl_const_operand" "eI,i,F")))]
  ""
  "#"
  [(set_attr "length" "8,12,16")
   (set_attr "type" "multi")])

(define_split
  [(set (match_operand:CC 0 "br_flag_operand" "")
	(ne:CC (match_operand:DI 1 "gpr_operand" "")
	       (match_operand:DI 2 "gpr_or_dbl_const_operand" "")))]
  "reload_completed"
  [(set (match_dup 0)
	(ne:CC (match_dup 3)
	       (match_dup 4)))
   (set (match_dup 0)
	(if_then_else:CC (match_dup 0)
			 (match_dup 0)
			 (ne:CC (match_dup 5)
				(match_dup 6))))]
  "
{
  d30v_split_double (operands[1], &operands[3], &operands[5]);
  d30v_split_double (operands[2], &operands[4], &operands[6]);
}")

(define_insn "*ltdi_zero"
  [(set (match_operand:CC 0 "flag_operand" "=f")
	(lt:CC (match_operand:DI 1 "gpr_operand" "e")
	       (const_int 0)))]
  ""
  "cmplt %0,%U1,0"
  [(set_attr "length" "4")
   (set_attr "type" "scmp")])

(define_insn "*ltdi_internal"
  [(set (match_operand:CC 0 "flag_operand" "=&f,&f,&f")
	(lt:CC (match_operand:DI 1 "gpr_operand" "e,e,e")
	       (match_operand:DI 2 "gpr_or_dbl_const_operand" "eJP,i,F")))
   (clobber (match_operand:CC 3 "br_flag_operand" "=&b,&b,&b"))]
  ""
  "#"
  [(set_attr "length" "12,16,24")
   (set_attr "type" "multi")])

(define_insn "*ledi_internal"
  [(set (match_operand:CC 0 "flag_operand" "=&f,&f,&f")
	(le:CC (match_operand:DI 1 "gpr_operand" "e,e,e")
	       (match_operand:DI 2 "gpr_or_dbl_const_operand" "eJP,i,F")))
   (clobber (match_operand:CC 3 "br_flag_operand" "=&b,&b,&b"))]
  ""
  "#"
  [(set_attr "length" "12,16,24")
   (set_attr "type" "multi")])

(define_insn "*gtdi_internal"
  [(set (match_operand:CC 0 "flag_operand" "=&f,&f,&f")
	(gt:CC (match_operand:DI 1 "gpr_operand" "e,e,e")
	       (match_operand:DI 2 "gpr_or_dbl_const_operand" "eJP,i,F")))
   (clobber (match_operand:CC 3 "br_flag_operand" "=&b,&b,&b"))]
  ""
  "#"
  [(set_attr "length" "12,16,24")
   (set_attr "type" "multi")])

(define_insn "*gedi_zero"
  [(set (match_operand:CC 0 "flag_operand" "=f")
	(ge:CC (match_operand:DI 1 "gpr_operand" "e")
	       (const_int 0)))]
  ""
  "cmpge %0,%U1,0"
  [(set_attr "length" "4")
   (set_attr "type" "scmp")])

(define_insn "*gedi_internal"
  [(set (match_operand:CC 0 "flag_operand" "=&f,&f,&f")
	(ge:CC (match_operand:DI 1 "gpr_operand" "e,e,e")
	       (match_operand:DI 2 "gpr_or_dbl_const_operand" "eJP,i,F")))
   (clobber (match_operand:CC 3 "br_flag_operand" "=&b,&b,&b"))]
  ""
  "#"
  [(set_attr "length" "12,16,24")
   (set_attr "type" "multi")])

(define_insn "*ltudi_internal"
  [(set (match_operand:CC 0 "flag_operand" "=&f,&f,&f")
	(ltu:CC (match_operand:DI 1 "gpr_operand" "e,e,e")
		(match_operand:DI 2 "gpr_or_dbl_const_operand" "eJP,i,F")))
   (clobber (match_operand:CC 3 "br_flag_operand" "=&b,&b,&b"))]
  ""
  "#"
  [(set_attr "length" "12,16,24")
   (set_attr "type" "multi")])

(define_insn "*leudi_internal"
  [(set (match_operand:CC 0 "flag_operand" "=&f,&f,&f")
	(leu:CC (match_operand:DI 1 "gpr_operand" "e,e,e")
		(match_operand:DI 2 "gpr_or_dbl_const_operand" "eJP,i,F")))
   (clobber (match_operand:CC 3 "br_flag_operand" "=&b,&b,&b"))]
  ""
  "#"
  [(set_attr "length" "12,16,24")
   (set_attr "type" "multi")])

(define_insn "*gtudi_internal"
  [(set (match_operand:CC 0 "flag_operand" "=&f,&f,&f")
	(gtu:CC (match_operand:DI 1 "gpr_operand" "e,e,e")
		(match_operand:DI 2 "gpr_or_dbl_const_operand" "eJP,i,F")))
   (clobber (match_operand:CC 3 "br_flag_operand" "=&b,&b,&b"))]
  ""
  "#"
  [(set_attr "length" "12,16,24")
   (set_attr "type" "multi")])

(define_insn "*geudi_internal"
  [(set (match_operand:CC 0 "flag_operand" "=&f,&f,&f")
	(geu:CC (match_operand:DI 1 "gpr_operand" "e,e,e")
		(match_operand:DI 2 "gpr_or_dbl_const_operand" "eJP,i,F")))
   (clobber (match_operand:CC 3 "br_flag_operand" "=&b,&b,&b"))]
  ""
  "#"
  [(set_attr "length" "12,16,24")
   (set_attr "type" "multi")])

(define_split
  [(set (match_operand:CC 0 "flag_operand" "")
	(match_operator:CC 1 "relational_di_operator"
			   [(match_operand:DI 2 "gpr_operand" "")
			    (match_operand:DI 3 "gpr_or_dbl_const_operand" "")]))
   (clobber (match_operand:CC 4 "br_flag_operand" ""))]
  "reload_completed"
  [(match_dup 5)
   (match_dup 6)
   (match_dup 7)]
  "
{
  enum rtx_code cond = GET_CODE (operands[1]);
  enum rtx_code ucond = unsigned_condition (cond);
  rtx tmpflag = operands[4];
  rtx outflag = operands[0];
  rtx high[2];
  rtx low[2];

  d30v_split_double (operands[2], &high[0], &low[0]);
  d30v_split_double (operands[3], &high[1], &low[1]);

  operands[5] = gen_rtx (SET, VOIDmode,
			 tmpflag,
			 gen_rtx (EQ, CCmode, high[0], high[1]));

  operands[6] = gen_rtx (SET, VOIDmode,
			 outflag,
			 gen_rtx (IF_THEN_ELSE, CCmode,
				  tmpflag,
				  outflag,
				  gen_rtx (cond, CCmode, high[0], high[1])));

  operands[7] = gen_rtx (SET, VOIDmode,
			 outflag,
			 gen_rtx (IF_THEN_ELSE, CCmode,
				  tmpflag,
				  gen_rtx (ucond, CCmode, low[0], low[1]),
				  outflag));
}")


;; ::::::::::::::::::::
;; ::
;; :: Branches
;; ::
;; ::::::::::::::::::::

;; Define_expands called by the machine independent part of the compiler
;; to allocate a new comparison register

(define_expand "beq"
  [(match_dup 2)
   (set (pc)
	(if_then_else (ne:CC (match_dup 1)
			     (const_int 0))
		      (label_ref (match_operand 0 "" ""))
		      (pc)))]
  ""
  "
{
  operands[1] = gen_reg_rtx (CCmode);
  operands[2] = d30v_emit_comparison (EQ, operands[1],
				      d30v_compare_op0,
				      d30v_compare_op1);
}")

(define_expand "bne"
  [(match_dup 2)
   (set (pc)
	(if_then_else (ne:CC (match_dup 1)
			     (const_int 0))
		      (label_ref (match_operand 0 "" ""))
		      (pc)))]
  ""
  "
{
  operands[1] = gen_reg_rtx (CCmode);
  operands[2] = d30v_emit_comparison (NE, operands[1],
				      d30v_compare_op0,
				      d30v_compare_op1);
}")

(define_expand "bgt"
  [(match_dup 2)
   (set (pc)
	(if_then_else (ne:CC (match_dup 1)
			     (const_int 0))
		      (label_ref (match_operand 0 "" ""))
		      (pc)))]
  ""
  "
{
  operands[1] = gen_reg_rtx (CCmode);
  operands[2] = d30v_emit_comparison (GT, operands[1],
				      d30v_compare_op0,
				      d30v_compare_op1);
}")

(define_expand "bge"
  [(match_dup 2)
   (set (pc)
	(if_then_else (ne:CC (match_dup 1)
			     (const_int 0))
		      (label_ref (match_operand 0 "" ""))
		      (pc)))]
  ""
  "
{
  operands[1] = gen_reg_rtx (CCmode);
  operands[2] = d30v_emit_comparison (GE, operands[1],
				      d30v_compare_op0,
				      d30v_compare_op1);
}")

(define_expand "blt"
  [(match_dup 2)
   (set (pc)
	(if_then_else (ne:CC (match_dup 1)
			     (const_int 0))
		      (label_ref (match_operand 0 "" ""))
		      (pc)))]
  ""
  "
{
  operands[1] = gen_reg_rtx (CCmode);
  operands[2] = d30v_emit_comparison (LT, operands[1],
				      d30v_compare_op0,
				      d30v_compare_op1);
}")

(define_expand "ble"
  [(match_dup 2)
   (set (pc)
	(if_then_else (ne:CC (match_dup 1)
			     (const_int 0))
		      (label_ref (match_operand 0 "" ""))
		      (pc)))]
  ""
  "
{
  operands[1] = gen_reg_rtx (CCmode);
  operands[2] = d30v_emit_comparison (LE, operands[1],
				      d30v_compare_op0,
				      d30v_compare_op1);
}")

(define_expand "bgtu"
  [(match_dup 2)
   (set (pc)
	(if_then_else (ne:CC (match_dup 1)
			     (const_int 0))
		      (label_ref (match_operand 0 "" ""))
		      (pc)))]
  ""
  "
{
  operands[1] = gen_reg_rtx (CCmode);
  operands[2] = d30v_emit_comparison (GTU, operands[1],
				      d30v_compare_op0,
				      d30v_compare_op1);
}")

(define_expand "bgeu"
  [(match_dup 2)
   (set (pc)
	(if_then_else (ne:CC (match_dup 1)
			     (const_int 0))
		      (label_ref (match_operand 0 "" ""))
		      (pc)))]
  ""
  "
{
  operands[1] = gen_reg_rtx (CCmode);
  operands[2] = d30v_emit_comparison (GEU, operands[1],
				      d30v_compare_op0,
				      d30v_compare_op1);
}")

(define_expand "bltu"
  [(match_dup 2)
   (set (pc)
	(if_then_else (ne:CC (match_dup 1)
			     (const_int 0))
		      (label_ref (match_operand 0 "" ""))
		      (pc)))]
  ""
  "
{
  operands[1] = gen_reg_rtx (CCmode);
  operands[2] = d30v_emit_comparison (LTU, operands[1],
				      d30v_compare_op0,
				      d30v_compare_op1);
}")

(define_expand "bleu"
  [(match_dup 2)
   (set (pc)
	(if_then_else (ne:CC (match_dup 1)
			     (const_int 0))
		      (label_ref (match_operand 0 "" ""))
		      (pc)))]
  ""
  "
{
  operands[1] = gen_reg_rtx (CCmode);
  operands[2] = d30v_emit_comparison (LEU, operands[1],
				      d30v_compare_op0,
				      d30v_compare_op1);
}")

;; Actual branches.  We must allow for the (label_ref) and the (pc) to be
;; swapped.  If they are swapped, it reverses the sense of the branch.
;; Also handle changing the ne to eq.
;; In order for the length calculations to be correct, the label must be
;; operand 0.

;; We used to handle branches against 0 to be folded directly into
;; bratnz/bratzr instruction, but this dimisses the possibility of doing
;; conditional execution.  Instead handle these via peepholes.

;; Branches based off of the flag bits
(define_insn "*bra_true"
  [(set (pc)
	(if_then_else (match_operator:CC 1 "condexec_branch_operator"
					 [(match_operand:CC 2 "br_flag_or_constant_operand" "b,I,N")
					  (const_int 0)])
		      (label_ref (match_operand 0 "" ""))
		      (pc)))]
  ""
  "*
{
  if (GET_CODE (operands[2]) == REG || GET_CODE (operands[2]) == SUBREG)
    return \"bra%F1 %l0\";

  if (GET_CODE (operands[2]) != CONST_INT)
    fatal_insn (\"bad jump\", insn);

  if ((GET_CODE (operands[1]) == EQ && INTVAL (operands[2]) == 0)
      || (GET_CODE (operands[1]) == NE && INTVAL (operands[2]) != 0))
    return \"bra %l0\";

  return \"; jump to %l0 optimized away\";
}"
  [(set_attr "type" "br")])

(define_insn "*bra_false"
  [(set (pc)
	(if_then_else (match_operator:CC 1 "condexec_branch_operator"
					 [(match_operand:CC 2 "br_flag_or_constant_operand" "b,I,N")
					  (const_int 0)])
		      (pc)
		      (label_ref (match_operand 0 "" ""))))]
  ""
  "*
{
  if (GET_CODE (operands[2]) == REG || GET_CODE (operands[2]) == SUBREG)
    return \"bra%T1 %l0\";

  if (GET_CODE (operands[2]) != CONST_INT)
    fatal_insn (\"bad jump\", insn);

  if ((GET_CODE (operands[1]) == EQ && INTVAL (operands[2]) != 0)
      || (GET_CODE (operands[1]) == NE && INTVAL (operands[2]) == 0))
    return \"bra %l0\";

  return \"; jump to %l0 optimized away\";
}"
  [(set_attr "type" "br")])

;; Peephole to turn set flag, cond. jumps into branch if register ==/!= 0.

(define_peephole2
  [(set (match_operand:CC 0 "br_flag_operand" "=b")
	(match_operator:CC 1 "branch_zero_operator"
			   [(match_operand:SI 2 "gpr_operand" "d")
			    (const_int 0)]))
   (set (pc)
	(if_then_else (match_operator:CC 3 "condexec_test_operator"
					 [(match_dup 0)
					  (const_int 0)])
		      (match_operand 4 "" "")
		      (match_operand 5 "" "")))]
  "reg_dead_p (last_insn, operands[0])"
  [(set (pc)
	(if_then_else (match_dup 6)
		      (match_dup 4)
		      (match_dup 5)))]
  "
{
  int true_false = 1;
  if (GET_CODE (operands[1]) == EQ)
    true_false = !true_false;
  if (GET_CODE (operands[3]) == EQ)
    true_false = !true_false;
  operands[6] = gen_rtx_fmt_ee ((true_false ? NE : EQ), CCmode,
				operands[2], const0_rtx);
}")

(define_insn "*bra_reg_true"
  [(set (pc) (if_then_else (match_operator:CC 1 "branch_zero_operator"
			     [(match_operand:SI 2 "gpr_operand" "d")
			      (const_int 0)])
			   (label_ref (match_operand 0 "" ""))
			   (pc)))]
  "reload_completed"
  "*
{
  return GET_CODE (operands[1]) == NE ? \"bratnz %2,%l0\" : \"bratzr %2,%l0\";
}"
  [(set_attr "type" "br2")])

(define_insn "*bra_reg_false"
  [(set (pc) (if_then_else (match_operator:CC 1 "branch_zero_operator"
			     [(match_operand:SI 2 "gpr_operand" "d")
			      (const_int 0)])
			   (pc)
			   (label_ref (match_operand 0 "" ""))))]
  "reload_completed"
  "*
{
  return GET_CODE (operands[1]) == EQ ? \"bratnz %2,%l0\" : \"bratzr %2,%l0\";
}"
  [(set_attr "type" "br2")])

;; ::::::::::::::::::::
;; ::
;; :: Set flag operations
;; ::
;; ::::::::::::::::::::

;; Define_expands called by the machine independent part of the compiler
;; to allocate a new comparison register

;; ??? These patterns should all probably use (ne:SI ... (const_int 0)) instead
;; of (eq:SI ... (const_int 1)), because the former is the canonical form.
;; The non-canonical form was used here because I was just trying to get the
;; port working again after it broke, and the non-canonical form was the
;; safer faster way to fix this.


(define_expand "seq"
  [(match_dup 2)
   (set (match_operand:SI 0 "gpr_operand" "")
	(ne:SI (match_dup 1) (const_int 0)))]
  ""
  "
{
  operands[1] = gen_reg_rtx (CCmode);
  operands[2] = d30v_emit_comparison (EQ, operands[1],
				      d30v_compare_op0,
				      d30v_compare_op1);
}")

(define_expand "sne"
  [(match_dup 2)
   (set (match_operand:SI 0 "gpr_operand" "")
	(ne:SI (match_dup 1) (const_int 0)))]
  ""
  "
{
  operands[1] = gen_reg_rtx (CCmode);
  operands[2] = d30v_emit_comparison (NE, operands[1],
				      d30v_compare_op0,
				      d30v_compare_op1);
}")

(define_expand "sgt"
  [(match_dup 2)
   (set (match_operand:SI 0 "gpr_operand" "")
	(ne:SI (match_dup 1) (const_int 0)))]
  ""
  "
{
  operands[1] = gen_reg_rtx (CCmode);
  operands[2] = d30v_emit_comparison (GT, operands[1],
				      d30v_compare_op0,
				      d30v_compare_op1);
}")

(define_expand "sge"
  [(match_dup 2)
   (set (match_operand:SI 0 "gpr_operand" "")
	(ne:SI (match_dup 1) (const_int 0)))]
  ""
  "
{
  operands[1] = gen_reg_rtx (CCmode);
  operands[2] = d30v_emit_comparison (GE, operands[1],
				      d30v_compare_op0,
				      d30v_compare_op1);
}")

(define_expand "slt"
  [(match_dup 2)
   (set (match_operand:SI 0 "gpr_operand" "")
	(ne:SI (match_dup 1) (const_int 0)))]
  ""
  "
{
  operands[1] = gen_reg_rtx (CCmode);
  operands[2] = d30v_emit_comparison (LT, operands[1],
				      d30v_compare_op0,
				      d30v_compare_op1);
}")

(define_expand "sle"
  [(match_dup 2)
   (set (match_operand:SI 0 "gpr_operand" "")
	(ne:SI (match_dup 1) (const_int 0)))]
  ""
  "
{
  operands[1] = gen_reg_rtx (CCmode);
  operands[2] = d30v_emit_comparison (LE, operands[1],
				      d30v_compare_op0,
				      d30v_compare_op1);
}")

(define_expand "sgtu"
  [(match_dup 2)
   (set (match_operand:SI 0 "gpr_operand" "")
	(ne:SI (match_dup 1) (const_int 0)))]
  ""
  "
{
  operands[1] = gen_reg_rtx (CCmode);
  operands[2] = d30v_emit_comparison (GTU, operands[1],
				      d30v_compare_op0,
				      d30v_compare_op1);
}")

(define_expand "sgeu"
  [(match_dup 2)
   (set (match_operand:SI 0 "gpr_operand" "")
	(ne:SI (match_dup 1) (const_int 0)))]
  ""
  "
{
  operands[1] = gen_reg_rtx (CCmode);
  operands[2] = d30v_emit_comparison (GEU, operands[1],
				      d30v_compare_op0,
				      d30v_compare_op1);
}")

(define_expand "sltu"
  [(match_dup 2)
   (set (match_operand:SI 0 "gpr_operand" "")
	(ne:SI (match_dup 1) (const_int 0)))]
  ""
  "
{
  operands[1] = gen_reg_rtx (CCmode);
  operands[2] = d30v_emit_comparison (LTU, operands[1],
				      d30v_compare_op0,
				      d30v_compare_op1);
}")

(define_expand "sleu"
  [(match_dup 2)
   (set (match_operand:SI 0 "gpr_operand" "")
	(ne:SI (match_dup 1) (const_int 0)))]
  ""
  "
{
  operands[1] = gen_reg_rtx (CCmode);
  operands[2] = d30v_emit_comparison (LEU, operands[1],
				      d30v_compare_op0,
				      d30v_compare_op1);
}")

;; Set flag operations.  We prefer to use conditional execution instead of
;; mvfsys, since it is faster, but allow the use of mvfsys to offload some
;; register pressure.
(define_insn "*setcc_internal"
  [(set (match_operand:SI 0 "gpr_operand" "=d,?d,?*d")
	(ne:SI (match_operand:CC 1 "flag_operand" "b,z,*d")
	       (const_int 0)))]
  ""
  "@
    #
    mvfsys %0,%1
    or %0,%.,%1"
  [(set_attr "length" "8,4,4")
   (set_attr "type" "multi,either,either")])

(define_split
  [(set (match_operand:SI 0 "gpr_operand" "")
	(ne:SI (match_operand:CC 1 "br_flag_operand" "")
	       (const_int 0)))]
  "reload_completed"
  [(set (match_dup 0)
	(const_int 0))
   (set (match_dup 0)
	(if_then_else:SI (ne:CC (match_dup 1)
				(const_int 0))
			 (const_int 1)
			 (match_dup 0)))]
  "")


;; ::::::::::::::::::::
;; ::
;; :: Operations on flags
;; ::
;; ::::::::::::::::::::

(define_insn "andcc3"
  [(set (match_operand:CC 0 "flag_operand" "=f")
	(and:CC (match_operand:CC 1 "flag_operand" "f")
		(match_operand:CC 2 "flag_operand" "f")))]
  ""
  "andfg %0,%1,%2"
  [(set_attr "length" "4")
   (set_attr "type" "either")])

(define_insn "iorcc3"
  [(set (match_operand:CC 0 "flag_operand" "=f")
	(ior:CC (match_operand:CC 1 "flag_operand" "f")
		(match_operand:CC 2 "flag_operand" "f")))]
  ""
  "orfg %0,%1,%2"
  [(set_attr "length" "4")
   (set_attr "type" "either")])

(define_insn "xorcc3"
  [(set (match_operand:CC 0 "flag_operand" "=f")
	(xor:CC (match_operand:CC 1 "flag_operand" "f")
		(match_operand:CC 2 "flag_operand" "f")))]
  ""
  "xorfg %0,%1,%2"
  [(set_attr "length" "4")
   (set_attr "type" "either")])

;; This is the canonical form produced by combine.

(define_insn "incscc"
  [(set (match_operand:SI 0 "gpr_operand" "=d")
        (plus:SI (eq:SI (match_operand:CC 1 "br_flag_operand" "b")
			(const_int 1))
		 (match_operand:SI 2 "gpr_operand" "0")))]
  ""
  "add%T1 %0,%2,1"
[(set_attr "length" "4")
 (set_attr "type" "either")])

(define_insn "decscc"
  [(set (match_operand:SI 0 "gpr_operand" "=d")
        (minus:SI (match_operand:SI 1 "gpr_operand" "0")
		  (eq:SI (match_operand:CC 2 "br_flag_operand" "b")
			 (const_int 1))))]
  ""
  "sub%T2 %0,%1,1"
[(set_attr "length" "4")
 (set_attr "type" "either")])

;; ::::::::::::::::::::
;; ::
;; :: Call and branch instructions
;; ::
;; ::::::::::::::::::::

;; Subroutine call instruction returning no value.  Operand 0 is the function
;; to call; operand 1 is the number of bytes of arguments pushed (in mode
;; `SImode', except it is normally a `const_int'); operand 2 is the number of
;; registers used as operands.

;; On most machines, operand 2 is not actually stored into the RTL pattern.  It
;; is supplied for the sake of some RISC machines which need to put this
;; information into the assembler code; they can put it in the RTL instead of
;; operand 1.

(define_expand "call"
  [(parallel [(call (match_operand 0 "call_operand" "")
		    (match_operand 1 "" ""))
	      (use (match_operand 2 "" ""))
	      (clobber (match_dup 3))])]
  ""
  "
{
  if (GET_CODE (XEXP (operands[0], 0)) == SUBREG)
    XEXP (operands[0], 0) = copy_addr_to_reg (XEXP (operands[0], 0));

  if (!operands[2])
    operands[2] = const0_rtx;

  operands[3] = gen_rtx (REG, Pmode, GPR_LINK);
}")

(define_insn "*call_internal"
  [(call (match_operand:QI 0 "call_operand" "R,S")
	 (match_operand 1 "" ""))
   (use (match_operand 2 "" ""))
   (clobber (match_operand 3 "" "=d,d"))]
  ""
  "@
    jsr %0
    bsr %0"
  [(set_attr "length" "4,8")
   (set_attr "type" "mu,long")])

;; Subroutine call instruction returning a value.  Operand 0 is the hard
;; register in which the value is returned.  There are three more operands, the
;; same as the three operands of the `call' instruction (but with numbers
;; increased by one).

;; Subroutines that return `BLKmode' objects use the `call' insn.

(define_expand "call_value"
  [(parallel [(set (match_operand 0 "gpr_operand" "")
		   (call (match_operand 1 "call_operand" "")
			 (match_operand 2 "" "")))
	     (use (match_operand 3 "" ""))
	     (clobber (match_dup 4))])]
  ""
  "
{
  if (GET_CODE (XEXP (operands[1], 0)) == SUBREG)
    XEXP (operands[1], 0) = copy_addr_to_reg (XEXP (operands[1], 0));

  if (!operands[3])
    operands[3] = const0_rtx;

  operands[4] = gen_rtx (REG, Pmode, GPR_LINK);
}")

(define_insn "*call_value_internal"
  [(set (match_operand 0 "gpr_operand" "=d,d")
	(call (match_operand:QI 1 "call_operand" "R,S")
	      (match_operand 2 "" "")))
	(use (match_operand 3 "" ""))
	(clobber (match_operand 4 "" "=d,d"))]
  ""
  "@
    jsr %1
    bsr %1"
  [(set_attr "length" "4,8")
   (set_attr "type" "mu,long")])

;; Subroutine return
(define_expand "return"
  [(return)]
  "direct_return ()"
  "")

(define_insn "*return_internal"
  [(return)]
  "reload_completed"
  "jmp link"
  [(set_attr "length" "4")
   (set_attr "type" "mu")])

(define_insn "*cond_return_true"
  [(set (pc)
	(if_then_else (match_operator:CC 0 "condexec_branch_operator"
			[(match_operand:CC 1 "br_flag_operand" "b")
			 (const_int 0)])
	  (return)
	  (pc)))]
  "reload_completed"
  "jmp%F0 link"
  [(set_attr "length" "4")
   (set_attr "type" "mu")])

(define_insn "*cond_return_false"
  [(set (pc)
	(if_then_else (match_operator:CC 0 "condexec_branch_operator"
			[(match_operand:CC 1 "br_flag_operand" "b")
			 (const_int 0)])
	  (pc)
	  (return)))]
  "reload_completed"
  "jmp%T0 link"
  [(set_attr "length" "4")
   (set_attr "type" "mu")])

;; Normal unconditional jump
(define_insn "jump"
  [(set (pc) (label_ref (match_operand 0 "" "")))]
  ""
  "bra %l0"
  [(set_attr "type" "br")])

;; Indirect jump through a register
(define_insn "indirect_jump"
  [(set (pc) (match_operand:SI 0 "gpr_operand" "d"))]
  ""
  "jmp %0"
  [(set_attr "length" "4")
   (set_attr "type" "mu")])

;; Instruction to jump to a variable address.  This is a low-level capability
;; which can be used to implement a dispatch table when there is no `casesi'
;; pattern.

;; This pattern requires two operands: the address or offset, and a label which
;; should immediately precede the jump table.  If the macro
;; `CASE_VECTOR_PC_RELATIVE' is defined then the first operand is an offset
;; which counts from the address of the table; otherwise, it is an absolute
;; address to jump to.  In either case, the first operand has mode `Pmode'.

;; The `tablejump' insn is always the last insn before the jump table it uses.
;; Its assembler code normally has no need to use the second operand, but you
;; should incorporate it in the RTL pattern so that the jump optimizer will not
;; delete the table as unreachable code.

(define_insn "tablejump"
  [(set (pc) (match_operand:SI 0 "gpr_operand" "d"))
   (use (label_ref (match_operand 1 "" "")))]
  ""
  "jmp %0"
  [(set_attr "length" "4")
   (set_attr "type" "mu")])



;; ::::::::::::::::::::
;; ::
;; :: Prologue and Epilogue instructions
;; ::
;; ::::::::::::::::::::

;; Called after register allocation to add any instructions needed for the
;; prologue.  Using a prologue insn is favored compared to putting all of the
;; instructions in the FUNCTION_PROLOGUE macro, since it allows the scheduler
;; to intermix instructions with the saves of the caller saved registers.  In
;; some cases, it might be necessary to emit a barrier instruction as the last
;; insn to prevent such scheduling.

(define_expand "prologue"
  [(const_int 1)]
  ""
  "
{
  d30v_expand_prologue ();
  DONE;
}")

;; Called after register allocation to add any instructions needed for the
;; epilogue.  Using a epilogue insn is favored compared to putting all of the
;; instructions in the FUNCTION_PROLOGUE macro, since it allows the scheduler
;; to intermix instructions with the saves of the caller saved registers.  In
;; some cases, it might be necessary to emit a barrier instruction as the last
;; insn to prevent such scheduling.

(define_expand "epilogue"
  [(const_int 2)]
  ""
  "
{
  d30v_expand_epilogue ();
  DONE;
}")

(define_expand "eh_epilogue"
  [(use (match_operand:DI 0 "register_operand" "r"))
   (use (match_operand:DI 1 "register_operand" "r"))
   (use (match_operand:DI 2 "register_operand" "r"))]
  ""
  "
{
  d30v_eh_epilogue_sp_ofs = operands[1];
  if (GET_CODE (operands[2]) != REG || REGNO (operands[2]) != GPR_LINK)
    {
      rtx ra = gen_rtx_REG (Pmode, GPR_LINK);
      emit_move_insn (ra, operands[2]);
      operands[2] = ra;
    }
}")


;; ::::::::::::::::::::
;; ::
;; :: Conditional move instructions
;; ::
;; ::::::::::::::::::::

;; Conditionally move operand 2 or operand 3 into operand 0 according to the
;; comparison in operand 1.  If the comparison is true, operand 2 is moved into
;; operand 0, otherwise operand 3 is moved.

;; The mode of the operands being compared need not be the same as the operands
;; being moved.  Some machines, sparc64 for example, have instructions that
;; conditionally move an integer value based on the floating point condition
;; codes and vice versa.

;; If the machine does not have conditional move instructions, do not
;; define these patterns.

;; Note we don't allow the general form of conditional store to be generated --
;; we always generate two separate if_then_elses's
(define_expand "movqicc"
  [(set (match_operand:QI 0 "move_output_operand" "")
	(if_then_else:QI (match_operand 1 "" "")
			 (match_operand:QI 2 "move_input_operand" "")
			 (match_operand:QI 3 "move_input_operand" "")))]
  "TARGET_COND_MOVE"
  "
{
  if (!d30v_emit_cond_move (operands[0], operands[1], operands[2], operands[3]))
    FAIL;

  DONE;
}")

(define_insn "*movqicc_internal"
  [(set (match_operand:QI 0 "gpr_operand" "=d,d,d,d,d,c,d,d,d,d,d,c,?&d")
	(if_then_else:QI (match_operator:CC 1 "condexec_test_operator"
					    [(match_operand:CC 2 "br_flag_operand" "b,b,b,b,b,b,b,b,b,b,b,b,b")
					     (const_int 0)])
			 (match_operand:QI 3 "move_input_operand" "dI,i,Q,m,c,d,0,0,0,0,0,0,dim")
			 (match_operand:QI 4 "move_input_operand" "0,0,0,0,0,0,dI,i,Q,m,c,d,dim")))]
  ""
  "#"
  [(set_attr "length" "4,8,4,8,4,4,4,8,4,8,4,4,16")
   (set_attr "type" "either,long,sload,lload,mu,mu,either,long,sload,lload,mu,mu,multi")])

;; If we have: a = (test) ? a : b, or a = (test) ? b : a, we can split it
;; before reload to allow combine to substitute in early.
;; ??? Not until we teach reload how to do conditional spills, we can't.
(define_split
  [(set (match_operand:QI 0 "move_output_operand" "")
	(if_then_else:QI (match_operator:CC 1 "condexec_test_operator"
			   [(match_operand:CC 2 "br_flag_operand" "")
			    (const_int 0)])
			 (match_operand:QI 3 "move_input_operand" "")
			 (match_dup 0)))]
  "reload_completed"
  [(cond_exec (match_dup 1) 
     (set (match_dup 0) (match_dup 3)))]
  "")

(define_split
  [(set (match_operand:QI 0 "move_output_operand" "")
	(if_then_else:QI (match_operator:CC 1 "condexec_test_operator"
			   [(match_operand:CC 2 "br_flag_operand" "")
			    (const_int 0)])
			 (match_dup 0)
			 (match_operand:QI 3 "move_input_operand" "")))]
  "reload_completed"
  [(cond_exec (match_dup 4)
     (set (match_dup 0) (match_dup 3)))]
  "
{
  if (GET_CODE (operands[1]) == EQ)
    operands[4] = gen_rtx_NE (CCmode, operands[2], const0_rtx);
  else
    operands[4] = gen_rtx_EQ (CCmode, operands[2], const0_rtx);
}")

(define_split
  [(set (match_operand:QI 0 "move_output_operand" "")
	(if_then_else:QI (match_operator:CC 1 "condexec_test_operator"
			   [(match_operand:CC 2 "br_flag_operand" "")
			    (const_int 0)])
			 (match_operand:QI 3 "move_input_operand" "")
			 (match_operand:QI 4 "move_input_operand" "")))]
  "reload_completed"
  [(cond_exec (match_dup 1)
     (set (match_dup 0) (match_dup 3)))
   (cond_exec (match_dup 5)
     (set (match_dup 0) (match_dup 4)))]
  "
{
  if (GET_CODE (operands[1]) == EQ)
    operands[5] = gen_rtx_NE (CCmode, operands[2], const0_rtx);
  else
    operands[5] = gen_rtx_EQ (CCmode, operands[2], const0_rtx);
}")

(define_expand "movhicc"
  [(set (match_operand:HI 0 "move_output_operand" "")
	(if_then_else:HI (match_operand 1 "" "")
			 (match_operand:HI 2 "move_input_operand" "")
			 (match_operand:HI 3 "move_input_operand" "")))]
  "TARGET_COND_MOVE"
  "
{
  if (!d30v_emit_cond_move (operands[0], operands[1], operands[2], operands[3]))
    FAIL;

  DONE;
}")

(define_insn "*movhicc_internal"
  [(set (match_operand:HI 0 "gpr_operand" "=d,d,d,d,d,c,d,d,d,d,d,c,?&d")
	(if_then_else:HI
	  (match_operator:CC 1 "condexec_test_operator"
	    [(match_operand:CC 2 "br_flag_operand" "b,b,b,b,b,b,b,b,b,b,b,b,b")
	     (const_int 0)])
	  (match_operand:HI 3 "move_input_operand" "dI,i,Q,m,c,d,0,0,0,0,0,0,dim")
	  (match_operand:HI 4 "move_input_operand" "0,0,0,0,0,0,dI,i,Q,m,c,d,dim")))]
  ""
  "#"
  [(set_attr "length" "4,8,4,8,4,4,4,8,4,8,4,4,16")
   (set_attr "type" "either,long,sload,lload,mu,mu,either,long,sload,lload,mu,mu,multi")])

;; If we have: a = (test) ? a : b, or a = (test) ? b : a, we can split it
;; before reload to allow combine to substitute in early.
;; ??? Not until we teach reload how to do conditional spills, we can't.
(define_split
  [(set (match_operand:HI 0 "move_output_operand" "")
	(if_then_else:HI (match_operator:CC 1 "condexec_test_operator"
			   [(match_operand:CC 2 "br_flag_operand" "")
			    (const_int 0)])
			 (match_operand:HI 3 "move_input_operand" "")
			 (match_dup 0)))]
  "reload_completed"
  [(cond_exec (match_dup 1)
     (set (match_dup 0) (match_dup 3)))]
  "")

(define_split
  [(set (match_operand:HI 0 "move_output_operand" "")
	(if_then_else:HI (match_operator:CC 1 "condexec_test_operator"
			   [(match_operand:CC 2 "br_flag_operand" "")
			    (const_int 0)])
			 (match_dup 0)
			 (match_operand:HI 3 "move_input_operand" "")))]
  "reload_completed"
  [(cond_exec (match_dup 4)
     (set (match_dup 0) (match_dup 3)))]
  "
{
  if (GET_CODE (operands[1]) == EQ)
    operands[4] = gen_rtx_NE (CCmode, operands[2], const0_rtx);
  else
    operands[4] = gen_rtx_EQ (CCmode, operands[2], const0_rtx);
}")

(define_split
  [(set (match_operand:HI 0 "move_output_operand" "")
	(if_then_else:HI (match_operator:CC 1 "condexec_test_operator"
			   [(match_operand:CC 2 "br_flag_operand" "")
			    (const_int 0)])
			 (match_operand:HI 3 "move_input_operand" "")
			 (match_operand:HI 4 "move_input_operand" "")))]
  "reload_completed"
  [(cond_exec (match_dup 1)
     (set (match_dup 0) (match_dup 3)))
   (cond_exec (match_dup 5)
     (set (match_dup 0) (match_dup 4)))]
  "
{
  if (GET_CODE (operands[1]) == EQ)
    operands[5] = gen_rtx_NE (CCmode, operands[2], const0_rtx);
  else
    operands[5] = gen_rtx_EQ (CCmode, operands[2], const0_rtx);
}")

(define_expand "movsicc"
  [(set (match_operand:SI 0 "move_output_operand" "")
	(if_then_else:SI (match_operand 1 "" "")
			 (match_operand:SI 2 "move_input_operand" "")
			 (match_operand:SI 3 "move_input_operand" "")))]
  "TARGET_COND_MOVE"
  "
{
  if (!d30v_emit_cond_move (operands[0], operands[1], operands[2], operands[3]))
    FAIL;

  DONE;
}")

(define_insn "*movsicc_internal"
  [(set (match_operand:SI 0 "move_output_operand" "=d,d,d,d,d,c,d,d,d,d,d,c,?&d")
	(if_then_else:SI
	  (match_operator:CC 1 "condexec_test_operator"
	    [(match_operand:CC 2 "br_flag_operand" "b,b,b,b,b,b,b,b,b,b,b,b,b")
	     (const_int 0)])
	  (match_operand:SI 3 "move_input_operand" "dI,i,Q,m,c,d,0,0,0,0,0,0,dim")
	  (match_operand:SI 4 "move_input_operand" "0,0,0,0,0,0,dI,i,Q,m,c,d,dim")))]
  ""
  "#"
  [(set_attr "length" "4,8,4,8,4,4,4,8,4,8,4,4,16")
   (set_attr "type" "either,long,sload,lload,mu,mu,either,long,sload,lload,mu,mu,multi")])

;; If we have: a = (test) ? a : b, or a = (test) ? b : a, we can split it
;; before reload to allow combine to substitute in early.
;; ??? Not until we teach reload how to do conditional spills, we can't.
(define_split
  [(set (match_operand:SI 0 "move_output_operand" "")
	(if_then_else:SI (match_operator:CC 1 "condexec_test_operator"
			   [(match_operand:CC 2 "br_flag_operand" "")
			    (const_int 0)])
			 (match_operand:SI 3 "move_input_operand" "")
			 (match_dup 0)))]
  "reload_completed"
  [(cond_exec (match_dup 1)
     (set (match_dup 0) (match_dup 3)))]
  "")

(define_split
  [(set (match_operand:SI 0 "move_output_operand" "")
	(if_then_else:SI (match_operator:CC 1 "condexec_test_operator"
			   [(match_operand:CC 2 "br_flag_operand" "")
			    (const_int 0)])
			 (match_dup 0)
			 (match_operand:SI 3 "move_input_operand" "")))]
  "reload_completed"
  [(cond_exec (match_dup 4)
     (set (match_dup 0) (match_dup 3)))]
  "
{
  if (GET_CODE (operands[1]) == EQ)
    operands[4] = gen_rtx_NE (CCmode, operands[2], const0_rtx);
  else
    operands[4] = gen_rtx_EQ (CCmode, operands[2], const0_rtx);
}")

(define_split
  [(set (match_operand:SI 0 "move_output_operand" "")
	(if_then_else:SI (match_operator:CC 1 "condexec_test_operator"
			   [(match_operand:CC 2 "br_flag_operand" "")
			    (const_int 0)])
			 (match_operand:SI 3 "move_input_operand" "")
			 (match_operand:SI 4 "move_input_operand" "")))]
  "reload_completed"
  [(cond_exec (match_dup 1)
     (set (match_dup 0) (match_dup 3)))
   (cond_exec (match_dup 5)
     (set (match_dup 0) (match_dup 4)))]
  "
{
  if (GET_CODE (operands[1]) == EQ)
    operands[5] = gen_rtx_NE (CCmode, operands[2], const0_rtx);
  else
    operands[5] = gen_rtx_EQ (CCmode, operands[2], const0_rtx);
}")

(define_expand "movsfcc"
  [(set (match_operand:SF 0 "move_output_operand" "")
	(if_then_else:SF (match_operand 1 "" "")
			 (match_operand:SF 2 "move_input_operand" "")
			 (match_operand:SF 3 "move_input_operand" "")))]
  "TARGET_COND_MOVE"
  "
{
  if (!d30v_emit_cond_move (operands[0], operands[1], operands[2], operands[3]))
    FAIL;

  DONE;
}")

(define_insn "*movsfcc_internal"
  [(set (match_operand:SF 0 "gpr_operand" "=d,d,d,d,d,d,d,d,?&d")
	(if_then_else:SF
	  (match_operator:CC 1 "condexec_test_operator"
	    [(match_operand:CC 2 "br_flag_operand" "b,b,b,b,b,b,b,b,b")
	     (const_int 0)])
	  (match_operand:SF 3 "move_input_operand" "dG,F,Q,m,0,0,0,0,dim")
	  (match_operand:SF 4 "move_input_operand" "0,0,0,0,dG,F,Q,m,dim")))]
  ""
  "#"
  [(set_attr "length" "4,8,4,8,4,8,4,8,16")
   (set_attr "type" "either,long,sload,lload,either,long,sload,lload,multi")])

(define_split
  [(set (match_operand:SF 0 "move_output_operand" "")
	(if_then_else:SF (match_operator:CC 1 "condexec_test_operator"
			   [(match_operand:CC 2 "br_flag_operand" "")
			    (const_int 0)])
			 (match_operand:SF 3 "move_input_operand" "")
			 (match_dup 0)))]
  "reload_completed"
  [(cond_exec (match_dup 1)
     (set (match_dup 0) (match_dup 3)))]
  "")

(define_split
  [(set (match_operand:SF 0 "move_output_operand" "")
	(if_then_else:SF (match_operator:CC 1 "condexec_test_operator"
			   [(match_operand:CC 2 "br_flag_operand" "")
			    (const_int 0)])
			 (match_dup 0)
			 (match_operand:SF 3 "move_input_operand" "")))]
  "reload_completed"
  [(cond_exec (match_dup 4)
     (set (match_dup 0) (match_dup 3)))]
  "
{
  if (GET_CODE (operands[1]) == EQ)
    operands[4] = gen_rtx_NE (CCmode, operands[2], const0_rtx);
  else
    operands[4] = gen_rtx_EQ (CCmode, operands[2], const0_rtx);
}")

(define_split
  [(set (match_operand:SF 0 "move_output_operand" "")
	(if_then_else:SF (match_operator:CC 1 "condexec_test_operator"
			   [(match_operand:CC 2 "br_flag_operand" "")
			    (const_int 0)])
			 (match_operand:SF 3 "move_input_operand" "")
			 (match_operand:SF 4 "move_input_operand" "")))]
  "reload_completed"
  [(cond_exec (match_dup 1)
     (set (match_dup 0) (match_dup 3)))
   (cond_exec (match_dup 5)
     (set (match_dup 0) (match_dup 4)))]
  "
{
  if (GET_CODE (operands[1]) == EQ)
    operands[5] = gen_rtx_NE (CCmode, operands[2], const0_rtx);
  else
    operands[5] = gen_rtx_EQ (CCmode, operands[2], const0_rtx);
}")


;; ::::::::::::::::::::
;; ::
;; :: Conditional execution
;; ::
;; ::::::::::::::::::::

(define_insn "*cond_exec_movqi"
  [(cond_exec
     (match_operator:CC 2 "condexec_test_operator"
       [(match_operand:CC 3 "br_flag_operand" "b,b,b,b,b,b,b,b,b,b")
	(const_int 0)])
     (set (match_operand:QI 0 "move_output_operand" "=d,d,d,d,Q,m,Q,m,d,c")
	  (match_operand:QI 1 "move_input_operand" "dI,i,Q,m,d,d,O,O,c,d")))]
  "register_operand (operands[0], QImode)
   || reg_or_0_operand (operands[1], QImode)"
  "@
    or%F2 %0,%.,%1
    or%F2 %0,%.,%1
    ldb%F2 %0,%M1
    ldb%F2 %0,%M1
    stb%F2 %1,%M0
    stb%F2 %1,%M0
    stb%F2 %.,%M0
    stb%F2 %.,%M0
    mvfsys%F2 %0,%1
    mvtsys%F2 %0,%1"
  [(set_attr "length" "4,8,4,8,4,8,4,8,4,4")
   (set_attr "type" "either,long,sload,lload,mu,long,mu,long,mu,mu")])

(define_insn "*cond_exec_movhi"
  [(cond_exec
     (match_operator:CC 2 "condexec_test_operator"
       [(match_operand:CC 3 "br_flag_operand" "b,b,b,b,b,b,b,b,b,b")
	(const_int 0)])
     (set (match_operand:HI 0 "move_output_operand" "=d,d,d,d,Q,m,Q,m,d,c")
	  (match_operand:HI 1 "move_input_operand" "dI,i,Q,m,d,d,O,O,c,d")))]
  "register_operand (operands[0], HImode)
   || reg_or_0_operand (operands[1], HImode)"
  "@
    or%F2 %0,%.,%1
    or%F2 %0,%.,%1
    ldh%F2 %0,%M1
    ldh%F2 %0,%M1
    sth%F2 %1,%M0
    sth%F2 %1,%M0
    sth%F2 %.,%M0
    sth%F2 %.,%M0
    mvfsys%F2 %0,%1
    mvtsys%F2 %0,%1"
  [(set_attr "length" "4,8,4,8,4,8,4,8,4,4")
   (set_attr "type" "either,long,sload,lload,mu,long,mu,long,mu,mu")])

(define_insn "*cond_exec_movsi"
  [(cond_exec
     (match_operator:CC 2 "condexec_test_operator"
       [(match_operand:CC 3 "br_flag_operand" "b,b,b,b,b,b,b,b,b,b,b")
	(const_int 0)])
     (set (match_operand:SI 0 "move_output_operand" "=d,d,d,d,d,Q,m,Q,m,d,c")
	  (match_operand:SI 1 "move_input_operand" "dI,F,i,Q,m,d,d,O,O,c,d")))]
  "register_operand (operands[0], SImode)
   || reg_or_0_operand (operands[1], SImode)"
  "@
    or%F2 %0,%.,%1
    or%F2 %0,%.,%L1
    or%F2 %0,%.,%1
    ldw%F2 %0,%M1
    ldw%F2 %0,%M1
    stw%F2 %1,%M0
    stw%F2 %1,%M0
    stw%F2 %.,%M0
    stw%F2 %.,%M0
    mvfsys%F2 %0,%1
    mvtsys%F2 %0,%1"
  [(set_attr "length" "4,8,8,4,8,4,8,4,8,4,4")
   (set_attr "type" "either,long,long,sload,lload,mu,long,mu,long,mu,mu")])

(define_insn "*cond_exec_movsf"
  [(cond_exec
     (match_operator:CC 2 "condexec_test_operator"
       [(match_operand:CC 3 "br_flag_operand" "b,b,b,b,b,b,b,b,b")
	(const_int 0)])
     (set (match_operand:SF 0 "move_output_operand" "=d,d,d,d,d,Q,m,Q,m")
	  (match_operand:SF 1 "move_input_operand" "d,G,F,Q,m,d,d,G,G")))]
  "register_operand (operands[0], SFmode)
   || reg_or_0_operand (operands[1], SFmode)"
  "@
    or%F2 %0,%.,%1
    or%F2 %0,%.,0
    or%F2 %0,%.,%f1
    ldw%F2 %0,%M1
    ldw%F2 %0,%M1
    stw%F2 %1,%M0
    stw%F2 %1,%M0
    stw%F2 %.,%M0
    stw%F2 %.,%M0"
  [(set_attr "length" "4,4,8,4,8,4,8,4,8")
   (set_attr "type" "either,either,long,sload,lload,mu,long,mu,long")])

(define_insn "*cond_exec_zero_extendqisi"
  [(cond_exec
     (match_operator 2 "condexec_test_operator"
       [(match_operand:CC 3 "br_flag_operand" "b,b,b")
        (const_int 0)])
     (set (match_operand:SI 0 "gpr_operand" "=d,d,d")
	  (zero_extend:SI
	    (match_operand:QI 1 "gpr_or_memory_operand" "d,Q,m"))))]
  ""
  "@
    and%F2 %0,%1,0xff
    ldbu%F2 %0,%M1
    ldbu%F2 %0,%M1"
  [(set_attr "length" "8,4,8")
   (set_attr "type" "long,sload,lload")])

(define_insn "*cond_exec_sign_extendqisi"
  [(cond_exec
     (match_operator 2 "condexec_test_operator"
       [(match_operand:CC 3 "br_flag_operand" "b,b,b")
        (const_int 0)])
     (set (match_operand:SI 0 "gpr_operand" "=d,d,d")
	  (sign_extend:SI
	    (match_operand:QI 1 "gpr_or_memory_operand" "d,Q,m"))))]
  ""
  "@
    #
    ldbu%F2 %0,%M1
    ldbu%F2 %0,%M1"
  [(set_attr "length" "8,4,8")
   (set_attr "type" "multi,sload,lload")])

(define_split
  [(cond_exec
     (match_operator 1 "condexec_test_operator"
       [(match_operand:CC 2 "br_flag_operand" "")
        (const_int 0)])
     (set (match_operand:SI 0 "gpr_operand" "")
	  (sign_extend:SI (match_operand:QI 3 "gpr_operand" ""))))]
   "reload_completed"
   [(cond_exec (match_dup 1)
      (set (match_dup 5) (ashift:SI (match_dup 6) (const_int 24))))
    (cond_exec (match_dup 1)
      (set (match_dup 5) (ashiftrt:SI (match_dup 5) (const_int 24))))]
   "
{
  operands[5] = gen_lowpart (SImode, operands[0]);
  operands[6] = gen_lowpart (SImode, operands[1]);
}")

(define_insn "*cond_exec_zero_extendhisi"
  [(cond_exec
     (match_operator 2 "condexec_test_operator"
       [(match_operand:CC 3 "br_flag_operand" "b,b,b")
        (const_int 0)])
     (set (match_operand:SI 0 "gpr_operand" "=d,d,d")
	  (zero_extend:SI
	    (match_operand:HI 1 "gpr_or_memory_operand" "d,Q,m"))))]
  ""
  "@
    and%F2 %0,%1,0xffff
    ldbu%F2 %0,%M1
    ldbu%F2 %0,%M1"
  [(set_attr "length" "8,4,8")
   (set_attr "type" "long,sload,lload")])

(define_insn "*cond_exec_sign_extendhisi"
  [(cond_exec
     (match_operator 2 "condexec_test_operator"
       [(match_operand:CC 3 "br_flag_operand" "b,b,b")
        (const_int 0)])
     (set (match_operand:SI 0 "gpr_operand" "=d,d,d")
	  (sign_extend:SI
	    (match_operand:HI 1 "gpr_or_memory_operand" "d,Q,m"))))]
  ""
  "@
    #
    ldbu%F2 %0,%M1
    ldbu%F2 %0,%M1"
  [(set_attr "length" "8,4,8")
   (set_attr "type" "multi,sload,lload")])

(define_split
  [(cond_exec
     (match_operator 2 "condexec_test_operator"
       [(match_operand:CC 3 "br_flag_operand" "")
        (const_int 0)])
     (set (match_operand:SI 0 "gpr_operand" "")
	  (sign_extend:SI (match_operand:HI 1 "gpr_operand" ""))))]
   "reload_completed"
   [(cond_exec (match_dup 1)
      (set (match_dup 5) (ashift:SI (match_dup 6) (const_int 16))))
    (cond_exec (match_dup 1)
      (set (match_dup 5) (ashiftrt:SI (match_dup 5) (const_int 16))))]
   "
{
  operands[5] = gen_lowpart (SImode, operands[0]);
  operands[6] = gen_lowpart (SImode, operands[3]);
}")

(define_insn "*cond_exec_si_unary"
  [(cond_exec
     (match_operator 3 "condexec_test_operator"
       [(match_operand:CC 4 "br_flag_operand" "b")
        (const_int 0)])
     (set (match_operand:SI 0 "gpr_operand" "=d")
	  (match_operator:SI 1 "condexec_unary_operator"
	    [(match_operand:SI 2 "gpr_operand" "d")])))]
  ""
  "*
{
  switch (GET_CODE (operands[1]))
    {
    default:
      fatal_insn (\"cond_exec_si_unary:\", insn);

    case ABS: return \"abs%F3 %0,%2\";
    case NOT: return \"not%F3 %0,%2\";
    }
}"
  [(set_attr "length" "4")
   (set_attr "type" "either")])

(define_insn "*cond_exec_si_neg"
  [(cond_exec
     (match_operator 2 "condexec_test_operator"
       [(match_operand:CC 3 "br_flag_operand" "b")
        (const_int 0)])
     (parallel [
       (set (match_operand:SI 0 "gpr_operand" "=d")
	    (neg:SI (match_operand:SI 1 "gpr_operand" "d")))
       (clobber (match_operand:CC 4 "flag_operand" ""))
       (clobber (match_operand:CC 5 "flag_operand" ""))
       (clobber (match_operand:CC 6 "flag_operand" ""))]))]
  ""
  "sub%F2 %0,%.,%1"
  [(set_attr "length" "4")
   (set_attr "type" "either")])

(define_insn "*cond_exec_si_addsub"
  [(cond_exec
     (match_operator 4 "condexec_test_operator"
       [(match_operand:CC 5 "br_flag_operand" "b,b")
        (const_int 0)])
     (parallel [
       (set (match_operand:SI 0 "gpr_operand" "=d,d")
	    (match_operator:SI 1 "condexec_addsub_operator"
	      [(match_operand:SI 2 "gpr_operand" "d,d")
	       (match_operand:SI 3 "gpr_or_constant_operand" "dI,i")]))
       (clobber (match_operand:CC 6 "flag_operand" ""))
       (clobber (match_operand:CC 7 "flag_operand" ""))
       (clobber (match_operand:CC 8 "flag_operand" ""))]))]
  ""
  "*
{
  switch (GET_CODE (operands[1]))
    {
    default:
      fatal_insn (\"cond_exec_si_addsub_true:\", insn);

    case PLUS:  return \"add%F4 %0,%2,%3\";
    case MINUS: return \"sub%F4 %0,%2,%3\";
    }
}"
  [(set_attr "length" "4,8")
   (set_attr "type" "either,long")])

(define_insn "*cond_exec_si_binary"
  [(cond_exec
     (match_operator 4 "condexec_test_operator"
       [(match_operand:CC 5 "br_flag_operand" "b,b")
        (const_int 0)])
     (set (match_operand:SI 0 "gpr_operand" "=d,d")
          (match_operator:SI 1 "condexec_binary_operator"
	    [(match_operand:SI 2 "gpr_operand" "d,d")
	     (match_operand:SI 3 "gpr_or_constant_operand" "dI,i")])))]
  ""
  "*
{
  switch (GET_CODE (operands[1]))
    {
    default:
      fatal_insn (\"cond_exec_si_binary_true:\", insn);

    case AND:      return \"and%F4 %0,%2,%3\";
    case IOR:      return \"or%F4 %0,%2,%3\";
    case XOR:      return \"xor%F4 %0,%2,%3\";
    case ASHIFT:   return \"sra%F4 %0,%2,%n3\";
    case ASHIFTRT: return \"sra%F4 %0,%2,%3\";
    case LSHIFTRT: return \"srl%F4 %0,%2,%3\";
    case ROTATE:   return \"rot%F4 %0,%2,%n3\";
    case ROTATERT: return \"rot%F4 %0,%2,%3\";
    }
}"
  [(set_attr "length" "4,8")
   (set_attr "type" "either,long")])

(define_insn "*cond_exec_si_shiftl"
  [(cond_exec
     (match_operator 4 "condexec_test_operator"
       [(match_operand:CC 5 "br_flag_operand" "b")
        (const_int 0)])
     (set (match_operand:SI 0 "gpr_operand" "=d")
	  (match_operator:SI 1 "condexec_shiftl_operator"
	    [(match_operand:SI 2 "gpr_operand" "d")
	     (neg:SI (match_operand:SI 3 "gpr_operand" "d"))])))]
  ""
  "*
{
  switch (GET_CODE (operands[1]))
    {
    default:
      fatal_insn (\"cond_exec_si_shiftl_true:\", insn);

    case ASHIFT:   return \"sra%F4 %0,%2,%3\";
    case ROTATE:   return \"rot%F4 %0,%2,%3\";
    }
}"
  [(set_attr "length" "4")
   (set_attr "type" "either")])

(define_insn "*cond_exec_si_mul"
  [(cond_exec
     (match_operator 4 "condexec_test_operator"
       [(match_operand:CC 5 "br_flag_operand" "b")
        (const_int 0)])
     (set (match_operand:SI 0 "gpr_operand" "=d")
	  (mult:SI (match_operand:SI 1 "gpr_operand" "%d")
		   (match_operand:SI 2 "gpr_or_signed6_operand" "dI"))))]
  ""
  "mul%F4 %0,%1,%2"
  [(set_attr "length" "4")
   (set_attr "type" "iu")])

(define_insn "*cond_exec_call_internal"
  [(cond_exec
     (match_operator 4 "condexec_test_operator"
       [(match_operand:CC 5 "br_flag_operand" "b,b")
        (const_int 0)])
     (parallel [
       (call (match_operand:QI 0 "call_operand" "R,S")
	     (match_operand 1 "" ""))
       (use (match_operand 2 "" ""))
       (clobber (match_operand 3 "" "=d,d"))]))]
  ""
  "@
    jsr%F4 %0
    bsr%F4 %0"
  [(set_attr "length" "4,8")
   (set_attr "type" "mu,long")])

(define_insn "*cond_exec_call_value_internal"
  [(cond_exec
     (match_operator 5 "condexec_test_operator"
       [(match_operand:CC 6 "br_flag_operand" "b,b")
        (const_int 0)])
     (parallel [
       (set (match_operand 0 "gpr_operand" "=d,d")
	    (call (match_operand:QI 1 "call_operand" "R,S")
	          (match_operand 2 "" "")))
       (use (match_operand 3 "" ""))
       (clobber (match_operand 4 "" "=d,d"))]))]
  ""
  "@
    jsr%F5 %1
    bsr%F5 %1"
  [(set_attr "length" "4,8")
   (set_attr "type" "mu,long")])

;; ::::::::::::::::::::
;; ::
;; :: Miscellaneous instructions
;; ::
;; ::::::::::::::::::::

;; No operation, needed in case the user uses -g but not -O.
(define_insn "nop"
  [(const_int 0)]
  ""
  "nop || nop"
  [(set_attr "length" "8")
   (set_attr "type" "long")])

;; Pseudo instruction that prevents the scheduler from moving code above this
;; point.
(define_insn "blockage"
  [(unspec_volatile [(const_int 0)] 0)]
  ""
  ""
  [(set_attr "length" "0")
   (set_attr "type" "unknown")])
