X-Git-Url: https://oss.titaniummirror.com/gitweb/?a=blobdiff_plain;f=gcc%2Fconfig%2Ffrv%2Ffrv.md;fp=gcc%2Fconfig%2Ffrv%2Ffrv.md;h=aadf02c4fbd9846c4e01841f98d81a044d1a79e8;hb=6fed43773c9b0ce596dca5686f37ac3fc0fa11c0;hp=0000000000000000000000000000000000000000;hpb=27b11d56b743098deb193d510b337ba22dc52e5c;p=msp430-gcc.git diff --git a/gcc/config/frv/frv.md b/gcc/config/frv/frv.md new file mode 100644 index 00000000..aadf02c4 --- /dev/null +++ b/gcc/config/frv/frv.md @@ -0,0 +1,8267 @@ +;; Frv Machine Description +;; Copyright (C) 1999, 2000, 2001, 2003, 2004, 2005, 2007, 2008 +;; Free Software Foundation, Inc. +;; Contributed by Red Hat, Inc. + +;; This file is part of GCC. + +;; GCC is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 3, or (at your option) +;; any later version. + +;; GCC is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GCC; see the file COPYING3. If not see +;; . + +;;- See file "rtl.def" for documentation on define_insn, match_*, et. al. + + +;; :::::::::::::::::::: +;; :: +;; :: Unspec's used +;; :: +;; :::::::::::::::::::: + +;; GOT constants must go 12/HI/LO for the splitter to work + +(define_constants + [(UNSPEC_BLOCKAGE 0) + (UNSPEC_CC_TO_GPR 1) + (UNSPEC_GPR_TO_CC 2) + (UNSPEC_PIC_PROLOGUE 3) + (UNSPEC_CR_LOGIC 4) + (UNSPEC_STACK_ADJUST 5) + (UNSPEC_EH_RETURN_EPILOGUE 6) + (UNSPEC_GOT 7) + (UNSPEC_LDD 8) + (UNSPEC_OPTIONAL_MEMBAR 9) + + (UNSPEC_GETTLSOFF 200) + (UNSPEC_TLS_LOAD_GOTTLSOFF12 201) + (UNSPEC_TLS_INDIRECT_CALL 202) + (UNSPEC_TLS_TLSDESC_LDD 203) + (UNSPEC_TLS_TLSDESC_LDD_AUX 204) + (UNSPEC_TLS_TLSOFF_LD 205) + (UNSPEC_TLS_LDDI 206) + (UNSPEC_TLSOFF_HILO 207) + + (R_FRV_GOT12 11) + (R_FRV_GOTHI 12) + (R_FRV_GOTLO 13) + (R_FRV_FUNCDESC 14) + (R_FRV_FUNCDESC_GOT12 15) + (R_FRV_FUNCDESC_GOTHI 16) + (R_FRV_FUNCDESC_GOTLO 17) + (R_FRV_FUNCDESC_VALUE 18) + (R_FRV_FUNCDESC_GOTOFF12 19) + (R_FRV_FUNCDESC_GOTOFFHI 20) + (R_FRV_FUNCDESC_GOTOFFLO 21) + (R_FRV_GOTOFF12 22) + (R_FRV_GOTOFFHI 23) + (R_FRV_GOTOFFLO 24) + (R_FRV_GPREL12 25) + (R_FRV_GPRELHI 26) + (R_FRV_GPRELLO 27) + (R_FRV_GOTTLSOFF_HI 28) + (R_FRV_GOTTLSOFF_LO 29) + (R_FRV_TLSMOFFHI 30) + (R_FRV_TLSMOFFLO 31) + (R_FRV_TLSMOFF12 32) + (R_FRV_TLSDESCHI 33) + (R_FRV_TLSDESCLO 34) + (R_FRV_GOTTLSDESCHI 35) + (R_FRV_GOTTLSDESCLO 36) + + (GR8_REG 8) + (GR9_REG 9) + (GR14_REG 14) + ;; LR_REG conflicts with definition in frv.h + (LRREG 169) + (FDPIC_REG 15) + ]) + +(define_mode_iterator IMODE [QI HI SI DI]) +(define_mode_attr IMODEsuffix [(QI "b") (HI "h") (SI "") (DI "d")]) +(define_mode_attr BREADsuffix [(QI "ub") (HI "uh") (SI "") (DI "d")]) + +;; :::::::::::::::::::: +;; :: +;; :: 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 (6-bit signed ints). +;; 'J' Second machine-dependent integer constant (10-bit signed ints). +;; 'K' Third machine-dependent integer constant (-2048). +;; 'L' Fourth machine-dependent integer constant (16-bit signed ints). +;; 'M' Fifth machine-dependent integer constant (16-bit unsigned ints). +;; 'N' Sixth machine-dependent integer constant (-2047..-1). +;; 'O' Seventh machine-dependent integer constant (zero). +;; 'P' Eighth machine-dependent integer constant (1..2047). +;; +;; 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. + + +;; :::::::::::::::::::: +;; :: +;; :: 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'. + +(define_attr "length" "" (const_int 4)) + +;; Processor type -- this attribute must exactly match the processor_type +;; enumeration in frv-protos.h. + +(define_attr "cpu" "generic,fr550,fr500,fr450,fr405,fr400,fr300,simple,tomcat" + (const (symbol_ref "frv_cpu_type"))) + +;; Attribute is "yes" for branches and jumps that span too great a distance +;; to be implemented in the most natural way. Such instructions will use +;; a call instruction in some way. + +(define_attr "far_jump" "yes,no" (const_string "no")) + +;; Instruction type +;; "unknown" must come last. +(define_attr "type" + "int,sethi,setlo,mul,div,gload,gstore,fload,fstore,movfg,movgf,macc,scan,cut,branch,jump,jumpl,call,spr,trap,fnop,fsconv,fsadd,fscmp,fsmul,fsmadd,fsdiv,sqrt_single,fdconv,fdadd,fdcmp,fdmul,fdmadd,fddiv,sqrt_double,mnop,mlogic,maveh,msath,maddh,mqaddh,mpackh,munpackh,mdpackh,mbhconv,mrot,mshift,mexpdhw,mexpdhd,mwcut,mmulh,mmulxh,mmach,mmrdh,mqmulh,mqmulxh,mqmach,mcpx,mqcpx,mcut,mclracc,mclracca,mdunpackh,mbhconve,mrdacc,mwtacc,maddacc,mdaddacc,mabsh,mdrot,mcpl,mdcut,mqsath,mqlimh,mqshift,mset,ccr,multi,load_or_call,unknown" + (const_string "unknown")) + +(define_attr "acc_group" "none,even,odd" + (symbol_ref "frv_acc_group (insn)")) + +;; Scheduling and Packing Overview +;; ------------------------------- +;; +;; FR-V instructions are divided into five groups: integer, floating-point, +;; media, branch and control. Each group is associated with a separate set +;; of processing units, the number and behavior of which depend on the target +;; target processor. Integer units have names like I0 and I1, floating-point +;; units have names like F0 and F1, and so on. +;; +;; Each member of the FR-V family has its own restrictions on which +;; instructions can issue to which units. For example, some processors +;; allow loads to issue to I0 or I1 while others only allow them to issue +;; to I0. As well as these processor-specific restrictions, there is a +;; general rule that an instruction can only issue to unit X + 1 if an +;; instruction in the same packet issued to unit X. +;; +;; Sometimes the only way to honor these restrictions is by adding nops +;; to a packet. For example, on the fr550, media instructions that access +;; ACC4-7 can only issue to M1 or M3. It is therefore only possible to +;; execute these instructions by packing them with something that issues +;; to M0. When no useful M0 instruction exists, an "mnop" can be used +;; instead. +;; +;; Having decided which instructions should issue to which units, the packet +;; should be ordered according to the following template: +;; +;; I0 F0/M0 I1 F1/M1 .... B0 B1 ... +;; +;; Note that VLIW packets execute strictly in parallel. Every instruction +;; in the packet will stall until all input operands are ready. These +;; operands are then read simultaneously before any registers are modified. +;; This means that it's OK to have write-after-read hazards between +;; instructions in the same packet, even if the write is listed earlier +;; than the read. +;; +;; Three gcc passes are involved in generating VLIW packets: +;; +;; (1) The scheduler. This pass uses the standard scheduling code and +;; behaves in much the same way as it would for a superscalar RISC +;; architecture. +;; +;; (2) frv_reorg. This pass inserts nops into packets in order to meet +;; the processor's issue requirements. It also has code to optimize +;; the type of padding used to align labels. +;; +;; (3) frv_pack_insns. The final packing phase, which puts the +;; instructions into assembly language order according to the +;; "I0 F0/M0 ..." template above. +;; +;; In the ideal case, these three passes will agree on which instructions +;; should be packed together, but this won't always happen. In particular: +;; +;; (a) (2) might not pack predicated instructions in the same way as (1). +;; The scheduler tries to schedule predicated instructions for the +;; worst case, assuming the predicate is true. However, if we have +;; something like a predicated load, it isn't always possible to +;; fill the load delay with useful instructions. (2) should then +;; pack the user of the loaded value as aggressively as possible, +;; in order to optimize the case when the predicate is false. +;; See frv_pack_insn_p for more details. +;; +;; (b) The final shorten_branches pass runs between (2) and (3). +;; Since (2) inserts nops, it is possible that some branches +;; that were thought to be in range during (2) turned out to +;; out-of-range in (3). +;; +;; All three passes use DFAs to model issue restrictions. The main +;; question that the DFAs are supposed to answer is simply: can these +;; instructions be packed together? The DFAs are not responsible for +;; assigning instructions to execution units; that's the job of +;; frv_sort_insn_group, see below for details. +;; +;; To get the best results, the DFAs should try to allow packets to +;; be built in every possible order. This gives the scheduler more +;; flexibility, removing the need for things like multipass lookahead. +;; It also means we can take more advantage of inter-packet dependencies. +;; +;; For example, suppose we're compiling for the fr400 and we have: +;; +;; addi gr4,#1,gr5 +;; ldi @(gr6,gr0),gr4 +;; +;; We can pack these instructions together by assigning the load to I0 and +;; the addition to I1. However, because of the anti dependence between the +;; two instructions, the scheduler must schedule the addition first. +;; We should generally get better schedules if the DFA allows both +;; (ldi, addi) and (addi, ldi), leaving the final packing pass to +;; reorder the packet where appropriate. +;; +;; Almost all integer instructions can issue to any unit in the range I0 +;; to Ix, where the value of "x" depends on the type of instruction and +;; on the target processor. The rules for other instruction groups are +;; usually similar. +;; +;; When the restrictions are as regular as this, we can get the desired +;; behavior by claiming the DFA unit associated with the highest unused +;; execution unit. For example, if an instruction can issue to I0 or I1, +;; the DFA first tries to take the DFA unit associated with I1, and will +;; only take I0's unit if I1 isn't free. (Note that, as mentioned above, +;; the DFA does not assign instructions to units. An instruction that +;; claims DFA unit I1 will not necessarily issue to I1 in the final packet.) +;; +;; There are some cases, such as the fr550 media restriction mentioned +;; above, where the rule is not as simple as "any unit between 0 and X". +;; Even so, allocating higher units first brings us close to the ideal. +;; +;; Having divided instructions into packets, passes (2) and (3) must +;; assign instructions to specific execution units. They do this using +;; the following algorithm: +;; +;; 1. Partition the instructions into groups (integer, float/media, etc.) +;; +;; 2. For each group of instructions: +;; +;; (a) Issue each instruction in the reset DFA state and use the +;; DFA cpu_unit_query interface to find out which unit it picks +;; first. +;; +;; (b) Sort the instructions into ascending order of picked units. +;; Instructions that pick I1 first come after those that pick +;; I0 first, and so on. Let S be the sorted sequence and S[i] +;; be the ith element of it (counting from zero). +;; +;; (c) If this is the control or branch group, goto (i) +;; +;; (d) Find the largest L such that S[0]...S[L-1] can be issued +;; consecutively from the reset state and such that the DFA +;; claims unit X when S[X] is added. Let D be the DFA state +;; after instructions S[0]...S[L-1] have been issued. +;; +;; (e) If L is the length of S, goto (i) +;; +;; (f) Let U be the number of units belonging to this group and #S be +;; the length of S. Create a new sequence S' by concatenating +;; S[L]...S[#S-1] and (U - #S) nops. +;; +;; (g) For each permutation S'' of S', try issuing S'' from last to +;; first, starting with state D. See if the DFA claims unit +;; X + L when each S''[X] is added. If so, set S to the +;; concatenation of S[0]...S[L-1] and S'', then goto (i). +;; +;; (h) If (g) found no permutation, abort. +;; +;; (i) S is now the sorted sequence for this group, meaning that S[X] +;; issues to unit X. Trim any unwanted nops from the end of S. +;; +;; The sequence calculated by (b) is trivially correct for control +;; instructions since they can't be packed. It is also correct for branch +;; instructions due to their simple issue requirements. For integer and +;; floating-point/media instructions, the sequence calculated by (b) is +;; often the correct answer; the rest of the algorithm is optimized for +;; the case in which it is correct. +;; +;; If there were no irregularities in the issue restrictions then step +;; (d) would not be needed. It is mainly there to cope with the fr550 +;; integer restrictions, where a store can issue to I1, but only if a store +;; also issues to I0. (Note that if a packet has two stores, they will be +;; at the beginning of the sequence calculated by (b).) It also copes +;; with fr400 M-2 instructions, which must issue to M0, and which cannot +;; be issued together with an mnop in M1. +;; +;; Step (g) is the main one for integer and float/media instructions. +;; The first permutation it tries is S' itself (because, as noted above, +;; the sequence calculated by (b) is often correct). If S' doesn't work, +;; the implementation tries varying the beginning of the sequence first. +;; Thus the nops towards the end of the sequence will only move to lower +;; positions if absolutely necessary. +;; +;; The algorithm is theoretically exponential in the number of instructions +;; in a group, although it's only O(n log(n)) if the sequence calculated by +;; (b) is acceptable. In practice, the algorithm completes quickly even +;; in the rare cases where (g) needs to try other permutations. +(define_automaton "integer, float_media, branch, control, idiv, div") + +;; The main issue units. Note that not all units are available on +;; all processors. +(define_query_cpu_unit "i0,i1,i2,i3" "integer") +(define_query_cpu_unit "f0,f1,f2,f3" "float_media") +(define_query_cpu_unit "b0,b1" "branch") +(define_query_cpu_unit "c" "control") + +;; Division units. +(define_cpu_unit "idiv1,idiv2" "idiv") +(define_cpu_unit "div1,div2,root" "div") + +;; Control instructions cannot be packed with others. +(define_reservation "control" "i0+i1+i2+i3+f0+f1+f2+f3+b0+b1") + +;; Generic reservation for control insns +(define_insn_reservation "control" 1 + (eq_attr "type" "trap,spr,unknown,multi") + "c + control") + +;; Reservation for relaxable calls to gettlsoff. +(define_insn_reservation "load_or_call" 3 + (eq_attr "type" "load_or_call") + "c + control") + +;; :::::::::::::::::::: +;; :: +;; :: Generic/FR500 scheduler description +;; :: +;; :::::::::::::::::::: + +;; Integer insns +;; Synthetic units used to describe issue restrictions. +(define_automaton "fr500_integer") +(define_cpu_unit "fr500_load0,fr500_load1,fr500_store0" "fr500_integer") +(exclusion_set "fr500_load0,fr500_load1" "fr500_store0") + +(define_bypass 0 "fr500_i1_sethi" "fr500_i1_setlo") +(define_insn_reservation "fr500_i1_sethi" 1 + (and (eq_attr "cpu" "generic,fr500,tomcat") + (eq_attr "type" "sethi")) + "i1|i0") + +(define_insn_reservation "fr500_i1_setlo" 1 + (and (eq_attr "cpu" "generic,fr500,tomcat") + (eq_attr "type" "setlo")) + "i1|i0") + +(define_insn_reservation "fr500_i1_int" 1 + (and (eq_attr "cpu" "generic,fr500,tomcat") + (eq_attr "type" "int")) + "i1|i0") + +(define_insn_reservation "fr500_i1_mul" 3 + (and (eq_attr "cpu" "generic,fr500,tomcat") + (eq_attr "type" "mul")) + "i1|i0") + +(define_insn_reservation "fr500_i1_div" 19 + (and (eq_attr "cpu" "generic,fr500,tomcat") + (eq_attr "type" "div")) + "(i1|i0),(idiv1*18|idiv2*18)") + +(define_insn_reservation "fr500_i2" 4 + (and (eq_attr "cpu" "generic,fr500,tomcat") + (eq_attr "type" "gload,fload")) + "(i1|i0) + (fr500_load0|fr500_load1)") + +(define_insn_reservation "fr500_i3" 0 + (and (eq_attr "cpu" "generic,fr500,tomcat") + (eq_attr "type" "gstore,fstore")) + "i0 + fr500_store0") + +(define_insn_reservation "fr500_i4" 3 + (and (eq_attr "cpu" "generic,fr500,tomcat") + (eq_attr "type" "movgf,movfg")) + "i0") + +(define_insn_reservation "fr500_i5" 0 + (and (eq_attr "cpu" "generic,fr500,tomcat") + (eq_attr "type" "jumpl")) + "i0") + +;; +;; Branch-instructions +;; +(define_insn_reservation "fr500_branch" 0 + (and (eq_attr "cpu" "generic,fr500,tomcat") + (eq_attr "type" "jump,branch,ccr")) + "b1|b0") + +(define_insn_reservation "fr500_call" 0 + (and (eq_attr "cpu" "generic,fr500,tomcat") + (eq_attr "type" "call")) + "b0") + +;; Floating point insns. The default latencies are for non-media +;; instructions; media instructions incur an extra cycle. + +(define_bypass 4 "fr500_farith" "fr500_m1,fr500_m2,fr500_m3, + fr500_m4,fr500_m5,fr500_m6") +(define_insn_reservation "fr500_farith" 3 + (and (eq_attr "cpu" "generic,fr500,tomcat") + (eq_attr "type" "fnop,fsconv,fsadd,fsmul,fsmadd,fdconv,fdadd,fdmul,fdmadd")) + "(f1|f0)") + +(define_insn_reservation "fr500_fcmp" 4 + (and (eq_attr "cpu" "generic,fr500,tomcat") + (eq_attr "type" "fscmp,fdcmp")) + "(f1|f0)") + +(define_bypass 11 "fr500_fdiv" "fr500_m1,fr500_m2,fr500_m3, + fr500_m4,fr500_m5,fr500_m6") +(define_insn_reservation "fr500_fdiv" 10 + (and (eq_attr "cpu" "generic,fr500,tomcat") + (eq_attr "type" "fsdiv,fddiv")) + "(f1|f0),(div1*9 | div2*9)") + +(define_bypass 16 "fr500_froot" "fr500_m1,fr500_m2,fr500_m3, + fr500_m4,fr500_m5,fr500_m6") +(define_insn_reservation "fr500_froot" 15 + (and (eq_attr "cpu" "generic,fr500,tomcat") + (eq_attr "type" "sqrt_single,sqrt_double")) + "(f1|f0) + root*15") + +;; Media insns. Conflict table is as follows: +;; +;; M1 M2 M3 M4 M5 M6 +;; M1 - - - - - - +;; M2 - - - - X X +;; M3 - - - - X X +;; M4 - - - - - X +;; M5 - X X - X X +;; M6 - X X X X X +;; +;; where X indicates an invalid combination. +;; +;; Target registers are as follows: +;; +;; M1 : FPRs +;; M2 : FPRs +;; M3 : ACCs +;; M4 : ACCs +;; M5 : FPRs +;; M6 : ACCs +;; +;; The default FPR latencies are for integer instructions. +;; Floating-point instructions need one cycle more and media +;; instructions need one cycle less. +(define_automaton "fr500_media") +(define_cpu_unit "fr500_m2_0,fr500_m2_1" "fr500_media") +(define_cpu_unit "fr500_m3_0,fr500_m3_1" "fr500_media") +(define_cpu_unit "fr500_m4_0,fr500_m4_1" "fr500_media") +(define_cpu_unit "fr500_m5" "fr500_media") +(define_cpu_unit "fr500_m6" "fr500_media") + +(exclusion_set "fr500_m5,fr500_m6" "fr500_m2_0,fr500_m2_1, + fr500_m3_0,fr500_m3_1") +(exclusion_set "fr500_m6" "fr500_m4_0,fr500_m4_1,fr500_m5") + +(define_bypass 2 "fr500_m1" "fr500_m1,fr500_m2,fr500_m3, + fr500_m4,fr500_m5,fr500_m6") +(define_bypass 4 "fr500_m1" "fr500_farith,fr500_fcmp,fr500_fdiv,fr500_froot") +(define_insn_reservation "fr500_m1" 3 + (and (eq_attr "cpu" "generic,fr500,tomcat") + (eq_attr "type" "mnop,mlogic,maveh,msath,maddh,mqaddh")) + "(f1|f0)") + +(define_bypass 2 "fr500_m2" "fr500_m1,fr500_m2,fr500_m3, + fr500_m4,fr500_m5,fr500_m6") +(define_bypass 4 "fr500_m2" "fr500_farith,fr500_fcmp,fr500_fdiv,fr500_froot") +(define_insn_reservation "fr500_m2" 3 + (and (eq_attr "cpu" "generic,fr500,tomcat") + (eq_attr "type" "mrdacc,mpackh,munpackh,mbhconv,mrot,mshift,mexpdhw,mexpdhd,mwcut,mcut,mdunpackh,mbhconve")) + "(f1|f0) + (fr500_m2_0|fr500_m2_1)") + +(define_bypass 1 "fr500_m3" "fr500_m4") +(define_insn_reservation "fr500_m3" 2 + (and (eq_attr "cpu" "generic,fr500,tomcat") + (eq_attr "type" "mclracc,mwtacc")) + "(f1|f0) + (fr500_m3_0|fr500_m3_1)") + +(define_bypass 1 "fr500_m4" "fr500_m4") +(define_insn_reservation "fr500_m4" 2 + (and (eq_attr "cpu" "generic,fr500,tomcat") + (eq_attr "type" "mmulh,mmulxh,mmach,mmrdh,mqmulh,mqmulxh,mqmach,mcpx,mqcpx")) + "(f1|f0) + (fr500_m4_0|fr500_m4_1)") + +(define_bypass 2 "fr500_m5" "fr500_m1,fr500_m2,fr500_m3, + fr500_m4,fr500_m5,fr500_m6") +(define_bypass 4 "fr500_m5" "fr500_farith,fr500_fcmp,fr500_fdiv,fr500_froot") +(define_insn_reservation "fr500_m5" 3 + (and (eq_attr "cpu" "generic,fr500,tomcat") + (eq_attr "type" "mdpackh")) + "(f1|f0) + fr500_m5") + +(define_bypass 1 "fr500_m6" "fr500_m4") +(define_insn_reservation "fr500_m6" 2 + (and (eq_attr "cpu" "generic,fr500,tomcat") + (eq_attr "type" "mclracca")) + "(f1|f0) + fr500_m6") + +;; :::::::::::::::::::: +;; :: +;; :: FR400 scheduler description +;; :: +;; :::::::::::::::::::: + +;; Category 2 media instructions use both media units, but can be packed +;; with non-media instructions. Use fr400_m1unit to claim the M1 unit +;; without claiming a slot. + +;; Name Class Units Latency +;; ==== ===== ===== ======= +;; int I1 I0/I1 1 +;; sethi I1 I0/I1 0 -- does not interfere with setlo +;; setlo I1 I0/I1 1 +;; mul I1 I0 3 (*) +;; div I1 I0 20 (*) +;; gload I2 I0 4 (*) +;; fload I2 I0 4 -- only 3 if read by a media insn +;; gstore I3 I0 0 -- provides no result +;; fstore I3 I0 0 -- provides no result +;; movfg I4 I0 3 (*) +;; movgf I4 I0 3 (*) +;; jumpl I5 I0 0 -- provides no result +;; +;; (*) The results of these instructions can be read one cycle earlier +;; than indicated. The penalty given is for instructions with write-after- +;; write dependencies. + +;; The FR400 can only do loads and stores in I0, so we there's no danger +;; of memory unit collision in the same packet. There's only one divide +;; unit too. + +(define_automaton "fr400_integer") +(define_cpu_unit "fr400_mul" "fr400_integer") + +(define_insn_reservation "fr400_i1_int" 1 + (and (eq_attr "cpu" "fr400,fr405,fr450") + (eq_attr "type" "int")) + "i1|i0") + +(define_bypass 0 "fr400_i1_sethi" "fr400_i1_setlo") +(define_insn_reservation "fr400_i1_sethi" 1 + (and (eq_attr "cpu" "fr400,fr405,fr450") + (eq_attr "type" "sethi")) + "i1|i0") + +(define_insn_reservation "fr400_i1_setlo" 1 + (and (eq_attr "cpu" "fr400,fr405,fr450") + (eq_attr "type" "setlo")) + "i1|i0") + +;; 3 is the worst case (write-after-write hazard). +(define_insn_reservation "fr400_i1_mul" 3 + (and (eq_attr "cpu" "fr400,fr405") + (eq_attr "type" "mul")) + "i0 + fr400_mul") + +(define_insn_reservation "fr450_i1_mul" 2 + (and (eq_attr "cpu" "fr450") + (eq_attr "type" "mul")) + "i0 + fr400_mul") + +(define_bypass 1 "fr400_i1_macc" "fr400_i1_macc") +(define_insn_reservation "fr400_i1_macc" 2 + (and (eq_attr "cpu" "fr405,fr450") + (eq_attr "type" "macc")) + "(i0|i1) + fr400_mul") + +(define_insn_reservation "fr400_i1_scan" 1 + (and (eq_attr "cpu" "fr400,fr405,fr450") + (eq_attr "type" "scan")) + "i0") + +(define_insn_reservation "fr400_i1_cut" 2 + (and (eq_attr "cpu" "fr405,fr450") + (eq_attr "type" "cut")) + "i0 + fr400_mul") + +;; 20 is for a write-after-write hazard. +(define_insn_reservation "fr400_i1_div" 20 + (and (eq_attr "cpu" "fr400,fr405") + (eq_attr "type" "div")) + "i0 + idiv1*19") + +(define_insn_reservation "fr450_i1_div" 19 + (and (eq_attr "cpu" "fr450") + (eq_attr "type" "div")) + "i0 + idiv1*19") + +;; 4 is for a write-after-write hazard. +(define_insn_reservation "fr400_i2" 4 + (and (eq_attr "cpu" "fr400,fr405") + (eq_attr "type" "gload,fload")) + "i0") + +(define_insn_reservation "fr450_i2_gload" 3 + (and (eq_attr "cpu" "fr450") + (eq_attr "type" "gload")) + "i0") + +;; 4 is for a write-after-write hazard. +(define_insn_reservation "fr450_i2_fload" 4 + (and (eq_attr "cpu" "fr450") + (eq_attr "type" "fload")) + "i0") + +(define_insn_reservation "fr400_i3" 0 + (and (eq_attr "cpu" "fr400,fr405,fr450") + (eq_attr "type" "gstore,fstore")) + "i0") + +;; 3 is for a write-after-write hazard. +(define_insn_reservation "fr400_i4" 3 + (and (eq_attr "cpu" "fr400,fr405") + (eq_attr "type" "movfg,movgf")) + "i0") + +(define_insn_reservation "fr450_i4_movfg" 2 + (and (eq_attr "cpu" "fr450") + (eq_attr "type" "movfg")) + "i0") + +;; 3 is for a write-after-write hazard. +(define_insn_reservation "fr450_i4_movgf" 3 + (and (eq_attr "cpu" "fr450") + (eq_attr "type" "movgf")) + "i0") + +(define_insn_reservation "fr400_i5" 0 + (and (eq_attr "cpu" "fr400,fr405,fr450") + (eq_attr "type" "jumpl")) + "i0") + +;; The bypass between FPR loads and media instructions, described above. + +(define_bypass 3 + "fr400_i2" + "fr400_m1_1,fr400_m1_2,\ + fr400_m2_1,fr400_m2_2,\ + fr400_m3_1,fr400_m3_2,\ + fr400_m4_1,fr400_m4_2,\ + fr400_m5") + +;; The branch instructions all use the B unit and produce no result. + +(define_insn_reservation "fr400_b" 0 + (and (eq_attr "cpu" "fr400,fr405,fr450") + (eq_attr "type" "jump,branch,ccr,call")) + "b0") + +;; FP->FP moves are marked as "fsconv" instructions in the define_insns +;; below, but are implemented on the FR400 using "mlogic" instructions. +;; It's easier to class "fsconv" as a "m1:1" instruction than provide +;; separate define_insns for the FR400. + +;; M1 instructions store their results in FPRs. Any instruction can read +;; the result in the following cycle, so no penalty occurs. + +(define_automaton "fr400_media") +(define_cpu_unit "fr400_m1a,fr400_m1b,fr400_m2a" "fr400_media") +(exclusion_set "fr400_m1a,fr400_m1b" "fr400_m2a") + +(define_reservation "fr400_m1" "(f1|f0) + (fr400_m1a|fr400_m1b)") +(define_reservation "fr400_m2" "f0 + fr400_m2a") + +(define_insn_reservation "fr400_m1_1" 1 + (and (eq_attr "cpu" "fr400,fr405") + (eq_attr "type" "fsconv,mnop,mlogic,maveh,msath,maddh,mabsh,mset")) + "fr400_m1") + +(define_insn_reservation "fr400_m1_2" 1 + (and (eq_attr "cpu" "fr400,fr405") + (eq_attr "type" "mqaddh,mqsath,mqlimh,mqshift")) + "fr400_m2") + +;; M2 instructions store their results in accumulators, which are read +;; by M2 or M4 media commands. M2 instructions can read the results in +;; the following cycle, but M4 instructions must wait a cycle more. + +(define_bypass 1 + "fr400_m2_1,fr400_m2_2" + "fr400_m2_1,fr400_m2_2") + +(define_insn_reservation "fr400_m2_1" 2 + (and (eq_attr "cpu" "fr400,fr405") + (eq_attr "type" "mmulh,mmulxh,mmach,mmrdh,mcpx,maddacc")) + "fr400_m1") + +(define_insn_reservation "fr400_m2_2" 2 + (and (eq_attr "cpu" "fr400,fr405") + (eq_attr "type" "mqmulh,mqmulxh,mqmach,mqcpx,mdaddacc")) + "fr400_m2") + +;; For our purposes, there seems to be little real difference between +;; M1 and M3 instructions. Keep them separate anyway in case the distinction +;; is needed later. + +(define_insn_reservation "fr400_m3_1" 1 + (and (eq_attr "cpu" "fr400,fr405") + (eq_attr "type" "mpackh,mrot,mshift,mexpdhw")) + "fr400_m1") + +(define_insn_reservation "fr400_m3_2" 1 + (and (eq_attr "cpu" "fr400,fr405") + (eq_attr "type" "munpackh,mdpackh,mbhconv,mexpdhd,mwcut,mdrot,mcpl")) + "fr400_m2") + +;; M4 instructions write to accumulators or FPRs. MOVFG and STF +;; instructions can read an FPR result in the following cycle, but +;; M-unit instructions must wait a cycle more for either kind of result. + +(define_bypass 1 "fr400_m4_1,fr400_m4_2" "fr400_i3,fr400_i4") + +(define_insn_reservation "fr400_m4_1" 2 + (and (eq_attr "cpu" "fr400,fr405") + (eq_attr "type" "mrdacc,mcut,mclracc")) + "fr400_m1") + +(define_insn_reservation "fr400_m4_2" 2 + (and (eq_attr "cpu" "fr400,fr405") + (eq_attr "type" "mclracca,mdcut")) + "fr400_m2") + +;; M5 instructions always incur a 1-cycle penalty. + +(define_insn_reservation "fr400_m5" 2 + (and (eq_attr "cpu" "fr400,fr405") + (eq_attr "type" "mwtacc")) + "fr400_m2") + +;; :::::::::::::::::::: +;; :: +;; :: FR450 media scheduler description +;; :: +;; :::::::::::::::::::: + +;; The FR451 media restrictions are similar to the FR400's, but not as +;; strict and not as regular. There are 6 categories with the following +;; restrictions: +;; +;; M1 +;; M-1 M-2 M-3 M-4 M-5 M-6 +;; M-1: x x x +;; M-2: x x x x x x +;; M0 M-3: x x x +;; M-4: x x x x +;; M-5: x x x +;; M-6: x x x x x x +;; +;; where "x" indicates a conflict. +;; +;; There is no difference between M-1 and M-3 as far as issue +;; restrictions are concerned, so they are combined as "m13". + +;; Units for odd-numbered categories. There can be two of these +;; in a packet. +(define_cpu_unit "fr450_m13a,fr450_m13b" "float_media") +(define_cpu_unit "fr450_m5a,fr450_m5b" "float_media") + +;; Units for even-numbered categories. There can only be one per packet. +(define_cpu_unit "fr450_m2a,fr450_m4a,fr450_m6a" "float_media") + +;; Enforce the restriction matrix above. +(exclusion_set "fr450_m2a,fr450_m4a,fr450_m6a" "fr450_m13a,fr450_m13b") +(exclusion_set "fr450_m2a,fr450_m6a" "fr450_m5a,fr450_m5b") +(exclusion_set "fr450_m4a,fr450_m6a" "fr450_m2a") + +(define_reservation "fr450_m13" "(f1|f0) + (fr450_m13a|fr450_m13b)") +(define_reservation "fr450_m2" "f0 + fr450_m2a") +(define_reservation "fr450_m4" "f0 + fr450_m4a") +(define_reservation "fr450_m5" "(f1|f0) + (fr450_m5a|fr450_m5b)") +(define_reservation "fr450_m6" "(f0|f1) + fr450_m6a") + +;; MD-1, MD-3 and MD-8 instructions, which are the same as far +;; as scheduling is concerned. The inputs and outputs are FPRs. +;; Instructions that have 32-bit inputs and outputs belong to M-1 while +;; the rest belong to M-2. +;; +;; ??? Arithmetic shifts (MD-6) have an extra cycle latency, but we don't +;; make the distinction between them and logical shifts. +(define_insn_reservation "fr450_md138_1" 1 + (and (eq_attr "cpu" "fr450") + (eq_attr "type" "fsconv,mnop,mlogic,maveh,msath,maddh,mabsh,mset, + mrot,mshift,mexpdhw,mpackh")) + "fr450_m13") + +(define_insn_reservation "fr450_md138_2" 1 + (and (eq_attr "cpu" "fr450") + (eq_attr "type" "mqaddh,mqsath,mqlimh, + mdrot,mwcut,mqshift,mexpdhd, + munpackh,mdpackh,mbhconv,mcpl")) + "fr450_m2") + +;; MD-2 instructions. These take FPR or ACC inputs and produce an ACC output. +;; Instructions that write to double ACCs belong to M-3 while those that write +;; to quad ACCs belong to M-4. +(define_insn_reservation "fr450_md2_3" 2 + (and (eq_attr "cpu" "fr450") + (eq_attr "type" "mmulh,mmach,mcpx,mmulxh,mmrdh,maddacc")) + "fr450_m13") + +(define_insn_reservation "fr450_md2_4" 2 + (and (eq_attr "cpu" "fr450") + (eq_attr "type" "mqmulh,mqmach,mqcpx,mqmulxh,mdaddacc")) + "fr450_m4") + +;; Another MD-2 instruction can use the result on the following cycle. +(define_bypass 1 "fr450_md2_3,fr450_md2_4" "fr450_md2_3,fr450_md2_4") + +;; MD-4 instructions that write to ACCs. +(define_insn_reservation "fr450_md4_3" 2 + (and (eq_attr "cpu" "fr450") + (eq_attr "type" "mclracc")) + "fr450_m13") + +(define_insn_reservation "fr450_md4_4" 3 + (and (eq_attr "cpu" "fr450") + (eq_attr "type" "mclracca")) + "fr450_m4") + +;; MD-4 instructions that write to FPRs. +(define_insn_reservation "fr450_md4_1" 2 + (and (eq_attr "cpu" "fr450") + (eq_attr "type" "mcut")) + "fr450_m13") + +(define_insn_reservation "fr450_md4_5" 2 + (and (eq_attr "cpu" "fr450") + (eq_attr "type" "mrdacc")) + "fr450_m5") + +(define_insn_reservation "fr450_md4_6" 2 + (and (eq_attr "cpu" "fr450") + (eq_attr "type" "mdcut")) + "fr450_m6") + +;; Integer instructions can read the FPR result of an MD-4 instruction on +;; the following cycle. +(define_bypass 1 "fr450_md4_1,fr450_md4_5,fr450_md4_6" + "fr400_i3,fr450_i4_movfg") + +;; MD-5 instructions, which belong to M-3. They take FPR inputs and +;; write to ACCs. +(define_insn_reservation "fr450_md5_3" 2 + (and (eq_attr "cpu" "fr450") + (eq_attr "type" "mwtacc")) + "fr450_m13") + +;; :::::::::::::::::::: +;; :: +;; :: FR550 scheduler description +;; :: +;; :::::::::::::::::::: + +;; Prevent loads and stores from being issued in the same packet. +;; These units must go into the generic "integer" reservation because +;; of the constraints on fr550_store0 and fr550_store1. +(define_cpu_unit "fr550_load0,fr550_load1" "integer") +(define_cpu_unit "fr550_store0,fr550_store1" "integer") +(exclusion_set "fr550_load0,fr550_load1" "fr550_store0,fr550_store1") + +;; A store can only issue to I1 if one has also been issued to I0. +(presence_set "fr550_store1" "fr550_store0") + +(define_bypass 0 "fr550_sethi" "fr550_setlo") +(define_insn_reservation "fr550_sethi" 1 + (and (eq_attr "cpu" "fr550") + (eq_attr "type" "sethi")) + "i3|i2|i1|i0") + +(define_insn_reservation "fr550_setlo" 1 + (and (eq_attr "cpu" "fr550") + (eq_attr "type" "setlo")) + "i3|i2|i1|i0") + +(define_insn_reservation "fr550_int" 1 + (and (eq_attr "cpu" "fr550") + (eq_attr "type" "int")) + "i3|i2|i1|i0") + +(define_insn_reservation "fr550_mul" 2 + (and (eq_attr "cpu" "fr550") + (eq_attr "type" "mul")) + "i1|i0") + +(define_insn_reservation "fr550_div" 19 + (and (eq_attr "cpu" "fr550") + (eq_attr "type" "div")) + "(i1|i0),(idiv1*18 | idiv2*18)") + +(define_insn_reservation "fr550_load" 3 + (and (eq_attr "cpu" "fr550") + (eq_attr "type" "gload,fload")) + "(i1|i0)+(fr550_load0|fr550_load1)") + +;; We can only issue a store to I1 if one was also issued to I0. +;; This means that, as far as frv_reorder_packet is concerned, +;; the instruction has the same priority as an I0-only instruction. +(define_insn_reservation "fr550_store" 1 + (and (eq_attr "cpu" "fr550") + (eq_attr "type" "gstore,fstore")) + "(i0+fr550_store0)|(i1+fr550_store1)") + +(define_insn_reservation "fr550_transfer" 2 + (and (eq_attr "cpu" "fr550") + (eq_attr "type" "movgf,movfg")) + "i0") + +(define_insn_reservation "fr550_jumpl" 0 + (and (eq_attr "cpu" "fr550") + (eq_attr "type" "jumpl")) + "i0") + +(define_cpu_unit "fr550_ccr0,fr550_ccr1" "float_media") + +(define_insn_reservation "fr550_branch" 0 + (and (eq_attr "cpu" "fr550") + (eq_attr "type" "jump,branch")) + "b1|b0") + +(define_insn_reservation "fr550_ccr" 0 + (and (eq_attr "cpu" "fr550") + (eq_attr "type" "ccr")) + "(b1|b0) + (fr550_ccr1|fr550_ccr0)") + +(define_insn_reservation "fr550_call" 0 + (and (eq_attr "cpu" "fr550") + (eq_attr "type" "call")) + "b0") + +(define_automaton "fr550_float_media") +(define_cpu_unit "fr550_add0,fr550_add1" "fr550_float_media") + +;; There are three possible combinations of floating-point/media instructions: +;; +;; - one media and one float +;; - up to four float, no media +;; - up to four media, no float +(define_cpu_unit "fr550_f0,fr550_f1,fr550_f2,fr550_f3" "fr550_float_media") +(define_cpu_unit "fr550_m0,fr550_m1,fr550_m2,fr550_m3" "fr550_float_media") +(exclusion_set "fr550_f1,fr550_f2,fr550_f3" "fr550_m1,fr550_m2,fr550_m3") +(exclusion_set "fr550_m0" "fr550_f1,fr550_f2,fr550_f3") +;; FIXME: This next exclusion set should be defined as well, so that we do +;; not get a packet containing multiple media instructions plus a single +;; floating point instruction. At the moment we can get away with not +;; defining it because gcc does not seem to generate such packets. +;; +;; If we do enable the exclusion however the insertion of fnop insns into +;; a packet containing media instructions will stop working, because the +;; fnop insn counts as a floating point instruction. The correct solution +;; is to fix the reservation for the fnop insn so that it does not have the +;; same restrictions as ordinary floating point insns. +;;(exclusion_set "fr550_f0" "fr550_m1,fr550_m2,fr550_m3") + +(define_reservation "fr550_float" "fr550_f0|fr550_f1|fr550_f2|fr550_f3") +(define_reservation "fr550_media" "fr550_m0|fr550_m1|fr550_m2|fr550_m3") + +(define_insn_reservation "fr550_f1" 0 + (and (eq_attr "cpu" "fr550") + (eq_attr "type" "fnop")) + "(f3|f2|f1|f0) + fr550_float") + +(define_insn_reservation "fr550_f2" 3 + (and (eq_attr "cpu" "fr550") + (eq_attr "type" "fsconv,fsadd,fscmp")) + "(f3|f2|f1|f0) + (fr550_add0|fr550_add1) + fr550_float") + +(define_insn_reservation "fr550_f3_mul" 3 + (and (eq_attr "cpu" "fr550") + (eq_attr "type" "fsmul")) + "(f1|f0) + fr550_float") + +(define_insn_reservation "fr550_f3_div" 10 + (and (eq_attr "cpu" "fr550") + (eq_attr "type" "fsdiv")) + "(f1|f0) + fr550_float") + +(define_insn_reservation "fr550_f3_sqrt" 15 + (and (eq_attr "cpu" "fr550") + (eq_attr "type" "sqrt_single")) + "(f1|f0) + fr550_float") + +;; Synthetic units for enforcing media issue restrictions. Certain types +;; of insn in M2 conflict with certain types in M0: +;; +;; M2 +;; MNOP MALU MSFT MMAC MSET +;; MNOP - - x - - +;; MALU - x x - - +;; M0 MSFT - - x - x +;; MMAC - - x x - +;; MSET - - x - - +;; +;; where "x" indicates a conflict. The same restrictions apply to +;; M3 and M1. +;; +;; In addition -- and this is the awkward bit! -- instructions that +;; access ACC0-3 can only issue to M0 or M2. Those that access ACC4-7 +;; can only issue to M1 or M3. We refer to such instructions as "even" +;; and "odd" respectively. +(define_cpu_unit "fr550_malu0,fr550_malu1" "float_media") +(define_cpu_unit "fr550_malu2,fr550_malu3" "float_media") +(define_cpu_unit "fr550_msft0,fr550_msft1" "float_media") +(define_cpu_unit "fr550_mmac0,fr550_mmac1" "float_media") +(define_cpu_unit "fr550_mmac2,fr550_mmac3" "float_media") +(define_cpu_unit "fr550_mset0,fr550_mset1" "float_media") +(define_cpu_unit "fr550_mset2,fr550_mset3" "float_media") + +(exclusion_set "fr550_malu0" "fr550_malu2") +(exclusion_set "fr550_malu1" "fr550_malu3") + +(exclusion_set "fr550_msft0" "fr550_mset2") +(exclusion_set "fr550_msft1" "fr550_mset3") + +(exclusion_set "fr550_mmac0" "fr550_mmac2") +(exclusion_set "fr550_mmac1" "fr550_mmac3") + +;; If an MSFT or MMAC instruction issues to a unit other than M0, we may +;; need to insert some nops. In the worst case, the packet will end up +;; having 4 integer instructions and 4 media instructions, leaving no +;; room for any branch instructions that the DFA might have accepted. +;; +;; This doesn't matter for JUMP_INSNs and CALL_INSNs because they are +;; always the last instructions to be passed to the DFA, and could be +;; pushed out to a separate packet once the nops have been added. +;; However, it does cause problems for ccr instructions since they +;; can occur anywhere in the unordered packet. +(exclusion_set "fr550_msft1,fr550_mmac1,fr550_mmac2,fr550_mmac3" + "fr550_ccr0,fr550_ccr1") + +(define_reservation "fr550_malu" + "(f3 + fr550_malu3) | (f2 + fr550_malu2) + | (f1 + fr550_malu1) | (f0 + fr550_malu0)") + +(define_reservation "fr550_msft_even" + "f0 + fr550_msft0") + +(define_reservation "fr550_msft_odd" + "f1 + fr550_msft1") + +(define_reservation "fr550_msft_either" + "(f1 + fr550_msft1) | (f0 + fr550_msft0)") + +(define_reservation "fr550_mmac_even" + "(f2 + fr550_mmac2) | (f0 + fr550_mmac0)") + +(define_reservation "fr550_mmac_odd" + "(f3 + fr550_mmac3) | (f1 + fr550_mmac1)") + +(define_reservation "fr550_mset" + "(f3 + fr550_mset3) | (f2 + fr550_mset2) + | (f1 + fr550_mset1) | (f0 + fr550_mset0)") + +(define_insn_reservation "fr550_mnop" 0 + (and (eq_attr "cpu" "fr550") + (eq_attr "type" "mnop")) + "fr550_media + (f3|f2|f1|f0)") + +(define_insn_reservation "fr550_malu" 2 + (and (eq_attr "cpu" "fr550") + (eq_attr "type" "mlogic,maveh,msath,mabsh,maddh,mqaddh,mqsath")) + "fr550_media + fr550_malu") + +;; These insns only operate on FPRs and so don't need to be classified +;; as even/odd. +(define_insn_reservation "fr550_msft_1_either" 2 + (and (eq_attr "cpu" "fr550") + (eq_attr "type" "mrot,mwcut,mshift,mexpdhw,mexpdhd,mpackh, + munpackh,mdpackh,mbhconv,mdrot,mcpl")) + "fr550_media + fr550_msft_either") + +;; These insns read from ACC0-3. +(define_insn_reservation "fr550_msft_1_even" 2 + (and (eq_attr "cpu" "fr550") + (and (eq_attr "type" "mcut,mrdacc,mdcut") + (eq_attr "acc_group" "even"))) + "fr550_media + fr550_msft_even") + +;; These insns read from ACC4-7. +(define_insn_reservation "fr550_msft_1_odd" 2 + (and (eq_attr "cpu" "fr550") + (and (eq_attr "type" "mcut,mrdacc,mdcut") + (eq_attr "acc_group" "odd"))) + "fr550_media + fr550_msft_odd") + +;; MCLRACC with A=1 can issue to either M0 or M1. +(define_insn_reservation "fr550_msft_2_either" 2 + (and (eq_attr "cpu" "fr550") + (eq_attr "type" "mclracca")) + "fr550_media + fr550_msft_either") + +;; These insns write to ACC0-3. +(define_insn_reservation "fr550_msft_2_even" 2 + (and (eq_attr "cpu" "fr550") + (and (eq_attr "type" "mclracc,mwtacc") + (eq_attr "acc_group" "even"))) + "fr550_media + fr550_msft_even") + +;; These insns write to ACC4-7. +(define_insn_reservation "fr550_msft_2_odd" 2 + (and (eq_attr "cpu" "fr550") + (and (eq_attr "type" "mclracc,mwtacc") + (eq_attr "acc_group" "odd"))) + "fr550_media + fr550_msft_odd") + +;; These insns read from and write to ACC0-3. +(define_insn_reservation "fr550_mmac_even" 2 + (and (eq_attr "cpu" "fr550") + (and (eq_attr "type" "mmulh,mmulxh,mmach,mmrdh,mqmulh,mqmulxh,mqmach, + maddacc,mdaddacc,mcpx,mqcpx") + (eq_attr "acc_group" "even"))) + "fr550_media + fr550_mmac_even") + +;; These insns read from and write to ACC4-7. +(define_insn_reservation "fr550_mmac_odd" 2 + (and (eq_attr "cpu" "fr550") + (and (eq_attr "type" "mmulh,mmulxh,mmach,mmrdh,mqmulh,mqmulxh,mqmach, + maddacc,mdaddacc,mcpx,mqcpx") + (eq_attr "acc_group" "odd"))) + "fr550_media + fr550_mmac_odd") + +(define_insn_reservation "fr550_mset" 1 + (and (eq_attr "cpu" "fr550") + (eq_attr "type" "mset")) + "fr550_media + fr550_mset") + +;; :::::::::::::::::::: +;; :: +;; :: Simple/FR300 scheduler description +;; :: +;; :::::::::::::::::::: + +;; Fr300 or simple processor. To describe it as 1 insn issue +;; processor, we use control unit. + +(define_insn_reservation "fr300_lat1" 1 + (and (eq_attr "cpu" "fr300,simple") + (eq_attr "type" "!gload,fload,movfg,movgf")) + "c + control") + +(define_insn_reservation "fr300_lat2" 2 + (and (eq_attr "cpu" "fr300,simple") + (eq_attr "type" "gload,fload,movfg,movgf")) + "c + control") + + +;; :::::::::::::::::::: +;; :: +;; :: 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)]) + +;; Note - it is the backend's responsibility to fill any unfilled delay slots +;; at assembler generation time. This is usually done by adding a special print +;; operand to the delayed instruction, and then in the PRINT_OPERAND function +;; calling dbr_sequence_length() to determine how many delay slots were filled. +;; For example: +;; +;; --------------.md----------------- +;; (define_insn "call" +;; [(call (match_operand 0 "memory_operand" "m") +;; (match_operand 1 "" ""))] +;; "" +;; "call_delayed %0,%1,%2%#" +;; [(set_attr "length" "4") +;; (set_attr "type" "call")]) +;; +;; -------------.h------------------- +;; #define PRINT_OPERAND_PUNCT_VALID_P(CODE) (CODE == '#') +;; +;; ------------.c------------------ +;; void +;; machine_print_operand (file, x, code) +;; FILE * file; +;; rtx x; +;; int code; +;; { +;; switch (code) +;; { +;; case '#': +;; if (dbr_sequence_length () == 0) +;; fputs ("\n\tnop", file); +;; return; + +;; :::::::::::::::::::: +;; :: +;; :: Notes on Patterns +;; :: +;; :::::::::::::::::::: + +;; If you need to construct a sequence of assembler instructions in order +;; to implement a pattern be sure to escape any backslashes and double quotes +;; that you use, e.g.: +;; +;; (define_insn "an example" +;; [(some rtl)] +;; "" +;; "* +;; { static char buffer [100]; +;; sprintf (buffer, \"insn \\t %d\", REGNO (operands[1])); +;; return buffer; +;; }" +;; ) +;; +;; Also if there is more than one instruction, they can be separated by \\; +;; which is a space saving synonym for \\n\\t: +;; +;; (define_insn "another example" +;; [(some rtl)] +;; "" +;; "* +;; { static char buffer [100]; +;; sprintf (buffer, \"insn1 \\t %d\\;insn2 \\t %%1\", +;; REGNO (operands[1])); +;; return buffer; +;; }" +;; ) +;; + +(include "predicates.md") + +;; :::::::::::::::::::: +;; :: +;; :: 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. + +;; 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" ""))] + "" + "{ frv_emit_move (QImode, operands[0], operands[1]); DONE; }") + +(define_insn "*movqi_load" + [(set (match_operand:QI 0 "register_operand" "=d,f") + (match_operand:QI 1 "frv_load_operand" "m,m"))] + "" + "* return output_move_single (operands, insn);" + [(set_attr "length" "4") + (set_attr "type" "gload,fload")]) + +(define_insn "*movqi_internal" + [(set (match_operand:QI 0 "move_destination_operand" "=d,d,m,m,?f,?f,?d,?m,f,d,f") + (match_operand:QI 1 "move_source_operand" "L,d,d,O, d, f, f, f,GO,!m,!m"))] + "register_operand(operands[0], QImode) || reg_or_0_operand (operands[1], QImode)" + "* return output_move_single (operands, insn);" + [(set_attr "length" "4") + (set_attr "type" "int,int,gstore,gstore,movgf,fsconv,movfg,fstore,movgf,gload,fload")]) + +(define_expand "movhi" + [(set (match_operand:HI 0 "general_operand" "") + (match_operand:HI 1 "general_operand" ""))] + "" + "{ frv_emit_move (HImode, operands[0], operands[1]); DONE; }") + +(define_insn "*movhi_load" + [(set (match_operand:HI 0 "register_operand" "=d,f") + (match_operand:HI 1 "frv_load_operand" "m,m"))] + "" + "* return output_move_single (operands, insn);" + [(set_attr "length" "4") + (set_attr "type" "gload,fload")]) + +(define_insn "*movhi_internal" + [(set (match_operand:HI 0 "move_destination_operand" "=d,d,d,m,m,?f,?f,?d,?m,f,d,f") + (match_operand:HI 1 "move_source_operand" "L,n,d,d,O, d, f, f, f,GO,!m,!m"))] + "register_operand(operands[0], HImode) || reg_or_0_operand (operands[1], HImode)" + "* return output_move_single (operands, insn);" + [(set_attr "length" "4,8,4,4,4,4,4,4,4,4,4,4") + (set_attr "type" "int,multi,int,gstore,gstore,movgf,fsconv,movfg,fstore,movgf,gload,fload")]) + +;; Split 2 word load of constants into sethi/setlo instructions +(define_split + [(set (match_operand:HI 0 "integer_register_operand" "") + (match_operand:HI 1 "int_2word_operand" ""))] + "reload_completed" + [(set (match_dup 0) + (high:HI (match_dup 1))) + (set (match_dup 0) + (lo_sum:HI (match_dup 0) + (match_dup 1)))] + "") + +(define_insn "movhi_high" + [(set (match_operand:HI 0 "integer_register_operand" "=d") + (high:HI (match_operand:HI 1 "int_2word_operand" "i")))] + "" + "sethi #hi(%1), %0" + [(set_attr "type" "sethi") + (set_attr "length" "4")]) + +(define_insn "movhi_lo_sum" + [(set (match_operand:HI 0 "integer_register_operand" "+d") + (lo_sum:HI (match_dup 0) + (match_operand:HI 1 "int_2word_operand" "i")))] + "" + "setlo #lo(%1), %0" + [(set_attr "type" "setlo") + (set_attr "length" "4")]) + +(define_expand "movsi" + [(set (match_operand:SI 0 "move_destination_operand" "") + (match_operand:SI 1 "move_source_operand" ""))] + "" + "{ frv_emit_move (SImode, operands[0], operands[1]); DONE; }") + +;; Note - it is best to only have one movsi pattern and to handle +;; all the various contingencies by the use of alternatives. This +;; allows reload the greatest amount of flexibility (since reload will +;; only choose amongst alternatives for a selected insn, it will not +;; replace the insn with another one). + +;; Unfortunately, we do have to separate out load-type moves from the rest, +;; and only allow memory source operands in the former. If we do memory and +;; constant loads in a single pattern, reload will be tempted to force +;; constants into memory when the destination is a floating-point register. +;; That may make a function use a PIC pointer when it didn't before, and we +;; cannot change PIC usage (and hence stack layout) so late in the game. +;; The resulting sequences for loading constants into FPRs are preferable +;; even when we're not generating PIC code. + +;; However, if we don't accept input from memory at all in the generic +;; movsi pattern, reloads for asm instructions that reference pseudos +;; that end up assigned to memory will fail to match, because we +;; recognize them right after they're emitted, and we don't +;; re-recognize them again after the substitution for memory. So keep +;; a memory constraint available, just make sure reload won't be +;; tempted to use it. +;; + + +(define_insn "*movsi_load" + [(set (match_operand:SI 0 "register_operand" "=d,f") + (match_operand:SI 1 "frv_load_operand" "m,m"))] + "" + "* return output_move_single (operands, insn);" + [(set_attr "length" "4") + (set_attr "type" "gload,fload")]) + +(define_insn "*movsi_got" + [(set (match_operand:SI 0 "integer_register_operand" "=d") + (match_operand:SI 1 "got12_operand" ""))] + "" + "addi gr0, %1, %0" + [(set_attr "type" "int") + (set_attr "length" "4")]) + +(define_insn "*movsi_high_got" + [(set (match_operand:SI 0 "integer_register_operand" "=d") + (high:SI (match_operand:SI 1 "const_unspec_operand" "")))] + "" + "sethi %1, %0" + [(set_attr "type" "sethi") + (set_attr "length" "4")]) + +(define_insn "*movsi_lo_sum_got" + [(set (match_operand:SI 0 "integer_register_operand" "=d") + (lo_sum:SI (match_operand:SI 1 "integer_register_operand" "0") + (match_operand:SI 2 "const_unspec_operand" "")))] + "" + "setlo %2, %0" + [(set_attr "type" "setlo") + (set_attr "length" "4")]) + +(define_insn "*movsi_internal" + [(set (match_operand:SI 0 "move_destination_operand" "=d,d,d,m,m,z,d,d,f,f,m,?f,?z,d,f") + (match_operand:SI 1 "move_source_operand" "L,n,d,d,O,d,z,f,d,f,f,GO,GO,!m,!m"))] + "register_operand (operands[0], SImode) || reg_or_0_operand (operands[1], SImode)" + "* return output_move_single (operands, insn);" + [(set_attr "length" "4,8,4,4,4,4,4,4,4,4,4,4,4,4,4") + (set_attr "type" "int,multi,int,gstore,gstore,spr,spr,movfg,movgf,fsconv,fstore,movgf,spr,gload,fload")]) + +;; Split 2 word load of constants into sethi/setlo instructions +(define_insn_and_split "*movsi_2word" + [(set (match_operand:SI 0 "integer_register_operand" "=d") + (match_operand:SI 1 "int_2word_operand" "i"))] + "" + "#" + "reload_completed" + [(set (match_dup 0) + (high:SI (match_dup 1))) + (set (match_dup 0) + (lo_sum:SI (match_dup 0) + (match_dup 1)))] + "" + [(set_attr "length" "8") + (set_attr "type" "multi")]) + +(define_insn "movsi_high" + [(set (match_operand:SI 0 "integer_register_operand" "=d") + (high:SI (match_operand:SI 1 "int_2word_operand" "i")))] + "" + "sethi #hi(%1), %0" + [(set_attr "type" "sethi") + (set_attr "length" "4")]) + +(define_insn "movsi_lo_sum" + [(set (match_operand:SI 0 "integer_register_operand" "+d") + (lo_sum:SI (match_dup 0) + (match_operand:SI 1 "int_2word_operand" "i")))] + "" + "setlo #lo(%1), %0" + [(set_attr "type" "setlo") + (set_attr "length" "4")]) + +(define_expand "movdi" + [(set (match_operand:DI 0 "nonimmediate_operand" "") + (match_operand:DI 1 "general_operand" ""))] + "" + "{ frv_emit_move (DImode, operands[0], operands[1]); DONE; }") + +(define_insn "*movdi_double" + [(set (match_operand:DI 0 "move_destination_operand" "=e,?h,??d,??f,R,?R,??m,??m,e,?h,??d,??f,?e,??d,?h,??f,R,m,e,??d,e,??d,?h,??f") + (match_operand:DI 1 "move_source_operand" " e,h,d,f,e,h,d,f,R,R,m,m,h,f,e,d,GO,GO,GO,GO,nF,nF,GO,GO"))] + "TARGET_DOUBLE + && (register_operand (operands[0], DImode) + || reg_or_0_operand (operands[1], DImode))" + "* return output_move_double (operands, insn);" + [(set_attr "length" "8,4,8,8,4,4,8,8,4,4,8,8,4,8,4,8,4,8,8,8,16,16,8,8") + (set_attr "type" "multi,fdconv,multi,multi,gstore,fstore,gstore,fstore,gload,fload,gload,fload,movfg,movfg,movgf,movgf,gstore,gstore,multi,multi,multi,multi,movgf,movgf")]) + +(define_insn "*movdi_nodouble" + [(set (match_operand:DI 0 "move_destination_operand" "=e,?h,??d,??f,R,?R,??m,??m,e,?h,??d,??f,?e,??d,?h,??f,R,m,e,??d,e,??d,?h,??f") + (match_operand:DI 1 "move_source_operand" " e,h,d,f,e,h,d,f,R,R,m,m,h,f,e,d,GO,GO,GO,GO,nF,nF,GO,GO"))] + "!TARGET_DOUBLE + && (register_operand (operands[0], DImode) + || reg_or_0_operand (operands[1], DImode))" + "* return output_move_double (operands, insn);" + [(set_attr "length" "8,8,8,8,4,4,8,8,4,4,8,8,8,8,8,8,4,8,8,8,16,16,8,8") + (set_attr "type" "multi,multi,multi,multi,gstore,fstore,gstore,fstore,gload,fload,gload,fload,movfg,movfg,movgf,movgf,gstore,gstore,multi,multi,multi,multi,movgf,movgf")]) + +(define_split + [(set (match_operand:DI 0 "register_operand" "") + (match_operand:DI 1 "dbl_memory_two_insn_operand" ""))] + "reload_completed" + [(const_int 0)] + "frv_split_double_load (operands[0], operands[1]);") + +(define_split + [(set (match_operand:DI 0 "odd_reg_operand" "") + (match_operand:DI 1 "memory_operand" ""))] + "reload_completed" + [(const_int 0)] + "frv_split_double_load (operands[0], operands[1]);") + +(define_split + [(set (match_operand:DI 0 "dbl_memory_two_insn_operand" "") + (match_operand:DI 1 "reg_or_0_operand" ""))] + "reload_completed" + [(const_int 0)] + "frv_split_double_store (operands[0], operands[1]);") + +(define_split + [(set (match_operand:DI 0 "memory_operand" "") + (match_operand:DI 1 "odd_reg_operand" ""))] + "reload_completed" + [(const_int 0)] + "frv_split_double_store (operands[0], operands[1]);") + +(define_split + [(set (match_operand:DI 0 "register_operand" "") + (match_operand:DI 1 "register_operand" ""))] + "reload_completed + && (odd_reg_operand (operands[0], DImode) + || odd_reg_operand (operands[1], DImode) + || (integer_register_operand (operands[0], DImode) + && integer_register_operand (operands[1], DImode)) + || (!TARGET_DOUBLE + && fpr_operand (operands[0], DImode) + && fpr_operand (operands[1], DImode)))" + [(set (match_dup 2) (match_dup 4)) + (set (match_dup 3) (match_dup 5))] + " +{ + rtx op0 = operands[0]; + rtx op0_low = gen_lowpart (SImode, op0); + rtx op0_high = gen_highpart (SImode, op0); + rtx op1 = operands[1]; + rtx op1_low = gen_lowpart (SImode, op1); + rtx op1_high = gen_highpart (SImode, op1); + + /* We normally copy the low-numbered register first. However, if the first + register operand 0 is the same as the second register of operand 1, we + must copy in the opposite order. */ + + if (REGNO (op0_high) == REGNO (op1_low)) + { + operands[2] = op0_low; + operands[3] = op0_high; + operands[4] = op1_low; + operands[5] = op1_high; + } + else + { + operands[2] = op0_high; + operands[3] = op0_low; + operands[4] = op1_high; + operands[5] = op1_low; + } +}") + +(define_split + [(set (match_operand:DI 0 "register_operand" "") + (match_operand:DI 1 "const_int_operand" ""))] + "reload_completed" + [(set (match_dup 2) (match_dup 4)) + (set (match_dup 3) (match_dup 5))] + " +{ + rtx op0 = operands[0]; + rtx op1 = operands[1]; + + operands[2] = gen_highpart (SImode, op0); + operands[3] = gen_lowpart (SImode, op0); + if (HOST_BITS_PER_WIDE_INT <= 32) + { + operands[4] = GEN_INT ((INTVAL (op1) < 0) ? -1 : 0); + operands[5] = op1; + } + else + { + operands[4] = GEN_INT ((((unsigned HOST_WIDE_INT)INTVAL (op1) >> 16) + >> 16) ^ ((unsigned HOST_WIDE_INT)1 << 31) + - ((unsigned HOST_WIDE_INT)1 << 31)); + operands[5] = GEN_INT (trunc_int_for_mode (INTVAL (op1), SImode)); + } +}") + +(define_split + [(set (match_operand:DI 0 "register_operand" "") + (match_operand:DI 1 "const_double_operand" ""))] + "reload_completed" + [(set (match_dup 2) (match_dup 4)) + (set (match_dup 3) (match_dup 5))] + " +{ + rtx op0 = operands[0]; + rtx op1 = operands[1]; + + operands[2] = gen_highpart (SImode, op0); + operands[3] = gen_lowpart (SImode, op0); + operands[4] = GEN_INT (CONST_DOUBLE_HIGH (op1)); + operands[5] = GEN_INT (CONST_DOUBLE_LOW (op1)); +}") + +;; Floating Point Moves +;; +;; Note - Patterns for SF mode moves are compulsory, but +;; patterns for DF are optional, as GCC can synthesize them. + +(define_expand "movsf" + [(set (match_operand:SF 0 "general_operand" "") + (match_operand:SF 1 "general_operand" ""))] + "" + "{ frv_emit_move (SFmode, operands[0], operands[1]); DONE; }") + +(define_split + [(set (match_operand:SF 0 "integer_register_operand" "") + (match_operand:SF 1 "int_2word_operand" ""))] + "reload_completed" + [(set (match_dup 0) + (high:SF (match_dup 1))) + (set (match_dup 0) + (lo_sum:SF (match_dup 0) + (match_dup 1)))] + "") + +(define_insn "*movsf_load_has_fprs" + [(set (match_operand:SF 0 "register_operand" "=f,d") + (match_operand:SF 1 "frv_load_operand" "m,m"))] + "TARGET_HAS_FPRS" + "* return output_move_single (operands, insn);" + [(set_attr "length" "4") + (set_attr "type" "fload,gload")]) + +(define_insn "*movsf_internal_has_fprs" + [(set (match_operand:SF 0 "move_destination_operand" "=f,f,m,m,?f,?d,?d,m,?d") + (match_operand:SF 1 "move_source_operand" "f,OG,f,OG,d,f,d,d,F"))] + "TARGET_HAS_FPRS + && (register_operand (operands[0], SFmode) || reg_or_0_operand (operands[1], SFmode))" + "* return output_move_single (operands, insn);" + [(set_attr "length" "4,4,4,4,4,4,4,4,8") + (set_attr "type" "fsconv,movgf,fstore,gstore,movgf,movfg,int,gstore,multi")]) + +;; If we don't support the double instructions, prefer gprs over fprs, since it +;; will all be emulated +(define_insn "*movsf_internal_no_fprs" + [(set (match_operand:SF 0 "move_destination_operand" "=d,d,m,d,d") + (match_operand:SF 1 "move_source_operand" " d,OG,dOG,m,F"))] + "!TARGET_HAS_FPRS + && (register_operand (operands[0], SFmode) || reg_or_0_operand (operands[1], SFmode))" + "* return output_move_single (operands, insn);" + [(set_attr "length" "4,4,4,4,8") + (set_attr "type" "int,int,gstore,gload,multi")]) + +(define_insn "movsf_high" + [(set (match_operand:SF 0 "integer_register_operand" "=d") + (high:SF (match_operand:SF 1 "int_2word_operand" "i")))] + "" + "sethi #hi(%1), %0" + [(set_attr "type" "sethi") + (set_attr "length" "4")]) + +(define_insn "movsf_lo_sum" + [(set (match_operand:SF 0 "integer_register_operand" "+d") + (lo_sum:SF (match_dup 0) + (match_operand:SF 1 "int_2word_operand" "i")))] + "" + "setlo #lo(%1), %0" + [(set_attr "type" "setlo") + (set_attr "length" "4")]) + +(define_expand "movdf" + [(set (match_operand:DF 0 "nonimmediate_operand" "") + (match_operand:DF 1 "general_operand" ""))] + "" + "{ frv_emit_move (DFmode, operands[0], operands[1]); DONE; }") + +(define_insn "*movdf_double" + [(set (match_operand:DF 0 "move_destination_operand" "=h,?e,??f,??d,R,?R,??m,??m,h,?e,??f,??d,?h,??f,?e,??d,R,m,h,??f,e,??d,e,??d") + (match_operand:DF 1 "move_source_operand" " h,e,f,d,h,e,f,d,R,R,m,m,e,d,h,f,GO,GO,GO,GO,GO,GO,F,F"))] + "TARGET_DOUBLE + && (register_operand (operands[0], DFmode) + || reg_or_0_operand (operands[1], DFmode))" + "* return output_move_double (operands, insn);" + [(set_attr "length" "4,8,8,8,4,4,8,8,4,4,8,8,4,8,4,8,4,8,8,8,8,8,16,16") + (set_attr "type" "fdconv,multi,multi,multi,fstore,gstore,fstore,gstore,fload,gload,fload,gload,movgf,movgf,movfg,movfg,gstore,gstore,movgf,movgf,multi,multi,multi,multi")]) + +;; If we don't support the double instructions, prefer gprs over fprs, since it +;; will all be emulated +(define_insn "*movdf_nodouble" + [(set (match_operand:DF 0 "move_destination_operand" "=e,?h,??d,??f,R,?R,??m,??m,e,?h,??d,??f,?e,??d,?h,??f,R,m,e,??d,e,??d,?h,??f") + (match_operand:DF 1 "move_source_operand" " e,h,d,f,e,h,d,f,R,R,m,m,h,f,e,d,GO,GO,GO,GO,nF,nF,GO,GO"))] + "!TARGET_DOUBLE + && (register_operand (operands[0], DFmode) + || reg_or_0_operand (operands[1], DFmode))" + "* return output_move_double (operands, insn);" + [(set_attr "length" "8,8,8,8,4,4,8,8,4,4,8,8,8,8,8,8,4,8,8,8,16,16,8,8") + (set_attr "type" "multi,multi,multi,multi,gstore,fstore,gstore,fstore,gload,fload,gload,fload,movfg,movfg,movgf,movgf,gstore,gstore,multi,multi,multi,multi,movgf,movgf")]) + +(define_split + [(set (match_operand:DF 0 "register_operand" "") + (match_operand:DF 1 "dbl_memory_two_insn_operand" ""))] + "reload_completed" + [(const_int 0)] + "frv_split_double_load (operands[0], operands[1]);") + +(define_split + [(set (match_operand:DF 0 "odd_reg_operand" "") + (match_operand:DF 1 "memory_operand" ""))] + "reload_completed" + [(const_int 0)] + "frv_split_double_load (operands[0], operands[1]);") + +(define_split + [(set (match_operand:DF 0 "dbl_memory_two_insn_operand" "") + (match_operand:DF 1 "reg_or_0_operand" ""))] + "reload_completed" + [(const_int 0)] + "frv_split_double_store (operands[0], operands[1]);") + +(define_split + [(set (match_operand:DF 0 "memory_operand" "") + (match_operand:DF 1 "odd_reg_operand" ""))] + "reload_completed" + [(const_int 0)] + "frv_split_double_store (operands[0], operands[1]);") + +(define_split + [(set (match_operand:DF 0 "register_operand" "") + (match_operand:DF 1 "register_operand" ""))] + "reload_completed + && (odd_reg_operand (operands[0], DFmode) + || odd_reg_operand (operands[1], DFmode) + || (integer_register_operand (operands[0], DFmode) + && integer_register_operand (operands[1], DFmode)) + || (!TARGET_DOUBLE + && fpr_operand (operands[0], DFmode) + && fpr_operand (operands[1], DFmode)))" + [(set (match_dup 2) (match_dup 4)) + (set (match_dup 3) (match_dup 5))] + " +{ + rtx op0 = operands[0]; + rtx op0_low = gen_lowpart (SImode, op0); + rtx op0_high = gen_highpart (SImode, op0); + rtx op1 = operands[1]; + rtx op1_low = gen_lowpart (SImode, op1); + rtx op1_high = gen_highpart (SImode, op1); + + /* We normally copy the low-numbered register first. However, if the first + register operand 0 is the same as the second register of operand 1, we + must copy in the opposite order. */ + + if (REGNO (op0_high) == REGNO (op1_low)) + { + operands[2] = op0_low; + operands[3] = op0_high; + operands[4] = op1_low; + operands[5] = op1_high; + } + else + { + operands[2] = op0_high; + operands[3] = op0_low; + operands[4] = op1_high; + operands[5] = op1_low; + } +}") + +(define_split + [(set (match_operand:DF 0 "register_operand" "") + (match_operand:DF 1 "const_int_operand" ""))] + "reload_completed" + [(set (match_dup 2) (match_dup 4)) + (set (match_dup 3) (match_dup 5))] + " +{ + rtx op0 = operands[0]; + rtx op1 = operands[1]; + + operands[2] = gen_highpart (SImode, op0); + operands[3] = gen_lowpart (SImode, op0); + if (HOST_BITS_PER_WIDE_INT <= 32) + { + operands[4] = GEN_INT ((INTVAL (op1) < 0) ? -1 : 0); + operands[5] = op1; + } + else + { + operands[4] = GEN_INT (((((unsigned HOST_WIDE_INT)INTVAL (op1) >> 16) + >> 16) ^ ((unsigned HOST_WIDE_INT)1 << 31)) + - ((unsigned HOST_WIDE_INT)1 << 31)); + operands[5] = GEN_INT (trunc_int_for_mode (INTVAL (op1), SImode)); + } +}") + +(define_split + [(set (match_operand:DF 0 "register_operand" "") + (match_operand:DF 1 "const_double_operand" ""))] + "reload_completed" + [(set (match_dup 2) (match_dup 4)) + (set (match_dup 3) (match_dup 5))] + " +{ + rtx op0 = operands[0]; + rtx op1 = operands[1]; + REAL_VALUE_TYPE rv; + long l[2]; + + REAL_VALUE_FROM_CONST_DOUBLE (rv, op1); + REAL_VALUE_TO_TARGET_DOUBLE (rv, l); + + operands[2] = gen_highpart (SImode, op0); + operands[3] = gen_lowpart (SImode, op0); + operands[4] = GEN_INT (l[0]); + operands[5] = GEN_INT (l[1]); +}") + +;; String/block move insn. +;; Argument 0 is the destination +;; Argument 1 is the source +;; Argument 2 is the length +;; Argument 3 is the alignment + +(define_expand "movmemsi" + [(parallel [(set (match_operand:BLK 0 "" "") + (match_operand:BLK 1 "" "")) + (use (match_operand:SI 2 "" "")) + (use (match_operand:SI 3 "" ""))])] + "" + " +{ + if (frv_expand_block_move (operands)) + DONE; + else + FAIL; +}") + +;; String/block set insn. +;; Argument 0 is the destination +;; Argument 1 is the length +;; Argument 2 is the byte value -- ignore any value but zero +;; Argument 3 is the alignment + +(define_expand "setmemsi" + [(parallel [(set (match_operand:BLK 0 "" "") + (match_operand 2 "" "")) + (use (match_operand:SI 1 "" "")) + (use (match_operand:SI 3 "" ""))])] + "" + " +{ + /* If value to set is not zero, use the library routine. */ + if (operands[2] != const0_rtx) + FAIL; + + if (frv_expand_block_clear (operands)) + DONE; + else + FAIL; +}") + + +;; The "membar" part of a __builtin_read* or __builtin_write* function. +;; Operand 0 is a volatile reference to the memory that the function reads +;; or writes. Operand 1 is the address being accessed, or zero if the +;; address isn't a known constant. Operand 2 describes the __builtin +;; function (either FRV_IO_READ or FRV_IO_WRITE). +(define_insn "optional_membar_" + [(set (match_operand:IMODE 0 "memory_operand" "=m") + (unspec:IMODE [(match_operand 1 "const_int_operand" "") + (match_operand 2 "const_int_operand" "")] + UNSPEC_OPTIONAL_MEMBAR))] + "" + "membar" + [(set_attr "length" "4")]) + +;; :::::::::::::::::::: +;; :: +;; :: Reload CC registers +;; :: +;; :::::::::::::::::::: + +;; Use as a define_expand so that cse/gcse/combine can't accidentally +;; create movcc insns. + +(define_expand "movcc" + [(parallel [(set (match_operand:CC 0 "move_destination_operand" "") + (match_operand:CC 1 "move_source_operand" "")) + (clobber (match_dup 2))])] + "" + " +{ + if (! reload_in_progress && ! reload_completed) + FAIL; + + operands[2] = gen_rtx_REG (CC_CCRmode, ICR_TEMP); +}") + +(define_insn "*internal_movcc" + [(set (match_operand:CC 0 "move_destination_operand" "=t,d,d,m,d") + (match_operand:CC 1 "move_source_operand" "d,d,m,d,t")) + (clobber (match_scratch:CC_CCR 2 "=X,X,X,X,&v"))] + "reload_in_progress || reload_completed" + "@ + cmpi %1, #0, %0 + mov %1, %0 + ld%I1%U1 %M1, %0 + st%I0%U0 %1, %M0 + #" + [(set_attr "length" "4,4,4,4,20") + (set_attr "type" "int,int,gload,gstore,multi")]) + +;; To move an ICC value to a GPR for a signed comparison, we create a value +;; that when compared to 0, sets the N and Z flags appropriately (we don't care +;; about the V and C flags, since these comparisons are signed). + +(define_split + [(set (match_operand:CC 0 "integer_register_operand" "") + (match_operand:CC 1 "icc_operand" "")) + (clobber (match_operand:CC_CCR 2 "icr_operand" ""))] + "reload_in_progress || reload_completed" + [(match_dup 3)] + " +{ + rtx dest = simplify_gen_subreg (SImode, operands[0], CCmode, 0); + rtx icc = operands[1]; + rtx icr = operands[2]; + + start_sequence (); + + emit_insn (gen_rtx_SET (VOIDmode, icr, + gen_rtx_LT (CC_CCRmode, icc, const0_rtx))); + + emit_insn (gen_movsi (dest, const1_rtx)); + + emit_insn (gen_rtx_COND_EXEC (VOIDmode, + gen_rtx_NE (CC_CCRmode, icr, const0_rtx), + gen_rtx_SET (VOIDmode, dest, + gen_rtx_NEG (SImode, dest)))); + + emit_insn (gen_rtx_SET (VOIDmode, icr, + gen_rtx_EQ (CC_CCRmode, icc, const0_rtx))); + + emit_insn (gen_rtx_COND_EXEC (VOIDmode, + gen_rtx_NE (CC_CCRmode, icr, const0_rtx), + gen_rtx_SET (VOIDmode, dest, const0_rtx))); + + operands[3] = get_insns (); + end_sequence (); +}") + +;; Reload CC_UNSmode for unsigned integer comparisons +;; Use define_expand so that cse/gcse/combine can't create movcc_uns insns + +(define_expand "movcc_uns" + [(parallel [(set (match_operand:CC_UNS 0 "move_destination_operand" "") + (match_operand:CC_UNS 1 "move_source_operand" "")) + (clobber (match_dup 2))])] + "" + " +{ + if (! reload_in_progress && ! reload_completed) + FAIL; + operands[2] = gen_rtx_REG (CC_CCRmode, ICR_TEMP); +}") + +(define_insn "*internal_movcc_uns" + [(set (match_operand:CC_UNS 0 "move_destination_operand" "=t,d,d,m,d") + (match_operand:CC_UNS 1 "move_source_operand" "d,d,m,d,t")) + (clobber (match_scratch:CC_CCR 2 "=X,X,X,X,&v"))] + "reload_in_progress || reload_completed" + "@ + cmpi %1, #1, %0 + mov %1, %0 + ld%I1%U1 %M1, %0 + st%I0%U0 %1, %M0 + #" + [(set_attr "length" "4,4,4,4,20") + (set_attr "type" "int,int,gload,gstore,multi")]) + +;; To move an ICC value to a GPR for an unsigned comparison, we create a value +;; that when compared to 1, sets the Z, V, and C flags appropriately (we don't +;; care about the N flag, since these comparisons are unsigned). + +(define_split + [(set (match_operand:CC_UNS 0 "integer_register_operand" "") + (match_operand:CC_UNS 1 "icc_operand" "")) + (clobber (match_operand:CC_CCR 2 "icr_operand" ""))] + "reload_in_progress || reload_completed" + [(match_dup 3)] + " +{ + rtx dest = simplify_gen_subreg (SImode, operands[0], CC_UNSmode, 0); + rtx icc = operands[1]; + rtx icr = operands[2]; + + start_sequence (); + + emit_insn (gen_rtx_SET (VOIDmode, icr, + gen_rtx_GTU (CC_CCRmode, icc, const0_rtx))); + + emit_insn (gen_movsi (dest, const1_rtx)); + + emit_insn (gen_rtx_COND_EXEC (VOIDmode, + gen_rtx_NE (CC_CCRmode, icr, const0_rtx), + gen_addsi3 (dest, dest, dest))); + + emit_insn (gen_rtx_SET (VOIDmode, icr, + gen_rtx_LTU (CC_CCRmode, icc, const0_rtx))); + + emit_insn (gen_rtx_COND_EXEC (VOIDmode, + gen_rtx_NE (CC_CCRmode, icr, const0_rtx), + gen_rtx_SET (VOIDmode, dest, const0_rtx))); + + operands[3] = get_insns (); + end_sequence (); +}") + +;; Reload CC_NZmode. This is mostly the same as the CCmode and CC_UNSmode +;; handling, but it uses different sequences for moving between GPRs and ICCs. + +(define_expand "movcc_nz" + [(parallel [(set (match_operand:CC_NZ 0 "move_destination_operand" "") + (match_operand:CC_NZ 1 "move_source_operand" "")) + (clobber (match_dup 2))])] + "" + " +{ + if (!reload_in_progress && !reload_completed) + FAIL; + operands[2] = gen_rtx_REG (CC_CCRmode, ICR_TEMP); +}") + +(define_insn "*internal_movcc_nz" + [(set (match_operand:CC_NZ 0 "move_destination_operand" "=t,d,d,m,d") + (match_operand:CC_NZ 1 "move_source_operand" "d,d,m,d,t")) + (clobber (match_scratch:CC_CCR 2 "=X,X,X,X,&v"))] + "reload_in_progress || reload_completed" + "@ + cmpi %1, #0, %0 + mov %1, %0 + ld%I1%U1 %M1, %0 + st%I0%U0 %1, %M0 + #" + [(set_attr "length" "4,4,4,4,20") + (set_attr "type" "int,int,gload,gstore,multi")]) + +;; Set the destination to a value that, when compared with zero, will +;; restore the value of the Z and N flags. The values of the other +;; flags don't matter. The sequence is: +;; +;; setlos op0,#-1 +;; ckp op1,op2 +;; csub gr0,op0,op0,op2 +;; ckeq op1,op2 +;; cmov gr0,op0,op2 +(define_split + [(set (match_operand:CC_NZ 0 "integer_register_operand" "") + (match_operand:CC_NZ 1 "icc_operand" "")) + (clobber (match_operand:CC_CCR 2 "icr_operand" ""))] + "reload_in_progress || reload_completed" + [(set (match_dup 3) + (const_int -1)) + (set (match_dup 2) + (ge:CC_CCR (match_dup 1) + (const_int 0))) + (cond_exec (ne:CC_CCR (match_dup 2) + (const_int 0)) + (set (match_dup 3) + (neg:SI (match_dup 3)))) + (set (match_dup 2) + (eq:CC_CCR (match_dup 1) + (const_int 0))) + (cond_exec (ne:CC_CCR (match_dup 2) + (const_int 0)) + (set (match_dup 3) (const_int 0)))] + "operands[3] = simplify_gen_subreg (SImode, operands[0], CC_NZmode, 0);") + +;; Reload CC_FPmode for floating point comparisons +;; We use a define_expand here so that cse/gcse/combine can't accidentally +;; create movcc insns. If this was a named define_insn, we would not be able +;; to make it conditional on reload. + +(define_expand "movcc_fp" + [(set (match_operand:CC_FP 0 "movcc_fp_destination_operand" "") + (match_operand:CC_FP 1 "move_source_operand" ""))] + "TARGET_HAS_FPRS" + " +{ + if (! reload_in_progress && ! reload_completed) + FAIL; +}") + +(define_insn "*movcc_fp_internal" + [(set (match_operand:CC_FP 0 "movcc_fp_destination_operand" "=d,d,d,m") + (match_operand:CC_FP 1 "move_source_operand" "u,d,m,d"))] + "TARGET_HAS_FPRS && (reload_in_progress || reload_completed)" + "@ + # + mov %1, %0 + ld%I1%U1 %M1, %0 + st%I0%U0 %1, %M0" + [(set_attr "length" "12,4,4,4") + (set_attr "type" "multi,int,gload,gstore")]) + + +(define_expand "reload_incc_fp" + [(match_operand:CC_FP 0 "fcc_operand" "=u") + (match_operand:CC_FP 1 "gpr_or_memory_operand_with_scratch" "m") + (match_operand:TI 2 "integer_register_operand" "=&d")] + "TARGET_HAS_FPRS" + " +{ + rtx cc_op2 = simplify_gen_subreg (CC_FPmode, operands[2], TImode, 0); + rtx int_op2 = simplify_gen_subreg (SImode, operands[2], TImode, 0); + rtx temp1 = simplify_gen_subreg (SImode, operands[2], TImode, 4); + rtx temp2 = simplify_gen_subreg (SImode, operands[2], TImode, 8); + int shift = CC_SHIFT_RIGHT (REGNO (operands[0])); + HOST_WIDE_INT mask; + + if (!gpr_or_memory_operand (operands[1], CC_FPmode)) + { + rtx addr; + rtx temp3 = simplify_gen_subreg (SImode, operands[2], TImode, 12); + + gcc_assert (GET_CODE (operands[1]) == MEM); + + addr = XEXP (operands[1], 0); + + gcc_assert (GET_CODE (addr) == PLUS); + + emit_move_insn (temp3, XEXP (addr, 1)); + + operands[1] = replace_equiv_address (operands[1], + gen_rtx_PLUS (GET_MODE (addr), + XEXP (addr, 0), + temp3)); + } + + emit_insn (gen_movcc_fp (cc_op2, operands[1])); + if (shift) + emit_insn (gen_ashlsi3 (int_op2, int_op2, GEN_INT (shift))); + + mask = ~ ((HOST_WIDE_INT)CC_MASK << shift); + emit_insn (gen_movsi (temp1, GEN_INT (mask))); + emit_insn (gen_update_fcc (operands[0], int_op2, temp1, temp2)); + DONE; +}") + +(define_expand "reload_outcc_fp" + [(set (match_operand:CC_FP 2 "integer_register_operand" "=&d") + (match_operand:CC_FP 1 "fcc_operand" "u")) + (set (match_operand:CC_FP 0 "memory_operand" "=m") + (match_dup 2))] + "TARGET_HAS_FPRS" + "") + +;; Convert a FCC value to gpr +(define_insn "read_fcc" + [(set (match_operand:SI 0 "integer_register_operand" "=d") + (unspec:SI [(match_operand:CC_FP 1 "fcc_operand" "u")] + UNSPEC_CC_TO_GPR))] + "TARGET_HAS_FPRS" + "movsg ccr, %0" + [(set_attr "type" "spr") + (set_attr "length" "4")]) + +(define_split + [(set (match_operand:CC_FP 0 "integer_register_operand" "") + (match_operand:CC_FP 1 "fcc_operand" ""))] + "reload_completed && TARGET_HAS_FPRS" + [(match_dup 2)] + " +{ + rtx int_op0 = simplify_gen_subreg (SImode, operands[0], CC_FPmode, 0); + int shift = CC_SHIFT_RIGHT (REGNO (operands[1])); + + start_sequence (); + + emit_insn (gen_read_fcc (int_op0, operands[1])); + if (shift) + emit_insn (gen_lshrsi3 (int_op0, int_op0, GEN_INT (shift))); + + emit_insn (gen_andsi3 (int_op0, int_op0, GEN_INT (CC_MASK))); + + operands[2] = get_insns (); + end_sequence (); +}") + +;; Move a gpr value to FCC. +;; Operand0 = FCC +;; Operand1 = reloaded value shifted appropriately +;; Operand2 = mask to eliminate current register +;; Operand3 = temporary to load/store ccr +(define_insn "update_fcc" + [(set (match_operand:CC_FP 0 "fcc_operand" "=u") + (unspec:CC_FP [(match_operand:SI 1 "integer_register_operand" "d") + (match_operand:SI 2 "integer_register_operand" "d")] + UNSPEC_GPR_TO_CC)) + (clobber (match_operand:SI 3 "integer_register_operand" "=&d"))] + "TARGET_HAS_FPRS" + "movsg ccr, %3\;and %2, %3, %3\;or %1, %3, %3\;movgs %3, ccr" + [(set_attr "type" "multi") + (set_attr "length" "16")]) + +;; Reload CC_CCRmode for conditional execution registers +(define_insn "movcc_ccr" + [(set (match_operand:CC_CCR 0 "move_destination_operand" "=d,d,d,m,v,?w,C,d") + (match_operand:CC_CCR 1 "move_source_operand" "C,d,m,d,n,n,C,L"))] + "" + "@ + # + mov %1, %0 + ld%I1%U1 %M1, %0 + st%I0%U0 %1, %M0 + # + # + orcr %1, %1, %0 + setlos #%1, %0" + [(set_attr "length" "8,4,4,4,8,12,4,4") + (set_attr "type" "multi,int,gload,gstore,multi,multi,ccr,int")]) + +(define_expand "reload_incc_ccr" + [(match_operand:CC_CCR 0 "cr_operand" "=C") + (match_operand:CC_CCR 1 "memory_operand" "m") + (match_operand:CC_CCR 2 "integer_register_operand" "=&d")] + "" + " +{ + rtx icc = gen_rtx_REG (CCmode, ICC_TEMP); + rtx int_op2 = simplify_gen_subreg (SImode, operands[2], CC_CCRmode, 0); + rtx icr = (ICR_P (REGNO (operands[0])) + ? operands[0] : gen_rtx_REG (CC_CCRmode, ICR_TEMP)); + + emit_insn (gen_movcc_ccr (operands[2], operands[1])); + emit_insn (gen_cmpsi_cc (icc, int_op2, const0_rtx)); + emit_insn (gen_movcc_ccr (icr, gen_rtx_NE (CC_CCRmode, icc, const0_rtx))); + + if (! ICR_P (REGNO (operands[0]))) + emit_insn (gen_movcc_ccr (operands[0], icr)); + + DONE; +}") + +(define_expand "reload_outcc_ccr" + [(set (match_operand:CC_CCR 2 "integer_register_operand" "=&d") + (match_operand:CC_CCR 1 "cr_operand" "C")) + (set (match_operand:CC_CCR 0 "memory_operand" "=m") + (match_dup 2))] + "" + "") + +(define_split + [(set (match_operand:CC_CCR 0 "integer_register_operand" "") + (match_operand:CC_CCR 1 "cr_operand" ""))] + "reload_completed" + [(match_dup 2)] + " +{ + rtx int_op0 = simplify_gen_subreg (SImode, operands[0], CC_CCRmode, 0); + + start_sequence (); + emit_move_insn (operands[0], const1_rtx); + emit_insn (gen_rtx_COND_EXEC (VOIDmode, + gen_rtx_EQ (CC_CCRmode, + operands[1], + const0_rtx), + gen_rtx_SET (VOIDmode, int_op0, + const0_rtx))); + + operands[2] = get_insns (); + end_sequence (); +}") + +(define_split + [(set (match_operand:CC_CCR 0 "cr_operand" "") + (match_operand:CC_CCR 1 "const_int_operand" ""))] + "reload_completed" + [(match_dup 2)] + " +{ + rtx icc = gen_rtx_REG (CCmode, ICC_TEMP); + rtx r0 = gen_rtx_REG (SImode, GPR_FIRST); + rtx icr = (ICR_P (REGNO (operands[0])) + ? operands[0] : gen_rtx_REG (CC_CCRmode, ICR_TEMP)); + + start_sequence (); + + emit_insn (gen_cmpsi_cc (icc, r0, const0_rtx)); + + emit_insn (gen_movcc_ccr (icr, + gen_rtx_fmt_ee (((INTVAL (operands[1]) == 0) + ? EQ : NE), CC_CCRmode, + r0, const0_rtx))); + + if (! ICR_P (REGNO (operands[0]))) + emit_insn (gen_movcc_ccr (operands[0], icr)); + + operands[2] = get_insns (); + end_sequence (); +}") + + +;; :::::::::::::::::::: +;; :: +;; :: Conversions +;; :: +;; :::::::::::::::::::: + +;; Signed conversions from a smaller integer to a larger integer +;; +;; These operations are optional. If they are not +;; present GCC will synthesize them for itself +;; Even though frv does not provide these instructions, we define them +;; to allow load + sign extend to be collapsed together +(define_insn "extendqihi2" + [(set (match_operand:HI 0 "integer_register_operand" "=d,d") + (sign_extend:HI (match_operand:QI 1 "gpr_or_memory_operand" "d,m")))] + "" + "@ + # + ldsb%I1%U1 %M1,%0" + [(set_attr "length" "8,4") + (set_attr "type" "multi,gload")]) + +(define_split + [(set (match_operand:HI 0 "integer_register_operand" "") + (sign_extend:HI (match_operand:QI 1 "integer_register_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_INT (24); + + operands[2] = gen_ashlsi3 (op0, op1, shift); + operands[3] = gen_ashrsi3 (op0, op0, shift); +}") + +(define_insn "extendqisi2" + [(set (match_operand:SI 0 "integer_register_operand" "=d,d") + (sign_extend:SI (match_operand:QI 1 "gpr_or_memory_operand" "d,m")))] + "" + "@ + # + ldsb%I1%U1 %M1,%0" + [(set_attr "length" "8,4") + (set_attr "type" "multi,gload")]) + +(define_split + [(set (match_operand:SI 0 "integer_register_operand" "") + (sign_extend:SI (match_operand:QI 1 "integer_register_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_INT (24); + + operands[2] = gen_ashlsi3 (op0, op1, shift); + operands[3] = gen_ashrsi3 (op0, op0, shift); +}") + +;;(define_insn "extendqidi2" +;; [(set (match_operand:DI 0 "register_operand" "=r") +;; (sign_extend:DI (match_operand:QI 1 "general_operand" "g")))] +;; "" +;; "extendqihi2 %0,%1" +;; [(set_attr "length" "4")]) + +(define_insn "extendhisi2" + [(set (match_operand:SI 0 "integer_register_operand" "=d,d") + (sign_extend:SI (match_operand:HI 1 "gpr_or_memory_operand" "d,m")))] + "" + "@ + # + ldsh%I1%U1 %M1,%0" + [(set_attr "length" "8,4") + (set_attr "type" "multi,gload")]) + +(define_split + [(set (match_operand:SI 0 "integer_register_operand" "") + (sign_extend:SI (match_operand:HI 1 "integer_register_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_INT (16); + + operands[2] = gen_ashlsi3 (op0, op1, shift); + operands[3] = gen_ashrsi3 (op0, op0, shift); +}") + +;;(define_insn "extendhidi2" +;; [(set (match_operand:DI 0 "register_operand" "=r") +;; (sign_extend:DI (match_operand:HI 1 "general_operand" "g")))] +;; "" +;; "extendhihi2 %0,%1" +;; [(set_attr "length" "4")]) +;; +;;(define_insn "extendsidi2" +;; [(set (match_operand:DI 0 "register_operand" "=r") +;; (sign_extend:DI (match_operand:SI 1 "general_operand" "g")))] +;; "" +;; "extendsidi2 %0,%1" +;; [(set_attr "length" "4")]) + +;; Unsigned conversions from a smaller integer to a larger integer +(define_insn "zero_extendqihi2" + [(set (match_operand:HI 0 "integer_register_operand" "=d,d,d") + (zero_extend:HI + (match_operand:QI 1 "gpr_or_memory_operand" "d,L,m")))] + "" + "@ + andi %1,#0xff,%0 + setlos %1,%0 + ldub%I1%U1 %M1,%0" + [(set_attr "length" "4") + (set_attr "type" "int,int,gload")]) + +(define_insn "zero_extendqisi2" + [(set (match_operand:SI 0 "integer_register_operand" "=d,d,d") + (zero_extend:SI + (match_operand:QI 1 "gpr_or_memory_operand" "d,L,m")))] + "" + "@ + andi %1,#0xff,%0 + setlos %1,%0 + ldub%I1%U1 %M1,%0" + [(set_attr "length" "4") + (set_attr "type" "int,int,gload")]) + +;;(define_insn "zero_extendqidi2" +;; [(set (match_operand:DI 0 "register_operand" "=r") +;; (zero_extend:DI (match_operand:QI 1 "general_operand" "g")))] +;; "" +;; "zero_extendqihi2 %0,%1" +;; [(set_attr "length" "4")]) + +;; Do not set the type for the sethi to "sethi", since the scheduler will think +;; the sethi takes 0 cycles as part of allowing sethi/setlo to be in the same +;; VLIW instruction. +(define_insn "zero_extendhisi2" + [(set (match_operand:SI 0 "integer_register_operand" "=d,d") + (zero_extend:SI (match_operand:HI 1 "gpr_or_memory_operand" "0,m")))] + "" + "@ + sethi #hi(#0),%0 + lduh%I1%U1 %M1,%0" + [(set_attr "length" "4") + (set_attr "type" "int,gload")]) + +;;(define_insn "zero_extendhidi2" +;; [(set (match_operand:DI 0 "register_operand" "=r") +;; (zero_extend:DI (match_operand:HI 1 "general_operand" "g")))] +;; "" +;; "zero_extendhihi2 %0,%1" +;; [(set_attr "length" "4")]) +;; +;;(define_insn "zero_extendsidi2" +;; [(set (match_operand:DI 0 "register_operand" "=r") +;; (zero_extend:DI (match_operand:SI 1 "general_operand" "g")))] +;; "" +;; "zero_extendsidi2 %0,%1" +;; [(set_attr "length" "4")]) +;; +;;;; Convert between floating point types of different sizes. +;; +;;(define_insn "extendsfdf2" +;; [(set (match_operand:DF 0 "register_operand" "=r") +;; (float_extend:DF (match_operand:SF 1 "register_operand" "r")))] +;; "" +;; "extendsfdf2 %0,%1" +;; [(set_attr "length" "4")]) +;; +;;(define_insn "truncdfsf2" +;; [(set (match_operand:SF 0 "register_operand" "=r") +;; (float_truncate:SF (match_operand:DF 1 "register_operand" "r")))] +;; "" +;; "truncdfsf2 %0,%1" +;; [(set_attr "length" "4")]) + +;;;; Convert between signed integer types and floating point. +(define_insn "floatsisf2" + [(set (match_operand:SF 0 "fpr_operand" "=f") + (float:SF (match_operand:SI 1 "fpr_operand" "f")))] + "TARGET_HARD_FLOAT" + "fitos %1,%0" + [(set_attr "length" "4") + (set_attr "type" "fsconv")]) + +(define_insn "floatsidf2" + [(set (match_operand:DF 0 "fpr_operand" "=h") + (float:DF (match_operand:SI 1 "fpr_operand" "f")))] + "TARGET_HARD_FLOAT && TARGET_DOUBLE" + "fitod %1,%0" + [(set_attr "length" "4") + (set_attr "type" "fdconv")]) + +;;(define_insn "floatdisf2" +;; [(set (match_operand:SF 0 "register_operand" "=r") +;; (float:SF (match_operand:DI 1 "register_operand" "r")))] +;; "" +;; "floatdisf2 %0,%1" +;; [(set_attr "length" "4")]) +;; +;;(define_insn "floatdidf2" +;; [(set (match_operand:DF 0 "register_operand" "=r") +;; (float:DF (match_operand:DI 1 "register_operand" "r")))] +;; "" +;; "floatdidf2 %0,%1" +;; [(set_attr "length" "4")]) + +(define_insn "fix_truncsfsi2" + [(set (match_operand:SI 0 "fpr_operand" "=f") + (fix:SI (match_operand:SF 1 "fpr_operand" "f")))] + "TARGET_HARD_FLOAT" + "fstoi %1,%0" + [(set_attr "length" "4") + (set_attr "type" "fsconv")]) + +(define_insn "fix_truncdfsi2" + [(set (match_operand:SI 0 "fpr_operand" "=f") + (fix:SI (match_operand:DF 1 "fpr_operand" "h")))] + "TARGET_HARD_FLOAT && TARGET_DOUBLE" + "fdtoi %1,%0" + [(set_attr "length" "4") + (set_attr "type" "fdconv")]) + +;;(define_insn "fix_truncsfdi2" +;; [(set (match_operand:DI 0 "register_operand" "=r") +;; (fix:DI (match_operand:SF 1 "register_operand" "r")))] +;; "" +;; "fix_truncsfdi2 %0,%1" +;; [(set_attr "length" "4")]) +;; +;;(define_insn "fix_truncdfdi2" +;; [(set (match_operand:DI 0 "register_operand" "=r") +;; (fix:DI (match_operand:DF 1 "register_operand" "r")))] +;; "" +;; "fix_truncdfdi2 %0,%1" +;; [(set_attr "length" "4")]) +;; +;;;; Convert between unsigned integer types and floating point. +;; +;;(define_insn "floatunssisf2" +;; [(set (match_operand:SF 0 "register_operand" "=r") +;; (unsigned_float:SF (match_operand:SI 1 "register_operand" "r")))] +;; "" +;; "floatunssisf2 %0,%1" +;; [(set_attr "length" "4")]) +;; +;;(define_insn "floatunssidf2" +;; [(set (match_operand:DF 0 "register_operand" "=r") +;; (unsigned_float:DF (match_operand:SI 1 "register_operand" "r")))] +;; "" +;; "floatunssidf2 %0,%1" +;; [(set_attr "length" "4")]) +;; +;;(define_insn "floatunsdisf2" +;; [(set (match_operand:SF 0 "register_operand" "=r") +;; (unsigned_float:SF (match_operand:DI 1 "register_operand" "r")))] +;; "" +;; "floatunsdisf2 %0,%1" +;; [(set_attr "length" "4")]) +;; +;;(define_insn "floatunsdidf2" +;; [(set (match_operand:DF 0 "register_operand" "=r") +;; (unsigned_float:DF (match_operand:DI 1 "register_operand" "r")))] +;; "" +;; "floatunsdidf2 %0,%1" +;; [(set_attr "length" "4")]) +;; +;;(define_insn "fixuns_truncsfsi2" +;; [(set (match_operand:SI 0 "register_operand" "=r") +;; (unsigned_fix:SI (match_operand:SF 1 "register_operand" "r")))] +;; "" +;; "fixuns_truncsfsi2 %0,%1" +;; [(set_attr "length" "4")]) +;; +;;(define_insn "fixuns_truncdfsi2" +;; [(set (match_operand:SI 0 "register_operand" "=r") +;; (unsigned_fix:SI (match_operand:DF 1 "register_operand" "r")))] +;; "" +;; "fixuns_truncdfsi2 %0,%1" +;; [(set_attr "length" "4")]) +;; +;;(define_insn "fixuns_truncsfdi2" +;; [(set (match_operand:DI 0 "register_operand" "=r") +;; (unsigned_fix:DI (match_operand:SF 1 "register_operand" "r")))] +;; "" +;; "fixuns_truncsfdi2 %0,%1" +;; [(set_attr "length" "4")]) +;; +;;(define_insn "fixuns_truncdfdi2" +;; [(set (match_operand:DI 0 "register_operand" "=r") +;; (unsigned_fix:DI (match_operand:DF 1 "register_operand" "r")))] +;; "" +;; "fixuns_truncdfdi2 %0,%1" +;; [(set_attr "length" "4")]) + + +;; :::::::::::::::::::: +;; :: +;; :: 32-bit Integer arithmetic +;; :: +;; :::::::::::::::::::: + +;; Addition +(define_insn "addsi3" + [(set (match_operand:SI 0 "integer_register_operand" "=d") + (plus:SI (match_operand:SI 1 "integer_register_operand" "%d") + (match_operand:SI 2 "gpr_or_int12_operand" "dNOPQ")))] + "" + "add%I2 %1,%2,%0" + [(set_attr "length" "4") + (set_attr "type" "int")]) + +;; Subtraction. No need to worry about constants, since the compiler +;; canonicalizes them into addsi3's. We prevent SUBREG's here to work around a +;; combine bug, that combines the 32x32->upper 32 bit multiply that uses a +;; SUBREG with a minus that shows up in modulus by constants. +(define_insn "subsi3" + [(set (match_operand:SI 0 "integer_register_operand" "=d") + (minus:SI (match_operand:SI 1 "gpr_no_subreg_operand" "d") + (match_operand:SI 2 "gpr_no_subreg_operand" "d")))] + "" + "sub %1,%2,%0" + [(set_attr "length" "4") + (set_attr "type" "int")]) + +;; Signed multiplication producing 64-bit results from 32-bit inputs +;; Note, frv doesn't have a 32x32->32 bit multiply, but the compiler +;; will do the 32x32->64 bit multiply and use the bottom word. +(define_expand "mulsidi3" + [(set (match_operand:DI 0 "integer_register_operand" "") + (mult:DI (sign_extend:DI (match_operand:SI 1 "integer_register_operand" "")) + (sign_extend:DI (match_operand:SI 2 "gpr_or_int12_operand" ""))))] + "" + " +{ + if (GET_CODE (operands[2]) == CONST_INT) + { + emit_insn (gen_mulsidi3_const (operands[0], operands[1], operands[2])); + DONE; + } +}") + +(define_insn "*mulsidi3_reg" + [(set (match_operand:DI 0 "even_gpr_operand" "=e") + (mult:DI (sign_extend:DI (match_operand:SI 1 "integer_register_operand" "%d")) + (sign_extend:DI (match_operand:SI 2 "integer_register_operand" "d"))))] + "" + "smul %1,%2,%0" + [(set_attr "length" "4") + (set_attr "type" "mul")]) + +(define_insn "mulsidi3_const" + [(set (match_operand:DI 0 "even_gpr_operand" "=e") + (mult:DI (sign_extend:DI (match_operand:SI 1 "integer_register_operand" "d")) + (match_operand:SI 2 "int12_operand" "NOP")))] + "" + "smuli %1,%2,%0" + [(set_attr "length" "4") + (set_attr "type" "mul")]) + +;; Unsigned multiplication producing 64-bit results from 32-bit inputs +(define_expand "umulsidi3" + [(set (match_operand:DI 0 "even_gpr_operand" "") + (mult:DI (zero_extend:DI (match_operand:SI 1 "integer_register_operand" "")) + (zero_extend:DI (match_operand:SI 2 "gpr_or_int12_operand" ""))))] + "" + " +{ + if (GET_CODE (operands[2]) == CONST_INT) + { + emit_insn (gen_umulsidi3_const (operands[0], operands[1], operands[2])); + DONE; + } +}") + +(define_insn "*mulsidi3_reg" + [(set (match_operand:DI 0 "even_gpr_operand" "=e") + (mult:DI (zero_extend:DI (match_operand:SI 1 "integer_register_operand" "%d")) + (zero_extend:DI (match_operand:SI 2 "integer_register_operand" "d"))))] + "" + "umul %1,%2,%0" + [(set_attr "length" "4") + (set_attr "type" "mul")]) + +(define_insn "umulsidi3_const" + [(set (match_operand:DI 0 "even_gpr_operand" "=e") + (mult:DI (zero_extend:DI (match_operand:SI 1 "integer_register_operand" "d")) + (match_operand:SI 2 "int12_operand" "NOP")))] + "" + "umuli %1,%2,%0" + [(set_attr "length" "4") + (set_attr "type" "mul")]) + +;; Signed Division +(define_insn "divsi3" + [(set (match_operand:SI 0 "register_operand" "=d,d") + (div:SI (match_operand:SI 1 "register_operand" "d,d") + (match_operand:SI 2 "gpr_or_int12_operand" "d,NOP")))] + "" + "sdiv%I2 %1,%2,%0" + [(set_attr "length" "4") + (set_attr "type" "div")]) + +;; Unsigned Division +(define_insn "udivsi3" + [(set (match_operand:SI 0 "register_operand" "=d,d") + (udiv:SI (match_operand:SI 1 "register_operand" "d,d") + (match_operand:SI 2 "gpr_or_int12_operand" "d,NOP")))] + "" + "udiv%I2 %1,%2,%0" + [(set_attr "length" "4") + (set_attr "type" "div")]) + +;; Negation +(define_insn "negsi2" + [(set (match_operand:SI 0 "integer_register_operand" "=d") + (neg:SI (match_operand:SI 1 "integer_register_operand" "d")))] + "" + "sub %.,%1,%0" + [(set_attr "length" "4") + (set_attr "type" "int")]) + +;; Find first one bit +;; (define_insn "ffssi2" +;; [(set (match_operand:SI 0 "register_operand" "=r") +;; (ffs:SI (match_operand:SI 1 "register_operand" "r")))] +;; "" +;; "ffssi2 %0,%1" +;; [(set_attr "length" "4")]) + + +;; :::::::::::::::::::: +;; :: +;; :: 64-bit Integer arithmetic +;; :: +;; :::::::::::::::::::: + +;; Addition +(define_insn_and_split "adddi3" + [(set (match_operand:DI 0 "integer_register_operand" "=&e,e") + (plus:DI (match_operand:DI 1 "integer_register_operand" "%e,0") + (match_operand:DI 2 "gpr_or_int10_operand" "eJ,eJ"))) + (clobber (match_scratch:CC 3 "=t,t"))] + "" + "#" + "reload_completed" + [(match_dup 4) + (match_dup 5)] + " +{ + rtx parts[3][2]; + int op, part; + + for (op = 0; op < 3; op++) + for (part = 0; part < 2; part++) + parts[op][part] = simplify_gen_subreg (SImode, operands[op], + DImode, part * UNITS_PER_WORD); + + operands[4] = gen_adddi3_lower (parts[0][1], parts[1][1], parts[2][1], + operands[3]); + operands[5] = gen_adddi3_upper (parts[0][0], parts[1][0], parts[2][0], + copy_rtx (operands[3])); +}" + [(set_attr "length" "8") + (set_attr "type" "multi")]) + +;; Subtraction No need to worry about constants, since the compiler +;; canonicalizes them into adddi3's. +(define_insn_and_split "subdi3" + [(set (match_operand:DI 0 "integer_register_operand" "=&e,e,e") + (minus:DI (match_operand:DI 1 "integer_register_operand" "e,0,e") + (match_operand:DI 2 "integer_register_operand" "e,e,0"))) + (clobber (match_scratch:CC 3 "=t,t,t"))] + "" + "#" + "reload_completed" + [(match_dup 4) + (match_dup 5)] + " +{ + rtx op0_high = gen_highpart (SImode, operands[0]); + rtx op1_high = gen_highpart (SImode, operands[1]); + rtx op2_high = gen_highpart (SImode, operands[2]); + rtx op0_low = gen_lowpart (SImode, operands[0]); + rtx op1_low = gen_lowpart (SImode, operands[1]); + rtx op2_low = gen_lowpart (SImode, operands[2]); + rtx op3 = operands[3]; + + operands[4] = gen_subdi3_lower (op0_low, op1_low, op2_low, op3); + operands[5] = gen_subdi3_upper (op0_high, op1_high, op2_high, op3); +}" + [(set_attr "length" "8") + (set_attr "type" "multi")]) + +;; Patterns for addsi3/subdi3 after splitting +(define_insn "adddi3_lower" + [(set (match_operand:SI 0 "integer_register_operand" "=d") + (plus:SI (match_operand:SI 1 "integer_register_operand" "d") + (match_operand:SI 2 "gpr_or_int10_operand" "dJ"))) + (set (match_operand:CC 3 "icc_operand" "=t") + (compare:CC (plus:SI (match_dup 1) + (match_dup 2)) + (const_int 0)))] + "" + "add%I2cc %1,%2,%0,%3" + [(set_attr "length" "4") + (set_attr "type" "int")]) + +(define_insn "adddi3_upper" + [(set (match_operand:SI 0 "integer_register_operand" "=d") + (plus:SI (match_operand:SI 1 "integer_register_operand" "d") + (plus:SI (match_operand:SI 2 "gpr_or_int10_operand" "dJ") + (match_operand:CC 3 "icc_operand" "t"))))] + "" + "addx%I2 %1,%2,%0,%3" + [(set_attr "length" "4") + (set_attr "type" "int")]) + +(define_insn "subdi3_lower" + [(set (match_operand:SI 0 "integer_register_operand" "=d") + (minus:SI (match_operand:SI 1 "integer_register_operand" "d") + (match_operand:SI 2 "integer_register_operand" "d"))) + (set (match_operand:CC 3 "icc_operand" "=t") + (compare:CC (plus:SI (match_dup 1) + (match_dup 2)) + (const_int 0)))] + "" + "subcc %1,%2,%0,%3" + [(set_attr "length" "4") + (set_attr "type" "int")]) + +(define_insn "subdi3_upper" + [(set (match_operand:SI 0 "integer_register_operand" "=d") + (minus:SI (match_operand:SI 1 "integer_register_operand" "d") + (minus:SI (match_operand:SI 2 "integer_register_operand" "d") + (match_operand:CC 3 "icc_operand" "t"))))] + "" + "subx %1,%2,%0,%3" + [(set_attr "length" "4") + (set_attr "type" "int")]) + +(define_insn_and_split "negdi2" + [(set (match_operand:DI 0 "integer_register_operand" "=&e,e") + (neg:DI (match_operand:DI 1 "integer_register_operand" "e,0"))) + (clobber (match_scratch:CC 2 "=t,t"))] + "" + "#" + "reload_completed" + [(match_dup 3) + (match_dup 4)] + " +{ + rtx op0_high = gen_highpart (SImode, operands[0]); + rtx op1_high = gen_rtx_REG (SImode, GPR_FIRST); + rtx op2_high = gen_highpart (SImode, operands[1]); + rtx op0_low = gen_lowpart (SImode, operands[0]); + rtx op1_low = op1_high; + rtx op2_low = gen_lowpart (SImode, operands[1]); + rtx op3 = operands[2]; + + operands[3] = gen_subdi3_lower (op0_low, op1_low, op2_low, op3); + operands[4] = gen_subdi3_upper (op0_high, op1_high, op2_high, op3); +}" + [(set_attr "length" "8") + (set_attr "type" "multi")]) + +;; Multiplication (same size) +;; (define_insn "muldi3" +;; [(set (match_operand:DI 0 "register_operand" "=r") +;; (mult:DI (match_operand:DI 1 "register_operand" "%r") +;; (match_operand:DI 2 "nonmemory_operand" "ri")))] +;; "" +;; "muldi3 %0,%1,%2" +;; [(set_attr "length" "4")]) + +;; Signed Division +;; (define_insn "divdi3" +;; [(set (match_operand:DI 0 "register_operand" "=r") +;; (div:DI (match_operand:DI 1 "register_operand" "r") +;; (match_operand:DI 2 "nonmemory_operand" "ri")))] +;; "" +;; "divdi3 %0,%1,%2" +;; [(set_attr "length" "4")]) + +;; Undsgned Division +;; (define_insn "udivdi3" +;; [(set (match_operand:DI 0 "register_operand" "=r") +;; (udiv:DI (match_operand:DI 1 "register_operand" "r") +;; (match_operand:DI 2 "nonmemory_operand" "ri")))] +;; "" +;; "udivdi3 %0,%1,%2" +;; [(set_attr "length" "4")]) + +;; Negation +;; (define_insn "negdi2" +;; [(set (match_operand:DI 0 "register_operand" "=r") +;; (neg:DI (match_operand:DI 1 "register_operand" "r")))] +;; "" +;; "negdi2 %0,%1" +;; [(set_attr "length" "4")]) + +;; Find first one bit +;; (define_insn "ffsdi2" +;; [(set (match_operand:DI 0 "register_operand" "=r") +;; (ffs:DI (match_operand:DI 1 "register_operand" "r")))] +;; "" +;; "ffsdi2 %0,%1" +;; [(set_attr "length" "4")]) + + +;; :::::::::::::::::::: +;; :: +;; :: 32-bit floating point arithmetic +;; :: +;; :::::::::::::::::::: + +;; Addition +(define_insn "addsf3" + [(set (match_operand:SF 0 "fpr_operand" "=f") + (plus:SF (match_operand:SF 1 "fpr_operand" "%f") + (match_operand:SF 2 "fpr_operand" "f")))] + "TARGET_HARD_FLOAT" + "fadds %1,%2,%0" + [(set_attr "length" "4") + (set_attr "type" "fsadd")]) + +;; Subtraction +(define_insn "subsf3" + [(set (match_operand:SF 0 "fpr_operand" "=f") + (minus:SF (match_operand:SF 1 "fpr_operand" "f") + (match_operand:SF 2 "fpr_operand" "f")))] + "TARGET_HARD_FLOAT" + "fsubs %1,%2,%0" + [(set_attr "length" "4") + (set_attr "type" "fsadd")]) + +;; Multiplication +(define_insn "mulsf3" + [(set (match_operand:SF 0 "fpr_operand" "=f") + (mult:SF (match_operand:SF 1 "fpr_operand" "%f") + (match_operand:SF 2 "fpr_operand" "f")))] + "TARGET_HARD_FLOAT" + "fmuls %1,%2,%0" + [(set_attr "length" "4") + (set_attr "type" "fsmul")]) + +;; Multiplication with addition/subtraction +(define_insn "*muladdsf4" + [(set (match_operand:SF 0 "fpr_operand" "=f") + (plus:SF (mult:SF (match_operand:SF 1 "fpr_operand" "%f") + (match_operand:SF 2 "fpr_operand" "f")) + (match_operand:SF 3 "fpr_operand" "0")))] + "TARGET_HARD_FLOAT && TARGET_MULADD" + "fmadds %1,%2,%0" + [(set_attr "length" "4") + (set_attr "type" "fsmadd")]) + +(define_insn "*mulsubsf4" + [(set (match_operand:SF 0 "fpr_operand" "=f") + (minus:SF (mult:SF (match_operand:SF 1 "fpr_operand" "%f") + (match_operand:SF 2 "fpr_operand" "f")) + (match_operand:SF 3 "fpr_operand" "0")))] + "TARGET_HARD_FLOAT && TARGET_MULADD" + "fmsubs %1,%2,%0" + [(set_attr "length" "4") + (set_attr "type" "fsmadd")]) + +;; Division +(define_insn "divsf3" + [(set (match_operand:SF 0 "fpr_operand" "=f") + (div:SF (match_operand:SF 1 "fpr_operand" "f") + (match_operand:SF 2 "fpr_operand" "f")))] + "TARGET_HARD_FLOAT" + "fdivs %1,%2,%0" + [(set_attr "length" "4") + (set_attr "type" "fsdiv")]) + +;; Negation +(define_insn "negsf2" + [(set (match_operand:SF 0 "fpr_operand" "=f") + (neg:SF (match_operand:SF 1 "fpr_operand" "f")))] + "TARGET_HARD_FLOAT" + "fnegs %1,%0" + [(set_attr "length" "4") + (set_attr "type" "fsconv")]) + +;; Absolute value +(define_insn "abssf2" + [(set (match_operand:SF 0 "fpr_operand" "=f") + (abs:SF (match_operand:SF 1 "fpr_operand" "f")))] + "TARGET_HARD_FLOAT" + "fabss %1,%0" + [(set_attr "length" "4") + (set_attr "type" "fsconv")]) + +;; Square root +(define_insn "sqrtsf2" + [(set (match_operand:SF 0 "fpr_operand" "=f") + (sqrt:SF (match_operand:SF 1 "fpr_operand" "f")))] + "TARGET_HARD_FLOAT" + "fsqrts %1,%0" + [(set_attr "length" "4") + (set_attr "type" "sqrt_single")]) + + +;; :::::::::::::::::::: +;; :: +;; :: 64-bit floating point arithmetic +;; :: +;; :::::::::::::::::::: + +;; Addition +(define_insn "adddf3" + [(set (match_operand:DF 0 "even_fpr_operand" "=h") + (plus:DF (match_operand:DF 1 "fpr_operand" "%h") + (match_operand:DF 2 "fpr_operand" "h")))] + "TARGET_HARD_FLOAT && TARGET_DOUBLE" + "faddd %1,%2,%0" + [(set_attr "length" "4") + (set_attr "type" "fdadd")]) + +;; Subtraction +(define_insn "subdf3" + [(set (match_operand:DF 0 "even_fpr_operand" "=h") + (minus:DF (match_operand:DF 1 "fpr_operand" "h") + (match_operand:DF 2 "fpr_operand" "h")))] + "TARGET_HARD_FLOAT && TARGET_DOUBLE" + "fsubd %1,%2,%0" + [(set_attr "length" "4") + (set_attr "type" "fdadd")]) + +;; Multiplication +(define_insn "muldf3" + [(set (match_operand:DF 0 "even_fpr_operand" "=h") + (mult:DF (match_operand:DF 1 "fpr_operand" "%h") + (match_operand:DF 2 "fpr_operand" "h")))] + "TARGET_HARD_FLOAT && TARGET_DOUBLE" + "fmuld %1,%2,%0" + [(set_attr "length" "4") + (set_attr "type" "fdmul")]) + +;; Multiplication with addition/subtraction +(define_insn "*muladddf4" + [(set (match_operand:DF 0 "fpr_operand" "=f") + (plus:DF (mult:DF (match_operand:DF 1 "fpr_operand" "%f") + (match_operand:DF 2 "fpr_operand" "f")) + (match_operand:DF 3 "fpr_operand" "0")))] + "TARGET_HARD_FLOAT && TARGET_DOUBLE && TARGET_MULADD" + "fmaddd %1,%2,%0" + [(set_attr "length" "4") + (set_attr "type" "fdmadd")]) + +(define_insn "*mulsubdf4" + [(set (match_operand:DF 0 "fpr_operand" "=f") + (minus:DF (mult:DF (match_operand:DF 1 "fpr_operand" "%f") + (match_operand:DF 2 "fpr_operand" "f")) + (match_operand:DF 3 "fpr_operand" "0")))] + "TARGET_HARD_FLOAT && TARGET_DOUBLE && TARGET_MULADD" + "fmsubd %1,%2,%0" + [(set_attr "length" "4") + (set_attr "type" "fdmadd")]) + +;; Division +(define_insn "divdf3" + [(set (match_operand:DF 0 "even_fpr_operand" "=h") + (div:DF (match_operand:DF 1 "fpr_operand" "h") + (match_operand:DF 2 "fpr_operand" "h")))] + "TARGET_HARD_FLOAT && TARGET_DOUBLE" + "fdivd %1,%2,%0" + [(set_attr "length" "4") + (set_attr "type" "fddiv")]) + +;; Negation +(define_insn "negdf2" + [(set (match_operand:DF 0 "even_fpr_operand" "=h") + (neg:DF (match_operand:DF 1 "fpr_operand" "h")))] + "TARGET_HARD_FLOAT && TARGET_DOUBLE" + "fnegd %1,%0" + [(set_attr "length" "4") + (set_attr "type" "fdconv")]) + +;; Absolute value +(define_insn "absdf2" + [(set (match_operand:DF 0 "even_fpr_operand" "=h") + (abs:DF (match_operand:DF 1 "fpr_operand" "h")))] + "TARGET_HARD_FLOAT && TARGET_DOUBLE" + "fabsd %1,%0" + [(set_attr "length" "4") + (set_attr "type" "fdconv")]) + +;; Square root +(define_insn "sqrtdf2" + [(set (match_operand:DF 0 "even_fpr_operand" "=h") + (sqrt:DF (match_operand:DF 1 "fpr_operand" "h")))] + "TARGET_HARD_FLOAT && TARGET_DOUBLE" + "fsqrtd %1,%0" + [(set_attr "length" "4") + (set_attr "type" "sqrt_double")]) + + +;; :::::::::::::::::::: +;; :: +;; :: 32-bit Integer Shifts and Rotates +;; :: +;; :::::::::::::::::::: + +;; Arithmetic Shift Left +(define_insn "ashlsi3" + [(set (match_operand:SI 0 "integer_register_operand" "=d,d") + (ashift:SI (match_operand:SI 1 "integer_register_operand" "d,d") + (match_operand:SI 2 "gpr_or_int12_operand" "d,NOP")))] + "" + "sll%I2 %1,%2,%0" + [(set_attr "length" "4") + (set_attr "type" "int")]) + +;; Arithmetic Shift Right +(define_insn "ashrsi3" + [(set (match_operand:SI 0 "integer_register_operand" "=d,d") + (ashiftrt:SI (match_operand:SI 1 "integer_register_operand" "d,d") + (match_operand:SI 2 "gpr_or_int12_operand" "d,NOP")))] + "" + "sra%I2 %1, %2, %0" + [(set_attr "length" "4") + (set_attr "type" "int")]) + +;; Logical Shift Right +(define_insn "lshrsi3" + [(set (match_operand:SI 0 "integer_register_operand" "=d,d") + (lshiftrt:SI (match_operand:SI 1 "integer_register_operand" "d,d") + (match_operand:SI 2 "gpr_or_int12_operand" "d,NOP")))] + "" + "srl%I2 %1, %2, %0" + [(set_attr "length" "4") + (set_attr "type" "int")]) + +;; Rotate Left +;; (define_insn "rotlsi3" +;; [(set (match_operand:SI 0 "register_operand" "=r") +;; (rotate:SI (match_operand:SI 1 "register_operand" "r") +;; (match_operand:SI 2 "nonmemory_operand" "ri")))] +;; "" +;; "rotlsi3 %0,%1,%2" +;; [(set_attr "length" "4")]) + +;; Rotate Right +;; (define_insn "rotrsi3" +;; [(set (match_operand:SI 0 "register_operand" "=r") +;; (rotatert:SI (match_operand:SI 1 "register_operand" "r") +;; (match_operand:SI 2 "nonmemory_operand" "ri")))] +;; "" +;; "rotrsi3 %0,%1,%2" +;; [(set_attr "length" "4")]) + + +;; :::::::::::::::::::: +;; :: +;; :: 64-bit Integer Shifts and Rotates +;; :: +;; :::::::::::::::::::: + +;; Arithmetic Shift Left +;; (define_insn "ashldi3" +;; [(set (match_operand:DI 0 "register_operand" "=r") +;; (ashift:DI (match_operand:DI 1 "register_operand" "r") +;; (match_operand:SI 2 "nonmemory_operand" "ri")))] +;; "" +;; "ashldi3 %0,%1,%2" +;; [(set_attr "length" "4")]) + +;; Arithmetic Shift Right +;; (define_insn "ashrdi3" +;; [(set (match_operand:DI 0 "register_operand" "=r") +;; (ashiftrt:DI (match_operand:DI 1 "register_operand" "r") +;; (match_operand:SI 2 "nonmemory_operand" "ri")))] +;; "" +;; "ashrdi3 %0,%1,%2" +;; [(set_attr "length" "4")]) + +;; Logical Shift Right +;; (define_insn "lshrdi3" +;; [(set (match_operand:DI 0 "register_operand" "=r") +;; (lshiftrt:DI (match_operand:DI 1 "register_operand" "r") +;; (match_operand:SI 2 "nonmemory_operand" "ri")))] +;; "" +;; "lshrdi3 %0,%1,%2" +;; [(set_attr "length" "4")]) + +;; Rotate Left +;; (define_insn "rotldi3" +;; [(set (match_operand:DI 0 "register_operand" "=r") +;; (rotate:DI (match_operand:DI 1 "register_operand" "r") +;; (match_operand:SI 2 "nonmemory_operand" "ri")))] +;; "" +;; "rotldi3 %0,%1,%2" +;; [(set_attr "length" "4")]) + +;; Rotate Right +;; (define_insn "rotrdi3" +;; [(set (match_operand:DI 0 "register_operand" "=r") +;; (rotatert:DI (match_operand:DI 1 "register_operand" "r") +;; (match_operand:SI 2 "nonmemory_operand" "ri")))] +;; "" +;; "rotrdi3 %0,%1,%2" +;; [(set_attr "length" "4")]) + + +;; :::::::::::::::::::: +;; :: +;; :: 32-Bit Integer Logical operations +;; :: +;; :::::::::::::::::::: + +;; Logical AND, 32-bit integers +(define_insn "andsi3_media" + [(set (match_operand:SI 0 "gpr_or_fpr_operand" "=d,f") + (and:SI (match_operand:SI 1 "gpr_or_fpr_operand" "%d,f") + (match_operand:SI 2 "gpr_fpr_or_int12_operand" "dNOP,f")))] + "TARGET_MEDIA" + "@ + and%I2 %1, %2, %0 + mand %1, %2, %0" + [(set_attr "length" "4") + (set_attr "type" "int,mlogic")]) + +(define_insn "andsi3_nomedia" + [(set (match_operand:SI 0 "integer_register_operand" "=d") + (and:SI (match_operand:SI 1 "integer_register_operand" "%d") + (match_operand:SI 2 "gpr_or_int12_operand" "dNOP")))] + "!TARGET_MEDIA" + "and%I2 %1, %2, %0" + [(set_attr "length" "4") + (set_attr "type" "int")]) + +(define_expand "andsi3" + [(set (match_operand:SI 0 "gpr_or_fpr_operand" "") + (and:SI (match_operand:SI 1 "gpr_or_fpr_operand" "") + (match_operand:SI 2 "gpr_fpr_or_int12_operand" "")))] + "" + "") + +;; Inclusive OR, 32-bit integers +(define_insn "iorsi3_media" + [(set (match_operand:SI 0 "gpr_or_fpr_operand" "=d,f") + (ior:SI (match_operand:SI 1 "gpr_or_fpr_operand" "%d,f") + (match_operand:SI 2 "gpr_fpr_or_int12_operand" "dNOP,f")))] + "TARGET_MEDIA" + "@ + or%I2 %1, %2, %0 + mor %1, %2, %0" + [(set_attr "length" "4") + (set_attr "type" "int,mlogic")]) + +(define_insn "iorsi3_nomedia" + [(set (match_operand:SI 0 "integer_register_operand" "=d") + (ior:SI (match_operand:SI 1 "integer_register_operand" "%d") + (match_operand:SI 2 "gpr_or_int12_operand" "dNOP")))] + "!TARGET_MEDIA" + "or%I2 %1, %2, %0" + [(set_attr "length" "4") + (set_attr "type" "int")]) + +(define_expand "iorsi3" + [(set (match_operand:SI 0 "gpr_or_fpr_operand" "") + (ior:SI (match_operand:SI 1 "gpr_or_fpr_operand" "") + (match_operand:SI 2 "gpr_fpr_or_int12_operand" "")))] + "" + "") + +;; Exclusive OR, 32-bit integers +(define_insn "xorsi3_media" + [(set (match_operand:SI 0 "gpr_or_fpr_operand" "=d,f") + (xor:SI (match_operand:SI 1 "gpr_or_fpr_operand" "%d,f") + (match_operand:SI 2 "gpr_fpr_or_int12_operand" "dNOP,f")))] + "TARGET_MEDIA" + "@ + xor%I2 %1, %2, %0 + mxor %1, %2, %0" + [(set_attr "length" "4") + (set_attr "type" "int,mlogic")]) + +(define_insn "xorsi3_nomedia" + [(set (match_operand:SI 0 "integer_register_operand" "=d") + (xor:SI (match_operand:SI 1 "integer_register_operand" "%d") + (match_operand:SI 2 "gpr_or_int12_operand" "dNOP")))] + "!TARGET_MEDIA" + "xor%I2 %1, %2, %0" + [(set_attr "length" "4") + (set_attr "type" "int")]) + +(define_expand "xorsi3" + [(set (match_operand:SI 0 "gpr_or_fpr_operand" "") + (xor:SI (match_operand:SI 1 "gpr_or_fpr_operand" "") + (match_operand:SI 2 "gpr_fpr_or_int12_operand" "")))] + "" + "") + +;; One's complement, 32-bit integers +(define_insn "one_cmplsi2_media" + [(set (match_operand:SI 0 "gpr_or_fpr_operand" "=d,f") + (not:SI (match_operand:SI 1 "gpr_or_fpr_operand" "d,f")))] + "TARGET_MEDIA" + "@ + not %1, %0 + mnot %1, %0" + [(set_attr "length" "4") + (set_attr "type" "int,mlogic")]) + +(define_insn "one_cmplsi2_nomedia" + [(set (match_operand:SI 0 "integer_register_operand" "=d") + (not:SI (match_operand:SI 1 "integer_register_operand" "d")))] + "!TARGET_MEDIA" + "not %1,%0" + [(set_attr "length" "4") + (set_attr "type" "int")]) + +(define_expand "one_cmplsi2" + [(set (match_operand:SI 0 "gpr_or_fpr_operand" "") + (not:SI (match_operand:SI 1 "gpr_or_fpr_operand" "")))] + "" + "") + + +;; :::::::::::::::::::: +;; :: +;; :: 64-Bit Integer Logical operations +;; :: +;; :::::::::::::::::::: + +;; Logical AND, 64-bit integers +;; (define_insn "anddi3" +;; [(set (match_operand:DI 0 "register_operand" "=r") +;; (and:DI (match_operand:DI 1 "register_operand" "%r") +;; (match_operand:DI 2 "nonmemory_operand" "ri")))] +;; "" +;; "anddi3 %0,%1,%2" +;; [(set_attr "length" "4")]) + +;; Inclusive OR, 64-bit integers +;; (define_insn "iordi3" +;; [(set (match_operand:DI 0 "register_operand" "=r") +;; (ior:DI (match_operand:DI 1 "register_operand" "%r") +;; (match_operand:DI 2 "nonmemory_operand" "ri")))] +;; "" +;; "iordi3 %0,%1,%2" +;; [(set_attr "length" "4")]) + +;; Exclusive OR, 64-bit integers +;; (define_insn "xordi3" +;; [(set (match_operand:DI 0 "register_operand" "=r") +;; (xor:DI (match_operand:DI 1 "register_operand" "%r") +;; (match_operand:DI 2 "nonmemory_operand" "ri")))] +;; "" +;; "xordi3 %0,%1,%2" +;; [(set_attr "length" "4")]) + +;; One's complement, 64-bit integers +;; (define_insn "one_cmpldi2" +;; [(set (match_operand:DI 0 "register_operand" "=r") +;; (not:DI (match_operand:DI 1 "register_operand" "r")))] +;; "" +;; "notdi3 %0,%1" +;; [(set_attr "length" "4")]) + + +;; :::::::::::::::::::: +;; :: +;; :: Combination of integer operation with comparison +;; :: +;; :::::::::::::::::::: + +(define_insn "*combo_intop_compare1" + [(set (match_operand:CC_NZ 0 "icc_operand" "=t") + (compare:CC_NZ + (match_operator:SI 1 "intop_compare_operator" + [(match_operand:SI 2 "integer_register_operand" "d") + (match_operand:SI 3 "gpr_or_int10_operand" "dJ")]) + (const_int 0)))] + "" + "%O1%I3cc %2, %3, %., %0" + [(set_attr "type" "int") + (set_attr "length" "4")]) + +(define_insn "*combo_intop_compare2" + [(set (match_operand:CC_NZ 0 "icc_operand" "=t") + (compare:CC_NZ + (match_operator:SI 1 "intop_compare_operator" + [(match_operand:SI 2 "integer_register_operand" "d") + (match_operand:SI 3 "gpr_or_int10_operand" "dJ")]) + (const_int 0))) + (set (match_operand:SI 4 "integer_register_operand" "=d") + (match_operator:SI 5 "intop_compare_operator" + [(match_dup 2) + (match_dup 3)]))] + "GET_CODE (operands[1]) == GET_CODE (operands[5])" + "%O1%I3cc %2, %3, %4, %0" + [(set_attr "type" "int") + (set_attr "length" "4")]) + +;; :::::::::::::::::::: +;; :: +;; :: 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 "integer_register_operand" "") + (match_operand:SI 1 "gpr_or_int10_operand" "")))] + "" + " +{ + frv_compare_op0 = operands[0]; + frv_compare_op1 = operands[1]; + DONE; +}") + +;(define_expand "cmpdi" +; [(set (cc0) +; (compare (match_operand:DI 0 "register_operand" "") +; (match_operand:DI 1 "nonmemory_operand" "")))] +; "" +; " +;{ +; frv_compare_op0 = operands[0]; +; frv_compare_op1 = operands[1]; +; DONE; +;}") + +(define_expand "cmpsf" + [(set (cc0) + (compare (match_operand:SF 0 "fpr_operand" "") + (match_operand:SF 1 "fpr_operand" "")))] + "TARGET_HARD_FLOAT" + " +{ + frv_compare_op0 = operands[0]; + frv_compare_op1 = operands[1]; + DONE; +}") + +(define_expand "cmpdf" + [(set (cc0) + (compare (match_operand:DF 0 "fpr_operand" "") + (match_operand:DF 1 "fpr_operand" "")))] + "TARGET_HARD_FLOAT && TARGET_DOUBLE" + " +{ + frv_compare_op0 = operands[0]; + frv_compare_op1 = operands[1]; + DONE; +}") + +;; Now, the actual comparisons, generated by the branch and/or scc operations + +(define_insn "cmpsi_cc" + [(set (match_operand:CC 0 "icc_operand" "=t,t") + (compare:CC (match_operand:SI 1 "integer_register_operand" "d,d") + (match_operand:SI 2 "gpr_or_int10_operand" "d,J")))] + "" + "cmp%I2 %1,%2,%0" + [(set_attr "length" "4") + (set_attr "type" "int")]) + +(define_insn "*cmpsi_cc_uns" + [(set (match_operand:CC_UNS 0 "icc_operand" "=t,t") + (compare:CC_UNS (match_operand:SI 1 "integer_register_operand" "d,d") + (match_operand:SI 2 "gpr_or_int10_operand" "d,J")))] + "" + "cmp%I2 %1,%2,%0" + [(set_attr "length" "4") + (set_attr "type" "int")]) + +;; The only requirement for a CC_NZmode GPR or memory value is that +;; comparing it against zero must set the Z and N flags appropriately. +;; The source operand is therefore a valid CC_NZmode value. +(define_insn "*cmpsi_cc_nz" + [(set (match_operand:CC_NZ 0 "nonimmediate_operand" "=t,d,m") + (compare:CC_NZ (match_operand:SI 1 "integer_register_operand" "d,d,d") + (const_int 0)))] + "" + "@ + cmpi %1, #0, %0 + mov %1, %0 + st%I0%U0 %1, %M0" + [(set_attr "length" "4,4,4") + (set_attr "type" "int,int,gstore")]) + +(define_insn "*cmpsf_cc_fp" + [(set (match_operand:CC_FP 0 "fcc_operand" "=u") + (compare:CC_FP (match_operand:SF 1 "fpr_operand" "f") + (match_operand:SF 2 "fpr_operand" "f")))] + "TARGET_HARD_FLOAT" + "fcmps %1,%2,%0" + [(set_attr "length" "4") + (set_attr "type" "fscmp")]) + +(define_insn "*cmpdf_cc_fp" + [(set (match_operand:CC_FP 0 "fcc_operand" "=u") + (compare:CC_FP (match_operand:DF 1 "even_fpr_operand" "h") + (match_operand:DF 2 "even_fpr_operand" "h")))] + "TARGET_HARD_FLOAT && TARGET_DOUBLE" + "fcmpd %1,%2,%0" + [(set_attr "length" "4") + (set_attr "type" "fdcmp")]) + + +;; :::::::::::::::::::: +;; :: +;; :: Branches +;; :: +;; :::::::::::::::::::: + +;; Define_expands called by the machine independent part of the compiler +;; to allocate a new comparison register. Each of these named patterns +;; must be present, and they cannot be amalgamated into one pattern. +;; +;; If a fixed condition code register is being used, (as opposed to, say, +;; using cc0), then the expands should look like this: +;; +;; (define_expand "" +;; [(set (reg:CC ) +;; (compare:CC (match_dup 1) +;; (match_dup 2))) +;; (set (pc) +;; (if_then_else (eq:CC (reg:CC ) +;; (const_int 0)) +;; (label_ref (match_operand 0 "" "")) +;; (pc)))] +;; "" +;; "{ +;; operands[1] = frv_compare_op0; +;; operands[2] = frv_compare_op1; +;; }" +;; ) + +(define_expand "beq" + [(use (match_operand 0 "" ""))] + "" + " +{ + if (! frv_emit_cond_branch (EQ, operands[0])) + FAIL; + + DONE; +}") + +(define_expand "bne" + [(use (match_operand 0 "" ""))] + "" + " +{ + if (! frv_emit_cond_branch (NE, operands[0])) + FAIL; + + DONE; +}") + +(define_expand "blt" + [(use (match_operand 0 "" ""))] + "" + " +{ + if (! frv_emit_cond_branch (LT, operands[0])) + FAIL; + + DONE; +}") + +(define_expand "ble" + [(use (match_operand 0 "" ""))] + "" + " +{ + if (! frv_emit_cond_branch (LE, operands[0])) + FAIL; + + DONE; +}") + +(define_expand "bgt" + [(use (match_operand 0 "" ""))] + "" + " +{ + if (! frv_emit_cond_branch (GT, operands[0])) + FAIL; + + DONE; +}") + +(define_expand "bge" + [(use (match_operand 0 "" ""))] + "" + " +{ + if (! frv_emit_cond_branch (GE, operands[0])) + FAIL; + + DONE; +}") + +(define_expand "bltu" + [(use (match_operand 0 "" ""))] + "" + " +{ + if (! frv_emit_cond_branch (LTU, operands[0])) + FAIL; + + DONE; +}") + +(define_expand "bleu" + [(use (match_operand 0 "" ""))] + "" + " +{ + if (! frv_emit_cond_branch (LEU, operands[0])) + FAIL; + + DONE; +}") + +(define_expand "bgtu" + [(use (match_operand 0 "" ""))] + "" + " +{ + if (! frv_emit_cond_branch (GTU, operands[0])) + FAIL; + + DONE; +}") + +(define_expand "bgeu" + [(use (match_operand 0 "" ""))] + "" + " +{ + if (! frv_emit_cond_branch (GEU, operands[0])) + FAIL; + + DONE; +}") + +;; 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. +;; +;; Note - unlike the define expands above, these patterns can be amalgamated +;; into one pattern for branch-if-true and one for branch-if-false. This does +;; require an operand operator to select the correct branch mnemonic. +;; +;; If a fixed condition code register is being used, (as opposed to, say, +;; using cc0), then the expands could look like this: +;; +;; (define_insn "*branch_true" +;; [(set (pc) +;; (if_then_else (match_operator:CC 0 "comparison_operator" +;; [(reg:CC ) +;; (const_int 0)]) +;; (label_ref (match_operand 1 "" "")) +;; (pc)))] +;; "" +;; "b%B0 %1" +;; [(set_attr "length" "4")] +;; ) +;; +;; In the above example the %B is a directive to frv_print_operand() +;; to decode and print the correct branch mnemonic. + +(define_insn "*branch_int_true" + [(set (pc) + (if_then_else (match_operator 0 "integer_relational_operator" + [(match_operand 1 "icc_operand" "t") + (const_int 0)]) + (label_ref (match_operand 2 "" "")) + (pc)))] + "" + "* +{ + if (get_attr_length (insn) == 4) + return \"b%c0 %1,%#,%l2\"; + else + return \"b%C0 %1,%#,1f\;call %l2\\n1:\"; +}" + [(set (attr "length") + (if_then_else + (and (ge (minus (match_dup 2) (pc)) (const_int -32768)) + (le (minus (match_dup 2) (pc)) (const_int 32764))) + (const_int 4) + (const_int 8))) + (set (attr "far_jump") + (if_then_else + (eq_attr "length" "4") + (const_string "no") + (const_string "yes"))) + (set (attr "type") + (if_then_else + (eq_attr "length" "4") + (const_string "branch") + (const_string "multi")))]) + +(define_insn "*branch_int_false" + [(set (pc) + (if_then_else (match_operator 0 "integer_relational_operator" + [(match_operand 1 "icc_operand" "t") + (const_int 0)]) + (pc) + (label_ref (match_operand 2 "" ""))))] + "" + "* +{ + if (get_attr_length (insn) == 4) + return \"b%C0 %1,%#,%l2\"; + else + return \"b%c0 %1,%#,1f\;call %l2\\n1:\"; +}" + [(set (attr "length") + (if_then_else + (and (ge (minus (match_dup 2) (pc)) (const_int -32768)) + (le (minus (match_dup 2) (pc)) (const_int 32764))) + (const_int 4) + (const_int 8))) + (set (attr "far_jump") + (if_then_else + (eq_attr "length" "4") + (const_string "no") + (const_string "yes"))) + (set (attr "type") + (if_then_else + (eq_attr "length" "4") + (const_string "branch") + (const_string "multi")))]) + +(define_insn "*branch_fp_true" + [(set (pc) + (if_then_else (match_operator:CC_FP 0 "float_relational_operator" + [(match_operand 1 "fcc_operand" "u") + (const_int 0)]) + (label_ref (match_operand 2 "" "")) + (pc)))] + "" + "* +{ + if (get_attr_length (insn) == 4) + return \"fb%f0 %1,%#,%l2\"; + else + return \"fb%F0 %1,%#,1f\;call %l2\\n1:\"; +}" + [(set (attr "length") + (if_then_else + (and (ge (minus (match_dup 2) (pc)) (const_int -32768)) + (le (minus (match_dup 2) (pc)) (const_int 32764))) + (const_int 4) + (const_int 8))) + (set (attr "far_jump") + (if_then_else + (eq_attr "length" "4") + (const_string "no") + (const_string "yes"))) + (set (attr "type") + (if_then_else + (eq_attr "length" "4") + (const_string "branch") + (const_string "multi")))]) + +(define_insn "*branch_fp_false" + [(set (pc) + (if_then_else (match_operator:CC_FP 0 "float_relational_operator" + [(match_operand 1 "fcc_operand" "u") + (const_int 0)]) + (pc) + (label_ref (match_operand 2 "" ""))))] + "" + "* +{ + if (get_attr_length (insn) == 4) + return \"fb%F0 %1,%#,%l2\"; + else + return \"fb%f0 %1,%#,1f\;call %l2\\n1:\"; +}" + [(set (attr "length") + (if_then_else + (and (ge (minus (match_dup 2) (pc)) (const_int -32768)) + (le (minus (match_dup 2) (pc)) (const_int 32764))) + (const_int 4) + (const_int 8))) + (set (attr "far_jump") + (if_then_else + (eq_attr "length" "4") + (const_string "no") + (const_string "yes"))) + (set (attr "type") + (if_then_else + (eq_attr "length" "4") + (const_string "branch") + (const_string "multi")))]) + + +;; :::::::::::::::::::: +;; :: +;; :: Set flag operations +;; :: +;; :::::::::::::::::::: + +;; Define_expands called by the machine independent part of the compiler +;; to allocate a new comparison register + +(define_expand "seq" + [(match_operand:SI 0 "integer_register_operand" "")] + "TARGET_SCC" + " +{ + if (! frv_emit_scc (EQ, operands[0])) + FAIL; + + DONE; +}") + +(define_expand "sne" + [(match_operand:SI 0 "integer_register_operand" "")] + "TARGET_SCC" + " +{ + if (! frv_emit_scc (NE, operands[0])) + FAIL; + + DONE; +}") + +(define_expand "slt" + [(match_operand:SI 0 "integer_register_operand" "")] + "TARGET_SCC" + " +{ + if (! frv_emit_scc (LT, operands[0])) + FAIL; + + DONE; +}") + +(define_expand "sle" + [(match_operand:SI 0 "integer_register_operand" "")] + "TARGET_SCC" + " +{ + if (! frv_emit_scc (LE, operands[0])) + FAIL; + + DONE; +}") + +(define_expand "sgt" + [(match_operand:SI 0 "integer_register_operand" "")] + "TARGET_SCC" + " +{ + if (! frv_emit_scc (GT, operands[0])) + FAIL; + + DONE; +}") + +(define_expand "sge" + [(match_operand:SI 0 "integer_register_operand" "")] + "TARGET_SCC" + " +{ + if (! frv_emit_scc (GE, operands[0])) + FAIL; + + DONE; +}") + +(define_expand "sltu" + [(match_operand:SI 0 "integer_register_operand" "")] + "TARGET_SCC" + " +{ + if (! frv_emit_scc (LTU, operands[0])) + FAIL; + + DONE; +}") + +(define_expand "sleu" + [(match_operand:SI 0 "integer_register_operand" "")] + "TARGET_SCC" + " +{ + if (! frv_emit_scc (LEU, operands[0])) + FAIL; + + DONE; +}") + +(define_expand "sgtu" + [(match_operand:SI 0 "integer_register_operand" "")] + "TARGET_SCC" + " +{ + if (! frv_emit_scc (GTU, operands[0])) + FAIL; + + DONE; +}") + +(define_expand "sgeu" + [(match_operand:SI 0 "integer_register_operand" "")] + "TARGET_SCC" + " +{ + if (! frv_emit_scc (GEU, operands[0])) + FAIL; + + DONE; +}") + +(define_insn "*scc_int" + [(set (match_operand:SI 0 "integer_register_operand" "=d") + (match_operator:SI 1 "integer_relational_operator" + [(match_operand 2 "icc_operand" "t") + (const_int 0)])) + (clobber (match_operand:CC_CCR 3 "icr_operand" "=v"))] + "" + "#" + [(set_attr "length" "12") + (set_attr "type" "multi")]) + +(define_insn "*scc_float" + [(set (match_operand:SI 0 "integer_register_operand" "=d") + (match_operator:SI 1 "float_relational_operator" + [(match_operand:CC_FP 2 "fcc_operand" "u") + (const_int 0)])) + (clobber (match_operand:CC_CCR 3 "fcr_operand" "=w"))] + "" + "#" + [(set_attr "length" "12") + (set_attr "type" "multi")]) + +;; XXX -- add reload_completed to the splits, because register allocation +;; currently isn't ready to see cond_exec packets. +(define_split + [(set (match_operand:SI 0 "integer_register_operand" "") + (match_operator:SI 1 "relational_operator" + [(match_operand 2 "cc_operand" "") + (const_int 0)])) + (clobber (match_operand 3 "cr_operand" ""))] + "reload_completed" + [(match_dup 4)] + "operands[4] = frv_split_scc (operands[0], operands[1], operands[2], + operands[3], (HOST_WIDE_INT) 1);") + +(define_insn "*scc_neg1_int" + [(set (match_operand:SI 0 "integer_register_operand" "=d") + (neg:SI (match_operator:SI 1 "integer_relational_operator" + [(match_operand 2 "icc_operand" "t") + (const_int 0)]))) + (clobber (match_operand:CC_CCR 3 "icr_operand" "=v"))] + "" + "#" + [(set_attr "length" "12") + (set_attr "type" "multi")]) + +(define_insn "*scc_neg1_float" + [(set (match_operand:SI 0 "integer_register_operand" "=d") + (neg:SI (match_operator:SI 1 "float_relational_operator" + [(match_operand:CC_FP 2 "fcc_operand" "u") + (const_int 0)]))) + (clobber (match_operand:CC_CCR 3 "fcr_operand" "=w"))] + "" + "#" + [(set_attr "length" "12") + (set_attr "type" "multi")]) + +(define_split + [(set (match_operand:SI 0 "integer_register_operand" "") + (neg:SI (match_operator:SI 1 "relational_operator" + [(match_operand 2 "cc_operand" "") + (const_int 0)]))) + (clobber (match_operand 3 "cr_operand" ""))] + "reload_completed" + [(match_dup 4)] + "operands[4] = frv_split_scc (operands[0], operands[1], operands[2], + operands[3], (HOST_WIDE_INT) -1);") + + +;; :::::::::::::::::::: +;; :: +;; :: Conditionally executed instructions +;; :: +;; :::::::::::::::::::: + +;; Convert ICC/FCC comparison into CCR bits so we can do conditional execution +(define_insn "*ck_signed" + [(set (match_operand:CC_CCR 0 "icr_operand" "=v") + (match_operator:CC_CCR 1 "integer_relational_operator" + [(match_operand 2 "icc_operand" "t") + (const_int 0)]))] + "" + "ck%c1 %2, %0" + [(set_attr "length" "4") + (set_attr "type" "ccr")]) + +(define_insn "*fck_float" + [(set (match_operand:CC_CCR 0 "fcr_operand" "=w") + (match_operator:CC_CCR 1 "float_relational_operator" + [(match_operand:CC_FP 2 "fcc_operand" "u") + (const_int 0)]))] + "TARGET_HAS_FPRS" + "fck%c1 %2, %0" + [(set_attr "length" "4") + (set_attr "type" "ccr")]) + +;; Conditionally convert ICC/FCC comparison into CCR bits to provide && and || +;; tests in conditional execution +(define_insn "cond_exec_ck" + [(set (match_operand:CC_CCR 0 "cr_operand" "=v,w") + (if_then_else:CC_CCR (match_operator 1 "ccr_eqne_operator" + [(match_operand 2 "cr_operand" "C,C") + (const_int 0)]) + (match_operator 3 "relational_operator" + [(match_operand 4 "cc_operand" "t,u") + (const_int 0)]) + (const_int 0)))] + "" + "@ + cck%c3 %4, %0, %2, %e1 + cfck%f3 %4, %0, %2, %e1" + [(set_attr "length" "4") + (set_attr "type" "ccr")]) + +;; Conditionally set a register to either 0 or another register +(define_insn "*cond_exec_movqi" + [(cond_exec + (match_operator 0 "ccr_eqne_operator" + [(match_operand 1 "cr_operand" "C,C,C,C,C,C") + (const_int 0)]) + (set (match_operand:QI 2 "condexec_dest_operand" "=d,d,U,?f,?f,?d") + (match_operand:QI 3 "condexec_source_operand" "dO,U,dO,f,d,f")))] + "register_operand(operands[2], QImode) || reg_or_0_operand (operands[3], QImode)" + "* return output_condmove_single (operands, insn);" + [(set_attr "length" "4") + (set_attr "type" "int,gload,gstore,fsconv,movgf,movfg")]) + +(define_insn "*cond_exec_movhi" + [(cond_exec + (match_operator 0 "ccr_eqne_operator" + [(match_operand 1 "cr_operand" "C,C,C,C,C,C") + (const_int 0)]) + (set (match_operand:HI 2 "condexec_dest_operand" "=d,d,U,?f,?f,?d") + (match_operand:HI 3 "condexec_source_operand" "dO,U,dO,f,d,f")))] + "register_operand(operands[2], HImode) || reg_or_0_operand (operands[3], HImode)" + "* return output_condmove_single (operands, insn);" + [(set_attr "length" "4") + (set_attr "type" "int,gload,gstore,fsconv,movgf,movfg")]) + +(define_insn "*cond_exec_movsi" + [(cond_exec + (match_operator 0 "ccr_eqne_operator" + [(match_operand 1 "cr_operand" "C,C,C,C,C,C,C,C") + (const_int 0)]) + (set (match_operand:SI 2 "condexec_dest_operand" "=d,d,U,?f,?f,?d,?f,?m") + (match_operand:SI 3 "condexec_source_operand" "dO,U,dO,f,d,f,m,f")))] + "register_operand(operands[2], SImode) || reg_or_0_operand (operands[3], SImode)" + "* return output_condmove_single (operands, insn);" + [(set_attr "length" "4") + (set_attr "type" "int,gload,gstore,fsconv,movgf,movfg,fload,fstore")]) + + +(define_insn "*cond_exec_movsf_has_fprs" + [(cond_exec + (match_operator 0 "ccr_eqne_operator" + [(match_operand 1 "cr_operand" "C,C,C,C,C,C,C,C,C,C") + (const_int 0)]) + (set (match_operand:SF 2 "condexec_dest_operand" "=f,?d,?d,?f,f,f,?d,U,?U,U") + (match_operand:SF 3 "condexec_source_operand" "f,d,f,d,G,U,U,f,d,G")))] + "TARGET_HAS_FPRS" + "* return output_condmove_single (operands, insn);" + [(set_attr "length" "4") + (set_attr "type" "fsconv,int,movgf,movfg,movgf,fload,gload,fstore,gstore,gstore")]) + +(define_insn "*cond_exec_movsf_no_fprs" + [(cond_exec + (match_operator 0 "ccr_eqne_operator" + [(match_operand 1 "cr_operand" "C,C,C") + (const_int 0)]) + (set (match_operand:SF 2 "condexec_dest_operand" "=d,d,U") + (match_operand:SF 3 "condexec_source_operand" "d,U,dG")))] + "! TARGET_HAS_FPRS" + "* return output_condmove_single (operands, insn);" + [(set_attr "length" "4") + (set_attr "type" "int,gload,gstore")]) + +(define_insn "*cond_exec_si_binary1" + [(cond_exec + (match_operator 0 "ccr_eqne_operator" + [(match_operand 1 "cr_operand" "C") + (const_int 0)]) + (set (match_operand:SI 2 "integer_register_operand" "=d") + (match_operator:SI 3 "condexec_si_binary_operator" + [(match_operand:SI 4 "integer_register_operand" "d") + (match_operand:SI 5 "integer_register_operand" "d")])))] + "" + "* +{ + switch (GET_CODE (operands[3])) + { + case PLUS: return \"cadd %4, %z5, %2, %1, %e0\"; + case MINUS: return \"csub %4, %z5, %2, %1, %e0\"; + case AND: return \"cand %4, %z5, %2, %1, %e0\"; + case IOR: return \"cor %4, %z5, %2, %1, %e0\"; + case XOR: return \"cxor %4, %z5, %2, %1, %e0\"; + case ASHIFT: return \"csll %4, %z5, %2, %1, %e0\"; + case ASHIFTRT: return \"csra %4, %z5, %2, %1, %e0\"; + case LSHIFTRT: return \"csrl %4, %z5, %2, %1, %e0\"; + default: gcc_unreachable (); + } +}" + [(set_attr "length" "4") + (set_attr "type" "int")]) + +(define_insn "*cond_exec_si_binary2" + [(cond_exec + (match_operator 0 "ccr_eqne_operator" + [(match_operand 1 "cr_operand" "C") + (const_int 0)]) + (set (match_operand:SI 2 "fpr_operand" "=f") + (match_operator:SI 3 "condexec_si_media_operator" + [(match_operand:SI 4 "fpr_operand" "f") + (match_operand:SI 5 "fpr_operand" "f")])))] + "TARGET_MEDIA" + "* +{ + switch (GET_CODE (operands[3])) + { + case AND: return \"cmand %4, %5, %2, %1, %e0\"; + case IOR: return \"cmor %4, %5, %2, %1, %e0\"; + case XOR: return \"cmxor %4, %5, %2, %1, %e0\"; + default: gcc_unreachable (); + } +}" + [(set_attr "length" "4") + (set_attr "type" "mlogic")]) + +;; Note, flow does not (currently) know how to handle an operation that uses +;; only part of the hard registers allocated for a multiregister value, such as +;; DImode in this case if the user is only interested in the lower 32-bits. So +;; we emit a USE of the entire register after the csmul instruction so it won't +;; get confused. See frv_ifcvt_modify_insn for more details. + +(define_insn "*cond_exec_si_smul" + [(cond_exec + (match_operator 0 "ccr_eqne_operator" + [(match_operand 1 "cr_operand" "C") + (const_int 0)]) + (set (match_operand:DI 2 "even_gpr_operand" "=e") + (mult:DI (sign_extend:DI (match_operand:SI 3 "integer_register_operand" "%d")) + (sign_extend:DI (match_operand:SI 4 "integer_register_operand" "d")))))] + "" + "csmul %3, %4, %2, %1, %e0" + [(set_attr "length" "4") + (set_attr "type" "mul")]) + +(define_insn "*cond_exec_si_divide" + [(cond_exec + (match_operator 0 "ccr_eqne_operator" + [(match_operand 1 "cr_operand" "C") + (const_int 0)]) + (set (match_operand:SI 2 "integer_register_operand" "=d") + (match_operator:SI 3 "condexec_si_divide_operator" + [(match_operand:SI 4 "integer_register_operand" "d") + (match_operand:SI 5 "integer_register_operand" "d")])))] + "" + "* +{ + switch (GET_CODE (operands[3])) + { + case DIV: return \"csdiv %4, %z5, %2, %1, %e0\"; + case UDIV: return \"cudiv %4, %z5, %2, %1, %e0\"; + default: gcc_unreachable (); + } +}" + [(set_attr "length" "4") + (set_attr "type" "div")]) + +(define_insn "*cond_exec_si_unary1" + [(cond_exec + (match_operator 0 "ccr_eqne_operator" + [(match_operand 1 "cr_operand" "C") + (const_int 0)]) + (set (match_operand:SI 2 "integer_register_operand" "=d") + (match_operator:SI 3 "condexec_si_unary_operator" + [(match_operand:SI 4 "integer_register_operand" "d")])))] + "" + "* +{ + switch (GET_CODE (operands[3])) + { + case NOT: return \"cnot %4, %2, %1, %e0\"; + case NEG: return \"csub %., %4, %2, %1, %e0\"; + default: gcc_unreachable (); + } +}" + [(set_attr "length" "4") + (set_attr "type" "int")]) + +(define_insn "*cond_exec_si_unary2" + [(cond_exec + (match_operator 0 "ccr_eqne_operator" + [(match_operand 1 "cr_operand" "C") + (const_int 0)]) + (set (match_operand:SI 2 "fpr_operand" "=f") + (not:SI (match_operand:SI 3 "fpr_operand" "f"))))] + "TARGET_MEDIA" + "cmnot %3, %2, %1, %e0" + [(set_attr "length" "4") + (set_attr "type" "mlogic")]) + +(define_insn "*cond_exec_cmpsi_cc" + [(cond_exec + (match_operator 0 "ccr_eqne_operator" + [(match_operand 1 "cr_operand" "C") + (const_int 0)]) + (set (match_operand:CC 2 "icc_operand" "=t") + (compare:CC (match_operand:SI 3 "integer_register_operand" "d") + (match_operand:SI 4 "reg_or_0_operand" "dO"))))] + "reload_completed + && REGNO (operands[1]) == REGNO (operands[2]) - ICC_FIRST + ICR_FIRST" + "ccmp %3, %z4, %1, %e0" + [(set_attr "length" "4") + (set_attr "type" "int")]) + +(define_insn "*cond_exec_cmpsi_cc_uns" + [(cond_exec + (match_operator 0 "ccr_eqne_operator" + [(match_operand 1 "cr_operand" "C") + (const_int 0)]) + (set (match_operand:CC_UNS 2 "icc_operand" "=t") + (compare:CC_UNS (match_operand:SI 3 "integer_register_operand" "d") + (match_operand:SI 4 "reg_or_0_operand" "dO"))))] + "reload_completed + && REGNO (operands[1]) == REGNO (operands[2]) - ICC_FIRST + ICR_FIRST" + "ccmp %3, %z4, %1, %e0" + [(set_attr "length" "4") + (set_attr "type" "int")]) + +(define_insn "*cond_exec_cmpsi_cc_nz" + [(cond_exec + (match_operator 0 "ccr_eqne_operator" + [(match_operand 1 "cr_operand" "C") + (const_int 0)]) + (set (match_operand:CC_NZ 2 "icc_operand" "=t") + (compare:CC_NZ (match_operand:SI 3 "integer_register_operand" "d") + (const_int 0))))] + "reload_completed + && REGNO (operands[1]) == REGNO (operands[2]) - ICC_FIRST + ICR_FIRST" + "ccmp %3, %., %1, %e0" + [(set_attr "length" "4") + (set_attr "type" "int")]) + +(define_insn "*cond_exec_sf_conv" + [(cond_exec + (match_operator 0 "ccr_eqne_operator" + [(match_operand 1 "cr_operand" "C") + (const_int 0)]) + (set (match_operand:SF 2 "fpr_operand" "=f") + (match_operator:SF 3 "condexec_sf_conv_operator" + [(match_operand:SF 4 "fpr_operand" "f")])))] + "TARGET_HARD_FLOAT" + "* +{ + switch (GET_CODE (operands[3])) + { + case ABS: return \"cfabss %4, %2, %1, %e0\"; + case NEG: return \"cfnegs %4, %2, %1, %e0\"; + default: gcc_unreachable (); + } +}" + [(set_attr "length" "4") + (set_attr "type" "fsconv")]) + +(define_insn "*cond_exec_sf_add" + [(cond_exec + (match_operator 0 "ccr_eqne_operator" + [(match_operand 1 "cr_operand" "C") + (const_int 0)]) + (set (match_operand:SF 2 "fpr_operand" "=f") + (match_operator:SF 3 "condexec_sf_add_operator" + [(match_operand:SF 4 "fpr_operand" "f") + (match_operand:SF 5 "fpr_operand" "f")])))] + "TARGET_HARD_FLOAT" + "* +{ + switch (GET_CODE (operands[3])) + { + case PLUS: return \"cfadds %4, %5, %2, %1, %e0\"; + case MINUS: return \"cfsubs %4, %5, %2, %1, %e0\"; + default: gcc_unreachable (); + } +}" + [(set_attr "length" "4") + (set_attr "type" "fsadd")]) + +(define_insn "*cond_exec_sf_mul" + [(cond_exec + (match_operator 0 "ccr_eqne_operator" + [(match_operand 1 "cr_operand" "C") + (const_int 0)]) + (set (match_operand:SF 2 "fpr_operand" "=f") + (mult:SF (match_operand:SF 3 "fpr_operand" "f") + (match_operand:SF 4 "fpr_operand" "f"))))] + "TARGET_HARD_FLOAT" + "cfmuls %3, %4, %2, %1, %e0" + [(set_attr "length" "4") + (set_attr "type" "fsmul")]) + +(define_insn "*cond_exec_sf_div" + [(cond_exec + (match_operator 0 "ccr_eqne_operator" + [(match_operand 1 "cr_operand" "C") + (const_int 0)]) + (set (match_operand:SF 2 "fpr_operand" "=f") + (div:SF (match_operand:SF 3 "fpr_operand" "f") + (match_operand:SF 4 "fpr_operand" "f"))))] + "TARGET_HARD_FLOAT" + "cfdivs %3, %4, %2, %1, %e0" + [(set_attr "length" "4") + (set_attr "type" "fsdiv")]) + +(define_insn "*cond_exec_sf_sqrt" + [(cond_exec + (match_operator 0 "ccr_eqne_operator" + [(match_operand 1 "cr_operand" "C") + (const_int 0)]) + (set (match_operand:SF 2 "fpr_operand" "=f") + (sqrt:SF (match_operand:SF 3 "fpr_operand" "f"))))] + "TARGET_HARD_FLOAT" + "cfsqrts %3, %2, %1, %e0" + [(set_attr "length" "4") + (set_attr "type" "fsdiv")]) + +(define_insn "*cond_exec_cmpsi_cc_fp" + [(cond_exec + (match_operator 0 "ccr_eqne_operator" + [(match_operand 1 "cr_operand" "C") + (const_int 0)]) + (set (match_operand:CC_FP 2 "fcc_operand" "=u") + (compare:CC_FP (match_operand:SF 3 "fpr_operand" "f") + (match_operand:SF 4 "fpr_operand" "f"))))] + "reload_completed && TARGET_HARD_FLOAT + && REGNO (operands[1]) == REGNO (operands[2]) - FCC_FIRST + FCR_FIRST" + "cfcmps %3, %4, %2, %1, %e0" + [(set_attr "length" "4") + (set_attr "type" "fsconv")]) + + +;; :::::::::::::::::::: +;; :: +;; :: Logical operations on CR registers +;; :: +;; :::::::::::::::::::: + +;; We use UNSPEC to encode andcr/iorcr/etc. rather than the normal RTL +;; operations, since the RTL operations only have an idea of TRUE and FALSE, +;; while the CRs have TRUE, FALSE, and UNDEFINED. + +(define_expand "andcr" + [(set (match_operand:CC_CCR 0 "cr_operand" "") + (unspec:CC_CCR [(match_operand:CC_CCR 1 "cr_operand" "") + (match_operand:CC_CCR 2 "cr_operand" "") + (const_int 0)] UNSPEC_CR_LOGIC))] + "" + "") + +(define_expand "orcr" + [(set (match_operand:CC_CCR 0 "cr_operand" "") + (unspec:CC_CCR [(match_operand:CC_CCR 1 "cr_operand" "") + (match_operand:CC_CCR 2 "cr_operand" "") + (const_int 1)] UNSPEC_CR_LOGIC))] + "" + "") + +(define_expand "xorcr" + [(set (match_operand:CC_CCR 0 "cr_operand" "") + (unspec:CC_CCR [(match_operand:CC_CCR 1 "cr_operand" "") + (match_operand:CC_CCR 2 "cr_operand" "") + (const_int 2)] UNSPEC_CR_LOGIC))] + "" + "") + +(define_expand "nandcr" + [(set (match_operand:CC_CCR 0 "cr_operand" "") + (unspec:CC_CCR [(match_operand:CC_CCR 1 "cr_operand" "") + (match_operand:CC_CCR 2 "cr_operand" "") + (const_int 3)] UNSPEC_CR_LOGIC))] + "" + "") + +(define_expand "norcr" + [(set (match_operand:CC_CCR 0 "cr_operand" "") + (unspec:CC_CCR [(match_operand:CC_CCR 1 "cr_operand" "") + (match_operand:CC_CCR 2 "cr_operand" "") + (const_int 4)] UNSPEC_CR_LOGIC))] + "" + "") + +(define_expand "andncr" + [(set (match_operand:CC_CCR 0 "cr_operand" "") + (unspec:CC_CCR [(match_operand:CC_CCR 1 "cr_operand" "") + (match_operand:CC_CCR 2 "cr_operand" "") + (const_int 5)] UNSPEC_CR_LOGIC))] + "" + "") + +(define_expand "orncr" + [(set (match_operand:CC_CCR 0 "cr_operand" "") + (unspec:CC_CCR [(match_operand:CC_CCR 1 "cr_operand" "") + (match_operand:CC_CCR 2 "cr_operand" "") + (const_int 6)] UNSPEC_CR_LOGIC))] + "" + "") + +(define_expand "nandncr" + [(set (match_operand:CC_CCR 0 "cr_operand" "") + (unspec:CC_CCR [(match_operand:CC_CCR 1 "cr_operand" "") + (match_operand:CC_CCR 2 "cr_operand" "") + (const_int 7)] UNSPEC_CR_LOGIC))] + "" + "") + +(define_expand "norncr" + [(set (match_operand:CC_CCR 0 "cr_operand" "") + (unspec:CC_CCR [(match_operand:CC_CCR 1 "cr_operand" "") + (match_operand:CC_CCR 2 "cr_operand" "") + (const_int 8)] UNSPEC_CR_LOGIC))] + "" + "") + +(define_expand "notcr" + [(set (match_operand:CC_CCR 0 "cr_operand" "") + (unspec:CC_CCR [(match_operand:CC_CCR 1 "cr_operand" "") + (match_dup 1) + (const_int 9)] UNSPEC_CR_LOGIC))] + "" + "") + +(define_insn "*logical_cr" + [(set (match_operand:CC_CCR 0 "cr_operand" "=C") + (unspec:CC_CCR [(match_operand:CC_CCR 1 "cr_operand" "C") + (match_operand:CC_CCR 2 "cr_operand" "C") + (match_operand:SI 3 "const_int_operand" "n")] + UNSPEC_CR_LOGIC))] + "" + "* +{ + switch (INTVAL (operands[3])) + { + default: break; + case 0: return \"andcr %1, %2, %0\"; + case 1: return \"orcr %1, %2, %0\"; + case 2: return \"xorcr %1, %2, %0\"; + case 3: return \"nandcr %1, %2, %0\"; + case 4: return \"norcr %1, %2, %0\"; + case 5: return \"andncr %1, %2, %0\"; + case 6: return \"orncr %1, %2, %0\"; + case 7: return \"nandncr %1, %2, %0\"; + case 8: return \"norncr %1, %2, %0\"; + case 9: return \"notcr %1, %0\"; + } + + fatal_insn (\"logical_cr\", insn); +}" + [(set_attr "length" "4") + (set_attr "type" "ccr")]) + + +;; :::::::::::::::::::: +;; :: +;; :: Conditional move instructions +;; :: +;; :::::::::::::::::::: + + +;; - conditional moves based on floating-point comparisons require +;; TARGET_HARD_FLOAT, because an FPU is required to do the comparison. + +;; - conditional moves between FPRs based on integer comparisons +;; require TARGET_HAS_FPRS. + +(define_expand "movqicc" + [(set (match_operand:QI 0 "integer_register_operand" "") + (if_then_else:QI (match_operand 1 "" "") + (match_operand:QI 2 "gpr_or_int_operand" "") + (match_operand:QI 3 "gpr_or_int_operand" "")))] + "TARGET_COND_MOVE" + " +{ + if (!frv_emit_cond_move (operands[0], operands[1], operands[2], operands[3])) + FAIL; + + DONE; +}") + +(define_insn "*movqicc_internal1_int" + [(set (match_operand:QI 0 "integer_register_operand" "=d,d,d") + (if_then_else:QI (match_operator 1 "integer_relational_operator" + [(match_operand 2 "icc_operand" "t,t,t") + (const_int 0)]) + (match_operand:QI 3 "reg_or_0_operand" "0,dO,dO") + (match_operand:QI 4 "reg_or_0_operand" "dO,0,dO"))) + (clobber (match_operand:CC_CCR 5 "icr_operand" "=v,v,v"))] + "" + "#" + [(set_attr "length" "8,8,12") + (set_attr "type" "multi")]) + +(define_insn "*movqicc_internal1_float" + [(set (match_operand:QI 0 "integer_register_operand" "=d,d,d") + (if_then_else:QI (match_operator:CC_FP 1 "float_relational_operator" + [(match_operand:CC_FP 2 "fcc_operand" "u,u,u") + (const_int 0)]) + (match_operand:QI 3 "reg_or_0_operand" "0,dO,dO") + (match_operand:QI 4 "reg_or_0_operand" "dO,0,dO"))) + (clobber (match_operand:CC_CCR 5 "fcr_operand" "=w,w,w"))] + "TARGET_HARD_FLOAT" + "#" + [(set_attr "length" "8,8,12") + (set_attr "type" "multi")]) + +(define_insn "*movqicc_internal2_int" + [(set (match_operand:QI 0 "integer_register_operand" "=d,d,d,d,d") + (if_then_else:QI (match_operator 1 "integer_relational_operator" + [(match_operand 2 "icc_operand" "t,t,t,t,t") + (const_int 0)]) + (match_operand:QI 3 "const_int_operand" "O,O,L,n,n") + (match_operand:QI 4 "const_int_operand" "L,n,O,O,n"))) + (clobber (match_operand:CC_CCR 5 "icr_operand" "=v,v,v,v,v"))] + "(INTVAL (operands[3]) == 0 + || INTVAL (operands[4]) == 0 + || (IN_RANGE_P (INTVAL (operands[3]), -2048, 2047) + && IN_RANGE_P (INTVAL (operands[4]) - INTVAL (operands[3]), -2048, 2047)))" + "#" + [(set_attr "length" "8,12,8,12,12") + (set_attr "type" "multi")]) + +(define_insn "*movqicc_internal2_float" + [(set (match_operand:QI 0 "integer_register_operand" "=d,d,d,d,d") + (if_then_else:QI (match_operator:CC_FP 1 "float_relational_operator" + [(match_operand:CC_FP 2 "fcc_operand" "u,u,u,u,u") + (const_int 0)]) + (match_operand:QI 3 "const_int_operand" "O,O,L,n,n") + (match_operand:QI 4 "const_int_operand" "L,n,O,O,n"))) + (clobber (match_operand:CC_CCR 5 "fcr_operand" "=w,w,w,w,w"))] + "TARGET_HARD_FLOAT + && (INTVAL (operands[3]) == 0 + || INTVAL (operands[4]) == 0 + || (IN_RANGE_P (INTVAL (operands[3]), -2048, 2047) + && IN_RANGE_P (INTVAL (operands[4]) - INTVAL (operands[3]), -2048, 2047)))" + "#" + [(set_attr "length" "8,12,8,12,12") + (set_attr "type" "multi")]) + +(define_split + [(set (match_operand:QI 0 "integer_register_operand" "") + (if_then_else:QI (match_operator 1 "relational_operator" + [(match_operand 2 "cc_operand" "") + (const_int 0)]) + (match_operand:QI 3 "gpr_or_int_operand" "") + (match_operand:QI 4 "gpr_or_int_operand" ""))) + (clobber (match_operand:CC_CCR 5 "cr_operand" ""))] + "reload_completed" + [(match_dup 6)] + "operands[6] = frv_split_cond_move (operands);") + +(define_expand "movhicc" + [(set (match_operand:HI 0 "integer_register_operand" "") + (if_then_else:HI (match_operand 1 "" "") + (match_operand:HI 2 "gpr_or_int_operand" "") + (match_operand:HI 3 "gpr_or_int_operand" "")))] + "TARGET_COND_MOVE" + " +{ + if (!frv_emit_cond_move (operands[0], operands[1], operands[2], operands[3])) + FAIL; + + DONE; +}") + +(define_insn "*movhicc_internal1_int" + [(set (match_operand:HI 0 "integer_register_operand" "=d,d,d") + (if_then_else:HI (match_operator 1 "integer_relational_operator" + [(match_operand 2 "icc_operand" "t,t,t") + (const_int 0)]) + (match_operand:HI 3 "reg_or_0_operand" "0,dO,dO") + (match_operand:HI 4 "reg_or_0_operand" "dO,0,dO"))) + (clobber (match_operand:CC_CCR 5 "icr_operand" "=v,v,v"))] + "" + "#" + [(set_attr "length" "8,8,12") + (set_attr "type" "multi")]) + +(define_insn "*movhicc_internal1_float" + [(set (match_operand:HI 0 "integer_register_operand" "=d,d,d") + (if_then_else:HI (match_operator:CC_FP 1 "float_relational_operator" + [(match_operand:CC_FP 2 "fcc_operand" "u,u,u") + (const_int 0)]) + (match_operand:HI 3 "reg_or_0_operand" "0,dO,dO") + (match_operand:HI 4 "reg_or_0_operand" "dO,0,dO"))) + (clobber (match_operand:CC_CCR 5 "fcr_operand" "=w,w,w"))] + "TARGET_HARD_FLOAT" + "#" + [(set_attr "length" "8,8,12") + (set_attr "type" "multi")]) + +(define_insn "*movhicc_internal2_int" + [(set (match_operand:HI 0 "integer_register_operand" "=d,d,d,d,d") + (if_then_else:HI (match_operator 1 "integer_relational_operator" + [(match_operand 2 "icc_operand" "t,t,t,t,t") + (const_int 0)]) + (match_operand:HI 3 "const_int_operand" "O,O,L,n,n") + (match_operand:HI 4 "const_int_operand" "L,n,O,O,n"))) + (clobber (match_operand:CC_CCR 5 "icr_operand" "=v,v,v,v,v"))] + "(INTVAL (operands[3]) == 0 + || INTVAL (operands[4]) == 0 + || (IN_RANGE_P (INTVAL (operands[3]), -2048, 2047) + && IN_RANGE_P (INTVAL (operands[4]) - INTVAL (operands[3]), -2048, 2047)))" + "#" + [(set_attr "length" "8,12,8,12,12") + (set_attr "type" "multi")]) + +(define_insn "*movhicc_internal2_float" + [(set (match_operand:HI 0 "integer_register_operand" "=d,d,d,d,d") + (if_then_else:HI (match_operator:CC_FP 1 "float_relational_operator" + [(match_operand:CC_FP 2 "fcc_operand" "u,u,u,u,u") + (const_int 0)]) + (match_operand:HI 3 "const_int_operand" "O,O,L,n,n") + (match_operand:HI 4 "const_int_operand" "L,n,O,O,n"))) + (clobber (match_operand:CC_CCR 5 "fcr_operand" "=w,w,w,w,w"))] + "TARGET_HARD_FLOAT + && (INTVAL (operands[3]) == 0 + || INTVAL (operands[4]) == 0 + || (IN_RANGE_P (INTVAL (operands[3]), -2048, 2047) + && IN_RANGE_P (INTVAL (operands[4]) - INTVAL (operands[3]), -2048, 2047)))" + "#" + [(set_attr "length" "8,12,8,12,12") + (set_attr "type" "multi")]) + +(define_split + [(set (match_operand:HI 0 "integer_register_operand" "") + (if_then_else:HI (match_operator 1 "relational_operator" + [(match_operand 2 "cc_operand" "") + (const_int 0)]) + (match_operand:HI 3 "gpr_or_int_operand" "") + (match_operand:HI 4 "gpr_or_int_operand" ""))) + (clobber (match_operand:CC_CCR 5 "cr_operand" ""))] + "reload_completed" + [(match_dup 6)] + "operands[6] = frv_split_cond_move (operands);") + +(define_expand "movsicc" + [(set (match_operand:SI 0 "integer_register_operand" "") + (if_then_else:SI (match_operand 1 "" "") + (match_operand:SI 2 "gpr_or_int_operand" "") + (match_operand:SI 3 "gpr_or_int_operand" "")))] + "TARGET_COND_MOVE" + " +{ + if (!frv_emit_cond_move (operands[0], operands[1], operands[2], operands[3])) + FAIL; + + DONE; +}") + +(define_insn "*movsicc_internal1_int" + [(set (match_operand:SI 0 "integer_register_operand" "=d,d,d") + (if_then_else:SI (match_operator 1 "integer_relational_operator" + [(match_operand 2 "icc_operand" "t,t,t") + (const_int 0)]) + (match_operand:SI 3 "reg_or_0_operand" "0,dO,dO") + (match_operand:SI 4 "reg_or_0_operand" "dO,0,dO"))) + (clobber (match_operand:CC_CCR 5 "icr_operand" "=v,v,v"))] + "" + "#" + [(set_attr "length" "8,8,12") + (set_attr "type" "multi")]) + +(define_insn "*movsicc_internal1_float" + [(set (match_operand:SI 0 "integer_register_operand" "=d,d,d") + (if_then_else:SI (match_operator:CC_FP 1 "float_relational_operator" + [(match_operand:CC_FP 2 "fcc_operand" "u,u,u") + (const_int 0)]) + (match_operand:SI 3 "reg_or_0_operand" "0,dO,dO") + (match_operand:SI 4 "reg_or_0_operand" "dO,0,dO"))) + (clobber (match_operand:CC_CCR 5 "fcr_operand" "=w,w,w"))] + "TARGET_HARD_FLOAT" + "#" + [(set_attr "length" "8,8,12") + (set_attr "type" "multi")]) + +(define_insn "*movsicc_internal2_int" + [(set (match_operand:SI 0 "integer_register_operand" "=d,d,d,d,d") + (if_then_else:SI (match_operator 1 "integer_relational_operator" + [(match_operand 2 "icc_operand" "t,t,t,t,t") + (const_int 0)]) + (match_operand:SI 3 "const_int_operand" "O,O,L,n,n") + (match_operand:SI 4 "const_int_operand" "L,n,O,O,n"))) + (clobber (match_operand:CC_CCR 5 "icr_operand" "=v,v,v,v,v"))] + "(INTVAL (operands[3]) == 0 + || INTVAL (operands[4]) == 0 + || (IN_RANGE_P (INTVAL (operands[3]), -2048, 2047) + && IN_RANGE_P (INTVAL (operands[4]) - INTVAL (operands[3]), -2048, 2047)))" + "#" + [(set_attr "length" "8,12,8,12,12") + (set_attr "type" "multi")]) + +(define_insn "*movsicc_internal2_float" + [(set (match_operand:SI 0 "integer_register_operand" "=d,d,d,d,d") + (if_then_else:SI (match_operator:CC_FP 1 "float_relational_operator" + [(match_operand:CC_FP 2 "fcc_operand" "u,u,u,u,u") + (const_int 0)]) + (match_operand:SI 3 "const_int_operand" "O,O,L,n,n") + (match_operand:SI 4 "const_int_operand" "L,n,O,O,n"))) + (clobber (match_operand:CC_CCR 5 "fcr_operand" "=w,w,w,w,w"))] + "TARGET_HARD_FLOAT + && (INTVAL (operands[3]) == 0 + || INTVAL (operands[4]) == 0 + || (IN_RANGE_P (INTVAL (operands[3]), -2048, 2047) + && IN_RANGE_P (INTVAL (operands[4]) - INTVAL (operands[3]), -2048, 2047)))" + "#" + [(set_attr "length" "8,12,8,12,12") + (set_attr "type" "multi")]) + +(define_split + [(set (match_operand:SI 0 "integer_register_operand" "") + (if_then_else:SI (match_operator 1 "relational_operator" + [(match_operand 2 "cc_operand" "") + (const_int 0)]) + (match_operand:SI 3 "gpr_or_int_operand" "") + (match_operand:SI 4 "gpr_or_int_operand" ""))) + (clobber (match_operand:CC_CCR 5 "cr_operand" ""))] + "reload_completed" + [(match_dup 6)] + "operands[6] = frv_split_cond_move (operands);") + +(define_expand "movsfcc" + [(set (match_operand:SF 0 "register_operand" "") + (if_then_else:SF (match_operand 1 "" "") + (match_operand:SF 2 "register_operand" "") + (match_operand:SF 3 "register_operand" "")))] + "TARGET_COND_MOVE" + " +{ + if (!frv_emit_cond_move (operands[0], operands[1], operands[2], operands[3])) + FAIL; + + DONE; +}") + +(define_insn "*movsfcc_has_fprs_int" + [(set (match_operand:SF 0 "register_operand" "=f,f,f,?f,?f,?d") + (if_then_else:SF (match_operator 1 "integer_relational_operator" + [(match_operand 2 "icc_operand" "t,t,t,t,t,t") + (const_int 0)]) + (match_operand:SF 3 "register_operand" "0,f,f,f,d,fd") + (match_operand:SF 4 "register_operand" "f,0,f,d,fd,fd"))) + (clobber (match_operand:CC_CCR 5 "icr_operand" "=v,v,v,v,v,v"))] + "TARGET_HAS_FPRS" + "#" + [(set_attr "length" "8,8,12,12,12,12") + (set_attr "type" "multi")]) + +(define_insn "*movsfcc_hardfloat_float" + [(set (match_operand:SF 0 "register_operand" "=f,f,f,?f,?f,?d") + (if_then_else:SF (match_operator:CC_FP 1 "float_relational_operator" + [(match_operand:CC_FP 2 "fcc_operand" "u,u,u,u,u,u") + (const_int 0)]) + (match_operand:SF 3 "register_operand" "0,f,f,f,d,fd") + (match_operand:SF 4 "register_operand" "f,0,f,d,fd,fd"))) + (clobber (match_operand:CC_CCR 5 "fcr_operand" "=w,w,w,w,w,w"))] + "TARGET_HARD_FLOAT" + "#" + [(set_attr "length" "8,8,12,12,12,12") + (set_attr "type" "multi")]) + +(define_insn "*movsfcc_no_fprs_int" + [(set (match_operand:SF 0 "integer_register_operand" "=d,d,d") + (if_then_else:SF (match_operator 1 "integer_relational_operator" + [(match_operand 2 "icc_operand" "t,t,t") + (const_int 0)]) + (match_operand:SF 3 "integer_register_operand" "0,d,d") + (match_operand:SF 4 "integer_register_operand" "d,0,d"))) + (clobber (match_operand:CC_CCR 5 "icr_operand" "=v,v,v"))] + "! TARGET_HAS_FPRS" + "#" + [(set_attr "length" "8,8,12") + (set_attr "type" "multi")]) + +(define_split + [(set (match_operand:SF 0 "register_operand" "") + (if_then_else:SF (match_operator 1 "relational_operator" + [(match_operand 2 "cc_operand" "") + (const_int 0)]) + (match_operand:SF 3 "register_operand" "") + (match_operand:SF 4 "register_operand" ""))) + (clobber (match_operand:CC_CCR 5 "cr_operand" ""))] + "reload_completed" + [(match_dup 6)] + "operands[6] = frv_split_cond_move (operands);") + + +;; :::::::::::::::::::: +;; :: +;; :: Minimum, maximum, and integer absolute value +;; :: +;; :::::::::::::::::::: + +;; These 'instructions' are provided to give the compiler a slightly better +;; nudge at register allocation, then it would if it constructed the +;; instructions from basic building blocks (since it indicates it prefers one +;; of the operands to be the same as the destination. It also helps the +;; earlier passes of the compiler, by not breaking things into small basic +;; blocks. + +(define_expand "abssi2" + [(parallel [(set (match_operand:SI 0 "integer_register_operand" "") + (abs:SI (match_operand:SI 1 "integer_register_operand" ""))) + (clobber (match_dup 2)) + (clobber (match_dup 3))])] + "TARGET_COND_MOVE" + " +{ + operands[2] = gen_reg_rtx (CCmode); + operands[3] = gen_reg_rtx (CC_CCRmode); +}") + +(define_insn_and_split "*abssi2_internal" + [(set (match_operand:SI 0 "integer_register_operand" "=d,d") + (abs:SI (match_operand:SI 1 "integer_register_operand" "0,d"))) + (clobber (match_operand:CC 2 "icc_operand" "=t,t")) + (clobber (match_operand:CC_CCR 3 "icr_operand" "=v,v"))] + "TARGET_COND_MOVE" + "#" + "reload_completed" + [(match_dup 4)] + "operands[4] = frv_split_abs (operands);" + [(set_attr "length" "12,16") + (set_attr "type" "multi")]) + +(define_expand "sminsi3" + [(parallel [(set (match_operand:SI 0 "integer_register_operand" "") + (smin:SI (match_operand:SI 1 "integer_register_operand" "") + (match_operand:SI 2 "gpr_or_int10_operand" ""))) + (clobber (match_dup 3)) + (clobber (match_dup 4))])] + "TARGET_COND_MOVE" + " +{ + operands[3] = gen_reg_rtx (CCmode); + operands[4] = gen_reg_rtx (CC_CCRmode); +}") + +(define_expand "smaxsi3" + [(parallel [(set (match_operand:SI 0 "integer_register_operand" "") + (smax:SI (match_operand:SI 1 "integer_register_operand" "") + (match_operand:SI 2 "gpr_or_int10_operand" ""))) + (clobber (match_dup 3)) + (clobber (match_dup 4))])] + "TARGET_COND_MOVE" + " +{ + operands[3] = gen_reg_rtx (CCmode); + operands[4] = gen_reg_rtx (CC_CCRmode); +}") + +(define_insn_and_split "*minmax_si_signed" + [(set (match_operand:SI 0 "integer_register_operand" "=d,d,&d") + (match_operator:SI 1 "minmax_operator" + [(match_operand:SI 2 "integer_register_operand" "%0,dO,d") + (match_operand:SI 3 "gpr_or_int10_operand" "dO,0,dJ")])) + (clobber (match_operand:CC 4 "icc_operand" "=t,t,t")) + (clobber (match_operand:CC_CCR 5 "icr_operand" "=v,v,v"))] + "TARGET_COND_MOVE" + "#" + "reload_completed" + [(match_dup 6)] + "operands[6] = frv_split_minmax (operands);" + [(set_attr "length" "12,12,16") + (set_attr "type" "multi")]) + +(define_expand "uminsi3" + [(parallel [(set (match_operand:SI 0 "integer_register_operand" "") + (umin:SI (match_operand:SI 1 "integer_register_operand" "") + (match_operand:SI 2 "gpr_or_int10_operand" ""))) + (clobber (match_dup 3)) + (clobber (match_dup 4))])] + "TARGET_COND_MOVE" + " +{ + operands[3] = gen_reg_rtx (CC_UNSmode); + operands[4] = gen_reg_rtx (CC_CCRmode); +}") + +(define_expand "umaxsi3" + [(parallel [(set (match_operand:SI 0 "integer_register_operand" "") + (umax:SI (match_operand:SI 1 "integer_register_operand" "") + (match_operand:SI 2 "gpr_or_int10_operand" ""))) + (clobber (match_dup 3)) + (clobber (match_dup 4))])] + "TARGET_COND_MOVE" + " +{ + operands[3] = gen_reg_rtx (CC_UNSmode); + operands[4] = gen_reg_rtx (CC_CCRmode); +}") + +(define_insn_and_split "*minmax_si_unsigned" + [(set (match_operand:SI 0 "integer_register_operand" "=d,d,&d") + (match_operator:SI 1 "minmax_operator" + [(match_operand:SI 2 "integer_register_operand" "%0,dO,d") + (match_operand:SI 3 "gpr_or_int10_operand" "dO,0,dJ")])) + (clobber (match_operand:CC_UNS 4 "icc_operand" "=t,t,t")) + (clobber (match_operand:CC_CCR 5 "icr_operand" "=v,v,v"))] + "TARGET_COND_MOVE" + "#" + "reload_completed" + [(match_dup 6)] + "operands[6] = frv_split_minmax (operands);" + [(set_attr "length" "12,12,16") + (set_attr "type" "multi")]) + +(define_expand "sminsf3" + [(parallel [(set (match_operand:SF 0 "fpr_operand" "") + (smin:SF (match_operand:SF 1 "fpr_operand" "") + (match_operand:SF 2 "fpr_operand" ""))) + (clobber (match_dup 3)) + (clobber (match_dup 4))])] + "TARGET_COND_MOVE && TARGET_HARD_FLOAT" + " +{ + operands[3] = gen_reg_rtx (CC_FPmode); + operands[4] = gen_reg_rtx (CC_CCRmode); +}") + +(define_expand "smaxsf3" + [(parallel [(set (match_operand:SF 0 "fpr_operand" "") + (smax:SF (match_operand:SF 1 "fpr_operand" "") + (match_operand:SF 2 "fpr_operand" ""))) + (clobber (match_dup 3)) + (clobber (match_dup 4))])] + "TARGET_COND_MOVE && TARGET_HARD_FLOAT" + " +{ + operands[3] = gen_reg_rtx (CC_FPmode); + operands[4] = gen_reg_rtx (CC_CCRmode); +}") + +(define_insn_and_split "*minmax_sf" + [(set (match_operand:SF 0 "fpr_operand" "=f,f,f") + (match_operator:SF 1 "minmax_operator" + [(match_operand:SF 2 "fpr_operand" "%0,f,f") + (match_operand:SF 3 "fpr_operand" "f,0,f")])) + (clobber (match_operand:CC_FP 4 "fcc_operand" "=u,u,u")) + (clobber (match_operand:CC_CCR 5 "fcr_operand" "=w,w,w"))] + "TARGET_COND_MOVE && TARGET_HARD_FLOAT" + "#" + "reload_completed" + [(match_dup 6)] + "operands[6] = frv_split_minmax (operands);" + [(set_attr "length" "12,12,16") + (set_attr "type" "multi")]) + +(define_expand "smindf3" + [(parallel [(set (match_operand:DF 0 "fpr_operand" "") + (smin:DF (match_operand:DF 1 "fpr_operand" "") + (match_operand:DF 2 "fpr_operand" ""))) + (clobber (match_dup 3)) + (clobber (match_dup 4))])] + "TARGET_COND_MOVE && TARGET_HARD_FLOAT && TARGET_DOUBLE" + " +{ + operands[3] = gen_reg_rtx (CC_FPmode); + operands[4] = gen_reg_rtx (CC_CCRmode); +}") + +(define_expand "smaxdf3" + [(parallel [(set (match_operand:DF 0 "fpr_operand" "") + (smax:DF (match_operand:DF 1 "fpr_operand" "") + (match_operand:DF 2 "fpr_operand" ""))) + (clobber (match_dup 3)) + (clobber (match_dup 4))])] + "TARGET_COND_MOVE && TARGET_HARD_FLOAT && TARGET_DOUBLE" + " +{ + operands[3] = gen_reg_rtx (CC_FPmode); + operands[4] = gen_reg_rtx (CC_CCRmode); +}") + +(define_insn_and_split "*minmax_df" + [(set (match_operand:DF 0 "fpr_operand" "=f,f,f") + (match_operator:DF 1 "minmax_operator" + [(match_operand:DF 2 "fpr_operand" "%0,f,f") + (match_operand:DF 3 "fpr_operand" "f,0,f")])) + (clobber (match_operand:CC_FP 4 "fcc_operand" "=u,u,u")) + (clobber (match_operand:CC_CCR 5 "fcr_operand" "=w,w,w"))] + "TARGET_COND_MOVE && TARGET_HARD_FLOAT && TARGET_DOUBLE" + "#" + "reload_completed" + [(match_dup 6)] + "operands[6] = frv_split_minmax (operands);" + [(set_attr "length" "12,12,16") + (set_attr "type" "multi")]) + + +;; :::::::::::::::::::: +;; :: +;; :: 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" + [(use (match_operand:QI 0 "" "")) + (use (match_operand 1 "" "")) + (use (match_operand 2 "" "")) + (use (match_operand 3 "" ""))] + "" + " +{ + rtx lr = gen_rtx_REG (Pmode, LR_REGNO); + rtx addr; + + gcc_assert (GET_CODE (operands[0]) == MEM); + + addr = XEXP (operands[0], 0); + if (! call_operand (addr, Pmode)) + addr = force_reg (Pmode, addr); + + if (! operands[2]) + operands[2] = const0_rtx; + + if (TARGET_FDPIC) + frv_expand_fdpic_call (operands, false, false); + else + emit_call_insn (gen_call_internal (addr, operands[1], operands[2], lr)); + + DONE; +}") + +(define_insn "call_internal" + [(call (mem:QI (match_operand:SI 0 "call_operand" "S,dNOP")) + (match_operand 1 "" "")) + (use (match_operand 2 "" "")) + (clobber (match_operand:SI 3 "lr_operand" "=l,l"))] + "! TARGET_FDPIC" + "@ + call %0 + call%i0l %M0" + [(set_attr "length" "4") + (set_attr "type" "call,jumpl")]) + +;; The odd use of GR0 within the UNSPEC below prevents cseing or +;; hoisting function descriptor loads out of loops. This is almost +;; never desirable, since if we preserve the function descriptor in a +;; pair of registers, it takes two insns to move it to gr14/gr15, and +;; if it's in the stack, we just waste space with the store, since +;; we'll have to load back from memory anyway. And, in the worst +;; case, we may end up reusing a function descriptor still pointing at +;; a PLT entry, instead of to the resolved function, which means going +;; through the resolver for every call that uses the outdated value. +;; Bad! + +;; The explicit MEM inside the SPEC prevents the compiler from moving +;; the load before a branch after a NULL test, or before a store that +;; initializes a function descriptor. + +(define_insn "movdi_ldd" + [(set (match_operand:DI 0 "fdpic_fptr_operand" "=e") + (unspec:DI [(mem:DI (match_operand:SI 1 "ldd_address_operand" "p")) + (reg:SI 0)] UNSPEC_LDD))] + "" + "ldd%I1 %M1, %0" + [(set_attr "length" "4") + (set_attr "type" "gload")]) + +(define_insn "call_fdpicdi" + [(call (mem:QI (match_operand:DI 0 "fdpic_fptr_operand" "W")) + (match_operand 1 "" "")) + (clobber (match_operand:SI 2 "lr_operand" "=l"))] + "TARGET_FDPIC" + "call%i0l %M0" + [(set_attr "length" "4") + (set_attr "type" "jumpl")]) + +(define_insn "call_fdpicsi" + [(call (mem:QI (match_operand:SI 0 "call_operand" "S,dNOP")) + (match_operand 1 "" "")) + (use (match_operand 2 "" "")) + (use (match_operand:SI 3 "fdpic_operand" "Z,Z")) + (clobber (match_operand:SI 4 "lr_operand" "=l,l"))] + "TARGET_FDPIC" + "@ + call %0 + call%i0l %M0" + [(set_attr "length" "4") + (set_attr "type" "call,jumpl")]) + +(define_expand "sibcall" + [(use (match_operand:QI 0 "" "")) + (use (match_operand 1 "" "")) + (use (match_operand 2 "" "")) + (use (match_operand 3 "" ""))] + "" + " +{ + rtx addr; + + gcc_assert (GET_CODE (operands[0]) == MEM); + + addr = XEXP (operands[0], 0); + if (! sibcall_operand (addr, Pmode)) + addr = force_reg (Pmode, addr); + + if (! operands[2]) + operands[2] = const0_rtx; + + if (TARGET_FDPIC) + frv_expand_fdpic_call (operands, false, true); + else + emit_call_insn (gen_sibcall_internal (addr, operands[1], operands[2])); + + DONE; +}") + +;; It might seem that these sibcall patterns are missing references to +;; LR, but they're not necessary because sibcall_epilogue will make +;; sure LR is restored, and having LR here will set +;; regs_ever_used[REG_LR], forcing it to be saved on the stack, and +;; then restored in sibcalls and regular return code paths, even if +;; the function becomes a leaf function after tail-call elimination. + +;; We must not use a call-saved register here. `W' limits ourselves +;; to gr14 or gr15, but since we're almost running out of constraint +;; letters, and most other call-clobbered registers are often used for +;; argument-passing, this will do. +(define_insn "sibcall_internal" + [(call (mem:QI (match_operand:SI 0 "sibcall_operand" "WNOP")) + (match_operand 1 "" "")) + (use (match_operand 2 "" "")) + (return)] + "! TARGET_FDPIC" + "jmp%i0l %M0" + [(set_attr "length" "4") + (set_attr "type" "jumpl")]) + +(define_insn "sibcall_fdpicdi" + [(call (mem:QI (match_operand:DI 0 "fdpic_fptr_operand" "W")) + (match_operand 1 "" "")) + (return)] + "TARGET_FDPIC" + "jmp%i0l %M0" + [(set_attr "length" "4") + (set_attr "type" "jumpl")]) + + +;; 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" + [(use (match_operand 0 "" "")) + (use (match_operand:QI 1 "" "")) + (use (match_operand 2 "" "")) + (use (match_operand 3 "" "")) + (use (match_operand 4 "" ""))] + "" + " +{ + rtx lr = gen_rtx_REG (Pmode, LR_REGNO); + rtx addr; + + gcc_assert (GET_CODE (operands[1]) == MEM); + + addr = XEXP (operands[1], 0); + if (! call_operand (addr, Pmode)) + addr = force_reg (Pmode, addr); + + if (! operands[3]) + operands[3] = const0_rtx; + + if (TARGET_FDPIC) + frv_expand_fdpic_call (operands, true, false); + else + emit_call_insn (gen_call_value_internal (operands[0], addr, operands[2], + operands[3], lr)); + + DONE; +}") + +(define_insn "call_value_internal" + [(set (match_operand 0 "register_operand" "=d,d") + (call (mem:QI (match_operand:SI 1 "call_operand" "S,dNOP")) + (match_operand 2 "" ""))) + (use (match_operand 3 "" "")) + (clobber (match_operand:SI 4 "lr_operand" "=l,l"))] + "! TARGET_FDPIC" + "@ + call %1 + call%i1l %M1" + [(set_attr "length" "4") + (set_attr "type" "call,jumpl")]) + +(define_insn "call_value_fdpicdi" + [(set (match_operand 0 "register_operand" "=d") + (call (mem:QI (match_operand:DI 1 "fdpic_fptr_operand" "W")) + (match_operand 2 "" ""))) + (clobber (match_operand:SI 3 "lr_operand" "=l"))] + "TARGET_FDPIC" + "call%i1l %M1" + [(set_attr "length" "4") + (set_attr "type" "jumpl")]) + +(define_insn "call_value_fdpicsi" + [(set (match_operand 0 "register_operand" "=d,d") + (call (mem:QI (match_operand:SI 1 "call_operand" "S,dNOP")) + (match_operand 2 "" ""))) + (use (match_operand 3 "" "")) + (use (match_operand:SI 4 "fdpic_operand" "Z,Z")) + (clobber (match_operand:SI 5 "lr_operand" "=l,l"))] + "TARGET_FDPIC" + "@ + call %1 + call%i1l %M1" + [(set_attr "length" "4") + (set_attr "type" "call,jumpl")]) + +(define_expand "sibcall_value" + [(use (match_operand 0 "" "")) + (use (match_operand:QI 1 "" "")) + (use (match_operand 2 "" "")) + (use (match_operand 3 "" "")) + (use (match_operand 4 "" ""))] + "" + " +{ + rtx addr; + + gcc_assert (GET_CODE (operands[1]) == MEM); + + addr = XEXP (operands[1], 0); + if (! sibcall_operand (addr, Pmode)) + addr = force_reg (Pmode, addr); + + if (! operands[3]) + operands[3] = const0_rtx; + + if (TARGET_FDPIC) + frv_expand_fdpic_call (operands, true, true); + else + emit_call_insn (gen_sibcall_value_internal (operands[0], addr, operands[2], + operands[3])); + DONE; +}") + +(define_insn "sibcall_value_internal" + [(set (match_operand 0 "register_operand" "=d") + (call (mem:QI (match_operand:SI 1 "sibcall_operand" "WNOP")) + (match_operand 2 "" ""))) + (use (match_operand 3 "" "")) + (return)] + "! TARGET_FDPIC" + "jmp%i1l %M1" + [(set_attr "length" "4") + (set_attr "type" "jumpl")]) + +(define_insn "sibcall_value_fdpicdi" + [(set (match_operand 0 "register_operand" "=d") + (call (mem:QI (match_operand:DI 1 "fdpic_fptr_operand" "W")) + (match_operand 2 "" ""))) + (return)] + "TARGET_FDPIC" + "jmp%i1l %M1" + [(set_attr "length" "4") + (set_attr "type" "jumpl")]) + +;; return instruction generated instead of jmp to epilog +(define_expand "return" + [(parallel [(return) + (use (match_dup 0)) + (use (const_int 1))])] + "direct_return_p ()" + " +{ + operands[0] = gen_rtx_REG (Pmode, LR_REGNO); +}") + +;; return instruction generated by the epilogue +(define_expand "epilogue_return" + [(parallel [(return) + (use (match_operand:SI 0 "register_operand" "")) + (use (const_int 0))])] + "" + "") + +(define_insn "*return_internal" + [(return) + (use (match_operand:SI 0 "register_operand" "l,d")) + (use (match_operand:SI 1 "immediate_operand" "n,n"))] + "" + "@ + ret + jmpl @(%0,%.)" + [(set_attr "length" "4") + (set_attr "type" "jump,jumpl")]) + +(define_insn "*return_true" + [(set (pc) + (if_then_else (match_operator 0 "integer_relational_operator" + [(match_operand 1 "icc_operand" "t") + (const_int 0)]) + (return) + (pc)))] + "direct_return_p ()" + "b%c0lr %1,%#" + [(set_attr "length" "4") + (set_attr "type" "jump")]) + +(define_insn "*return_false" + [(set (pc) + (if_then_else (match_operator 0 "integer_relational_operator" + [(match_operand 1 "icc_operand" "t") + (const_int 0)]) + (pc) + (return)))] + "direct_return_p ()" + "b%C0lr %1,%#" + [(set_attr "length" "4") + (set_attr "type" "jump")]) + +;; A version of addsi3 for deallocating stack space at the end of the +;; epilogue. The addition is done in parallel with an (unspec_volatile), +;; which represents the clobbering of the deallocated space. +(define_insn "stack_adjust" + [(set (match_operand:SI 0 "register_operand" "=d") + (plus:SI (match_operand:SI 1 "register_operand" "d") + (match_operand:SI 2 "general_operand" "dNOP"))) + (unspec_volatile [(const_int 0)] UNSPEC_STACK_ADJUST)] + "" + "add%I2 %1,%2,%0" + [(set_attr "length" "4") + (set_attr "type" "int")]) + +;; Normal unconditional jump + +;; Use the "call" instruction for long branches, but prefer to use "bra" for +;; short ones since it does not force us to save the link register. + +;; This define_insn uses the branch-shortening code to decide which +;; instruction it emits. Since the main branch-shortening interface is +;; through get_attr_length(), the two alternatives must be given different +;; lengths. Here we pretend that the far jump is 8 rather than 4 bytes +;; long, though both alternatives are really the same size. +(define_insn "jump" + [(set (pc) (label_ref (match_operand 0 "" "")))] + "" + "* +{ + if (get_attr_length (insn) == 4) + return \"bra %l0\"; + else + return \"call %l0\"; +}" + [(set (attr "length") + (if_then_else + (and (ge (minus (match_dup 0) (pc)) (const_int -32768)) + (le (minus (match_dup 0) (pc)) (const_int 32764))) + (const_int 4) + (const_int 8))) + (set (attr "far_jump") + (if_then_else + (eq_attr "length" "4") + (const_string "no") + (const_string "yes"))) + (set (attr "type") + (if_then_else + (eq_attr "length" "4") + (const_string "jump") + (const_string "call")))]) + +;; Indirect jump through a register +(define_insn "indirect_jump" + [(set (pc) (match_operand:SI 0 "register_operand" "d,l"))] + "" + "@ + jmpl @(%0,%.) + bralr" + [(set_attr "length" "4") + (set_attr "type" "jumpl,branch")]) + +;; 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. Either the 'casesi' pattern or the 'tablejump' pattern, or both, +;; MUST be present in this file. + +;; 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_expand "tablejump" + [(parallel [(set (pc) (match_operand:SI 0 "address_operand" "p")) + (use (label_ref (match_operand 1 "" "")))])] + "!flag_pic" + "") + +(define_insn "tablejump_insn" + [(set (pc) (match_operand:SI 0 "address_operand" "p")) + (use (label_ref (match_operand 1 "" "")))] + "" + "jmp%I0l %M0" + [(set_attr "length" "4") + (set_attr "type" "jumpl")]) + +;; Implement switch statements when generating PIC code. Switches are +;; implemented by `tablejump' when not using -fpic. + +;; Emit code here to do the range checking and make the index zero based. +;; operand 0 is the index +;; operand 1 is the lower bound +;; operand 2 is the range of indices (highest - lowest + 1) +;; operand 3 is the label that precedes the table itself +;; operand 4 is the fall through label + +(define_expand "casesi" + [(use (match_operand:SI 0 "integer_register_operand" "")) + (use (match_operand:SI 1 "const_int_operand" "")) + (use (match_operand:SI 2 "const_int_operand" "")) + (use (match_operand 3 "" "")) + (use (match_operand 4 "" ""))] + "flag_pic" + " +{ + rtx indx; + rtx scale; + rtx low = operands[1]; + rtx range = operands[2]; + rtx table = operands[3]; + rtx treg; + rtx fail = operands[4]; + rtx mem; + rtx reg2; + rtx reg3; + + gcc_assert (GET_CODE (operands[1]) == CONST_INT); + + gcc_assert (GET_CODE (operands[2]) == CONST_INT); + + /* If we can't generate an immediate instruction, promote to register. */ + if (! IN_RANGE_P (INTVAL (range), -2048, 2047)) + range = force_reg (SImode, range); + + /* If low bound is 0, we don't have to subtract it. */ + if (INTVAL (operands[1]) == 0) + indx = operands[0]; + else + { + indx = gen_reg_rtx (SImode); + if (IN_RANGE_P (INTVAL (low), -2047, 2048)) + emit_insn (gen_addsi3 (indx, operands[0], GEN_INT (- INTVAL (low)))); + else + emit_insn (gen_subsi3 (indx, operands[0], force_reg (SImode, low))); + } + + /* Do an unsigned comparison (in the proper mode) between the index + expression and the value which represents the length of the range. + Since we just finished subtracting the lower bound of the range + from the index expression, this comparison allows us to simultaneously + check that the original index expression value is both greater than + or equal to the minimum value of the range and less than or equal to + the maximum value of the range. */ + + emit_cmp_and_jump_insns (indx, range, GTU, NULL_RTX, SImode, 1, fail); + + /* Move the table address to a register. */ + treg = gen_reg_rtx (Pmode); + emit_insn (gen_movsi (treg, gen_rtx_LABEL_REF (VOIDmode, table))); + + /* Scale index-low by wordsize. */ + scale = gen_reg_rtx (SImode); + emit_insn (gen_ashlsi3 (scale, indx, const2_rtx)); + + /* Load the address, add the start of the table back in, + and jump to it. */ + mem = gen_rtx_MEM (SImode, gen_rtx_PLUS (Pmode, scale, treg)); + reg2 = gen_reg_rtx (SImode); + reg3 = gen_reg_rtx (SImode); + emit_insn (gen_movsi (reg2, mem)); + emit_insn (gen_addsi3 (reg3, reg2, treg)); + emit_jump_insn (gen_tablejump_insn (reg3, table)); + DONE; +}") + + +;; :::::::::::::::::::: +;; :: +;; :: 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)] + "" + " +{ + frv_expand_prologue (); + DONE; +}") + +;; Called after register allocation to add any instructions needed for the +;; epilogue. Using an epilogue insn is favored compared to putting all of the +;; instructions in the FUNCTION_EPILOGUE macro, since it allows the scheduler +;; to intermix instructions with the restores of the caller saved registers. +;; In some cases, it might be necessary to emit a barrier instruction as the +;; first insn to prevent such scheduling. +(define_expand "epilogue" + [(const_int 2)] + "" + " +{ + frv_expand_epilogue (true); + DONE; +}") + +;; This pattern, if defined, emits RTL for exit from a function without the final +;; branch back to the calling function. This pattern will be emitted before any +;; sibling call (aka tail call) sites. +;; +;; The sibcall_epilogue pattern must not clobber any arguments used for +;; parameter passing or any stack slots for arguments passed to the current +;; function. +(define_expand "sibcall_epilogue" + [(const_int 3)] + "" + " +{ + frv_expand_epilogue (false); + DONE; +}") + +;; Set up the pic register to hold the address of the pic table +(define_insn "pic_prologue" + [(set (match_operand:SI 0 "integer_register_operand" "=d") + (unspec_volatile:SI [(const_int 0)] UNSPEC_PIC_PROLOGUE)) + (clobber (match_operand:SI 1 "lr_operand" "=l")) + (clobber (match_operand:SI 2 "integer_register_operand" "=d"))] + "" + "* +{ + static int frv_pic_labelno = 0; + + operands[3] = GEN_INT (frv_pic_labelno++); + return \"call %P3\\n%P3:\;movsg %1, %0\;sethi #gprelhi(%P3), %2\;setlo #gprello(%P3), %2\;sub %0,%2,%0\"; +}" + [(set_attr "length" "16") + (set_attr "type" "multi")]) + +;; :::::::::::::::::::: +;; :: +;; :: Miscellaneous instructions +;; :: +;; :::::::::::::::::::: + +;; No operation, needed in case the user uses -g but not -O. +(define_insn "nop" + [(const_int 0)] + "" + "nop" + [(set_attr "length" "4") + (set_attr "type" "int")]) + +(define_insn "fnop" + [(const_int 1)] + "" + "fnop" + [(set_attr "length" "4") + (set_attr "type" "fnop")]) + +(define_insn "mnop" + [(const_int 2)] + "" + "mnop" + [(set_attr "length" "4") + (set_attr "type" "mnop")]) + +;; Pseudo instruction that prevents the scheduler from moving code above this +;; point. Note, type unknown is used to make sure the VLIW instructions are +;; not continued past this point. +(define_insn "blockage" + [(unspec_volatile [(const_int 0)] UNSPEC_BLOCKAGE)] + "" + "# blockage" + [(set_attr "length" "0") + (set_attr "type" "unknown")]) + +;; :::::::::::::::::::: +;; :: +;; :: Media instructions +;; :: +;; :::::::::::::::::::: + +;; Unimplemented instructions: +;; - MCMPSH, MCMPUH + +(define_constants + [(UNSPEC_MLOGIC 100) + (UNSPEC_MNOT 101) + (UNSPEC_MAVEH 102) + (UNSPEC_MSATH 103) + (UNSPEC_MADDH 104) + (UNSPEC_MQADDH 105) + (UNSPEC_MPACKH 106) + (UNSPEC_MUNPACKH 107) + (UNSPEC_MDPACKH 108) + (UNSPEC_MBTOH 109) + (UNSPEC_MHTOB 110) + (UNSPEC_MROT 111) + (UNSPEC_MSHIFT 112) + (UNSPEC_MEXPDHW 113) + (UNSPEC_MEXPDHD 114) + (UNSPEC_MWCUT 115) + (UNSPEC_MMULH 116) + (UNSPEC_MMULXH 117) + (UNSPEC_MMACH 118) + (UNSPEC_MMRDH 119) + (UNSPEC_MQMULH 120) + (UNSPEC_MQMULXH 121) + (UNSPEC_MQMACH 122) + (UNSPEC_MCPX 123) + (UNSPEC_MQCPX 124) + (UNSPEC_MCUT 125) + (UNSPEC_MRDACC 126) + (UNSPEC_MRDACCG 127) + (UNSPEC_MWTACC 128) + (UNSPEC_MWTACCG 129) + (UNSPEC_MTRAP 130) + (UNSPEC_MCLRACC 131) + (UNSPEC_MCLRACCA 132) + (UNSPEC_MCOP1 133) + (UNSPEC_MCOP2 134) + (UNSPEC_MDUNPACKH 135) + (UNSPEC_MDUNPACKH_INTERNAL 136) + (UNSPEC_MBTOHE 137) + (UNSPEC_MBTOHE_INTERNAL 138) + (UNSPEC_MBTOHE 137) + (UNSPEC_MBTOHE_INTERNAL 138) + (UNSPEC_MQMACH2 139) + (UNSPEC_MADDACC 140) + (UNSPEC_MDADDACC 141) + (UNSPEC_MABSHS 142) + (UNSPEC_MDROTLI 143) + (UNSPEC_MCPLHI 144) + (UNSPEC_MCPLI 145) + (UNSPEC_MDCUTSSI 146) + (UNSPEC_MQSATHS 147) + (UNSPEC_MHSETLOS 148) + (UNSPEC_MHSETLOH 149) + (UNSPEC_MHSETHIS 150) + (UNSPEC_MHSETHIH 151) + (UNSPEC_MHDSETS 152) + (UNSPEC_MHDSETH 153) + (UNSPEC_MQLCLRHS 154) + (UNSPEC_MQLMTHS 155) + (UNSPEC_MQSLLHI 156) + (UNSPEC_MQSRAHI 157) + (UNSPEC_MASACCS 158) + (UNSPEC_MDASACCS 159) +]) + +;; Logic operations: type "mlogic" + +(define_expand "mand" + [(set (match_operand:SI 0 "fpr_operand" "") + (unspec:SI [(match_operand:SI 1 "fpr_operand" "") + (match_operand:SI 2 "fpr_operand" "") + (match_dup 3)] + UNSPEC_MLOGIC))] + "TARGET_MEDIA" + "operands[3] = GEN_INT (FRV_BUILTIN_MAND);") + +(define_expand "mor" + [(set (match_operand:SI 0 "fpr_operand" "") + (unspec:SI [(match_operand:SI 1 "fpr_operand" "") + (match_operand:SI 2 "fpr_operand" "") + (match_dup 3)] + UNSPEC_MLOGIC))] + "TARGET_MEDIA" + "operands[3] = GEN_INT (FRV_BUILTIN_MOR);") + +(define_expand "mxor" + [(set (match_operand:SI 0 "fpr_operand" "") + (unspec:SI [(match_operand:SI 1 "fpr_operand" "") + (match_operand:SI 2 "fpr_operand" "") + (match_dup 3)] + UNSPEC_MLOGIC))] + "TARGET_MEDIA" + "operands[3] = GEN_INT (FRV_BUILTIN_MXOR);") + +(define_insn "*mlogic" + [(set (match_operand:SI 0 "fpr_operand" "=f") + (unspec:SI [(match_operand:SI 1 "fpr_operand" "f") + (match_operand:SI 2 "fpr_operand" "f") + (match_operand:SI 3 "const_int_operand" "n")] + UNSPEC_MLOGIC))] + "TARGET_MEDIA" + "* +{ + switch (INTVAL (operands[3])) + { + default: break; + case FRV_BUILTIN_MAND: return \"mand %1, %2, %0\"; + case FRV_BUILTIN_MOR: return \"mor %1, %2, %0\"; + case FRV_BUILTIN_MXOR: return \"mxor %1, %2, %0\"; + } + + fatal_insn (\"Bad media insn, mlogic\", insn); +}" + [(set_attr "length" "4") + (set_attr "type" "mlogic")]) + +(define_insn "*cond_exec_mlogic" + [(cond_exec + (match_operator 0 "ccr_eqne_operator" + [(match_operand 1 "cr_operand" "C") + (const_int 0)]) + (set (match_operand:SI 2 "fpr_operand" "=f") + (unspec:SI [(match_operand:SI 3 "fpr_operand" "f") + (match_operand:SI 4 "fpr_operand" "f") + (match_operand:SI 5 "const_int_operand" "n")] + UNSPEC_MLOGIC)))] + "TARGET_MEDIA" + "* +{ + switch (INTVAL (operands[5])) + { + default: break; + case FRV_BUILTIN_MAND: return \"cmand %3, %4, %2, %1, %e0\"; + case FRV_BUILTIN_MOR: return \"cmor %3, %4, %2, %1, %e0\"; + case FRV_BUILTIN_MXOR: return \"cmxor %3, %4, %2, %1, %e0\"; + } + + fatal_insn (\"Bad media insn, cond_exec_mlogic\", insn); +}" + [(set_attr "length" "4") + (set_attr "type" "mlogic")]) + +;; Logical not: type "mlogic" + +(define_insn "mnot" + [(set (match_operand:SI 0 "fpr_operand" "=f") + (unspec:SI [(match_operand:SI 1 "fpr_operand" "f")] UNSPEC_MNOT))] + "TARGET_MEDIA" + "mnot %1, %0" + [(set_attr "length" "4") + (set_attr "type" "mlogic")]) + +(define_insn "*cond_exec_mnot" + [(cond_exec + (match_operator 0 "ccr_eqne_operator" + [(match_operand 1 "cr_operand" "C") + (const_int 0)]) + (set (match_operand:SI 2 "fpr_operand" "=f") + (unspec:SI [(match_operand:SI 3 "fpr_operand" "f")] UNSPEC_MNOT)))] + "TARGET_MEDIA" + "cmnot %3, %2, %1, %e0" + [(set_attr "length" "4") + (set_attr "type" "mlogic")]) + +;; Dual average (halfword): type "maveh" + +(define_insn "maveh" + [(set (match_operand:SI 0 "fpr_operand" "=f") + (unspec:SI [(match_operand:SI 1 "fpr_operand" "f") + (match_operand:SI 2 "fpr_operand" "f")] + UNSPEC_MAVEH))] + "TARGET_MEDIA" + "maveh %1, %2, %0" + [(set_attr "length" "4") + (set_attr "type" "maveh")]) + +;; Dual saturation (halfword): type "msath" + +(define_expand "msaths" + [(set (match_operand:SI 0 "fpr_operand" "=f") + (unspec:SI [(match_operand:SI 1 "fpr_operand" "f") + (match_operand:SI 2 "fpr_operand" "f") + (match_dup 3)] + UNSPEC_MSATH))] + "TARGET_MEDIA" + "operands[3] = GEN_INT (FRV_BUILTIN_MSATHS);") + +(define_expand "msathu" + [(set (match_operand:SI 0 "fpr_operand" "=f") + (unspec:SI [(match_operand:SI 1 "fpr_operand" "f") + (match_operand:SI 2 "fpr_operand" "f") + (match_dup 3)] + UNSPEC_MSATH))] + "TARGET_MEDIA" + "operands[3] = GEN_INT (FRV_BUILTIN_MSATHU);") + +(define_insn "*msath" + [(set (match_operand:SI 0 "fpr_operand" "=f") + (unspec:SI [(match_operand:SI 1 "fpr_operand" "f") + (match_operand:SI 2 "fpr_operand" "f") + (match_operand:SI 3 "const_int_operand" "n")] + UNSPEC_MSATH))] + "TARGET_MEDIA" + "* +{ + switch (INTVAL (operands[3])) + { + default: break; + case FRV_BUILTIN_MSATHS: return \"msaths %1, %2, %0\"; + case FRV_BUILTIN_MSATHU: return \"msathu %1, %2, %0\"; + } + + fatal_insn (\"Bad media insn, msath\", insn); +}" + [(set_attr "length" "4") + (set_attr "type" "msath")]) + +;; Dual addition/subtraction with saturation (halfword): type "maddh" + +(define_expand "maddhss" + [(set (match_operand:SI 0 "fpr_operand" "=f") + (unspec:SI [(match_operand:SI 1 "fpr_operand" "f") + (match_operand:SI 2 "fpr_operand" "f") + (match_dup 3)] + UNSPEC_MADDH))] + "TARGET_MEDIA" + "operands[3] = GEN_INT (FRV_BUILTIN_MADDHSS);") + +(define_expand "maddhus" + [(set (match_operand:SI 0 "fpr_operand" "=f") + (unspec:SI [(match_operand:SI 1 "fpr_operand" "f") + (match_operand:SI 2 "fpr_operand" "f") + (match_dup 3)] + UNSPEC_MADDH))] + "TARGET_MEDIA" + "operands[3] = GEN_INT (FRV_BUILTIN_MADDHUS);") + +(define_expand "msubhss" + [(set (match_operand:SI 0 "fpr_operand" "=f") + (unspec:SI [(match_operand:SI 1 "fpr_operand" "f") + (match_operand:SI 2 "fpr_operand" "f") + (match_dup 3)] + UNSPEC_MADDH))] + "TARGET_MEDIA" + "operands[3] = GEN_INT (FRV_BUILTIN_MSUBHSS);") + +(define_expand "msubhus" + [(set (match_operand:SI 0 "fpr_operand" "=f") + (unspec:SI [(match_operand:SI 1 "fpr_operand" "f") + (match_operand:SI 2 "fpr_operand" "f") + (match_dup 3)] + UNSPEC_MADDH))] + "TARGET_MEDIA" + "operands[3] = GEN_INT (FRV_BUILTIN_MSUBHUS);") + +(define_insn "*maddh" + [(set (match_operand:SI 0 "fpr_operand" "=f") + (unspec:SI [(match_operand:SI 1 "fpr_operand" "f") + (match_operand:SI 2 "fpr_operand" "f") + (match_operand:SI 3 "const_int_operand" "n")] + UNSPEC_MADDH))] + "TARGET_MEDIA" + "* +{ + switch (INTVAL (operands[3])) + { + default: break; + case FRV_BUILTIN_MADDHSS: return \"maddhss %1, %2, %0\"; + case FRV_BUILTIN_MADDHUS: return \"maddhus %1, %2, %0\"; + case FRV_BUILTIN_MSUBHSS: return \"msubhss %1, %2, %0\"; + case FRV_BUILTIN_MSUBHUS: return \"msubhus %1, %2, %0\"; + } + + fatal_insn (\"Bad media insn, maddh\", insn); +}" + [(set_attr "length" "4") + (set_attr "type" "maddh")]) + +(define_insn "*cond_exec_maddh" + [(cond_exec + (match_operator 0 "ccr_eqne_operator" + [(match_operand 1 "cr_operand" "C") + (const_int 0)]) + (set (match_operand:SI 2 "fpr_operand" "=f") + (unspec:SI [(match_operand:SI 3 "fpr_operand" "f") + (match_operand:SI 4 "fpr_operand" "f") + (match_operand:SI 5 "const_int_operand" "n")] + UNSPEC_MADDH)))] + "TARGET_MEDIA" + "* +{ + switch (INTVAL (operands[5])) + { + default: break; + case FRV_BUILTIN_MADDHSS: return \"cmaddhss %3, %4, %2, %1, %e0\"; + case FRV_BUILTIN_MADDHUS: return \"cmaddhus %3, %4, %2, %1, %e0\"; + case FRV_BUILTIN_MSUBHSS: return \"cmsubhss %3, %4, %2, %1, %e0\"; + case FRV_BUILTIN_MSUBHUS: return \"cmsubhus %3, %4, %2, %1, %e0\"; + } + + fatal_insn (\"Bad media insn, cond_exec_maddh\", insn); +}" + [(set_attr "length" "4") + (set_attr "type" "maddh")]) + +;; Quad addition/subtraction with saturation (halfword): type "mqaddh" + +(define_expand "mqaddhss" + [(set (match_operand:DI 0 "even_fpr_operand" "=h") + (unspec:DI [(match_operand:DI 1 "even_fpr_operand" "h") + (match_operand:DI 2 "even_fpr_operand" "h") + (match_dup 3)] + UNSPEC_MQADDH))] + "TARGET_MEDIA" + "operands[3] = GEN_INT (FRV_BUILTIN_MQADDHSS);") + +(define_expand "mqaddhus" + [(set (match_operand:DI 0 "even_fpr_operand" "=h") + (unspec:DI [(match_operand:DI 1 "even_fpr_operand" "h") + (match_operand:DI 2 "even_fpr_operand" "h") + (match_dup 3)] + UNSPEC_MQADDH))] + "TARGET_MEDIA" + "operands[3] = GEN_INT (FRV_BUILTIN_MQADDHUS);") + +(define_expand "mqsubhss" + [(set (match_operand:DI 0 "even_fpr_operand" "=h") + (unspec:DI [(match_operand:DI 1 "even_fpr_operand" "h") + (match_operand:DI 2 "even_fpr_operand" "h") + (match_dup 3)] + UNSPEC_MQADDH))] + "TARGET_MEDIA" + "operands[3] = GEN_INT (FRV_BUILTIN_MQSUBHSS);") + +(define_expand "mqsubhus" + [(set (match_operand:DI 0 "even_fpr_operand" "=h") + (unspec:DI [(match_operand:DI 1 "even_fpr_operand" "h") + (match_operand:DI 2 "even_fpr_operand" "h") + (match_dup 3)] + UNSPEC_MQADDH))] + "TARGET_MEDIA" + "operands[3] = GEN_INT (FRV_BUILTIN_MQSUBHUS);") + +(define_insn "*mqaddh" + [(set (match_operand:DI 0 "even_fpr_operand" "=h") + (unspec:DI [(match_operand:DI 1 "even_fpr_operand" "h") + (match_operand:DI 2 "even_fpr_operand" "h") + (match_operand:SI 3 "const_int_operand" "n")] + UNSPEC_MQADDH))] + "TARGET_MEDIA" + "* +{ + switch (INTVAL (operands[3])) + { + default: break; + case FRV_BUILTIN_MQADDHSS: return \"mqaddhss %1, %2, %0\"; + case FRV_BUILTIN_MQADDHUS: return \"mqaddhus %1, %2, %0\"; + case FRV_BUILTIN_MQSUBHSS: return \"mqsubhss %1, %2, %0\"; + case FRV_BUILTIN_MQSUBHUS: return \"mqsubhus %1, %2, %0\"; + } + + fatal_insn (\"Bad media insn, mqaddh\", insn); +}" + [(set_attr "length" "4") + (set_attr "type" "mqaddh")]) + +(define_insn "*cond_exec_mqaddh" + [(cond_exec + (match_operator 0 "ccr_eqne_operator" + [(match_operand 1 "cr_operand" "C") + (const_int 0)]) + (set (match_operand:DI 2 "even_fpr_operand" "=h") + (unspec:DI [(match_operand:DI 3 "even_fpr_operand" "h") + (match_operand:DI 4 "even_fpr_operand" "h") + (match_operand:SI 5 "const_int_operand" "n")] + UNSPEC_MQADDH)))] + "TARGET_MEDIA" + "* +{ + switch (INTVAL (operands[5])) + { + default: break; + case FRV_BUILTIN_MQADDHSS: return \"cmqaddhss %3, %4, %2, %1, %e0\"; + case FRV_BUILTIN_MQADDHUS: return \"cmqaddhus %3, %4, %2, %1, %e0\"; + case FRV_BUILTIN_MQSUBHSS: return \"cmqsubhss %3, %4, %2, %1, %e0\"; + case FRV_BUILTIN_MQSUBHUS: return \"cmqsubhus %3, %4, %2, %1, %e0\"; + } + + fatal_insn (\"Bad media insn, cond_exec_mqaddh\", insn); +}" + [(set_attr "length" "4") + (set_attr "type" "mqaddh")]) + +;; Pack halfword: type "mpackh" + +(define_insn "mpackh" + [(set (match_operand:SI 0 "fpr_operand" "=f") + (unspec:SI [(match_operand:HI 1 "fpr_operand" "f") + (match_operand:HI 2 "fpr_operand" "f")] + UNSPEC_MPACKH))] + "TARGET_MEDIA" + "mpackh %1, %2, %0" + [(set_attr "length" "4") + (set_attr "type" "mpackh")]) + +;; Unpack halfword: type "mpackh" + +(define_insn "munpackh" + [(set (match_operand:DI 0 "even_fpr_operand" "=h") + (unspec:DI [(match_operand:SI 1 "fpr_operand" "f")] + UNSPEC_MUNPACKH))] + "TARGET_MEDIA" + "munpackh %1, %0" + [(set_attr "length" "4") + (set_attr "type" "munpackh")]) + +;; Dual pack halfword: type "mdpackh" + +(define_insn "mdpackh" + [(set (match_operand:DI 0 "even_fpr_operand" "=h") + (unspec:DI [(match_operand:DI 1 "even_fpr_operand" "h") + (match_operand:DI 2 "even_fpr_operand" "h")] + UNSPEC_MDPACKH))] + "TARGET_MEDIA" + "mdpackh %1, %2, %0" + [(set_attr "length" "4") + (set_attr "type" "mdpackh")]) + +;; Byte-halfword conversion: type "mbhconv" + +(define_insn "mbtoh" + [(set (match_operand:DI 0 "even_fpr_operand" "=h") + (unspec:DI [(match_operand:SI 1 "fpr_operand" "f")] + UNSPEC_MBTOH))] + "TARGET_MEDIA" + "mbtoh %1, %0" + [(set_attr "length" "4") + (set_attr "type" "mbhconv")]) + +(define_insn "*cond_exec_mbtoh" + [(cond_exec + (match_operator 0 "ccr_eqne_operator" + [(match_operand 1 "cr_operand" "C") + (const_int 0)]) + (set (match_operand:DI 2 "even_fpr_operand" "=h") + (unspec:DI [(match_operand:SI 3 "fpr_operand" "f")] + UNSPEC_MBTOH)))] + "TARGET_MEDIA" + "cmbtoh %3, %2, %1, %e0" + [(set_attr "length" "4") + (set_attr "type" "mbhconv")]) + +(define_insn "mhtob" + [(set (match_operand:SI 0 "fpr_operand" "=f") + (unspec:SI [(match_operand:DI 1 "even_fpr_operand" "h")] + UNSPEC_MHTOB))] + "TARGET_MEDIA" + "mhtob %1, %0" + [(set_attr "length" "4") + (set_attr "type" "mbhconv")]) + +(define_insn "*cond_exec_mhtob" + [(cond_exec + (match_operator 0 "ccr_eqne_operator" + [(match_operand 1 "cr_operand" "C") + (const_int 0)]) + (set (match_operand:SI 2 "fpr_operand" "=f") + (unspec:SI [(match_operand:DI 3 "even_fpr_operand" "h")] + UNSPEC_MHTOB)))] + "TARGET_MEDIA" + "cmhtob %3, %2, %1, %e0" + [(set_attr "length" "4") + (set_attr "type" "mbhconv")]) + +;; Rotate: type "mrot" + +(define_expand "mrotli" + [(set (match_operand:SI 0 "fpr_operand" "") + (unspec:SI [(match_operand:SI 1 "fpr_operand" "") + (match_operand:SI 2 "uint5_operand" "") + (match_dup 3)] + UNSPEC_MROT))] + "TARGET_MEDIA" + "operands[3] = GEN_INT (FRV_BUILTIN_MROTLI);") + +(define_expand "mrotri" + [(set (match_operand:SI 0 "fpr_operand" "") + (unspec:SI [(match_operand:SI 1 "fpr_operand" "") + (match_operand:SI 2 "uint5_operand" "") + (match_dup 3)] + UNSPEC_MROT))] + "TARGET_MEDIA" + "operands[3] = GEN_INT (FRV_BUILTIN_MROTRI);") + +(define_insn "*mrot" + [(set (match_operand:SI 0 "fpr_operand" "=f") + (unspec:SI [(match_operand:SI 1 "fpr_operand" "f") + (match_operand:SI 2 "uint5_operand" "I") + (match_operand:SI 3 "const_int_operand" "n")] + UNSPEC_MROT))] + "TARGET_MEDIA" + "* +{ + switch (INTVAL (operands[3])) + { + default: break; + case FRV_BUILTIN_MROTLI: return \"mrotli %1, %2, %0\"; + case FRV_BUILTIN_MROTRI: return \"mrotri %1, %2, %0\"; + } + + fatal_insn (\"Bad media insn, mrot\", insn); +}" + [(set_attr "length" "4") + (set_attr "type" "mrot")]) + +;; Dual shift halfword: type "msh" + +(define_expand "msllhi" + [(set (match_operand:SI 0 "fpr_operand" "") + (unspec:SI [(match_operand:SI 1 "fpr_operand" "") + (match_operand:SI 2 "uint4_operand" "") + (match_dup 3)] + UNSPEC_MSHIFT))] + "TARGET_MEDIA" + "operands[3] = GEN_INT (FRV_BUILTIN_MSLLHI);") + +(define_expand "msrlhi" + [(set (match_operand:SI 0 "fpr_operand" "") + (unspec:SI [(match_operand:SI 1 "fpr_operand" "") + (match_operand:SI 2 "uint4_operand" "") + (match_dup 3)] + UNSPEC_MSHIFT))] + "TARGET_MEDIA" + "operands[3] = GEN_INT (FRV_BUILTIN_MSRLHI);") + +(define_expand "msrahi" + [(set (match_operand:SI 0 "fpr_operand" "") + (unspec:SI [(match_operand:SI 1 "fpr_operand" "") + (match_operand:SI 2 "uint4_operand" "") + (match_dup 3)] + UNSPEC_MSHIFT))] + "TARGET_MEDIA" + "operands[3] = GEN_INT (FRV_BUILTIN_MSRAHI);") + +(define_insn "*mshift" + [(set (match_operand:SI 0 "fpr_operand" "=f") + (unspec:SI [(match_operand:SI 1 "fpr_operand" "f") + (match_operand:SI 2 "uint4_operand" "I") + (match_operand:SI 3 "const_int_operand" "n")] + UNSPEC_MSHIFT))] + "TARGET_MEDIA" + "* +{ + switch (INTVAL (operands[3])) + { + default: break; + case FRV_BUILTIN_MSLLHI: return \"msllhi %1, %2, %0\"; + case FRV_BUILTIN_MSRLHI: return \"msrlhi %1, %2, %0\"; + case FRV_BUILTIN_MSRAHI: return \"msrahi %1, %2, %0\"; + } + + fatal_insn (\"Bad media insn, mshift\", insn); +}" + [(set_attr "length" "4") + (set_attr "type" "mshift")]) + +;; Expand halfword to word: type "mexpdhw" + +(define_insn "mexpdhw" + [(set (match_operand:SI 0 "fpr_operand" "=f") + (unspec:SI [(match_operand:SI 1 "fpr_operand" "f") + (match_operand:SI 2 "uint1_operand" "I")] + UNSPEC_MEXPDHW))] + "TARGET_MEDIA" + "mexpdhw %1, %2, %0" + [(set_attr "length" "4") + (set_attr "type" "mexpdhw")]) + +(define_insn "*cond_exec_mexpdhw" + [(cond_exec + (match_operator 0 "ccr_eqne_operator" + [(match_operand 1 "cr_operand" "C") + (const_int 0)]) + (set (match_operand:SI 2 "fpr_operand" "=f") + (unspec:SI [(match_operand:SI 3 "fpr_operand" "f") + (match_operand:SI 4 "uint1_operand" "I")] + UNSPEC_MEXPDHW)))] + "TARGET_MEDIA" + "cmexpdhw %3, %4, %2, %1, %e0" + [(set_attr "length" "4") + (set_attr "type" "mexpdhw")]) + +;; Expand halfword to double: type "mexpdhd" + +(define_insn "mexpdhd" + [(set (match_operand:DI 0 "even_fpr_operand" "=h") + (unspec:DI [(match_operand:SI 1 "fpr_operand" "f") + (match_operand:SI 2 "uint1_operand" "I")] + UNSPEC_MEXPDHD))] + "TARGET_MEDIA" + "mexpdhd %1, %2, %0" + [(set_attr "length" "4") + (set_attr "type" "mexpdhd")]) + +(define_insn "*cond_exec_mexpdhd" + [(cond_exec + (match_operator 0 "ccr_eqne_operator" + [(match_operand 1 "cr_operand" "C") + (const_int 0)]) + (set (match_operand:DI 2 "even_fpr_operand" "=h") + (unspec:DI [(match_operand:SI 3 "fpr_operand" "f") + (match_operand:SI 4 "uint1_operand" "I")] + UNSPEC_MEXPDHD)))] + "TARGET_MEDIA" + "cmexpdhd %3, %4, %2, %1, %e0" + [(set_attr "length" "4") + (set_attr "type" "mexpdhd")]) + +;; FR cut: type "mwcut" + +(define_insn "mwcut" + [(set (match_operand:SI 0 "fpr_operand" "=f") + (unspec:SI [(match_operand:DI 1 "fpr_operand" "f") + (match_operand:SI 2 "fpr_or_int6_operand" "fI")] + UNSPEC_MWCUT))] + "TARGET_MEDIA" + "mwcut%i2 %1, %2, %0" + [(set_attr "length" "4") + (set_attr "type" "mwcut")]) + +;; Dual multiplication (halfword): type "mmulh" + +(define_expand "mmulhs" + [(parallel [(set (match_operand:DI 0 "even_acc_operand" "=b") + (unspec:DI [(match_operand:SI 1 "fpr_operand" "f") + (match_operand:SI 2 "fpr_operand" "f") + (match_dup 4)] + UNSPEC_MMULH)) + (set (match_operand:HI 3 "accg_operand" "=B") + (unspec:HI [(const_int 0)] UNSPEC_MMULH))])] + "TARGET_MEDIA" + "operands[4] = GEN_INT (FRV_BUILTIN_MMULHS);") + +(define_expand "mmulhu" + [(parallel [(set (match_operand:DI 0 "even_acc_operand" "=b") + (unspec:DI [(match_operand:SI 1 "fpr_operand" "f") + (match_operand:SI 2 "fpr_operand" "f") + (match_dup 4)] + UNSPEC_MMULH)) + (set (match_operand:HI 3 "accg_operand" "=B") + (unspec:HI [(const_int 0)] UNSPEC_MMULH))])] + "TARGET_MEDIA" + "operands[4] = GEN_INT (FRV_BUILTIN_MMULHU);") + +(define_insn "*mmulh" + [(set (match_operand:DI 0 "even_acc_operand" "=b") + (unspec:DI [(match_operand:SI 1 "fpr_operand" "f") + (match_operand:SI 2 "fpr_operand" "f") + (match_operand:SI 3 "const_int_operand" "n")] + UNSPEC_MMULH)) + (set (match_operand:HI 4 "accg_operand" "=B") + (unspec:HI [(const_int 0)] UNSPEC_MMULH))] + "TARGET_MEDIA" + "* +{ + switch (INTVAL (operands[3])) + { + default: break; + case FRV_BUILTIN_MMULHS: return \"mmulhs %1, %2, %0\"; + case FRV_BUILTIN_MMULHU: return \"mmulhu %1, %2, %0\"; + } + + fatal_insn (\"Bad media insn, mmulh\", insn); +}" + [(set_attr "length" "4") + (set_attr "type" "mmulh")]) + +(define_insn "*cond_exec_mmulh" + [(cond_exec + (match_operator 0 "ccr_eqne_operator" + [(match_operand 1 "cr_operand" "C") + (const_int 0)]) + (parallel [(set (match_operand:DI 2 "even_acc_operand" "=b") + (unspec:DI [(match_operand:SI 3 "fpr_operand" "f") + (match_operand:SI 4 "fpr_operand" "f") + (match_operand:SI 5 "const_int_operand" "n")] + UNSPEC_MMULH)) + (set (match_operand:HI 6 "accg_operand" "=B") + (unspec:HI [(const_int 0)] UNSPEC_MMULH))]))] + "TARGET_MEDIA" + "* +{ + switch (INTVAL (operands[5])) + { + default: break; + case FRV_BUILTIN_MMULHS: return \"cmmulhs %3, %4, %2, %1, %e0\"; + case FRV_BUILTIN_MMULHU: return \"cmmulhu %3, %4, %2, %1, %e0\"; + } + + fatal_insn (\"Bad media insn, cond_exec_mmulh\", insn); +}" + [(set_attr "length" "4") + (set_attr "type" "mmulh")]) + +;; Dual cross multiplication (halfword): type "mmulxh" + +(define_expand "mmulxhs" + [(parallel [(set (match_operand:DI 0 "even_acc_operand" "=b") + (unspec:DI [(match_operand:SI 1 "fpr_operand" "f") + (match_operand:SI 2 "fpr_operand" "f") + (match_dup 4)] + UNSPEC_MMULXH)) + (set (match_operand:HI 3 "accg_operand" "=B") + (unspec:HI [(const_int 0)] UNSPEC_MMULXH))])] + "TARGET_MEDIA" + "operands[4] = GEN_INT (FRV_BUILTIN_MMULXHS);") + +(define_expand "mmulxhu" + [(parallel [(set (match_operand:DI 0 "even_acc_operand" "=b") + (unspec:DI [(match_operand:SI 1 "fpr_operand" "f") + (match_operand:SI 2 "fpr_operand" "f") + (match_dup 4)] + UNSPEC_MMULXH)) + (set (match_operand:HI 3 "accg_operand" "=B") + (unspec:HI [(const_int 0)] UNSPEC_MMULXH))])] + "TARGET_MEDIA" + "operands[4] = GEN_INT (FRV_BUILTIN_MMULXHU);") + +(define_insn "*mmulxh" + [(set (match_operand:DI 0 "even_acc_operand" "=b") + (unspec:DI [(match_operand:SI 1 "fpr_operand" "f") + (match_operand:SI 2 "fpr_operand" "f") + (match_operand:SI 3 "const_int_operand" "n")] + UNSPEC_MMULXH)) + (set (match_operand:HI 4 "accg_operand" "=B") + (unspec:HI [(const_int 0)] UNSPEC_MMULXH))] + "TARGET_MEDIA" + "* +{ + switch (INTVAL (operands[3])) + { + default: break; + case FRV_BUILTIN_MMULXHS: return \"mmulxhs %1, %2, %0\"; + case FRV_BUILTIN_MMULXHU: return \"mmulxhu %1, %2, %0\"; + } + + fatal_insn (\"Bad media insn, mmulxh\", insn); +}" + [(set_attr "length" "4") + (set_attr "type" "mmulxh")]) + +;; Dual product-sum (halfword): type "mmach" + +(define_expand "mmachs" + [(parallel [(set (match_operand:DI 0 "even_acc_operand" "+b") + (unspec:DI [(match_dup 0) + (match_operand:SI 1 "fpr_operand" "f") + (match_operand:SI 2 "fpr_operand" "f") + (match_operand:HI 3 "accg_operand" "+B") + (match_dup 4)] + UNSPEC_MMACH)) + (set (match_dup 3) + (unspec:HI [(const_int 0)] UNSPEC_MMACH))])] + "TARGET_MEDIA" + "operands[4] = GEN_INT (FRV_BUILTIN_MMACHS);") + +(define_expand "mmachu" + [(parallel [(set (match_operand:DI 0 "even_acc_operand" "+b") + (unspec:DI [(match_dup 0) + (match_operand:SI 1 "fpr_operand" "f") + (match_operand:SI 2 "fpr_operand" "f") + (match_operand:HI 3 "accg_operand" "+B") + (match_dup 4)] + UNSPEC_MMACH)) + (set (match_dup 3) + (unspec:HI [(const_int 0)] UNSPEC_MMACH))])] + "TARGET_MEDIA" + "operands[4] = GEN_INT (FRV_BUILTIN_MMACHU);") + +(define_insn "*mmach" + [(set (match_operand:DI 0 "even_acc_operand" "+b") + (unspec:DI [(match_dup 0) + (match_operand:SI 1 "fpr_operand" "f") + (match_operand:SI 2 "fpr_operand" "f") + (match_operand:HI 3 "accg_operand" "+B") + (match_operand:SI 4 "const_int_operand" "n")] + UNSPEC_MMACH)) + (set (match_dup 3) (unspec:HI [(const_int 0)] UNSPEC_MMACH))] + "TARGET_MEDIA" + "* +{ + switch (INTVAL (operands[4])) + { + default: break; + case FRV_BUILTIN_MMACHS: return \"mmachs %1, %2, %0\"; + case FRV_BUILTIN_MMACHU: return \"mmachu %1, %2, %0\"; + } + + fatal_insn (\"Bad media insn, mmach\", insn); +}" + [(set_attr "length" "4") + (set_attr "type" "mmach")]) + +(define_insn "*cond_exec_mmach" + [(cond_exec + (match_operator 0 "ccr_eqne_operator" + [(match_operand 1 "cr_operand" "C") + (const_int 0)]) + (parallel [(set (match_operand:DI 2 "even_acc_operand" "+b") + (unspec:DI [(match_dup 2) + (match_operand:SI 3 "fpr_operand" "f") + (match_operand:SI 4 "fpr_operand" "f") + (match_operand:HI 5 "accg_operand" "+B") + (match_operand:SI 6 "const_int_operand" "n")] + UNSPEC_MMACH)) + (set (match_dup 5) + (unspec:HI [(const_int 0)] UNSPEC_MMACH))]))] + "TARGET_MEDIA" + "* +{ + switch (INTVAL (operands[6])) + { + default: break; + case FRV_BUILTIN_MMACHS: return \"cmmachs %3, %4, %2, %1, %e0\"; + case FRV_BUILTIN_MMACHU: return \"cmmachu %3, %4, %2, %1, %e0\"; + } + + fatal_insn (\"Bad media insn, cond_exec_mmach\", insn); +}" + [(set_attr "length" "4") + (set_attr "type" "mmach")]) + +;; Dual product-difference: type "mmrdh" + +(define_expand "mmrdhs" + [(parallel [(set (match_operand:DI 0 "even_acc_operand" "+b") + (unspec:DI [(match_dup 0) + (match_operand:SI 1 "fpr_operand" "f") + (match_operand:SI 2 "fpr_operand" "f") + (match_operand:HI 3 "accg_operand" "+B") + (match_dup 4)] + UNSPEC_MMRDH)) + (set (match_dup 3) + (unspec:HI [(const_int 0)] UNSPEC_MMRDH))])] + "TARGET_MEDIA" + "operands[4] = GEN_INT (FRV_BUILTIN_MMRDHS);") + +(define_expand "mmrdhu" + [(parallel [(set (match_operand:DI 0 "even_acc_operand" "+b") + (unspec:DI [(match_dup 0) + (match_operand:SI 1 "fpr_operand" "f") + (match_operand:SI 2 "fpr_operand" "f") + (match_operand:HI 3 "accg_operand" "+B") + (match_dup 4)] + UNSPEC_MMRDH)) + (set (match_dup 3) + (unspec:HI [(const_int 0)] UNSPEC_MMRDH))])] + "TARGET_MEDIA" + "operands[4] = GEN_INT (FRV_BUILTIN_MMRDHU);") + +(define_insn "*mmrdh" + [(set (match_operand:DI 0 "even_acc_operand" "+b") + (unspec:DI [(match_dup 0) + (match_operand:SI 1 "fpr_operand" "f") + (match_operand:SI 2 "fpr_operand" "f") + (match_operand:HI 3 "accg_operand" "+B") + (match_operand:SI 4 "const_int_operand" "n")] + UNSPEC_MMRDH)) + (set (match_dup 3) + (unspec:HI [(const_int 0)] UNSPEC_MMRDH))] + "TARGET_MEDIA" + "* +{ + switch (INTVAL (operands[4])) + { + default: break; + case FRV_BUILTIN_MMRDHS: return \"mmrdhs %1, %2, %0\"; + case FRV_BUILTIN_MMRDHU: return \"mmrdhu %1, %2, %0\"; + } + + fatal_insn (\"Bad media insn, mrdh\", insn); +}" + [(set_attr "length" "4") + (set_attr "type" "mmrdh")]) + +;; Quad multiply (halfword): type "mqmulh" + +(define_expand "mqmulhs" + [(parallel [(set (match_operand:V4SI 0 "quad_acc_operand" "=A") + (unspec:V4SI [(match_operand:DI 1 "even_fpr_operand" "h") + (match_operand:DI 2 "even_fpr_operand" "h") + (match_dup 4)] + UNSPEC_MQMULH)) + (set (match_operand:V4QI 3 "accg_operand" "=B") + (unspec:V4QI [(const_int 0)] UNSPEC_MQMULH))])] + "TARGET_MEDIA" + "operands[4] = GEN_INT (FRV_BUILTIN_MQMULHS);") + +(define_expand "mqmulhu" + [(parallel [(set (match_operand:V4SI 0 "quad_acc_operand" "=A") + (unspec:V4SI [(match_operand:DI 1 "even_fpr_operand" "h") + (match_operand:DI 2 "even_fpr_operand" "h") + (match_dup 4)] + UNSPEC_MQMULH)) + (set (match_operand:V4QI 3 "accg_operand" "=B") + (unspec:V4QI [(const_int 0)] UNSPEC_MQMULH))])] + "TARGET_MEDIA" + "operands[4] = GEN_INT (FRV_BUILTIN_MQMULHU);") + +(define_insn "*mqmulh" + [(set (match_operand:V4SI 0 "quad_acc_operand" "=A") + (unspec:V4SI [(match_operand:DI 1 "even_fpr_operand" "h") + (match_operand:DI 2 "even_fpr_operand" "h") + (match_operand:SI 3 "const_int_operand" "n")] + UNSPEC_MQMULH)) + (set (match_operand:V4QI 4 "accg_operand" "=B") + (unspec:V4QI [(const_int 0)] UNSPEC_MQMULH))] + "TARGET_MEDIA" + "* +{ + switch (INTVAL (operands[3])) + { + default: break; + case FRV_BUILTIN_MQMULHS: return \"mqmulhs %1, %2, %0\"; + case FRV_BUILTIN_MQMULHU: return \"mqmulhu %1, %2, %0\"; + } + + fatal_insn (\"Bad media insn, mqmulh\", insn); +}" + [(set_attr "length" "4") + (set_attr "type" "mqmulh")]) + +(define_insn "*cond_exec_mqmulh" + [(cond_exec + (match_operator 0 "ccr_eqne_operator" + [(match_operand 1 "cr_operand" "C") + (const_int 0)]) + (parallel [(set (match_operand:V4SI 2 "quad_acc_operand" "=A") + (unspec:V4SI [(match_operand:DI 3 "even_fpr_operand" "h") + (match_operand:DI 4 "even_fpr_operand" "h") + (match_operand:SI 5 "const_int_operand" "n")] + UNSPEC_MQMULH)) + (set (match_operand:V4QI 6 "accg_operand" "=B") + (unspec:V4QI [(const_int 0)] UNSPEC_MQMULH))]))] + "TARGET_MEDIA" + "* +{ + switch (INTVAL (operands[5])) + { + default: break; + case FRV_BUILTIN_MQMULHS: return \"cmqmulhs %3, %4, %2, %1, %e0\"; + case FRV_BUILTIN_MQMULHU: return \"cmqmulhu %3, %4, %2, %1, %e0\"; + } + + fatal_insn (\"Bad media insn, cond_exec_mqmulh\", insn); +}" + [(set_attr "length" "4") + (set_attr "type" "mqmulh")]) + +;; Quad cross multiply (halfword): type "mqmulxh" + +(define_expand "mqmulxhs" + [(parallel [(set (match_operand:V4SI 0 "quad_acc_operand" "=A") + (unspec:V4SI [(match_operand:DI 1 "even_fpr_operand" "h") + (match_operand:DI 2 "even_fpr_operand" "h") + (match_dup 4)] + UNSPEC_MQMULXH)) + (set (match_operand:V4QI 3 "accg_operand" "=B") + (unspec:V4QI [(const_int 0)] UNSPEC_MQMULXH))])] + "TARGET_MEDIA" + "operands[4] = GEN_INT (FRV_BUILTIN_MQMULXHS);") + +(define_expand "mqmulxhu" + [(parallel [(set (match_operand:V4SI 0 "quad_acc_operand" "=A") + (unspec:V4SI [(match_operand:DI 1 "even_fpr_operand" "h") + (match_operand:DI 2 "even_fpr_operand" "h") + (match_dup 4)] + UNSPEC_MQMULXH)) + (set (match_operand:V4QI 3 "accg_operand" "=B") + (unspec:V4QI [(const_int 0)] UNSPEC_MQMULXH))])] + "TARGET_MEDIA" + "operands[4] = GEN_INT (FRV_BUILTIN_MQMULXHU);") + +(define_insn "*mqmulxh" + [(set (match_operand:V4SI 0 "quad_acc_operand" "=A") + (unspec:V4SI [(match_operand:DI 1 "even_fpr_operand" "h") + (match_operand:DI 2 "even_fpr_operand" "h") + (match_operand:SI 3 "const_int_operand" "n")] + UNSPEC_MQMULXH)) + (set (match_operand:V4QI 4 "accg_operand" "=B") + (unspec:V4QI [(const_int 0)] UNSPEC_MQMULXH))] + "TARGET_MEDIA" + "* +{ + switch (INTVAL (operands[3])) + { + default: break; + case FRV_BUILTIN_MQMULXHS: return \"mqmulxhs %1, %2, %0\"; + case FRV_BUILTIN_MQMULXHU: return \"mqmulxhu %1, %2, %0\"; + } + + fatal_insn (\"Bad media insn, mqmulxh\", insn); +}" + [(set_attr "length" "4") + (set_attr "type" "mqmulxh")]) + +;; Quad product-sum (halfword): type "mqmach" + +(define_expand "mqmachs" + [(parallel [(set (match_operand:V4SI 0 "even_acc_operand" "+A") + (unspec:V4SI [(match_dup 0) + (match_operand:DI 1 "even_fpr_operand" "h") + (match_operand:DI 2 "even_fpr_operand" "h") + (match_operand:V4QI 3 "accg_operand" "+B") + (match_dup 4)] + UNSPEC_MQMACH)) + (set (match_dup 3) + (unspec:V4QI [(const_int 0)] UNSPEC_MQMACH))])] + "TARGET_MEDIA" + "operands[4] = GEN_INT (FRV_BUILTIN_MQMACHS);") + +(define_expand "mqmachu" + [(parallel [(set (match_operand:V4SI 0 "even_acc_operand" "+A") + (unspec:V4SI [(match_dup 0) + (match_operand:DI 1 "even_fpr_operand" "h") + (match_operand:DI 2 "even_fpr_operand" "h") + (match_operand:V4QI 3 "accg_operand" "+B") + (match_dup 4)] + UNSPEC_MQMACH)) + (set (match_dup 3) + (unspec:V4QI [(const_int 0)] UNSPEC_MQMACH))])] + "TARGET_MEDIA" + "operands[4] = GEN_INT (FRV_BUILTIN_MQMACHU);") + +(define_insn "*mqmach" + [(set (match_operand:V4SI 0 "even_acc_operand" "+A") + (unspec:V4SI [(match_dup 0) + (match_operand:DI 1 "even_fpr_operand" "h") + (match_operand:DI 2 "even_fpr_operand" "h") + (match_operand:V4QI 3 "accg_operand" "+B") + (match_operand:SI 4 "const_int_operand" "n")] + UNSPEC_MQMACH)) + (set (match_dup 3) + (unspec:V4QI [(const_int 0)] UNSPEC_MQMACH))] + "TARGET_MEDIA" + "* +{ + switch (INTVAL (operands[4])) + { + default: break; + case FRV_BUILTIN_MQMACHS: return \"mqmachs %1, %2, %0\"; + case FRV_BUILTIN_MQMACHU: return \"mqmachu %1, %2, %0\"; + } + + fatal_insn (\"Bad media insn, mqmach\", insn); +}" + [(set_attr "length" "4") + (set_attr "type" "mqmach")]) + +(define_insn "*cond_exec_mqmach" + [(cond_exec + (match_operator 0 "ccr_eqne_operator" + [(match_operand 1 "cr_operand" "C") + (const_int 0)]) + (parallel [(set (match_operand:V4SI 2 "even_acc_operand" "+A") + (unspec:V4SI [(match_dup 2) + (match_operand:DI 3 "even_fpr_operand" "h") + (match_operand:DI 4 "even_fpr_operand" "h") + (match_operand:V4QI 5 "accg_operand" "+B") + (match_operand:SI 6 "const_int_operand" "n")] + UNSPEC_MQMACH)) + (set (match_dup 5) + (unspec:V4QI [(const_int 0)] UNSPEC_MQMACH))]))] + "TARGET_MEDIA" + "* +{ + switch (INTVAL (operands[6])) + { + default: break; + case FRV_BUILTIN_MQMACHS: return \"cmqmachs %3, %4, %2, %1, %e0\"; + case FRV_BUILTIN_MQMACHU: return \"cmqmachu %3, %4, %2, %1, %e0\"; + } + + fatal_insn (\"Bad media insn, cond_exec_mqmach\", insn); +}" + [(set_attr "length" "4") + (set_attr "type" "mqmach")]) + +;; Dual complex number product-sum (halfword) + +(define_expand "mcpxrs" + [(parallel [(set (match_operand:SI 0 "acc_operand" "=a") + (unspec:SI [(match_operand:SI 1 "fpr_operand" "f") + (match_operand:SI 2 "fpr_operand" "f") + (match_dup 4)] + UNSPEC_MCPX)) + (set (match_operand:QI 3 "accg_operand" "=B") + (unspec:QI [(const_int 0)] UNSPEC_MCPX))])] + "TARGET_MEDIA" + "operands[4] = GEN_INT (FRV_BUILTIN_MCPXRS);") + +(define_expand "mcpxru" + [(parallel [(set (match_operand:SI 0 "acc_operand" "=a") + (unspec:SI [(match_operand:SI 1 "fpr_operand" "f") + (match_operand:SI 2 "fpr_operand" "f") + (match_dup 4)] + UNSPEC_MCPX)) + (set (match_operand:QI 3 "accg_operand" "=B") + (unspec:QI [(const_int 0)] UNSPEC_MCPX))])] + "TARGET_MEDIA" + "operands[4] = GEN_INT (FRV_BUILTIN_MCPXRU);") + +(define_expand "mcpxis" + [(parallel [(set (match_operand:SI 0 "acc_operand" "=a") + (unspec:SI [(match_operand:SI 1 "fpr_operand" "f") + (match_operand:SI 2 "fpr_operand" "f") + (match_dup 4)] + UNSPEC_MCPX)) + (set (match_operand:QI 3 "accg_operand" "=B") + (unspec:QI [(const_int 0)] UNSPEC_MCPX))])] + "TARGET_MEDIA" + "operands[4] = GEN_INT (FRV_BUILTIN_MCPXIS);") + +(define_expand "mcpxiu" + [(parallel [(set (match_operand:SI 0 "acc_operand" "=a") + (unspec:SI [(match_operand:SI 1 "fpr_operand" "f") + (match_operand:SI 2 "fpr_operand" "f") + (match_dup 4)] + UNSPEC_MCPX)) + (set (match_operand:QI 3 "accg_operand" "=B") + (unspec:QI [(const_int 0)] UNSPEC_MCPX))])] + "TARGET_MEDIA" + "operands[4] = GEN_INT (FRV_BUILTIN_MCPXIU);") + +(define_insn "*mcpx" + [(parallel [(set (match_operand:SI 0 "acc_operand" "=a") + (unspec:SI [(match_operand:SI 1 "fpr_operand" "f") + (match_operand:SI 2 "fpr_operand" "f") + (match_operand:SI 3 "const_int_operand" "n")] + UNSPEC_MCPX)) + (set (match_operand:QI 4 "accg_operand" "=B") + (unspec:QI [(const_int 0)] UNSPEC_MCPX))])] + "TARGET_MEDIA" + "* +{ + switch (INTVAL (operands[3])) + { + default: break; + case FRV_BUILTIN_MCPXRS: return \"mcpxrs %1, %2, %0\"; + case FRV_BUILTIN_MCPXRU: return \"mcpxru %1, %2, %0\"; + case FRV_BUILTIN_MCPXIS: return \"mcpxis %1, %2, %0\"; + case FRV_BUILTIN_MCPXIU: return \"mcpxiu %1, %2, %0\"; + } + + fatal_insn (\"Bad media insn, mcpx\", insn); +}" + [(set_attr "length" "4") + (set_attr "type" "mcpx")]) + +(define_insn "*cond_exec_mcpx" + [(cond_exec + (match_operator 0 "ccr_eqne_operator" + [(match_operand 1 "cr_operand" "C") + (const_int 0)]) + (parallel [(set (match_operand:SI 2 "acc_operand" "=a") + (unspec:SI [(match_operand:SI 3 "fpr_operand" "f") + (match_operand:SI 4 "fpr_operand" "f") + (match_operand:SI 5 "const_int_operand" "n")] + UNSPEC_MCPX)) + (set (match_operand:QI 6 "accg_operand" "=B") + (unspec:QI [(const_int 0)] UNSPEC_MCPX))]))] + "TARGET_MEDIA" + "* +{ + switch (INTVAL (operands[5])) + { + default: break; + case FRV_BUILTIN_MCPXRS: return \"cmcpxrs %3, %4, %2, %1, %e0\"; + case FRV_BUILTIN_MCPXRU: return \"cmcpxru %3, %4, %2, %1, %e0\"; + case FRV_BUILTIN_MCPXIS: return \"cmcpxis %3, %4, %2, %1, %e0\"; + case FRV_BUILTIN_MCPXIU: return \"cmcpxiu %3, %4, %2, %1, %e0\"; + } + + fatal_insn (\"Bad media insn, cond_exec_mcpx\", insn); +}" + [(set_attr "length" "4") + (set_attr "type" "mcpx")]) + +;; Quad complex number product-sum (halfword): type "mqcpx" + +(define_expand "mqcpxrs" + [(parallel [(set (match_operand:DI 0 "even_acc_operand" "=b") + (unspec:DI [(match_operand:DI 1 "fpr_operand" "f") + (match_operand:DI 2 "fpr_operand" "f") + (match_dup 4)] + UNSPEC_MQCPX)) + (set (match_operand:HI 3 "accg_operand" "=B") + (unspec:HI [(const_int 0)] UNSPEC_MQCPX))])] + "TARGET_MEDIA" + "operands[4] = GEN_INT (FRV_BUILTIN_MQCPXRS);") + +(define_expand "mqcpxru" + [(parallel [(set (match_operand:DI 0 "even_acc_operand" "=b") + (unspec:DI [(match_operand:DI 1 "fpr_operand" "f") + (match_operand:DI 2 "fpr_operand" "f") + (match_dup 4)] + UNSPEC_MQCPX)) + (set (match_operand:HI 3 "accg_operand" "=B") + (unspec:HI [(const_int 0)] UNSPEC_MQCPX))])] + "TARGET_MEDIA" + "operands[4] = GEN_INT (FRV_BUILTIN_MQCPXRU);") + +(define_expand "mqcpxis" + [(parallel [(set (match_operand:DI 0 "even_acc_operand" "=b") + (unspec:DI [(match_operand:DI 1 "fpr_operand" "f") + (match_operand:DI 2 "fpr_operand" "f") + (match_dup 4)] + UNSPEC_MQCPX)) + (set (match_operand:HI 3 "accg_operand" "=B") + (unspec:HI [(const_int 0)] UNSPEC_MQCPX))])] + "TARGET_MEDIA" + "operands[4] = GEN_INT (FRV_BUILTIN_MQCPXIS);") + +(define_expand "mqcpxiu" + [(parallel [(set (match_operand:DI 0 "even_acc_operand" "=b") + (unspec:DI [(match_operand:DI 1 "fpr_operand" "f") + (match_operand:DI 2 "fpr_operand" "f") + (match_dup 4)] + UNSPEC_MQCPX)) + (set (match_operand:HI 3 "accg_operand" "=B") + (unspec:HI [(const_int 0)] UNSPEC_MQCPX))])] + "TARGET_MEDIA" + "operands[4] = GEN_INT (FRV_BUILTIN_MQCPXIU);") + +(define_insn "*mqcpx" + [(set (match_operand:DI 0 "even_acc_operand" "=b") + (unspec:DI [(match_operand:DI 1 "fpr_operand" "f") + (match_operand:DI 2 "fpr_operand" "f") + (match_operand:SI 3 "const_int_operand" "n")] + UNSPEC_MQCPX)) + (set (match_operand:HI 4 "accg_operand" "=B") + (unspec:HI [(const_int 0)] UNSPEC_MQCPX))] + "TARGET_MEDIA" + "* +{ + switch (INTVAL (operands[3])) + { + default: break; + case FRV_BUILTIN_MQCPXRS: return \"mqcpxrs %1, %2, %0\"; + case FRV_BUILTIN_MQCPXRU: return \"mqcpxru %1, %2, %0\"; + case FRV_BUILTIN_MQCPXIS: return \"mqcpxis %1, %2, %0\"; + case FRV_BUILTIN_MQCPXIU: return \"mqcpxiu %1, %2, %0\"; + } + + fatal_insn (\"Bad media insn, mqcpx\", insn); +}" + [(set_attr "length" "4") + (set_attr "type" "mqcpx")]) + +;; Cut: type "mcut" + +(define_expand "mcut" + [(set (match_operand:SI 0 "fpr_operand" "=f") + (unspec:SI [(match_operand:SI 1 "acc_operand" "a") + (match_operand:SI 2 "fpr_or_int6_operand" "fI") + (match_operand:QI 3 "accg_operand" "B") + (match_dup 4)] + UNSPEC_MCUT))] + "TARGET_MEDIA" + "operands[4] = GEN_INT (FRV_BUILTIN_MCUT);") + +(define_expand "mcutss" + [(set (match_operand:SI 0 "fpr_operand" "=f") + (unspec:SI [(match_operand:SI 1 "acc_operand" "a") + (match_operand:SI 2 "fpr_or_int6_operand" "fI") + (match_operand:QI 3 "accg_operand" "B") + (match_dup 4)] + UNSPEC_MCUT))] + "TARGET_MEDIA" + "operands[4] = GEN_INT (FRV_BUILTIN_MCUTSS);") + +(define_insn "*mcut" + [(set (match_operand:SI 0 "fpr_operand" "=f") + (unspec:SI [(match_operand:SI 1 "acc_operand" "a") + (match_operand:SI 2 "fpr_or_int6_operand" "fI") + (match_operand:QI 3 "accg_operand" "B") + (match_operand:SI 4 "const_int_operand" "n")] + UNSPEC_MCUT))] + "TARGET_MEDIA" + "* +{ + switch (INTVAL (operands[4])) + { + default: break; + case FRV_BUILTIN_MCUT: return \"mcut%i2 %1, %2, %0\"; + case FRV_BUILTIN_MCUTSS: return \"mcutss%i2 %1, %2, %0\"; + } + + fatal_insn (\"Bad media insn, mcut\", insn); +}" + [(set_attr "length" "4") + (set_attr "type" "mcut")]) + +;; Accumulator read: type "mrdacc" + +(define_insn "mrdacc" + [(set (match_operand:SI 0 "fpr_operand" "=f") + (unspec:SI [(match_operand:SI 1 "acc_operand" "a")] UNSPEC_MRDACC))] + "TARGET_MEDIA" + "mrdacc %1, %0" + [(set_attr "length" "4") + (set_attr "type" "mrdacc")]) + +(define_insn "mrdaccg" + [(set (match_operand:SI 0 "fpr_operand" "=f") + (unspec:SI [(match_operand:QI 1 "accg_operand" "B")] UNSPEC_MRDACCG))] + "TARGET_MEDIA" + "mrdaccg %1, %0" + [(set_attr "length" "4") + (set_attr "type" "mrdacc")]) + +;; Accumulator write: type "mwtacc" + +(define_insn "mwtacc" + [(set (match_operand:SI 0 "acc_operand" "=a") + (unspec:SI [(match_operand:SI 1 "fpr_operand" "f")] UNSPEC_MWTACC))] + "TARGET_MEDIA" + "mwtacc %1, %0" + [(set_attr "length" "4") + (set_attr "type" "mwtacc")]) + +(define_insn "mwtaccg" + [(set (match_operand:QI 0 "accg_operand" "=B") + (unspec:QI [(match_operand:SI 1 "fpr_operand" "f")] UNSPEC_MWTACCG))] + "TARGET_MEDIA" + "mwtaccg %1, %0" + [(set_attr "length" "4") + (set_attr "type" "mwtacc")]) + +;; Trap: This one executes on the control unit, not the media units. + +(define_insn "mtrap" + [(unspec_volatile [(const_int 0)] UNSPEC_MTRAP)] + "TARGET_MEDIA" + "mtrap" + [(set_attr "length" "4") + (set_attr "type" "trap")]) + +;; Clear single accumulator: type "mclracc" + +(define_insn "mclracc_internal" + [(set (match_operand:SI 0 "acc_operand" "=a") + (unspec:SI [(const_int 0)] UNSPEC_MCLRACC)) + (set (match_operand:QI 1 "accg_operand" "=B") + (unspec:QI [(const_int 0)] UNSPEC_MCLRACC))] + "TARGET_MEDIA" + "mclracc %0,#0" + [(set_attr "length" "4") + (set_attr "type" "mclracc")]) + +(define_expand "mclracc" + [(parallel [(set (match_operand:SI 0 "acc_operand" "=a") + (unspec:SI [(const_int 0)] UNSPEC_MCLRACC)) + (set (match_dup 1) + (unspec:QI [(const_int 0)] UNSPEC_MCLRACC))])] + "TARGET_MEDIA" + " +{ + if (GET_CODE (operands[0]) != REG || !ACC_P (REGNO (operands[0]))) + FAIL; + + operands[1] = frv_matching_accg_for_acc (operands[0]); +}") + +;; Clear all accumulators: type "mclracca" + +(define_insn "mclracca8_internal" + [(set (match_operand:V4SI 0 "quad_acc_operand" "=b") + (unspec:V4SI [(const_int 0)] UNSPEC_MCLRACCA)) + (set (match_operand:V4SI 1 "quad_acc_operand" "=b") + (unspec:V4SI [(const_int 0)] UNSPEC_MCLRACCA)) + (set (match_operand:V4QI 2 "accg_operand" "=B") + (unspec:V4QI [(const_int 0)] UNSPEC_MCLRACCA)) + (set (match_operand:V4QI 3 "accg_operand" "=B") + (unspec:V4QI [(const_int 0)] UNSPEC_MCLRACCA))] + "TARGET_MEDIA && TARGET_ACC_8" + "mclracc acc0,#1" + [(set_attr "length" "4") + (set_attr "type" "mclracca")]) + +(define_insn "mclracca4_internal" + [(set (match_operand:V4SI 0 "quad_acc_operand" "=b") + (unspec:V4SI [(const_int 0)] UNSPEC_MCLRACCA)) + (set (match_operand:V4QI 1 "accg_operand" "=B") + (unspec:V4QI [(const_int 0)] UNSPEC_MCLRACCA))] + "TARGET_MEDIA && TARGET_ACC_4" + "mclracc acc0,#1" + [(set_attr "length" "4") + (set_attr "type" "mclracca")]) + +(define_expand "mclracca8" + [(parallel [(set (match_dup 0) (unspec:V4SI [(const_int 0)] UNSPEC_MCLRACCA)) + (set (match_dup 1) (unspec:V4SI [(const_int 0)] UNSPEC_MCLRACCA)) + (set (match_dup 2) (unspec:V4QI [(const_int 0)] UNSPEC_MCLRACCA)) + (set (match_dup 3) (unspec:V4QI [(const_int 0)] UNSPEC_MCLRACCA))])] + "TARGET_MEDIA && TARGET_ACC_8" + " +{ + operands[0] = gen_rtx_REG (V4SImode, ACC_FIRST); + operands[1] = gen_rtx_REG (V4SImode, ACC_FIRST + (~3 & ACC_MASK)); + operands[2] = gen_rtx_REG (V4QImode, ACCG_FIRST); + operands[3] = gen_rtx_REG (V4QImode, ACCG_FIRST + (~3 & ACC_MASK)); +}") + +(define_expand "mclracca4" + [(parallel [(set (match_dup 0) (unspec:V4SI [(const_int 0)] UNSPEC_MCLRACCA)) + (set (match_dup 1) (unspec:V4QI [(const_int 0)] UNSPEC_MCLRACCA))])] + "TARGET_MEDIA && TARGET_ACC_4" + " +{ + operands[0] = gen_rtx_REG (V4SImode, ACC_FIRST); + operands[1] = gen_rtx_REG (V4QImode, ACCG_FIRST); +}") + +(define_insn "mcop1" + [(set (match_operand:SI 0 "fpr_operand" "=f") + (unspec:SI [(match_operand:SI 1 "fpr_operand" "f") + (match_operand:SI 2 "fpr_operand" "f")] UNSPEC_MCOP1))] + "TARGET_MEDIA_REV1" + "mcop1 %1, %2, %0" + [(set_attr "length" "4") +;; What is the class of the insn ??? + (set_attr "type" "multi")]) + +(define_insn "mcop2" + [(set (match_operand:SI 0 "fpr_operand" "=f") + (unspec:SI [(match_operand:SI 1 "fpr_operand" "f") + (match_operand:SI 2 "fpr_operand" "f")] UNSPEC_MCOP2))] + "TARGET_MEDIA_REV1" + "mcop2 %1, %2, %0" + [(set_attr "length" "4") +;; What is the class of the insn ??? + (set_attr "type" "multi")]) + +(define_insn "*mdunpackh_internal" + [(set (match_operand:V4SI 0 "quad_fpr_operand" "=x") + (unspec:V4SI [(match_operand:DI 1 "even_fpr_operand" "h")] + UNSPEC_MDUNPACKH_INTERNAL))] + "TARGET_MEDIA_REV1" + "mdunpackh %1, %0" + [(set_attr "length" "4") + (set_attr "type" "mdunpackh")]) + +(define_insn_and_split "mdunpackh" + [(set (match_operand:V4SI 0 "memory_operand" "=o") + (unspec:V4SI [(match_operand:DI 1 "even_fpr_operand" "h")] + UNSPEC_MDUNPACKH)) + (clobber (match_scratch:V4SI 2 "=x"))] + "TARGET_MEDIA_REV1" + "#" + "reload_completed" + [(set (match_dup 2) + (unspec:V4SI [(match_dup 1)] UNSPEC_MDUNPACKH_INTERNAL)) + (set (match_dup 3) + (match_dup 4)) + (set (match_dup 5) + (match_dup 6))] + " +{ + operands[3] = change_address (operands[0], DImode, NULL_RTX); + operands[4] = gen_rtx_REG (DImode, REGNO (operands[2])); + operands[5] = frv_index_memory (operands[0], DImode, 1); + operands[6] = gen_rtx_REG (DImode, REGNO (operands[2])+2); +}" + [(set_attr "length" "20") + (set_attr "type" "multi")]) + +(define_insn "*mbtohe_internal" + [(set (match_operand:V4SI 0 "quad_fpr_operand" "=x") + (unspec:V4SI [(match_operand:SI 1 "fpr_operand" "f")] + UNSPEC_MBTOHE_INTERNAL))] + "TARGET_MEDIA_REV1" + "mbtohe %1, %0" + [(set_attr "length" "4") + (set_attr "type" "mbhconve")]) + +(define_insn_and_split "mbtohe" + [(set (match_operand:V4SI 0 "memory_operand" "=o") + (unspec:V4SI [(match_operand:SI 1 "fpr_operand" "f")] + UNSPEC_MBTOHE)) + (clobber (match_scratch:V4SI 2 "=x"))] + "TARGET_MEDIA_REV1" + "#" + "reload_completed" + [(set (match_dup 2) + (unspec:V4SI [(match_dup 1)] UNSPEC_MBTOHE_INTERNAL)) + (set (match_dup 3) + (match_dup 4)) + (set (match_dup 5) + (match_dup 6))] + " +{ + operands[3] = change_address (operands[0], DImode, NULL_RTX); + operands[4] = gen_rtx_REG (DImode, REGNO (operands[2])); + operands[5] = frv_index_memory (operands[0], DImode, 1); + operands[6] = gen_rtx_REG (DImode, REGNO (operands[2])+2); +}" + [(set_attr "length" "20") + (set_attr "type" "multi")]) + +;; Quad product-sum (halfword) instructions only found on the FR400. +;; type "mqmach" + +(define_expand "mqxmachs" + [(parallel [(set (match_operand:V4SI 0 "quad_acc_operand" "") + (unspec:V4SI [(match_dup 0) + (match_operand:DI 1 "even_fpr_operand" "") + (match_operand:DI 2 "even_fpr_operand" "") + (match_operand:V4QI 3 "accg_operand" "") + (match_dup 4)] + UNSPEC_MQMACH2)) + (set (match_dup 3) + (unspec:V4QI [(const_int 0)] UNSPEC_MQMACH2))])] + "TARGET_MEDIA_REV2" + "operands[4] = GEN_INT (FRV_BUILTIN_MQXMACHS);") + +(define_expand "mqxmacxhs" + [(parallel [(set (match_operand:V4SI 0 "quad_acc_operand" "") + (unspec:V4SI [(match_dup 0) + (match_operand:DI 1 "even_fpr_operand" "") + (match_operand:DI 2 "even_fpr_operand" "") + (match_operand:V4QI 3 "accg_operand" "") + (match_dup 4)] + UNSPEC_MQMACH2)) + (set (match_dup 3) + (unspec:V4QI [(const_int 0)] UNSPEC_MQMACH2))])] + "TARGET_MEDIA_REV2" + "operands[4] = GEN_INT (FRV_BUILTIN_MQXMACXHS);") + +(define_expand "mqmacxhs" + [(parallel [(set (match_operand:V4SI 0 "quad_acc_operand" "") + (unspec:V4SI [(match_dup 0) + (match_operand:DI 1 "even_fpr_operand" "") + (match_operand:DI 2 "even_fpr_operand" "") + (match_operand:V4QI 3 "accg_operand" "") + (match_dup 4)] + UNSPEC_MQMACH2)) + (set (match_dup 3) + (unspec:V4QI [(const_int 0)] UNSPEC_MQMACH2))])] + "TARGET_MEDIA_REV2" + "operands[4] = GEN_INT (FRV_BUILTIN_MQMACXHS);") + +(define_insn "*mqmach2" + [(set (match_operand:V4SI 0 "quad_acc_operand" "+A") + (unspec:V4SI [(match_dup 0) + (match_operand:DI 1 "even_fpr_operand" "h") + (match_operand:DI 2 "even_fpr_operand" "h") + (match_operand:V4QI 3 "accg_operand" "+B") + (match_operand:SI 4 "const_int_operand" "n")] + UNSPEC_MQMACH2)) + (set (match_dup 3) + (unspec:V4QI [(const_int 0)] UNSPEC_MQMACH2))] + "TARGET_MEDIA_REV2" + "* +{ + switch (INTVAL (operands[4])) + { + default: break; + case FRV_BUILTIN_MQXMACHS: return \"mqxmachs %1, %2, %0\"; + case FRV_BUILTIN_MQXMACXHS: return \"mqxmacxhs %1, %2, %0\"; + case FRV_BUILTIN_MQMACXHS: return \"mqmacxhs %1, %2, %0\"; + } + + fatal_insn (\"Bad media insn, mqmach2\", insn); +}" + [(set_attr "length" "4") + (set_attr "type" "mqmach")]) + +;; Accumulator addition/subtraction: type "maddacc" + +(define_expand "maddaccs" + [(parallel [(set (match_operand:SI 0 "acc_operand" "") + (unspec:SI [(match_operand:DI 1 "even_acc_operand" "")] + UNSPEC_MADDACC)) + (set (match_operand:QI 2 "accg_operand" "") + (unspec:QI [(match_operand:HI 3 "accg_operand" "") + (match_dup 4)] + UNSPEC_MADDACC))])] + "TARGET_MEDIA_REV2" + "operands[4] = GEN_INT (FRV_BUILTIN_MADDACCS);") + +(define_expand "msubaccs" + [(parallel [(set (match_operand:SI 0 "acc_operand" "") + (unspec:SI [(match_operand:DI 1 "even_acc_operand" "")] + UNSPEC_MADDACC)) + (set (match_operand:QI 2 "accg_operand" "") + (unspec:QI [(match_operand:HI 3 "accg_operand" "") + (match_dup 4)] + UNSPEC_MADDACC))])] + "TARGET_MEDIA_REV2" + "operands[4] = GEN_INT (FRV_BUILTIN_MSUBACCS);") + +(define_insn "masaccs" + [(set (match_operand:DI 0 "even_acc_operand" "=b") + (unspec:DI [(match_operand:DI 1 "even_acc_operand" "b")] + UNSPEC_MASACCS)) + (set (match_operand:HI 2 "accg_operand" "=B") + (unspec:HI [(match_operand:HI 3 "accg_operand" "B")] + UNSPEC_MASACCS))] + "TARGET_MEDIA_REV2" + "masaccs %1, %0" + [(set_attr "length" "4") + (set_attr "type" "maddacc")]) + +(define_insn "*maddacc" + [(set (match_operand:SI 0 "acc_operand" "=a") + (unspec:SI [(match_operand:DI 1 "even_acc_operand" "b")] + UNSPEC_MADDACC)) + (set (match_operand:QI 2 "accg_operand" "=B") + (unspec:QI [(match_operand:HI 3 "accg_operand" "B") + (match_operand:SI 4 "const_int_operand" "n")] + UNSPEC_MADDACC))] + "TARGET_MEDIA_REV2" + "* +{ + switch (INTVAL (operands[4])) + { + default: break; + case FRV_BUILTIN_MADDACCS: return \"maddaccs %1, %0\"; + case FRV_BUILTIN_MSUBACCS: return \"msubaccs %1, %0\"; + } + + fatal_insn (\"Bad media insn, maddacc\", insn); +}" + [(set_attr "length" "4") + (set_attr "type" "maddacc")]) + +;; Dual accumulator addition/subtraction: type "mdaddacc" + +(define_expand "mdaddaccs" + [(parallel [(set (match_operand:DI 0 "even_acc_operand" "") + (unspec:DI [(match_operand:V4SI 1 "quad_acc_operand" "")] + UNSPEC_MDADDACC)) + (set (match_operand:HI 2 "accg_operand" "") + (unspec:HI [(match_operand:V4QI 3 "accg_operand" "") + (match_dup 4)] + UNSPEC_MDADDACC))])] + "TARGET_MEDIA_REV2" + "operands[4] = GEN_INT (FRV_BUILTIN_MDADDACCS);") + +(define_expand "mdsubaccs" + [(parallel [(set (match_operand:DI 0 "even_acc_operand" "") + (unspec:DI [(match_operand:V4SI 1 "quad_acc_operand" "")] + UNSPEC_MDADDACC)) + (set (match_operand:HI 2 "accg_operand" "") + (unspec:HI [(match_operand:V4QI 3 "accg_operand" "") + (match_dup 4)] + UNSPEC_MDADDACC))])] + "TARGET_MEDIA_REV2" + "operands[4] = GEN_INT (FRV_BUILTIN_MDSUBACCS);") + +(define_insn "mdasaccs" + [(set (match_operand:V4SI 0 "quad_acc_operand" "=A") + (unspec:V4SI [(match_operand:V4SI 1 "quad_acc_operand" "A")] + UNSPEC_MDASACCS)) + (set (match_operand:V4QI 2 "accg_operand" "=B") + (unspec:V4QI [(match_operand:V4QI 3 "accg_operand" "B")] + UNSPEC_MDASACCS))] + "TARGET_MEDIA_REV2" + "mdasaccs %1, %0" + [(set_attr "length" "4") + (set_attr "type" "mdaddacc")]) + +(define_insn "*mdaddacc" + [(set (match_operand:DI 0 "even_acc_operand" "=b") + (unspec:DI [(match_operand:V4SI 1 "quad_acc_operand" "A")] + UNSPEC_MDADDACC)) + (set (match_operand:HI 2 "accg_operand" "=B") + (unspec:HI [(match_operand:V4QI 3 "accg_operand" "B") + (match_operand:SI 4 "const_int_operand" "n")] + UNSPEC_MDADDACC))] + "TARGET_MEDIA_REV2" + "* +{ + switch (INTVAL (operands[4])) + { + default: break; + case FRV_BUILTIN_MDADDACCS: return \"mdaddaccs %1, %0\"; + case FRV_BUILTIN_MDSUBACCS: return \"mdsubaccs %1, %0\"; + } + + fatal_insn (\"Bad media insn, mdaddacc\", insn); +}" + [(set_attr "length" "4") + (set_attr "type" "mdaddacc")]) + +;; Dual absolute (halfword): type "mabsh" + +(define_insn "mabshs" + [(set (match_operand:SI 0 "fpr_operand" "=f") + (unspec:SI [(match_operand:SI 1 "fpr_operand" "f")] UNSPEC_MABSHS))] + "TARGET_MEDIA_REV2" + "mabshs %1, %0" + [(set_attr "length" "4") + (set_attr "type" "mabsh")]) + +;; Dual rotate: type "mdrot" + +(define_insn "mdrotli" + [(set (match_operand:DI 0 "even_fpr_operand" "=h") + (unspec:DI [(match_operand:DI 1 "even_fpr_operand" "h") + (match_operand:SI 2 "uint5_operand" "I")] + UNSPEC_MDROTLI))] + "TARGET_MEDIA_REV2" + "mdrotli %1, %2, %0" + [(set_attr "length" "4") + (set_attr "type" "mdrot")]) + +;; Dual coupling (concatenation): type "mcpl" + +(define_insn "mcplhi" + [(set (match_operand:SI 0 "fpr_operand" "=f") + (unspec:SI [(match_operand:DI 1 "fpr_operand" "h") + (match_operand:SI 2 "uint4_operand" "I")] + UNSPEC_MCPLHI))] + "TARGET_MEDIA_REV2" + "mcplhi %1, %2, %0" + [(set_attr "length" "4") + (set_attr "type" "mcpl")]) + +(define_insn "mcpli" + [(set (match_operand:SI 0 "fpr_operand" "=f") + (unspec:SI [(match_operand:DI 1 "fpr_operand" "h") + (match_operand:SI 2 "uint5_operand" "I")] + UNSPEC_MCPLI))] + "TARGET_MEDIA_REV2" + "mcpli %1, %2, %0" + [(set_attr "length" "4") + (set_attr "type" "mcpl")]) + +;; Dual cut: type "mdcut" + +(define_insn "mdcutssi" + [(set (match_operand:DI 0 "even_fpr_operand" "=h") + (unspec:DI [(match_operand:DI 1 "even_acc_operand" "b") + (match_operand:SI 2 "int6_operand" "I") + (match_operand:HI 3 "accg_operand" "B")] + UNSPEC_MDCUTSSI))] + "TARGET_MEDIA_REV2" + "mdcutssi %1, %2, %0" + [(set_attr "length" "4") + (set_attr "type" "mdcut")]) + +;; Quad saturate (halfword): type "mqsath" + +(define_insn "mqsaths" + [(set (match_operand:DI 0 "even_fpr_operand" "=h") + (unspec:DI [(match_operand:DI 1 "even_fpr_operand" "h") + (match_operand:DI 2 "even_fpr_operand" "h")] + UNSPEC_MQSATHS))] + "TARGET_MEDIA_REV2" + "mqsaths %1, %2, %0" + [(set_attr "length" "4") + (set_attr "type" "mqsath")]) + +;; Quad limit instructions: type "mqlimh" + +(define_insn "mqlclrhs" + [(set (match_operand:DI 0 "even_fpr_operand" "=h") + (unspec:DI [(match_operand:DI 1 "even_fpr_operand" "h") + (match_operand:DI 2 "even_fpr_operand" "h")] + UNSPEC_MQLCLRHS))] + "TARGET_MEDIA_FR450" + "mqlclrhs %1, %2, %0" + [(set_attr "length" "4") + (set_attr "type" "mqlimh")]) + +(define_insn "mqlmths" + [(set (match_operand:DI 0 "even_fpr_operand" "=h") + (unspec:DI [(match_operand:DI 1 "even_fpr_operand" "h") + (match_operand:DI 2 "even_fpr_operand" "h")] + UNSPEC_MQLMTHS))] + "TARGET_MEDIA_FR450" + "mqlmths %1, %2, %0" + [(set_attr "length" "4") + (set_attr "type" "mqlimh")]) + +(define_insn "mqsllhi" + [(set (match_operand:DI 0 "even_fpr_operand" "=h") + (unspec:DI [(match_operand:DI 1 "even_fpr_operand" "h") + (match_operand:SI 2 "int6_operand" "I")] + UNSPEC_MQSLLHI))] + "TARGET_MEDIA_FR450" + "mqsllhi %1, %2, %0" + [(set_attr "length" "4") + (set_attr "type" "mqshift")]) + +(define_insn "mqsrahi" + [(set (match_operand:DI 0 "even_fpr_operand" "=h") + (unspec:DI [(match_operand:DI 1 "even_fpr_operand" "h") + (match_operand:SI 2 "int6_operand" "I")] + UNSPEC_MQSRAHI))] + "TARGET_MEDIA_FR450" + "mqsrahi %1, %2, %0" + [(set_attr "length" "4") + (set_attr "type" "mqshift")]) + +;; Set hi/lo instructions: type "mset" + +(define_insn "mhsetlos" + [(set (match_operand:SI 0 "fpr_operand" "=f") + (unspec:SI [(match_operand:SI 1 "fpr_operand" "0") + (match_operand:SI 2 "int12_operand" "NOP")] + UNSPEC_MHSETLOS))] + "TARGET_MEDIA_REV2" + "mhsetlos %2, %0" + [(set_attr "length" "4") + (set_attr "type" "mset")]) + +(define_insn "mhsetloh" + [(set (match_operand:SI 0 "fpr_operand" "=f") + (unspec:SI [(match_operand:SI 1 "fpr_operand" "0") + (match_operand:SI 2 "int5_operand" "I")] + UNSPEC_MHSETLOH))] + "TARGET_MEDIA_REV2" + "mhsetloh %2, %0" + [(set_attr "length" "4") + (set_attr "type" "mset")]) + +(define_insn "mhsethis" + [(set (match_operand:SI 0 "fpr_operand" "=f") + (unspec:SI [(match_operand:SI 1 "fpr_operand" "0") + (match_operand:SI 2 "int12_operand" "NOP")] + UNSPEC_MHSETHIS))] + "TARGET_MEDIA_REV2" + "mhsethis %2, %0" + [(set_attr "length" "4") + (set_attr "type" "mset")]) + +(define_insn "mhsethih" + [(set (match_operand:SI 0 "fpr_operand" "=f") + (unspec:SI [(match_operand:SI 1 "fpr_operand" "0") + (match_operand:SI 2 "int5_operand" "I")] + UNSPEC_MHSETHIH))] + "TARGET_MEDIA_REV2" + "mhsethih %2, %0" + [(set_attr "length" "4") + (set_attr "type" "mset")]) + +(define_insn "mhdsets" + [(set (match_operand:SI 0 "fpr_operand" "=f") + (unspec:SI [(match_operand:SI 1 "int12_operand" "NOP")] + UNSPEC_MHDSETS))] + "TARGET_MEDIA_REV2" + "mhdsets %1, %0" + [(set_attr "length" "4") + (set_attr "type" "mset")]) + +(define_insn "mhdseth" + [(set (match_operand:SI 0 "fpr_operand" "=f") + (unspec:SI [(match_operand:SI 1 "fpr_operand" "0") + (match_operand:SI 2 "int5_operand" "I")] + UNSPEC_MHDSETH))] + "TARGET_MEDIA_REV2" + "mhdseth %2, %0" + [(set_attr "length" "4") + (set_attr "type" "mset")]) + +;;----------------------------------------------------------------------------- + +(define_expand "symGOT2reg" + [(match_operand:SI 0 "" "") + (match_operand:SI 1 "" "") + (match_operand:SI 2 "" "") + (match_operand:SI 3 "" "")] + "" + " +{ + rtx insn; + + insn = emit_insn (gen_symGOT2reg_i (operands[0], operands[1], operands[2], operands[3])); + + MEM_READONLY_P (SET_SRC (PATTERN (insn))) = 1; + + set_unique_reg_note (insn, REG_EQUAL, operands[1]); + + DONE; +}") + +(define_expand "symGOT2reg_i" + [(set (match_operand:SI 0 "" "") + (mem:SI (plus:SI (match_operand:SI 2 "" "") + (const:SI (unspec:SI [(match_operand:SI 1 "" "") + (match_operand:SI 3 "" "")] + UNSPEC_GOT)))))] + "" + "") + +(define_expand "symGOT2reg_hilo" + [(set (match_dup 6) + (high:SI (const:SI (unspec:SI [(match_operand:SI 1 "" "") + (match_dup 4)] UNSPEC_GOT)))) + (set (match_dup 5) + (lo_sum:SI (match_dup 6) + (const:SI (unspec:SI [(match_dup 1) + (match_operand:SI 3 "" "")] + UNSPEC_GOT)))) + (set (match_operand:SI 0 "" "") + (mem:SI (plus:SI (match_dup 5) + (match_operand:SI 2 "" "")))) + ] + "" + " +{ + if (!can_create_pseudo_p ()) + operands[6] = operands[5] = operands[0]; + else + { + operands[6] = gen_reg_rtx (SImode); + operands[5] = gen_reg_rtx (SImode); + } + + operands[4] = GEN_INT (INTVAL (operands[3]) + 1); + operands[3] = GEN_INT (INTVAL (operands[3]) + 2); +}") + +(define_expand "symGOTOFF2reg_hilo" + [(set (match_dup 6) + (high:SI (const:SI (unspec:SI [(match_operand:SI 1 "" "") + (match_dup 4)] UNSPEC_GOT)))) + (set (match_dup 5) + (lo_sum:SI (match_dup 6) + (const:SI (unspec:SI [(match_dup 1) + (match_operand:SI 3 "" "")] + UNSPEC_GOT)))) + (set (match_operand:SI 0 "" "") + (plus:SI (match_dup 5) + (match_operand:SI 2 "" ""))) + ] + "" + " +{ + if (!can_create_pseudo_p ()) + operands[6] = operands[5] = operands[0]; + else + { + operands[6] = gen_reg_rtx (SImode); + operands[5] = gen_reg_rtx (SImode); + } + + operands[4] = GEN_INT (INTVAL (operands[3]) + 1); + operands[3] = GEN_INT (INTVAL (operands[3]) + 2); +}") + +(define_expand "symGOTOFF2reg" + [(match_operand:SI 0 "" "") + (match_operand:SI 1 "" "") + (match_operand:SI 2 "" "") + (match_operand:SI 3 "" "")] + "" + " +{ + rtx insn = emit_insn (gen_symGOTOFF2reg_i (operands[0], operands[1], operands[2], operands[3])); + + set_unique_reg_note (insn, REG_EQUAL, operands[1]); + + DONE; +}") + +(define_expand "symGOTOFF2reg_i" + [(set (match_operand:SI 0 "" "") + (plus:SI (match_operand:SI 2 "" "") + (const:SI + (unspec:SI [(match_operand:SI 1 "" "") + (match_operand:SI 3 "" "")] + UNSPEC_GOT))))] + "" + "") + +(define_expand "symGPREL2reg" + [(match_operand:SI 0 "" "") + (match_operand:SI 1 "" "") + (match_operand:SI 2 "" "") + (match_operand:SI 3 "" "") + (match_dup 4)] + "" + " +{ + rtx insn; + + if (!can_create_pseudo_p ()) + operands[4] = operands[0]; + else + operands[4] = gen_reg_rtx (SImode); + + emit_insn (frv_gen_GPsym2reg (operands[4], operands[2])); + + insn = emit_insn (gen_symGOTOFF2reg_i (operands[0], operands[1], + operands[4], operands[3])); + + set_unique_reg_note (insn, REG_EQUAL, operands[1]); + + DONE; +}") + +(define_expand "symGPREL2reg_hilo" + [(match_operand:SI 0 "" "") + (match_operand:SI 1 "" "") + (match_operand:SI 2 "" "") + (match_operand:SI 3 "" "") + (match_dup 4)] + "" + " +{ + rtx insn; + + if (!can_create_pseudo_p ()) + { + emit_insn (gen_symGOT2reg (operands[0], operands[1], operands[2], + GEN_INT (R_FRV_GOT12))); + DONE; + } + + operands[4] = gen_reg_rtx (SImode); + + emit_insn (frv_gen_GPsym2reg (operands[4], operands[2])); + + insn = emit_insn (gen_symGOTOFF2reg_hilo (operands[0], operands[1], + operands[4], operands[3])); + + set_unique_reg_note (insn, REG_EQUAL, operands[1]); + + DONE; +}") + +(define_constants + [ + (UNSPEC_SMUL 154) + (UNSPEC_UMUL 155) + (UNSPEC_SMU 156) + (UNSPEC_ADDSS 157) + (UNSPEC_SUBSS 158) + (UNSPEC_SLASS 159) + (UNSPEC_SCAN 160) + (UNSPEC_INTSS 161) + (UNSPEC_SCUTSS 162) + (UNSPEC_PREFETCH0 163) + (UNSPEC_PREFETCH 164) + (UNSPEC_IACCreadll 165) + (UNSPEC_IACCreadl 166) + (UNSPEC_IACCsetll 167) + (UNSPEC_IACCsetl 168) + (UNSPEC_SMASS 169) + (UNSPEC_SMSSS 170) + (UNSPEC_IMUL 171) + + (IACC0_REG 171) +]) + +(define_insn "smul" + [(set (match_operand:DI 0 "integer_register_operand" "=d") + (unspec:DI [(match_operand:SI 1 "integer_register_operand" "d") + (match_operand:SI 2 "integer_register_operand" "d")] + UNSPEC_SMUL))] + "" + "smul %1, %2, %0" + [(set_attr "length" "4") + (set_attr "type" "mul")]) + +(define_insn "umul" + [(set (match_operand:DI 0 "integer_register_operand" "=d") + (unspec:DI [(match_operand:SI 1 "integer_register_operand" "d") + (match_operand:SI 2 "integer_register_operand" "d")] + UNSPEC_UMUL))] + "" + "umul %1, %2, %0" + [(set_attr "length" "4") + (set_attr "type" "mul")]) + +(define_insn "smass" + [(set (reg:DI IACC0_REG) + (unspec:DI [(match_operand:SI 0 "integer_register_operand" "d") + (match_operand:SI 1 "integer_register_operand" "d") + (reg:DI IACC0_REG)] + UNSPEC_SMASS))] + "TARGET_FR405_BUILTINS" + "smass %1, %0" + [(set_attr "length" "4") + (set_attr "type" "macc")]) + +(define_insn "smsss" + [(set (reg:DI IACC0_REG) + (unspec:DI [(match_operand:SI 0 "integer_register_operand" "d") + (match_operand:SI 1 "integer_register_operand" "d") + (reg:DI IACC0_REG)] + UNSPEC_SMSSS))] + "TARGET_FR405_BUILTINS" + "smsss %1, %0" + [(set_attr "length" "4") + (set_attr "type" "macc")]) + +(define_insn "smu" + [(set (reg:DI IACC0_REG) + (unspec:DI [(match_operand:SI 0 "integer_register_operand" "d") + (match_operand:SI 1 "integer_register_operand" "d")] + UNSPEC_SMU))] + "TARGET_FR405_BUILTINS" + "smu %1, %0" + [(set_attr "length" "4") + (set_attr "type" "macc")]) + +(define_insn "addss" + [(set (match_operand:SI 0 "integer_register_operand" "=d") + (unspec:SI [(match_operand:SI 1 "integer_register_operand" "d") + (match_operand:SI 2 "integer_register_operand" "d")] + UNSPEC_ADDSS))] + "TARGET_FR405_BUILTINS" + "addss %1, %2, %0" + [(set_attr "length" "4") + (set_attr "type" "int")]) + +(define_insn "subss" + [(set (match_operand:SI 0 "integer_register_operand" "=d") + (unspec:SI [(match_operand:SI 1 "integer_register_operand" "d") + (match_operand:SI 2 "integer_register_operand" "d")] + UNSPEC_SUBSS))] + "TARGET_FR405_BUILTINS" + "subss %1, %2, %0" + [(set_attr "length" "4") + (set_attr "type" "int")]) + +(define_insn "slass" + [(set (match_operand:SI 0 "integer_register_operand" "=d") + (unspec:SI [(match_operand:SI 1 "integer_register_operand" "d") + (match_operand:SI 2 "integer_register_operand" "d")] + UNSPEC_SLASS))] + "TARGET_FR405_BUILTINS" + "slass %1, %2, %0" + [(set_attr "length" "4") + (set_attr "type" "int")]) + +(define_insn "scan" + [(set (match_operand:SI 0 "integer_register_operand" "=d") + (unspec:SI [(match_operand:SI 1 "integer_register_operand" "d") + (match_operand:SI 2 "integer_register_operand" "d")] + UNSPEC_SCAN))] + "" + "scan %1, %2, %0" + [(set_attr "length" "4") + (set_attr "type" "scan")]) + +(define_insn "scutss" + [(set (match_operand:SI 0 "integer_register_operand" "=d") + (unspec:SI [(match_operand:SI 1 "integer_register_operand" "d") + (reg:DI IACC0_REG)] + UNSPEC_SCUTSS))] + "TARGET_FR405_BUILTINS" + "scutss %1,%0" + [(set_attr "length" "4") + (set_attr "type" "cut")]) + +(define_insn "frv_prefetch0" + [(prefetch (unspec:SI [(match_operand:SI 0 "register_operand" "r")] + UNSPEC_PREFETCH0) + (const_int 0) + (const_int 0))] + "" + "dcpl %0, gr0, #0" + [(set_attr "length" "4")]) + +(define_insn "frv_prefetch" + [(prefetch (unspec:SI [(match_operand:SI 0 "register_operand" "r")] + UNSPEC_PREFETCH) + (const_int 0) + (const_int 0))] + "TARGET_FR500_FR550_BUILTINS" + "nop.p\\n\\tnldub @(%0, gr0), gr0" + [(set_attr "length" "8")]) + +;; TLS patterns + +(define_insn "call_gettlsoff" + [(set (match_operand:SI 0 "register_operand" "=D09") + (unspec:SI + [(match_operand:SI 1 "symbolic_operand" "")] + UNSPEC_GETTLSOFF)) + (clobber (reg:SI GR8_REG)) + (clobber (reg:SI LRREG)) + (use (match_operand:SI 2 "register_operand" "D15"))] + "HAVE_AS_TLS" + "call #gettlsoff(%a1)" + [(set_attr "length" "4") + (set_attr "type" "load_or_call")]) + +;; We have to expand this like a libcall (it sort of actually is) +;; because otherwise sched may move, for example, an insn that sets up +;; GR8 for a subsequence call before the *tls_indirect_call insn, and +;; then reload won't be able to fix things up. +(define_expand "tls_indirect_call" + [(set (reg:DI GR8_REG) + (match_operand:DI 2 "register_operand" "")) + (parallel + [(set (reg:SI GR9_REG) + (unspec:SI + [(match_operand:SI 1 "symbolic_operand" "") + (reg:DI GR8_REG)] + UNSPEC_TLS_INDIRECT_CALL)) + (clobber (reg:SI GR8_REG)) + (clobber (reg:SI LRREG)) + (use (match_operand:SI 3 "register_operand" ""))]) + (set (match_operand:SI 0 "register_operand" "") + (reg:SI GR9_REG))] + "HAVE_AS_TLS") + +(define_insn "*tls_indirect_call" + [(set (reg:SI GR9_REG) + (unspec:SI + [(match_operand:SI 0 "symbolic_operand" "") + (reg:DI GR8_REG)] + UNSPEC_TLS_INDIRECT_CALL)) + (clobber (reg:SI GR8_REG)) + (clobber (reg:SI LRREG)) + ;; If there was a way to represent the fact that we don't need GR9 + ;; or GR15 to be set before this instruction (it could be in + ;; parallel), we could use it here. This change wouldn't apply to + ;; call_gettlsoff, thought, since the linker may turn the latter + ;; into ldi @(gr15,offset),gr9. + (use (match_operand:SI 1 "register_operand" "D15"))] + "HAVE_AS_TLS" + "calll #gettlsoff(%a0)@(gr8,gr0)" + [(set_attr "length" "4") + (set_attr "type" "jumpl")]) + +(define_insn "tls_load_gottlsoff12" + [(set (match_operand:SI 0 "register_operand" "=r") + (unspec:SI + [(match_operand:SI 1 "symbolic_operand" "") + (match_operand:SI 2 "register_operand" "r")] + UNSPEC_TLS_LOAD_GOTTLSOFF12))] + "HAVE_AS_TLS" + "ldi @(%2, #gottlsoff12(%1)), %0" + [(set_attr "length" "4")]) + +(define_expand "tlsoff_hilo" + [(set (match_operand:SI 0 "register_operand" "=r") + (high:SI (const:SI (unspec:SI + [(match_operand:SI 1 "symbolic_operand" "") + (match_operand:SI 2 "immediate_operand" "n")] + UNSPEC_GOT)))) + (set (match_dup 0) + (lo_sum:SI (match_dup 0) + (const:SI (unspec:SI [(match_dup 1) + (match_dup 3)] UNSPEC_GOT))))] + "" + " +{ + operands[3] = GEN_INT (INTVAL (operands[2]) + 1); +}") + +;; Just like movdi_ldd, but with relaxation annotations. +(define_insn "tls_tlsdesc_ldd" + [(set (match_operand:DI 0 "register_operand" "=r") + (unspec:DI [(mem:DI (unspec:SI + [(match_operand:SI 1 "register_operand" "r") + (match_operand:SI 2 "register_operand" "r") + (match_operand:SI 3 "symbolic_operand" "")] + UNSPEC_TLS_TLSDESC_LDD_AUX))] + UNSPEC_TLS_TLSDESC_LDD))] + "" + "ldd #tlsdesc(%a3)@(%1,%2), %0" + [(set_attr "length" "4") + (set_attr "type" "gload")]) + +(define_insn "tls_tlsoff_ld" + [(set (match_operand:SI 0 "register_operand" "=r") + (mem:SI (unspec:SI + [(match_operand:SI 1 "register_operand" "r") + (match_operand:SI 2 "register_operand" "r") + (match_operand:SI 3 "symbolic_operand" "")] + UNSPEC_TLS_TLSOFF_LD)))] + "" + "ld #tlsoff(%a3)@(%1,%2), %0" + [(set_attr "length" "4") + (set_attr "type" "gload")]) + +(define_insn "tls_lddi" + [(set (match_operand:DI 0 "register_operand" "=r") + (unspec:DI [(match_operand:SI 1 "symbolic_operand" "") + (match_operand:SI 2 "register_operand" "d")] + UNSPEC_TLS_LDDI))] + "" + "lddi @(%2, #gottlsdesc12(%a1)), %0" + [(set_attr "length" "4") + (set_attr "type" "gload")])