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

(define_attr “predicable” “no,yes” (const_string “yes”)) ;; :::::::::::::::::::: ;; :: ;; :: 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”) ;; Not strictly true, since we ought to be able to combine conditions, (set_attr “predicable” “no”)])

;; 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”) ;; Not strictly true, since we ought to be able to combine conditions, (set_attr “predicable” “no”)])

;; 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”) ;; Not strictly true, since we ought to be able to combine conditions, (set_attr “predicable” “no”)])

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

;; Logical AND, 32 bit integers

(define_insn “andsi3” [(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 “gpr_or_constant_operand” “L,I,i,d”)))] "" “@ bclr%: %0,%1,%B2 and%: %0,%1,%2 and%: %0,%1,%2 and%: %0,%1,%2” [(set_attr “length” “4,4,8,4”) (set_attr “type” “either,either,long,either”)])

;; Inclusive OR, 32 bit integers

(define_insn “iorsi3” [(set (match_operand:SI 0 “gpr_operand” “=d,d,d,d”) (ior:SI (match_operand:SI 1 “gpr_operand” “%d,d,d,d”) (match_operand:SI 2 “gpr_or_constant_operand” “K,I,i,d”)))] "" “@ bset%: %0,%1,%B2 or%: %0,%1,%2 or%: %0,%1,%2 or%: %0,%1,%2” [(set_attr “length” “4,4,8,4”) (set_attr “type” “either,either,long,either”)])

;; Exclusive OR, 32 bit integers

(define_insn “*xorsi3_constant” [(set (match_operand:SI 0 “gpr_operand” “=d,d,d,d”) (xor:SI (match_operand:SI 1 “gpr_operand” “%d,d,d,d”) (match_operand:SI 2 “gpr_or_constant_operand” “K,I,i,d”)))] "" “@ bnot%: %0,%1,%B2 xor%: %0,%1,%2 xor%: %0,%1,%2 xor%: %0,%1,%2” [(set_attr “length” “4,4,8,4”) (set_attr “type” “either,either,long,either”)])

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

;; 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))) (cond_exec (eq:CC (match_dup 0) (const_int 0)) (set (match_dup 0) (eq: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 “*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))) (cond_exec (ne:CC (match_dup 0) (const_int 0)) (set (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_COND_EXEC (VOIDmode, gen_rtx_NE (CCmode, tmpflag, const0_rtx), gen_rtx_SET (VOIDmode, outflag, gen_rtx_fmt_ee (cond, CCmode, high[0], high[1])));

operands[7] = gen_rtx_COND_EXEC (VOIDmode, gen_rtx_EQ (CCmode, tmpflag, const0_rtx), gen_rtx_SET (VOIDmode, outflag, gen_rtx_fmt_ee (ucond, CCmode, low[0], low[1]))); }")

;; :::::::::::::::::::: ;; :: ;; :: 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”) (set_attr “predicable” “no”)])

(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”) (set_attr “predicable” “no”)])

;; 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 "" "“)))] “peep2_reg_dead_p (2, operands[0]) && GET_CODE (operands[4]) != RETURN && GET_CODE (operands[5]) != RETURN” [(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”) (set_attr “predicable” “no”)])

(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_attr “predicable” “no”)]) ;; :::::::::::::::::::: ;; :: ;; :: 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”) ;; Not strictly true -- we could combine conditions. (set_attr “predicable” “no”)])

(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”) ;; Not strictly true -- we could combine conditions. (set_attr “predicable” “no”)]) ;; :::::::::::::::::::: ;; :: ;; :: 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”) (set_attr “predicable” “no”)])

(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”) (set_attr “predicable” “no”)])

(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”) (set_attr “predicable” “no”)])

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

;; 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”) (set_attr “predicable” “no”)])

;; 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”) (set_attr “predicable” “no”)])

;; :::::::::::::::::::: ;; :: ;; :: 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”))] "" " { cfun->machine->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”) (set_attr “predicable” “no”)])

;; 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”) (set_attr “predicable” “no”)])

;; 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”) (set_attr “predicable” “no”)])

;; 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”) (set_attr “predicable” “no”)])

(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); }”)

;; :::::::::::::::::::: ;; :: ;; :: 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”) (set_attr “predicable” “no”)])

;; 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”) (set_attr “predicable” “no”)]) ;; :::::::::::::::::::: ;; :: ;; :: Conditional execution ;; :: ;; ::::::::::::::::::::

(define_cond_exec [(match_operator:CC 0 “condexec_test_operator” [(match_operand:CC 1 “br_flag_operand” “b”) (const_int 0)])] "" "")