diff options
Diffstat (limited to 'gcc/config/c4x/c4x.md')
-rwxr-xr-x | gcc/config/c4x/c4x.md | 6877 |
1 files changed, 6877 insertions, 0 deletions
diff --git a/gcc/config/c4x/c4x.md b/gcc/config/c4x/c4x.md new file mode 100755 index 0000000..1e3d343 --- /dev/null +++ b/gcc/config/c4x/c4x.md @@ -0,0 +1,6877 @@ +;; Machine description for the TMS320C[34]x for GNU C compiler +;; Copyright (C) 1994-98, 1999 Free Software Foundation, Inc. + +;; Contributed by Michael Hayes (m.hayes@elec.canterbury.ac.nz) +;; and Herman Ten Brugge (Haj.Ten.Brugge@net.HCC.nl) + +;; This file is part of GNU CC. + +;; GNU CC is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 2, or (at your option) +;; any later version. + +;; GNU CC is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GNU CC; see the file COPYING. If not, write to +;; the Free Software Foundation, 59 Temple Place - Suite 330, +;; Boston, MA 02111-1307, USA. + +; +; TODO : +; Set up addressing macros to handle direct memory references properly. +; Try using PQImode again for addresses since C30 only uses +; 24-bit addresses. Ideally GCC would emit different insns +; for QImode and Pmode, whether Pmode was QImode or PQImode. +; For addresses we wouldn't have to have a clobber of the CC +; associated with each insn and we could use MPYI in address +; calculations without having to synthesise a proper 32 bit multiply. + +; Additional C30/C40 instructions not coded: +; CALLcond, IACK, IDLE, LDE, LDFI, LDII, LDM, NORM, RETIcond +; ROLC, RORC, SIGI, STFI, STII, SUBC, SWI, TRAPcond + +; Additional C40 instructions not coded: +; LDEP, LDPE, LWRct, FRIEEE, TOIEEE, LAJcond, LATcond, RETIcondD + +; +; C4x MODES +; +; QImode char, short, int, long (32-bits) +; HImode long long (64-bits) +; QFmode float, double (32-bits) +; HFmode long double (40-bits) +; CCmode +; CC_NOOVmode + +; +; C4x PREDICATES: +; +; comparison_operator LT, GT, LE, GE, LTU, GTU, LEU, GEU, EQ, NE +; memory_operand memory [m] +; immediate_operand immediate constant [IKN] +; register_operand register [rf] +; general_operand register, memory, constant [rfmI] + +; addr_reg_operand AR0-AR7, pseudo reg [a] +; sp_reg_operand SP [b] +; std_reg_operand AR0-AR7, IR0-IR1, RC, RS, RE, SP, pseudo [c] +; ext_reg_operand R0-R11, pseudo reg [f] +; ext_low_reg_operand R0-R7, pseudo reg [q] +; index_reg_operand IR0-IR1, pseudo reg [x] +; st_reg_operand ST [y] +; dp_reg_operand DP [z] +; stik_const_operand 5-bit const [K] +; src_operand general operand [rfmHI] +; par_ind_operand indirect S mode (ARx + 0, 1, IRx) [S<>] +; parallel_operand par_ind_operand or ext_low_reg_operand + +; ADDI src2, src1, dst three operand op +; ADDI src, dst two operand op + +; Note that the predicates are only used when selecting a pattern +; to determine if an operand is valid. + +; The constraints then select which of the possible valid operands +; is present (and guide register selection). The actual assembly +; instruction is then selected on the basis of the constraints. + +; The extra constraint (valid_operands) is used to determine if +; the combination of operands is legitimate for the pattern. + +; +; C4x CONSTRAINTS: +; +; a address reg AR0-AR7 +; b stack pointer SP +; c other int reg AR0-AR7, IR0-IR1, RC, RS, RE +; d fp reg R0-R11 (sets CC when dst) +; e +; f fp reg R0-R11 (sets CC when dst) +; g general reg, memory, constant +; h fp reg (HFmode) R0-R11 (sets CC when dst) +; i immediate int constant +; j +; k block count BK +; l +; m memory +; n immediate int constant with known numeric value +; o offsettable memory +; p memory address +; q low fp reg R0-R7 (sets CC when dst) +; r general reg R0-R11, AR0-AR7, IR0-IR1, RC, RS, RE +; s immediate int constant (value not explicit) +; t R0-R1 +; u R2-R3 +; v repeat count reg RC +; w +; x index reg IR0-IR1 +; y status (CC) reg ST +; z data pointer DP + +; G fp zero +; H fp 16-bit constant +; I signed 16-bit +; J signed 8-bit (C4x only) +; K signed 5-bit (C4x only) +; L unsigned 16-bit +; M unsigned 8-bit (C4x only) +; N ones complement of unsigned 16-bit +; O 16 bit high constant +; Q ARx + 9-bit signed disp +; R ARx + 5-bit unsigned disp (C4x only) +; S ARx + 0, 1, IRx disp +; T symbol ref (direct) +; V non offsettable memory +; X any operand +; < memory operand with autodecrement addressing +; > memory operand with autoincrement addressing +; { memory operand with pre-modify addressing +; } memory operand with post-modify addressing + +; Note that the d, f, and h constraints are equivalent. +; The m constraint is equivalent to QT<>{} + +; Note that the constraints are used to select the operands +; for a chosen pattern. The constraint that requires the fewest +; instructions to load an operand is chosen. + +; Note that the 'r' constraint is mostly only used for src integer register +; operands, while 'c' and 'd' constraints are generally only used for dst +; integer register operands (the 'r' constraint is the union of the 'c' and +; 'd' constraints). When a register satisfying the 'd' constraint +; is used as a dst operand, the CC gets clobbered (except for LDIcond)---but +; not for 'c'. + +; The 'f' constraint is only for float register operands---when +; a register satisying the 'f' constraint is used as a dst operand, +; the CC gets clobbered (except for LDFcond). + +; The ! in front of the 'b' constaint says to GCC to disparage the +; use of this constraint. The 'b' constraint applies only to the SP. + +; Note that we deal with the condition code CC like some of the RISC +; architectures (arm, sh, sparc) where it is stored in a general register, +; in this case the hard register ST (21). Unlike these other architectures +; that do not set the CC with many instructions, the C[34]x architectures +; sets the CC for many instructions when the destination register is +; an extended precision register. While it would have been easier +; to use the generic cc0 register to store the CC, as with most of +; the other ported architectures, this constrains the setting and testing +; of the CC to be consecutive insns. Thus we would reduce the benefit +; of scheduling instructions to avoid pipeline conflicts and filling of +; delayed branch slots. + +; Since the C[34]x has many instructions that set the CC, we pay the +; price of having to explicity define which insns clobber the CC +; (rather than using the macro NOTICE_UPDATE_CC). + +; Note that many patterns say that the CC is clobbered when in fact +; that it may not be (depending on the destination register). +; We have to cover ourselves if an extended precision register +; is allocated to the destination register. +; Unfortunately, it is not easy to tell GCC that the clobbering of CC +; is register dependent. If we could tolerate the ST register being +; copied about, then we could store the CC in a pseudo register and +; use constructs such as (clobber (match_scratch:CC N "&y,X")) to +; indicate that the 'y' class (ST register) is clobbered for the +; first combination of operands, but not with the second. +; I tried this approach for a while but reload got unhappy since I +; didn't allow it to move the CC around. + +; Note that fundamental operations, such as moves, must not clobber the +; CC. Thus movqi choses a move instruction that doesn't clobber the CC. +; If GCC wants to combine a move with a compare, it is smart enough to +; chose the move instruction that sets the CC. + +; Unfortunately, the C[34]x instruction set does not have arithmetic or +; logical operations that never touch the CC. We thus have to assume +; that the CC may be clobbered at all times. If we define patterns +; such as addqi without the clobber of CC, then GCC will be forced +; to use registers such as the auxiliary registers which can cause +; horrible pipeline conflicts. The tradeoff is that GCC can't now +; sneak in an add instruction between setting and testing of the CC. + +; Most of the C[34]x instructions require operands of the following formats, +; where imm represents an immediate constant, dir a direct memory reference, +; ind an indirect memory reference, and reg a register: + +; src2 (op2) src1 (op1) dst (op0) +; imm dir ind reg | imm dir ind reg | reg Notes +;---------------------+----------------------+------ +; ILH T Q<> r | - - - 0 | r 2 operand +; - - S<> r | - - S<> r | r +; J - R - | - - R r | r C4x + +; Arithmetic operations use the I, J constraints for immediate constants, +; while logical operations use the L, J constraints. Floating point +; operations use the H constraint for immediate constants. + +; With most instructions the src2 and src1 operands are commutative +; (except for SUB, SUBR, ANDN). The assembler considers +; ADDI 10, R0, R1 and ADDI R0, 10, R1 to be equivalent. +; We thus match src2 and src1 with the src_operand predicate and +; use valid_operands as the extra constraint to reject invalid +; operand combinations. For example, ADDI @foo, @bar, R0. + +; Note that we use the ? modifier so that reload doesn't preferentially +; try the alternative where three registers are acceptable as +; operands (whenever an operand requires reloading). Instead it will try +; the 2 operand form which will produce better code since it won't require +; a new spill register. + +; Note that the floating point representation of 0.0 on the C4x +; is 0x80000000 (-2147483648). This value produces an warning +; message on 32-bit machines about the decimal constant being so large +; that it is unsigned. + +; With two operand instructions patterns having two sets, +; the compare set must come first to keep the combiner happy. +; While the combiner seems to cope most of the time with the +; compare set coming second, it's best to have it first. + +; +; C4x CONSTANT attributes +; +(define_attr "cpu" "c4x,c3x" + (const + (cond [(symbol_ref "TARGET_C3X") (const_string "c3x")] + (const_string "c4x")))) + +; +; C4x INSN ATTRIBUTES: +; +; lda load address, non-clobber CC +; store memory store, non-clobber CC +; load_load parallel memory loads, non-clobber CC +; load_store parallel memory load and store, non-clobber CC +; store_load parallel memory store and load, non-clobber CC +; store_store parallel memory stores, non-clobber CC +; unary two operand arithmetic, non-clobber CC +; unarycc two operand arithmetic, clobber CC +; binary three operand arithmetic, non-clobber CC +; binarycc three operand arithmetic, clobber CC +; compare compare, clobber CC +; call function call +; rets return from subroutine +; jump unconditional branch +; jmpc conditional branch +; db decrement and branch (unconditional) +; dbc decrement and branch (conditional) +; ldp load DP +; push stack push +; pop stack pop +; repeat block repeat +; repeat_top block repeat top +; laj link and jump +; multi multiple instruction +; misc nop (default) + +; The only real instructions that affect things are the ones that modify +; address registers and ones that call or jump. Note that the number +; of operands refers to the RTL insn pattern, not the number of explicit +; operands in the machine instruction. +; +(define_attr "type" "lda,store,unary,unarycc,binary,binarycc,compare,call,rets,jump,jmpc,db,dbc,misc,ldp,repeat,repeat_top,laj,load_load,load_store,store_load,store_store,push,pop,multi" + (const_string "misc")) + + +; Some instructions operate on unsigned data constants, some on signed data +; constants, or the ones complement of unsigned constants. +; This differentiates them. Default to signed. This attribute +; is used by the macro SMALL_CONST () (defined in c4x.h) to determine +; whether an immediate integer constant will fit within the instruction, +; or will have to be loaded using direct addressing from memory. +; Note that logical operations assume unsigned integers whereas +; arithmetic operations assume signed integers. Note that the C4x +; small immediate constant (J) used as src2 in three operand instructions +; is always signed. not_uint16 refers to a number that fits into 16-bits +; when one's complemented. +; +(define_attr "data" "int16,uint16,high_16,not_uint16" (const_string "int16")) + +(define_asm_attributes + [(set_attr "type" "multi")]) + +; +; C4x DELAY SLOTS +; +; Define delay slot scheduling for branch and call instructions. +; The C[34]x has three delay slots. Note that none of the three instructions +; that follow a delayed branch can be a Bcond, BcondD, BR, BRD, DBcond, +; DBcondD, CALL, CALLcond, TRAPcond, RETIcond, RETScond, RPTB, RPTS, or IDLE. +; +; Annulled branches are a bit difficult because the next instructions +; are preprocessed. +; The table below shows what phase of the c4x is executed. +; BccA[TF] label +; op1 fetch, decode and read executed +; op2 fetch and decode executed +; op3 fetch executed +; This means that we can allow any instruction in the last delay slot +; and only instructions which modify registers in the first two. +; lda can not be executed in the first delay slot +; and ldpk can not be executed in the first two delay slots. + +(define_attr "onlyreg" "false,true" + (cond [(eq_attr "type" "unary,unarycc") + (if_then_else (and (match_operand 0 "reg_imm_operand" "") + (match_operand 1 "reg_imm_operand" "")) + (const_string "true") (const_string "false")) + (eq_attr "type" "binary,binarycc") + (if_then_else (and (match_operand 0 "reg_imm_operand" "") + (and (match_operand 1 "reg_imm_operand" "") + (match_operand 2 "reg_imm_operand" ""))) + (const_string "true") (const_string "false"))] + (const_string "false"))) + +(define_attr "onlyreg_nomod" "false,true" + (cond [(eq_attr "type" "unary,unarycc,compare,lda,store") + (if_then_else (and (match_operand 0 "not_modify_reg" "") + (match_operand 1 "not_modify_reg" "")) + (const_string "true") (const_string "false")) + (eq_attr "type" "binary,binarycc") + (if_then_else (and (match_operand 0 "not_modify_reg" "") + (and (match_operand 1 "not_modify_reg" "") + (match_operand 2 "not_modify_reg" ""))) + (const_string "true") (const_string "false"))] + (const_string "false"))) + +(define_attr "not_repeat_reg" "false,true" + (cond [(eq_attr "type" "unary,unarycc,compare,lda,store") + (if_then_else (and (match_operand 0 "not_rc_reg" "") + (match_operand 1 "not_rc_reg" "")) + (const_string "true") (const_string "false")) + (eq_attr "type" "binary,binarycc") + (if_then_else (and (match_operand 0 "not_rc_reg" "") + (and (match_operand 1 "not_rc_reg" "") + (match_operand 2 "not_rc_reg" ""))) + (const_string "true") (const_string "false"))] + (const_string "false"))) + +(define_attr "in_annul_slot_1" "false,true" + (if_then_else (and (and (eq_attr "cpu" "c4x") + (eq_attr "type" "!jump,call,rets,jmpc,compare,db,dbc,repeat,repeat_top,laj,push,pop,lda,ldp,multi")) + (eq_attr "onlyreg" "true")) + (const_string "true") + (const_string "false"))) + +(define_attr "in_annul_slot_2" "false,true" + (if_then_else (and (and (eq_attr "cpu" "c4x") + (eq_attr "type" "!jump,call,rets,jmpc,db,dbc,repeat,repeat_top,laj,push,pop,ldp,multi")) + (eq_attr "onlyreg_nomod" "true")) + (const_string "true") + (const_string "false"))) + +(define_attr "in_annul_slot_3" "false,true" + (if_then_else (and (eq_attr "cpu" "c4x") + (eq_attr "type" "!jump,call,rets,jmpc,unarycc,binarycc,db,dbc,repeat,repeat_top,laj,push,pop,multi")) + (const_string "true") + (const_string "false"))) + +(define_attr "in_delay_slot" "false,true" + (if_then_else (eq_attr "type" "!jump,call,rets,jmpc,db,dbc,repeat,repeat_top,laj,multi") + (const_string "true") + (const_string "false"))) + +(define_attr "in_repeat_slot" "false,true" + (if_then_else (and (eq_attr "cpu" "c4x") + (and (eq_attr "type" "!jump,call,rets,jmpc,db,dbc,repeat,repeat_top,laj,multi") + (eq_attr "not_repeat_reg" "true"))) + (const_string "true") + (const_string "false"))) + +(define_attr "in_dbc_slot" "false,true" + (if_then_else (eq_attr "type" "!jump,call,rets,jmpc,unarycc,binarycc,compare,db,dbc,repeat,repeat_top,laj,multi") + (const_string "true") + (const_string "false"))) + +(define_delay (eq_attr "type" "jmpc") + [(eq_attr "in_delay_slot" "true") + (eq_attr "in_annul_slot_1" "true") + (eq_attr "in_annul_slot_1" "true") + + (eq_attr "in_delay_slot" "true") + (eq_attr "in_annul_slot_2" "true") + (eq_attr "in_annul_slot_2" "true") + + (eq_attr "in_delay_slot" "true") + (eq_attr "in_annul_slot_3" "true") + (eq_attr "in_annul_slot_3" "true") ]) + + +(define_delay (eq_attr "type" "repeat_top") + [(eq_attr "in_repeat_slot" "true") (nil) (nil) + (eq_attr "in_repeat_slot" "true") (nil) (nil) + (eq_attr "in_repeat_slot" "true") (nil) (nil)]) + +(define_delay (eq_attr "type" "jump,db") + [(eq_attr "in_delay_slot" "true") (nil) (nil) + (eq_attr "in_delay_slot" "true") (nil) (nil) + (eq_attr "in_delay_slot" "true") (nil) (nil)]) + + +; Decrement and branch conditional instructions cannot modify the +; condition codes for the cycles in the delay slots. +; +(define_delay (eq_attr "type" "dbc") + [(eq_attr "in_dbc_slot" "true") (nil) (nil) + (eq_attr "in_dbc_slot" "true") (nil) (nil) + (eq_attr "in_dbc_slot" "true") (nil) (nil)]) + +; The LAJ instruction has three delay slots but the last slot is +; used for pushing the return address. Thus we can only use two slots. +; +(define_delay (eq_attr "type" "laj") + [(eq_attr "in_delay_slot" "true") (nil) (nil) + (eq_attr "in_delay_slot" "true") (nil) (nil)]) + +; +; C4x UNSPEC NUMBERS +; +; 1 BU/BUD +; 2 RPTS +; 3 LSH +; 4 cmphi +; 5 RCPF +; 6 RND +; 7 repeat block filler +; 8 loadhf_int +; 9 storehf_int +; 10 RSQRF + + +; +; C4x FUNCTIONAL UNITS +; +; Define functional units for instruction scheduling to minimise +; pipeline conflicts. +; +; With the C3x, an external memory write (with no wait states) takes +; two cycles and an external memory read (with no wait states) takes +; one cycle. However, an external read following an external write +; takes two cycles. With internal memory, reads and writes take +; half a cycle. +; +; When a C4x address register is loaded it will not be available for +; an extra machine cycle. Calculating with a C4x address register +; makes it unavailable for 2 machine cycles. To notify GCC of these +; pipeline delays, each of the auxiliary and index registers are declared +; as separate functional units. +; +; (define_function_unit NAME MULTIPLICITY SIMULTANEITY +; TEST READY-DELAY ISSUE-DELAY [CONFLICT-LIST]) +; +; MULTIPLICITY 1 (C4x has no independent identical function units) +; SIMULTANEITY 0 (C4x is pipelined) +; READY_DELAY 1 (Results usually ready after every cyle) +; ISSUE_DELAY 1 (Can issue insns every cycle) + +; Just some dummy definitions. The real work is done in c4x_adjust_cost. +; These are needed so the min/max READY_DELAY is known. + +(define_function_unit "dummy" 1 0 (const_int 0) 1 1) +(define_function_unit "dummy" 1 0 (const_int 0) 2 1) +(define_function_unit "dummy" 1 0 (const_int 0) 3 1) + +;(define_function_unit "ar0" 1 0 +; (and (eq_attr "cpu" "c4x") +; (and (eq_attr "setar0" "1") +; (eq_attr "usear0" "1"))) +; 3 1 ) + +;(define_function_unit "ar0" 1 0 +; (and (eq_attr "cpu" "c4x") +; (and (eq_attr "setlda_ar0" "1") +; (eq_attr "usear0" "1"))) +; 2 1 ) + +;(define_function_unit "ar0" 1 0 +; (and (eq_attr "cpu" "c4x") +; (and (eq_attr "usear0" "1") +; (eq_attr "readar0" "1"))) +; 2 1 ) + +; The attribute setar0 is set to 1 for insns where ar0 is a dst operand. +; Note that the attributes unarycc and binarycc do not apply +; if ar0 is a dst operand (only loading an ext. prec. reg. sets CC) +(define_attr "setar0" "" + (cond [(eq_attr "type" "unary,binary") + (if_then_else (match_operand 0 "ar0_reg_operand" "") + (const_int 1) (const_int 0))] + (const_int 0))) + +(define_attr "setlda_ar0" "" + (cond [(eq_attr "type" "lda") + (if_then_else (match_operand 0 "ar0_reg_operand" "") + (const_int 1) (const_int 0))] + (const_int 0))) + +; The attribute usear0 is set to 1 for insns where ar0 is used +; for addressing, as a src operand, or as a dst operand. +(define_attr "usear0" "" + (cond [(eq_attr "type" "compare,store") + (if_then_else (match_operand 0 "ar0_mem_operand" "") + (const_int 1) (const_int 0)) + (eq_attr "type" "compare,lda,unary,unarycc,binary,binarycc") + (if_then_else (match_operand 1 "ar0_mem_operand" "") + (const_int 1) (const_int 0)) + (eq_attr "type" "binary,binarycc") + (if_then_else (match_operand 2 "ar0_mem_operand" "") + (const_int 1) (const_int 0)) + (eq_attr "type" "db,dbc") + (if_then_else (match_operand 0 "ar0_reg_operand" "") + (const_int 1) (const_int 0))] + (const_int 0))) + +; The attribute readar0 is set to 1 for insns where ar0 is a src operand. +(define_attr "readar0" "" + (cond [(eq_attr "type" "compare") + (if_then_else (match_operand 0 "ar0_reg_operand" "") + (const_int 1) (const_int 0)) + (eq_attr "type" "compare,store,lda,unary,unarycc,binary,binarycc") + (if_then_else (match_operand 1 "ar0_reg_operand" "") + (const_int 1) (const_int 0)) + (eq_attr "type" "binary,binarycc") + (if_then_else (match_operand 2 "ar0_reg_operand" "") + (const_int 1) (const_int 0))] + (const_int 0))) + +;(define_function_unit "ar1" 1 0 +; (and (eq_attr "cpu" "c4x") +; (and (eq_attr "setar1" "1") +; (eq_attr "usear1" "1"))) +; 3 1 ) + +;(define_function_unit "ar1" 1 0 +; (and (eq_attr "cpu" "c4x") +; (and (eq_attr "setlda_ar1" "1") +; (eq_attr "usear1" "1"))) +; 2 1 ) + +;(define_function_unit "ar1" 1 0 +; (and (eq_attr "cpu" "c4x") +; (and (eq_attr "usear1" "1") +; (eq_attr "readar1" "1"))) +; 2 1 ) + +(define_attr "setar1" "" + (cond [(eq_attr "type" "unary,binary") + (if_then_else (match_operand 0 "ar1_reg_operand" "") + (const_int 1) (const_int 0))] + (const_int 0))) + +(define_attr "setlda_ar1" "" + (cond [(eq_attr "type" "lda") + (if_then_else (match_operand 0 "ar1_reg_operand" "") + (const_int 1) (const_int 0))] + (const_int 0))) + +(define_attr "usear1" "" + (cond [(eq_attr "type" "compare,store") + (if_then_else (match_operand 0 "ar1_mem_operand" "") + (const_int 1) (const_int 0)) + (eq_attr "type" "compare,lda,unary,unarycc,binary,binarycc") + (if_then_else (match_operand 1 "ar1_mem_operand" "") + (const_int 1) (const_int 0)) + (eq_attr "type" "binary,binarycc") + (if_then_else (match_operand 2 "ar1_mem_operand" "") + (const_int 1) (const_int 0)) + (eq_attr "type" "db,dbc") + (if_then_else (match_operand 0 "ar1_reg_operand" "") + (const_int 1) (const_int 0))] + (const_int 0))) + +(define_attr "readar1" "" + (cond [(eq_attr "type" "compare") + (if_then_else (match_operand 0 "ar1_reg_operand" "") + (const_int 1) (const_int 0)) + (eq_attr "type" "compare,store,lda,unary,unarycc,binary,binarycc") + (if_then_else (match_operand 1 "ar1_reg_operand" "") + (const_int 1) (const_int 0)) + (eq_attr "type" "binary,binarycc") + (if_then_else (match_operand 2 "ar1_reg_operand" "") + (const_int 1) (const_int 0))] + (const_int 0))) + +;(define_function_unit "ar2" 1 0 +; (and (eq_attr "cpu" "c4x") +; (and (eq_attr "setar2" "1") +; (eq_attr "usear2" "1"))) +; 3 1 ) + +;(define_function_unit "ar2" 1 0 +; (and (eq_attr "cpu" "c4x") +; (and (eq_attr "setlda_ar2" "1") +; (eq_attr "usear2" "1"))) +; 2 1 ) + +;(define_function_unit "ar2" 1 0 +; (and (eq_attr "cpu" "c4x") +; (and (eq_attr "usear2" "1") +; (eq_attr "readar2" "1"))) +; 2 1 ) + +(define_attr "setar2" "" + (cond [(eq_attr "type" "unary,binary") + (if_then_else (match_operand 0 "ar2_reg_operand" "") + (const_int 1) (const_int 0))] + (const_int 0))) + +(define_attr "setlda_ar2" "" + (cond [(eq_attr "type" "lda") + (if_then_else (match_operand 0 "ar2_reg_operand" "") + (const_int 1) (const_int 0))] + (const_int 0))) + +(define_attr "usear2" "" + (cond [(eq_attr "type" "compare,store") + (if_then_else (match_operand 0 "ar2_mem_operand" "") + (const_int 1) (const_int 0)) + (eq_attr "type" "compare,lda,unary,unarycc,binary,binarycc") + (if_then_else (match_operand 1 "ar2_mem_operand" "") + (const_int 1) (const_int 0)) + (eq_attr "type" "binary,binarycc") + (if_then_else (match_operand 2 "ar2_mem_operand" "") + (const_int 1) (const_int 0)) + (eq_attr "type" "db,dbc") + (if_then_else (match_operand 0 "ar2_reg_operand" "") + (const_int 1) (const_int 0))] + (const_int 0))) + +(define_attr "readar2" "" + (cond [(eq_attr "type" "compare") + (if_then_else (match_operand 0 "ar2_reg_operand" "") + (const_int 1) (const_int 0)) + (eq_attr "type" "compare,store,lda,unary,unarycc,binary,binarycc") + (if_then_else (match_operand 1 "ar2_reg_operand" "") + (const_int 1) (const_int 0)) + (eq_attr "type" "binary,binarycc") + (if_then_else (match_operand 2 "ar2_reg_operand" "") + (const_int 1) (const_int 0))] + (const_int 0))) + +;(define_function_unit "ar3" 1 0 +; (and (eq_attr "cpu" "c4x") +; (and (eq_attr "setar3" "1") +; (eq_attr "usear3" "1"))) +; 3 1 ) + +;(define_function_unit "ar3" 1 0 +; (and (eq_attr "cpu" "c4x") +; (and (eq_attr "setlda_ar3" "1") +; (eq_attr "usear3" "1"))) +; 2 1 ) + +;(define_function_unit "ar3" 1 0 +; (and (eq_attr "cpu" "c4x") +; (and (eq_attr "usear3" "1") +; (eq_attr "readar3" "1"))) +; 2 1 ) + +(define_attr "setar3" "" + (cond [(eq_attr "type" "unary,binary") + (if_then_else (match_operand 0 "ar3_reg_operand" "") + (const_int 1) (const_int 0))] + (const_int 0))) + +(define_attr "setlda_ar3" "" + (cond [(eq_attr "type" "lda") + (if_then_else (match_operand 0 "ar3_reg_operand" "") + (const_int 1) (const_int 0))] + (const_int 0))) + +(define_attr "usear3" "" + (cond [(eq_attr "type" "compare,store") + (if_then_else (match_operand 0 "ar3_mem_operand" "") + (const_int 1) (const_int 0)) + (eq_attr "type" "compare,lda,unary,unarycc,binary,binarycc") + (if_then_else (match_operand 1 "ar3_mem_operand" "") + (const_int 1) (const_int 0)) + (eq_attr "type" "binary,binarycc") + (if_then_else (match_operand 2 "ar3_mem_operand" "") + (const_int 1) (const_int 0)) + (eq_attr "type" "db,dbc") + (if_then_else (match_operand 0 "ar3_reg_operand" "") + (const_int 1) (const_int 0))] + (const_int 0))) + +(define_attr "readar3" "" + (cond [(eq_attr "type" "compare") + (if_then_else (match_operand 0 "ar3_reg_operand" "") + (const_int 1) (const_int 0)) + (eq_attr "type" "compare,store,lda,unary,unarycc,binary,binarycc") + (if_then_else (match_operand 1 "ar3_reg_operand" "") + (const_int 1) (const_int 0)) + (eq_attr "type" "binary,binarycc") + (if_then_else (match_operand 2 "ar3_reg_operand" "") + (const_int 1) (const_int 0))] + (const_int 0))) + +;(define_function_unit "ar4" 1 0 +; (and (eq_attr "cpu" "c4x") +; (and (eq_attr "setar4" "1") +; (eq_attr "usear4" "1"))) +; 3 1 ) + +;(define_function_unit "ar4" 1 0 +; (and (eq_attr "cpu" "c4x") +; (and (eq_attr "setlda_ar4" "1") +; (eq_attr "usear4" "1"))) +; 2 1 ) + +;(define_function_unit "ar4" 1 0 +; (and (eq_attr "cpu" "c4x") +; (and (eq_attr "usear4" "1") +; (eq_attr "readar4" "1"))) +; 2 1 ) + +(define_attr "setar4" "" + (cond [(eq_attr "type" "unary,binary") + (if_then_else (match_operand 0 "ar4_reg_operand" "") + (const_int 1) (const_int 0))] + (const_int 0))) + +(define_attr "setlda_ar4" "" + (cond [(eq_attr "type" "lda") + (if_then_else (match_operand 0 "ar4_reg_operand" "") + (const_int 1) (const_int 0))] + (const_int 0))) + +(define_attr "usear4" "" + (cond [(eq_attr "type" "compare,store") + (if_then_else (match_operand 0 "ar4_mem_operand" "") + (const_int 1) (const_int 0)) + (eq_attr "type" "compare,lda,unary,unarycc,binary,binarycc") + (if_then_else (match_operand 1 "ar4_mem_operand" "") + (const_int 1) (const_int 0)) + (eq_attr "type" "binary,binarycc") + (if_then_else (match_operand 2 "ar4_mem_operand" "") + (const_int 1) (const_int 0)) + (eq_attr "type" "db,dbc") + (if_then_else (match_operand 0 "ar4_reg_operand" "") + (const_int 1) (const_int 0))] + (const_int 0))) + +(define_attr "readar4" "" + (cond [(eq_attr "type" "compare") + (if_then_else (match_operand 0 "ar4_reg_operand" "") + (const_int 1) (const_int 0)) + (eq_attr "type" "compare,store,lda,unary,unarycc,binary,binarycc") + (if_then_else (match_operand 1 "ar4_reg_operand" "") + (const_int 1) (const_int 0)) + (eq_attr "type" "binary,binarycc") + (if_then_else (match_operand 2 "ar4_reg_operand" "") + (const_int 1) (const_int 0))] + (const_int 0))) + +;(define_function_unit "ar5" 1 0 +; (and (eq_attr "cpu" "c4x") +; (and (eq_attr "setar5" "1") +; (eq_attr "usear5" "1"))) +; 3 1 ) + +;(define_function_unit "ar5" 1 0 +; (and (eq_attr "cpu" "c4x") +; (and (eq_attr "setlda_ar5" "1") +; (eq_attr "usear5" "1"))) +; 2 1 ) + +;(define_function_unit "ar5" 1 0 +; (and (eq_attr "cpu" "c4x") +; (and (eq_attr "usear5" "1") +; (eq_attr "readar5" "1"))) +; 2 1 ) + +(define_attr "setar5" "" + (cond [(eq_attr "type" "unary,binary") + (if_then_else (match_operand 0 "ar5_reg_operand" "") + (const_int 1) (const_int 0))] + (const_int 0))) + +(define_attr "setlda_ar5" "" + (cond [(eq_attr "type" "lda") + (if_then_else (match_operand 0 "ar5_reg_operand" "") + (const_int 1) (const_int 0))] + (const_int 0))) + +(define_attr "usear5" "" + (cond [(eq_attr "type" "compare,store") + (if_then_else (match_operand 0 "ar5_mem_operand" "") + (const_int 1) (const_int 0)) + (eq_attr "type" "compare,lda,unary,unarycc,binary,binarycc") + (if_then_else (match_operand 1 "ar5_mem_operand" "") + (const_int 1) (const_int 0)) + (eq_attr "type" "binary,binarycc") + (if_then_else (match_operand 2 "ar5_mem_operand" "") + (const_int 1) (const_int 0)) + (eq_attr "type" "db,dbc") + (if_then_else (match_operand 0 "ar5_reg_operand" "") + (const_int 1) (const_int 0))] + (const_int 0))) + +(define_attr "readar5" "" + (cond [(eq_attr "type" "compare") + (if_then_else (match_operand 0 "ar5_reg_operand" "") + (const_int 1) (const_int 0)) + (eq_attr "type" "compare,store,lda,unary,unarycc,binary,binarycc") + (if_then_else (match_operand 1 "ar5_reg_operand" "") + (const_int 1) (const_int 0)) + (eq_attr "type" "binary,binarycc") + (if_then_else (match_operand 2 "ar5_reg_operand" "") + (const_int 1) (const_int 0))] + (const_int 0))) + +;(define_function_unit "ar6" 1 0 +; (and (eq_attr "cpu" "c4x") +; (and (eq_attr "setar6" "1") +; (eq_attr "usear6" "1"))) +; 3 1 ) + +;(define_function_unit "ar6" 1 0 +; (and (eq_attr "cpu" "c4x") +; (and (eq_attr "setlda_ar6" "1") +; (eq_attr "usear6" "1"))) +; 2 1 ) + +;(define_function_unit "ar6" 1 0 +; (and (eq_attr "cpu" "c4x") +; (and (eq_attr "usear6" "1") +; (eq_attr "readar6" "1"))) +; 2 1 ) + +(define_attr "setar6" "" + (cond [(eq_attr "type" "unary,binary") + (if_then_else (match_operand 0 "ar6_reg_operand" "") + (const_int 1) (const_int 0))] + (const_int 0))) + +(define_attr "setlda_ar6" "" + (cond [(eq_attr "type" "lda") + (if_then_else (match_operand 0 "ar6_reg_operand" "") + (const_int 1) (const_int 0))] + (const_int 0))) + +(define_attr "usear6" "" + (cond [(eq_attr "type" "compare,store") + (if_then_else (match_operand 0 "ar6_mem_operand" "") + (const_int 1) (const_int 0)) + (eq_attr "type" "compare,lda,unary,unarycc,binary,binarycc") + (if_then_else (match_operand 1 "ar6_mem_operand" "") + (const_int 1) (const_int 0)) + (eq_attr "type" "binary,binarycc") + (if_then_else (match_operand 2 "ar6_mem_operand" "") + (const_int 1) (const_int 0)) + (eq_attr "type" "db,dbc") + (if_then_else (match_operand 0 "ar6_reg_operand" "") + (const_int 1) (const_int 0))] + (const_int 0))) + +(define_attr "readar6" "" + (cond [(eq_attr "type" "compare") + (if_then_else (match_operand 0 "ar6_reg_operand" "") + (const_int 1) (const_int 0)) + (eq_attr "type" "compare,store,lda,unary,unarycc,binary,binarycc") + (if_then_else (match_operand 1 "ar6_reg_operand" "") + (const_int 1) (const_int 0)) + (eq_attr "type" "binary,binarycc") + (if_then_else (match_operand 2 "ar6_reg_operand" "") + (const_int 1) (const_int 0))] + (const_int 0))) + +;(define_function_unit "ar7" 1 0 +; (and (eq_attr "cpu" "c4x") +; (and (eq_attr "setar7" "1") +; (eq_attr "usear7" "1"))) +; 3 1 ) + +;(define_function_unit "ar7" 1 0 +; (and (eq_attr "cpu" "c4x") +; (and (eq_attr "setlda_ar7" "1") +; (eq_attr "usear7" "1"))) +; 2 1 ) + +;(define_function_unit "ar7" 1 0 +; (and (eq_attr "cpu" "c4x") +; (and (eq_attr "usear7" "1") +; (eq_attr "readar7" "1"))) +; 2 1 ) + +(define_attr "setar7" "" + (cond [(eq_attr "type" "unary,binary") + (if_then_else (match_operand 0 "ar7_reg_operand" "") + (const_int 1) (const_int 0))] + (const_int 0))) + +(define_attr "setlda_ar7" "" + (cond [(eq_attr "type" "lda") + (if_then_else (match_operand 0 "ar7_reg_operand" "") + (const_int 1) (const_int 0))] + (const_int 0))) + +(define_attr "usear7" "" + (cond [(eq_attr "type" "compare,store") + (if_then_else (match_operand 0 "ar7_mem_operand" "") + (const_int 1) (const_int 0)) + (eq_attr "type" "compare,lda,unary,unarycc,binary,binarycc") + (if_then_else (match_operand 1 "ar7_mem_operand" "") + (const_int 1) (const_int 0)) + (eq_attr "type" "binary,binarycc") + (if_then_else (match_operand 2 "ar7_mem_operand" "") + (const_int 1) (const_int 0)) + (eq_attr "type" "db,dbc") + (if_then_else (match_operand 0 "ar7_reg_operand" "") + (const_int 1) (const_int 0))] + (const_int 0))) + +(define_attr "readar7" "" + (cond [(eq_attr "type" "compare") + (if_then_else (match_operand 0 "ar7_reg_operand" "") + (const_int 1) (const_int 0)) + (eq_attr "type" "compare,store,lda,unary,unarycc,binary,binarycc") + (if_then_else (match_operand 1 "ar7_reg_operand" "") + (const_int 1) (const_int 0)) + (eq_attr "type" "binary,binarycc") + (if_then_else (match_operand 2 "ar7_reg_operand" "") + (const_int 1) (const_int 0))] + (const_int 0))) + +;(define_function_unit "ir0" 1 0 +; (and (eq_attr "cpu" "c4x") +; (and (eq_attr "setir0" "1") +; (eq_attr "useir0" "1"))) +; 3 1 ) + +;(define_function_unit "ir0" 1 0 +; (and (eq_attr "cpu" "c4x") +; (and (eq_attr "setlda_ir0" "1") +; (eq_attr "useir0" "1"))) +; 2 1 ) + +(define_attr "setir0" "" + (cond [(eq_attr "type" "unary,binary") + (if_then_else (match_operand 0 "ir0_reg_operand" "") + (const_int 1) (const_int 0))] + (const_int 0))) + +(define_attr "setlda_ir0" "" + (cond [(eq_attr "type" "lda") + (if_then_else (match_operand 0 "ir0_reg_operand" "") + (const_int 1) (const_int 0))] + (const_int 0))) + +(define_attr "useir0" "" + (cond [(eq_attr "type" "compare,store") + (if_then_else (match_operand 0 "ir0_mem_operand" "") + (const_int 1) (const_int 0)) + (eq_attr "type" "compare,lda,unary,unarycc,binary,binarycc") + (if_then_else (match_operand 1 "ir0_mem_operand" "") + (const_int 1) (const_int 0)) + (eq_attr "type" "binary,binarycc") + (if_then_else (match_operand 2 "ir0_mem_operand" "") + (const_int 1) (const_int 0))] + (const_int 0))) + +;(define_function_unit "ir1" 1 0 +; (and (eq_attr "cpu" "c4x") +; (and (eq_attr "setir1" "1") +; (eq_attr "useir1" "1"))) +; 3 1 ) + +;(define_function_unit "ir1" 1 0 +; (and (eq_attr "cpu" "c4x") +; (and (eq_attr "setlda_ir1" "1") +; (eq_attr "useir1" "1"))) +; 2 1 ) + +(define_attr "setir1" "" + (cond [(eq_attr "type" "unary,binary") + (if_then_else (match_operand 0 "ir1_reg_operand" "") + (const_int 1) (const_int 0))] + (const_int 0))) + +(define_attr "setlda_ir1" "" + (cond [(eq_attr "type" "lda") + (if_then_else (match_operand 0 "ir1_reg_operand" "") + (const_int 1) (const_int 0))] + (const_int 0))) + +(define_attr "useir1" "" + (cond [(eq_attr "type" "compare,store") + (if_then_else (match_operand 0 "ir1_mem_operand" "") + (const_int 1) (const_int 0)) + (eq_attr "type" "compare,lda,unary,unarycc,binary,binarycc") + (if_then_else (match_operand 1 "ir1_mem_operand" "") + (const_int 1) (const_int 0)) + (eq_attr "type" "binary,binarycc") + (if_then_else (match_operand 2 "ir1_mem_operand" "") + (const_int 1) (const_int 0))] + (const_int 0))) + +; With the C3x, things are simpler, but slower, i.e. more pipeline conflicts :( +; There are three functional groups: +; (1) AR0-AR7, IR0-IR1, BK +; (2) DP +; (3) SP +; +; When a register in one of these functional groups is loaded, +; the contents of that or any other register in its group +; will not be available to the next instruction for 2 machine cycles. +; Similarly, when a register in one of the functional groups is read +; excepting (IR0-IR1, BK, DP) the contents of that or any other register +; in its group will not be available to the next instruction for +; 1 machine cycle. +; +; Let's ignore functional groups 2 and 3 for now, since they are not +; so important. + +;(define_function_unit "group1" 1 0 +; (and (eq_attr "cpu" "c3x") +; (and (eq_attr "setgroup1" "1") +; (eq_attr "usegroup1" "1"))) +; 3 1) + +;(define_function_unit "group1" 1 0 +; (and (eq_attr "cpu" "c3x") +; (and (eq_attr "usegroup1" "1") +; (eq_attr "readarx" "1"))) +; 2 1) + +(define_attr "setgroup1" "" + (cond [(eq_attr "type" "lda,unary,binary") + (if_then_else (match_operand 0 "group1_reg_operand" "") + (const_int 1) (const_int 0))] + (const_int 0))) + +(define_attr "usegroup1" "" + (cond [(eq_attr "type" "compare,store,store_store,store_load") + (if_then_else (match_operand 0 "group1_mem_operand" "") + (const_int 1) (const_int 0)) + (eq_attr "type" "compare,lda,unary,unarycc,binary,binarycc,load_load,load_store") + (if_then_else (match_operand 1 "group1_mem_operand" "") + (const_int 1) (const_int 0)) + (eq_attr "type" "store_store,load_store") + (if_then_else (match_operand 2 "group1_mem_operand" "") + (const_int 1) (const_int 0)) + (eq_attr "type" "load_load,store_load") + (if_then_else (match_operand 3 "group1_mem_operand" "") + (const_int 1) (const_int 0))] + (const_int 0))) + +(define_attr "readarx" "" + (cond [(eq_attr "type" "compare") + (if_then_else (match_operand 0 "arx_reg_operand" "") + (const_int 1) (const_int 0)) + (eq_attr "type" "compare,store,lda,unary,unarycc,binary,binarycc") + (if_then_else (match_operand 1 "arx_reg_operand" "") + (const_int 1) (const_int 0)) + (eq_attr "type" "binary,binarycc") + (if_then_else (match_operand 2 "arx_reg_operand" "") + (const_int 1) (const_int 0))] + (const_int 0))) + + +; +; C4x INSN PATTERNS: +; +; Note that the movMM and addP patterns can be called during reload +; so we need to take special care with theses patterns since +; we cannot blindly clobber CC or generate new pseudo registers. + +; +; TWO OPERAND INTEGER INSTRUCTIONS +; + +; +; LDP/LDPK +; +(define_insn "set_ldp" + [(set (match_operand:QI 0 "dp_reg_operand" "=z") + (high:QI (match_operand:QI 1 "" "")))] + "! TARGET_SMALL" + "* return (TARGET_C3X) ? \"ldp\\t%A1\" : \"ldpk\\t%A1\";" + [(set_attr "type" "ldp")]) + + +; Used when moving a constant label reference to an external +; location, this will make sure the original label is still +; used so the optimizer will not optimize it away. +; +(define_insn "set_ldp_use" + [(parallel [(set (match_operand:QI 0 "dp_reg_operand" "=z") + (high:QI (match_operand:QI 1 "" ""))) + (use (match_operand 2 "" ""))])] + "! TARGET_SMALL" + "* return (TARGET_C3X) ? \"ldp\\t%A1\" : \"ldpk\\t%A1\";" + [(set_attr "type" "ldp")]) + +(define_insn "set_high_use" + [(parallel [(set (match_operand:QI 0 "std_reg_operand" "=c") + (high:QI (match_operand:QI 1 "" ""))) + (use (match_operand 2 "" ""))])] + "! TARGET_C3X && ! TARGET_SMALL" + "ldhi\\t^%H1,%0" + [(set_attr "type" "unary")]) + +(define_insn "set_ior_lo_use" + [(parallel [(set (match_operand:QI 0 "std_reg_operand" "=c") + (ior:QI (match_dup 0) + (and:QI (match_operand:QI 1 "" "") + (const_int 65535)))) + (use (match_operand 2 "" ""))])] + "! TARGET_C3X && ! TARGET_SMALL" + "or\\t#%H1,%0" + [(set_attr "type" "unary")]) + +; +; LDIU/LDA/STI/STIK +; +; The following moves will not set the condition codes register. +; + +; This must come before the general case +(define_insn "*movqi_stik" + [(set (match_operand:QI 0 "memory_operand" "=m") + (match_operand:QI 1 "stik_const_operand" "K"))] + "! TARGET_C3X" + "stik\\t%1,%0" + [(set_attr "type" "store")]) + +; We must provide an alternative to store to memory in case we have to +; spill a register. +(define_insn "movqi_noclobber" + [(set (match_operand:QI 0 "src_operand" "=d,*c,m,r") + (match_operand:QI 1 "src_hi_operand" "rmI,rmI,r,O"))] + "reg_operand (operands[0], QImode) + || reg_operand (operands[1], QImode)" + "* + if (which_alternative == 2) + return \"sti\\t%1,%0\"; + + if (! TARGET_C3X && which_alternative == 3) + { + operands[1] = GEN_INT ((INTVAL (operands[1]) >> 16) & 0xffff); + return \"ldhi\\t%1,%0\"; + } + + /* The lda instruction cannot use the same register as source + and destination. */ + if (! TARGET_C3X && which_alternative == 1 + && ( IS_ADDR_REG (REGNO (operands[0])) + || IS_INDEX_REG (REGNO (operands[0])) + || IS_SP_REG (REGNO (operands[0]))) + && (REGNO (operands[0]) != REGNO (operands[1]))) + return \"lda\\t%1,%0\"; + return \"ldiu\\t%1,%0\"; + " + [(set_attr "type" "unary,lda,store,unary") + (set_attr "data" "int16,int16,int16,high_16")]) + +; +; LDI +; + +; We shouldn't need these peepholes, but the combiner seems to miss them... +(define_peephole + [(set (match_operand:QI 0 "ext_reg_operand" "=d") + (match_operand:QI 1 "src_operand" "g")) + (set (reg:CC 21) + (compare:CC (match_dup 0) (const_int 0)))] + "" + "@ + ldi\\t%1,%0" + [(set_attr "type" "unarycc") + (set_attr "data" "int16")]) + +(define_insn "*movqi_set" + [(set (reg:CC 21) + (compare:CC (match_operand:QI 1 "src_operand" "g") + (const_int 0))) + (set (match_operand:QI 0 "ext_reg_operand" "=d") + (match_dup 1))] + "" + "@ + ldi\\t%1,%0" + [(set_attr "type" "unarycc") + (set_attr "data" "int16")]) + +; This pattern probably gets in the way and requires a scratch register +; when a simple compare with zero will suffice. +;(define_insn "*movqi_test" +; [(set (reg:CC 21) +; (compare:CC (match_operand:QI 1 "src_operand" "g") +; (const_int 0))) +; (clobber (match_scratch:QI 0 "=d"))] +; "" +; "@ +; ldi\\t%1,%0" +; [(set_attr "type" "unarycc") +; (set_attr "data" "int16")]) + +; If one of the operands is not a register, then we should +; emit two insns, using a scratch register. This will produce +; better code in loops if the source operand is invariant, since +; the source reload can be optimised out. During reload we cannot +; use change_address or force_reg which will allocate new pseudo regs. + +; Unlike most other insns, the move insns can't be split with +; different predicates, because register spilling and other parts of +; the compiler, have memoized the insn number already. + +(define_expand "movqi" + [(set (match_operand:QI 0 "src_operand" "") + (match_operand:QI 1 "src_operand" ""))] + "" + " + /* We shouldn't have to do this, since reload is supposed to + be able to do this if we have a memory constraint. */ + if (CONSTANT_P (operands[1]) + && ! const_operand (operands[1], QImode)) + { + operands[1] = force_const_mem (QImode, operands[1]); + if (! memory_address_p (QImode, XEXP (operands[1], 0)) + && ! reload_in_progress) + operands[1] = change_address (operands[1], QImode, + XEXP (operands[1], 0)); + } + + if (! reload_in_progress + && ! reg_operand (operands[0], QImode) + && ! reg_operand (operands[1], QImode) + && ! (stik_const_operand (operands[1], QImode) + && ! push_operand (operands[0], QImode))) + operands[1] = force_reg (QImode, operands[1]);") + +(define_insn "*movqi_update" + [(set (match_operand:QI 0 "reg_operand" "=r") + (mem:QI (plus:QI (match_operand:QI 1 "addr_reg_operand" "a") + (match_operand:QI 2 "index_reg_operand" "x")))) + (set (match_dup 1) + (plus:QI (match_dup 1) (match_dup 2)))] + "" + "ldiu\\t*%1++(%2),%0" + [(set_attr "type" "unary") + (set_attr "data" "int16")]) + +(define_insn "movqi_parallel" + [(set (match_operand:QI 0 "parallel_operand" "=q,S<>,q,S<>") + (match_operand:QI 1 "parallel_operand" "S<>,q,S<>,q")) + (set (match_operand:QI 2 "parallel_operand" "=q,S<>,S<>,q") + (match_operand:QI 3 "parallel_operand" "S<>,q,q,S<>"))] + "valid_parallel_load_store (operands, QImode)" + "@ + ldi1\\t%1,%0\\n||\\tldi2\\t%3,%2 + sti1\\t%1,%0\\n||\\tsti2\\t%3,%2 + ldi\\t%1,%0\\n||\\tsti\\t%3,%2 + ldi\\t%3,%2\\n||\\tsti\\t%1,%0" + [(set_attr "type" "load_load,store_store,load_store,store_load")]) + +; +; PUSH/POP +; +(define_insn "*pushqi" + [(set (mem:QI (pre_inc:QI (reg:QI 20))) + (match_operand:QI 0 "reg_operand" "r"))] + "" + "push\\t%0" + [(set_attr "type" "push")]) + +(define_insn "*popqi" + [(set (match_operand:QI 0 "reg_operand" "=r") + (mem:QI (post_dec:QI (reg:QI 20)))) + (clobber (reg:CC 21))] + "" + "pop\\t%0" + [(set_attr "type" "pop")]) + +; +; ABSI +; +(define_expand "absqi2" + [(parallel [(set (match_operand:QI 0 "reg_operand" "") + (abs:QI (match_operand:QI 1 "src_operand" ""))) + (clobber (reg:CC_NOOV 21))])] + "" + "") + +(define_insn "*absqi2_clobber" + [(set (match_operand:QI 0 "reg_operand" "=d,c") + (abs:QI (match_operand:QI 1 "src_operand" "g,g"))) + (clobber (reg:CC_NOOV 21))] + "" + "absi\\t%1,%0" + [(set_attr "type" "unarycc,unary") + (set_attr "data" "int16,int16")]) + +(define_insn "*absqi2_test" + [(set (reg:CC_NOOV 21) + (compare:CC_NOOV (abs:QI (match_operand:QI 1 "src_operand" "g")) + (const_int 0))) + (clobber (match_scratch:QI 0 "=d"))] + "" + "absi\\t%1,%0" + [(set_attr "type" "unarycc") + (set_attr "data" "int16")]) + +(define_insn "*absqi2_set" + [(set (reg:CC_NOOV 21) + (compare:CC_NOOV (abs:QI (match_operand:QI 1 "src_operand" "g")) + (const_int 0))) + (set (match_operand:QI 0 "ext_reg_operand" "=d") + (abs:QI (match_dup 1)))] + "" + "absi\\t%1,%0" + [(set_attr "type" "unarycc") + (set_attr "data" "int16")]) + +; +; NEGI +; +(define_expand "negqi2" + [(parallel [(set (match_operand:QI 0 "reg_operand" "") + (neg:QI (match_operand:QI 1 "src_operand" ""))) + (clobber (reg:CC_NOOV 21))])] +"" +"") + +(define_insn "*negqi2_clobber" + [(set (match_operand:QI 0 "reg_operand" "=d,c") + (neg:QI (match_operand:QI 1 "src_operand" "g,g"))) + (clobber (reg:CC_NOOV 21))] + "" + "negi\\t%1,%0" + [(set_attr "type" "unarycc,unary") + (set_attr "data" "int16,int16")]) + +(define_insn "*negqi2_test" + [(set (reg:CC_NOOV 21) + (compare:CC_NOOV (neg:QI (match_operand:QI 1 "src_operand" "g")) + (const_int 0))) + (clobber (match_scratch:QI 0 "=d"))] + "" + "negi\\t%1,%0" + [(set_attr "type" "unarycc") + (set_attr "data" "int16")]) + +(define_insn "*negqi2_set" + [(set (reg:CC_NOOV 21) + (compare:CC_NOOV (neg:QI (match_operand:QI 1 "src_operand" "g")) + (const_int 0))) + (set (match_operand:QI 0 "ext_reg_operand" "=d") + (neg:QI (match_dup 1)))] + "" + "negi\\t%1,%0" + [(set_attr "type" "unarycc") + (set_attr "data" "int16")]) + +(define_insn "*negbqi2_clobber" + [(set (match_operand:QI 0 "ext_reg_operand" "=d") + (neg:QI (match_operand:QI 1 "src_operand" "g"))) + (use (reg:CC_NOOV 21)) + (clobber (reg:CC_NOOV 21))] + "" + "negb\\t%1,%0" + [(set_attr "type" "unarycc") + (set_attr "data" "int16")]) + +; +; NOT +; +(define_expand "one_cmplqi2" + [(parallel [(set (match_operand:QI 0 "reg_operand" "") + (not:QI (match_operand:QI 1 "lsrc_operand" ""))) + (clobber (reg:CC 21))])] + "" + "") + +(define_insn "*one_cmplqi2_clobber" + [(set (match_operand:QI 0 "reg_operand" "=d,c") + (not:QI (match_operand:QI 1 "lsrc_operand" "g,g"))) + (clobber (reg:CC 21))] + "" + "not\\t%1,%0" + [(set_attr "type" "unarycc,unary") + (set_attr "data" "uint16,uint16")]) + +(define_insn "*one_cmplqi2_test" + [(set (reg:CC 21) + (compare:CC (not:QI (match_operand:QI 1 "lsrc_operand" "g")) + (const_int 0))) + (clobber (match_scratch:QI 0 "=d"))] + "" + "not\\t%1,%0" + [(set_attr "type" "unarycc") + (set_attr "data" "uint16")]) + +(define_insn "*one_cmplqi2_set" + [(set (reg:CC 21) + (compare:CC (not:QI (match_operand:QI 1 "lsrc_operand" "g")) + (const_int 0))) + (set (match_operand:QI 0 "ext_reg_operand" "=d") + (not:QI (match_dup 1)))] + "" + "not\\t%1,%0" + [(set_attr "type" "unarycc") + (set_attr "data" "uint16")]) + +(define_insn "*one_cmplqi2_const_clobber" + [(set (match_operand:QI 0 "reg_operand" "=d,c") + (match_operand:QI 1 "not_const_operand" "N,N")) + (clobber (reg:CC 21))] + "" + "@ + not\\t%N1,%0 + not\\t%N1,%0" + [(set_attr "type" "unarycc,unary") + (set_attr "data" "not_uint16,not_uint16")]) + +; movqi can use this for loading an integer that can't normally +; fit into a 16-bit signed integer. The drawback is that it cannot +; go into R0-R11 since that will clobber the CC and movqi shouldn't +; do that. This can cause additional reloading but in most cases +; this will cause only an additional register move. With the large +; memory model we require an extra instruction to load DP anyway, +; if we're loading the constant from memory. The big advantage of +; allowing constants that satisfy not_const_operand in movqi, is that +; it allows andn to be generated more often. +; However, there is a problem if GCC has decided that it wants +; to use R0-R11, since we won't have a matching pattern... +; In interim, we prevent immed_const allowing `N' constants. +(define_insn "*one_cmplqi2_const_noclobber" + [(set (match_operand:QI 0 "std_reg_operand" "=c") + (match_operand:QI 1 "not_const_operand" "N"))] + "" + "not\\t%N1,%0" + [(set_attr "type" "unary") + (set_attr "data" "not_uint16")]) + +; +; ROL +; +(define_expand "rotlqi3" + [(parallel [(set (match_operand:QI 0 "reg_operand" "") + (rotate:QI (match_operand:QI 1 "reg_operand" "") + (match_operand:QI 2 "const_int_operand" ""))) + (clobber (reg:CC 21))])] + "" + "if (INTVAL (operands[2]) > 4) + FAIL; /* Open code as two shifts and an or */ + if (INTVAL (operands[2]) > 1) + { + int i; + rtx tmp; + + /* If we have 4 or fewer shifts, then it is probably faster + to emit separate ROL instructions. A C3x requires + at least 4 instructions (a C4x requires at least 3), to + perform a rotation by shifts. */ + + tmp = operands[1]; + for (i = 0; i < INTVAL (operands[2]) - 1; i++) + { + tmp = gen_reg_rtx (QImode); + emit_insn (gen_rotl_1_clobber (tmp, operands[1])); + operands[1] = tmp; + } + emit_insn (gen_rotl_1_clobber (operands[0], tmp)); + DONE; + }") + +(define_insn "rotl_1_clobber" + [(set (match_operand:QI 0 "reg_operand" "=d,c") + (rotate:QI (match_operand:QI 1 "reg_operand" "0,0") + (const_int 1))) + (clobber (reg:CC 21))] + "" + "rol\\t%0" + [(set_attr "type" "unarycc,unary")]) +; Default to int16 data attr. + +; +; ROR +; +(define_expand "rotrqi3" + [(parallel [(set (match_operand:QI 0 "reg_operand" "") + (rotatert:QI (match_operand:QI 1 "reg_operand" "") + (match_operand:QI 2 "const_int_operand" ""))) + (clobber (reg:CC 21))])] + "" + "if (INTVAL (operands[2]) > 4) + FAIL; /* Open code as two shifts and an or */ + if (INTVAL (operands[2]) > 1) + { + int i; + rtx tmp; + + /* If we have 4 or fewer shifts, then it is probably faster + to emit separate ROL instructions. A C3x requires + at least 4 instructions (a C4x requires at least 3), to + perform a rotation by shifts. */ + + tmp = operands[1]; + for (i = 0; i < INTVAL (operands[2]) - 1; i++) + { + tmp = gen_reg_rtx (QImode); + emit_insn (gen_rotr_1_clobber (tmp, operands[1])); + operands[1] = tmp; + } + emit_insn (gen_rotr_1_clobber (operands[0], tmp)); + DONE; + }") + +(define_insn "rotr_1_clobber" + [(set (match_operand:QI 0 "reg_operand" "=d,c") + (rotatert:QI (match_operand:QI 1 "reg_operand" "0,0") + (const_int 1))) + (clobber (reg:CC 21))] + "" + "ror\\t%0" + [(set_attr "type" "unarycc,unary")]) +; Default to int16 data attr. + + +; +; THREE OPERAND INTEGER INSTRUCTIONS +; + +; +; ADDI +; +; This is used by reload when it calls gen_add2_insn for address arithmetic +; so we must emit the pattern that doesn't clobber CC. +; +(define_expand "addqi3" + [(parallel [(set (match_operand:QI 0 "reg_operand" "") + (plus:QI (match_operand:QI 1 "src_operand" "") + (match_operand:QI 2 "src_operand" ""))) + (clobber (reg:CC_NOOV 21))])] + "" + "legitimize_operands (PLUS, operands, QImode); + if (reload_in_progress + || (! IS_PSEUDO_REGNO (operands[0]) + && ! IS_EXT_REG (REGNO (operands[0])))) + { + emit_insn (gen_addqi3_noclobber (operands[0], operands[1], operands[2])); + DONE; + }") + +(define_insn "*addqi3_clobber" + [(set (match_operand:QI 0 "reg_operand" "=d,?d,d,c,?c,c") + (plus:QI (match_operand:QI 1 "src_operand" "%rR,rS<>,0,rR,rS<>,0") + (match_operand:QI 2 "src_operand" "JR,rS<>,g,JR,rS<>,g"))) + (clobber (reg:CC_NOOV 21))] + "valid_operands (PLUS, operands, QImode)" + "@ + addi3\\t%2,%1,%0 + addi3\\t%2,%1,%0 + addi\\t%2,%0 + addi3\\t%2,%1,%0 + addi3\\t%2,%1,%0 + addi\\t%2,%0" + [(set_attr "type" "binarycc,binarycc,binarycc,binary,binary,binary")]) +; Default to int16 data attr. + +(define_insn "*addqi3_test" + [(set (reg:CC_NOOV 21) + (compare:CC_NOOV (plus:QI (match_operand:QI 1 "src_operand" "%rR,rS<>,0") + (match_operand:QI 2 "src_operand" "JR,rS<>,g")) + (const_int 0))) + (clobber (match_scratch:QI 0 "=d,?d,d"))] + "valid_operands (PLUS, operands, QImode)" + "@ + addi3\\t%2,%1,%0 + addi3\\t%2,%1,%0 + addi\\t%2,%0" + [(set_attr "type" "binarycc,binarycc,binarycc")]) +; Default to int16 data attr. + +; gcc does this in combine.c we just reverse it here +(define_insn "*cmp_neg" + [(set (reg:CC_NOOV 21) + (compare:CC_NOOV (match_operand:QI 1 "src_operand" "%rR,rS<>,0") + (neg: QI (match_operand:QI 2 "src_operand" "JR,rS<>,g")))) + (clobber (match_scratch:QI 0 "=d,?d,d"))] + "valid_operands (PLUS, operands, QImode)" + "@ + addi3\\t%2,%1,%0 + addi3\\t%2,%1,%0 + addi\\t%2,%0" + [(set_attr "type" "binarycc,binarycc,binarycc")]) + +(define_peephole + [(parallel [(set (match_operand:QI 0 "ext_reg_operand" "=d,?d,d") + (plus:QI (match_operand:QI 1 "src_operand" "%rR,rS<>,0") + (match_operand:QI 2 "src_operand" "JR,rS<>,g"))) + (clobber (reg:CC_NOOV 21))]) + (set (reg:CC_NOOV 21) + (compare:CC_NOOV (match_dup 0) (const_int 0)))] + "valid_operands (PLUS, operands, QImode)" + "@ + addi3\\t%2,%1,%0 + addi3\\t%2,%1,%0 + addi\\t%2,%0" + [(set_attr "type" "binarycc,binarycc,binarycc")]) + +(define_insn "*addqi3_set" + [(set (reg:CC_NOOV 21) + (compare:CC_NOOV (plus:QI (match_operand:QI 1 "src_operand" "%rR,rS<>,0") + (match_operand:QI 2 "src_operand" "JR,rS<>,g")) + (const_int 0))) + (set (match_operand:QI 0 "ext_reg_operand" "=d,?d,d") + (plus:QI (match_dup 1) (match_dup 2)))] + "valid_operands (PLUS, operands, QImode)" + "@ + addi3\\t%2,%1,%0 + addi3\\t%2,%1,%0 + addi\\t%2,%0" + [(set_attr "type" "binarycc,binarycc,binarycc")]) +; Default to int16 data attr. + +; This pattern is required primarily for manipulating the stack pointer +; where GCC doesn't expect CC to be clobbered or for calculating +; addresses during reload. +(define_insn "addqi3_noclobber" + [(set (match_operand:QI 0 "std_reg_operand" "=c,?c,c") + (plus:QI (match_operand:QI 1 "src_operand" "%rR,rS<>,0") + (match_operand:QI 2 "src_operand" "JR,rS<>,g")))] + "valid_operands (PLUS, operands, QImode)" + "@ + addi3\\t%2,%1,%0 + addi3\\t%2,%1,%0 + addi\\t%2,%0" + [(set_attr "type" "binary,binary,binary")]) +; Default to int16 data attr. + + +; This pattern is required during reload when eliminate_regs_in_insn +; effectively converts a move insn into an add insn when the src +; operand is the frame pointer plus a constant. Without this +; pattern, gen_addqi3 can be called with a register for operand0 +; that can clobber CC. +; For example, we may have (set (mem (reg ar0)) (reg 99)) +; with (set (reg 99) (plus (reg ar3) (const_int 8))) +; Now since ar3, the frame pointer, is unchanging within the function, +; (plus (reg ar3) (const_int 8)) is considered a constant. +; eliminate_regs_in_insn substitutes this constant to give +; (set (mem (reg ar0)) (plus (reg ar3) (const_int 8))). +; This is an invalid C4x insn but if we don't provide a pattern +; for it, it will be considered to be a move insn for reloading. +; The nasty bit is that a GENERAL_REGS class register, say r0, +; may be allocated to reload the PLUS and thus gen_reload will +; emit an add insn that may clobber CC. +(define_insn "*addqi3_noclobber_reload" + [(set (match_operand:QI 0 "general_operand" "=c,?c,c") + (plus:QI (match_operand:QI 1 "src_operand" "%rR,rS<>,0") + (match_operand:QI 2 "src_operand" "JR,rS<>,g")))] + "reload_in_progress" + "@ + addi3\\t%2,%1,%0 + addi3\\t%2,%1,%0 + addi\\t%2,%0" + [(set_attr "type" "binary,binary,binary")]) +; Default to int16 data attr. + + +(define_insn "*addqi3_carry_clobber" + [(set (match_operand:QI 0 "reg_operand" "=d,?d,d,c,?c,c") + (plus:QI (match_operand:QI 1 "src_operand" "%rR,rS<>,0,rR,rS<>,0") + (match_operand:QI 2 "src_operand" "JR,rS<>,g,JR,rS<>,g"))) + (use (reg:CC_NOOV 21)) + (clobber (reg:CC_NOOV 21))] + "valid_operands (PLUS, operands, QImode)" + "@ + addc3\\t%2,%1,%0 + addc3\\t%2,%1,%0 + addc\\t%2,%0 + addc3\\t%2,%1,%0 + addc3\\t%2,%1,%0 + addc\\t%2,%0" + [(set_attr "type" "binarycc,binarycc,binarycc,binary,binary,binary")]) +; Default to int16 data attr. + + +; +; SUBI/SUBRI +; +(define_expand "subqi3" + [(parallel [(set (match_operand:QI 0 "reg_operand" "") + (minus:QI (match_operand:QI 1 "src_operand" "") + (match_operand:QI 2 "src_operand" ""))) + (clobber (reg:CC_NOOV 21))])] + "" + "legitimize_operands (MINUS, operands, QImode);") + +(define_insn "*subqi3_clobber" + [(set (match_operand:QI 0 "reg_operand" "=d,?d,d,d,c,?c,c,c") + (minus:QI (match_operand:QI 1 "src_operand" "rR,rS<>,0,g,rR,rS<>,0,g") + (match_operand:QI 2 "src_operand" "JR,rS<>,g,0,JR,rS<>,g,0"))) + (clobber (reg:CC_NOOV 21))] + "valid_operands (MINUS, operands, QImode)" + "@ + subi3\\t%2,%1,%0 + subi3\\t%2,%1,%0 + subi\\t%2,%0 + subri\\t%1,%0 + subi3\\t%2,%1,%0 + subi3\\t%2,%1,%0 + subi\\t%2,%0 + subri\\t%1,%0" + [(set_attr "type" "binarycc,binarycc,binarycc,binarycc,binary,binary,binary,binary")]) +; Default to int16 data attr. + +(define_insn "*subqi3_test" + [(set (reg:CC_NOOV 21) + (compare:CC_NOOV (minus:QI (match_operand:QI 1 "src_operand" "rR,rS<>,0,g") + (match_operand:QI 2 "src_operand" "JR,rS<>,g,0")) + (const_int 0))) + (clobber (match_scratch:QI 0 "=d,?d,d,d"))] + "valid_operands (MINUS, operands, QImode)" + "@ + subi3\\t%2,%1,%0 + subi3\\t%2,%1,%0 + subi\\t%2,%0 + subri\\t%1,%0" + [(set_attr "type" "binarycc,binarycc,binarycc,binarycc")]) +; Default to int16 data attr. + +(define_peephole + [(parallel [(set (match_operand:QI 0 "ext_reg_operand" "=d,?d,d,d") + (minus:QI (match_operand:QI 1 "src_operand" "rR,rS<>,0,g") + (match_operand:QI 2 "src_operand" "JR,rS<>,g,0"))) + (clobber (reg:CC_NOOV 21))]) + (set (reg:CC_NOOV 21) + (compare:CC_NOOV (match_dup 0) (const_int 0)))] + "valid_operands (MINUS, operands, QImode)" + "@ + subi3\\t%2,%1,%0 + subi3\\t%2,%1,%0 + subi\\t%2,%0 + subri\\t%1,%0" + [(set_attr "type" "binarycc,binarycc,binarycc,binarycc")]) + +(define_insn "*subqi3_set" + [(set (reg:CC_NOOV 21) + (compare:CC_NOOV (minus:QI (match_operand:QI 1 "src_operand" "rR,rS<>,0,g") + (match_operand:QI 2 "src_operand" "JR,rS<>,g,0")) + (const_int 0))) + (set (match_operand:QI 0 "ext_reg_operand" "=d,?d,d,d") + (minus:QI (match_dup 1) + (match_dup 2)))] + "valid_operands (MINUS, operands, QImode)" + "@ + subi3\\t%2,%1,%0 + subi3\\t%2,%1,%0 + subi\\t%2,%0 + subri\\t%1,%0" + [(set_attr "type" "binarycc,binarycc,binarycc,binarycc")]) +; Default to int16 data attr. + +(define_insn "*subqi3_carry_clobber" + [(set (match_operand:QI 0 "reg_operand" "=d,?d,d,d,c,?c,c,c") + (minus:QI (match_operand:QI 1 "src_operand" "rR,rS<>,0,g,rR,rS<>,0,g") + (match_operand:QI 2 "src_operand" "JR,rS<>,g,0,JR,rS<>,g,0"))) + (use (reg:CC_NOOV 21)) + (clobber (reg:CC_NOOV 21))] + "valid_operands (MINUS, operands, QImode)" + "@ + subb3\\t%2,%1,%0 + subb3\\t%2,%1,%0 + subb\\t%2,%0 + subrb\\t%1,%0 + subb3\\t%2,%1,%0 + subb3\\t%2,%1,%0 + subb\\t%2,%0 + subrb\\t%1,%0" + [(set_attr "type" "binarycc,binarycc,binarycc,binarycc,binary,binary,binary,binary")]) +; Default to int16 data attr. + +(define_insn "*subqi3_carry_set" + [(set (reg:CC_NOOV 21) + (compare:CC_NOOV (minus:QI (match_operand:QI 1 "src_operand" "rR,rS<>,0,g") + (match_operand:QI 2 "src_operand" "JR,rS<>,g,0")) + (const_int 0))) + (set (match_operand:QI 0 "ext_reg_operand" "=d,?d,d,d") + (minus:QI (match_dup 1) + (match_dup 2))) + (use (reg:CC_NOOV 21))] + "valid_operands (MINUS, operands, QImode)" + "@ + subb3\\t%2,%1,%0 + subb3\\t%2,%1,%0 + subb\\t%2,%0 + subrb\\t%1,%0" + [(set_attr "type" "binarycc,binarycc,binarycc,binarycc")]) +; Default to int16 data attr. + +; +; MPYI +; +(define_expand "mulqi3" + [(parallel [(set (match_operand:QI 0 "reg_operand" "") + (mult:QI (match_operand:QI 1 "src_operand" "") + (match_operand:QI 2 "src_operand" ""))) + (clobber (reg:CC_NOOV 21))])] + "" + "if (TARGET_MPYI || (GET_CODE (operands[2]) == CONST_INT + && exact_log2 (INTVAL (operands[2])) >= 0)) + legitimize_operands (MULT, operands, QImode); + else + { + if (GET_CODE (operands[2]) == CONST_INT) + { + /* Let GCC try to synthesise the multiplication using shifts + and adds. In most cases this will be more profitable than + using the C3x MPYI. */ + FAIL; + } + if (operands[1] == operands[2]) + { + /* Do the squaring operation in-line. */ + emit_insn (gen_sqrqi2_inline (operands[0], operands[1])); + DONE; + } + if (TARGET_INLINE) + { + emit_insn (gen_mulqi3_inline (operands[0], operands[1], + operands[2])); + DONE; + } + c4x_emit_libcall3 (MULQI3_LIBCALL, MULT, QImode, operands); + DONE; + } + ") + +(define_insn "*mulqi3_clobber" + [(set (match_operand:QI 0 "reg_operand" "=d,?d,d,c,?c,c") + (mult:QI (match_operand:QI 1 "src_operand" "%rR,rS<>,0,rR,rS<>,0") + (match_operand:QI 2 "src_operand" "JR,rS<>,g,JR,rS<>,g"))) + (clobber (reg:CC_NOOV 21))] + "valid_operands (MULT, operands, QImode)" + "* + if (which_alternative == 2 || which_alternative == 5) + { + if (TARGET_C3X + && GET_CODE (operands[2]) == CONST_INT + && exact_log2 (INTVAL (operands[2])) >= 0) + return \"ash\\t%L2,%0\"; + else + return \"mpyi\\t%2,%0\"; + } + else + return \"mpyi3\\t%2,%1,%0\";" + [(set_attr "type" "binarycc,binarycc,binarycc,binary,binary,binary")]) +; Default to int16 data attr. + +(define_insn "*mulqi3_test" + [(set (reg:CC_NOOV 21) + (compare:CC_NOOV (mult:QI (match_operand:QI 1 "src_operand" "%rR,rS<>,0") + (match_operand:QI 2 "src_operand" "JR,rS<>,g")) + (const_int 0))) + (clobber (match_scratch:QI 0 "=d,?d,d"))] + "valid_operands (MULT, operands, QImode)" + "* + if (which_alternative == 2) + { + if (TARGET_C3X + && GET_CODE (operands[2]) == CONST_INT + && exact_log2 (INTVAL (operands[2])) >= 0) + return \"ash\\t%L2,%0\"; + else + return \"mpyi\\t%2,%0\"; + } + else + return \"mpyi3\\t%2,%1,%0\";" + [(set_attr "type" "binarycc,binarycc,binarycc")]) +; Default to int16 data attr. + +(define_insn "*mulqi3_set" + [(set (reg:CC_NOOV 21) + (compare:CC_NOOV (mult:QI (match_operand:QI 1 "src_operand" "%rR,rS<>,0") + (match_operand:QI 2 "src_operand" "JR,rS<>,g")) + (const_int 0))) + (set (match_operand:QI 0 "ext_reg_operand" "=d,?d,d") + (mult:QI (match_dup 1) + (match_dup 2)))] + "valid_operands (MULT, operands, QImode)" + "* + if (which_alternative == 2) + { + if (TARGET_C3X + && GET_CODE (operands[2]) == CONST_INT + && exact_log2 (INTVAL (operands[2])) >= 0) + return \"ash\\t%L2,%0\"; + else + return \"mpyi\\t%2,%0\"; + } + else + return \"mpyi3\\t%2,%1,%0\";" + [(set_attr "type" "binarycc,binarycc,binarycc")]) +; Default to int16 data attr. + +; The C3x multiply instruction assumes 24-bit signed integer operands +; and the 48-bit result is truncated to 32-bits. +(define_insn "*mulqi3_24_clobber" + [(set (match_operand:QI 0 "reg_operand" "=d,?d,d,c,?c,c") + (mult:QI + (sign_extend:QI + (and:QI (match_operand:QI 1 "src_operand" "%rR,rS<>,0,rR,rS<>,0") + (const_int 16777215))) + (sign_extend:QI + (and:QI (match_operand:QI 2 "src_operand" "JR,rS<>,g,JR,rS<>,g") + (const_int 16777215))))) + (clobber (reg:CC_NOOV 21))] + "TARGET_C3X && valid_operands (MULT, operands, QImode)" + "@ + mpyi3\\t%2,%1,%0 + mpyi3\\t%2,%1,%0 + mpyi\\t%2,%0 + mpyi3\\t%2,%1,%0 + mpyi3\\t%2,%1,%0 + mpyi\\t%2,%0" + [(set_attr "type" "binarycc,binarycc,binarycc,binary,binary,binary")]) +; Default to int16 data attr. + + +; Fast square function for C3x where TARGET_MPYI not asserted +(define_expand "sqrqi2_inline" + [(set (match_dup 7) (match_operand:QI 1 "src_operand" "")) + (parallel [(set (match_dup 3) + (lshiftrt:QI (match_dup 7) (const_int 16))) + (clobber (reg:CC 21))]) + (parallel [(set (match_dup 2) + (and:QI (match_dup 7) (const_int 65535))) + (clobber (reg:CC 21))]) + (parallel [(set (match_dup 4) + (mult:QI (sign_extend:QI (and:QI (match_dup 2) + (const_int 16777215))) + (sign_extend:QI (and:QI (match_dup 2) + (const_int 16777215))))) + (clobber (reg:CC_NOOV 21))]) + (parallel [(set (match_dup 5) + (mult:QI (sign_extend:QI (and:QI (match_dup 2) + (const_int 16777215))) + (sign_extend:QI (and:QI (match_dup 3) + (const_int 16777215))))) + (clobber (reg:CC_NOOV 21))]) + (parallel [(set (match_dup 6) + (ashift:QI (match_dup 5) (const_int 17))) + (clobber (reg:CC 21))]) + (parallel [(set (match_operand:QI 0 "reg_operand" "") + (plus:QI (match_dup 4) (match_dup 6))) + (clobber (reg:CC_NOOV 21))])] + "" + " + operands[2] = gen_reg_rtx (QImode); /* a = val & 0xffff */ + operands[3] = gen_reg_rtx (QImode); /* b = val >> 16 */ + operands[4] = gen_reg_rtx (QImode); /* a * a */ + operands[5] = gen_reg_rtx (QImode); /* a * b */ + operands[6] = gen_reg_rtx (QImode); /* (a * b) << 17 */ + operands[7] = gen_reg_rtx (QImode); /* val */ + ") + +; Inlined integer multiply for C3x +(define_expand "mulqi3_inline" + [(set (match_dup 12) (const_int -16)) + (set (match_dup 13) (match_operand:QI 1 "src_operand" "")) + (set (match_dup 14) (match_operand:QI 2 "src_operand" "")) + (parallel [(set (match_dup 4) + (lshiftrt:QI (match_dup 13) (neg:QI (match_dup 12)))) + (clobber (reg:CC 21))]) + (parallel [(set (match_dup 6) + (lshiftrt:QI (match_dup 14) (neg:QI (match_dup 12)))) + (clobber (reg:CC 21))]) + (parallel [(set (match_dup 3) + (and:QI (match_dup 13) + (const_int 65535))) + (clobber (reg:CC 21))]) + (parallel [(set (match_dup 5) + (and:QI (match_dup 14) + (const_int 65535))) + (clobber (reg:CC 21))]) + (parallel [(set (match_dup 7) + (mult:QI (sign_extend:QI (and:QI (match_dup 4) + (const_int 16777215))) + (sign_extend:QI (and:QI (match_dup 5) + (const_int 16777215))))) + (clobber (reg:CC_NOOV 21))]) + (parallel [(set (match_dup 8) + (mult:QI (sign_extend:QI (and:QI (match_dup 3) + (const_int 16777215))) + (sign_extend:QI (and:QI (match_dup 5) + (const_int 16777215))))) + (clobber (reg:CC_NOOV 21))]) + (parallel [(set (match_dup 9) + (mult:QI (sign_extend:QI (and:QI (match_dup 3) + (const_int 16777215))) + (sign_extend:QI (and:QI (match_dup 6) + (const_int 16777215))))) + (clobber (reg:CC_NOOV 21))]) + (parallel [(set (match_dup 10) + (plus:QI (match_dup 7) (match_dup 9))) + (clobber (reg:CC_NOOV 21))]) + (parallel [(set (match_dup 11) + (ashift:QI (match_dup 10) (const_int 16))) + (clobber (reg:CC 21))]) + (parallel [(set (match_operand:QI 0 "reg_operand" "") + (plus:QI (match_dup 8) (match_dup 11))) + (clobber (reg:CC_NOOV 21))])] + "TARGET_C3X" + " + operands[3] = gen_reg_rtx (QImode); /* a = arg1 & 0xffff */ + operands[4] = gen_reg_rtx (QImode); /* b = arg1 >> 16 */ + operands[5] = gen_reg_rtx (QImode); /* a = arg2 & 0xffff */ + operands[6] = gen_reg_rtx (QImode); /* b = arg2 >> 16 */ + operands[7] = gen_reg_rtx (QImode); /* b * c */ + operands[8] = gen_reg_rtx (QImode); /* a * c */ + operands[9] = gen_reg_rtx (QImode); /* a * d */ + operands[10] = gen_reg_rtx (QImode); /* b * c + a * d */ + operands[11] = gen_reg_rtx (QImode); /* (b *c + a * d) << 16 */ + operands[12] = gen_reg_rtx (QImode); /* -16 */ + operands[13] = gen_reg_rtx (QImode); /* arg1 */ + operands[14] = gen_reg_rtx (QImode); /* arg2 */ + ") + +; +; MPYSHI (C4x only) +; +(define_expand "smulqi3_highpart" + [(parallel [(set (match_operand:QI 0 "reg_operand" "") + (truncate:QI + (lshiftrt:HI + (mult:HI + (sign_extend:HI (match_operand:QI 1 "src_operand" "")) + (sign_extend:HI (match_operand:QI 2 "src_operand" ""))) + (const_int 32)))) + (clobber (reg:CC_NOOV 21))])] + "" + "legitimize_operands (MULT, operands, QImode); + if (TARGET_C3X) + { + c4x_emit_libcall_mulhi (SMULHI3_LIBCALL, SIGN_EXTEND, QImode, operands); + DONE; + } + ") + +(define_insn "*smulqi3_highpart_clobber" + [(set (match_operand:QI 0 "reg_operand" "=d,?d,d,c,?c,c") + (truncate:QI + (lshiftrt:HI + (mult:HI + (sign_extend:HI (match_operand:QI 1 "src_operand" "%rR,rS<>,0,rR,rS<>,0")) + (sign_extend:HI (match_operand:QI 2 "src_operand" "JR,rS<>,g,JR,rS<>,g"))) + (const_int 32)))) + (clobber (reg:CC_NOOV 21))] + "! TARGET_C3X && valid_operands (MULT, operands, QImode)" + "@ + mpyshi3\\t%2,%1,%0 + mpyshi3\\t%2,%1,%0 + mpyshi\\t%2,%0 + mpyshi3\\t%2,%1,%0 + mpyshi3\\t%2,%1,%0 + mpyshi\\t%2,%0" + [(set_attr "type" "binarycc,binarycc,binarycc,binary,binary,binary") + (set_attr "data" "int16,int16,int16,int16,int16,int16")]) + +; +; MPYUHI (C4x only) +; +(define_expand "umulqi3_highpart" + [(parallel [(set (match_operand:QI 0 "reg_operand" "") + (truncate:QI + (lshiftrt:HI + (mult:HI + (zero_extend:HI (match_operand:QI 1 "src_operand" "")) + (zero_extend:HI (match_operand:QI 2 "lsrc_operand" ""))) + (const_int 32)))) + (clobber (reg:CC_NOOV 21))])] + "" + "legitimize_operands (MULT, operands, QImode); + if (TARGET_C3X) + { + c4x_emit_libcall_mulhi (UMULHI3_LIBCALL, ZERO_EXTEND, QImode, operands); + DONE; + } + ") + +(define_insn "*umulqi3_highpart_clobber" + [(set (match_operand:QI 0 "reg_operand" "=d,?d,d,c,?c,c") + (truncate:QI + (lshiftrt:HI + (mult:HI + (zero_extend:HI (match_operand:QI 1 "src_operand" "%rR,rS<>,0,rR,rS<>,0")) + (zero_extend:HI (match_operand:QI 2 "lsrc_operand" "JR,rS<>,g,JR,rS<>,g"))) + (const_int 32)))) + (clobber (reg:CC_NOOV 21))] + "! TARGET_C3X && valid_operands (MULT, operands, QImode)" + "@ + mpyuhi3\\t%2,%1,%0 + mpyuhi3\\t%2,%1,%0 + mpyuhi\\t%2,%0 + mpyuhi3\\t%2,%1,%0 + mpyuhi3\\t%2,%1,%0 + mpyuhi\\t%2,%0" + [(set_attr "type" "binarycc,binarycc,binarycc,binary,binary,binary") + (set_attr "data" "uint16,uint16,uint16,uint16,uint16,uint16")]) + +; +; AND +; +(define_expand "andqi3" + [(parallel [(set (match_operand:QI 0 "reg_operand" "") + (and:QI (match_operand:QI 1 "src_operand" "") + (match_operand:QI 2 "tsrc_operand" ""))) + (clobber (reg:CC 21))])] + "" + "legitimize_operands (AND, operands, QImode);") + +(define_insn "*andqi3_clobber" + [(set (match_operand:QI 0 "reg_operand" "=d,?d,d,d,c,?c,c,c") + (and:QI (match_operand:QI 1 "src_operand" "%rR,rS<>,0,0,rR,rS<>,0,0") + (match_operand:QI 2 "tsrc_operand" "JR,rS<>,N,rLm,JR,rS<>,N,rLm"))) + (clobber (reg:CC 21))] + "valid_operands (AND, operands, QImode)" + "@ + and3\\t%2,%1,%0 + and3\\t%2,%1,%0 + andn\\t%N2,%0 + and\\t%2,%0 + and3\\t%2,%1,%0 + and3\\t%2,%1,%0 + andn\\t%N2,%0 + and\\t%2,%0" + [(set_attr "type" "binarycc,binarycc,binarycc,binarycc,binary,binary,binary,binary") + (set_attr "data" "int16,uint16,not_uint16,uint16,int16,uint16,not_uint16,uint16")]) + +(define_insn "*andqi3_test" + [(set (reg:CC 21) + (compare:CC (and:QI (match_operand:QI 1 "src_operand" "rR,rS<>,0,r") + (match_operand:QI 2 "tsrc_operand" "JR,rS<>,N,rLm")) + (const_int 0))) + (clobber (match_scratch:QI 0 "=X,X,d,X"))] + "valid_operands (AND, operands, QImode)" + "@ + tstb3\\t%2,%1 + tstb3\\t%2,%1 + andn\\t%N2,%0 + tstb\\t%2,%1" + [(set_attr "type" "binarycc,binarycc,binarycc,binarycc") + (set_attr "data" "int16,uint16,not_uint16,uint16")]) + +(define_peephole + [(parallel [(set (match_operand:QI 0 "ext_reg_operand" "=d,?d,d,d") + (and:QI (match_operand:QI 1 "src_operand" "%rR,rS<>,0,0") + (match_operand:QI 2 "tsrc_operand" "JR,rS<>,N,rLm"))) + (clobber (reg:CC 21))]) + (set (reg:CC 21) + (compare:CC (match_dup 0) (const_int 0)))] + "valid_operands (AND, operands, QImode)" + "@ + and3\\t%2,%1,%0 + and3\\t%2,%1,%0 + andn\\t%N2,%0 + and\\t%2,%0" + [(set_attr "type" "binarycc,binarycc,binarycc,binarycc") + (set_attr "data" "int16,uint16,not_uint16,uint16")]) + +(define_insn "*andqi3_set" + [(set (reg:CC 21) + (compare:CC (and:QI (match_operand:QI 1 "src_operand" "%rR,rS<>,0,0") + (match_operand:QI 2 "tsrc_operand" "JR,rS<>,N,rLm")) + (const_int 0))) + (set (match_operand:QI 0 "ext_reg_operand" "=d,?d,d,d") + (and:QI (match_dup 1) + (match_dup 2)))] + "valid_operands (AND, operands, QImode)" + "@ + and3\\t%2,%1,%0 + and3\\t%2,%1,%0 + andn\\t%N2,%0 + and\\t%2,%0" + [(set_attr "type" "binarycc,binarycc,binarycc,binarycc") + (set_attr "data" "int16,uint16,not_uint16,uint16")]) + +; +; ANDN +; +; NB, this insn doesn't have commutative operands, but valid_operands +; assumes that the code AND does. We might have to kludge this if +; we make valid_operands stricter. +(define_insn "*andnqi3_clobber" + [(set (match_operand:QI 0 "reg_operand" "=d,?d,d,c,?c,c") + (and:QI (not:QI (match_operand:QI 2 "lsrc_operand" "JR,rS<>,rLm,JR,rS<>,rLm")) + (match_operand:QI 1 "src_operand" "rR,rS<>,0,rR,rS<>,0"))) + (clobber (reg:CC 21))] + "valid_operands (AND, operands, QImode)" + "@ + andn3\\t%2,%1,%0 + andn3\\t%2,%1,%0 + andn\\t%2,%0 + andn3\\t%2,%1,%0 + andn3\\t%2,%1,%0 + andn\\t%2,%0" + [(set_attr "type" "binarycc,binarycc,binarycc,binary,binary,binary") + (set_attr "data" "int16,uint16,uint16,int16,uint16,uint16")]) + +(define_insn "*andnqi3_test" + [(set (reg:CC 21) + (compare:CC (and:QI (not:QI (match_operand:QI 2 "lsrc_operand" "JR,rS<>,rLm")) + (match_operand:QI 1 "src_operand" "rR,rS<>,0")) + (const_int 0))) + (clobber (match_scratch:QI 0 "=d,?d,d"))] + "valid_operands (AND, operands, QImode)" + "@ + andn3\\t%2,%1,%0 + andn3\\t%2,%1,%0 + andn\\t%2,%0" + [(set_attr "type" "binarycc,binarycc,binarycc") + (set_attr "data" "int16,uint16,uint16")]) + +(define_insn "*andnqi3_set" + [(set (reg:CC 21) + (compare:CC (and:QI (not:QI (match_operand:QI 2 "lsrc_operand" "JR,rS<>,rLm")) + (match_operand:QI 1 "src_operand" "rR,rS<>,0")) + (const_int 0))) + (set (match_operand:QI 0 "ext_reg_operand" "=d,?d,d") + (and:QI (not:QI (match_dup 2)) + (match_dup 1)))] + "valid_operands (AND, operands, QImode)" + "@ + andn3\\t%2,%1,%0 + andn3\\t%2,%1,%0 + andn\\t%2,%0" + [(set_attr "type" "binarycc,binarycc,binarycc") + (set_attr "data" "int16,uint16,uint16")]) + +; +; OR +; +(define_expand "iorqi3" + [(parallel [(set (match_operand:QI 0 "reg_operand" "") + (ior:QI (match_operand:QI 1 "src_operand" "") + (match_operand:QI 2 "lsrc_operand" ""))) + (clobber (reg:CC 21))])] + "" + "legitimize_operands (IOR, operands, QImode);") + +(define_insn "*iorqi3_clobber" + [(set (match_operand:QI 0 "reg_operand" "=d,?d,d,c,?c,c") + (ior:QI (match_operand:QI 1 "src_operand" "%rR,rS<>,0,rR,rS<>,0") + (match_operand:QI 2 "lsrc_operand" "JR,rS<>,rLm,JR,rS<>,rLm"))) + (clobber (reg:CC 21))] + "valid_operands (IOR, operands, QImode)" + "@ + or3\\t%2,%1,%0 + or3\\t%2,%1,%0 + or\\t%2,%0 + or3\\t%2,%1,%0 + or3\\t%2,%1,%0 + or\\t%2,%0" + [(set_attr "type" "binarycc,binarycc,binarycc,binary,binary,binary") + (set_attr "data" "int16,uint16,uint16,int16,uint16,uint16")]) + +(define_insn "*iorqi3_test" + [(set (reg:CC 21) + (compare:CC (ior:QI (match_operand:QI 1 "src_operand" "%rR,rS<>,0") + (match_operand:QI 2 "lsrc_operand" "JR,rS<>,rLm")) + (const_int 0))) + (clobber (match_scratch:QI 0 "=d,?d,d"))] + "valid_operands (IOR, operands, QImode)" + "@ + or3\\t%2,%1,%0 + or3\\t%2,%1,%0 + or\\t%2,%0" + [(set_attr "type" "binarycc,binarycc,binarycc") + (set_attr "data" "int16,uint16,uint16")]) + +(define_peephole + [(parallel [(set (match_operand:QI 0 "ext_reg_operand" "=d,?d,d") + (ior:QI (match_operand:QI 1 "src_operand" "%rR,rS<>,0") + (match_operand:QI 2 "lsrc_operand" "JR,rS<>,rLm"))) + (clobber (reg:CC 21))]) + (set (reg:CC 21) + (compare:CC (match_dup 0) (const_int 0)))] + "valid_operands (IOR, operands, QImode)" + "@ + or3\\t%2,%1,%0 + or3\\t%2,%1,%0 + or\\t%2,%0" + [(set_attr "type" "binarycc,binarycc,binarycc") + (set_attr "data" "int16,uint16,uint16")]) + +(define_insn "*iorqi3_set" + [(set (reg:CC 21) + (compare:CC (ior:QI (match_operand:QI 1 "src_operand" "%rR,rS<>,0") + (match_operand:QI 2 "lsrc_operand" "JR,rS<>,rLm")) + (const_int 0))) + (set (match_operand:QI 0 "ext_reg_operand" "=d,?d,d") + (ior:QI (match_dup 1) + (match_dup 2)))] + "valid_operands (IOR, operands, QImode)" + "@ + or3\\t%2,%1,%0 + or3\\t%2,%1,%0 + or\\t%2,%0" + [(set_attr "type" "binarycc,binarycc,binarycc") + (set_attr "data" "int16,uint16,uint16")]) + +; This pattern is used for loading symbol references in several parts. +(define_insn "iorqi3_noclobber" + [(set (match_operand:QI 0 "std_reg_operand" "=c,?c,c") + (ior:QI (match_operand:QI 1 "src_operand" "%rR,rS<>,0") + (match_operand:QI 2 "lsrc_operand" "JR,rS<>,rLm")))] + "valid_operands (IOR, operands, QImode)" + "@ + or3\\t%2,%1,%0 + or3\\t%2,%1,%0 + or\\t%2,%0" + [(set_attr "type" "binary,binary,binary") + (set_attr "data" "int16,uint16,uint16")]) + +; +; XOR +; +(define_expand "xorqi3" + [(parallel [(set (match_operand:QI 0 "reg_operand" "") + (xor:QI (match_operand:QI 1 "src_operand" "") + (match_operand:QI 2 "lsrc_operand" ""))) + (clobber (reg:CC 21))])] + "" + "legitimize_operands (XOR, operands, QImode);") + +(define_insn "*xorqi3_clobber" + [(set (match_operand:QI 0 "reg_operand" "=d,?d,d,c,?c,c") + (xor:QI (match_operand:QI 1 "src_operand" "%rR,rS<>,0,rR,rS<>,0") + (match_operand:QI 2 "lsrc_operand" "JR,rS<>,rLm,JR,rS<>,rLm"))) + (clobber (reg:CC 21))] + "valid_operands (XOR, operands, QImode)" + "@ + xor3\\t%2,%1,%0 + xor3\\t%2,%1,%0 + xor\\t%2,%0 + xor3\\t%2,%1,%0 + xor3\\t%2,%1,%0 + xor\\t%2,%0" + [(set_attr "type" "binarycc,binarycc,binarycc,binary,binary,binary") + (set_attr "data" "int16,uint16,uint16,int16,uint16,uint16")]) + +(define_insn "*xorqi3_test" + [(set (reg:CC 21) + (compare:CC (xor:QI (match_operand:QI 1 "src_operand" "%rR,rS<>,0") + (match_operand:QI 2 "lsrc_operand" "JR,rS<>,rLm")) + (const_int 0))) + (clobber (match_scratch:QI 0 "=d,?d,d"))] + "valid_operands (XOR, operands, QImode)" + "@ + xor3\\t%2,%1,%0 + xor3\\t%2,%1,%0 + xor\\t%2,%0" + [(set_attr "type" "binarycc,binarycc,binarycc") + (set_attr "data" "int16,uint16,uint16")]) + +(define_insn "*xorqi3_set" + [(set (reg:CC 21) + (compare:CC (xor:QI (match_operand:QI 1 "src_operand" "%rR,rS<>,0") + (match_operand:QI 2 "lsrc_operand" "JR,rS<>,rLm")) + (const_int 0))) + (set (match_operand:QI 0 "ext_reg_operand" "=d,?d,d") + (xor:QI (match_dup 1) + (match_dup 2)))] + "valid_operands (XOR, operands, QImode)" + "@ + xor3\\t%2,%1,%0 + xor3\\t%2,%1,%0 + xor\\t%2,%0" + [(set_attr "type" "binarycc,binarycc,binarycc") + (set_attr "data" "int16,uint16,uint16")]) + +; +; LSH/ASH (left) +; +; The C3x and C4x have two shift instructions ASH and LSH +; If the shift count is positive, a left shift is performed +; otherwise a right shift is performed. The number of bits +; shifted is determined by the seven LSBs of the shift count. +; If the absolute value of the count is 32 or greater, the result +; using the LSH instruction is zero; with the ASH insn the result +; is zero or negative 1. Note that the ISO C standard allows +; the result to be machine dependent whenever the shift count +; exceeds the size of the object. +(define_expand "ashlqi3" + [(parallel [(set (match_operand:QI 0 "reg_operand" "") + (ashift:QI (match_operand:QI 1 "src_operand" "") + (match_operand:QI 2 "src_operand" ""))) + (clobber (reg:CC 21))])] + "" + "legitimize_operands (ASHIFT, operands, QImode);") + +(define_insn "*ashlqi3_clobber" + [(set (match_operand:QI 0 "reg_operand" "=d,?d,d,c,?c,c") + (ashift:QI (match_operand:QI 1 "src_operand" "rR,rS<>,0,rR,rS<>,0") + (match_operand:QI 2 "src_operand" "JR,rS<>,g,JR,rS<>,g"))) + (clobber (reg:CC 21))] + "valid_operands (ASHIFT, operands, QImode)" + "@ + ash3\\t%2,%1,%0 + ash3\\t%2,%1,%0 + ash\\t%2,%0 + ash3\\t%2,%1,%0 + ash3\\t%2,%1,%0 + ash\\t%2,%0" + [(set_attr "type" "binarycc,binarycc,binarycc,binary,binary,binary")]) +; Default to int16 data attr. + +(define_insn "*ashlqi3_set" + [(set (reg:CC 21) + (compare:CC + (ashift:QI (match_operand:QI 1 "src_operand" "rR,rS<>,0") + (match_operand:QI 2 "src_operand" "JR,rS<>,g")) + (const_int 0))) + (set (match_operand:QI 0 "reg_operand" "=d,?d,d") + (ashift:QI (match_dup 1) + (match_dup 2)))] + "valid_operands (ASHIFT, operands, QImode)" + "@ + ash3\\t%2,%1,%0 + ash3\\t%2,%1,%0 + ash\\t%2,%0" + [(set_attr "type" "binarycc,binarycc,binarycc")]) +; Default to int16 data attr. + +; This is only used by lshrhi3_reg where we need a LSH insn that will +; shift both ways. +(define_insn "*lshlqi3_clobber" + [(set (match_operand:QI 0 "reg_operand" "=d,?d,d,c,?c,c") + (ashift:QI (match_operand:QI 1 "src_operand" "rR,rS<>,0,rR,rS<>,0") + (unspec [(match_operand:QI 2 "src_operand" "JR,rS<>,g,JR,rS<>,g")] 3))) + (clobber (reg:CC 21))] + "valid_operands (ASHIFT, operands, QImode)" + "@ + lsh3\\t%2,%1,%0 + lsh3\\t%2,%1,%0 + lsh\\t%2,%0 + lsh3\\t%2,%1,%0 + lsh3\\t%2,%1,%0 + lsh\\t%2,%0" + [(set_attr "type" "binarycc,binarycc,binarycc,binary,binary,binary")]) +; Default to int16 data attr. + +; +; LSH (right) +; +; Logical right shift on the C[34]x works by negating the shift count, +; then emitting a right shift with the shift count negated. This means +; that all actual shift counts in the RTL will be positive. +; +(define_expand "lshrqi3" + [(parallel [(set (match_operand:QI 0 "reg_operand" "") + (lshiftrt:QI (match_operand:QI 1 "src_operand" "") + (match_operand:QI 2 "src_operand" ""))) + (clobber (reg:CC 21))])] + "" + "legitimize_operands (LSHIFTRT, operands, QImode);") + +; When the shift count is greater than the size of the word +; the result can be implementation specific +(define_insn "*lshrqi3_const_clobber" + [(set (match_operand:QI 0 "reg_operand" "=d,c,?d,?c") + (lshiftrt:QI (match_operand:QI 1 "src_operand" "0,0,r,r") + (match_operand:QI 2 "const_int_operand" "n,n,J,J"))) + (clobber (reg:CC 21))] + "valid_operands (LSHIFTRT, operands, QImode)" + "@ + lsh\\t%n2,%0 + lsh\\t%n2,%0 + lsh3\\t%n2,%1,%0 + lsh3\\t%n2,%1,%0" + [(set_attr "type" "binarycc,binarycc,binarycc,binarycc")]) + +; When the shift count is greater than the size of the word +; the result can be implementation specific +(define_insn "*lshrqi3_const_set" + [(set (reg:CC 21) + (compare:CC + (lshiftrt:QI (match_operand:QI 1 "src_operand" "0,r") + (match_operand:QI 2 "const_int_operand" "n,J")) + (const_int 0))) + (set (match_operand:QI 0 "reg_operand" "=?d,d") + (lshiftrt:QI (match_dup 1) + (match_dup 2)))] + "valid_operands (LSHIFTRT, operands, QImode)" + "@ + lsh\\t%n2,%0 + lsh3\\t%n2,%1,%0" + [(set_attr "type" "binarycc,binarycc")]) + +(define_insn "*lshrqi3_nonconst_clobber" + [(set (match_operand:QI 0 "reg_operand" "=d,?d,d,c,?c,c") + (lshiftrt:QI (match_operand:QI 1 "src_operand" "rR,rS<>,0,rR,rS<>,0") + (neg:QI (match_operand:QI 2 "src_operand" "R,rS<>,rm,R,rS<>,rm")))) + (clobber (reg:CC 21))] + "valid_operands (LSHIFTRT, operands, QImode)" + "@ + lsh3\\t%2,%1,%0 + lsh3\\t%2,%1,%0 + lsh\\t%2,%0 + lsh3\\t%2,%1,%0 + lsh3\\t%2,%1,%0 + lsh\\t%2,%0" + [(set_attr "type" "binarycc,binarycc,binarycc,binary,binary,binary")]) +; Default to int16 data attr. + +; +; ASH (right) +; +; Arithmetic right shift on the C[34]x works by negating the shift count, +; then emitting a right shift with the shift count negated. This means +; that all actual shift counts in the RTL will be positive. + +(define_expand "ashrqi3" + [(parallel [(set (match_operand:QI 0 "reg_operand" "") + (ashiftrt:QI (match_operand:QI 1 "src_operand" "") + (match_operand:QI 2 "src_operand" ""))) + (clobber (reg:CC 21))])] + "" + "legitimize_operands (ASHIFTRT, operands, QImode);") + +; When the shift count is greater than the size of the word +; the result can be implementation specific +(define_insn "*ashrqi3_const_clobber" + [(set (match_operand:QI 0 "reg_operand" "=d,c,?d,?c") + (ashiftrt:QI (match_operand:QI 1 "src_operand" "0,0,r,r") + (match_operand:QI 2 "const_int_operand" "n,n,J,J"))) + (clobber (reg:CC 21))] + "valid_operands (ASHIFTRT, operands, QImode)" + "@ + ash\\t%n2,%0 + ash\\t%n2,%0 + ash3\\t%n2,%1,%0 + ash3\\t%n2,%1,%0" + [(set_attr "type" "binarycc,binarycc,binarycc,binarycc")]) + +; When the shift count is greater than the size of the word +; the result can be implementation specific +(define_insn "*ashrqi3_const_set" + [(set (reg:CC 21) + (compare:CC + (ashiftrt:QI (match_operand:QI 1 "src_operand" "0,r") + (match_operand:QI 2 "const_int_operand" "n,J")) + (const_int 0))) + (set (match_operand:QI 0 "reg_operand" "=?d,d") + (ashiftrt:QI (match_dup 1) + (match_dup 2)))] + "valid_operands (ASHIFTRT, operands, QImode)" + "@ + ash\\t%n2,%0 + ash3\\t%n2,%1,%0" + [(set_attr "type" "binarycc,binarycc")]) + +(define_insn "*ashrqi3_nonconst_clobber" + [(set (match_operand:QI 0 "reg_operand" "=d,?d,d,c,?c,c") + (ashiftrt:QI (match_operand:QI 1 "src_operand" "rR,rS<>,0,rR,rS<>,0") + (neg:QI (match_operand:QI 2 "src_operand" "R,rS<>,rm,R,rS<>,rm")))) + (clobber (reg:CC 21))] + "valid_operands (ASHIFTRT, operands, QImode)" + "@ + ash3\\t%2,%1,%0 + ash3\\t%2,%1,%0 + ash\\t%2,%0 + ash3\\t%2,%1,%0 + ash3\\t%2,%1,%0 + ash\\t%2,%0" + [(set_attr "type" "binarycc,binarycc,binarycc,binary,binary,binary")]) +; Default to int16 data attr. + +; +; CMPI +; +; Unfortunately the C40 doesn't allow cmpi3 7, *ar0++ so the next best +; thing would be to get the small constant loaded into a register (say r0) +; so that it could be hoisted out of the loop so that we only +; would need to do cmpi3 *ar0++, r0. Now the loop optimisation pass +; comes before the flow pass (which finds autoincrements) so we're stuck. +; Ideally, GCC requires another loop optimisation pass (preferably after +; reload) so that it can hoist invariants out of loops. +; The current solution modifies legitimize_operands () so that small +; constants are forced into a pseudo register. +; +(define_expand "cmpqi" + [(set (reg:CC 21) + (compare:CC (match_operand:QI 0 "src_operand" "") + (match_operand:QI 1 "src_operand" "")))] + "" + "legitimize_operands (COMPARE, operands, QImode); + c4x_compare_op0 = operands[0]; + c4x_compare_op1 = operands[1]; + DONE;") + +(define_insn "*cmpqi_test" + [(set (reg:CC 21) + (compare:CC (match_operand:QI 0 "src_operand" "rR,?rS<>,r") + (match_operand:QI 1 "src_operand" "JR,rS<>,g")))] + "valid_operands (COMPARE, operands, QImode)" + "@ + cmpi3\\t%1,%0 + cmpi3\\t%1,%0 + cmpi\\t%1,%0" + [(set_attr "type" "compare,compare,compare")]) + +(define_insn "*cmpqi_test_noov" + [(set (reg:CC_NOOV 21) + (compare:CC_NOOV (match_operand:QI 0 "src_operand" "rR,?rS<>,r") + (match_operand:QI 1 "src_operand" "JR,rS<>,g")))] + "valid_operands (COMPARE, operands, QImode)" + "@ + cmpi3\\t%1,%0 + cmpi3\\t%1,%0 + cmpi\\t%1,%0" + [(set_attr "type" "compare,compare,compare")]) + +(define_expand "udivqi3" + [(parallel [(set (match_operand:QI 0 "reg_operand" "") + (udiv:QI (match_operand:QI 1 "src_operand" "") + (match_operand:QI 2 "src_operand" ""))) + (clobber (reg:CC 21))])] + "" + "c4x_emit_libcall3 (UDIVQI3_LIBCALL, UDIV, QImode, operands); + DONE;") + +(define_expand "divqi3" + [(parallel [(set (match_operand:QI 0 "reg_operand" "") + (div:QI (match_operand:QI 1 "src_operand" "") + (match_operand:QI 2 "src_operand" ""))) + (clobber (reg:CC 21))])] + "" + "c4x_emit_libcall3 (DIVQI3_LIBCALL, DIV, QImode, operands); + DONE;") + +(define_expand "umodqi3" + [(parallel [(set (match_operand:QI 0 "reg_operand" "") + (umod:QI (match_operand:QI 1 "src_operand" "") + (match_operand:QI 2 "src_operand" ""))) + (clobber (reg:CC 21))])] + "" + "c4x_emit_libcall3 (UMODQI3_LIBCALL, UMOD, QImode, operands); + DONE;") + +(define_expand "modqi3" + [(parallel [(set (match_operand:QI 0 "reg_operand" "") + (mod:QI (match_operand:QI 1 "src_operand" "") + (match_operand:QI 2 "src_operand" ""))) + (clobber (reg:CC 21))])] + "" + "c4x_emit_libcall3 (MODQI3_LIBCALL, MOD, QImode, operands); + DONE;") + +(define_expand "ffsqi2" + [(parallel [(set (match_operand:QI 0 "reg_operand" "") + (ffs:QI (match_operand:QI 1 "src_operand" ""))) + (clobber (reg:CC 21))])] + "" + "c4x_emit_libcall (FFS_LIBCALL, FFS, QImode, QImode, 2, operands); + DONE;") + +; +; BIT-FIELD INSTRUCTIONS +; + +; +; LBx/LHw (C4x only) +; +(define_expand "extv" + [(parallel [(set (match_operand:QI 0 "reg_operand" "") + (sign_extract:QI (match_operand:QI 1 "src_operand" "") + (match_operand:QI 2 "const_int_operand" "") + (match_operand:QI 3 "const_int_operand" ""))) + (clobber (reg:CC 21))])] + "! TARGET_C3X" + "if ((INTVAL (operands[2]) != 8 && INTVAL (operands[2]) != 16) + || (INTVAL (operands[3]) % INTVAL (operands[2]) != 0)) + FAIL; + ") + +(define_insn "*extv_clobber" + [(set (match_operand:QI 0 "reg_operand" "=d,c") + (sign_extract:QI (match_operand:QI 1 "src_operand" "g,g") + (match_operand:QI 2 "const_int_operand" "n,n") + (match_operand:QI 3 "const_int_operand" "n,n"))) + (clobber (reg:CC 21))] + "! TARGET_C3X + && (INTVAL (operands[2]) == 8 || INTVAL (operands[2]) == 16) + && (INTVAL (operands[3]) % INTVAL (operands[2]) == 0)" + "* + if (INTVAL (operands[2]) == 8) + { + operands[3] = GEN_INT (INTVAL (operands[3]) / 8); + return \"lb%3\\t%1,%0\"; + } + operands[3] = GEN_INT (INTVAL (operands[3]) / 16); + return \"lh%3\\t%1,%0\"; + " + [(set_attr "type" "binarycc,binary") + (set_attr "data" "int16,int16")]) + +(define_insn "*extv_clobber_test" + [(set (reg:CC 21) + (compare:CC (sign_extract:QI (match_operand:QI 1 "src_operand" "g") + (match_operand:QI 2 "const_int_operand" "n") + (match_operand:QI 3 "const_int_operand" "n")) + (const_int 0))) + (clobber (match_scratch:QI 0 "=d"))] + "! TARGET_C3X + && (INTVAL (operands[2]) == 8 || INTVAL (operands[2]) == 16) + && (INTVAL (operands[3]) % INTVAL (operands[2]) == 0)" + "* + if (INTVAL (operands[2]) == 8) + { + operands[3] = GEN_INT (INTVAL (operands[3]) / 8); + return \"lb%3\\t%1,%0\"; + } + operands[3] = GEN_INT (INTVAL (operands[3]) / 16); + return \"lh%3\\t%1,%0\"; + " + [(set_attr "type" "binarycc") + (set_attr "data" "int16")]) + +(define_insn "*extv_clobber_set" + [(set (reg:CC 21) + (compare:CC (sign_extract:QI (match_operand:QI 1 "src_operand" "g") + (match_operand:QI 2 "const_int_operand" "n") + (match_operand:QI 3 "const_int_operand" "n")) + (const_int 0))) + (set (match_operand:QI 0 "reg_operand" "=d") + (sign_extract:QI (match_dup 1) + (match_dup 2) + (match_dup 3)))] + "! TARGET_C3X + && (INTVAL (operands[2]) == 8 || INTVAL (operands[2]) == 16) + && (INTVAL (operands[3]) % INTVAL (operands[2]) == 0)" + "* + if (INTVAL (operands[2]) == 8) + { + operands[3] = GEN_INT (INTVAL (operands[3]) / 8); + return \"lb%3\\t%1,%0\"; + } + operands[3] = GEN_INT (INTVAL (operands[3]) / 16); + return \"lh%3\\t%1,%0\"; + " + [(set_attr "type" "binarycc") + (set_attr "data" "int16")]) + +; +; LBUx/LHUw (C4x only) +; +(define_expand "extzv" + [(parallel [(set (match_operand:QI 0 "reg_operand" "") + (zero_extract:QI (match_operand:QI 1 "src_operand" "") + (match_operand:QI 2 "const_int_operand" "") + (match_operand:QI 3 "const_int_operand" ""))) + (clobber (reg:CC 21))])] + "! TARGET_C3X" + "if ((INTVAL (operands[2]) != 8 && INTVAL (operands[2]) != 16) + || (INTVAL (operands[3]) % INTVAL (operands[2]) != 0)) + FAIL; + ") + +(define_insn "*extzv_clobber" + [(set (match_operand:QI 0 "reg_operand" "=d,c") + (zero_extract:QI (match_operand:QI 1 "src_operand" "g,g") + (match_operand:QI 2 "const_int_operand" "n,n") + (match_operand:QI 3 "const_int_operand" "n,n"))) + (clobber (reg:CC 21))] + "! TARGET_C3X + && (INTVAL (operands[2]) == 8 || INTVAL (operands[2]) == 16) + && (INTVAL (operands[3]) % INTVAL (operands[2]) == 0)" + "* + if (INTVAL (operands[2]) == 8) + { + operands[3] = GEN_INT (INTVAL (operands[3]) / 8); + return \"lbu%3\\t%1,%0\"; + } + operands[3] = GEN_INT (INTVAL (operands[3]) / 16); + return \"lhu%3\\t%1,%0\"; + " + [(set_attr "type" "binarycc,binary") + (set_attr "data" "uint16,uint16")]) + +(define_insn "*extzv_test" + [(set (reg:CC 21) + (compare:CC (zero_extract:QI (match_operand:QI 1 "src_operand" "g") + (match_operand:QI 2 "const_int_operand" "n") + (match_operand:QI 3 "const_int_operand" "n")) + (const_int 0))) + (clobber (match_scratch:QI 0 "=d"))] + "! TARGET_C3X + && (INTVAL (operands[2]) == 8 || INTVAL (operands[2]) == 16) + && (INTVAL (operands[3]) % INTVAL (operands[2]) == 0)" + "* + if (INTVAL (operands[2]) == 8) + { + operands[3] = GEN_INT (INTVAL (operands[3]) / 8); + return \"lbu%3\\t%1,%0\"; + } + operands[3] = GEN_INT (INTVAL (operands[3]) / 16); + return \"lhu%3\\t%1,%0\"; + " + [(set_attr "type" "binarycc") + (set_attr "data" "uint16")]) + +(define_insn "*extzv_set" + [(set (reg:CC 21) + (compare:CC (zero_extract:QI (match_operand:QI 1 "src_operand" "g") + (match_operand:QI 2 "const_int_operand" "n") + (match_operand:QI 3 "const_int_operand" "n")) + (const_int 0))) + (set (match_operand:QI 0 "reg_operand" "=d") + (zero_extract:QI (match_dup 1) + (match_dup 2) + (match_dup 3)))] + "! TARGET_C3X + && (INTVAL (operands[2]) == 8 || INTVAL (operands[2]) == 16) + && (INTVAL (operands[3]) % INTVAL (operands[2]) == 0)" + "* + if (INTVAL (operands[2]) == 8) + { + operands[3] = GEN_INT (INTVAL (operands[3]) / 8); + return \"lbu%3\\t%1,%0\"; + } + operands[3] = GEN_INT (INTVAL (operands[3]) / 16); + return \"lhu%3\\t%1,%0\"; + " + [(set_attr "type" "binarycc") + (set_attr "data" "uint16")]) + +; +; MBx/MHw (C4x only) +; +(define_expand "insv" + [(parallel [(set (zero_extract:QI (match_operand:QI 0 "reg_operand" "") + (match_operand:QI 1 "const_int_operand" "") + (match_operand:QI 2 "const_int_operand" "")) + (match_operand:QI 3 "src_operand" "")) + (clobber (reg:CC 21))])] + "! TARGET_C3X" + "if (! (((INTVAL (operands[1]) == 8 || INTVAL (operands[1]) == 16) + && (INTVAL (operands[2]) % INTVAL (operands[1]) == 0)) + || (INTVAL (operands[1]) == 24 && INTVAL (operands[2]) == 8))) + FAIL; + ") + +(define_insn "*insv_clobber" + [(set (zero_extract:QI (match_operand:QI 0 "reg_operand" "=d,c") + (match_operand:QI 1 "const_int_operand" "n,n") + (match_operand:QI 2 "const_int_operand" "n,n")) + (match_operand:QI 3 "src_operand" "g,g")) + (clobber (reg:CC 21))] + "! TARGET_C3X + && (((INTVAL (operands[1]) == 8 || INTVAL (operands[1]) == 16) + && (INTVAL (operands[2]) % INTVAL (operands[1]) == 0)) + || (INTVAL (operands[1]) == 24 && INTVAL (operands[2]) == 8))" + "* + if (INTVAL (operands[1]) == 8) + { + operands[2] = GEN_INT (INTVAL (operands[2]) / 8); + return \"mb%2\\t%3,%0\"; + } + else if (INTVAL (operands[1]) == 16) + { + operands[2] = GEN_INT (INTVAL (operands[2]) / 16); + return \"mh%2\\t%3,%0\"; + } + return \"lwl1\\t%3,%0\"; + " + [(set_attr "type" "binarycc,binary") + (set_attr "data" "uint16,uint16")]) + +(define_peephole + [(parallel [(set (zero_extract:QI (match_operand:QI 0 "reg_operand" "=d") + (match_operand:QI 1 "const_int_operand" "n") + (match_operand:QI 2 "const_int_operand" "n")) + (match_operand:QI 3 "src_operand" "g")) + (clobber (reg:CC 21))]) + (set (reg:CC 21) + (compare:CC (match_dup 0) (const_int 0)))] + "! TARGET_C3X + && (INTVAL (operands[1]) == 8 || INTVAL (operands[1]) == 16) + && (INTVAL (operands[2]) % INTVAL (operands[1]) == 0)" + "* + if (INTVAL (operands[1]) == 8) + { + operands[2] = GEN_INT (INTVAL (operands[2]) / 8); + return \"mb%2\\t%3,%0\"; + } + operands[2] = GEN_INT (INTVAL (operands[2]) / 16); + return \"mh%2\\t%3,%0\"; + " + [(set_attr "type" "binarycc") + (set_attr "data" "uint16")]) + +; +; TWO OPERAND FLOAT INSTRUCTIONS +; + +; +; LDF/STF +; +; If one of the operands is not a register, then we should +; emit two insns, using a scratch register. This will produce +; better code in loops if the source operand is invariant, since +; the source reload can be optimised out. During reload we cannot +; use change_address or force_reg. +(define_expand "movqf" + [(set (match_operand:QF 0 "src_operand" "") + (match_operand:QF 1 "src_operand" ""))] + "" + " + if (CONSTANT_P (operands[1]) && ! const_operand (operands[1], QFmode)) + { + operands[1] = force_const_mem (QFmode, operands[1]); + if (! memory_address_p (QFmode, XEXP (operands[1], 0)) + && ! reload_in_progress) + operands[1] = change_address (operands[1], QFmode, + XEXP (operands[1], 0)); + } + + if (! reload_in_progress + && ! reg_operand (operands[0], QFmode) + && ! reg_operand (operands[1], QFmode)) + operands[1] = force_reg (QFmode, operands[1]); + ") + +; We must provide an alternative to store to memory in case we have to +; spill a register. +(define_insn "*movqf_noclobber" + [(set (match_operand:QF 0 "src_operand" "=f,m") + (match_operand:QF 1 "src_operand" "fmH,f"))] + "reg_operand (operands[0], QFmode) + || reg_operand (operands[1], QFmode)" + "@ + ldfu\\t%1,%0 + stf\\t%1,%0" + [(set_attr "type" "unary,store")]) + +;(define_insn "*movqf_clobber" +; [(set (match_operand:QF 0 "reg_operand" "=f") +; (match_operand:QF 1 "src_operand" "fmH")) +; (clobber (reg:CC 21))] +; "0" +; "ldf\\t%1,%0" +; [(set_attr "type" "unarycc")]) + +(define_insn "*movqf_test" + [(set (reg:CC 21) + (compare:CC (match_operand:QF 1 "src_operand" "fmH") + (const_int 0))) + (clobber (match_scratch:QF 0 "=f"))] + "" + "ldf\\t%1,%0" + [(set_attr "type" "unarycc")]) + +(define_insn "*movqf_set" + [(set (reg:CC 21) + (compare:CC (match_operand:QF 1 "src_operand" "fmH") + (match_operand:QF 2 "fp_zero_operand" "G"))) + (set (match_operand:QF 0 "reg_operand" "=f") + (match_dup 1))] + "" + "ldf\\t%1,%0" + [(set_attr "type" "unarycc")]) + +(define_insn "*movqf_update" + [(set (match_operand:QF 0 "reg_operand" "=r") + (mem:QF (plus:QI (match_operand:QI 1 "addr_reg_operand" "a") + (match_operand:QI 2 "index_reg_operand" "x")))) + (set (match_dup 1) + (plus:QI (match_dup 1) (match_dup 2)))] + "" + "ldfu\\t*%1++(%2),%0" + [(set_attr "type" "unary")]) + +(define_insn "*movqf_parallel" + [(set (match_operand:QF 0 "parallel_operand" "=q,S<>,q,S<>") + (match_operand:QF 1 "parallel_operand" "S<>,q,S<>,q")) + (set (match_operand:QF 2 "parallel_operand" "=q,S<>,S<>,q") + (match_operand:QF 3 "parallel_operand" "S<>,q,q,S<>"))] + "valid_parallel_load_store (operands, QFmode)" + "@ + ldf1\\t%1,%0\\n||\\tldf2\\t%3,%2 + stf1\\t%1,%0\\n||\\tstf2\\t%3,%2 + ldf\\t%1,%0\\n||\\tstf\\t%3,%2 + ldf\\t%3,%2\\n||\\tstf\\t%1,%0" + [(set_attr "type" "load_load,store_store,load_store,store_load")]) + + +; +; PUSH/POP +; +(define_insn "*pushqf" + [(set (mem:QF (pre_inc:QI (reg:QI 20))) + (match_operand:QF 0 "reg_operand" "f"))] + "" + "pushf\\t%0" + [(set_attr "type" "push")]) + +(define_insn "*popqf" + [(set (match_operand:QF 0 "reg_operand" "=f") + (mem:QF (post_dec:QI (reg:QI 20)))) + (clobber (reg:CC 21))] + "" + "popf\\t%0" + [(set_attr "type" "pop")]) + + +; +; ABSF +; +(define_expand "absqf2" + [(parallel [(set (match_operand:QF 0 "reg_operand" "") + (abs:QF (match_operand:QF 1 "src_operand" ""))) + (clobber (reg:CC_NOOV 21))])] +"" +"") + +(define_insn "*absqf2_clobber" + [(set (match_operand:QF 0 "reg_operand" "=f") + (abs:QF (match_operand:QF 1 "src_operand" "fmH"))) + (clobber (reg:CC_NOOV 21))] + "" + "absf\\t%1,%0" + [(set_attr "type" "unarycc")]) + +(define_insn "*absqf2_test" + [(set (reg:CC_NOOV 21) + (compare:CC_NOOV (abs:QF (match_operand:QF 1 "src_operand" "fmH")) + (match_operand:QF 2 "fp_zero_operand" "G"))) + (clobber (match_scratch:QF 0 "=f"))] + "" + "absf\\t%1,%0" + [(set_attr "type" "unarycc")]) + +(define_insn "*absqf2_set" + [(set (reg:CC_NOOV 21) + (compare:CC_NOOV (abs:QF (match_operand:QF 1 "src_operand" "fmH")) + (match_operand:QF 2 "fp_zero_operand" "G"))) + (set (match_operand:QF 0 "reg_operand" "=f") + (abs:QF (match_dup 1)))] + + "" + "absf\\t%1,%0" + [(set_attr "type" "unarycc")]) + +; +; NEGF +; +(define_expand "negqf2" + [(parallel [(set (match_operand:QF 0 "reg_operand" "") + (neg:QF (match_operand:QF 1 "src_operand" ""))) + (clobber (reg:CC_NOOV 21))])] +"" +"") + +(define_insn "*negqf2_clobber" + [(set (match_operand:QF 0 "reg_operand" "=f") + (neg:QF (match_operand:QF 1 "src_operand" "fmH"))) + (clobber (reg:CC_NOOV 21))] + "" + "negf\\t%1,%0" + [(set_attr "type" "unarycc")]) + +(define_insn "*negqf2_test" + [(set (reg:CC_NOOV 21) + (compare:CC_NOOV (neg:QF (match_operand:QF 1 "src_operand" "fmH")) + (match_operand:QF 2 "fp_zero_operand" "G"))) + (clobber (match_scratch:QF 0 "=f"))] + "" + "negf\\t%1,%0" + [(set_attr "type" "unarycc")]) + +(define_insn "*negqf2_set" + [(set (reg:CC_NOOV 21) + (compare:CC_NOOV (neg:QF (match_operand:QF 1 "src_operand" "fmH")) + (match_operand:QF 2 "fp_zero_operand" "G"))) + (set (match_operand:QF 0 "reg_operand" "=f") + (neg:QF (match_dup 1)))] + "" + "negf\\t%1,%0" + [(set_attr "type" "unarycc")]) + +; +; FLOAT +; +(define_insn "floatqiqf2" + [(set (match_operand:QF 0 "reg_operand" "=f") + (float:QF (match_operand:QI 1 "src_operand" "g"))) + (clobber (reg:CC 21))] + "" + "float\\t%1,%0" + [(set_attr "type" "unarycc")]) + +(define_insn "*floatqiqf2_set" + [(set (reg:CC 21) + (compare:CC (float:QF (match_operand:QI 1 "src_operand" "g")) + (match_operand:QF 2 "fp_zero_operand" "G"))) + (set (match_operand:QF 0 "reg_operand" "=f") + (float:QF (match_dup 1)))] + + "" + "float\\t%1,%0" + [(set_attr "type" "unarycc")]) + +; Unsigned conversions are a little tricky because we need to +; add the value for the high bit if necessary. +; +(define_expand "floatunsqiqf2" + [(set (match_dup 2) (match_dup 3)) + (parallel [(set (reg:CC 21) + (compare:CC (float:QF (match_operand:QI 1 "src_operand" "")) + (match_dup 3))) + (set (match_dup 4) + (float:QF (match_dup 1)))]) + (set (match_dup 2) + (if_then_else:QF (lt (reg:CC 21) (const_int 0)) + (mem:QF (symbol_ref:QF "*___unsfltconst")) + (match_dup 2))) + (parallel [(set (match_operand:QF 0 "reg_operand" "") + (plus:QF (match_dup 2) (match_dup 4))) + (clobber (reg:CC_NOOV 21))])] + "" + "operands[2] = gen_reg_rtx (QFmode); + operands[3] = CONST0_RTX (QFmode); + operands[4] = gen_reg_rtx (QFmode); + ") + +(define_insn "floatqihf2" + [(set (match_operand:HF 0 "reg_operand" "=h") + (float:HF (match_operand:QI 1 "src_operand" "g"))) + (clobber (reg:CC 21))] + "" + "float\\t%1,%0" + [(set_attr "type" "unarycc")]) + +; +; FIX +; +(define_insn "fixqfqi_clobber" + [(set (match_operand:QI 0 "reg_operand" "=d,c") + (fix:QI (match_operand:QF 1 "src_operand" "fmH,fmH"))) + (clobber (reg:CC 21))] + "" + "fix\\t%1,%0" + [(set_attr "type" "unarycc")]) + +(define_insn "*fixqfqi_set" + [(set (reg:CC 21) + (compare:CC (fix:QI (match_operand:QF 1 "src_operand" "fmH")) + (const_int 0))) + (set (match_operand:QI 0 "reg_operand" "=d") + (fix:QI (match_dup 1)))] + "" + "fix\\t%1,%0" + [(set_attr "type" "unarycc")]) + +; +; The C[34]x fix instruction implements a floor, not a straight trunc, +; so we have to invert the number, fix it, and reinvert it if negative +; +(define_expand "fix_truncqfqi2" + [(parallel [(set (match_dup 2) + (fix:QI (match_operand:QF 1 "src_operand" ""))) + (clobber (reg:CC 21))]) + (parallel [(set (match_dup 3) (neg:QF (match_dup 1))) + (clobber (reg:CC_NOOV 21))]) + (parallel [(set (match_dup 4) (fix:QI (match_dup 3))) + (clobber (reg:CC 21))]) + (parallel [(set (reg:CC_NOOV 21) + (compare:CC_NOOV (neg:QI (match_dup 4)) (const_int 0))) + (set (match_dup 5) (neg:QI (match_dup 4)))]) + (set (match_dup 2) + (if_then_else:QI (le (reg:CC 21) (const_int 0)) + (match_dup 5) + (match_dup 2))) + (set (match_operand:QI 0 "reg_operand" "=r") (match_dup 2))] + "" + "if (TARGET_FAST_FIX) + { + emit_insn (gen_fixqfqi_clobber (operands[0], operands[1])); + DONE; + } + operands[2] = gen_reg_rtx (QImode); + operands[3] = gen_reg_rtx (QFmode); + operands[4] = gen_reg_rtx (QImode); + operands[5] = gen_reg_rtx (QImode); + ") + +(define_expand "fix_truncqfhi2" + [(parallel [(set (match_operand:HI 0 "reg_operand" "") + (fix:HI (match_operand:QF 1 "src_operand" ""))) + (clobber (reg:CC 21))])] + "" + "c4x_emit_libcall (FIX_TRUNCQFHI2_LIBCALL, FIX, HImode, QFmode, 2, operands); + DONE;") + +(define_expand "fixuns_truncqfqi2" + [(set (match_dup 2) (match_dup 4)) + (set (reg:CC 21) + (compare:CC (match_operand:QF 1 "reg_operand" "") + (mem:QF (symbol_ref "*___unsfltcompare")))) + (set (match_dup 2) + (if_then_else:QF (ge (reg:CC 21) (const_int 0)) + (mem:QF (symbol_ref "*___unsfltconst")) + (match_dup 2))) + (parallel [(set (match_dup 3) + (minus:QF (match_dup 1) (match_dup 2))) + (clobber (reg:CC_NOOV 21))]) + (parallel [(set (match_operand:QI 0 "reg_operand" "") + (fix:QI (match_dup 3))) + (clobber (reg:CC 21))])] + "" + "operands[2] = gen_reg_rtx (QFmode); + operands[3] = gen_reg_rtx (QFmode); + operands[4] = CONST0_RTX (QFmode); + ") + +(define_expand "fixuns_truncqfhi2" + [(parallel [(set (match_operand:HI 0 "reg_operand" "") + (unsigned_fix:HI (match_operand:QF 1 "src_operand" ""))) + (clobber (reg:CC 21))])] + "" + "c4x_emit_libcall (FIXUNS_TRUNCQFHI2_LIBCALL, UNSIGNED_FIX, + HImode, QFmode, 2, operands); + DONE;") + +; +; RCPF +; +(define_insn "*rcpfqf_clobber" + [(set (match_operand:QF 0 "reg_operand" "=f") + (unspec [(match_operand:QF 1 "src_operand" "fmH")] 5)) + (clobber (reg:CC_NOOV 21))] + "! TARGET_C3X" + "rcpf\\t%1,%0" + [(set_attr "type" "unarycc")]) + +; +; RSQRF +; +(define_insn "*rsqrfqf_clobber" + [(set (match_operand:QF 0 "reg_operand" "=f") + (unspec [(match_operand:QF 1 "src_operand" "fmH")] 10)) + (clobber (reg:CC_NOOV 21))] + "! TARGET_C3X" + "rsqrf\\t%1,%0" + [(set_attr "type" "unarycc")]) + +; +; RNDF +; +(define_insn "*rndqf_clobber" + [(set (match_operand:QF 0 "reg_operand" "=f") + (unspec [(match_operand:QF 1 "src_operand" "fmH")] 6)) + (clobber (reg:CC_NOOV 21))] + "! TARGET_C3X" + "rnd\\t%1,%0" + [(set_attr "type" "unarycc")]) + + +; Inlined float square root for C4x +(define_expand "sqrtqf2_inline" + [(parallel [(set (match_dup 2) + (unspec [(match_operand:QF 1 "src_operand" "")] 10)) + (clobber (reg:CC_NOOV 21))]) + (parallel [(set (match_dup 3) (mult:QF (match_dup 5) (match_dup 1))) + (clobber (reg:CC_NOOV 21))]) + (parallel [(set (match_dup 4) (mult:QF (match_dup 2) (match_dup 3))) + (clobber (reg:CC_NOOV 21))]) + (parallel [(set (match_dup 4) (mult:QF (match_dup 2) (match_dup 4))) + (clobber (reg:CC_NOOV 21))]) + (parallel [(set (match_dup 4) (minus:QF (match_dup 6) (match_dup 4))) + (clobber (reg:CC_NOOV 21))]) + (parallel [(set (match_dup 2) (mult:QF (match_dup 2) (match_dup 4))) + (clobber (reg:CC_NOOV 21))]) + (parallel [(set (match_dup 4) (mult:QF (match_dup 2) (match_dup 3))) + (clobber (reg:CC_NOOV 21))]) + (parallel [(set (match_dup 4) (mult:QF (match_dup 2) (match_dup 4))) + (clobber (reg:CC_NOOV 21))]) + (parallel [(set (match_dup 4) (minus:QF (match_dup 6) (match_dup 4))) + (clobber (reg:CC_NOOV 21))]) + (parallel [(set (match_dup 2) (mult:QF (match_dup 2) (match_dup 4))) + (clobber (reg:CC_NOOV 21))]) + (parallel [(set (match_dup 4) (mult:QF (match_dup 2) (match_dup 1))) + (clobber (reg:CC_NOOV 21))]) + (parallel [(set (match_operand:QF 0 "reg_operand" "") + (unspec [(match_dup 4)] 6)) + (clobber (reg:CC_NOOV 21))])] + "! TARGET_C3X" + "if (! reload_in_progress + && ! reg_operand (operands[1], QFmode)) + operands[1] = force_reg (QFmode, operands[1]); + operands[2] = gen_reg_rtx (QFmode); + operands[3] = gen_reg_rtx (QFmode); + operands[4] = gen_reg_rtx (QFmode); + operands[5] = immed_real_const_1 (REAL_VALUE_ATOF (\"0.5\", QFmode), + QFmode); + operands[6] = immed_real_const_1 (REAL_VALUE_ATOF (\"1.5\", QFmode), + QFmode);") + +(define_expand "sqrtqf2" + [(parallel [(set (match_operand:QF 0 "reg_operand" "") + (sqrt:QF (match_operand:QF 1 "src_operand" ""))) + (clobber (reg:CC 21))])] + "" + "if (TARGET_C3X || ! TARGET_INLINE) + FAIL; + else + { + emit_insn (gen_sqrtqf2_inline (operands[0], operands[1])); + DONE; + } + ") + +; +; THREE OPERAND FLOAT INSTRUCTIONS +; + +; +; ADDF +; +(define_expand "addqf3" + [(parallel [(set (match_operand:QF 0 "reg_operand" "") + (plus:QF (match_operand:QF 1 "src_operand" "") + (match_operand:QF 2 "src_operand" ""))) + (clobber (reg:CC_NOOV 21))])] + "" + "legitimize_operands (PLUS, operands, QFmode);") + +(define_insn "*addqf3_clobber" + [(set (match_operand:QF 0 "reg_operand" "=f,?f,f") + (plus:QF (match_operand:QF 1 "src_operand" "%fR,fS<>,0") + (match_operand:QF 2 "src_operand" "R,fS<>,fmH"))) + (clobber (reg:CC_NOOV 21))] + "valid_operands (PLUS, operands, QFmode)" + "@ + addf3\\t%2,%1,%0 + addf3\\t%2,%1,%0 + addf\\t%2,%0" + [(set_attr "type" "binarycc,binarycc,binarycc")]) + +(define_insn "*addqf3_test" + [(set (reg:CC_NOOV 21) + (compare:CC_NOOV (plus:QF (match_operand:QF 1 "src_operand" "%fR,fS<>,0") + (match_operand:QF 2 "src_operand" "R,fS<>,fmH")) + (match_operand:QF 3 "fp_zero_operand" "G,G,G"))) + (clobber (match_scratch:QF 0 "=f,?f,f"))] + "valid_operands (PLUS, operands, QFmode)" + "@ + addf3\\t%2,%1,%0 + addf3\\t%2,%1,%0 + addf\\t%2,%0" + [(set_attr "type" "binarycc,binarycc,binarycc")]) + +(define_insn "*addqf3_set" + [(set (reg:CC_NOOV 21) + (compare:CC_NOOV (plus:QF (match_operand:QF 1 "src_operand" "%fR,fS<>,0") + (match_operand:QF 2 "src_operand" "R,fS<>,fmH")) + (match_operand:QF 3 "fp_zero_operand" "G,G,G"))) + (set (match_operand:QF 0 "reg_operand" "=f,?f,f") + (plus:QF (match_dup 1) + (match_dup 2)))] + "valid_operands (PLUS, operands, QFmode)" + "@ + addf3\\t%2,%1,%0 + addf3\\t%2,%1,%0 + addf\\t%2,%0" + [(set_attr "type" "binarycc,binarycc,binarycc")]) + +; +; SUBF/SUBRF +; +(define_expand "subqf3" + [(parallel [(set (match_operand:QF 0 "reg_operand" "") + (minus:QF (match_operand:QF 1 "src_operand" "") + (match_operand:QF 2 "src_operand" ""))) + (clobber (reg:CC_NOOV 21))])] + "" + "legitimize_operands (MINUS, operands, QFmode);") + +(define_insn "*subqf3_clobber" + [(set (match_operand:QF 0 "reg_operand" "=f,?f,f,f") + (minus:QF (match_operand:QF 1 "src_operand" "fR,fS<>,0,fmH") + (match_operand:QF 2 "src_operand" "R,fS<>,fmH,0"))) + (clobber (reg:CC_NOOV 21))] + "valid_operands (MINUS, operands, QFmode)" + "@ + subf3\\t%2,%1,%0 + subf3\\t%2,%1,%0 + subf\\t%2,%0 + subrf\\t%1,%0" + [(set_attr "type" "binarycc,binarycc,binarycc,binarycc")]) + +(define_insn "*subqf3_test" + [(set (reg:CC_NOOV 21) + (compare:CC_NOOV (minus:QF (match_operand:QF 1 "src_operand" "fR,fS<>,0,fmH") + (match_operand:QF 2 "src_operand" "R,fS<>,fmH,0")) + (match_operand:QF 3 "fp_zero_operand" "G,G,G,G"))) + (clobber (match_scratch:QF 0 "=f,?f,f,f"))] + "valid_operands (MINUS, operands, QFmode)" + "@ + subf3\\t%2,%1,%0 + subf3\\t%2,%1,%0 + subf\\t%2,%0 + subrf\\t%1,%0" + [(set_attr "type" "binarycc,binarycc,binarycc,binarycc")]) + +(define_insn "*subqf3_set" + [(set (reg:CC_NOOV 21) + (compare:CC_NOOV (minus:QF (match_operand:QF 1 "src_operand" "fR,fS<>,0,fmH") + (match_operand:QF 2 "src_operand" "R,fS<>,fmH,0")) + (match_operand:QF 3 "fp_zero_operand" "G,G,G,G"))) + (set (match_operand:QF 0 "reg_operand" "=f,?f,f,f") + (minus:QF (match_dup 1) + (match_dup 2)))] + "valid_operands (MINUS, operands, QFmode)" + "@ + subf3\\t%2,%1,%0 + subf3\\t%2,%1,%0 + subf\\t%2,%0 + subrf\\t%1,%0" + [(set_attr "type" "binarycc,binarycc,binarycc,binarycc")]) + +; +; MPYF +; +(define_expand "mulqf3" + [(parallel [(set (match_operand:QF 0 "reg_operand" "") + (mult:QF (match_operand:QF 1 "src_operand" "") + (match_operand:QF 2 "src_operand" ""))) + (clobber (reg:CC_NOOV 21))])] + "" + "legitimize_operands (MULT, operands, QFmode);") + +(define_insn "*mulqf3_clobber" + [(set (match_operand:QF 0 "reg_operand" "=f,?f,f") + (mult:QF (match_operand:QF 1 "src_operand" "%fR,fS<>,0") + (match_operand:QF 2 "src_operand" "R,fS<>,fmH"))) + (clobber (reg:CC_NOOV 21))] + "valid_operands (MULT, operands, QFmode)" + "@ + mpyf3\\t%2,%1,%0 + mpyf3\\t%2,%1,%0 + mpyf\\t%2,%0" + [(set_attr "type" "binarycc,binarycc,binarycc")]) + +(define_insn "*mulqf3_test" + [(set (reg:CC_NOOV 21) + (compare:CC_NOOV (mult:QF (match_operand:QF 1 "src_operand" "%fR,fS<>,0") + (match_operand:QF 2 "src_operand" "R,fS<>,fmH")) + (match_operand:QF 3 "fp_zero_operand" "G,G,G"))) + (clobber (match_scratch:QF 0 "=f,?f,f"))] + "valid_operands (MULT, operands, QFmode)" + "@ + mpyf3\\t%2,%1,%0 + mpyf3\\t%2,%1,%0 + mpyf\\t%2,%0" + [(set_attr "type" "binarycc,binarycc,binarycc")]) + +(define_insn "*mulqf3_set" + [(set (reg:CC_NOOV 21) + (compare:CC_NOOV (mult:QF (match_operand:QF 1 "src_operand" "%fR,fS<>,0") + (match_operand:QF 2 "src_operand" "R,fS<>,fmH")) + (match_operand:QF 3 "fp_zero_operand" "G,G,G"))) + (set (match_operand:QF 0 "reg_operand" "=f,?f,f") + (mult:QF (match_dup 1) + (match_dup 2)))] + "valid_operands (MULT, operands, QFmode)" + "@ + mpyf3\\t%2,%1,%0 + mpyf3\\t%2,%1,%0 + mpyf\\t%2,%0" + [(set_attr "type" "binarycc,binarycc,binarycc")]) + +; +; CMPF +; +(define_expand "cmpqf" + [(set (reg:CC 21) + (compare:CC (match_operand:QF 0 "src_operand" "") + (match_operand:QF 1 "src_operand" "")))] + "" + "legitimize_operands (COMPARE, operands, QFmode); + c4x_compare_op0 = operands[0]; + c4x_compare_op1 = operands[1]; + DONE;") + +(define_insn "*cmpqf" + [(set (reg:CC 21) + (compare:CC (match_operand:QF 0 "src_operand" "fR,?fS<>,f") + (match_operand:QF 1 "src_operand" "R,fS<>,fmH")))] + "valid_operands (COMPARE, operands, QFmode)" + "@ + cmpf3\\t%1,%0 + cmpf3\\t%1,%0 + cmpf\\t%1,%0" + [(set_attr "type" "compare,compare,compare")]) + +(define_insn "*cmpqf_noov" + [(set (reg:CC_NOOV 21) + (compare:CC_NOOV (match_operand:QF 0 "src_operand" "fR,?fS<>,f") + (match_operand:QF 1 "src_operand" "R,fS<>,fmH")))] + "valid_operands (COMPARE, operands, QFmode)" + "@ + cmpf3\\t%1,%0 + cmpf3\\t%1,%0 + cmpf\\t%1,%0" + [(set_attr "type" "compare,compare,compare")]) + +; Inlined float divide for C4x +(define_expand "divqf3_inline" + [(parallel [(set (match_dup 3) + (unspec [(match_operand:QF 2 "src_operand" "")] 5)) + (clobber (reg:CC_NOOV 21))]) + (parallel [(set (match_dup 4) (mult:QF (match_dup 2) (match_dup 3))) + (clobber (reg:CC_NOOV 21))]) + (parallel [(set (match_dup 4) (minus:QF (match_dup 5) (match_dup 4))) + (clobber (reg:CC_NOOV 21))]) + (parallel [(set (match_dup 3) (mult:QF (match_dup 3) (match_dup 4))) + (clobber (reg:CC_NOOV 21))]) + (parallel [(set (match_dup 4) (mult:QF (match_dup 2) (match_dup 3))) + (clobber (reg:CC_NOOV 21))]) + (parallel [(set (match_dup 4) (minus:QF (match_dup 5) (match_dup 4))) + (clobber (reg:CC_NOOV 21))]) + (parallel [(set (match_dup 3) (mult:QF (match_dup 3) (match_dup 4))) + (clobber (reg:CC_NOOV 21))]) + (parallel [(set (match_dup 3) + (mult:QF (match_operand:QF 1 "src_operand" "") + (match_dup 3))) + (clobber (reg:CC_NOOV 21))]) + (parallel [(set (match_operand:QF 0 "reg_operand" "") + (unspec [(match_dup 3)] 6)) + (clobber (reg:CC_NOOV 21))])] + "! TARGET_C3X" + "if (! reload_in_progress + && ! reg_operand (operands[2], QFmode)) + operands[2] = force_reg (QFmode, operands[2]); + operands[3] = gen_reg_rtx (QFmode); + operands[4] = gen_reg_rtx (QFmode); + operands[5] = CONST2_RTX (QFmode);") + +(define_expand "divqf3" + [(parallel [(set (match_operand:QF 0 "reg_operand" "") + (div:QF (match_operand:QF 1 "src_operand" "") + (match_operand:QF 2 "src_operand" ""))) + (clobber (reg:CC 21))])] + "" + "if (TARGET_C3X || ! TARGET_INLINE) + { + c4x_emit_libcall3 (DIVQF3_LIBCALL, DIV, QFmode, operands); + DONE; + } + else + { + emit_insn (gen_divqf3_inline (operands[0], operands[1], operands[2])); + DONE; + } + ") + +; +; CONDITIONAL MOVES +; + +(define_insn "*ldi_conditional" + [(set (match_operand:QI 0 "reg_operand" "=r,r") + (if_then_else:QI (match_operator 1 "comparison_operator" + [(reg:CC 21) (const_int 0)]) + (match_operand:QI 2 "src_operand" "g,0") + (match_operand:QI 3 "src_operand" "0,g")))] + "" + "@ + ldi%1\\t%2,%0 + ldi%I1\\t%3,%0" + [(set_attr "type" "binary")]) + +(define_insn "*ldi_conditional_noov" + [(set (match_operand:QI 0 "reg_operand" "=r,r") + (if_then_else:QI (match_operator 1 "comparison_operator" + [(reg:CC_NOOV 21) (const_int 0)]) + (match_operand:QI 2 "src_operand" "g,0") + (match_operand:QI 3 "src_operand" "0,g")))] + "GET_CODE (operands[1]) != LE + && GET_CODE (operands[1]) != GE + && GET_CODE (operands[1]) != LT + && GET_CODE (operands[1]) != GT" + "@ + ldi%1\\t%2,%0 + ldi%I1\\t%3,%0" + [(set_attr "type" "binary")]) + +; Move operand 2 to operand 0 if condition (operand 1) is true +; else move operand 3 to operand 0. +; The temporary register is required below because some of the operands +; might be identical (namely 0 and 2). +; +(define_expand "movqicc" + [(set (match_operand:QI 0 "reg_operand" "") + (if_then_else:QI (match_operand 1 "comparison_operator" "") + (match_operand:QI 2 "src_operand" "") + (match_operand:QI 3 "src_operand" "")))] + "" + "{ + enum rtx_code code = GET_CODE (operands[1]); + rtx ccreg = c4x_gen_compare_reg (code, c4x_compare_op0, c4x_compare_op1); + if (ccreg == NULL_RTX) FAIL; + emit_insn (gen_rtx_SET (QImode, operands[0], + gen_rtx_IF_THEN_ELSE (QImode, + gen_rtx (code, VOIDmode, ccreg, const0_rtx), + operands[2], operands[3]))); + DONE;}") + +(define_insn "*ldf_conditional" + [(set (match_operand:QF 0 "reg_operand" "=f,f") + (if_then_else:QF (match_operator 1 "comparison_operator" + [(reg:CC 21) (const_int 0)]) + (match_operand:QF 2 "src_operand" "fmH,0") + (match_operand:QF 3 "src_operand" "0,fmH")))] + "" + "@ + ldf%1\\t%2,%0 + ldf%I1\\t%3,%0" + [(set_attr "type" "binary")]) + +(define_insn "*ldf_conditional_noov" + [(set (match_operand:QF 0 "reg_operand" "=f,f") + (if_then_else:QF (match_operator 1 "comparison_operator" + [(reg:CC_NOOV 21) (const_int 0)]) + (match_operand:QF 2 "src_operand" "fmH,0") + (match_operand:QF 3 "src_operand" "0,fmH")))] + "GET_CODE (operands[1]) != LE + && GET_CODE (operands[1]) != GE + && GET_CODE (operands[1]) != LT + && GET_CODE (operands[1]) != GT" + "@ + ldf%1\\t%2,%0 + ldf%I1\\t%3,%0" + [(set_attr "type" "binary")]) + +(define_expand "movqfcc" + [(set (match_operand:QF 0 "reg_operand" "") + (if_then_else:QF (match_operand 1 "comparison_operator" "") + (match_operand:QF 2 "src_operand" "") + (match_operand:QF 3 "src_operand" "")))] + "" + "{ + enum rtx_code code = GET_CODE (operands[1]); + rtx ccreg = c4x_gen_compare_reg (code, c4x_compare_op0, c4x_compare_op1); + if (ccreg == NULL_RTX) FAIL; + emit_insn (gen_rtx_SET (QFmode, operands[0], + gen_rtx_IF_THEN_ELSE (QFmode, + gen_rtx (code, VOIDmode, ccreg, const0_rtx), + operands[2], operands[3]))); + DONE;}") + +(define_expand "seq" + [(set (match_operand:QI 0 "reg_operand" "") + (const_int 0)) + (set (match_dup 0) + (if_then_else:QI (eq (match_dup 1) (const_int 0)) + (const_int 1) + (match_dup 0)))] + "" + "operands[1] = c4x_gen_compare_reg (EQ, c4x_compare_op0, c4x_compare_op1);") + +(define_expand "sne" + [(set (match_operand:QI 0 "reg_operand" "") + (const_int 0)) + (set (match_dup 0) + (if_then_else:QI (ne (match_dup 1) (const_int 0)) + (const_int 1) + (match_dup 0)))] + "" + "operands[1] = c4x_gen_compare_reg (NE, c4x_compare_op0, c4x_compare_op1);") + +(define_expand "slt" + [(set (match_operand:QI 0 "reg_operand" "") + (const_int 0)) + (set (match_dup 0) + (if_then_else:QI (lt (match_dup 1) (const_int 0)) + (const_int 1) + (match_dup 0)))] + "" + "operands[1] = c4x_gen_compare_reg (LT, c4x_compare_op0, c4x_compare_op1); + if (operands[1] == NULL_RTX) FAIL;") + +(define_expand "sltu" + [(set (match_operand:QI 0 "reg_operand" "") + (const_int 0)) + (set (match_dup 0) + (if_then_else:QI (ltu (match_dup 1) (const_int 0)) + (const_int 1) + (match_dup 0)))] + "" + "operands[1] = c4x_gen_compare_reg (LTU, c4x_compare_op0, c4x_compare_op1);") + +(define_expand "sgt" + [(set (match_operand:QI 0 "reg_operand" "") + (const_int 0)) + (set (match_dup 0) + (if_then_else:QI (gt (match_dup 1) (const_int 0)) + (const_int 1) + (match_dup 0)))] + "" + "operands[1] = c4x_gen_compare_reg (GT, c4x_compare_op0, c4x_compare_op1); + if (operands[1] == NULL_RTX) FAIL;") + +(define_expand "sgtu" + [(set (match_operand:QI 0 "reg_operand" "") + (const_int 0)) + (set (match_dup 0) + (if_then_else:QI (gtu (match_dup 1) (const_int 0)) + (const_int 1) + (match_dup 0)))] + "" + "operands[1] = c4x_gen_compare_reg (GTU, c4x_compare_op0, c4x_compare_op1);") + +(define_expand "sle" + [(set (match_operand:QI 0 "reg_operand" "") + (const_int 0)) + (set (match_dup 0) + (if_then_else:QI (le (match_dup 1) (const_int 0)) + (const_int 1) + (match_dup 0)))] + "" + "operands[1] = c4x_gen_compare_reg (LE, c4x_compare_op0, c4x_compare_op1); + if (operands[1] == NULL_RTX) FAIL;") + +(define_expand "sleu" + [(set (match_operand:QI 0 "reg_operand" "") + (const_int 0)) + (set (match_dup 0) + (if_then_else:QI (leu (match_dup 1) (const_int 0)) + (const_int 1) + (match_dup 0)))] + "" + "operands[1] = c4x_gen_compare_reg (LEU, c4x_compare_op0, c4x_compare_op1);") + +(define_expand "sge" + [(set (match_operand:QI 0 "reg_operand" "") + (const_int 0)) + (set (match_dup 0) + (if_then_else:QI (ge (match_dup 1) (const_int 0)) + (const_int 1) + (match_dup 0)))] + "" + "operands[1] = c4x_gen_compare_reg (GE, c4x_compare_op0, c4x_compare_op1); + if (operands[1] == NULL_RTX) FAIL;") + +(define_expand "sgeu" + [(set (match_operand:QI 0 "reg_operand" "") + (const_int 0)) + (set (match_dup 0) + (if_then_else:QI (geu (match_dup 1) (const_int 0)) + (const_int 1) + (match_dup 0)))] + "" + "operands[1] = c4x_gen_compare_reg (GEU, c4x_compare_op0, c4x_compare_op1);") + +(define_split + [(set (match_operand:QI 0 "reg_operand" "") + (match_operator 1 "comparison_operator" [(reg:CC 21) (const_int 0)]))] + "reload_completed" + [(set (match_dup 0) (const_int 0)) + (set (match_dup 0) + (if_then_else:QI (match_op_dup 1 [(reg:CC 21) (const_int 0)]) + (const_int 1) + (match_dup 0)))] + "") + +(define_split + [(set (match_operand:QI 0 "reg_operand" "") + (match_operator 1 "comparison_operator" [(reg:CC_NOOV 21) (const_int 0)]))] + "reload_completed" + [(set (match_dup 0) (const_int 0)) + (set (match_dup 0) + (if_then_else:QI (match_op_dup 1 [(reg:CC_NOOV 21) (const_int 0)]) + (const_int 1) + (match_dup 0)))] + "") + +(define_insn "*bu" + [(set (pc) + (unspec [(match_operand:QI 0 "reg_operand" "r")] 1))] + "" + "bu%#\\t%0" + [(set_attr "type" "jump")]) + +(define_expand "caseqi" + [(parallel [(set (match_dup 5) + (minus:QI (match_operand:QI 0 "reg_operand" "") + (match_operand:QI 1 "src_operand" ""))) + (clobber (reg:CC_NOOV 21))]) + (set (reg:CC 21) + (compare:CC (match_dup 5) + (match_operand:QI 2 "src_operand" ""))) + (set (pc) + (if_then_else (gtu (reg:CC 21) + (const_int 0)) + (label_ref (match_operand 4 "" "")) + (pc))) + (parallel [(set (match_dup 6) + (plus:QI (match_dup 5) + (label_ref:QI (match_operand 3 "" "")))) + (clobber (reg:CC_NOOV 21))]) + (set (match_dup 7) + (mem:QI (match_dup 6))) + (set (pc) (match_dup 7))] + "" + "operands[5] = gen_reg_rtx (QImode); + operands[6] = gen_reg_rtx (QImode); + operands[7] = gen_reg_rtx (QImode);") + +; +; PARALLEL FLOAT INSTRUCTIONS +; +; This patterns are under development + +; +; ABSF/STF +; + +(define_insn "*absqf2_movqf_clobber" + [(set (match_operand:QF 0 "ext_low_reg_operand" "=q") + (abs:QF (match_operand:QF 1 "par_ind_operand" "S<>"))) + (set (match_operand:QF 2 "par_ind_operand" "=S<>") + (match_operand:QF 3 "ext_low_reg_operand" "q")) + (clobber (reg:CC_NOOV 21))] + "TARGET_PARALLEL && valid_parallel_operands_4 (operands, QFmode)" + "absf\\t%1,%0\\n||\\tstf\\t%3,%2" + [(set_attr "type" "binarycc")]) + +; +; ADDF/STF +; + +(define_insn "*addqf3_movqf_clobber" + [(set (match_operand:QF 0 "ext_low_reg_operand" "=q") + (plus:QF (match_operand:QF 1 "parallel_operand" "%q") + (match_operand:QF 2 "parallel_operand" "S<>"))) + (set (match_operand:QF 3 "par_ind_operand" "=S<>") + (match_operand:QF 4 "ext_low_reg_operand" "q")) + (clobber (reg:CC 21))] + "TARGET_PARALLEL && valid_parallel_operands_5 (operands, QFmode)" + "addf3\\t%2,%1,%0\\n||\\tstf\\t%4,%3" + [(set_attr "type" "binarycc")]) + +; +; FLOAT/STF +; + +(define_insn "*floatqiqf2_movqf_clobber" + [(set (match_operand:QF 0 "ext_low_reg_operand" "=q") + (float:QF (match_operand:QI 1 "par_ind_operand" "S<>"))) + (set (match_operand:QF 2 "par_ind_operand" "=S<>") + (match_operand:QF 3 "ext_low_reg_operand" "q")) + (clobber (reg:CC 21))] + "TARGET_PARALLEL && valid_parallel_operands_4 (operands, QFmode)" + "float\\t%1,%0\\n||\\tstf\\t%3,%2" + [(set_attr "type" "binarycc")]) + +; +; MPYF/ADDF +; + +(define_insn "*mulqf3_addqf3_clobber" + [(set (match_operand:QF 0 "r0r1_reg_operand" "=t") + (mult:QF (match_operand:QF 1 "parallel_operand" "%S<>q") + (match_operand:QF 2 "parallel_operand" "S<>q"))) + (set (match_operand:QF 3 "r2r3_reg_operand" "=u") + (plus:QF (match_operand:QF 4 "parallel_operand" "%S<>q") + (match_operand:QF 5 "parallel_operand" "S<>q"))) + (clobber (reg:CC 21))] + "TARGET_PARALLEL_MPY && valid_parallel_operands_6 (operands, QFmode)" + "mpyf3\\t%2,%1,%0\\n||\\taddf3\\t%5,%4,%3" + [(set_attr "type" "binarycc")]) + + +; +; MPYF/STF +; + +(define_insn "*mulqf3_movqf_clobber" + [(set (match_operand:QF 0 "ext_low_reg_operand" "=q") + (mult:QF (match_operand:QF 1 "parallel_operand" "%q") + (match_operand:QF 2 "parallel_operand" "S<>"))) + (set (match_operand:QF 3 "par_ind_operand" "=S<>") + (match_operand:QF 4 "ext_low_reg_operand" "q")) + (clobber (reg:CC 21))] + "TARGET_PARALLEL && valid_parallel_operands_5 (operands, QFmode)" + "mpyf3\\t%2,%1,%0\\n||\\tstf\\t%4,%3" + [(set_attr "type" "binarycc")]) + +; +; MPYF/SUBF +; + +(define_insn "*mulqf3_subqf3_clobber" + [(set (match_operand:QF 0 "r0r1_reg_operand" "=t") + (mult:QF (match_operand:QF 1 "parallel_operand" "S<>q") + (match_operand:QF 2 "parallel_operand" "S<>q"))) + (set (match_operand:QF 3 "r2r3_reg_operand" "=u") + (minus:QF (match_operand:QF 4 "parallel_operand" "S<>q") + (match_operand:QF 5 "parallel_operand" "S<>q"))) + (clobber (reg:CC 21))] + "TARGET_PARALLEL_MPY && valid_parallel_operands_6 (operands, QFmode)" + "mpyf3\\t%2,%1,%0\\n||\\tsubf3\\t%5,%4,%3" + [(set_attr "type" "binarycc")]) + +; +; NEGF/STF +; + +(define_insn "*negqf2_movqf_clobber" + [(set (match_operand:QF 0 "ext_low_reg_operand" "=q") + (neg:QF (match_operand:QF 1 "par_ind_operand" "S<>"))) + (set (match_operand:QF 2 "par_ind_operand" "=S<>") + (match_operand:QF 3 "ext_low_reg_operand" "q")) + (clobber (reg:CC 21))] + "TARGET_PARALLEL && valid_parallel_operands_4 (operands, QFmode)" + "negf\\t%1,%0\\n||\\tstf\\t%3,%2" + [(set_attr "type" "binarycc")]) + +; +; SUBF/STF +; + +(define_insn "*subqf3_movqf_clobber" + [(set (match_operand:QF 0 "ext_low_reg_operand" "=q") + (minus:QF (match_operand:QF 1 "ext_low_reg_operand" "q") + (match_operand:QF 2 "par_ind_operand" "S<>"))) + (set (match_operand:QF 3 "par_ind_operand" "=S<>") + (match_operand:QF 4 "ext_low_reg_operand" "q")) + (clobber (reg:CC 21))] + "TARGET_PARALLEL && valid_parallel_operands_5 (operands, QFmode)" + "subf3\\t%2,%1,%0\\n||\\tstf\\t%4,%3" + [(set_attr "type" "binarycc")]) + +; +; PARALLEL INTEGER INSTRUCTIONS +; +; These patterns are under development + +; +; ABSI/STI +; + +(define_insn "*absqi2_movqi_clobber" + [(set (match_operand:QI 0 "ext_low_reg_operand" "=q") + (abs:QI (match_operand:QI 1 "par_ind_operand" "S<>"))) + (set (match_operand:QI 2 "par_ind_operand" "=S<>") + (match_operand:QI 3 "ext_low_reg_operand" "q")) + (clobber (reg:CC_NOOV 21))] + "TARGET_PARALLEL && valid_parallel_operands_4 (operands, QImode)" + "absi\\t%1,%0\\n||\\tsti\\t%3,%2" + [(set_attr "type" "binarycc")]) + +; +; ADDI/STI +; + +(define_insn "*addqi3_movqi_clobber" + [(set (match_operand:QI 0 "ext_low_reg_operand" "=q") + (plus:QI (match_operand:QI 1 "parallel_operand" "%q") + (match_operand:QI 2 "parallel_operand" "S<>"))) + (set (match_operand:QI 3 "par_ind_operand" "=S<>") + (match_operand:QI 4 "ext_low_reg_operand" "q")) + (clobber (reg:CC 21))] + "TARGET_PARALLEL && valid_parallel_operands_5 (operands, QImode)" + "addi3\\t%2,%1,%0\\n||\\tsti\\t%4,%3" + [(set_attr "type" "binarycc")]) + +; +; AND/STI +; + +(define_insn "*andqi3_movqi_clobber" + [(set (match_operand:QI 0 "ext_low_reg_operand" "=q") + (and:QI (match_operand:QI 1 "parallel_operand" "%q") + (match_operand:QI 2 "parallel_operand" "S<>"))) + (set (match_operand:QI 3 "par_ind_operand" "=S<>") + (match_operand:QI 4 "ext_low_reg_operand" "q")) + (clobber (reg:CC 21))] + "TARGET_PARALLEL && valid_parallel_operands_5 (operands, QImode)" + "and3\\t%2,%1,%0\\n||\\tsti\\t%4,%3" + [(set_attr "type" "binarycc")]) + +; +; ASH(left)/STI +; + +(define_insn "*ashlqi3_movqi_clobber" + [(set (match_operand:QI 0 "ext_low_reg_operand" "=q") + (ashift:QI (match_operand:QI 1 "par_ind_operand" "S<>") + (match_operand:QI 2 "ext_low_reg_operand" "q"))) + (set (match_operand:QI 3 "par_ind_operand" "=S<>") + (match_operand:QI 4 "ext_low_reg_operand" "q")) + (clobber (reg:CC 21))] + "TARGET_PARALLEL && valid_parallel_operands_5 (operands, QImode)" + "ash3\\t%2,%1,%0\\n||\\tsti\\t%4,%3" + [(set_attr "type" "binarycc")]) + +; +; ASH(right)/STI +; + +(define_insn "*ashrqi3_movqi_clobber" + [(set (match_operand:QI 0 "ext_low_reg_operand" "=q") + (ashiftrt:QI (match_operand:QI 1 "par_ind_operand" "S<>") + (neg:QI (match_operand:QI 2 "ext_low_reg_operand" "q")))) + (set (match_operand:QI 3 "par_ind_operand" "=S<>") + (match_operand:QI 4 "ext_low_reg_operand" "q")) + (clobber (reg:CC 21))] + "TARGET_PARALLEL && valid_parallel_operands_5 (operands, QImode)" + "ash3\\t%2,%1,%0\\n||\\tsti\\t%4,%3" + [(set_attr "type" "binarycc")]) + +; +; FIX/STI +; + +(define_insn "*fixqfqi2_movqi_clobber" + [(set (match_operand:QI 0 "ext_low_reg_operand" "=q") + (fix:QI (match_operand:QF 1 "par_ind_operand" "S<>"))) + (set (match_operand:QI 2 "par_ind_operand" "=S<>") + (match_operand:QI 3 "ext_low_reg_operand" "q")) + (clobber (reg:CC 21))] + "TARGET_PARALLEL && valid_parallel_operands_4 (operands, QImode)" + "fix\\t%1,%0\\n||\\tsti\\t%3,%2" + [(set_attr "type" "binarycc")]) + +; +; LSH(right)/STI +; + +(define_insn "*lshrqi3_movqi_clobber" + [(set (match_operand:QI 0 "ext_low_reg_operand" "=q") + (lshiftrt:QI (match_operand:QI 1 "par_ind_operand" "S<>") + (neg:QI (match_operand:QI 2 "ext_low_reg_operand" "q")))) + (set (match_operand:QI 3 "par_ind_operand" "=S<>") + (match_operand:QI 4 "ext_low_reg_operand" "q")) + (clobber (reg:CC 21))] + "TARGET_PARALLEL && valid_parallel_operands_5 (operands, QImode)" + "lsh3\\t%2,%1,%0\\n||\\tsti\\t%4,%3" + [(set_attr "type" "binarycc")]) + +; +; MPYI/ADDI +; + +(define_insn "*mulqi3_addqi3_clobber" + [(set (match_operand:QI 0 "r0r1_reg_operand" "=t") + (mult:QI (match_operand:QI 1 "parallel_operand" "S<>q") + (match_operand:QI 2 "parallel_operand" "S<>q"))) + (set (match_operand:QI 3 "r2r3_reg_operand" "=u") + (plus:QI (match_operand:QI 4 "parallel_operand" "S<>q") + (match_operand:QI 5 "parallel_operand" "S<>q"))) + (clobber (reg:CC 21))] + "TARGET_PARALLEL_MPY && TARGET_MPYI + && valid_parallel_operands_6 (operands, QImode)" + "mpyi3\\t%2,%1,%0\\n||\\taddi3\\t%5,%4,%3" + [(set_attr "type" "binarycc")]) + +; +; MPYI/STI +; + +(define_insn "*mulqi3_movqi_clobber" + [(set (match_operand:QI 0 "ext_low_reg_operand" "=q") + (mult:QI (match_operand:QI 1 "parallel_operand" "%q") + (match_operand:QI 2 "parallel_operand" "S<>"))) + (set (match_operand:QI 3 "par_ind_operand" "=S<>") + (match_operand:QI 4 "ext_low_reg_operand" "q")) + (clobber (reg:CC 21))] + "TARGET_PARALLEL && TARGET_MPYI + && valid_parallel_operands_5 (operands, QImode)" + "mpyi3\\t%2,%1,%0\\n||\\tsti\\t%4,%3" + [(set_attr "type" "binarycc")]) + +; +; MPYI/SUBI +; + +(define_insn "*mulqi3_subqi3_clobber" + [(set (match_operand:QI 0 "r0r1_reg_operand" "=t") + (mult:QI (match_operand:QI 1 "parallel_operand" "S<>q") + (match_operand:QI 2 "parallel_operand" "S<>q"))) + (set (match_operand:QI 3 "r2r3_reg_operand" "=u") + (minus:QI (match_operand:QI 4 "parallel_operand" "S<>q") + (match_operand:QI 5 "parallel_operand" "S<>q"))) + (clobber (reg:CC 21))] + "TARGET_PARALLEL_MPY && TARGET_MPYI + && valid_parallel_operands_6 (operands, QImode)" + "mpyi3\\t%2,%1,%0\\n||\\tsubi3\\t%5,%4,%3" + [(set_attr "type" "binarycc")]) + +; +; NEGI/STI +; + +(define_insn "*negqi2_movqi_clobber" + [(set (match_operand:QI 0 "ext_low_reg_operand" "=q") + (neg:QI (match_operand:QI 1 "par_ind_operand" "S<>"))) + (set (match_operand:QI 2 "par_ind_operand" "=S<>") + (match_operand:QI 3 "ext_low_reg_operand" "q")) + (clobber (reg:CC 21))] + "TARGET_PARALLEL && valid_parallel_operands_4 (operands, QImode)" + "negi\\t%1,%0\\n||\\tsti\\t%3,%2" + [(set_attr "type" "binarycc")]) + +; +; NOT/STI +; + +(define_insn "*notqi2_movqi_clobber" + [(set (match_operand:QI 0 "ext_low_reg_operand" "=q") + (not:QI (match_operand:QI 1 "par_ind_operand" "S<>"))) + (set (match_operand:QI 2 "par_ind_operand" "=S<>") + (match_operand:QI 3 "ext_low_reg_operand" "q")) + (clobber (reg:CC 21))] + "TARGET_PARALLEL && valid_parallel_operands_4 (operands, QImode)" + "not\\t%1,%0\\n||\\tsti\\t%3,%2" + [(set_attr "type" "binarycc")]) + +; +; OR/STI +; + +(define_insn "*iorqi3_movqi_clobber" + [(set (match_operand:QI 0 "ext_low_reg_operand" "=q") + (ior:QI (match_operand:QI 1 "parallel_operand" "%q") + (match_operand:QI 2 "parallel_operand" "S<>"))) + (set (match_operand:QI 3 "par_ind_operand" "=S<>") + (match_operand:QI 4 "ext_low_reg_operand" "q")) + (clobber (reg:CC 21))] + "TARGET_PARALLEL && valid_parallel_operands_5 (operands, QImode)" + "or3\\t%2,%1,%0\\n||\\tsti\\t%4,%3" + [(set_attr "type" "binarycc")]) + +; +; SUBI/STI +; + +(define_insn "*subqi3_movqi_clobber" + [(set (match_operand:QI 0 "ext_low_reg_operand" "=q") + (minus:QI (match_operand:QI 1 "ext_low_reg_operand" "q") + (match_operand:QI 2 "par_ind_operand" "S<>"))) + (set (match_operand:QI 3 "par_ind_operand" "=S<>") + (match_operand:QI 4 "ext_low_reg_operand" "q")) + (clobber (reg:CC 21))] + "TARGET_PARALLEL && valid_parallel_operands_5 (operands, QImode)" + "subi3\\t%2,%1,%0\\n||\\tsti\\t%4,%3" + [(set_attr "type" "binarycc")]) + +; +; XOR/STI +; + +(define_insn "*xorqi3_movqi_clobber" + [(set (match_operand:QI 0 "ext_low_reg_operand" "=q") + (xor:QI (match_operand:QI 1 "parallel_operand" "%q") + (match_operand:QI 2 "parallel_operand" "S<>"))) + (set (match_operand:QI 3 "par_ind_operand" "=S<>") + (match_operand:QI 4 "ext_low_reg_operand" "q")) + (clobber (reg:CC 21))] + "TARGET_PARALLEL && valid_parallel_operands_5 (operands, QImode)" + "xor3\\t%2,%1,%0\\n||\\tsti\\t%4,%3" + [(set_attr "type" "binarycc")]) + +; +; BRANCH/CALL INSTRUCTIONS +; + +; +; Branch instructions +; +(define_insn "*b" + [(set (pc) (if_then_else (match_operator 0 "comparison_operator" + [(reg:CC 21) (const_int 0)]) + (label_ref (match_operand 1 "" "")) + (pc)))] + "" + "* + return c4x_output_cbranch (\"b%0\", insn);" + [(set_attr "type" "jmpc")]) + +(define_insn "*b_rev" + [(set (pc) (if_then_else (match_operator 0 "comparison_operator" + [(reg:CC 21) (const_int 0)]) + (pc) + (label_ref (match_operand 1 "" ""))))] + "" + "* + return c4x_output_cbranch (\"b%I0\", insn);" + [(set_attr "type" "jmpc")]) + +(define_insn "*b_noov" + [(set (pc) (if_then_else (match_operator 0 "comparison_operator" + [(reg:CC_NOOV 21) (const_int 0)]) + (label_ref (match_operand 1 "" "")) + (pc)))] + "GET_CODE (operands[0]) != LE + && GET_CODE (operands[0]) != GE + && GET_CODE (operands[0]) != LT + && GET_CODE (operands[0]) != GT" + "* + return c4x_output_cbranch (\"b%0\", insn);" + [(set_attr "type" "jmpc")]) + +(define_insn "*b_noov_rev" + [(set (pc) (if_then_else (match_operator 0 "comparison_operator" + [(reg:CC_NOOV 21) (const_int 0)]) + (pc) + (label_ref (match_operand 1 "" ""))))] + "GET_CODE (operands[0]) != LE + && GET_CODE (operands[0]) != GE + && GET_CODE (operands[0]) != LT + && GET_CODE (operands[0]) != GT" + "* + return c4x_output_cbranch (\"b%I0\", insn);" + [(set_attr "type" "jmpc")]) + +(define_expand "beq" + [(set (pc) (if_then_else (eq (match_dup 1) (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "operands[1] = c4x_gen_compare_reg (EQ, c4x_compare_op0, c4x_compare_op1);") + +(define_expand "bne" + [(set (pc) (if_then_else (ne (match_dup 1) (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "operands[1] = c4x_gen_compare_reg (NE, c4x_compare_op0, c4x_compare_op1);") + +(define_expand "blt" + [(set (pc) (if_then_else (lt (match_dup 1) (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "operands[1] = c4x_gen_compare_reg (LT, c4x_compare_op0, c4x_compare_op1); + if (operands[1] == NULL_RTX) FAIL;") + +(define_expand "bltu" + [(set (pc) (if_then_else (ltu (match_dup 1) (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "operands[1] = c4x_gen_compare_reg (LTU, c4x_compare_op0, c4x_compare_op1);") + +(define_expand "bgt" + [(set (pc) (if_then_else (gt (match_dup 1) (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "operands[1] = c4x_gen_compare_reg (GT, c4x_compare_op0, c4x_compare_op1); + if (operands[1] == NULL_RTX) FAIL;") + +(define_expand "bgtu" + [(set (pc) (if_then_else (gtu (match_dup 1) (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "operands[1] = c4x_gen_compare_reg (GTU, c4x_compare_op0, c4x_compare_op1);") + +(define_expand "ble" + [(set (pc) (if_then_else (le (match_dup 1) (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "operands[1] = c4x_gen_compare_reg (LE, c4x_compare_op0, c4x_compare_op1); + if (operands[1] == NULL_RTX) FAIL;") + +(define_expand "bleu" + [(set (pc) (if_then_else (leu (match_dup 1) (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "operands[1] = c4x_gen_compare_reg (LEU, c4x_compare_op0, c4x_compare_op1);") + +(define_expand "bge" + [(set (pc) (if_then_else (ge (match_dup 1) (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "operands[1] = c4x_gen_compare_reg (GE, c4x_compare_op0, c4x_compare_op1); + if (operands[1] == NULL_RTX) FAIL;") + +(define_expand "bgeu" + [(set (pc) (if_then_else (geu (match_dup 1) (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "operands[1] = c4x_gen_compare_reg (GEU, c4x_compare_op0, c4x_compare_op1);") + +(define_insn "*b_reg" + [(set (pc) (match_operand:QI 0 "reg_operand" "r"))] + "" + "bu%#\\t%0" + [(set_attr "type" "jump")]) + +(define_expand "indirect_jump" + [(set (pc) (match_operand:QI 0 "reg_operand" ""))] + "" + "") + +(define_insn "tablejump" + [(set (pc) (match_operand:QI 0 "src_operand" "r")) + (use (label_ref (match_operand 1 "" "")))] + "" + "bu%#\\t%0" + [(set_attr "type" "jump")]) + +; +; CALL +; +(define_insn "*call_c3x" + [(call (match_operand:QI 0 "call_operand" "T,!o") + (match_operand:QI 1 "general_operand" "")) + (clobber (reg:QI 31))] + ;; Operand 1 not really used on the C4x. The C30 doesn't have reg 31. + + "TARGET_C3X" + "@ + call\\t%C0 + callu\\t%R0" + [(set_attr "type" "call,call")]) + +; LAJ requires R11 (31) for the return address +(define_insn "*laj" + [(call (match_operand:QI 0 "call_operand" "T,!o") + (match_operand:QI 1 "general_operand" "")) + (clobber (reg:QI 31))] + ;; Operand 1 not really used on the C4x. + + "! TARGET_C3X" + "* + if (which_alternative == 0) + { + if (final_sequence) + return \"laj\\t%C0\"; + else + return \"call\\t%C0\"; + } + else + { + if (final_sequence) + return \"laju\\t%R0\"; + else + return \"callu\\t%R0\"; + }" + [(set_attr "type" "laj,laj")]) + +(define_expand "call" + [(parallel [(call (match_operand:QI 0 "call_operand" "") + (match_operand:QI 1 "general_operand" "")) + (clobber (reg:QI 31))])] + "" + "") + +(define_insn "*callv_c3x" + [(set (match_operand 0 "" "=r,r") + (call (match_operand:QI 1 "call_operand" "T,!o") + (match_operand:QI 2 "general_operand" ""))) + (clobber (reg:QI 31))] + ;; Operand 0 and 2 not really used for the C4x. + ;; The C30 doesn't have reg 31. + + "TARGET_C3X" + "@ + call\\t%C1 + callu\\t%R1" + [(set_attr "type" "call,call")]) + +; LAJ requires R11 (31) for the return address +(define_insn "*lajv" + [(set (match_operand 0 "" "=r,r") + (call (match_operand:QI 1 "call_operand" "T,!o") + (match_operand:QI 2 "general_operand" ""))) + (clobber (reg:QI 31))] + ;; Operand 0 and 2 not really used in the C30 instruction. + + "! TARGET_C3X" + "* + if (which_alternative == 0) + { + if (final_sequence) + return \"laj\\t%C1\"; + else + return \"call\\t%C1\"; + } + else + { + if (final_sequence) + return \"laju\\t%R1\"; + else + return \"callu\\t%R1\"; + }" + [(set_attr "type" "laj,laj")]) + +(define_expand "call_value" + [(parallel [(set (match_operand 0 "" "") + (call (match_operand:QI 1 "call_operand" "") + (match_operand:QI 2 "general_operand" ""))) + (clobber (reg:QI 31))])] + "" + "") + +(define_insn "return" + [(return)] + "c4x_null_epilogue_p ()" + "rets" + [(set_attr "type" "rets")]) + +(define_insn "*return_cc" + [(set (pc) + (if_then_else (match_operator 0 "comparison_operator" + [(reg:CC 21) (const_int 0)]) + (return) + (pc)))] + "c4x_null_epilogue_p ()" + "rets%0" + [(set_attr "type" "rets")]) + +(define_insn "*return_cc_noov" + [(set (pc) + (if_then_else (match_operator 0 "comparison_operator" + [(reg:CC_NOOV 21) (const_int 0)]) + (return) + (pc)))] + "GET_CODE (operands[0]) != LE + && GET_CODE (operands[0]) != GE + && GET_CODE (operands[0]) != LT + && GET_CODE (operands[0]) != GT + && c4x_null_epilogue_p ()" + "rets%0" + [(set_attr "type" "rets")]) + +(define_insn "*return_cc_inverse" + [(set (pc) + (if_then_else (match_operator 0 "comparison_operator" + [(reg:CC 21) (const_int 0)]) + (pc) + (return)))] + "c4x_null_epilogue_p ()" + "rets%I0" + [(set_attr "type" "rets")]) + +(define_insn "*return_cc_noov_inverse" + [(set (pc) + (if_then_else (match_operator 0 "comparison_operator" + [(reg:CC_NOOV 21) (const_int 0)]) + (pc) + (return)))] + "GET_CODE (operands[0]) != LE + && GET_CODE (operands[0]) != GE + && GET_CODE (operands[0]) != LT + && GET_CODE (operands[0]) != GT + && c4x_null_epilogue_p ()" + "rets%I0" + [(set_attr "type" "rets")]) + +(define_insn "jump" + [(set (pc) (label_ref (match_operand 0 "" "")))] + "" + "br%#\\t%l0" + [(set_attr "type" "jump")]) + +; +; DBcond +; +; Note we have to emit a dbu instruction if there are no delay slots +; to fill. +; Also note that GCC will try to reverse a loop to see if it can +; utilise this instruction. However, if there are more than one +; memory reference in the loop, it cannot guarantee that reversing +; the loop will work :( (see check_dbra_loop() in loop.c) +; Note that the C3x only decrements the 24 LSBs of the address register +; and the 8 MSBs are untouched. The C4x uses all 32-bits. We thus +; have an option to disable this instruction. +(define_insn "*db" + [(set (pc) + (if_then_else (ne (match_operand:QI 0 "addr_reg_operand" "+a,?*d,??*r,!m") + (const_int 0)) + (label_ref (match_operand 1 "" "")) + (pc))) + (set (match_dup 0) + (plus:QI (match_dup 0) + (const_int -1))) + (clobber (reg:CC_NOOV 21))] + "TARGET_DB && TARGET_LOOP_UNSIGNED" + "* + if (which_alternative == 0) + return \"dbu%#\\t%0,%l1\"; + else if (which_alternative == 1) + return c4x_output_cbranch (\"subi\\t1,%0\\n\\tbge\", insn); + else if (which_alternative == 2) + return c4x_output_cbranch (\"subi\\t1,%0\\n\\tcmpi\\t0,%0\\n\\tbge\", insn); + else + return c4x_output_cbranch (\"push\\tr0\\n\\tldi\\t%0,r0\\n\\tsubi\\t1,r0\\n\\tsti\\tr0,%0\\n\\tpop\\tr0\\n\\tbhs\", insn); + " + [(set_attr "type" "db,jmpc,jmpc,jmpc")]) + + +; This insn is used for some loop tests, typically loops reversed when +; strength reduction is used. It is actually created when the instruction +; combination phase combines the special loop test. Since this insn +; is both a jump insn and has an output, it must deal with its own +; reloads, hence the `m' constraints. + +; The C4x does the decrement and then compares the result against zero. +; It branches if the result was greater than or equal to zero. +; In the RTL the comparison and decrement are assumed to happen +; at the same time so we bias the iteration counter with by -1 +; when we make the test. +(define_insn "decrement_and_branch_until_zero" + [(set (pc) + (if_then_else (ge (plus:QI (match_operand:QI 0 "addr_reg_operand" "+a,?*d,??*r,!m") + (const_int -1)) + (const_int 0)) + (label_ref (match_operand 1 "" "")) + (pc))) + (set (match_dup 0) + (plus:QI (match_dup 0) + (const_int -1))) + (clobber (reg:CC_NOOV 21))] + "TARGET_DB && find_reg_note (insn, REG_NONNEG, 0)" + "* + if (which_alternative == 0) + return \"dbu%#\\t%0,%l1\"; + else if (which_alternative == 1) + return c4x_output_cbranch (\"subi\\t1,%0\\n\\tbge\", insn); + else if (which_alternative == 2) + return c4x_output_cbranch (\"subi\\t1,%0\\n\\tcmpi\\t0,%0\\n\\tbge\", insn); + else + return c4x_output_cbranch (\"push\\tr0\\n\\tldi\\t%0,r0\\n\\tsubi\\t1,r0\\n\\tsti\\tr0,%0\\n\\tpop\\tr0\\n\\tbhs\", insn); + " + [(set_attr "type" "db,jmpc,jmpc,jmpc")]) + +; +; MISC INSTRUCTIONS +; + +; +; NOP +; +(define_insn "nop" + [(const_int 0)] + "" + "nop") +; Default to misc type attr. + + +; +; RPTB +; +(define_insn "rptb_top" + [(use (label_ref (match_operand 0 "" ""))) + (use (label_ref (match_operand 1 "" "")))] + "" + "* + return ! final_sequence && c4x_rptb_rpts_p (insn, operands[0]) + ? \"rpts\\trc\" : \"rptb%#\\t%l1-1\"; + " + [(set_attr "type" "repeat_top")]) + +; This pattern needs to be emitted at the start of the loop to +; say that RS and RE are loaded. +(define_insn "init_branch_on_count" + [(unspec[(match_operand:QI 0 "rc_reg_operand" "v")] 22) + (clobber (reg:QI 25)) + (clobber (reg:QI 26))] + "" + "" + [(set_attr "type" "repeat")]) + +; The RS (25) and RE (26) registers must be unviolate from the top of the loop +; to here. +(define_insn "rptb_end" + [(set (pc) + (if_then_else (ge (match_operand:QI 2 "rc_reg_operand" "0,0,0,0,0") + (const_int 0)) + (label_ref (match_operand 1 "" "")) + (pc))) + (set (match_operand:QI 0 "rc_reg_operand" "+v,*a,*d,*x*k,*m") + (plus:QI (match_dup 0) + (const_int -1))) + (use (reg:QI 25)) + (use (reg:QI 26)) + (clobber (reg:CC_NOOV 21))] + "" + "* + if (which_alternative == 0) + return c4x_rptb_nop_p (insn) ? \"nop\" : \"\"; + else if (which_alternative == 1) + return \"dbu%#\\t%0,%l1\"; + else if (which_alternative == 2) + return c4x_output_cbranch (\"subi\\t1,%0\\n\\tbge\", insn); + else if (which_alternative == 3) + return c4x_output_cbranch (\"subi\\t1,%0\\n\\tcmpi\\t0,%0\\n\\tbge\", insn); + else + return c4x_output_cbranch (\"push\\tr0\\n\\tldi\\t%0,r0\\n\\tsubi\\t1,r0\\n\\tsti\\tr0,%0\\n\\tpop\\tr0\\n\\tbhs\", insn); + " + [(set_attr "type" "repeat,db,jmpc,jmpc,jmpc")]) + + +(define_expand "decrement_and_branch_on_count" + [(parallel [(set (pc) + (if_then_else (ge (match_operand:QI 0 "rc_reg_operand" "") + (const_int 0)) + (label_ref (match_operand 1 "" "")) + (pc))) + (set (match_dup 0) + (plus:QI (match_dup 0) + (const_int -1))) + (use (reg:QI 25)) + (use (reg:QI 26)) + (clobber (reg:CC_NOOV 21))])] + "" + "") + + +(define_expand "movstrqi_small2" + [(parallel [(set (mem:BLK (match_operand:BLK 0 "src_operand" "")) + (mem:BLK (match_operand:BLK 1 "src_operand" ""))) + (use (match_operand:QI 2 "immediate_operand" "")) + (use (match_operand:QI 3 "immediate_operand" "")) + (clobber (match_operand:QI 4 "ext_low_reg_operand" ""))])] + "" + " + { + rtx src, dst, tmp; + rtx src_mem, dst_mem; + int len; + int i; + + dst = operands[0]; + src = operands[1]; + len = INTVAL (operands[2]); + tmp = operands[4]; + + src_mem = gen_rtx_MEM (QImode, src); + dst_mem = gen_rtx_MEM (QImode, dst); + + emit_insn (gen_movqi (tmp, src_mem)); + emit_insn (gen_addqi3_noclobber (src, src, const1_rtx)); + for (i = 1; i < len; i++) + { + emit_insn (gen_movqi_parallel (tmp, src_mem, dst_mem, tmp)); + emit_insn (gen_addqi3_noclobber (src, src, const1_rtx)); + emit_insn (gen_addqi3_noclobber (dst, dst, const1_rtx)); + } + emit_insn (gen_movqi (dst_mem, tmp)); + emit_insn (gen_addqi3_noclobber (dst, dst, const1_rtx)); + DONE; + } + ") + + +; +; BLOCK MOVE +; We should probably get RC loaded when using RPTB automagically... +; There's probably no need to call _memcpy() if we don't get +; a immediate operand for the size. We could do a better job here +; than most memcpy() implementations. +; operand 2 is the number of bytes +; operand 3 is the shared alignment +; operand 4 is a scratch register + +(define_insn "movstrqi_small" + [(set (mem:BLK (match_operand:QI 0 "addr_reg_operand" "a")) + (mem:BLK (match_operand:QI 1 "addr_reg_operand" "a"))) + (use (match_operand:QI 2 "immediate_operand" "i")) + (use (match_operand:QI 3 "immediate_operand" "")) + (clobber (match_operand:QI 4 "ext_low_reg_operand" "=&q")) + (clobber (match_dup 0)) + (clobber (match_dup 1))] + "" + "* + { + int i; + int len = INTVAL (operands[2]); + int first = 1; + + for (i = 0; i < len; i++) + { + if (first) + output_asm_insn (\"ldiu\\t*%1++,%4\", operands); + else + output_asm_insn (\"|| ldi\\t*%1++,%4\", operands); + output_asm_insn (\"sti\\t%4,*%0++\", operands); + first = 0; + } + return \"\"; + } + " + [(set_attr "type" "multi")]) + +(define_insn "movstrqi_large" + [(set (mem:BLK (match_operand:QI 0 "addr_reg_operand" "a")) + (mem:BLK (match_operand:QI 1 "addr_reg_operand" "a"))) + (use (match_operand:QI 2 "immediate_operand" "i")) + (use (match_operand:QI 3 "immediate_operand" "")) + (clobber (match_operand:QI 4 "ext_low_reg_operand" "=&q")) + (clobber (match_dup 0)) + (clobber (match_dup 1)) + (clobber (reg:QI 25)) + (clobber (reg:QI 26)) + (clobber (reg:QI 27))] + "" + "* + { + int len = INTVAL (operands[2]); + + output_asm_insn (\"ldiu\\t*%1++,%4\", operands); + if (TARGET_RPTS_CYCLES (len)) + { + output_asm_insn (\"rpts\\t%2-2\", operands); + output_asm_insn (\"sti\\t%4,*%0++\", operands); + output_asm_insn (\"|| ldi\\t*%1++,%4\", operands); + return \"sti\\t%4,*%0++\"; + } + else + { + output_asm_insn (\"ldiu\\t%2-2,rc\", operands); + output_asm_insn (\"rptb\\t$+1\", operands); + output_asm_insn (\"sti\\t%4,*%0++\", operands); + output_asm_insn (\"|| ldi\\t*%1++,%4\", operands); + + return \"sti\\t%4,*%0++\"; + } + } + " + [(set_attr "type" "multi")]) + +; Operand 2 is the count, operand 3 is the alignment. +(define_expand "movstrqi" + [(parallel [(set (mem:BLK (match_operand:BLK 0 "src_operand" "")) + (mem:BLK (match_operand:BLK 1 "src_operand" ""))) + (use (match_operand:QI 2 "immediate_operand" "")) + (use (match_operand:QI 3 "immediate_operand" ""))])] + "" + " + { + rtx tmp; + if (GET_CODE (operands[2]) != CONST_INT + || INTVAL (operands[2]) > 32767 + || INTVAL (operands[2]) <= 0) + { + FAIL; /* Try to call _memcpy */ + } + + operands[0] = copy_to_mode_reg (Pmode, XEXP (operands[0], 0)); + operands[1] = copy_to_mode_reg (Pmode, XEXP (operands[1], 0)); + tmp = gen_reg_rtx (QImode); + if (INTVAL (operands[2]) < 8) + emit_insn (gen_movstrqi_small (operands[0], operands[1], operands[2], + operands[3], tmp)); + else + { + emit_insn (gen_movstrqi_large (operands[0], operands[1], operands[2], + operands[3], tmp)); + } + DONE; + }") + + +(define_insn "*cmpstrqi" + [(set (match_operand:QI 0 "reg_operand" "=d") + (compare:QI (mem:BLK (match_operand:QI 1 "addr_reg_operand" "a")) + (mem:BLK (match_operand:QI 2 "addr_reg_operand" "a")))) + (use (match_operand:QI 3 "immediate_operand" "i")) + (use (match_operand:QI 4 "immediate_operand" "")) + (clobber (match_operand:QI 5 "std_reg_operand" "=&c")) + (clobber (reg:QI 21))] + "" + "* + { + output_asm_insn (\"ldi\\t%3-1,%5\", operands); + output_asm_insn (\"$1:\tsubi3\\t*%1++,*%2++,%0\", operands); + output_asm_insn (\"dbeq\\t%5,$1\", operands); + return \"\"; + }") + +(define_expand "cmpstrqi" + [(parallel [(set (match_operand:QI 0 "reg_operand" "") + (compare:QI (match_operand:BLK 1 "general_operand" "") + (match_operand:BLK 2 "general_operand" ""))) + (use (match_operand:QI 3 "immediate_operand" "")) + (use (match_operand:QI 4 "immediate_operand" "")) + (clobber (match_dup 5)) + (clobber (reg:QI 21))])] + "" + " +{ + if (GET_CODE (operands[3]) != CONST_INT + || INTVAL (operands[3]) > 32767 + || INTVAL (operands[3]) <= 0) + { + FAIL; + } + operands[1] = copy_to_mode_reg (Pmode, XEXP (operands[1], 0)); + operands[2] = copy_to_mode_reg (Pmode, XEXP (operands[2], 0)); + operands[5] = gen_reg_rtx (QImode); +}") + +; +; TWO OPERAND LONG DOUBLE INSTRUCTIONS +; + +(define_expand "movhf" + [(set (match_operand:HF 0 "src_operand" "") + (match_operand:HF 1 "src_operand" ""))] + "" + "if (CONSTANT_P (operands[1])) + { + operands[1] = force_const_mem (HFmode, operands[1]); + if (! memory_address_p (HFmode, XEXP (operands[1], 0)) + && ! reload_in_progress) + operands[1] = change_address (operands[1], HFmode, + XEXP (operands[1], 0)); + } + + /* Memory to memory copies must go through a register. */ + if (GET_CODE (operands[1]) == MEM && GET_CODE (operands[0]) == MEM + && ! reload_in_progress) + operands[1] = force_reg (HFmode, operands[1]); +") + +(define_insn "*movhf_noclobber_reg" + [(set (match_operand:HF 0 "reg_operand" "=h") + (match_operand:HF 1 "reg_operand" "h"))] + "" + "ldfu\\t%1,%0" + [(set_attr "type" "unary")]) + +; The predicates could be tightened to disallow constants +(define_insn "*movhf_noclobber" + [(set (match_operand:HF 0 "src_operand" "=h,m") + (match_operand:HF 1 "src_operand" "m,h"))] + "reg_operand (operands[0], HFmode) ^ reg_operand (operands[1], HFmode)" + "#" + [(set_attr "type" "multi,multi")]) + +(define_insn "*movhf_test" + [(set (reg:CC 21) + (compare:CC (match_operand:HF 1 "reg_operand" "h") + (const_int 0))) + (clobber (match_scratch:HF 0 "=h"))] + "" + "ldf\\t%1,%0" + [(set_attr "type" "unarycc")]) + +(define_insn "*movhf_set" + [(set (reg:CC 21) + (compare:CC (match_operand:HF 1 "reg_operand" "h") + (match_operand:HF 2 "fp_zero_operand" "G"))) + (set (match_operand:HF 0 "reg_operand" "=h") + (match_dup 1))] + "" + "ldf\\t%1,%0" + [(set_attr "type" "unarycc")]) + +(define_split + [(set (match_operand:HF 0 "reg_operand" "") + (match_operand:HF 1 "memory_operand" ""))] + "reload_completed" + [(set (match_dup 0) (float_extend:HF (match_dup 2))) + (set (match_dup 0) (unspec[(subreg:QI (match_dup 0) 0) (match_dup 3)] 8))] + "operands[2] = c4x_operand_subword (operands[1], 0, 1, HFmode); + operands[3] = c4x_operand_subword (operands[1], 1, 1, HFmode); + PUT_MODE (operands[2], QFmode); + PUT_MODE (operands[3], QImode);") + +(define_split + [(set (match_operand:HF 0 "reg_operand" "") + (match_operand:HF 1 "const_operand" ""))] + "reload_completed && 0" + [(set (match_dup 0) (float_extend:HF (match_dup 2))) + (set (match_dup 0) (unspec[(subreg:QI (match_dup 0) 0) (match_dup 3)] 8))] + "operands[2] = c4x_operand_subword (operands[1], 0, 1, HFmode); + operands[3] = c4x_operand_subword (operands[1], 1, 1, HFmode); + PUT_MODE (operands[2], QFmode); + PUT_MODE (operands[3], QImode);") + +(define_split + [(set (match_operand:HF 0 "memory_operand" "") + (match_operand:HF 1 "reg_operand" ""))] + "reload_completed" + [(set (match_dup 2) (float_truncate:QF (match_dup 1))) + (set (match_dup 3) (unspec [(match_dup 1)] 9))] + "operands[2] = c4x_operand_subword (operands[0], 0, 1, HFmode); + operands[3] = c4x_operand_subword (operands[0], 1, 1, HFmode); + PUT_MODE (operands[2], QFmode); + PUT_MODE (operands[3], QImode);") + +(define_insn "*loadhf_float" + [(set (match_operand:HF 0 "reg_operand" "=h") + (float_extend:HF (match_operand:QF 1 "src_operand" "fmH")))] + "" + "@ + ldfu\\t%1,%0" + [(set_attr "type" "unary")]) + +(define_insn "*loadhf_int" + [(set (match_operand:HF 0 "reg_operand" "=h") + (unspec[(subreg:QI (match_dup 0) 0) + (match_operand:QI 1 "src_operand" "g")] 8))] + "" + "@ + ldiu\\t%1,%0" + [(set_attr "type" "unary")]) + +(define_insn "*storehf_float" + [(set (match_operand:QF 0 "memory_operand" "=m") + (float_truncate:QF (match_operand:HF 1 "reg_operand" "h")))] + "" + "stf\\t%1,%0" + [(set_attr "type" "store")]) + +(define_insn "*storehf_int" + [(set (match_operand:QI 0 "memory_operand" "=m") + (unspec [(match_operand:HF 1 "reg_operand" "h")] 9))] + "" + "@ + sti\\t%1,%0" + [(set_attr "type" "store")]) + +(define_insn "extendqfhf2" + [(set (match_operand:HF 0 "reg_operand" "=h") + (float_extend:HF (match_operand:QF 1 "reg_operand" "h")))] + "" + "ldfu\\t%1,%0" + [(set_attr "type" "unarycc")]) + +(define_insn "trunchfqf2" + [(set (match_operand:QF 0 "reg_operand" "=h") + (float_truncate:QF (match_operand:HF 1 "reg_operand" "0"))) + (clobber (reg:CC 21))] + "" + "andn\\t0ffh,%0" + [(set_attr "type" "unarycc")]) + +; +; PUSH/POP +; +(define_insn "*pushhf" + [(set (mem:HF (pre_inc:QI (reg:QI 20))) + (match_operand:HF 0 "reg_operand" "h"))] + "" + "#" + [(set_attr "type" "multi")]) + +(define_split + [(set (mem:HF (pre_inc:QI (reg:QI 20))) + (match_operand:HF 0 "reg_operand" ""))] + "reload_completed" + [(set (mem:QF (pre_inc:QI (reg:QI 20))) + (float_truncate:QF (match_dup 0))) + (set (mem:QI (pre_inc:QI (reg:QI 20))) + (unspec [(match_dup 0)] 9))] + "") + +(define_insn "pushhf_trunc" + [(set (mem:QF (pre_inc:QI (reg:QI 20))) + (float_truncate:QF (match_operand:HF 0 "reg_operand" "h")))] + "" + "pushf\\t%0" + [(set_attr "type" "push")]) + +(define_insn "pushhf_int" + [(set (mem:QI (pre_inc:QI (reg:QI 20))) + (unspec [(match_operand:HF 0 "reg_operand" "h")] 9))] + "" + "push\\t%0" + [(set_attr "type" "push")]) + +; we can not use this because the popf will destroy the low 8 bits +;(define_insn "*pophf" +; [(set (match_operand:HF 0 "reg_operand" "=h") +; (mem:HF (post_dec:QI (reg:QI 20)))) +; (clobber (reg:CC 21))] +; "" +; "#" +; [(set_attr "type" "multi")]) + +(define_split + [(set (match_operand:HF 0 "reg_operand" "") + (mem:HF (post_dec:QI (reg:QI 20)))) + (clobber (reg:CC 21))] + "reload_completed" + [(parallel [(set (match_operand:HF 0 "reg_operand" "=h") + (float_extend:HF (mem:QF (post_dec:QI (reg:QI 20))))) + (clobber (reg:CC 21))]) + (parallel [(set (match_dup 0) + (unspec[(subreg:QI (match_dup 0) 0) + (mem:QI (post_dec:QI (reg:QI 20)))] 8)) + (clobber (reg:CC 21))])] + "") + +(define_insn "*pophf_int" + [(set (match_operand:HF 0 "reg_operand" "=h") + (unspec[(subreg:QI (match_dup 0) 0) + (mem:QI (post_dec:QI (reg:QI 20)))] 8)) + (clobber (reg:CC 21))] + "" + "@ + pop\\t%0" + [(set_attr "type" "pop")]) + +(define_insn "*pophf_float" + [(set (match_operand:HF 0 "reg_operand" "=h") + (float_extend:HF (mem:QF (post_dec:QI (reg:QI 20))))) + (clobber (reg:CC 21))] + "" + "@ + popf\\t%0" + [(set_attr "type" "unary")]) + +; +; FIX +; +(define_insn "fixhfqi_clobber" + [(set (match_operand:QI 0 "reg_operand" "=dc") + (fix:QI (match_operand:HF 1 "reg_or_const_operand" "hH"))) + (clobber (reg:CC 21))] + "" + "fix\\t%1,%0" + [(set_attr "type" "unarycc")]) + +; +; ABSF +; +(define_expand "abshf2" + [(parallel [(set (match_operand:HF 0 "reg_operand" "") + (abs:HF (match_operand:HF 1 "reg_or_const_operand" ""))) + (clobber (reg:CC_NOOV 21))])] +"" +"") + +(define_insn "*abshf2_clobber" + [(set (match_operand:HF 0 "reg_operand" "=h") + (abs:HF (match_operand:HF 1 "reg_or_const_operand" "hH"))) + (clobber (reg:CC_NOOV 21))] + "" + "absf\\t%1,%0" + [(set_attr "type" "unarycc")]) + +(define_insn "*abshf2_test" + [(set (reg:CC_NOOV 21) + (compare:CC_NOOV (abs:HF (match_operand:HF 1 "reg_operand" "h")) + (match_operand:HF 2 "fp_zero_operand" "G"))) + (clobber (match_scratch:HF 0 "=h"))] + "" + "absf\\t%1,%0" + [(set_attr "type" "unarycc")]) + +(define_insn "*abshf2_set" + [(set (reg:CC_NOOV 21) + (compare:CC_NOOV (abs:HF (match_operand:HF 1 "reg_or_const_operand" "hH")) + (match_operand:HF 2 "fp_zero_operand" "G"))) + (set (match_operand:HF 0 "reg_operand" "=h") + (abs:HF (match_dup 1)))] + + "" + "absf\\t%1,%0" + [(set_attr "type" "unarycc")]) + +; +; NEGF +; +(define_expand "neghf2" + [(parallel [(set (match_operand:HF 0 "reg_operand" "") + (neg:HF (match_operand:HF 1 "reg_or_const_operand" ""))) + (clobber (reg:CC 21))])] +"" +"") + +(define_insn "*neghf2_clobber" + [(set (match_operand:HF 0 "reg_operand" "=h") + (neg:HF (match_operand:HF 1 "reg_or_const_operand" "hH"))) + (clobber (reg:CC 21))] + "" + "negf\\t%1,%0" + [(set_attr "type" "unarycc")]) + +(define_insn "*neghf2_test" + [(set (reg:CC 21) + (compare:CC (neg:HF (match_operand:HF 1 "reg_or_const_operand" "hH")) + (match_operand:HF 2 "fp_zero_operand" "G"))) + (clobber (match_scratch:HF 0 "=h"))] + "" + "negf\\t%1,%0" + [(set_attr "type" "unarycc")]) + +(define_insn "*neghf2_set" + [(set (reg:CC 21) + (compare:CC (neg:HF (match_operand:HF 1 "reg_or_const_operand" "hH")) + (match_operand:HF 2 "fp_zero_operand" "G"))) + (set (match_operand:HF 0 "reg_operand" "=h") + (neg:HF (match_dup 1)))] + "" + "negf\\t%1,%0" + [(set_attr "type" "unarycc")]) + +; +; RCPF +; +(define_insn "*rcpfhf_clobber" + [(set (match_operand:HF 0 "reg_operand" "=h") + (unspec [(match_operand:HF 1 "reg_or_const_operand" "hH")] 5)) + (clobber (reg:CC_NOOV 21))] + "! TARGET_C3X" + "rcpf\\t%1,%0" + [(set_attr "type" "unarycc")]) + +; +; RSQRF +; +(define_insn "*rsqrfhf_clobber" + [(set (match_operand:HF 0 "reg_operand" "=h") + (unspec [(match_operand:HF 1 "reg_or_const_operand" "hH")] 10)) + (clobber (reg:CC_NOOV 21))] + "! TARGET_C3X" + "rsqrf\\t%1,%0" + [(set_attr "type" "unarycc")]) + +; +; RNDF +; +(define_insn "*rndhf_clobber" + [(set (match_operand:HF 0 "reg_operand" "=h") + (unspec [(match_operand:HF 1 "reg_or_const_operand" "hH")] 6)) + (clobber (reg:CC_NOOV 21))] + "! TARGET_C3X" + "rnd\\t%1,%0" + [(set_attr "type" "unarycc")]) + + +; Inlined float square root for C4x +(define_expand "sqrthf2_inline" + [(parallel [(set (match_dup 2) + (unspec [(match_operand:HF 1 "reg_operand" "")] 10)) + (clobber (reg:CC_NOOV 21))]) + (parallel [(set (match_dup 3) (mult:HF (match_dup 5) (match_dup 1))) + (clobber (reg:CC_NOOV 21))]) + (parallel [(set (match_dup 4) (mult:HF (match_dup 2) (match_dup 3))) + (clobber (reg:CC_NOOV 21))]) + (parallel [(set (match_dup 4) (mult:HF (match_dup 2) (match_dup 4))) + (clobber (reg:CC_NOOV 21))]) + (parallel [(set (match_dup 4) (minus:HF (match_dup 6) (match_dup 4))) + (clobber (reg:CC_NOOV 21))]) + (parallel [(set (match_dup 2) (mult:HF (match_dup 2) (match_dup 4))) + (clobber (reg:CC_NOOV 21))]) + (parallel [(set (match_dup 4) (mult:HF (match_dup 2) (match_dup 3))) + (clobber (reg:CC_NOOV 21))]) + (parallel [(set (match_dup 4) (mult:HF (match_dup 2) (match_dup 4))) + (clobber (reg:CC_NOOV 21))]) + (parallel [(set (match_dup 4) (minus:HF (match_dup 6) (match_dup 4))) + (clobber (reg:CC_NOOV 21))]) + (parallel [(set (match_dup 2) (mult:HF (match_dup 2) (match_dup 4))) + (clobber (reg:CC_NOOV 21))]) + (parallel [(set (match_operand:HF 0 "reg_operand" "") + (mult:HF (match_dup 2) (match_dup 1))) + (clobber (reg:CC_NOOV 21))])] + "! TARGET_C3X" + " + operands[2] = gen_reg_rtx (HFmode); + operands[3] = gen_reg_rtx (HFmode); + operands[4] = gen_reg_rtx (HFmode); + operands[5] = immed_real_const_1 (REAL_VALUE_ATOF (\"0.5\", HFmode), HFmode); + operands[6] = immed_real_const_1 (REAL_VALUE_ATOF (\"1.5\", HFmode), HFmode); + ") + + +(define_expand "sqrthf2" + [(parallel [(set (match_operand:HF 0 "reg_operand" "") + (sqrt:HF (match_operand:HF 1 "reg_operand" ""))) + (clobber (reg:CC 21))])] + "" + "if (TARGET_C3X || ! TARGET_INLINE) + FAIL; + else + { + emit_insn (gen_sqrthf2_inline (operands[0], operands[1])); + DONE; + } + ") + +(define_expand "fix_trunchfhi2" + [(parallel [(set (match_operand:HI 0 "reg_operand" "") + (fix:HI (match_operand:HF 1 "reg_operand" ""))) + (clobber (reg:CC 21))])] + "" + "c4x_emit_libcall (FIX_TRUNCHFHI2_LIBCALL, FIX, HImode, HFmode, 2, operands); + DONE;") + +(define_expand "fixuns_trunchfhi2" + [(parallel [(set (match_operand:HI 0 "reg_operand" "") + (unsigned_fix:HI (match_operand:HF 1 "reg_operand" ""))) + (clobber (reg:CC 21))])] + "" + "c4x_emit_libcall (FIXUNS_TRUNCHFHI2_LIBCALL, UNSIGNED_FIX, + HImode, HFmode, 2, operands); + DONE;") + +; +; THREE OPERAND LONG DOUBLE INSTRUCTIONS +; + +; +; ADDF +; +(define_insn "addhf3" + [(set (match_operand:HF 0 "reg_operand" "=?h,h") + (plus:HF (match_operand:HF 1 "reg_operand" "%h,0") + (match_operand:HF 2 "reg_or_const_operand" "h,H"))) + (clobber (reg:CC_NOOV 21))] + "" + "@ + addf3\\t%2,%1,%0 + addf\\t%2,%0" + [(set_attr "type" "binarycc,binarycc")]) + +; +; SUBF +; +(define_insn "subhf3" + [(set (match_operand:HF 0 "reg_operand" "=?h,h,h") + (minus:HF (match_operand:HF 1 "reg_or_const_operand" "h,0,H") + (match_operand:HF 2 "reg_or_const_operand" "h,H,0"))) + (clobber (reg:CC_NOOV 21))] + "" + "@ + subf3\\t%2,%1,%0 + subf\\t%2,%0 + subrf\\t%1,%0" + [(set_attr "type" "binarycc,binarycc,binarycc")]) + +; +; MULF +; +; The C3x MPYF only uses 24 bit precision while the C4x uses 32 bit precison. +; +(define_expand "mulhf3" + [(parallel [(set (match_operand:HF 0 "reg_operand" "=h") + (mult:HF (match_operand:HF 1 "reg_operand" "h") + (match_operand:HF 2 "reg_operand" "h"))) + (clobber (reg:CC_NOOV 21))])] + "" + "if (TARGET_C3X) + { + c4x_emit_libcall3 (MULHF3_LIBCALL, MULT, HFmode, operands); + DONE; + } + ") + +(define_insn "*mulhf3_c40" + [(set (match_operand:HF 0 "reg_operand" "=?h,h") + (mult:HF (match_operand:HF 1 "reg_operand" "%h,0") + (match_operand:HF 2 "reg_or_const_operand" "h,hH"))) + (clobber (reg:CC_NOOV 21))] + "" + "@ + mpyf3\\t%2,%1,%0 + mpyf\\t%2,%0" + [(set_attr "type" "binarycc,binarycc")]) + +; +; CMPF +; +(define_expand "cmphf" + [(set (reg:CC 21) + (compare:CC (match_operand:HF 0 "reg_operand" "") + (match_operand:HF 1 "reg_or_const_operand" "")))] + "" + "c4x_compare_op0 = operands[0]; + c4x_compare_op1 = operands[1]; + DONE;") + +(define_insn "*cmphf" + [(set (reg:CC 21) + (compare:CC (match_operand:HF 0 "reg_operand" "h") + (match_operand:HF 1 "reg_or_const_operand" "hH")))] + "" + "cmpf\\t%1,%0" + [(set_attr "type" "compare")]) + +(define_insn "*cmphf_noov" + [(set (reg:CC_NOOV 21) + (compare:CC_NOOV (match_operand:HF 0 "reg_operand" "h") + (match_operand:HF 1 "reg_or_const_operand" "hH")))] + "" + "cmpf\\t%1,%0" + [(set_attr "type" "compare")]) + +; Inlined float divide for C4x +(define_expand "divhf3_inline" + [(parallel [(set (match_dup 3) + (unspec [(match_operand:HF 2 "reg_operand" "")] 5)) + (clobber (reg:CC_NOOV 21))]) + (parallel [(set (match_dup 4) (mult:HF (match_dup 2) (match_dup 3))) + (clobber (reg:CC_NOOV 21))]) + (parallel [(set (match_dup 4) (minus:HF (match_dup 5) (match_dup 4))) + (clobber (reg:CC_NOOV 21))]) + (parallel [(set (match_dup 3) (mult:HF (match_dup 3) (match_dup 4))) + (clobber (reg:CC_NOOV 21))]) + (parallel [(set (match_dup 4) (mult:HF (match_dup 2) (match_dup 3))) + (clobber (reg:CC_NOOV 21))]) + (parallel [(set (match_dup 4) (minus:HF (match_dup 5) (match_dup 4))) + (clobber (reg:CC_NOOV 21))]) + (parallel [(set (match_dup 3) (mult:HF (match_dup 3) (match_dup 4))) + (clobber (reg:CC_NOOV 21))]) + (parallel [(set (match_operand:HF 0 "reg_operand" "") + (mult:HF (match_operand:HF 1 "reg_operand" "") + (match_dup 3))) + (clobber (reg:CC_NOOV 21))])] + "! TARGET_C3X" + " + operands[3] = gen_reg_rtx (HFmode); + operands[4] = gen_reg_rtx (HFmode); + operands[5] = CONST2_RTX (HFmode); + ") + +(define_expand "divhf3" + [(parallel [(set (match_operand:HF 0 "reg_operand" "") + (div:HF (match_operand:HF 1 "reg_operand" "") + (match_operand:HF 2 "reg_operand" ""))) + (clobber (reg:CC 21))])] + "" + "if (TARGET_C3X || ! TARGET_INLINE) + { + c4x_emit_libcall3 (DIVHF3_LIBCALL, DIV, HFmode, operands); + DONE; + } + else + { + emit_insn (gen_divhf3_inline (operands[0], operands[1], operands[2])); + DONE; + } + ") + + +; +; TWO OPERAND LONG LONG INSTRUCTIONS +; + +; We could load some constants using define_splits for the C30 +; in the large memory model---these would emit shift and or insns. +(define_expand "movhi" + [(set (match_operand:HI 0 "src_operand" "") + (match_operand:HI 1 "src_operand" ""))] + "" + "if (CONSTANT_P (operands[1])) + { + /* We don't need to force all constants into memory. + This could be improved.... */ + operands[1] = force_const_mem (HImode, operands[1]); + if (! memory_address_p (HImode, XEXP (operands[1], 0)) + && ! reload_in_progress) + operands[1] = change_address (operands[1], HImode, + XEXP (operands[1], 0)); + } + + /* Memory to memory copies must go through a register. */ + if (GET_CODE (operands[1]) == MEM && GET_CODE (operands[0]) == MEM + && ! reload_in_progress) + operands[1] = force_reg (HImode, operands[1]); +") + +; The constraints for movhi must include 'r' if we don't +; restrict HImode regnos to start on an even number, since +; we can get RC, R8 allocated as a pair. We want more +; votes for FP_REGS so we use dr as the constraints. +(define_insn "*movhi_noclobber" + [(set (match_operand:HI 0 "src_operand" "=dr,m") + (match_operand:HI 1 "src_operand" "drm,r"))] + "reg_operand (operands[0], HImode) + || reg_operand (operands[1], HImode)" + "#" + [(set_attr "type" "multi,multi")]) + +(define_split + [(set (match_operand:HI 0 "src_operand" "") + (match_operand:HI 1 "src_operand" ""))] + "reload_completed + && (reg_operand (operands[0], HImode) || reg_operand (operands[1], HImode))" + [(set (match_dup 2) (match_dup 3)) + (set (match_dup 4) (match_dup 5))] + "operands[2] = c4x_operand_subword (operands[0], 0, 1, HImode); + operands[3] = c4x_operand_subword (operands[1], 0, 1, HImode); + operands[4] = c4x_operand_subword (operands[0], 1, 1, HImode); + operands[5] = c4x_operand_subword (operands[1], 1, 1, HImode);") + + +(define_insn "extendqihi2" + [(set (match_operand:HI 0 "reg_operand" "=dc") + (sign_extend:HI (match_operand:QI 1 "src_operand" "g"))) + (clobber (reg:CC 21))] + "" + "#" + [(set_attr "type" "multi")]) + +(define_split + [(set (match_operand:HI 0 "reg_operand" "=?dc") + (sign_extend:HI (match_operand:QI 1 "src_operand" "g"))) + (clobber (reg:CC 21))] + "reload_completed && TARGET_C3X" + [(set (match_dup 2) (match_dup 1)) + (set (match_dup 3) (match_dup 2)) + (parallel [(set (match_dup 3) (ashiftrt:QI (match_dup 3) (const_int 31))) + (clobber (reg:CC 21))])] + "operands[2] = c4x_operand_subword (operands[0], 0, 0, HImode); + operands[3] = c4x_operand_subword (operands[0], 1, 0, HImode);") + +(define_split + [(set (match_operand:HI 0 "reg_operand" "=?dc") + (sign_extend:HI (match_operand:QI 1 "src_operand" "g"))) + (clobber (reg:CC 21))] + "reload_completed && ! TARGET_C3X" + [(set (match_dup 2) (match_dup 1)) + (parallel [(set (match_dup 3) (ashiftrt:QI (match_dup 2) (const_int 31))) + (clobber (reg:CC 21))])] + "operands[2] = c4x_operand_subword (operands[0], 0, 0, HImode); + operands[3] = c4x_operand_subword (operands[0], 1, 0, HImode);") + +(define_insn "zero_extendqihi2" + [(set (match_operand:HI 0 "reg_operand" "=?dc") + (zero_extend:HI (match_operand:QI 1 "src_operand" "g"))) + (clobber (reg:CC 21))] + "" + "#" + [(set_attr "type" "multi")]) + +; If operand0 and operand1 are the same register we don't need +; the first set. +(define_split + [(set (match_operand:HI 0 "reg_operand" "=?dc") + (zero_extend:HI (match_operand:QI 1 "src_operand" "g"))) + (clobber (reg:CC 21))] + "reload_completed" + [(set (match_dup 2) (match_dup 1)) + (set (match_dup 3) (const_int 0))] + "operands[2] = c4x_operand_subword (operands[0], 0, 0, HImode); + operands[3] = c4x_operand_subword (operands[0], 1, 0, HImode);") + +; +; PUSH/POP +; +(define_insn "*pushhi" + [(set (mem:HI (pre_inc:QI (reg:QI 20))) + (match_operand:HI 0 "reg_operand" "r"))] + "" + "#" + [(set_attr "type" "multi")]) + +(define_split + [(set (mem:HI (pre_inc:QI (reg:QI 20))) + (match_operand:HI 0 "reg_operand" ""))] + "reload_completed" + [(set (mem:QI (pre_inc:QI (reg:QI 20))) (match_dup 2)) + (set (mem:QI (pre_inc:QI (reg:QI 20))) (match_dup 3))] + "operands[2] = c4x_operand_subword (operands[0], 0, 0, HImode); + operands[3] = c4x_operand_subword (operands[0], 1, 0, HImode);") + +(define_insn "*pophi" + [(set (match_operand:HI 0 "reg_operand" "=r") + (mem:HI (post_dec:QI (reg:QI 20)))) + (clobber (reg:CC 21))] + "" + "#" + [(set_attr "type" "multi")]) + +(define_split + [(set (match_operand:HI 0 "reg_operand" "") + (mem:HI (pre_inc:QI (reg:QI 20))))] + "reload_completed" + [(set (match_dup 2) (mem:QI (pre_inc:QI (reg:QI 20)))) + (set (match_dup 3) (mem:QI (pre_inc:QI (reg:QI 20))))] + "operands[2] = c4x_operand_subword (operands[0], 0, 0, HImode); + operands[3] = c4x_operand_subword (operands[0], 1, 0, HImode);") + +; +; NEG +; +(define_insn "neghi2" + [(set (match_operand:HI 0 "ext_reg_operand" "=d") + (neg:HI (match_operand:HI 1 "src_operand" "rm"))) + (clobber (reg:CC_NOOV 21))] + "" + "#" + [(set_attr "type" "multi")]) + +(define_split + [(set (match_operand:HI 0 "ext_reg_operand" "") + (neg:HI (match_operand:HI 1 "src_operand" ""))) + (clobber (reg:CC_NOOV 21))] + "reload_completed" + [(parallel [(set (reg:CC_NOOV 21) + (compare:CC_NOOV (neg:QI (match_dup 3)) + (const_int 0))) + (set (match_dup 2) (neg:QI (match_dup 3)))]) + (parallel [(set (match_dup 4) (neg:QI (match_dup 5))) + (use (reg:CC_NOOV 21)) + (clobber (reg:CC_NOOV 21))])] + "operands[2] = c4x_operand_subword (operands[0], 0, 1, HImode); + operands[3] = c4x_operand_subword (operands[1], 0, 1, HImode); + operands[4] = c4x_operand_subword (operands[0], 1, 1, HImode); + operands[5] = c4x_operand_subword (operands[1], 1, 1, HImode);") + +(define_insn "one_cmplhi2" + [(set (match_operand:HI 0 "reg_operand" "=r") + (not:HI (match_operand:HI 1 "src_operand" "rm"))) + (clobber (reg:CC 21))] + "" + "#" + [(set_attr "type" "multi")]) + +(define_split + [(set (match_operand:HI 0 "reg_operand" "") + (not:HI (match_operand:HI 1 "src_operand" ""))) + (clobber (reg:CC 21))] + "reload_completed" + [(parallel [(set (match_dup 2) (not:QI (match_dup 3))) + (clobber (reg:CC 21))]) + (parallel [(set (match_dup 4) (not:QI (match_dup 5))) + (clobber (reg:CC 21))])] + "operands[2] = c4x_operand_subword (operands[0], 0, 1, HImode); + operands[3] = c4x_operand_subword (operands[1], 0, 1, HImode); + operands[4] = c4x_operand_subword (operands[0], 1, 1, HImode); + operands[5] = c4x_operand_subword (operands[1], 1, 1, HImode);") + +(define_expand "floathiqf2" + [(parallel [(set (match_operand:QF 0 "reg_operand" "") + (float:QF (match_operand:HI 1 "src_operand" ""))) + (clobber (reg:CC 21))])] + "" + "c4x_emit_libcall (FLOATHIQF2_LIBCALL, FLOAT, QFmode, HImode, 2, operands); + DONE;") + +(define_expand "floatunshiqf2" + [(parallel [(set (match_operand:QF 0 "reg_operand" "") + (unsigned_float:QF (match_operand:HI 1 "src_operand" ""))) + (clobber (reg:CC 21))])] + "" + "c4x_emit_libcall (FLOATUNSHIQF2_LIBCALL, UNSIGNED_FLOAT, + QFmode, HImode, 2, operands); + DONE;") + +(define_expand "floathihf2" + [(parallel [(set (match_operand:HF 0 "reg_operand" "") + (float:HF (match_operand:HI 1 "src_operand" ""))) + (clobber (reg:CC 21))])] + "" + "c4x_emit_libcall (FLOATHIHF2_LIBCALL, FLOAT, HFmode, HImode, 2, operands); + DONE;") + +(define_expand "floatunshihf2" + [(parallel [(set (match_operand:HF 0 "reg_operand" "") + (unsigned_float:HF (match_operand:HI 1 "src_operand" ""))) + (clobber (reg:CC 21))])] + "" + "c4x_emit_libcall (FLOATUNSHIHF2_LIBCALL, UNSIGNED_FLOAT, + HFmode, HImode, 2, operands); + DONE;") + + +; +; THREE OPERAND LONG LONG INSTRUCTIONS +; + +(define_expand "addhi3" + [(parallel [(set (match_operand:HI 0 "ext_reg_operand" "") + (plus:HI (match_operand:HI 1 "src_operand" "") + (match_operand:HI 2 "src_operand" ""))) + (clobber (reg:CC_NOOV 21))])] + "" + "legitimize_operands (PLUS, operands, HImode);") + +(define_insn "*addhi3_clobber" + [(set (match_operand:HI 0 "ext_reg_operand" "=d,?d,d") + (plus:HI (match_operand:HI 1 "src_operand" "%rR,rS<>,0") + (match_operand:HI 2 "src_operand" "R,rS<>,rm"))) + (clobber (reg:CC_NOOV 21))] + "valid_operands (PLUS, operands, HImode)" + "#" + [(set_attr "type" "multi,multi,multi")]) + +(define_split + [(set (match_operand:HI 0 "ext_reg_operand" "") + (plus:HI (match_operand:HI 1 "src_operand" "") + (match_operand:HI 2 "src_operand" ""))) + (clobber (reg:CC_NOOV 21))] + "reload_completed" + [(parallel [(set (reg:CC_NOOV 21) + (compare:CC_NOOV (plus:QI (match_dup 4) (match_dup 5)) + (const_int 0))) + (set (match_dup 3) (plus:QI (match_dup 4) (match_dup 5)))]) + (parallel [(set (match_dup 6) (plus:QI (match_dup 7) (match_dup 8))) + (use (reg:CC_NOOV 21)) + (clobber (reg:CC_NOOV 21))])] + "operands[3] = c4x_operand_subword (operands[0], 0, 1, HImode); + operands[4] = c4x_operand_subword (operands[1], 0, 1, HImode); + operands[5] = c4x_operand_subword (operands[2], 0, 1, HImode); + operands[6] = c4x_operand_subword (operands[0], 1, 1, HImode); + operands[7] = c4x_operand_subword (operands[1], 1, 1, HImode); + operands[8] = c4x_operand_subword (operands[2], 1, 1, HImode);") + +(define_expand "subhi3" + [(parallel [(set (match_operand:HI 0 "ext_reg_operand" "") + (minus:HI (match_operand:HI 1 "src_operand" "") + (match_operand:HI 2 "src_operand" ""))) + (clobber (reg:CC_NOOV 21))])] + "" + "legitimize_operands (MINUS, operands, HImode);") + + +(define_insn "*subhi3_clobber" + [(set (match_operand:HI 0 "ext_reg_operand" "=d,?d,d") + (minus:HI (match_operand:HI 1 "src_operand" "rR,rS<>,0") + (match_operand:HI 2 "src_operand" "R,rS<>,rm"))) + (clobber (reg:CC_NOOV 21))] + "valid_operands (MINUS, operands, HImode)" + "#" + [(set_attr "type" "multi,multi,multi")]) + +(define_split + [(set (match_operand:HI 0 "ext_reg_operand" "") + (minus:HI (match_operand:HI 1 "src_operand" "") + (match_operand:HI 2 "src_operand" ""))) + (clobber (reg:CC_NOOV 21))] + "reload_completed" + [(parallel [(set (reg:CC_NOOV 21) + (compare:CC_NOOV (minus:QI (match_dup 4) (match_dup 5)) + (const_int 0))) + (set (match_dup 3) (minus:QI (match_dup 4) (match_dup 5)))]) + (parallel [(set (match_dup 6) (minus:QI (match_dup 7) (match_dup 8))) + (use (reg:CC_NOOV 21)) + (clobber (reg:CC_NOOV 21))])] + "operands[3] = c4x_operand_subword (operands[0], 0, 1, HImode); + operands[4] = c4x_operand_subword (operands[1], 0, 1, HImode); + operands[5] = c4x_operand_subword (operands[2], 0, 1, HImode); + operands[6] = c4x_operand_subword (operands[0], 1, 1, HImode); + operands[7] = c4x_operand_subword (operands[1], 1, 1, HImode); + operands[8] = c4x_operand_subword (operands[2], 1, 1, HImode);") + +(define_expand "iorhi3" + [(parallel [(set (match_operand:HI 0 "reg_operand" "") + (ior:HI (match_operand:HI 1 "src_operand" "") + (match_operand:HI 2 "src_operand" ""))) + (clobber (reg:CC 21))])] + "" + "legitimize_operands (IOR, operands, HImode);") + +(define_insn "*iorhi3_clobber" + [(set (match_operand:HI 0 "reg_operand" "=d,?d,d") + (ior:HI (match_operand:HI 1 "src_operand" "%rR,rS<>,0") + (match_operand:HI 2 "src_operand" "R,rS<>,rm"))) + (clobber (reg:CC 21))] + "valid_operands (IOR, operands, HImode)" + "#" + [(set_attr "type" "multi,multi,multi")]) + +(define_split + [(set (match_operand:HI 0 "reg_operand" "") + (ior:HI (match_operand:HI 1 "src_operand" "") + (match_operand:HI 2 "src_operand" ""))) + (clobber (reg:CC 21))] + "reload_completed" + [(parallel [(set (match_dup 3) (ior:QI (match_dup 4) (match_dup 5))) + (clobber (reg:CC 21))]) + (parallel [(set (match_dup 6) (ior:QI (match_dup 7) (match_dup 8))) + (clobber (reg:CC 21))])] + "operands[3] = c4x_operand_subword (operands[0], 0, 1, HImode); + operands[4] = c4x_operand_subword (operands[1], 0, 1, HImode); + operands[5] = c4x_operand_subword (operands[2], 0, 1, HImode); + operands[6] = c4x_operand_subword (operands[0], 1, 1, HImode); + operands[7] = c4x_operand_subword (operands[1], 1, 1, HImode); + operands[8] = c4x_operand_subword (operands[2], 1, 1, HImode);") + +(define_expand "andhi3" + [(parallel [(set (match_operand:HI 0 "reg_operand" "") + (and:HI (match_operand:HI 1 "src_operand" "") + (match_operand:HI 2 "src_operand" ""))) + (clobber (reg:CC 21))])] + "" + "legitimize_operands (AND, operands, HImode);") + +(define_insn "*andhi3_clobber" + [(set (match_operand:HI 0 "reg_operand" "=d,?d,d") + (and:HI (match_operand:HI 1 "src_operand" "%rR,rS<>,0") + (match_operand:HI 2 "src_operand" "R,rS<>,rm"))) + (clobber (reg:CC 21))] + "valid_operands (AND, operands, HImode)" + "#" + [(set_attr "type" "multi,multi,multi")]) + +(define_split + [(set (match_operand:HI 0 "reg_operand" "") + (and:HI (match_operand:HI 1 "src_operand" "") + (match_operand:HI 2 "src_operand" ""))) + (clobber (reg:CC 21))] + "reload_completed" + [(parallel [(set (match_dup 3) (and:QI (match_dup 4) (match_dup 5))) + (clobber (reg:CC 21))]) + (parallel [(set (match_dup 6) (and:QI (match_dup 7) (match_dup 8))) + (clobber (reg:CC 21))])] + "operands[3] = c4x_operand_subword (operands[0], 0, 1, HImode); + operands[4] = c4x_operand_subword (operands[1], 0, 1, HImode); + operands[5] = c4x_operand_subword (operands[2], 0, 1, HImode); + operands[6] = c4x_operand_subword (operands[0], 1, 1, HImode); + operands[7] = c4x_operand_subword (operands[1], 1, 1, HImode); + operands[8] = c4x_operand_subword (operands[2], 1, 1, HImode);") + +(define_expand "xorhi3" + [(parallel [(set (match_operand:HI 0 "reg_operand" "") + (xor:HI (match_operand:HI 1 "src_operand" "") + (match_operand:HI 2 "src_operand" ""))) + (clobber (reg:CC 21))])] + "" + "legitimize_operands (AND, operands, HImode);") + + +(define_insn "*xorhi3_clobber" + [(set (match_operand:HI 0 "reg_operand" "=d,?d,d") + (xor:HI (match_operand:HI 1 "src_operand" "%rR,rS<>,0") + (match_operand:HI 2 "src_operand" "R,rS<>,rm"))) + (clobber (reg:CC 21))] + "valid_operands (XOR, operands, HImode)" + "#" + [(set_attr "type" "multi,multi,multi")]) + +(define_split + [(set (match_operand:HI 0 "reg_operand" "") + (xor:HI (match_operand:HI 1 "src_operand" "") + (match_operand:HI 2 "src_operand" ""))) + (clobber (reg:CC 21))] + "reload_completed" + [(parallel [(set (match_dup 3) (xor:QI (match_dup 4) (match_dup 5))) + (clobber (reg:CC 21))]) + (parallel [(set (match_dup 6) (xor:QI (match_dup 7) (match_dup 8))) + (clobber (reg:CC 21))])] + "operands[3] = c4x_operand_subword (operands[0], 0, 1, HImode); + operands[4] = c4x_operand_subword (operands[1], 0, 1, HImode); + operands[5] = c4x_operand_subword (operands[2], 0, 1, HImode); + operands[6] = c4x_operand_subword (operands[0], 1, 1, HImode); + operands[7] = c4x_operand_subword (operands[1], 1, 1, HImode); + operands[8] = c4x_operand_subword (operands[2], 1, 1, HImode);") + +; This should do all the dirty work with define_split +(define_expand "ashlhi3" + [(parallel [(set (match_operand:HI 0 "reg_operand" "") + (ashift:HI (match_operand:HI 1 "src_operand" "") + (match_operand:QI 2 "src_operand" ""))) + (clobber (reg:CC 21))])] + "" + "if (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) >= 32) + { + rtx op0hi = operand_subword (operands[0], 1, 0, HImode); + rtx op0lo = operand_subword (operands[0], 0, 0, HImode); + rtx op1lo = operand_subword (operands[1], 0, 0, HImode); + rtx count = GEN_INT ((INTVAL (operands[2]) - 32)); + + if (INTVAL (count)) + emit_insn (gen_ashlqi3 (op0hi, op1lo, count)); + else + emit_insn (gen_movqi (op0hi, op1lo)); + emit_insn (gen_movqi (op0lo, const0_rtx)); + DONE; + } + emit_insn (gen_ashlhi3_reg (operands[0], operands[1], operands[2])); + DONE;") + +; %0.lo = %1.lo << %2 +; %0.hi = (%1.hi << %2 ) | (%1.lo >> (32 - %2)) +; This algorithm should work for shift counts greater than 32 +(define_expand "ashlhi3_reg" + [(use (match_operand:HI 1 "src_operand" "")) + (use (match_operand:HI 0 "reg_operand" "")) + /* If the shift count is greater than 32 this will give zero. */ + (parallel [(set (match_dup 7) + (ashift:QI (match_dup 3) + (match_operand:QI 2 "reg_operand" ""))) + (clobber (reg:CC 21))]) + /* If the shift count is greater than 32 this will give zero. */ + (parallel [(set (match_dup 8) + (ashift:QI (match_dup 4) (match_dup 2))) + (clobber (reg:CC 21))]) + (parallel [(set (match_dup 10) + (plus:QI (match_dup 2) (const_int -32))) + (clobber (reg:CC_NOOV 21))]) + /* If the shift count is greater than 32 this will do a left shift. */ + (parallel [(set (match_dup 9) + (lshiftrt:QI (match_dup 3) (neg:QI (match_dup 10)))) + (clobber (reg:CC 21))]) + (set (match_dup 5) (match_dup 7)) + (parallel [(set (match_dup 6) + (ior:QI (match_dup 8) (match_dup 9))) + (clobber (reg:CC 21))])] + "" + " + operands[3] = operand_subword (operands[1], 0, 1, HImode); /* lo */ + operands[4] = operand_subword (operands[1], 1, 1, HImode); /* hi */ + operands[5] = operand_subword (operands[0], 0, 1, HImode); /* lo */ + operands[6] = operand_subword (operands[0], 1, 1, HImode); /* hi */ + operands[7] = gen_reg_rtx (QImode); /* lo << count */ + operands[8] = gen_reg_rtx (QImode); /* hi << count */ + operands[9] = gen_reg_rtx (QImode); /* lo >> (32 - count) */ + operands[10] = gen_reg_rtx (QImode); /* 32 - count */ + ") + +; This should do all the dirty work with define_split +(define_expand "lshrhi3" + [(parallel [(set (match_operand:HI 0 "reg_operand" "") + (lshiftrt:HI (match_operand:HI 1 "src_operand" "") + (match_operand:QI 2 "src_operand" ""))) + (clobber (reg:CC 21))])] + "" + "if (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) >= 32) + { + rtx op0hi = operand_subword (operands[0], 1, 0, HImode); + rtx op0lo = operand_subword (operands[0], 0, 0, HImode); + rtx op1hi = operand_subword (operands[1], 1, 0, HImode); + rtx count = GEN_INT ((INTVAL (operands[2]) - 32)); + + if (INTVAL (count)) + emit_insn (gen_lshrqi3 (op0lo, op1hi, count)); + else + emit_insn (gen_movqi (op0lo, op1hi)); + emit_insn (gen_movqi (op0hi, const0_rtx)); + DONE; + } + emit_insn (gen_lshrhi3_reg (operands[0], operands[1], operands[2])); + DONE;") + +; %0.hi = %1.hi >> %2 +; %0.lo = (%1.lo >> %2 ) | (%1.hi << (32 - %2)) +; This algorithm should work for shift counts greater than 32 +(define_expand "lshrhi3_reg" + [(use (match_operand:HI 1 "src_operand" "")) + (use (match_operand:HI 0 "reg_operand" "")) + (parallel [(set (match_dup 11) + (neg:QI (match_operand:QI 2 "reg_operand" ""))) + (clobber (reg:CC_NOOV 21))]) + /* If the shift count is greater than 32 this will give zero. */ + (parallel [(set (match_dup 7) + (lshiftrt:QI (match_dup 3) + (neg:QI (match_dup 11)))) + (clobber (reg:CC 21))]) + /* If the shift count is greater than 32 this will give zero. */ + (parallel [(set (match_dup 8) + (lshiftrt:QI (match_dup 4) + (neg:QI (match_dup 11)))) + (clobber (reg:CC 21))]) + (parallel [(set (match_dup 10) + (plus:QI (match_dup 11) (const_int 32))) + (clobber (reg:CC_NOOV 21))]) + /* If the shift count is greater than 32 this will do an arithmetic + right shift. However, we need a logical right shift. */ + (parallel [(set (match_dup 9) + (ashift:QI (match_dup 4) (unspec [(match_dup 10)] 3))) + (clobber (reg:CC 21))]) + (set (match_dup 6) (match_dup 8)) + (parallel [(set (match_dup 5) + (ior:QI (match_dup 7) (match_dup 9))) + (clobber (reg:CC 21))])] + "" + " + operands[3] = operand_subword (operands[1], 0, 1, HImode); /* lo */ + operands[4] = operand_subword (operands[1], 1, 1, HImode); /* hi */ + operands[5] = operand_subword (operands[0], 0, 1, HImode); /* lo */ + operands[6] = operand_subword (operands[0], 1, 1, HImode); /* hi */ + operands[7] = gen_reg_rtx (QImode); /* lo >> count */ + operands[8] = gen_reg_rtx (QImode); /* hi >> count */ + operands[9] = gen_reg_rtx (QImode); /* hi << (32 - count) */ + operands[10] = gen_reg_rtx (QImode); /* 32 - count */ + operands[11] = gen_reg_rtx (QImode); /* -count */ + ") + +; This should do all the dirty work with define_split +(define_expand "ashrhi3" + [(parallel [(set (match_operand:HI 0 "reg_operand" "") + (ashiftrt:HI (match_operand:HI 1 "src_operand" "") + (match_operand:QI 2 "src_operand" ""))) + (clobber (reg:CC 21))])] + "" + "if (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) >= 32) + { + rtx op0hi = operand_subword (operands[0], 1, 0, HImode); + rtx op0lo = operand_subword (operands[0], 0, 0, HImode); + rtx op1hi = operand_subword (operands[1], 1, 0, HImode); + rtx count = GEN_INT ((INTVAL (operands[2]) - 32)); + + if (INTVAL (count)) + emit_insn (gen_ashrqi3 (op0lo, op1hi, count)); + else + emit_insn (gen_movqi (op0lo, op1hi)); + emit_insn (gen_ashrqi3 (op0hi, op1hi, GEN_INT (31))); + DONE; + } + emit_insn (gen_ashrhi3_reg (operands[0], operands[1], operands[2])); + DONE;") + +; %0.hi = %1.hi >> %2 +; %0.lo = (%1.lo >> %2 ) | (%1.hi << (32 - %2)) +; This algorithm should work for shift counts greater than 32 +(define_expand "ashrhi3_reg" + [(use (match_operand:HI 1 "src_operand" "")) + (use (match_operand:HI 0 "reg_operand" "")) + (parallel [(set (match_dup 11) + (neg:QI (match_operand:QI 2 "reg_operand" ""))) + (clobber (reg:CC_NOOV 21))]) + /* If the shift count is greater than 32 this will give zero. */ + (parallel [(set (match_dup 7) + (lshiftrt:QI (match_dup 3) + (neg:QI (match_dup 11)))) + (clobber (reg:CC 21))]) + /* If the shift count is greater than 32 this will give zero. */ + (parallel [(set (match_dup 8) + (ashiftrt:QI (match_dup 4) + (neg:QI (match_dup 11)))) + (clobber (reg:CC 21))]) + (parallel [(set (match_dup 10) + (plus:QI (match_dup 11) (const_int 32))) + (clobber (reg:CC_NOOV 21))]) + /* If the shift count is greater than 32 this will do an arithmetic + right shift. */ + (parallel [(set (match_dup 9) + (ashift:QI (match_dup 4) (match_dup 10))) + (clobber (reg:CC 21))]) + (set (match_dup 6) (match_dup 8)) + (parallel [(set (match_dup 5) + (ior:QI (match_dup 7) (match_dup 9))) + (clobber (reg:CC 21))])] + "" + " + operands[3] = operand_subword (operands[1], 0, 1, HImode); /* lo */ + operands[4] = operand_subword (operands[1], 1, 1, HImode); /* hi */ + operands[5] = operand_subword (operands[0], 0, 1, HImode); /* lo */ + operands[6] = operand_subword (operands[0], 1, 1, HImode); /* hi */ + operands[7] = gen_reg_rtx (QImode); /* lo >> count */ + operands[8] = gen_reg_rtx (QImode); /* hi >> count */ + operands[9] = gen_reg_rtx (QImode); /* hi << (32 - count) */ + operands[10] = gen_reg_rtx (QImode); /* 32 - count */ + operands[11] = gen_reg_rtx (QImode); /* -count */ + ") + +(define_expand "cmphi" + [(set (reg:CC 21) + (compare:CC (match_operand:HI 0 "src_operand" "") + (match_operand:HI 1 "src_operand" "")))] + "" + "legitimize_operands (COMPARE, operands, HImode); + c4x_compare_op0 = operands[0]; + c4x_compare_op1 = operands[1]; + DONE;") + +; This works only before reload because we need 2 extra registers. +; Use unspec to avoid recursive split. +(define_split + [(set (reg:CC 21) + (compare:CC (match_operand:HI 0 "src_operand" "") + (match_operand:HI 1 "src_operand" "")))] + "! reload_completed" + [(parallel [(set (reg:CC 21) + (unspec [(compare:CC (match_dup 0) + (match_dup 1))] 4)) + (clobber (match_scratch:QI 2 "")) + (clobber (match_scratch:QI 3 ""))])] + "") + +(define_split + [(set (reg:CC_NOOV 21) + (compare:CC_NOOV (match_operand:HI 0 "src_operand" "") + (match_operand:HI 1 "src_operand" "")))] + "! reload_completed" + [(parallel [(set (reg:CC_NOOV 21) + (unspec [(compare:CC_NOOV (match_dup 0) + (match_dup 1))] 4)) + (clobber (match_scratch:QI 2 "")) + (clobber (match_scratch:QI 3 ""))])] + "") + +; This is normally not used. The define splits above are used first. +(define_insn "*cmphi" + [(set (reg:CC 21) + (compare:CC (match_operand:HI 0 "src_operand" "rR,rS<>") + (match_operand:HI 1 "src_operand" "R,rS<>")))] + "valid_operands (COMPARE, operands, HImode)" + "* + { + int use_ir1 = (reg_operand (operands[0], HImode) + && REG_P (operands[0]) + && REGNO (operands[0]) == IR1_REGNO) + || (reg_operand (operands[1], HImode) + && REG_P (operands[1]) + && REGNO (operands[1]) == IR1_REGNO); + + if (use_ir1) + output_asm_insn (\"push\\tir1\", operands); + else + output_asm_insn (\"push\\tbk\", operands); + output_asm_insn (\"push\\tr0\", operands); + output_asm_insn (\"subi3\\t%1,%0,r0\", operands); + if (use_ir1) + { + output_asm_insn (\"ldiu\\tst,ir1\", operands); + output_asm_insn (\"or\\t07bh,ir1\", operands); + } + else + { + output_asm_insn (\"ldiu\\tst,bk\", operands); + output_asm_insn (\"or\\t07bh,bk\", operands); + } + output_asm_insn (\"subb3\\t%O1,%O0,r0\", operands); + if (use_ir1) + output_asm_insn (\"and3\\tir1,st,ir1\", operands); + else + output_asm_insn (\"and3\\tbk,st,bk\", operands); + output_asm_insn (\"pop\\tr0\", operands); + if (use_ir1) + { + output_asm_insn (\"ldiu\\tir1,st\", operands); + output_asm_insn (\"pop\\tir1\", operands); + } + else + { + output_asm_insn (\"ldiu\\tbk,st\", operands); + output_asm_insn (\"pop\\tbk\", operands); + } + return \"\"; + }" + [(set_attr "type" "multi")]) + +(define_insn "*cmphi_noov" + [(set (reg:CC_NOOV 21) + (compare:CC_NOOV (match_operand:HI 0 "src_operand" "rR,rS<>") + (match_operand:HI 1 "src_operand" "R,rS<>")))] + "valid_operands (COMPARE, operands, HImode)" + "* + { + int use_ir1 = (reg_operand (operands[0], HImode) + && REG_P (operands[0]) + && REGNO (operands[0]) == IR1_REGNO) + || (reg_operand (operands[1], HImode) + && REG_P (operands[1]) + && REGNO (operands[1]) == IR1_REGNO); + + if (use_ir1) + output_asm_insn (\"push\\tir1\", operands); + else + output_asm_insn (\"push\\tbk\", operands); + output_asm_insn (\"push\\tr0\", operands); + output_asm_insn (\"subi3\\t%1,%0,r0\", operands); + if (use_ir1) + { + output_asm_insn (\"ldiu\\tst,ir1\", operands); + output_asm_insn (\"or\\t07bh,ir1\", operands); + } + else + { + output_asm_insn (\"ldiu\\tst,bk\", operands); + output_asm_insn (\"or\\t07bh,bk\", operands); + } + output_asm_insn (\"subb3\\t%O1,%O0,r0\", operands); + if (use_ir1) + output_asm_insn (\"and3\\tir1,st,ir1\", operands); + else + output_asm_insn (\"and3\\tbk,st,bk\", operands); + output_asm_insn (\"pop\\tr0\", operands); + if (use_ir1) + { + output_asm_insn (\"ldiu\\tir1,st\", operands); + output_asm_insn (\"pop\\tir1\", operands); + } + else + { + output_asm_insn (\"ldiu\\tbk,st\", operands); + output_asm_insn (\"pop\\tbk\", operands); + } + return \"\"; + }" + [(set_attr "type" "multi")]) + + +(define_insn "cmphi_cc" + [(set (reg:CC 21) + (unspec [(compare:CC (match_operand:HI 0 "src_operand" "rR,rS<>") + (match_operand:HI 1 "src_operand" "R,rS<>"))] 4)) + (clobber (match_scratch:QI 2 "=&d,&d")) + (clobber (match_scratch:QI 3 "=&c,&c"))] + "valid_operands (COMPARE, operands, HImode)" + "* + output_asm_insn (\"subi3\\t%1,%0,%2\", operands); + output_asm_insn (\"ldiu\\tst,%3\", operands); + output_asm_insn (\"or\\t07bh,%3\", operands); + output_asm_insn (\"subb3\\t%O1,%O0,%2\", operands); + output_asm_insn (\"and\\t%3,st\", operands); + return \"\";" + [(set_attr "type" "multi")]) + +(define_insn "cmphi_cc_noov" + [(set (reg:CC_NOOV 21) + (unspec [(compare:CC_NOOV (match_operand:HI 0 "src_operand" "rR,rS<>") + (match_operand:HI 1 "src_operand" "R,rS<>"))] 4)) + (clobber (match_scratch:QI 2 "=&d,&d")) + (clobber (match_scratch:QI 3 "=&c,&c"))] + "valid_operands (COMPARE, operands, HImode)" + "* + output_asm_insn (\"subi3\\t%1,%0,%2\", operands); + output_asm_insn (\"ldiu\\tst,%3\", operands); + output_asm_insn (\"or\\t07bh,%3\", operands); + output_asm_insn (\"subb3\\t%O1,%O0,%2\", operands); + output_asm_insn (\"and\\t%3,st\", operands); + return \"\";" + [(set_attr "type" "multi")]) + +(define_expand "mulhi3" + [(parallel [(set (match_operand:HI 0 "reg_operand" "") + (mult:HI (match_operand:HI 1 "src_operand" "") + (match_operand:HI 2 "src_operand" ""))) + (clobber (reg:CC 21))])] + "" + "c4x_emit_libcall3 (MULHI3_LIBCALL, MULT, HImode, operands); + DONE;") + +(define_expand "udivhi3" + [(parallel [(set (match_operand:HI 0 "reg_operand" "") + (udiv:HI (match_operand:HI 1 "src_operand" "") + (match_operand:HI 2 "src_operand" ""))) + (clobber (reg:CC 21))])] + "" + "c4x_emit_libcall3 (UDIVHI3_LIBCALL, UDIV, HImode, operands); + DONE;") + +(define_expand "divhi3" + [(parallel [(set (match_operand:HI 0 "reg_operand" "") + (div:HI (match_operand:HI 1 "src_operand" "") + (match_operand:HI 2 "src_operand" ""))) + (clobber (reg:CC 21))])] + "" + "c4x_emit_libcall3 (DIVHI3_LIBCALL, DIV, HImode, operands); + DONE;") + +(define_expand "umodhi3" + [(parallel [(set (match_operand:HI 0 "reg_operand" "") + (umod:HI (match_operand:HI 1 "src_operand" "") + (match_operand:HI 2 "src_operand" ""))) + (clobber (reg:CC 21))])] + "" + "c4x_emit_libcall3 (UMODHI3_LIBCALL, UMOD, HImode, operands); + DONE;") + +(define_expand "modhi3" + [(parallel [(set (match_operand:HI 0 "reg_operand" "") + (mod:HI (match_operand:HI 1 "src_operand" "") + (match_operand:HI 2 "src_operand" ""))) + (clobber (reg:CC 21))])] + "" + "c4x_emit_libcall3 (MODHI3_LIBCALL, MOD, HImode, operands); + DONE;") + +; +; PEEPHOLES +; + +; dbCC peepholes +; +; Turns +; loop: +; [ ... ] +; bCC label ; abnormal loop termination +; dbu aN, loop ; normal loop termination +; +; Into +; loop: +; [ ... ] +; dbCC aN, loop +; bCC label +; +; Which moves the bCC condition outside the inner loop for free. +; +(define_peephole + [(set (pc) (if_then_else (match_operator 3 "comparison_operator" + [(reg:CC 21) (const_int 0)]) + (label_ref (match_operand 2 "" "")) + (pc))) + (parallel + [(set (pc) + (if_then_else + (ge (plus:QI (match_operand:QI 4 "addr_reg_operand" "0") + (const_int -1)) + (const_int 0)) + (label_ref (match_operand 1 "" "")) + (pc))) + (set (match_operand:QI 0 "addr_reg_operand" "+a") + (plus:QI (match_dup 0) + (const_int -1))) + (clobber (reg:CC_NOOV 21))])] + "! c4x_label_conflict (insn, operands[2], operands[1])" + "db%I3\\t%0,%l1\\n\\tb%3\\t%l2" + [(set_attr "type" "multi")]) + +(define_peephole + [(set (pc) (if_then_else (match_operator 3 "comparison_operator" + [(reg:CC 21) (const_int 0)]) + (label_ref (match_operand 2 "" "")) + (pc))) + (parallel + [(set (pc) + (if_then_else + (ne (match_operand:QI 4 "addr_reg_operand" "0") + (const_int 0)) + (label_ref (match_operand 1 "" "")) + (pc))) + (set (match_operand:QI 0 "addr_reg_operand" "+a") + (plus:QI (match_dup 0) + (const_int -1))) + (clobber (reg:CC_NOOV 21))])] + "! c4x_label_conflict (insn, operands[2], operands[1])" + "db%I3\\t%0,%l1\\n\\tb%3\\t%l2" + [(set_attr "type" "multi")]) + +; +; Peepholes to convert 'call label; rets' into jump label +; +(define_peephole + [(parallel [(call (match_operand:QI 0 "call_operand" "T,!o") + (match_operand:QI 1 "general_operand" "")) + (clobber (reg:QI 31))]) + (return)] + "c4x_null_epilogue_p ()" + "@ + br%#\\t%C0 + bu%#\\t%R0" + [(set_attr "type" "jump,jump")]) + +(define_peephole + [(parallel [(set (match_operand 0 "" "") + (call (match_operand:QI 1 "call_operand" "T,!o") + (match_operand:QI 2 "general_operand" ""))) + (clobber (reg:QI 31))]) + (return)] + "c4x_null_epilogue_p ()" + "@ + br%#\\t%C1 + bu%#\\t%R1" + [(set_attr "type" "jump,jump")]) + +; +; Peepholes for parallel instructions +; +(define_peephole + [(set (match_operand:QI 0 "ext_low_reg_operand" "") + (match_operand:QI 1 "par_ind_operand" "")) + (set (match_operand:QI 2 "ext_low_reg_operand" "") + (match_operand:QI 3 "par_ind_operand" ""))] + "(REGNO (operands[0]) != REGNO (operands[2])) + && ! c4x_address_conflict (operands[1], operands[3], 0, 0)" + "ldi1\\t%1,%0\\n||\\tldi2\\t%3,%2") + +; load occurs before store if 1 and 2 point to same address +(define_peephole + [(set (match_operand:QI 0 "ext_low_reg_operand" "") + (match_operand:QI 1 "par_ind_operand" "")) + (set (match_operand:QI 2 "par_ind_operand" "") + (match_operand:QI 3 "ext_low_reg_operand" ""))] + "(REGNO (operands[0]) != REGNO (operands[3])) + && ! c4x_address_conflict (operands[1], operands[2], 0, 1)" + "ldi\\t%1,%0\\n||\\tsti\\t%3,%2") + +; load occurs before store if 0 and 3 point to same address +(define_peephole + [(set (match_operand:QI 0 "par_ind_operand" "") + (match_operand:QI 1 "ext_low_reg_operand" "")) + (set (match_operand:QI 2 "ext_low_reg_operand" "") + (match_operand:QI 3 "par_ind_operand" ""))] + "(REGNO (operands[1]) != REGNO (operands[2])) + && ! c4x_address_conflict (operands[0], operands[3], 1, 0)" + "ldi\\t%3,%2\\n||\\tsti\\t%1,%0") + +(define_peephole + [(set (match_operand:QI 0 "par_ind_operand" "") + (match_operand:QI 1 "ext_low_reg_operand" "")) + (set (match_operand:QI 2 "par_ind_operand" "") + (match_operand:QI 3 "ext_low_reg_operand" ""))] + "! c4x_address_conflict (operands[0], operands[2], 1, 1)" + "sti\\t%1,%0\\n||\\tsti\\t%3,%2") + +; This peephole should be unnecessary with my patches to flow.c +; for better autoincrement detection +(define_peephole + [(set (match_operand:QF 0 "ext_low_reg_operand" "") + (mem:QF (match_operand:QI 1 "addr_reg_operand" ""))) + (set (match_operand:QF 2 "ext_low_reg_operand" "") + (mem:QF (plus:QI (match_dup 1) (const_int 1)))) + (parallel [(set (match_dup 1) (plus:QI (match_dup 1) (const_int 2))) + (clobber (reg:CC_NOOV 21))])] + "" + "ldf\\t*%1++,%0\\n\\tldf\\t*%1++,%2") + +(define_peephole + [(set (match_operand:QF 0 "ext_low_reg_operand" "") + (match_operand:QF 1 "par_ind_operand" "")) + (set (match_operand:QF 2 "ext_low_reg_operand" "") + (match_operand:QF 3 "par_ind_operand" ""))] + "(REGNO (operands[0]) != REGNO (operands[2])) + && ! c4x_address_conflict (operands[1], operands[3], 0, 1)" + "ldf1\\t%1,%0\\n||\\tldf2\\t%3,%2") + +; This peephole should be unnecessary with my patches to flow.c +; for better autoincrement detection +(define_peephole + [(set (mem:QF (match_operand:QI 0 "addr_reg_operand" "")) + (match_operand:QF 1 "ext_low_reg_operand" "")) + (set (mem:QF (plus:QI (match_dup 0) (const_int 1))) + (match_operand:QF 2 "ext_low_reg_operand" "")) + (parallel [(set (match_dup 0) (plus:QI (match_dup 0) (const_int 2))) + (clobber (reg:CC_NOOV 21))])] + "" + "stf\\t%1,*%0++\\n\\tstf\\t%2,*%0++") + +(define_peephole + [(set (match_operand:QF 0 "ext_low_reg_operand" "") + (match_operand:QF 1 "par_ind_operand" "")) + (set (match_operand:QF 2 "par_ind_operand" "") + (match_operand:QF 3 "ext_low_reg_operand" ""))] + "(REGNO (operands[0]) != REGNO (operands[3]))" + "ldf\\t%1,%0\\n||\\tstf\\t%3,%2") + +(define_peephole + [(set (match_operand:QF 0 "par_ind_operand" "") + (match_operand:QF 1 "ext_low_reg_operand" "")) + (set (match_operand:QF 2 "ext_low_reg_operand" "") + (match_operand:QF 3 "par_ind_operand" ""))] + "! c4x_address_conflict (operands[0], operands[3], 1, 1)" + "ldf\\t%3,%2\\n||\\tstf\\t%1,%0") + +(define_peephole + [(set (match_operand:QF 0 "par_ind_operand" "") + (match_operand:QF 1 "ext_low_reg_operand" "")) + (set (match_operand:QF 2 "par_ind_operand" "") + (match_operand:QF 3 "ext_low_reg_operand" ""))] + "! c4x_address_conflict (operands[0], operands[2], 1, 1)" + "stf1\\t%1,%0\\n||\\tstf2\\t%3,%2") + +(define_peephole + [(parallel [(set (reg:CC_NOOV 21) + (compare:CC_NOOV (abs:QF (match_operand:QF 1 "par_ind_operand" "")) + (match_operand:QF 2 "fp_zero_operand" ""))) + (set (match_operand:QF 0 "ext_low_reg_operand" "") + (abs:QF (match_dup 1)))]) + (set (match_operand:QF 3 "par_ind_operand" "") + (match_operand:QF 4 "ext_low_reg_operand" ""))] + "(REGNO (operands[0]) != REGNO (operands[4]))" + "absf\\t%1,%0\\n||\\tstf\\t%4,%3") + +(define_peephole + [(parallel [(set (match_operand:QF 0 "ext_low_reg_operand" "") + (abs:QF (match_operand:QF 1 "par_ind_operand" ""))) + (clobber (reg:CC_NOOV 21))]) + (set (match_operand:QF 2 "par_ind_operand" "") + (match_operand:QF 3 "ext_low_reg_operand" ""))] + "(REGNO (operands[0]) != REGNO (operands[3]))" + "absf\\t%1,%0\\n||\\tstf\\t%3,%2") + +(define_peephole + [(parallel [(set (reg:CC_NOOV 21) + (compare:CC_NOOV (abs:QI (match_operand:QI 1 "par_ind_operand" "")) + (const_int 0))) + (set (match_operand:QI 0 "ext_low_reg_operand" "") + (abs:QI (match_dup 1)))]) + (set (match_operand:QI 2 "par_ind_operand" "") + (match_operand:QI 3 "ext_low_reg_operand" ""))] + "(REGNO (operands[0]) != REGNO (operands[3]))" + "absi\\t%1,%0\\n||\\tsti\\t%3,%2") + +(define_peephole + [(parallel [(set (match_operand:QI 0 "ext_low_reg_operand" "") + (abs:QI (match_operand:QI 1 "par_ind_operand" ""))) + (clobber (reg:CC_NOOV 21))]) + (set (match_operand:QI 2 "par_ind_operand" "") + (match_operand:QI 3 "ext_low_reg_operand" ""))] + "(REGNO (operands[0]) != REGNO (operands[3]))" + "absi\\t%1,%0\\n||\\tsti\\t%3,%2") + +(define_peephole + [(parallel [(set (reg:CC_NOOV 21) + (compare:CC_NOOV (plus:QI (match_operand:QI 1 "ext_low_reg_operand" "") + (match_operand:QI 2 "par_ind_operand" "")) + (const_int 0))) + (set (match_operand:QI 0 "ext_low_reg_operand" "") + (plus:QI (match_dup 1) (match_dup 2)))]) + (set (match_operand:QI 3 "par_ind_operand" "") + (match_operand:QI 4 "ext_low_reg_operand" ""))] + "(REGNO (operands[0]) != REGNO (operands[4]))" + "addi3\\t%2,%1,%0\\n||\\tsti\\t%4,%3") + +(define_peephole + [(parallel [(set (reg:CC_NOOV 21) + (compare:CC_NOOV (plus:QI (match_operand:QI 1 "par_ind_operand" "") + (match_operand:QI 2 "ext_low_reg_operand" "")) + (const_int 0))) + (set (match_operand:QI 0 "ext_low_reg_operand" "") + (plus:QI (match_dup 1) (match_dup 2)))]) + (set (match_operand:QI 3 "par_ind_operand" "") + (match_operand:QI 4 "ext_low_reg_operand" ""))] + "(REGNO (operands[0]) != REGNO (operands[4]))" + "addi3\\t%2,%1,%0\\n||\\tsti\\t%4,%3") + +(define_peephole + [(parallel [(set (match_operand:QI 0 "ext_low_reg_operand" "") + (plus:QI (match_operand:QI 1 "ext_low_reg_operand" "") + (match_operand:QI 2 "par_ind_operand" ""))) + (clobber (reg:CC_NOOV 21))]) + (set (match_operand:QI 3 "par_ind_operand" "") + (match_operand:QI 4 "ext_low_reg_operand" ""))] + "(REGNO (operands[0]) != REGNO (operands[4]))" + "addi3\\t%2,%1,%0\\n||\\tsti\\t%4,%3") + +(define_peephole + [(parallel [(set (match_operand:QI 0 "ext_low_reg_operand" "") + (plus:QI (match_operand:QI 1 "par_ind_operand" "") + (match_operand:QI 2 "ext_low_reg_operand" ""))) + (clobber (reg:CC_NOOV 21))]) + (set (match_operand:QI 3 "par_ind_operand" "") + (match_operand:QI 4 "ext_low_reg_operand" ""))] + "(REGNO (operands[0]) != REGNO (operands[4]))" + "addi3\\t%2,%1,%0\\n||\\tsti\\t%4,%3") + +(define_peephole + [(parallel [(set (reg:CC_NOOV 21) + (compare:CC_NOOV (plus:QF (match_operand:QF 1 "ext_low_reg_operand" "") + (match_operand:QF 2 "par_ind_operand" "")) + (match_operand:QF 3 "fp_zero_operand" ""))) + (set (match_operand:QF 0 "ext_low_reg_operand" "") + (plus:QF (match_dup 1) (match_dup 2)))]) + (set (match_operand:QF 4 "par_ind_operand" "") + (match_operand:QF 5 "ext_low_reg_operand" ""))] + "(REGNO (operands[0]) != REGNO (operands[5]))" + "addf3\\t%2,%1,%0\\n||\\tstf\\t%5,%4") + +(define_peephole + [(parallel [(set (reg:CC_NOOV 21) + (compare:CC_NOOV (plus:QF (match_operand:QF 1 "par_ind_operand" "") + (match_operand:QF 2 "ext_low_reg_operand" "")) + (match_operand:QF 3 "fp_zero_operand" ""))) + (set (match_operand:QF 0 "ext_low_reg_operand" "") + (plus:QF (match_dup 1) (match_dup 2)))]) + (set (match_operand:QF 4 "par_ind_operand" "") + (match_operand:QF 5 "ext_low_reg_operand" ""))] + "(REGNO (operands[0]) != REGNO (operands[5]))" + "addf3\\t%2,%1,%0\\n||\\tstf\\t%5,%4") + +(define_peephole + [(parallel [(set (match_operand:QF 0 "ext_low_reg_operand" "") + (plus:QF (match_operand:QF 1 "ext_low_reg_operand" "") + (match_operand:QF 2 "par_ind_operand" ""))) + (clobber (reg:CC_NOOV 21))]) + (set (match_operand:QF 3 "par_ind_operand" "") + (match_operand:QF 4 "ext_low_reg_operand" ""))] + "(REGNO (operands[0]) != REGNO (operands[4]))" + "addf3\\t%2,%1,%0\\n||\\tstf\\t%4,%3") + +(define_peephole + [(parallel [(set (match_operand:QF 0 "ext_low_reg_operand" "") + (plus:QF (match_operand:QF 1 "par_ind_operand" "") + (match_operand:QF 2 "ext_low_reg_operand" ""))) + (clobber (reg:CC_NOOV 21))]) + (set (match_operand:QF 3 "par_ind_operand" "") + (match_operand:QF 4 "ext_low_reg_operand" ""))] + "(REGNO (operands[0]) != REGNO (operands[4]))" + "addf3\\t%2,%1,%0\\n||\\tstf\\t%4,%3") + +(define_peephole + [(parallel [(set (reg:CC 21) + (compare:CC (and:QI (match_operand:QI 1 "ext_low_reg_operand" "") + (match_operand:QI 2 "par_ind_operand" "")) + (const_int 0))) + (set (match_operand:QI 0 "ext_low_reg_operand" "") + (and:QI (match_dup 1) (match_dup 2)))]) + (set (match_operand:QI 3 "par_ind_operand" "") + (match_operand:QI 4 "ext_low_reg_operand" ""))] + "(REGNO (operands[0]) != REGNO (operands[4]))" + "and3\\t%2,%1,%0\\n||\\tsti\\t%4,%3") + +(define_peephole + [(parallel [(set (reg:CC 21) + (compare:CC (and:QI (match_operand:QI 1 "par_ind_operand" "") + (match_operand:QI 2 "ext_low_reg_operand" "")) + (const_int 0))) + (set (match_operand:QI 0 "ext_low_reg_operand" "") + (and:QI (match_dup 1) (match_dup 2)))]) + (set (match_operand:QI 3 "par_ind_operand" "") + (match_operand:QI 4 "ext_low_reg_operand" ""))] + "(REGNO (operands[0]) != REGNO (operands[4]))" + "and3\\t%2,%1,%0\\n||\\tsti\\t%4,%3") + +(define_peephole + [(parallel [(set (match_operand:QI 0 "ext_low_reg_operand" "") + (and:QI (match_operand:QI 1 "ext_low_reg_operand" "") + (match_operand:QI 2 "par_ind_operand" ""))) + (clobber (reg:CC 21))]) + (set (match_operand:QI 3 "par_ind_operand" "") + (match_operand:QI 4 "ext_low_reg_operand" ""))] + "(REGNO (operands[0]) != REGNO (operands[4]))" + "and3\\t%2,%1,%0\\n||\\tsti\\t%4,%3") + +(define_peephole + [(parallel [(set (match_operand:QI 0 "ext_low_reg_operand" "") + (and:QI (match_operand:QI 1 "par_ind_operand" "") + (match_operand:QI 2 "ext_low_reg_operand" ""))) + (clobber (reg:CC 21))]) + (set (match_operand:QI 3 "par_ind_operand" "") + (match_operand:QI 4 "ext_low_reg_operand" ""))] + "(REGNO (operands[0]) != REGNO (operands[4]))" + "and3\\t%2,%1,%0\\n||\\tsti\\t%4,%3") + +(define_peephole + [(parallel [(set (match_operand:QI 0 "ext_low_reg_operand" "") + (ashift:QI (match_operand:QI 1 "par_ind_operand" "") + (match_operand:QI 2 "ext_low_reg_operand" ""))) + (clobber (reg:CC 21))]) + (set (match_operand:QI 3 "par_ind_operand" "") + (match_operand:QI 4 "ext_low_reg_operand" ""))] + "(REGNO (operands[0]) != REGNO (operands[4]))" + "ash3\\t%2,%1,%0\\n||\\tsti\\t%4,%3") + +(define_peephole + [(parallel [(set (match_operand:QI 0 "ext_low_reg_operand" "") + (ashiftrt:QI (match_operand:QI 1 "par_ind_operand" "") + (neg:QI (match_operand:QI 2 "ext_low_reg_operand" "")))) + (clobber (reg:CC 21))]) + (set (match_operand:QI 3 "par_ind_operand" "") + (match_operand:QI 4 "ext_low_reg_operand" ""))] + "(REGNO (operands[0]) != REGNO (operands[4]))" + "ash3\\t%2,%1,%0\\n||\\tsti\\t%4,%3") + +(define_peephole + [(parallel [(set (reg:CC 21) + (compare:CC (fix:QI (match_operand:QF 1 "par_ind_operand" "")) + (const_int 0))) + (set (match_operand:QI 0 "ext_low_reg_operand" "") + (fix:QI (match_dup 1)))]) + (set (match_operand:QI 2 "par_ind_operand" "") + (match_operand:QI 3 "ext_low_reg_operand" ""))] + "(REGNO (operands[0]) != REGNO (operands[3]))" + "fix\\t%1,%0\\n||\\tsti\\t%3,%2") + +(define_peephole + [(parallel [(set (match_operand:QI 0 "ext_low_reg_operand" "") + (fix:QI (match_operand:QF 1 "par_ind_operand" ""))) + (clobber (reg:CC 21))]) + (set (match_operand:QI 2 "par_ind_operand" "") + (match_operand:QI 3 "ext_low_reg_operand" ""))] + "(REGNO (operands[0]) != REGNO (operands[3]))" + "fix\\t%1,%0\\n||\\tsti\\t%3,%2") + +(define_peephole + [(parallel [(set (reg:CC 21) + (compare:CC (float:QF (match_operand:QI 1 "par_ind_operand" "")) + (match_operand:QF 2 "fp_zero_operand" ""))) + (set (match_operand:QF 0 "ext_low_reg_operand" "") + (float:QF (match_dup 1)))]) + (set (match_operand:QF 3 "par_ind_operand" "") + (match_operand:QF 4 "ext_low_reg_operand" ""))] + "(REGNO (operands[0]) != REGNO (operands[4]))" + "float\\t%1,%0\\n||\\tstf\\t%4,%3") + +(define_peephole + [(parallel [(set (match_operand:QF 0 "ext_low_reg_operand" "") + (float:QF (match_operand:QI 1 "par_ind_operand" ""))) + (clobber (reg:CC 21))]) + (set (match_operand:QF 2 "par_ind_operand" "") + (match_operand:QF 3 "ext_low_reg_operand" ""))] + "(REGNO (operands[0]) != REGNO (operands[3]))" + "float\\t%1,%0\\n||\\tstf\\t%3,%2") + +(define_peephole + [(parallel [(set (reg:CC_NOOV 21) + (compare:CC_NOOV (mult:QI (match_operand:QI 1 "ext_low_reg_operand" "") + (match_operand:QI 2 "par_ind_operand" "")) + (const_int 0))) + (set (match_operand:QI 0 "ext_low_reg_operand" "") + (mult:QI (match_dup 1) (match_dup 2)))]) + (set (match_operand:QI 3 "par_ind_operand" "") + (match_operand:QI 4 "ext_low_reg_operand" ""))] + "(REGNO (operands[0]) != REGNO (operands[4]))" + "mpyi3\\t%2,%1,%0\\n||\\tsti\\t%4,%3") + +(define_peephole + [(parallel [(set (reg:CC_NOOV 21) + (compare:CC_NOOV (mult:QI (match_operand:QI 1 "par_ind_operand" "") + (match_operand:QI 2 "ext_low_reg_operand" "")) + (const_int 0))) + (set (match_operand:QI 0 "ext_low_reg_operand" "") + (mult:QI (match_dup 1) (match_dup 2)))]) + (set (match_operand:QI 3 "par_ind_operand" "") + (match_operand:QI 4 "ext_low_reg_operand" ""))] + "(REGNO (operands[0]) != REGNO (operands[4]))" + "mpyi3\\t%2,%1,%0\\n||\\tsti\\t%4,%3") + +(define_peephole + [(parallel [(set (match_operand:QI 0 "ext_low_reg_operand" "") + (mult:QI (match_operand:QI 1 "ext_low_reg_operand" "") + (match_operand:QI 2 "par_ind_operand" ""))) + (clobber (reg:CC 21))]) + (set (match_operand:QI 3 "par_ind_operand" "") + (match_operand:QI 4 "ext_low_reg_operand" ""))] + "(REGNO (operands[0]) != REGNO (operands[4]))" + "mpyi3\\t%2,%1,%0\\n||\\tsti\\t%4,%3") + +(define_peephole + [(parallel [(set (match_operand:QI 0 "ext_low_reg_operand" "") + (mult:QI (match_operand:QI 1 "par_ind_operand" "") + (match_operand:QI 2 "ext_low_reg_operand" ""))) + (clobber (reg:CC 21))]) + (set (match_operand:QI 3 "par_ind_operand" "") + (match_operand:QI 4 "ext_low_reg_operand" ""))] + "(REGNO (operands[0]) != REGNO (operands[4]))" + "mpyi3\\t%2,%1,%0\\n||\\tsti\\t%4,%3") + +(define_peephole + [(parallel [(set (reg:CC_NOOV 21) + (compare:CC_NOOV (mult:QF (match_operand:QF 1 "ext_low_reg_operand" "") + (match_operand:QF 2 "par_ind_operand" "")) + (match_operand:QF 3 "fp_zero_operand" ""))) + (set (match_operand:QF 0 "ext_low_reg_operand" "") + (mult:QF (match_dup 1) (match_dup 2)))]) + (set (match_operand:QF 4 "par_ind_operand" "") + (match_operand:QF 5 "ext_low_reg_operand" ""))] + "(REGNO (operands[0]) != REGNO (operands[5]))" + "mpyf3\\t%2,%1,%0\\n||\\tstf\\t%5,%4") + +(define_peephole + [(parallel [(set (reg:CC_NOOV 21) + (compare:CC_NOOV (mult:QF (match_operand:QF 1 "par_ind_operand" "") + (match_operand:QF 2 "ext_low_reg_operand" "")) + (match_operand:QF 3 "fp_zero_operand" ""))) + (set (match_operand:QF 0 "ext_low_reg_operand" "") + (mult:QF (match_dup 1) (match_dup 2)))]) + (set (match_operand:QF 4 "par_ind_operand" "") + (match_operand:QF 5 "ext_low_reg_operand" ""))] + "(REGNO (operands[0]) != REGNO (operands[5]))" + "mpyf3\\t%2,%1,%0\\n||\\tstf\\t%5,%4") + +(define_peephole + [(parallel [(set (match_operand:QF 0 "ext_low_reg_operand" "") + (mult:QF (match_operand:QF 1 "ext_low_reg_operand" "") + (match_operand:QF 2 "par_ind_operand" ""))) + (clobber (reg:CC 21))]) + (set (match_operand:QF 3 "par_ind_operand" "") + (match_operand:QF 4 "ext_low_reg_operand" ""))] + "(REGNO (operands[0]) != REGNO (operands[4]))" + "mpyf3\\t%2,%1,%0\\n||\\tstf\\t%4,%3") + +(define_peephole + [(parallel [(set (match_operand:QF 0 "ext_low_reg_operand" "") + (mult:QF (match_operand:QF 1 "par_ind_operand" "") + (match_operand:QF 2 "ext_low_reg_operand" ""))) + (clobber (reg:CC 21))]) + (set (match_operand:QF 3 "par_ind_operand" "") + (match_operand:QF 4 "ext_low_reg_operand" ""))] + "(REGNO (operands[0]) != REGNO (operands[4]))" + "mpyf3\\t%2,%1,%0\\n||\\tstf\\t%4,%3") + +(define_peephole + [(parallel [(set (reg:CC_NOOV 21) + (compare:CC_NOOV (neg:QF (match_operand:QF 1 "par_ind_operand" "")) + (match_operand:QF 2 "fp_zero_operand" ""))) + (set (match_operand:QF 0 "ext_low_reg_operand" "") + (neg:QF (match_dup 1)))]) + (set (match_operand:QF 3 "par_ind_operand" "") + (match_operand:QF 4 "ext_low_reg_operand" ""))] + "(REGNO (operands[0]) != REGNO (operands[4]))" + "negf\\t%1,%0\\n||\\tstf\\t%4,%3") + +(define_peephole + [(parallel [(set (match_operand:QF 0 "ext_low_reg_operand" "") + (neg:QF (match_operand:QF 1 "par_ind_operand" ""))) + (clobber (reg:CC_NOOV 21))]) + (set (match_operand:QF 2 "par_ind_operand" "") + (match_operand:QF 3 "ext_low_reg_operand" ""))] + "(REGNO (operands[0]) != REGNO (operands[3]))" + "negf\\t%1,%0\\n||\\tstf\\t%3,%2") + +(define_peephole + [(parallel [(set (reg:CC_NOOV 21) + (compare:CC_NOOV (neg:QI (match_operand:QI 1 "par_ind_operand" "")) + (const_int 0))) + (set (match_operand:QI 0 "ext_low_reg_operand" "") + (neg:QI (match_dup 1)))]) + (set (match_operand:QI 2 "par_ind_operand" "") + (match_operand:QI 3 "ext_low_reg_operand" ""))] + "(REGNO (operands[0]) != REGNO (operands[3]))" + "negi\\t%1,%0\\n||\\tsti\\t%3,%2") + +(define_peephole + [(parallel [(set (match_operand:QI 0 "ext_low_reg_operand" "") + (neg:QI (match_operand:QI 1 "par_ind_operand" ""))) + (clobber (reg:CC_NOOV 21))]) + (set (match_operand:QI 2 "par_ind_operand" "") + (match_operand:QI 3 "ext_low_reg_operand" ""))] + "(REGNO (operands[0]) != REGNO (operands[3]))" + "negi\\t%1,%0\\n||\\tsti\\t%3,%2") + +(define_peephole + [(parallel [(set (reg:CC 21) + (compare:CC (not:QI (match_operand:QI 1 "par_ind_operand" "")) + (const_int 0))) + (set (match_operand:QI 0 "ext_low_reg_operand" "") + (not:QI (match_dup 1)))]) + (set (match_operand:QI 2 "par_ind_operand" "") + (match_operand:QI 3 "ext_low_reg_operand" ""))] + "(REGNO (operands[0]) != REGNO (operands[3]))" + "not\\t%1,%0\\n||\\tsti\\t%3,%2") + +(define_peephole + [(parallel [(set (match_operand:QI 0 "ext_low_reg_operand" "") + (not:QI (match_operand:QI 1 "par_ind_operand" ""))) + (clobber (reg:CC 21))]) + (set (match_operand:QI 2 "par_ind_operand" "") + (match_operand:QI 3 "ext_low_reg_operand" ""))] + "(REGNO (operands[0]) != REGNO (operands[3]))" + "not\\t%1,%0\\n||\\tsti\\t%3,%2") + +(define_peephole + [(parallel [(set (reg:CC 21) + (compare:CC (ior:QI (match_operand:QI 1 "ext_low_reg_operand" "") + (match_operand:QI 2 "par_ind_operand" "")) + (const_int 0))) + (set (match_operand:QI 0 "ext_low_reg_operand" "") + (ior:QI (match_dup 1) (match_dup 2)))]) + (set (match_operand:QI 3 "par_ind_operand" "") + (match_operand:QI 4 "ext_low_reg_operand" ""))] + "(REGNO (operands[0]) != REGNO (operands[4]))" + "or3\\t%2,%1,%0\\n||\\tsti\\t%4,%3") + +(define_peephole + [(parallel [(set (reg:CC 21) + (compare:CC (ior:QI (match_operand:QI 1 "par_ind_operand" "") + (match_operand:QI 2 "ext_low_reg_operand" "")) + (const_int 0))) + (set (match_operand:QI 0 "ext_low_reg_operand" "") + (ior:QI (match_dup 1) (match_dup 2)))]) + (set (match_operand:QI 3 "par_ind_operand" "") + (match_operand:QI 4 "ext_low_reg_operand" ""))] + "(REGNO (operands[0]) != REGNO (operands[4]))" + "or3\\t%2,%1,%0\\n||\\tsti\\t%4,%3") + +(define_peephole + [(parallel [(set (match_operand:QI 0 "ext_low_reg_operand" "") + (ior:QI (match_operand:QI 1 "ext_low_reg_operand" "") + (match_operand:QI 2 "par_ind_operand" ""))) + (clobber (reg:CC 21))]) + (set (match_operand:QI 3 "par_ind_operand" "") + (match_operand:QI 4 "ext_low_reg_operand" ""))] + "(REGNO (operands[0]) != REGNO (operands[4]))" + "or3\\t%2,%1,%0\\n||\\tsti\\t%4,%3") + +(define_peephole + [(parallel [(set (match_operand:QI 0 "ext_low_reg_operand" "") + (ior:QI (match_operand:QI 1 "par_ind_operand" "") + (match_operand:QI 2 "ext_low_reg_operand" ""))) + (clobber (reg:CC 21))]) + (set (match_operand:QI 3 "par_ind_operand" "") + (match_operand:QI 4 "ext_low_reg_operand" ""))] + "(REGNO (operands[0]) != REGNO (operands[4]))" + "or3\\t%2,%1,%0\\n||\\tsti\\t%4,%3") + +(define_peephole + [(parallel [(set (reg:CC_NOOV 21) + (compare:CC_NOOV (minus:QI (match_operand:QI 1 "ext_low_reg_operand" "") + (match_operand:QI 2 "par_ind_operand" "")) + (const_int 0))) + (set (match_operand:QI 0 "ext_low_reg_operand" "") + (minus:QI (match_dup 1) (match_dup 2)))]) + (set (match_operand:QI 3 "par_ind_operand" "") + (match_operand:QI 4 "ext_low_reg_operand" ""))] + "(REGNO (operands[0]) != REGNO (operands[4]))" + "subi3\\t%2,%1,%0\\n||\\tsti\\t%4,%3") + +(define_peephole + [(parallel [(set (match_operand:QI 0 "ext_low_reg_operand" "") + (minus:QI (match_operand:QI 1 "ext_low_reg_operand" "") + (match_operand:QI 2 "par_ind_operand" ""))) + (clobber (reg:CC_NOOV 21))]) + (set (match_operand:QI 3 "par_ind_operand" "") + (match_operand:QI 4 "ext_low_reg_operand" ""))] + "(REGNO (operands[0]) != REGNO (operands[4]))" + "subi3\\t%2,%1,%0\\n||\\tsti\\t%4,%3") + +(define_peephole + [(parallel [(set (reg:CC_NOOV 21) + (compare:CC_NOOV (minus:QF (match_operand:QF 1 "ext_low_reg_operand" "") + (match_operand:QF 2 "par_ind_operand" "")) + (match_operand:QF 3 "fp_zero_operand" ""))) + (set (match_operand:QF 0 "ext_low_reg_operand" "") + (minus:QF (match_dup 1) (match_dup 2)))]) + (set (match_operand:QF 4 "par_ind_operand" "") + (match_operand:QF 5 "ext_low_reg_operand" ""))] + "(REGNO (operands[0]) != REGNO (operands[5]))" + "subf3\\t%2,%1,%0\\n||\\tstf\\t%5,%4") + +(define_peephole + [(parallel [(set (match_operand:QF 0 "ext_low_reg_operand" "") + (minus:QF (match_operand:QF 1 "ext_low_reg_operand" "") + (match_operand:QF 2 "par_ind_operand" ""))) + (clobber (reg:CC_NOOV 21))]) + (set (match_operand:QF 3 "par_ind_operand" "") + (match_operand:QF 4 "ext_low_reg_operand" ""))] + "(REGNO (operands[0]) != REGNO (operands[4]))" + "subf3\\t%2,%1,%0\\n||\\tstf\\t%4,%3") + +(define_peephole + [(parallel [(set (reg:CC 21) + (compare:CC (xor:QI (match_operand:QI 1 "ext_low_reg_operand" "") + (match_operand:QI 2 "par_ind_operand" "")) + (const_int 0))) + (set (match_operand:QI 0 "ext_low_reg_operand" "") + (xor:QI (match_dup 1) (match_dup 2)))]) + (set (match_operand:QI 3 "par_ind_operand" "") + (match_operand:QI 4 "ext_low_reg_operand" ""))] + "(REGNO (operands[0]) != REGNO (operands[4]))" + "xor3\\t%2,%1,%0\\n||\\tsti\\t%4,%3") + +(define_peephole + [(parallel [(set (reg:CC 21) + (compare:CC (xor:QI (match_operand:QI 1 "par_ind_operand" "") + (match_operand:QI 2 "ext_low_reg_operand" "")) + (const_int 0))) + (set (match_operand:QI 0 "ext_low_reg_operand" "") + (xor:QI (match_dup 1) (match_dup 2)))]) + (set (match_operand:QI 3 "par_ind_operand" "") + (match_operand:QI 4 "ext_low_reg_operand" ""))] + "(REGNO (operands[0]) != REGNO (operands[4]))" + "xor3\\t%2,%1,%0\\n||\\tsti\\t%4,%3") + +(define_peephole + [(parallel [(set (match_operand:QI 0 "ext_low_reg_operand" "") + (xor:QI (match_operand:QI 1 "ext_low_reg_operand" "") + (match_operand:QI 2 "par_ind_operand" ""))) + (clobber (reg:CC 21))]) + (set (match_operand:QI 3 "par_ind_operand" "") + (match_operand:QI 4 "ext_low_reg_operand" ""))] + "(REGNO (operands[0]) != REGNO (operands[4]))" + "xor3\\t%2,%1,%0\\n||\\tsti\\t%4,%3") + +(define_peephole + [(parallel [(set (match_operand:QI 0 "ext_low_reg_operand" "") + (xor:QI (match_operand:QI 1 "par_ind_operand" "") + (match_operand:QI 2 "ext_low_reg_operand" ""))) + (clobber (reg:CC 21))]) + (set (match_operand:QI 3 "par_ind_operand" "") + (match_operand:QI 4 "ext_low_reg_operand" ""))] + "(REGNO (operands[0]) != REGNO (operands[4]))" + "xor3\\t%2,%1,%0\\n||\\tsti\\t%4,%3") + + |