;;- Machine description for GNU compiler -- S/390 / zSeries version.
;; Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
;; 2009, 2010 Free Software Foundation, Inc.
;; Contributed by Hartmut Penner (hpenner@de.ibm.com) and
;; Ulrich Weigand (uweigand@de.ibm.com) and
;; Andreas Krebbel (Andreas.Krebbel@de.ibm.com)
;; This file is part of GCC.
;; GCC is free software; you can redistribute it and/or modify it under
;; the terms of the GNU General Public License as published by the Free
;; Software Foundation; either version 3, or (at your option) any later
;; version.
;; GCC is distributed in the hope that it will be useful, but WITHOUT ANY
;; WARRANTY; without even the implied warranty of MERCHANTABILITY or
;; FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
;; for more details.
;; You should have received a copy of the GNU General Public License
;; along with GCC; see the file COPYING3. If not see
;; .
;;
;; See constraints.md for a description of constraints specific to s390.
;;
;; Special formats used for outputting 390 instructions.
;;
;; %C: print opcode suffix for branch condition.
;; %D: print opcode suffix for inverse branch condition.
;; %J: print tls_load/tls_gdcall/tls_ldcall suffix
;; %G: print the size of the operand in bytes.
;; %O: print only the displacement of a memory reference.
;; %R: print only the base register of a memory reference.
;; %S: print S-type memory reference (base+displacement).
;; %N: print the second word of a DImode operand.
;; %M: print the second word of a TImode operand.
;; %Y: print shift count operand.
;;
;; %b: print integer X as if it's an unsigned byte.
;; %c: print integer X as if it's an signed byte.
;; %x: print integer X as if it's an unsigned halfword.
;; %h: print integer X as if it's a signed halfword.
;; %i: print the first nonzero HImode part of X.
;; %j: print the first HImode part unequal to -1 of X.
;; %k: print the first nonzero SImode part of X.
;; %m: print the first SImode part unequal to -1 of X.
;; %o: print integer X as if it's an unsigned 32bit word.
;;
;; We have a special constraint for pattern matching.
;;
;; s_operand -- Matches a valid S operand in a RS, SI or SS type instruction.
;;
;;
;; UNSPEC usage
;;
(define_constants
[; Miscellaneous
(UNSPEC_ROUND 1)
(UNSPEC_CCU_TO_INT 2)
(UNSPEC_CCZ_TO_INT 3)
(UNSPEC_ICM 10)
(UNSPEC_TIE 11)
; GOT/PLT and lt-relative accesses
(UNSPEC_LTREL_OFFSET 100)
(UNSPEC_LTREL_BASE 101)
(UNSPEC_POOL_OFFSET 102)
(UNSPEC_GOTENT 110)
(UNSPEC_GOT 111)
(UNSPEC_GOTOFF 112)
(UNSPEC_PLT 113)
(UNSPEC_PLTOFF 114)
; Literal pool
(UNSPEC_RELOAD_BASE 210)
(UNSPEC_MAIN_BASE 211)
(UNSPEC_LTREF 212)
(UNSPEC_INSN 213)
(UNSPEC_EXECUTE 214)
; Atomic Support
(UNSPEC_MB 400)
; TLS relocation specifiers
(UNSPEC_TLSGD 500)
(UNSPEC_TLSLDM 501)
(UNSPEC_NTPOFF 502)
(UNSPEC_DTPOFF 503)
(UNSPEC_GOTNTPOFF 504)
(UNSPEC_INDNTPOFF 505)
; TLS support
(UNSPEC_TLSLDM_NTPOFF 511)
(UNSPEC_TLS_LOAD 512)
; String Functions
(UNSPEC_SRST 600)
(UNSPEC_MVST 601)
; Stack Smashing Protector
(UNSPEC_SP_SET 700)
(UNSPEC_SP_TEST 701)
; Test Data Class (TDC)
(UNSPEC_TDC_INSN 800)
; Population Count
(UNSPEC_POPCNT 900)
(UNSPEC_COPYSIGN 901)
])
;;
;; UNSPEC_VOLATILE usage
;;
(define_constants
[; Blockage
(UNSPECV_BLOCKAGE 0)
; TPF Support
(UNSPECV_TPF_PROLOGUE 20)
(UNSPECV_TPF_EPILOGUE 21)
; Literal pool
(UNSPECV_POOL 200)
(UNSPECV_POOL_SECTION 201)
(UNSPECV_POOL_ALIGN 202)
(UNSPECV_POOL_ENTRY 203)
(UNSPECV_MAIN_POOL 300)
; TLS support
(UNSPECV_SET_TP 500)
; Atomic Support
(UNSPECV_CAS 700)
(UNSPECV_ATOMIC_OP 701)
])
;;
;; Registers
;;
; Registers with special meaning
(define_constants
[
; Sibling call register.
(SIBCALL_REGNUM 1)
; Literal pool base register.
(BASE_REGNUM 13)
; Return address register.
(RETURN_REGNUM 14)
; Condition code register.
(CC_REGNUM 33)
; Thread local storage pointer register.
(TP_REGNUM 36)
])
; Hardware register names
(define_constants
[
; General purpose registers
(GPR0_REGNUM 0)
; Floating point registers.
(FPR0_REGNUM 16)
(FPR2_REGNUM 18)
])
;;
;; PFPO GPR0 argument format
;;
(define_constants
[
; PFPO operation type
(PFPO_CONVERT 0x1000000)
; PFPO operand types
(PFPO_OP_TYPE_SF 0x5)
(PFPO_OP_TYPE_DF 0x6)
(PFPO_OP_TYPE_TF 0x7)
(PFPO_OP_TYPE_SD 0x8)
(PFPO_OP_TYPE_DD 0x9)
(PFPO_OP_TYPE_TD 0xa)
; Bitposition of operand types
(PFPO_OP0_TYPE_SHIFT 16)
(PFPO_OP1_TYPE_SHIFT 8)
])
;; Instruction operand type as used in the Principles of Operation.
;; Used to determine defaults for length and other attribute values.
(define_attr "op_type"
"NN,E,RR,RRE,RX,RS,RSI,RI,SI,S,SS,SSE,RXE,RSE,RIL,RIE,RXY,RSY,SIY,RRF,RRR,SIL,RRS,RIS"
(const_string "NN"))
;; Instruction type attribute used for scheduling.
(define_attr "type" "none,integer,load,lr,la,larl,lm,stm,
cs,vs,store,sem,idiv,
imulhi,imulsi,imuldi,
branch,jsr,fsimptf,fsimpdf,fsimpsf,fhex,
floadtf,floaddf,floadsf,fstoredf,fstoresf,
fmultf,fmuldf,fmulsf,fdivtf,fdivdf,fdivsf,
ftoi,fsqrttf,fsqrtdf,fsqrtsf,
fmadddf,fmaddsf,
ftrunctf,ftruncdf, ftruncsd, ftruncdd,
itoftf, itofdf, itofsf, itofdd, itoftd,
fdivdd, fdivtd, floaddd, floadsd, fmuldd, fmultd,
fsimpdd, fsimpsd, fsimptd, fstoredd, fstoresd,
ftoidfp, other"
(cond [(eq_attr "op_type" "NN") (const_string "other")
(eq_attr "op_type" "SS") (const_string "cs")]
(const_string "integer")))
;; Another attribute used for scheduling purposes:
;; agen: Instruction uses the address generation unit
;; reg: Instruction does not use the agen unit
(define_attr "atype" "agen,reg"
(if_then_else (eq_attr "op_type" "E,RR,RI,RRE,RSI,RIL,RIE,RRF,RRR")
(const_string "reg")
(const_string "agen")))
;; Properties concerning Z10 execution grouping and value forwarding.
;; z10_super: instruction is superscalar.
;; z10_super_c: instruction is superscalar and meets the condition of z10_c.
;; z10_fwd: The instruction reads the value of an operand and stores it into a
;; target register. It can forward this value to a second instruction that reads
;; the same register if that second instruction is issued in the same group.
;; z10_rec: The instruction is in the T pipeline and reads a register. If the
;; instruction in the S pipe writes to the register, then the T instruction
;; can immediately read the new value.
;; z10_fr: union of Z10_fwd and z10_rec.
;; z10_c: second operand of instruction is a register and read with complemented bits.
;;
;; An additional suffix A1, A3, or E1 indicates the respective AGI bypass.
(define_attr "z10prop" "none,
z10_super, z10_super_E1, z10_super_A1, z10_super_c, z10_super_c_E1,
z10_fwd, z10_fwd_A1, z10_fwd_A3, z10_fwd_E1,
z10_rec,
z10_fr, z10_fr_A3, z10_fr_E1,
z10_c"
(const_string "none"))
;; Properties concerning Z196 decoding
;; z196_alone: must group alone
;; z196_end: ends a group
;; z196_cracked: instruction is cracked or expanded
(define_attr "z196prop" "none,
z196_alone, z196_ends,
z196_cracked"
(const_string "none"))
;; Length in bytes.
(define_attr "length" ""
(cond [(eq_attr "op_type" "E,RR") (const_int 2)
(eq_attr "op_type" "RX,RI,RRE,RS,RSI,S,SI,RRF,RRR") (const_int 4)]
(const_int 6)))
;; Processor type. This attribute must exactly match the processor_type
;; enumeration in s390.h. The current machine description does not
;; distinguish between g5 and g6, but there are differences between the two
;; CPUs could in theory be modeled.
(define_attr "cpu" "g5,g6,z900,z990,z9_109,z10,z196"
(const (symbol_ref "s390_tune_attr")))
(define_attr "cpu_facility" "standard,ieee,zarch,longdisp,extimm,dfp,z10,z196"
(const_string "standard"))
(define_attr "enabled" ""
(cond [(eq_attr "cpu_facility" "standard")
(const_int 1)
(and (eq_attr "cpu_facility" "ieee")
(ne (symbol_ref "TARGET_CPU_IEEE_FLOAT") (const_int 0)))
(const_int 1)
(and (eq_attr "cpu_facility" "zarch")
(ne (symbol_ref "TARGET_ZARCH") (const_int 0)))
(const_int 1)
(and (eq_attr "cpu_facility" "longdisp")
(ne (symbol_ref "TARGET_LONG_DISPLACEMENT") (const_int 0)))
(const_int 1)
(and (eq_attr "cpu_facility" "extimm")
(ne (symbol_ref "TARGET_EXTIMM") (const_int 0)))
(const_int 1)
(and (eq_attr "cpu_facility" "dfp")
(ne (symbol_ref "TARGET_DFP") (const_int 0)))
(const_int 1)
(and (eq_attr "cpu_facility" "z10")
(ne (symbol_ref "TARGET_Z10") (const_int 0)))
(const_int 1)
(and (eq_attr "cpu_facility" "z196")
(ne (symbol_ref "TARGET_Z196") (const_int 0)))
(const_int 1)]
(const_int 0)))
;; Pipeline description for z900. For lack of anything better,
;; this description is also used for the g5 and g6.
(include "2064.md")
;; Pipeline description for z990, z9-109 and z9-ec.
(include "2084.md")
;; Pipeline description for z10
(include "2097.md")
;; Pipeline description for z196
(include "2817.md")
;; Predicates
(include "predicates.md")
;; Constraint definitions
(include "constraints.md")
;; Other includes
(include "tpf.md")
;; Iterators
;; These mode iterators allow floating point patterns to be generated from the
;; same template.
(define_mode_iterator FP_ALL [TF DF SF (TD "TARGET_HARD_DFP") (DD "TARGET_HARD_DFP")
(SD "TARGET_HARD_DFP")])
(define_mode_iterator FP [TF DF SF (TD "TARGET_HARD_DFP") (DD "TARGET_HARD_DFP")])
(define_mode_iterator FPALL [TF DF SF TD DD SD])
(define_mode_iterator BFP [TF DF SF])
(define_mode_iterator DFP [TD DD])
(define_mode_iterator DFP_ALL [TD DD SD])
(define_mode_iterator DSF [DF SF])
(define_mode_iterator SD_SF [SF SD])
(define_mode_iterator DD_DF [DF DD])
(define_mode_iterator TD_TF [TF TD])
;; This mode iterator allows 31-bit and 64-bit TDSI patterns to be generated
;; from the same template.
(define_mode_iterator TDSI [(TI "TARGET_64BIT") DI SI])
;; These mode iterators allow 31-bit and 64-bit GPR patterns to be generated
;; from the same template.
(define_mode_iterator GPR [(DI "TARGET_ZARCH") SI])
(define_mode_iterator DSI [DI SI])
;; These mode iterators allow :P to be used for patterns that operate on
;; pointer-sized quantities. Exactly one of the two alternatives will match.
(define_mode_iterator P [(DI "TARGET_64BIT") (SI "!TARGET_64BIT")])
;; These macros refer to the actual word_mode of the configuration. This is equal
;; to Pmode except on 31-bit machines in zarch mode.
(define_mode_iterator DW [(TI "TARGET_ZARCH") (DI "!TARGET_ZARCH")])
(define_mode_iterator W [(DI "TARGET_ZARCH") (SI "!TARGET_ZARCH")])
;; This mode iterator allows the QI and HI patterns to be defined from
;; the same template.
(define_mode_iterator HQI [HI QI])
;; This mode iterator allows the integer patterns to be defined from the
;; same template.
(define_mode_iterator INT [(DI "TARGET_ZARCH") SI HI QI])
(define_mode_iterator INTALL [TI DI SI HI QI])
;; This iterator allows some 'ashift' and 'lshiftrt' pattern to be defined from
;; the same template.
(define_code_iterator SHIFT [ashift lshiftrt])
;; This iterator and attribute allow to combine most atomic operations.
(define_code_iterator ATOMIC [and ior xor plus minus mult])
(define_code_iterator ATOMIC_Z196 [and ior xor plus])
(define_code_attr atomic [(and "and") (ior "ior") (xor "xor")
(plus "add") (minus "sub") (mult "nand")])
(define_code_attr noxa [(and "n") (ior "o") (xor "x") (plus "a")])
;; In FP templates, a string like "ltbr" will expand to "ltxbr" in
;; TF/TDmode, "ltdbr" in DF/DDmode, and "ltebr" in SF/SDmode.
(define_mode_attr xde [(TF "x") (DF "d") (SF "e") (TD "x") (DD "d") (SD "e")])
;; In FP templates, a in "mr" will expand to "mxr" in
;; TF/TDmode, "mdr" in DF/DDmode, "meer" in SFmode and "mer in
;; SDmode.
(define_mode_attr xdee [(TF "x") (DF "d") (SF "ee") (TD "x") (DD "d") (SD "e")])
;; In FP templates, "" will expand to "RRE" in TFmode and "RR" otherwise.
;; Likewise for "".
(define_mode_attr RRe [(TF "RRE") (DF "RR") (SF "RR")])
(define_mode_attr RXe [(TF "RXE") (DF "RX") (SF "RX")])
;; The decimal floating point variants of add, sub, div and mul support 3
;; fp register operands. The following attributes allow to merge the bfp and
;; dfp variants in a single insn definition.
;; This attribute is used to set op_type accordingly.
(define_mode_attr RRer [(TF "RRE") (DF "RRE") (SF "RRE") (TD "RRR")
(DD "RRR") (SD "RRR")])
;; This attribute is used in the operand constraint list in order to have the
;; first and the second operand match for bfp modes.
(define_mode_attr f0 [(TF "0") (DF "0") (SF "0") (TD "f") (DD "f") (DD "f")])
;; This attribute is used in the operand list of the instruction to have an
;; additional operand for the dfp instructions.
(define_mode_attr op1 [(TF "") (DF "") (SF "")
(TD "%1,") (DD "%1,") (SD "%1,")])
;; This attribute is used in the operand constraint list
;; for instructions dealing with the sign bit of 32 or 64bit fp values.
;; TFmode values are represented by a fp register pair. Since the
;; sign bit instructions only handle single source and target fp registers
;; these instructions can only be used for TFmode values if the source and
;; target operand uses the same fp register.
(define_mode_attr fT0 [(TF "0") (DF "f") (SF "f")])
;; In FP templates, "" will expand to "f" in TFmode and "R" otherwise.
;; This is used to disable the memory alternative in TFmode patterns.
(define_mode_attr Rf [(TF "f") (DF "R") (SF "R") (TD "f") (DD "f") (SD "f")])
;; This attribute adds b for bfp instructions and t for dfp instructions and is used
;; within instruction mnemonics.
(define_mode_attr bt [(TF "b") (DF "b") (SF "b") (TD "t") (DD "t") (SD "t")])
;; This attribute is used within instruction mnemonics. It evaluates to d for dfp
;; modes and to an empty string for bfp modes.
(define_mode_attr _d [(TF "") (DF "") (SF "") (TD "d") (DD "d") (SD "d")])
;; In GPR and P templates, a constraint like "" will expand to "d" in DImode
;; and "0" in SImode. This allows to combine instructions of which the 31bit
;; version only operates on one register.
(define_mode_attr d0 [(DI "d") (SI "0")])
;; In combination with d0 this allows to combine instructions of which the 31bit
;; version only operates on one register. The DImode version needs an additional
;; register for the assembler output.
(define_mode_attr 1 [(DI "%1,") (SI "")])
;; In SHIFT templates, a string like "sdl" will expand to "sldl" in
;; 'ashift' and "srdl" in 'lshiftrt'.
(define_code_attr lr [(ashift "l") (lshiftrt "r")])
;; In SHIFT templates, this attribute holds the correct standard name for the
;; pattern itself and the corresponding function calls.
(define_code_attr shift [(ashift "ashl") (lshiftrt "lshr")])
;; This attribute handles differences in the instruction 'type' and will result
;; in "RRE" for DImode and "RR" for SImode.
(define_mode_attr E [(DI "E") (SI "")])
;; This attribute handles differences in the instruction 'type' and makes RX
;; to result in "RXY" for DImode and "RX" for SImode.
(define_mode_attr Y [(DI "Y") (SI "")])
;; This attribute handles differences in the instruction 'type' and will result
;; in "RSE" for TImode and "RS" for DImode.
(define_mode_attr TE [(TI "E") (DI "")])
;; In GPR templates, a string like "lcr" will expand to "lcgr" in DImode
;; and "lcr" in SImode.
(define_mode_attr g [(DI "g") (SI "")])
;; In GPR templates, a string like "sl" will expand to "slg" in DImode
;; and "sly" in SImode. This is useful because on 64bit the ..g instructions
;; were enhanced with long displacements whereas 31bit instructions got a ..y
;; variant for long displacements.
(define_mode_attr y [(DI "g") (SI "y")])
;; In DW templates, a string like "cds" will expand to "cdsg" in TImode
;; and "cds" in DImode.
(define_mode_attr tg [(TI "g") (DI "")])
;; In GPR templates, a string like "cdbr" will expand to "cgdbr" in DImode
;; and "cfdbr" in SImode.
(define_mode_attr gf [(DI "g") (SI "f")])
;; In GPR templates, a string like sll will expand to sllg for DI
;; and sllk for SI. This way it is possible to merge the new z196 SI
;; 3 operands shift instructions into the existing patterns.
(define_mode_attr gk [(DI "g") (SI "k")])
;; ICM mask required to load MODE value into the lowest subreg
;; of a SImode register.
(define_mode_attr icm_lo [(HI "3") (QI "1")])
;; In HQI templates, a string like "llg" will expand to "llgh" in
;; HImode and "llgc" in QImode.
(define_mode_attr hc [(HI "h") (QI "c")])
;; In P templates, the mode will expand to "TI" in DImode and "DI"
;; in SImode.
(define_mode_attr DBL [(DI "TI") (SI "DI")])
;; This attribute expands to DF for TFmode and to DD for TDmode . It is
;; used for Txmode splitters splitting a Txmode copy into 2 Dxmode copies.
(define_mode_attr HALF_TMODE [(TF "DF") (TD "DD")])
;; Maximum unsigned integer that fits in MODE.
(define_mode_attr max_uint [(HI "65535") (QI "255")])
;;
;;- Compare instructions.
;;
; Test-under-Mask instructions
(define_insn "*tmqi_mem"
[(set (reg CC_REGNUM)
(compare (and:QI (match_operand:QI 0 "memory_operand" "Q,S")
(match_operand:QI 1 "immediate_operand" "n,n"))
(match_operand:QI 2 "immediate_operand" "n,n")))]
"s390_match_ccmode (insn, s390_tm_ccmode (operands[1], operands[2], false))"
"@
tm\t%S0,%b1
tmy\t%S0,%b1"
[(set_attr "op_type" "SI,SIY")
(set_attr "z10prop" "z10_super,z10_super")])
(define_insn "*tmdi_reg"
[(set (reg CC_REGNUM)
(compare (and:DI (match_operand:DI 0 "nonimmediate_operand" "d,d,d,d")
(match_operand:DI 1 "immediate_operand"
"N0HD0,N1HD0,N2HD0,N3HD0"))
(match_operand:DI 2 "immediate_operand" "n,n,n,n")))]
"TARGET_ZARCH
&& s390_match_ccmode (insn, s390_tm_ccmode (operands[1], operands[2], true))
&& s390_single_part (operands[1], DImode, HImode, 0) >= 0"
"@
tmhh\t%0,%i1
tmhl\t%0,%i1
tmlh\t%0,%i1
tmll\t%0,%i1"
[(set_attr "op_type" "RI")
(set_attr "z10prop" "z10_super,z10_super,z10_super,z10_super")])
(define_insn "*tmsi_reg"
[(set (reg CC_REGNUM)
(compare (and:SI (match_operand:SI 0 "nonimmediate_operand" "d,d")
(match_operand:SI 1 "immediate_operand" "N0HS0,N1HS0"))
(match_operand:SI 2 "immediate_operand" "n,n")))]
"s390_match_ccmode (insn, s390_tm_ccmode (operands[1], operands[2], true))
&& s390_single_part (operands[1], SImode, HImode, 0) >= 0"
"@
tmh\t%0,%i1
tml\t%0,%i1"
[(set_attr "op_type" "RI")
(set_attr "z10prop" "z10_super,z10_super")])
(define_insn "*tm_full"
[(set (reg CC_REGNUM)
(compare (match_operand:HQI 0 "register_operand" "d")
(match_operand:HQI 1 "immediate_operand" "n")))]
"s390_match_ccmode (insn, s390_tm_ccmode (constm1_rtx, operands[1], true))"
"tml\t%0,"
[(set_attr "op_type" "RI")
(set_attr "z10prop" "z10_super")])
;
; Load-and-Test instructions
;
; tst(di|si) instruction pattern(s).
(define_insn "*tstdi_sign"
[(set (reg CC_REGNUM)
(compare
(ashiftrt:DI
(ashift:DI
(subreg:DI (match_operand:SI 0 "nonimmediate_operand" "d,RT") 0)
(const_int 32)) (const_int 32))
(match_operand:DI 1 "const0_operand" "")))
(set (match_operand:DI 2 "register_operand" "=d,d")
(sign_extend:DI (match_dup 0)))]
"s390_match_ccmode(insn, CCSmode) && TARGET_ZARCH"
"ltgfr\t%2,%0
ltgf\t%2,%0"
[(set_attr "op_type" "RRE,RXY")
(set_attr "cpu_facility" "*,z10")
(set_attr "z10prop" "z10_super_E1,z10_super_E1") ])
; ltr, lt, ltgr, ltg
(define_insn "*tst_extimm"
[(set (reg CC_REGNUM)
(compare (match_operand:GPR 0 "nonimmediate_operand" "d,RT")
(match_operand:GPR 1 "const0_operand" "")))
(set (match_operand:GPR 2 "register_operand" "=d,d")
(match_dup 0))]
"s390_match_ccmode(insn, CCSmode) && TARGET_EXTIMM"
"@
ltr\t%2,%0
lt\t%2,%0"
[(set_attr "op_type" "RR,RXY")
(set_attr "z10prop" "z10_fr_E1,z10_fwd_A3") ])
; ltr, lt, ltgr, ltg
(define_insn "*tst_cconly_extimm"
[(set (reg CC_REGNUM)
(compare (match_operand:GPR 0 "nonimmediate_operand" "d,RT")
(match_operand:GPR 1 "const0_operand" "")))
(clobber (match_scratch:GPR 2 "=X,d"))]
"s390_match_ccmode(insn, CCSmode) && TARGET_EXTIMM"
"@
ltr\t%0,%0
lt\t%2,%0"
[(set_attr "op_type" "RR,RXY")
(set_attr "z10prop" "z10_fr_E1,z10_fwd_A3")])
(define_insn "*tstdi"
[(set (reg CC_REGNUM)
(compare (match_operand:DI 0 "register_operand" "d")
(match_operand:DI 1 "const0_operand" "")))
(set (match_operand:DI 2 "register_operand" "=d")
(match_dup 0))]
"s390_match_ccmode(insn, CCSmode) && TARGET_ZARCH && !TARGET_EXTIMM"
"ltgr\t%2,%0"
[(set_attr "op_type" "RRE")
(set_attr "z10prop" "z10_fr_E1")])
(define_insn "*tstsi"
[(set (reg CC_REGNUM)
(compare (match_operand:SI 0 "nonimmediate_operand" "d,Q,S")
(match_operand:SI 1 "const0_operand" "")))
(set (match_operand:SI 2 "register_operand" "=d,d,d")
(match_dup 0))]
"s390_match_ccmode(insn, CCSmode) && !TARGET_EXTIMM"
"@
ltr\t%2,%0
icm\t%2,15,%S0
icmy\t%2,15,%S0"
[(set_attr "op_type" "RR,RS,RSY")
(set_attr "z10prop" "z10_fr_E1,z10_super_E1,z10_super_E1")])
(define_insn "*tstsi_cconly"
[(set (reg CC_REGNUM)
(compare (match_operand:SI 0 "nonimmediate_operand" "d,Q,S")
(match_operand:SI 1 "const0_operand" "")))
(clobber (match_scratch:SI 2 "=X,d,d"))]
"s390_match_ccmode(insn, CCSmode)"
"@
ltr\t%0,%0
icm\t%2,15,%S0
icmy\t%2,15,%S0"
[(set_attr "op_type" "RR,RS,RSY")
(set_attr "z10prop" "z10_fr_E1,z10_super_E1,z10_super_E1")])
(define_insn "*tstdi_cconly_31"
[(set (reg CC_REGNUM)
(compare (match_operand:DI 0 "register_operand" "d")
(match_operand:DI 1 "const0_operand" "")))]
"s390_match_ccmode(insn, CCSmode) && !TARGET_ZARCH"
"srda\t%0,0"
[(set_attr "op_type" "RS")
(set_attr "atype" "reg")])
; ltr, ltgr
(define_insn "*tst_cconly2"
[(set (reg CC_REGNUM)
(compare (match_operand:GPR 0 "register_operand" "d")
(match_operand:GPR 1 "const0_operand" "")))]
"s390_match_ccmode(insn, CCSmode)"
"ltr\t%0,%0"
[(set_attr "op_type" "RR")
(set_attr "z10prop" "z10_fr_E1")])
; tst(hi|qi) instruction pattern(s).
(define_insn "*tstCCT"
[(set (reg CC_REGNUM)
(compare (match_operand:HQI 0 "nonimmediate_operand" "?Q,?S,d")
(match_operand:HQI 1 "const0_operand" "")))
(set (match_operand:HQI 2 "register_operand" "=d,d,0")
(match_dup 0))]
"s390_match_ccmode(insn, CCTmode)"
"@
icm\t%2,,%S0
icmy\t%2,,%S0
tml\t%0,"
[(set_attr "op_type" "RS,RSY,RI")
(set_attr "z10prop" "z10_super_E1,z10_super_E1,z10_super")])
(define_insn "*tsthiCCT_cconly"
[(set (reg CC_REGNUM)
(compare (match_operand:HI 0 "nonimmediate_operand" "Q,S,d")
(match_operand:HI 1 "const0_operand" "")))
(clobber (match_scratch:HI 2 "=d,d,X"))]
"s390_match_ccmode(insn, CCTmode)"
"@
icm\t%2,3,%S0
icmy\t%2,3,%S0
tml\t%0,65535"
[(set_attr "op_type" "RS,RSY,RI")
(set_attr "z10prop" "z10_super_E1,z10_super_E1,z10_super")])
(define_insn "*tstqiCCT_cconly"
[(set (reg CC_REGNUM)
(compare (match_operand:QI 0 "nonimmediate_operand" "?Q,?S,d")
(match_operand:QI 1 "const0_operand" "")))]
"s390_match_ccmode(insn, CCTmode)"
"@
cli\t%S0,0
cliy\t%S0,0
tml\t%0,255"
[(set_attr "op_type" "SI,SIY,RI")
(set_attr "z10prop" "z10_super,z10_super,z10_super")])
(define_insn "*tst"
[(set (reg CC_REGNUM)
(compare (match_operand:HQI 0 "s_operand" "Q,S")
(match_operand:HQI 1 "const0_operand" "")))
(set (match_operand:HQI 2 "register_operand" "=d,d")
(match_dup 0))]
"s390_match_ccmode(insn, CCSmode)"
"@
icm\t%2,,%S0
icmy\t%2,,%S0"
[(set_attr "op_type" "RS,RSY")
(set_attr "z10prop" "z10_super_E1,z10_super_E1")])
(define_insn "*tst_cconly"
[(set (reg CC_REGNUM)
(compare (match_operand:HQI 0 "s_operand" "Q,S")
(match_operand:HQI 1 "const0_operand" "")))
(clobber (match_scratch:HQI 2 "=d,d"))]
"s390_match_ccmode(insn, CCSmode)"
"@
icm\t%2,,%S0
icmy\t%2,,%S0"
[(set_attr "op_type" "RS,RSY")
(set_attr "z10prop" "z10_super_E1,z10_super_E1")])
; Compare (equality) instructions
(define_insn "*cmpdi_cct"
[(set (reg CC_REGNUM)
(compare (match_operand:DI 0 "nonimmediate_operand" "%d,d,d,d,Q")
(match_operand:DI 1 "general_operand" "d,K,Os,RT,BQ")))]
"s390_match_ccmode (insn, CCTmode) && TARGET_ZARCH"
"@
cgr\t%0,%1
cghi\t%0,%h1
cgfi\t%0,%1
cg\t%0,%1
#"
[(set_attr "op_type" "RRE,RI,RIL,RXY,SS")
(set_attr "z10prop" "z10_super_c,z10_super,z10_super,z10_super,*")])
(define_insn "*cmpsi_cct"
[(set (reg CC_REGNUM)
(compare (match_operand:SI 0 "nonimmediate_operand" "%d,d,d,d,d,Q")
(match_operand:SI 1 "general_operand" "d,K,Os,R,T,BQ")))]
"s390_match_ccmode (insn, CCTmode)"
"@
cr\t%0,%1
chi\t%0,%h1
cfi\t%0,%1
c\t%0,%1
cy\t%0,%1
#"
[(set_attr "op_type" "RR,RI,RIL,RX,RXY,SS")
(set_attr "z10prop" "z10_super_c,z10_super,z10_super,z10_super,z10_super,*")])
; Compare (signed) instructions
(define_insn "*cmpdi_ccs_sign"
[(set (reg CC_REGNUM)
(compare (sign_extend:DI (match_operand:SI 1 "nonimmediate_operand"
"d,RT,b"))
(match_operand:DI 0 "register_operand" "d, d,d")))]
"s390_match_ccmode(insn, CCSRmode) && TARGET_ZARCH"
"@
cgfr\t%0,%1
cgf\t%0,%1
cgfrl\t%0,%1"
[(set_attr "op_type" "RRE,RXY,RIL")
(set_attr "z10prop" "z10_c,*,*")
(set_attr "type" "*,*,larl")])
(define_insn "*cmpsi_ccs_sign"
[(set (reg CC_REGNUM)
(compare (sign_extend:SI (match_operand:HI 1 "memory_operand" "R,T,b"))
(match_operand:SI 0 "register_operand" "d,d,d")))]
"s390_match_ccmode(insn, CCSRmode)"
"@
ch\t%0,%1
chy\t%0,%1
chrl\t%0,%1"
[(set_attr "op_type" "RX,RXY,RIL")
(set_attr "cpu_facility" "*,*,z10")
(set_attr "type" "*,*,larl")
(set_attr "z196prop" "z196_cracked,z196_cracked,z196_cracked")])
(define_insn "*cmphi_ccs_z10"
[(set (reg CC_REGNUM)
(compare (match_operand:HI 0 "s_operand" "Q")
(match_operand:HI 1 "immediate_operand" "K")))]
"s390_match_ccmode(insn, CCSmode) && TARGET_Z10"
"chhsi\t%0,%1"
[(set_attr "op_type" "SIL")
(set_attr "z196prop" "z196_cracked")])
(define_insn "*cmpdi_ccs_signhi_rl"
[(set (reg CC_REGNUM)
(compare (sign_extend:DI (match_operand:HI 1 "memory_operand" "RT,b"))
(match_operand:GPR 0 "register_operand" "d,d")))]
"s390_match_ccmode(insn, CCSRmode) && TARGET_Z10"
"@
cgh\t%0,%1
cghrl\t%0,%1"
[(set_attr "op_type" "RXY,RIL")
(set_attr "type" "*,larl")])
; cr, chi, cfi, c, cy, cgr, cghi, cgfi, cg, chsi, cghsi, crl, cgrl
(define_insn "*cmp_ccs"
[(set (reg CC_REGNUM)
(compare (match_operand:GPR 0 "nonimmediate_operand"
"d,d,Q, d,d,d,d")
(match_operand:GPR 1 "general_operand"
"d,K,K,Os,R,T,b")))]
"s390_match_ccmode(insn, CCSmode)"
"@
cr\t%0,%1
chi\t%0,%h1
chsi\t%0,%h1
cfi\t%0,%1
c\t%0,%1
c\t%0,%1
crl\t%0,%1"
[(set_attr "op_type" "RR,RI,SIL,RIL,RX,RXY,RIL")
(set_attr "cpu_facility" "*,*,z10,extimm,*,*,z10")
(set_attr "type" "*,*,*,*,*,*,larl")
(set_attr "z10prop" "z10_super_c,z10_super,z10_super,z10_super,z10_super,z10_super,z10_super")])
; Compare (unsigned) instructions
(define_insn "*cmpsi_ccu_zerohi_rlsi"
[(set (reg CC_REGNUM)
(compare (zero_extend:SI (mem:HI (match_operand:SI 1
"larl_operand" "X")))
(match_operand:SI 0 "register_operand" "d")))]
"s390_match_ccmode(insn, CCURmode) && TARGET_Z10"
"clhrl\t%0,%1"
[(set_attr "op_type" "RIL")
(set_attr "type" "larl")
(set_attr "z10prop" "z10_super")])
; clhrl, clghrl
(define_insn "*cmp_ccu_zerohi_rldi"
[(set (reg CC_REGNUM)
(compare (zero_extend:GPR (mem:HI (match_operand:DI 1
"larl_operand" "X")))
(match_operand:GPR 0 "register_operand" "d")))]
"s390_match_ccmode(insn, CCURmode) && TARGET_Z10"
"clhrl\t%0,%1"
[(set_attr "op_type" "RIL")
(set_attr "type" "larl")
(set_attr "z10prop" "z10_super")])
(define_insn "*cmpdi_ccu_zero"
[(set (reg CC_REGNUM)
(compare (zero_extend:DI (match_operand:SI 1 "nonimmediate_operand"
"d,RT,b"))
(match_operand:DI 0 "register_operand" "d, d,d")))]
"s390_match_ccmode (insn, CCURmode) && TARGET_ZARCH"
"@
clgfr\t%0,%1
clgf\t%0,%1
clgfrl\t%0,%1"
[(set_attr "op_type" "RRE,RXY,RIL")
(set_attr "cpu_facility" "*,*,z10")
(set_attr "type" "*,*,larl")
(set_attr "z10prop" "z10_super_c,z10_super_E1,z10_super")])
(define_insn "*cmpdi_ccu"
[(set (reg CC_REGNUM)
(compare (match_operand:DI 0 "nonimmediate_operand"
"d, d,d,Q, d, Q,BQ")
(match_operand:DI 1 "general_operand"
"d,Op,b,D,RT,BQ,Q")))]
"s390_match_ccmode (insn, CCUmode) && TARGET_ZARCH"
"@
clgr\t%0,%1
clgfi\t%0,%1
clgrl\t%0,%1
clghsi\t%0,%x1
clg\t%0,%1
#
#"
[(set_attr "op_type" "RRE,RIL,RIL,SIL,RXY,SS,SS")
(set_attr "cpu_facility" "*,extimm,z10,z10,*,*,*")
(set_attr "type" "*,*,larl,*,*,*,*")
(set_attr "z10prop" "z10_super_c,z10_super,z10_super,z10_super,z10_super,*,*")])
(define_insn "*cmpsi_ccu"
[(set (reg CC_REGNUM)
(compare (match_operand:SI 0 "nonimmediate_operand" "d, d,d,Q,d,d, Q,BQ")
(match_operand:SI 1 "general_operand" "d,Os,b,D,R,T,BQ, Q")))]
"s390_match_ccmode (insn, CCUmode)"
"@
clr\t%0,%1
clfi\t%0,%o1
clrl\t%0,%1
clfhsi\t%0,%x1
cl\t%0,%1
cly\t%0,%1
#
#"
[(set_attr "op_type" "RR,RIL,RIL,SIL,RX,RXY,SS,SS")
(set_attr "cpu_facility" "*,extimm,z10,z10,*,*,*,*")
(set_attr "type" "*,*,larl,*,*,*,*,*")
(set_attr "z10prop" "z10_super_c,z10_super,z10_super,z10_super,z10_super,z10_super,*,*")])
(define_insn "*cmphi_ccu"
[(set (reg CC_REGNUM)
(compare (match_operand:HI 0 "nonimmediate_operand" "d,d,Q,Q,BQ")
(match_operand:HI 1 "general_operand" "Q,S,D,BQ,Q")))]
"s390_match_ccmode (insn, CCUmode)
&& !register_operand (operands[1], HImode)"
"@
clm\t%0,3,%S1
clmy\t%0,3,%S1
clhhsi\t%0,%1
#
#"
[(set_attr "op_type" "RS,RSY,SIL,SS,SS")
(set_attr "cpu_facility" "*,*,z10,*,*")
(set_attr "z10prop" "*,*,z10_super,*,*")])
(define_insn "*cmpqi_ccu"
[(set (reg CC_REGNUM)
(compare (match_operand:QI 0 "nonimmediate_operand" "d,d,Q,S,Q,BQ")
(match_operand:QI 1 "general_operand" "Q,S,n,n,BQ,Q")))]
"s390_match_ccmode (insn, CCUmode)
&& !register_operand (operands[1], QImode)"
"@
clm\t%0,1,%S1
clmy\t%0,1,%S1
cli\t%S0,%b1
cliy\t%S0,%b1
#
#"
[(set_attr "op_type" "RS,RSY,SI,SIY,SS,SS")
(set_attr "z10prop" "*,*,z10_super,z10_super,*,*")])
; Block compare (CLC) instruction patterns.
(define_insn "*clc"
[(set (reg CC_REGNUM)
(compare (match_operand:BLK 0 "memory_operand" "Q")
(match_operand:BLK 1 "memory_operand" "Q")))
(use (match_operand 2 "const_int_operand" "n"))]
"s390_match_ccmode (insn, CCUmode)
&& INTVAL (operands[2]) >= 1 && INTVAL (operands[2]) <= 256"
"clc\t%O0(%2,%R0),%S1"
[(set_attr "op_type" "SS")])
(define_split
[(set (reg CC_REGNUM)
(compare (match_operand 0 "memory_operand" "")
(match_operand 1 "memory_operand" "")))]
"reload_completed
&& s390_match_ccmode (insn, CCUmode)
&& GET_MODE (operands[0]) == GET_MODE (operands[1])
&& GET_MODE_SIZE (GET_MODE (operands[0])) > 0"
[(parallel
[(set (match_dup 0) (match_dup 1))
(use (match_dup 2))])]
{
operands[2] = GEN_INT (GET_MODE_SIZE (GET_MODE (operands[0])));
operands[0] = adjust_address (operands[0], BLKmode, 0);
operands[1] = adjust_address (operands[1], BLKmode, 0);
operands[1] = gen_rtx_COMPARE (GET_MODE (SET_DEST (PATTERN (curr_insn))),
operands[0], operands[1]);
operands[0] = SET_DEST (PATTERN (curr_insn));
})
; (TF|DF|SF|TD|DD|SD) instructions
; ltxbr, ltdbr, ltebr, ltxtr, ltdtr
(define_insn "*cmp_ccs_0"
[(set (reg CC_REGNUM)
(compare (match_operand:FP 0 "register_operand" "f")
(match_operand:FP 1 "const0_operand" "")))]
"s390_match_ccmode(insn, CCSmode) && TARGET_HARD_FLOAT"
"ltr\t%0,%0"
[(set_attr "op_type" "RRE")
(set_attr "type" "fsimp")])
; cxtr, cxbr, cdbr, cebr, cdb, ceb, cxbtr, cdbtr
(define_insn "*cmp_ccs"
[(set (reg CC_REGNUM)
(compare (match_operand:FP 0 "register_operand" "f,f")
(match_operand:FP 1 "general_operand" "f,")))]
"s390_match_ccmode(insn, CCSmode) && TARGET_HARD_FLOAT"
"@
cr\t%0,%1
cb\t%0,%1"
[(set_attr "op_type" "RRE,RXE")
(set_attr "type" "fsimp")])
; Compare and Branch instructions
; cij, cgij, crj, cgrj, cfi, cgfi, cr, cgr
; The following instructions do a complementary access of their second
; operand (z01 only): crj_c, cgrjc, cr, cgr
(define_insn "*cmp_and_br_signed_"
[(set (pc)
(if_then_else (match_operator 0 "s390_signed_integer_comparison"
[(match_operand:GPR 1 "register_operand" "d,d")
(match_operand:GPR 2 "nonmemory_operand" "d,C")])
(label_ref (match_operand 3 "" ""))
(pc)))
(clobber (reg:CC CC_REGNUM))]
"TARGET_Z10 && !TARGET_AVOID_CMP_AND_BRANCH"
{
if (get_attr_length (insn) == 6)
return which_alternative ?
"cij%C0\t%1,%c2,%l3" : "crj%C0\t%1,%2,%l3";
else
return which_alternative ?
"cfi\t%1,%c2\;jg%C0\t%l3" : "cr\t%1,%2\;jg%C0\t%l3";
}
[(set_attr "op_type" "RIE")
(set_attr "type" "branch")
(set_attr "z10prop" "z10_super_c,z10_super")
(set (attr "length")
(if_then_else (lt (abs (minus (pc) (match_dup 3))) (const_int 60000))
(const_int 6) (const_int 12)))]) ; 8 byte for cr/jg
; 10 byte for cgr/jg
; clij, clgij, clrj, clgrj, clfi, clgfi, clr, clgr
; The following instructions do a complementary access of their second
; operand (z10 only): clrj, clgrj, clr, clgr
(define_insn "*cmp_and_br_unsigned_"
[(set (pc)
(if_then_else (match_operator 0 "s390_unsigned_integer_comparison"
[(match_operand:GPR 1 "register_operand" "d,d")
(match_operand:GPR 2 "nonmemory_operand" "d,I")])
(label_ref (match_operand 3 "" ""))
(pc)))
(clobber (reg:CC CC_REGNUM))]
"TARGET_Z10 && !TARGET_AVOID_CMP_AND_BRANCH"
{
if (get_attr_length (insn) == 6)
return which_alternative ?
"clij%C0\t%1,%b2,%l3" : "clrj%C0\t%1,%2,%l3";
else
return which_alternative ?
"clfi\t%1,%b2\;jg%C0\t%l3" : "clr\t%1,%2\;jg%C0\t%l3";
}
[(set_attr "op_type" "RIE")
(set_attr "type" "branch")
(set_attr "z10prop" "z10_super_c,z10_super")
(set (attr "length")
(if_then_else (lt (abs (minus (pc) (match_dup 3))) (const_int 60000))
(const_int 6) (const_int 12)))]) ; 8 byte for clr/jg
; 10 byte for clgr/jg
; And now the same two patterns as above but with a negated CC mask.
; cij, cgij, crj, cgrj, cfi, cgfi, cr, cgr
; The following instructions do a complementary access of their second
; operand (z01 only): crj_c, cgrjc, cr, cgr
(define_insn "*icmp_and_br_signed_"
[(set (pc)
(if_then_else (match_operator 0 "s390_signed_integer_comparison"
[(match_operand:GPR 1 "register_operand" "d,d")
(match_operand:GPR 2 "nonmemory_operand" "d,C")])
(pc)
(label_ref (match_operand 3 "" ""))))
(clobber (reg:CC CC_REGNUM))]
"TARGET_Z10 && !TARGET_AVOID_CMP_AND_BRANCH"
{
if (get_attr_length (insn) == 6)
return which_alternative ?
"cij%D0\t%1,%c2,%l3" : "crj%D0\t%1,%2,%l3";
else
return which_alternative ?
"cfi\t%1,%c2\;jg%D0\t%l3" : "cr\t%1,%2\;jg%D0\t%l3";
}
[(set_attr "op_type" "RIE")
(set_attr "type" "branch")
(set_attr "z10prop" "z10_super_c,z10_super")
(set (attr "length")
(if_then_else (lt (abs (minus (pc) (match_dup 3))) (const_int 60000))
(const_int 6) (const_int 12)))]) ; 8 byte for cr/jg
; 10 byte for cgr/jg
; clij, clgij, clrj, clgrj, clfi, clgfi, clr, clgr
; The following instructions do a complementary access of their second
; operand (z10 only): clrj, clgrj, clr, clgr
(define_insn "*icmp_and_br_unsigned_"
[(set (pc)
(if_then_else (match_operator 0 "s390_unsigned_integer_comparison"
[(match_operand:GPR 1 "register_operand" "d,d")
(match_operand:GPR 2 "nonmemory_operand" "d,I")])
(pc)
(label_ref (match_operand 3 "" ""))))
(clobber (reg:CC CC_REGNUM))]
"TARGET_Z10 && !TARGET_AVOID_CMP_AND_BRANCH"
{
if (get_attr_length (insn) == 6)
return which_alternative ?
"clij%D0\t%1,%b2,%l3" : "clrj%D0\t%1,%2,%l3";
else
return which_alternative ?
"clfi\t%1,%b2\;jg%D0\t%l3" : "clr\t%1,%2\;jg%D0\t%l3";
}
[(set_attr "op_type" "RIE")
(set_attr "type" "branch")
(set_attr "z10prop" "z10_super_c,z10_super")
(set (attr "length")
(if_then_else (lt (abs (minus (pc) (match_dup 3))) (const_int 60000))
(const_int 6) (const_int 12)))]) ; 8 byte for clr/jg
; 10 byte for clgr/jg
;;
;;- Move instructions.
;;
;
; movti instruction pattern(s).
;
(define_insn "movti"
[(set (match_operand:TI 0 "nonimmediate_operand" "=d,QS,d,o")
(match_operand:TI 1 "general_operand" "QS,d,dPRT,d"))]
"TARGET_ZARCH"
"@
lmg\t%0,%N0,%S1
stmg\t%1,%N1,%S0
#
#"
[(set_attr "op_type" "RSY,RSY,*,*")
(set_attr "type" "lm,stm,*,*")])
(define_split
[(set (match_operand:TI 0 "nonimmediate_operand" "")
(match_operand:TI 1 "general_operand" ""))]
"TARGET_ZARCH && reload_completed
&& s390_split_ok_p (operands[0], operands[1], TImode, 0)"
[(set (match_dup 2) (match_dup 4))
(set (match_dup 3) (match_dup 5))]
{
operands[2] = operand_subword (operands[0], 0, 0, TImode);
operands[3] = operand_subword (operands[0], 1, 0, TImode);
operands[4] = operand_subword (operands[1], 0, 0, TImode);
operands[5] = operand_subword (operands[1], 1, 0, TImode);
})
(define_split
[(set (match_operand:TI 0 "nonimmediate_operand" "")
(match_operand:TI 1 "general_operand" ""))]
"TARGET_ZARCH && reload_completed
&& s390_split_ok_p (operands[0], operands[1], TImode, 1)"
[(set (match_dup 2) (match_dup 4))
(set (match_dup 3) (match_dup 5))]
{
operands[2] = operand_subword (operands[0], 1, 0, TImode);
operands[3] = operand_subword (operands[0], 0, 0, TImode);
operands[4] = operand_subword (operands[1], 1, 0, TImode);
operands[5] = operand_subword (operands[1], 0, 0, TImode);
})
(define_split
[(set (match_operand:TI 0 "register_operand" "")
(match_operand:TI 1 "memory_operand" ""))]
"TARGET_ZARCH && reload_completed
&& !s_operand (operands[1], VOIDmode)"
[(set (match_dup 0) (match_dup 1))]
{
rtx addr = operand_subword (operands[0], 1, 0, TImode);
addr = gen_lowpart (Pmode, addr);
s390_load_address (addr, XEXP (operands[1], 0));
operands[1] = replace_equiv_address (operands[1], addr);
})
;
; Patterns used for secondary reloads
;
; z10 provides move instructions accepting larl memory operands.
; Unfortunately there is no such variant for QI, TI and FP mode moves.
; These patterns are also used for unaligned SI and DI accesses.
(define_expand "reload_tomem_z10"
[(parallel [(match_operand:INTALL 0 "memory_operand" "")
(match_operand:INTALL 1 "register_operand" "=d")
(match_operand:P 2 "register_operand" "=&a")])]
"TARGET_Z10"
{
s390_reload_symref_address (operands[1], operands[0], operands[2], 1);
DONE;
})
(define_expand "reload_toreg_z10"
[(parallel [(match_operand:INTALL 0 "register_operand" "=d")
(match_operand:INTALL 1 "memory_operand" "")
(match_operand:P 2 "register_operand" "=a")])]
"TARGET_Z10"
{
s390_reload_symref_address (operands[0], operands[1], operands[2], 0);
DONE;
})
(define_expand "reload_tomem_z10"
[(parallel [(match_operand:FPALL 0 "memory_operand" "")
(match_operand:FPALL 1 "register_operand" "=d")
(match_operand:P 2 "register_operand" "=&a")])]
"TARGET_Z10"
{
s390_reload_symref_address (operands[1], operands[0], operands[2], 1);
DONE;
})
(define_expand "reload_toreg_z10"
[(parallel [(match_operand:FPALL 0 "register_operand" "=d")
(match_operand:FPALL 1 "memory_operand" "")
(match_operand:P 2 "register_operand" "=a")])]
"TARGET_Z10"
{
s390_reload_symref_address (operands[0], operands[1], operands[2], 0);
DONE;
})
(define_expand "reload_larl_odd_addend_z10"
[(parallel [(match_operand:P 0 "register_operand" "=d")
(match_operand:P 1 "larl_operand" "")
(match_operand:P 2 "register_operand" "=a")])]
"TARGET_Z10"
{
s390_reload_larl_operand (operands[0], operands[1], operands[2]);
DONE;
})
; Handles loading a PLUS (load address) expression
(define_expand "reload_plus"
[(parallel [(match_operand:P 0 "register_operand" "=a")
(match_operand:P 1 "s390_plus_operand" "")
(match_operand:P 2 "register_operand" "=&a")])]
""
{
s390_expand_plus_operand (operands[0], operands[1], operands[2]);
DONE;
})
; Handles assessing a non-offsetable memory address
(define_expand "reload_nonoffmem_in"
[(parallel [(match_operand 0 "register_operand" "")
(match_operand 1 "" "")
(match_operand:P 2 "register_operand" "=&a")])]
""
{
gcc_assert (MEM_P (operands[1]));
s390_load_address (operands[2], find_replacement (&XEXP (operands[1], 0)));
operands[1] = replace_equiv_address (operands[1], operands[2]);
emit_move_insn (operands[0], operands[1]);
DONE;
})
(define_expand "reload_nonoffmem_out"
[(parallel [(match_operand 0 "" "")
(match_operand 1 "register_operand" "")
(match_operand:P 2 "register_operand" "=&a")])]
""
{
gcc_assert (MEM_P (operands[0]));
s390_load_address (operands[2], find_replacement (&XEXP (operands[0], 0)));
operands[0] = replace_equiv_address (operands[0], operands[2]);
emit_move_insn (operands[0], operands[1]);
DONE;
})
(define_expand "reload_PIC_addr"
[(parallel [(match_operand 0 "register_operand" "=d")
(match_operand 1 "larl_operand" "")
(match_operand:P 2 "register_operand" "=a")])]
""
{
rtx new_rtx = legitimize_pic_address (operands[1], operands[2]);
emit_move_insn (operands[0], new_rtx);
})
;
; movdi instruction pattern(s).
;
(define_expand "movdi"
[(set (match_operand:DI 0 "general_operand" "")
(match_operand:DI 1 "general_operand" ""))]
""
{
/* Handle symbolic constants. */
if (TARGET_64BIT
&& (SYMBOLIC_CONST (operands[1])
|| (GET_CODE (operands[1]) == PLUS
&& XEXP (operands[1], 0) == pic_offset_table_rtx
&& SYMBOLIC_CONST (XEXP (operands[1], 1)))))
emit_symbolic_move (operands);
})
(define_insn "*movdi_larl"
[(set (match_operand:DI 0 "register_operand" "=d")
(match_operand:DI 1 "larl_operand" "X"))]
"TARGET_64BIT
&& !FP_REG_P (operands[0])"
"larl\t%0,%1"
[(set_attr "op_type" "RIL")
(set_attr "type" "larl")
(set_attr "z10prop" "z10_super_A1")])
(define_insn "*movdi_64"
[(set (match_operand:DI 0 "nonimmediate_operand"
"=d,d,d,d,d,d,d,d,f,d,d,d,d,d,
RT,!*f,!*f,!*f,!R,!T,b,Q,d,t,Q,t")
(match_operand:DI 1 "general_operand"
"K,N0HD0,N1HD0,N2HD0,N3HD0,Os,N0SD0,N1SD0,d,f,L,b,d,RT,
d,*f,R,T,*f,*f,d,K,t,d,t,Q"))]
"TARGET_ZARCH"
"@
lghi\t%0,%h1
llihh\t%0,%i1
llihl\t%0,%i1
llilh\t%0,%i1
llill\t%0,%i1
lgfi\t%0,%1
llihf\t%0,%k1
llilf\t%0,%k1
ldgr\t%0,%1
lgdr\t%0,%1
lay\t%0,%a1
lgrl\t%0,%1
lgr\t%0,%1
lg\t%0,%1
stg\t%1,%0
ldr\t%0,%1
ld\t%0,%1
ldy\t%0,%1
std\t%1,%0
stdy\t%1,%0
stgrl\t%1,%0
mvghi\t%0,%1
#
#
stam\t%1,%N1,%S0
lam\t%0,%N0,%S1"
[(set_attr "op_type" "RI,RI,RI,RI,RI,RIL,RIL,RIL,RRE,RRE,RXY,RIL,RRE,RXY,
RXY,RR,RX,RXY,RX,RXY,RIL,SIL,*,*,RS,RS")
(set_attr "type" "*,*,*,*,*,*,*,*,floaddf,floaddf,la,larl,lr,load,store,
floaddf,floaddf,floaddf,fstoredf,fstoredf,larl,*,*,*,
*,*")
(set_attr "cpu_facility" "*,*,*,*,*,extimm,extimm,extimm,dfp,dfp,longdisp,
z10,*,*,*,*,*,longdisp,*,longdisp,
z10,z10,*,*,*,*")
(set_attr "z10prop" "z10_fwd_A1,
z10_fwd_E1,
z10_fwd_E1,
z10_fwd_E1,
z10_fwd_E1,
z10_fwd_A1,
z10_fwd_E1,
z10_fwd_E1,
*,
*,
z10_fwd_A1,
z10_fwd_A3,
z10_fr_E1,
z10_fwd_A3,
z10_rec,
*,
*,
*,
*,
*,
z10_rec,
z10_super,
*,
*,
*,
*")
])
(define_split
[(set (match_operand:DI 0 "register_operand" "")
(match_operand:DI 1 "register_operand" ""))]
"TARGET_ZARCH && ACCESS_REG_P (operands[1])"
[(set (match_dup 2) (match_dup 3))
(set (match_dup 0) (ashift:DI (match_dup 0) (const_int 32)))
(set (strict_low_part (match_dup 2)) (match_dup 4))]
"operands[2] = gen_lowpart (SImode, operands[0]);
s390_split_access_reg (operands[1], &operands[4], &operands[3]);")
(define_split
[(set (match_operand:DI 0 "register_operand" "")
(match_operand:DI 1 "register_operand" ""))]
"TARGET_ZARCH && ACCESS_REG_P (operands[0])
&& dead_or_set_p (insn, operands[1])"
[(set (match_dup 3) (match_dup 2))
(set (match_dup 1) (lshiftrt:DI (match_dup 1) (const_int 32)))
(set (match_dup 4) (match_dup 2))]
"operands[2] = gen_lowpart (SImode, operands[1]);
s390_split_access_reg (operands[0], &operands[3], &operands[4]);")
(define_split
[(set (match_operand:DI 0 "register_operand" "")
(match_operand:DI 1 "register_operand" ""))]
"TARGET_ZARCH && ACCESS_REG_P (operands[0])
&& !dead_or_set_p (insn, operands[1])"
[(set (match_dup 3) (match_dup 2))
(set (match_dup 1) (rotate:DI (match_dup 1) (const_int 32)))
(set (match_dup 4) (match_dup 2))
(set (match_dup 1) (rotate:DI (match_dup 1) (const_int 32)))]
"operands[2] = gen_lowpart (SImode, operands[1]);
s390_split_access_reg (operands[0], &operands[3], &operands[4]);")
(define_insn "*movdi_31"
[(set (match_operand:DI 0 "nonimmediate_operand"
"=d,d,Q,S,d ,o,!*f,!*f,!*f,!R,!T,d")
(match_operand:DI 1 "general_operand"
" Q,S,d,d,dPRT,d, *f, R, T,*f,*f,b"))]
"!TARGET_ZARCH"
"@
lm\t%0,%N0,%S1
lmy\t%0,%N0,%S1
stm\t%1,%N1,%S0
stmy\t%1,%N1,%S0
#
#
ldr\t%0,%1
ld\t%0,%1
ldy\t%0,%1
std\t%1,%0
stdy\t%1,%0
#"
[(set_attr "op_type" "RS,RSY,RS,RSY,*,*,RR,RX,RXY,RX,RXY,*")
(set_attr "type" "lm,lm,stm,stm,*,*,floaddf,floaddf,floaddf,fstoredf,fstoredf,*")
(set_attr "cpu_facility" "*,*,*,*,*,*,*,*,*,*,*,z10")])
; For a load from a symbol ref we can use one of the target registers
; together with larl to load the address.
(define_split
[(set (match_operand:DI 0 "register_operand" "")
(match_operand:DI 1 "memory_operand" ""))]
"!TARGET_ZARCH && reload_completed && TARGET_Z10
&& larl_operand (XEXP (operands[1], 0), SImode)"
[(set (match_dup 2) (match_dup 3))
(set (match_dup 0) (match_dup 1))]
{
operands[2] = operand_subword (operands[0], 1, 0, DImode);
operands[3] = XEXP (operands[1], 0);
operands[1] = replace_equiv_address (operands[1], operands[2]);
})
(define_split
[(set (match_operand:DI 0 "nonimmediate_operand" "")
(match_operand:DI 1 "general_operand" ""))]
"!TARGET_ZARCH && reload_completed
&& s390_split_ok_p (operands[0], operands[1], DImode, 0)"
[(set (match_dup 2) (match_dup 4))
(set (match_dup 3) (match_dup 5))]
{
operands[2] = operand_subword (operands[0], 0, 0, DImode);
operands[3] = operand_subword (operands[0], 1, 0, DImode);
operands[4] = operand_subword (operands[1], 0, 0, DImode);
operands[5] = operand_subword (operands[1], 1, 0, DImode);
})
(define_split
[(set (match_operand:DI 0 "nonimmediate_operand" "")
(match_operand:DI 1 "general_operand" ""))]
"!TARGET_ZARCH && reload_completed
&& s390_split_ok_p (operands[0], operands[1], DImode, 1)"
[(set (match_dup 2) (match_dup 4))
(set (match_dup 3) (match_dup 5))]
{
operands[2] = operand_subword (operands[0], 1, 0, DImode);
operands[3] = operand_subword (operands[0], 0, 0, DImode);
operands[4] = operand_subword (operands[1], 1, 0, DImode);
operands[5] = operand_subword (operands[1], 0, 0, DImode);
})
(define_split
[(set (match_operand:DI 0 "register_operand" "")
(match_operand:DI 1 "memory_operand" ""))]
"!TARGET_ZARCH && reload_completed
&& !FP_REG_P (operands[0])
&& !s_operand (operands[1], VOIDmode)"
[(set (match_dup 0) (match_dup 1))]
{
rtx addr = operand_subword (operands[0], 1, 0, DImode);
s390_load_address (addr, XEXP (operands[1], 0));
operands[1] = replace_equiv_address (operands[1], addr);
})
(define_peephole2
[(set (match_operand:DI 0 "register_operand" "")
(mem:DI (match_operand 1 "address_operand" "")))]
"TARGET_ZARCH
&& !FP_REG_P (operands[0])
&& GET_CODE (operands[1]) == SYMBOL_REF
&& CONSTANT_POOL_ADDRESS_P (operands[1])
&& get_pool_mode (operands[1]) == DImode
&& legitimate_reload_constant_p (get_pool_constant (operands[1]))"
[(set (match_dup 0) (match_dup 2))]
"operands[2] = get_pool_constant (operands[1]);")
(define_insn "*la_64"
[(set (match_operand:DI 0 "register_operand" "=d,d")
(match_operand:QI 1 "address_operand" "ZQZR,ZSZT"))]
"TARGET_64BIT"
"@
la\t%0,%a1
lay\t%0,%a1"
[(set_attr "op_type" "RX,RXY")
(set_attr "type" "la")
(set_attr "z10prop" "z10_fwd_A1,z10_fwd_A1")])
(define_peephole2
[(parallel
[(set (match_operand:DI 0 "register_operand" "")
(match_operand:QI 1 "address_operand" ""))
(clobber (reg:CC CC_REGNUM))])]
"TARGET_64BIT
&& preferred_la_operand_p (operands[1], const0_rtx)"
[(set (match_dup 0) (match_dup 1))]
"")
(define_peephole2
[(set (match_operand:DI 0 "register_operand" "")
(match_operand:DI 1 "register_operand" ""))
(parallel
[(set (match_dup 0)
(plus:DI (match_dup 0)
(match_operand:DI 2 "nonmemory_operand" "")))
(clobber (reg:CC CC_REGNUM))])]
"TARGET_64BIT
&& !reg_overlap_mentioned_p (operands[0], operands[2])
&& preferred_la_operand_p (operands[1], operands[2])"
[(set (match_dup 0) (plus:DI (match_dup 1) (match_dup 2)))]
"")
;
; movsi instruction pattern(s).
;
(define_expand "movsi"
[(set (match_operand:SI 0 "general_operand" "")
(match_operand:SI 1 "general_operand" ""))]
""
{
/* Handle symbolic constants. */
if (!TARGET_64BIT
&& (SYMBOLIC_CONST (operands[1])
|| (GET_CODE (operands[1]) == PLUS
&& XEXP (operands[1], 0) == pic_offset_table_rtx
&& SYMBOLIC_CONST (XEXP(operands[1], 1)))))
emit_symbolic_move (operands);
})
(define_insn "*movsi_larl"
[(set (match_operand:SI 0 "register_operand" "=d")
(match_operand:SI 1 "larl_operand" "X"))]
"!TARGET_64BIT && TARGET_CPU_ZARCH
&& !FP_REG_P (operands[0])"
"larl\t%0,%1"
[(set_attr "op_type" "RIL")
(set_attr "type" "larl")
(set_attr "z10prop" "z10_fwd_A1")])
(define_insn "*movsi_zarch"
[(set (match_operand:SI 0 "nonimmediate_operand"
"=d,d,d,d,d,d,d,d,d,R,T,!*f,!*f,!*f,!R,!T,d,t,Q,b,Q,t")
(match_operand:SI 1 "general_operand"
"K,N0HS0,N1HS0,Os,L,b,d,R,T,d,d,*f,R,T,*f,*f,t,d,t,d,K,Q"))]
"TARGET_ZARCH"
"@
lhi\t%0,%h1
llilh\t%0,%i1
llill\t%0,%i1
iilf\t%0,%o1
lay\t%0,%a1
lrl\t%0,%1
lr\t%0,%1
l\t%0,%1
ly\t%0,%1
st\t%1,%0
sty\t%1,%0
ler\t%0,%1
le\t%0,%1
ley\t%0,%1
ste\t%1,%0
stey\t%1,%0
ear\t%0,%1
sar\t%0,%1
stam\t%1,%1,%S0
strl\t%1,%0
mvhi\t%0,%1
lam\t%0,%0,%S1"
[(set_attr "op_type" "RI,RI,RI,RIL,RXY,RIL,RR,RX,RXY,RX,RXY,
RR,RX,RXY,RX,RXY,RRE,RRE,RS,RIL,SIL,RS")
(set_attr "type" "*,
*,
*,
*,
la,
larl,
lr,
load,
load,
store,
store,
floadsf,
floadsf,
floadsf,
fstoresf,
fstoresf,
*,
*,
*,
larl,
*,
*")
(set_attr "cpu_facility" "*,*,*,extimm,longdisp,z10,*,*,longdisp,*,longdisp,
*,*,longdisp,*,longdisp,*,*,*,z10,z10,*")
(set_attr "z10prop" "z10_fwd_A1,
z10_fwd_E1,
z10_fwd_E1,
z10_fwd_A1,
z10_fwd_A1,
z10_fwd_A3,
z10_fr_E1,
z10_fwd_A3,
z10_fwd_A3,
z10_rec,
z10_rec,
*,
*,
*,
*,
*,
z10_super_E1,
z10_super,
*,
z10_rec,
z10_super,
*")])
(define_insn "*movsi_esa"
[(set (match_operand:SI 0 "nonimmediate_operand" "=d,d,d,R,!*f,!*f,!R,d,t,Q,t")
(match_operand:SI 1 "general_operand" "K,d,R,d,*f,R,*f,t,d,t,Q"))]
"!TARGET_ZARCH"
"@
lhi\t%0,%h1
lr\t%0,%1
l\t%0,%1
st\t%1,%0
ler\t%0,%1
le\t%0,%1
ste\t%1,%0
ear\t%0,%1
sar\t%0,%1
stam\t%1,%1,%S0
lam\t%0,%0,%S1"
[(set_attr "op_type" "RI,RR,RX,RX,RR,RX,RX,RRE,RRE,RS,RS")
(set_attr "type" "*,lr,load,store,floadsf,floadsf,fstoresf,*,*,*,*")
(set_attr "z10prop" "z10_fwd_A1,
z10_fr_E1,
z10_fwd_A3,
z10_rec,
*,
*,
*,
z10_super_E1,
z10_super,
*,
*")
])
(define_peephole2
[(set (match_operand:SI 0 "register_operand" "")
(mem:SI (match_operand 1 "address_operand" "")))]
"!FP_REG_P (operands[0])
&& GET_CODE (operands[1]) == SYMBOL_REF
&& CONSTANT_POOL_ADDRESS_P (operands[1])
&& get_pool_mode (operands[1]) == SImode
&& legitimate_reload_constant_p (get_pool_constant (operands[1]))"
[(set (match_dup 0) (match_dup 2))]
"operands[2] = get_pool_constant (operands[1]);")
(define_insn "*la_31"
[(set (match_operand:SI 0 "register_operand" "=d,d")
(match_operand:QI 1 "address_operand" "ZQZR,ZSZT"))]
"!TARGET_64BIT && legitimate_la_operand_p (operands[1])"
"@
la\t%0,%a1
lay\t%0,%a1"
[(set_attr "op_type" "RX,RXY")
(set_attr "type" "la")
(set_attr "z10prop" "z10_fwd_A1,z10_fwd_A1")])
(define_peephole2
[(parallel
[(set (match_operand:SI 0 "register_operand" "")
(match_operand:QI 1 "address_operand" ""))
(clobber (reg:CC CC_REGNUM))])]
"!TARGET_64BIT
&& preferred_la_operand_p (operands[1], const0_rtx)"
[(set (match_dup 0) (match_dup 1))]
"")
(define_peephole2
[(set (match_operand:SI 0 "register_operand" "")
(match_operand:SI 1 "register_operand" ""))
(parallel
[(set (match_dup 0)
(plus:SI (match_dup 0)
(match_operand:SI 2 "nonmemory_operand" "")))
(clobber (reg:CC CC_REGNUM))])]
"!TARGET_64BIT
&& !reg_overlap_mentioned_p (operands[0], operands[2])
&& preferred_la_operand_p (operands[1], operands[2])"
[(set (match_dup 0) (plus:SI (match_dup 1) (match_dup 2)))]
"")
(define_insn "*la_31_and"
[(set (match_operand:SI 0 "register_operand" "=d,d")
(and:SI (match_operand:QI 1 "address_operand" "ZQZR,ZSZT")
(const_int 2147483647)))]
"!TARGET_64BIT"
"@
la\t%0,%a1
lay\t%0,%a1"
[(set_attr "op_type" "RX,RXY")
(set_attr "type" "la")
(set_attr "z10prop" "z10_fwd_A1,z10_fwd_A1")])
(define_insn_and_split "*la_31_and_cc"
[(set (match_operand:SI 0 "register_operand" "=d")
(and:SI (match_operand:QI 1 "address_operand" "p")
(const_int 2147483647)))
(clobber (reg:CC CC_REGNUM))]
"!TARGET_64BIT"
"#"
"&& reload_completed"
[(set (match_dup 0)
(and:SI (match_dup 1) (const_int 2147483647)))]
""
[(set_attr "op_type" "RX")
(set_attr "type" "la")])
(define_insn "force_la_31"
[(set (match_operand:SI 0 "register_operand" "=d,d")
(match_operand:QI 1 "address_operand" "ZQZR,ZSZT"))
(use (const_int 0))]
"!TARGET_64BIT"
"@
la\t%0,%a1
lay\t%0,%a1"
[(set_attr "op_type" "RX")
(set_attr "type" "la")
(set_attr "z10prop" "z10_fwd_A1,z10_fwd_A1")])
;
; movhi instruction pattern(s).
;
(define_expand "movhi"
[(set (match_operand:HI 0 "nonimmediate_operand" "")
(match_operand:HI 1 "general_operand" ""))]
""
{
/* Make it explicit that loading a register from memory
always sign-extends (at least) to SImode. */
if (optimize && can_create_pseudo_p ()
&& register_operand (operands[0], VOIDmode)
&& GET_CODE (operands[1]) == MEM)
{
rtx tmp = gen_reg_rtx (SImode);
rtx ext = gen_rtx_SIGN_EXTEND (SImode, operands[1]);
emit_insn (gen_rtx_SET (VOIDmode, tmp, ext));
operands[1] = gen_lowpart (HImode, tmp);
}
})
(define_insn "*movhi"
[(set (match_operand:HI 0 "nonimmediate_operand" "=d,d,d,d,d,R,T,b,Q")
(match_operand:HI 1 "general_operand" " d,n,R,T,b,d,d,d,K"))]
""
"@
lr\t%0,%1
lhi\t%0,%h1
lh\t%0,%1
lhy\t%0,%1
lhrl\t%0,%1
sth\t%1,%0
sthy\t%1,%0
sthrl\t%1,%0
mvhhi\t%0,%1"
[(set_attr "op_type" "RR,RI,RX,RXY,RIL,RX,RXY,RIL,SIL")
(set_attr "type" "lr,*,*,*,larl,store,store,store,*")
(set_attr "cpu_facility" "*,*,*,*,z10,*,*,z10,z10")
(set_attr "z10prop" "z10_fr_E1,
z10_fwd_A1,
z10_super_E1,
z10_super_E1,
z10_super_E1,
z10_rec,
z10_rec,
z10_rec,
z10_super")])
(define_peephole2
[(set (match_operand:HI 0 "register_operand" "")
(mem:HI (match_operand 1 "address_operand" "")))]
"GET_CODE (operands[1]) == SYMBOL_REF
&& CONSTANT_POOL_ADDRESS_P (operands[1])
&& get_pool_mode (operands[1]) == HImode
&& GET_CODE (get_pool_constant (operands[1])) == CONST_INT"
[(set (match_dup 0) (match_dup 2))]
"operands[2] = get_pool_constant (operands[1]);")
;
; movqi instruction pattern(s).
;
(define_expand "movqi"
[(set (match_operand:QI 0 "nonimmediate_operand" "")
(match_operand:QI 1 "general_operand" ""))]
""
{
/* On z/Architecture, zero-extending from memory to register
is just as fast as a QImode load. */
if (TARGET_ZARCH && optimize && can_create_pseudo_p ()
&& register_operand (operands[0], VOIDmode)
&& GET_CODE (operands[1]) == MEM)
{
rtx tmp = gen_reg_rtx (DImode);
rtx ext = gen_rtx_ZERO_EXTEND (DImode, operands[1]);
emit_insn (gen_rtx_SET (VOIDmode, tmp, ext));
operands[1] = gen_lowpart (QImode, tmp);
}
})
(define_insn "*movqi"
[(set (match_operand:QI 0 "nonimmediate_operand" "=d,d,d,d,R,T,Q,S,?Q")
(match_operand:QI 1 "general_operand" " d,n,R,T,d,d,n,n,?Q"))]
""
"@
lr\t%0,%1
lhi\t%0,%b1
ic\t%0,%1
icy\t%0,%1
stc\t%1,%0
stcy\t%1,%0
mvi\t%S0,%b1
mviy\t%S0,%b1
#"
[(set_attr "op_type" "RR,RI,RX,RXY,RX,RXY,SI,SIY,SS")
(set_attr "type" "lr,*,*,*,store,store,store,store,*")
(set_attr "z10prop" "z10_fr_E1,
z10_fwd_A1,
z10_super_E1,
z10_super_E1,
z10_rec,
z10_rec,
z10_super,
z10_super,
*")])
(define_peephole2
[(set (match_operand:QI 0 "nonimmediate_operand" "")
(mem:QI (match_operand 1 "address_operand" "")))]
"GET_CODE (operands[1]) == SYMBOL_REF
&& CONSTANT_POOL_ADDRESS_P (operands[1])
&& get_pool_mode (operands[1]) == QImode
&& GET_CODE (get_pool_constant (operands[1])) == CONST_INT"
[(set (match_dup 0) (match_dup 2))]
"operands[2] = get_pool_constant (operands[1]);")
;
; movstrictqi instruction pattern(s).
;
(define_insn "*movstrictqi"
[(set (strict_low_part (match_operand:QI 0 "register_operand" "+d,d"))
(match_operand:QI 1 "memory_operand" "R,T"))]
""
"@
ic\t%0,%1
icy\t%0,%1"
[(set_attr "op_type" "RX,RXY")
(set_attr "z10prop" "z10_super_E1,z10_super_E1")])
;
; movstricthi instruction pattern(s).
;
(define_insn "*movstricthi"
[(set (strict_low_part (match_operand:HI 0 "register_operand" "+d,d"))
(match_operand:HI 1 "memory_operand" "Q,S"))
(clobber (reg:CC CC_REGNUM))]
""
"@
icm\t%0,3,%S1
icmy\t%0,3,%S1"
[(set_attr "op_type" "RS,RSY")
(set_attr "z10prop" "z10_super_E1,z10_super_E1")])
;
; movstrictsi instruction pattern(s).
;
(define_insn "movstrictsi"
[(set (strict_low_part (match_operand:SI 0 "register_operand" "+d,d,d,d"))
(match_operand:SI 1 "general_operand" "d,R,T,t"))]
"TARGET_ZARCH"
"@
lr\t%0,%1
l\t%0,%1
ly\t%0,%1
ear\t%0,%1"
[(set_attr "op_type" "RR,RX,RXY,RRE")
(set_attr "type" "lr,load,load,*")
(set_attr "z10prop" "z10_fr_E1,z10_fwd_A3,z10_fwd_A3,z10_super_E1")])
;
; mov(tf|td) instruction pattern(s).
;
(define_expand "mov"
[(set (match_operand:TD_TF 0 "nonimmediate_operand" "")
(match_operand:TD_TF 1 "general_operand" ""))]
""
"")
(define_insn "*mov_64"
[(set (match_operand:TD_TF 0 "nonimmediate_operand" "=f,f,f,o, d,QS, d,o")
(match_operand:TD_TF 1 "general_operand" " G,f,o,f,QS, d,dRT,d"))]
"TARGET_ZARCH"
"@
lzxr\t%0
lxr\t%0,%1
#
#
lmg\t%0,%N0,%S1
stmg\t%1,%N1,%S0
#
#"
[(set_attr "op_type" "RRE,RRE,*,*,RSY,RSY,*,*")
(set_attr "type" "fsimptf,fsimptf,*,*,lm,stm,*,*")
(set_attr "cpu_facility" "z196,*,*,*,*,*,*,*")])
(define_insn "*mov_31"
[(set (match_operand:TD_TF 0 "nonimmediate_operand" "=f,f,f,o")
(match_operand:TD_TF 1 "general_operand" " G,f,o,f"))]
"!TARGET_ZARCH"
"@
lzxr\t%0
lxr\t%0,%1
#
#"
[(set_attr "op_type" "RRE,RRE,*,*")
(set_attr "type" "fsimptf,fsimptf,*,*")
(set_attr "cpu_facility" "z196,*,*,*")])
; TFmode in GPRs splitters
(define_split
[(set (match_operand:TD_TF 0 "nonimmediate_operand" "")
(match_operand:TD_TF 1 "general_operand" ""))]
"TARGET_ZARCH && reload_completed
&& s390_split_ok_p (operands[0], operands[1], mode, 0)"
[(set (match_dup 2) (match_dup 4))
(set (match_dup 3) (match_dup 5))]
{
operands[2] = operand_subword (operands[0], 0, 0, mode);
operands[3] = operand_subword (operands[0], 1, 0, mode);
operands[4] = operand_subword (operands[1], 0, 0, mode);
operands[5] = operand_subword (operands[1], 1, 0, mode);
})
(define_split
[(set (match_operand:TD_TF 0 "nonimmediate_operand" "")
(match_operand:TD_TF 1 "general_operand" ""))]
"TARGET_ZARCH && reload_completed
&& s390_split_ok_p (operands[0], operands[1], mode, 1)"
[(set (match_dup 2) (match_dup 4))
(set (match_dup 3) (match_dup 5))]
{
operands[2] = operand_subword (operands[0], 1, 0, mode);
operands[3] = operand_subword (operands[0], 0, 0, mode);
operands[4] = operand_subword (operands[1], 1, 0, mode);
operands[5] = operand_subword (operands[1], 0, 0, mode);
})
(define_split
[(set (match_operand:TD_TF 0 "register_operand" "")
(match_operand:TD_TF 1 "memory_operand" ""))]
"TARGET_ZARCH && reload_completed
&& !FP_REG_P (operands[0])
&& !s_operand (operands[1], VOIDmode)"
[(set (match_dup 0) (match_dup 1))]
{
rtx addr = operand_subword (operands[0], 1, 0, mode);
addr = gen_lowpart (Pmode, addr);
s390_load_address (addr, XEXP (operands[1], 0));
operands[1] = replace_equiv_address (operands[1], addr);
})
; TFmode in BFPs splitters
(define_split
[(set (match_operand:TD_TF 0 "register_operand" "")
(match_operand:TD_TF 1 "memory_operand" ""))]
"reload_completed && offsettable_memref_p (operands[1])
&& FP_REG_P (operands[0])"
[(set (match_dup 2) (match_dup 4))
(set (match_dup 3) (match_dup 5))]
{
operands[2] = simplify_gen_subreg (mode, operands[0],
mode, 0);
operands[3] = simplify_gen_subreg (mode, operands[0],
mode, 8);
operands[4] = adjust_address_nv (operands[1], mode, 0);
operands[5] = adjust_address_nv (operands[1], mode, 8);
})
(define_split
[(set (match_operand:TD_TF 0 "memory_operand" "")
(match_operand:TD_TF 1 "register_operand" ""))]
"reload_completed && offsettable_memref_p (operands[0])
&& FP_REG_P (operands[1])"
[(set (match_dup 2) (match_dup 4))
(set (match_dup 3) (match_dup 5))]
{
operands[2] = adjust_address_nv (operands[0], mode, 0);
operands[3] = adjust_address_nv (operands[0], mode, 8);
operands[4] = simplify_gen_subreg (mode, operands[1],
mode, 0);
operands[5] = simplify_gen_subreg (mode, operands[1],
mode, 8);
})
;
; mov(df|dd) instruction pattern(s).
;
(define_expand "mov"
[(set (match_operand:DD_DF 0 "nonimmediate_operand" "")
(match_operand:DD_DF 1 "general_operand" ""))]
""
"")
(define_insn "*mov_64dfp"
[(set (match_operand:DD_DF 0 "nonimmediate_operand"
"=f,f,f,d,f,f,R,T,d,d, d,RT")
(match_operand:DD_DF 1 "general_operand"
" G,f,d,f,R,T,f,f,G,d,RT, d"))]
"TARGET_DFP"
"@
lzdr\t%0
ldr\t%0,%1
ldgr\t%0,%1
lgdr\t%0,%1
ld\t%0,%1
ldy\t%0,%1
std\t%1,%0
stdy\t%1,%0
lghi\t%0,0
lgr\t%0,%1
lg\t%0,%1
stg\t%1,%0"
[(set_attr "op_type" "RRE,RR,RRE,RRE,RX,RXY,RX,RXY,RI,RRE,RXY,RXY")
(set_attr "type" "fsimpdf,floaddf,floaddf,floaddf,floaddf,floaddf,
fstoredf,fstoredf,*,lr,load,store")
(set_attr "z10prop" "*,*,*,*,*,*,*,*,z10_fwd_A1,z10_fr_E1,z10_fwd_A3,z10_rec")
(set_attr "cpu_facility" "z196,*,*,*,*,*,*,*,*,*,*,*")])
(define_insn "*mov_64"
[(set (match_operand:DD_DF 0 "nonimmediate_operand" "=f,f,f,f,R,T,d,d, d,RT")
(match_operand:DD_DF 1 "general_operand" " G,f,R,T,f,f,G,d,RT, d"))]
"TARGET_ZARCH"
"@
lzdr\t%0
ldr\t%0,%1
ld\t%0,%1
ldy\t%0,%1
std\t%1,%0
stdy\t%1,%0
lghi\t%0,0
lgr\t%0,%1
lg\t%0,%1
stg\t%1,%0"
[(set_attr "op_type" "RRE,RR,RX,RXY,RX,RXY,RI,RRE,RXY,RXY")
(set_attr "type" "fsimpdf,fload,fload,fload,
fstore,fstore,*,lr,load,store")
(set_attr "z10prop" "*,*,*,*,*,*,z10_fwd_A1,z10_fr_E1,z10_fwd_A3,z10_rec")
(set_attr "cpu_facility" "z196,*,*,*,*,*,*,*,*,*")])
(define_insn "*mov_31"
[(set (match_operand:DD_DF 0 "nonimmediate_operand"
"=f,f,f,f,R,T,d,d,Q,S, d,o")
(match_operand:DD_DF 1 "general_operand"
" G,f,R,T,f,f,Q,S,d,d,dPRT,d"))]
"!TARGET_ZARCH"
"@
lzdr\t%0
ldr\t%0,%1
ld\t%0,%1
ldy\t%0,%1
std\t%1,%0
stdy\t%1,%0
lm\t%0,%N0,%S1
lmy\t%0,%N0,%S1
stm\t%1,%N1,%S0
stmy\t%1,%N1,%S0
#
#"
[(set_attr "op_type" "RRE,RR,RX,RXY,RX,RXY,RS,RSY,RS,RSY,*,*")
(set_attr "type" "fsimpdf,fload,fload,fload,
fstore,fstore,lm,lm,stm,stm,*,*")
(set_attr "cpu_facility" "z196,*,*,*,*,*,*,*,*,*,*,*")])
(define_split
[(set (match_operand:DD_DF 0 "nonimmediate_operand" "")
(match_operand:DD_DF 1 "general_operand" ""))]
"!TARGET_ZARCH && reload_completed
&& s390_split_ok_p (operands[0], operands[1], mode, 0)"
[(set (match_dup 2) (match_dup 4))
(set (match_dup 3) (match_dup 5))]
{
operands[2] = operand_subword (operands[0], 0, 0, mode);
operands[3] = operand_subword (operands[0], 1, 0, mode);
operands[4] = operand_subword (operands[1], 0, 0, mode);
operands[5] = operand_subword (operands[1], 1, 0, mode);
})
(define_split
[(set (match_operand:DD_DF 0 "nonimmediate_operand" "")
(match_operand:DD_DF 1 "general_operand" ""))]
"!TARGET_ZARCH && reload_completed
&& s390_split_ok_p (operands[0], operands[1], mode, 1)"
[(set (match_dup 2) (match_dup 4))
(set (match_dup 3) (match_dup 5))]
{
operands[2] = operand_subword (operands[0], 1, 0, mode);
operands[3] = operand_subword (operands[0], 0, 0, mode);
operands[4] = operand_subword (operands[1], 1, 0, mode);
operands[5] = operand_subword (operands[1], 0, 0, mode);
})
(define_split
[(set (match_operand:DD_DF 0 "register_operand" "")
(match_operand:DD_DF 1 "memory_operand" ""))]
"!TARGET_ZARCH && reload_completed
&& !FP_REG_P (operands[0])
&& !s_operand (operands[1], VOIDmode)"
[(set (match_dup 0) (match_dup 1))]
{
rtx addr = operand_subword (operands[0], 1, 0, mode);
s390_load_address (addr, XEXP (operands[1], 0));
operands[1] = replace_equiv_address (operands[1], addr);
})
;
; mov(sf|sd) instruction pattern(s).
;
(define_insn "mov"
[(set (match_operand:SD_SF 0 "nonimmediate_operand"
"=f,f,f,f,R,T,d,d,d,d,R,T")
(match_operand:SD_SF 1 "general_operand"
" G,f,R,T,f,f,G,d,R,T,d,d"))]
""
"@
lzer\t%0
ler\t%0,%1
le\t%0,%1
ley\t%0,%1
ste\t%1,%0
stey\t%1,%0
lhi\t%0,0
lr\t%0,%1
l\t%0,%1
ly\t%0,%1
st\t%1,%0
sty\t%1,%0"
[(set_attr "op_type" "RRE,RR,RX,RXY,RX,RXY,RI,RR,RX,RXY,RX,RXY")
(set_attr "type" "fsimpsf,fload,fload,fload,
fstore,fstore,*,lr,load,load,store,store")
(set_attr "z10prop" "*,*,*,*,*,*,z10_fwd_A1,z10_fr_E1,z10_fwd_A3,z10_fwd_A3,z10_rec,z10_rec")
(set_attr "cpu_facility" "z196,*,*,*,*,*,*,*,*,*,*,*")])
;
; movcc instruction pattern
;
(define_insn "movcc"
[(set (match_operand:CC 0 "nonimmediate_operand" "=d,c,d,d,d,R,T")
(match_operand:CC 1 "nonimmediate_operand" "d,d,c,R,T,d,d"))]
""
"@
lr\t%0,%1
tmh\t%1,12288
ipm\t%0
st\t%0,%1
sty\t%0,%1
l\t%1,%0
ly\t%1,%0"
[(set_attr "op_type" "RR,RI,RRE,RX,RXY,RX,RXY")
(set_attr "type" "lr,*,*,store,store,load,load")
(set_attr "z10prop" "z10_fr_E1,z10_super,*,z10_rec,z10_rec,z10_fwd_A3,z10_fwd_A3")
(set_attr "z196prop" "*,*,z196_ends,*,*,*,*")])
;
; Block move (MVC) patterns.
;
(define_insn "*mvc"
[(set (match_operand:BLK 0 "memory_operand" "=Q")
(match_operand:BLK 1 "memory_operand" "Q"))
(use (match_operand 2 "const_int_operand" "n"))]
"INTVAL (operands[2]) >= 1 && INTVAL (operands[2]) <= 256"
"mvc\t%O0(%2,%R0),%S1"
[(set_attr "op_type" "SS")])
; This splitter converts a QI to QI mode copy into a BLK mode copy in
; order to have it implemented with mvc.
(define_split
[(set (match_operand:QI 0 "memory_operand" "")
(match_operand:QI 1 "memory_operand" ""))]
"reload_completed"
[(parallel
[(set (match_dup 0) (match_dup 1))
(use (const_int 1))])]
{
operands[0] = adjust_address (operands[0], BLKmode, 0);
operands[1] = adjust_address (operands[1], BLKmode, 0);
})
(define_peephole2
[(parallel
[(set (match_operand:BLK 0 "memory_operand" "")
(match_operand:BLK 1 "memory_operand" ""))
(use (match_operand 2 "const_int_operand" ""))])
(parallel
[(set (match_operand:BLK 3 "memory_operand" "")
(match_operand:BLK 4 "memory_operand" ""))
(use (match_operand 5 "const_int_operand" ""))])]
"s390_offset_p (operands[0], operands[3], operands[2])
&& s390_offset_p (operands[1], operands[4], operands[2])
&& !s390_overlap_p (operands[0], operands[1],
INTVAL (operands[2]) + INTVAL (operands[5]))
&& INTVAL (operands[2]) + INTVAL (operands[5]) <= 256"
[(parallel
[(set (match_dup 6) (match_dup 7))
(use (match_dup 8))])]
"operands[6] = gen_rtx_MEM (BLKmode, XEXP (operands[0], 0));
operands[7] = gen_rtx_MEM (BLKmode, XEXP (operands[1], 0));
operands[8] = GEN_INT (INTVAL (operands[2]) + INTVAL (operands[5]));")
;
; load_multiple pattern(s).
;
; ??? Due to reload problems with replacing registers inside match_parallel
; we currently support load_multiple/store_multiple only after reload.
;
(define_expand "load_multiple"
[(match_par_dup 3 [(set (match_operand 0 "" "")
(match_operand 1 "" ""))
(use (match_operand 2 "" ""))])]
"reload_completed"
{
enum machine_mode mode;
int regno;
int count;
rtx from;
int i, off;
/* Support only loading a constant number of fixed-point registers from
memory and only bother with this if more than two */
if (GET_CODE (operands[2]) != CONST_INT
|| INTVAL (operands[2]) < 2
|| INTVAL (operands[2]) > 16
|| GET_CODE (operands[1]) != MEM
|| GET_CODE (operands[0]) != REG
|| REGNO (operands[0]) >= 16)
FAIL;
count = INTVAL (operands[2]);
regno = REGNO (operands[0]);
mode = GET_MODE (operands[0]);
if (mode != SImode && (!TARGET_ZARCH || mode != DImode))
FAIL;
operands[3] = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (count));
if (!can_create_pseudo_p ())
{
if (GET_CODE (XEXP (operands[1], 0)) == REG)
{
from = XEXP (operands[1], 0);
off = 0;
}
else if (GET_CODE (XEXP (operands[1], 0)) == PLUS
&& GET_CODE (XEXP (XEXP (operands[1], 0), 0)) == REG
&& GET_CODE (XEXP (XEXP (operands[1], 0), 1)) == CONST_INT)
{
from = XEXP (XEXP (operands[1], 0), 0);
off = INTVAL (XEXP (XEXP (operands[1], 0), 1));
}
else
FAIL;
}
else
{
from = force_reg (Pmode, XEXP (operands[1], 0));
off = 0;
}
for (i = 0; i < count; i++)
XVECEXP (operands[3], 0, i)
= gen_rtx_SET (VOIDmode, gen_rtx_REG (mode, regno + i),
change_address (operands[1], mode,
plus_constant (from, off + i * GET_MODE_SIZE (mode))));
})
(define_insn "*load_multiple_di"
[(match_parallel 0 "load_multiple_operation"
[(set (match_operand:DI 1 "register_operand" "=r")
(match_operand:DI 2 "s_operand" "QS"))])]
"reload_completed && TARGET_ZARCH"
{
int words = XVECLEN (operands[0], 0);
operands[0] = gen_rtx_REG (DImode, REGNO (operands[1]) + words - 1);
return "lmg\t%1,%0,%S2";
}
[(set_attr "op_type" "RSY")
(set_attr "type" "lm")])
(define_insn "*load_multiple_si"
[(match_parallel 0 "load_multiple_operation"
[(set (match_operand:SI 1 "register_operand" "=r,r")
(match_operand:SI 2 "s_operand" "Q,S"))])]
"reload_completed"
{
int words = XVECLEN (operands[0], 0);
operands[0] = gen_rtx_REG (SImode, REGNO (operands[1]) + words - 1);
return which_alternative == 0 ? "lm\t%1,%0,%S2" : "lmy\t%1,%0,%S2";
}
[(set_attr "op_type" "RS,RSY")
(set_attr "type" "lm")])
;
; store multiple pattern(s).
;
(define_expand "store_multiple"
[(match_par_dup 3 [(set (match_operand 0 "" "")
(match_operand 1 "" ""))
(use (match_operand 2 "" ""))])]
"reload_completed"
{
enum machine_mode mode;
int regno;
int count;
rtx to;
int i, off;
/* Support only storing a constant number of fixed-point registers to
memory and only bother with this if more than two. */
if (GET_CODE (operands[2]) != CONST_INT
|| INTVAL (operands[2]) < 2
|| INTVAL (operands[2]) > 16
|| GET_CODE (operands[0]) != MEM
|| GET_CODE (operands[1]) != REG
|| REGNO (operands[1]) >= 16)
FAIL;
count = INTVAL (operands[2]);
regno = REGNO (operands[1]);
mode = GET_MODE (operands[1]);
if (mode != SImode && (!TARGET_ZARCH || mode != DImode))
FAIL;
operands[3] = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (count));
if (!can_create_pseudo_p ())
{
if (GET_CODE (XEXP (operands[0], 0)) == REG)
{
to = XEXP (operands[0], 0);
off = 0;
}
else if (GET_CODE (XEXP (operands[0], 0)) == PLUS
&& GET_CODE (XEXP (XEXP (operands[0], 0), 0)) == REG
&& GET_CODE (XEXP (XEXP (operands[0], 0), 1)) == CONST_INT)
{
to = XEXP (XEXP (operands[0], 0), 0);
off = INTVAL (XEXP (XEXP (operands[0], 0), 1));
}
else
FAIL;
}
else
{
to = force_reg (Pmode, XEXP (operands[0], 0));
off = 0;
}
for (i = 0; i < count; i++)
XVECEXP (operands[3], 0, i)
= gen_rtx_SET (VOIDmode,
change_address (operands[0], mode,
plus_constant (to, off + i * GET_MODE_SIZE (mode))),
gen_rtx_REG (mode, regno + i));
})
(define_insn "*store_multiple_di"
[(match_parallel 0 "store_multiple_operation"
[(set (match_operand:DI 1 "s_operand" "=QS")
(match_operand:DI 2 "register_operand" "r"))])]
"reload_completed && TARGET_ZARCH"
{
int words = XVECLEN (operands[0], 0);
operands[0] = gen_rtx_REG (DImode, REGNO (operands[2]) + words - 1);
return "stmg\t%2,%0,%S1";
}
[(set_attr "op_type" "RSY")
(set_attr "type" "stm")])
(define_insn "*store_multiple_si"
[(match_parallel 0 "store_multiple_operation"
[(set (match_operand:SI 1 "s_operand" "=Q,S")
(match_operand:SI 2 "register_operand" "r,r"))])]
"reload_completed"
{
int words = XVECLEN (operands[0], 0);
operands[0] = gen_rtx_REG (SImode, REGNO (operands[2]) + words - 1);
return which_alternative == 0 ? "stm\t%2,%0,%S1" : "stmy\t%2,%0,%S1";
}
[(set_attr "op_type" "RS,RSY")
(set_attr "type" "stm")])
;;
;; String instructions.
;;
(define_insn "*execute_rl"
[(match_parallel 0 ""
[(unspec [(match_operand 1 "register_operand" "a")
(match_operand 2 "" "")
(match_operand:SI 3 "larl_operand" "X")] UNSPEC_EXECUTE)])]
"TARGET_Z10 && GET_MODE_CLASS (GET_MODE (operands[1])) == MODE_INT
&& GET_MODE_SIZE (GET_MODE (operands[1])) <= UNITS_PER_WORD"
"exrl\t%1,%3"
[(set_attr "op_type" "RIL")
(set_attr "type" "cs")])
(define_insn "*execute"
[(match_parallel 0 ""
[(unspec [(match_operand 1 "register_operand" "a")
(match_operand:BLK 2 "memory_operand" "R")
(match_operand 3 "" "")] UNSPEC_EXECUTE)])]
"GET_MODE_CLASS (GET_MODE (operands[1])) == MODE_INT
&& GET_MODE_SIZE (GET_MODE (operands[1])) <= UNITS_PER_WORD"
"ex\t%1,%2"
[(set_attr "op_type" "RX")
(set_attr "type" "cs")])
;
; strlenM instruction pattern(s).
;
(define_expand "strlen"
[(set (reg:SI 0) (match_operand:SI 2 "immediate_operand" ""))
(parallel
[(set (match_dup 4)
(unspec:P [(const_int 0)
(match_operand:BLK 1 "memory_operand" "")
(reg:SI 0)
(match_operand 3 "immediate_operand" "")] UNSPEC_SRST))
(clobber (scratch:P))
(clobber (reg:CC CC_REGNUM))])
(parallel
[(set (match_operand:P 0 "register_operand" "")
(minus:P (match_dup 4) (match_dup 5)))
(clobber (reg:CC CC_REGNUM))])]
""
{
operands[4] = gen_reg_rtx (Pmode);
operands[5] = gen_reg_rtx (Pmode);
emit_move_insn (operands[5], force_operand (XEXP (operands[1], 0), NULL_RTX));
operands[1] = replace_equiv_address (operands[1], operands[5]);
})
(define_insn "*strlen"
[(set (match_operand:P 0 "register_operand" "=a")
(unspec:P [(match_operand:P 2 "general_operand" "0")
(mem:BLK (match_operand:P 3 "register_operand" "1"))
(reg:SI 0)
(match_operand 4 "immediate_operand" "")] UNSPEC_SRST))
(clobber (match_scratch:P 1 "=a"))
(clobber (reg:CC CC_REGNUM))]
""
"srst\t%0,%1\;jo\t.-4"
[(set_attr "length" "8")
(set_attr "type" "vs")])
;
; cmpstrM instruction pattern(s).
;
(define_expand "cmpstrsi"
[(set (reg:SI 0) (const_int 0))
(parallel
[(clobber (match_operand 3 "" ""))
(clobber (match_dup 4))
(set (reg:CCU CC_REGNUM)
(compare:CCU (match_operand:BLK 1 "memory_operand" "")
(match_operand:BLK 2 "memory_operand" "")))
(use (reg:SI 0))])
(parallel
[(set (match_operand:SI 0 "register_operand" "=d")
(unspec:SI [(reg:CCU CC_REGNUM)] UNSPEC_CCU_TO_INT))
(clobber (reg:CC CC_REGNUM))])]
""
{
/* As the result of CMPINT is inverted compared to what we need,
we have to swap the operands. */
rtx op1 = operands[2];
rtx op2 = operands[1];
rtx addr1 = gen_reg_rtx (Pmode);
rtx addr2 = gen_reg_rtx (Pmode);
emit_move_insn (addr1, force_operand (XEXP (op1, 0), NULL_RTX));
emit_move_insn (addr2, force_operand (XEXP (op2, 0), NULL_RTX));
operands[1] = replace_equiv_address_nv (op1, addr1);
operands[2] = replace_equiv_address_nv (op2, addr2);
operands[3] = addr1;
operands[4] = addr2;
})
(define_insn "*cmpstr"
[(clobber (match_operand:P 0 "register_operand" "=d"))
(clobber (match_operand:P 1 "register_operand" "=d"))
(set (reg:CCU CC_REGNUM)
(compare:CCU (mem:BLK (match_operand:P 2 "register_operand" "0"))
(mem:BLK (match_operand:P 3 "register_operand" "1"))))
(use (reg:SI 0))]
""
"clst\t%0,%1\;jo\t.-4"
[(set_attr "length" "8")
(set_attr "type" "vs")])
;
; movstr instruction pattern.
;
(define_expand "movstr"
[(set (reg:SI 0) (const_int 0))
(parallel
[(clobber (match_dup 3))
(set (match_operand:BLK 1 "memory_operand" "")
(match_operand:BLK 2 "memory_operand" ""))
(set (match_operand 0 "register_operand" "")
(unspec [(match_dup 1)
(match_dup 2)
(reg:SI 0)] UNSPEC_MVST))
(clobber (reg:CC CC_REGNUM))])]
""
{
rtx addr1 = gen_reg_rtx (Pmode);
rtx addr2 = gen_reg_rtx (Pmode);
emit_move_insn (addr1, force_operand (XEXP (operands[1], 0), NULL_RTX));
emit_move_insn (addr2, force_operand (XEXP (operands[2], 0), NULL_RTX));
operands[1] = replace_equiv_address_nv (operands[1], addr1);
operands[2] = replace_equiv_address_nv (operands[2], addr2);
operands[3] = addr2;
})
(define_insn "*movstr"
[(clobber (match_operand:P 2 "register_operand" "=d"))
(set (mem:BLK (match_operand:P 1 "register_operand" "0"))
(mem:BLK (match_operand:P 3 "register_operand" "2")))
(set (match_operand:P 0 "register_operand" "=d")
(unspec [(mem:BLK (match_dup 1))
(mem:BLK (match_dup 3))
(reg:SI 0)] UNSPEC_MVST))
(clobber (reg:CC CC_REGNUM))]
""
"mvst\t%1,%2\;jo\t.-4"
[(set_attr "length" "8")
(set_attr "type" "vs")])
;
; movmemM instruction pattern(s).
;
(define_expand "movmem"
[(set (match_operand:BLK 0 "memory_operand" "") ; destination
(match_operand:BLK 1 "memory_operand" "")) ; source
(use (match_operand:GPR 2 "general_operand" "")) ; count
(match_operand 3 "" "")]
""
"s390_expand_movmem (operands[0], operands[1], operands[2]); DONE;")
; Move a block that is up to 256 bytes in length.
; The block length is taken as (operands[2] % 256) + 1.
(define_expand "movmem_short"
[(parallel
[(set (match_operand:BLK 0 "memory_operand" "")
(match_operand:BLK 1 "memory_operand" ""))
(use (match_operand 2 "nonmemory_operand" ""))
(use (const:BLK (unspec:BLK [(const_int 0)] UNSPEC_INSN)))
(clobber (match_dup 3))])]
""
"operands[3] = gen_rtx_SCRATCH (Pmode);")
(define_insn "*movmem_short"
[(set (match_operand:BLK 0 "memory_operand" "=Q,Q,Q,Q")
(match_operand:BLK 1 "memory_operand" "Q,Q,Q,Q"))
(use (match_operand 2 "nonmemory_operand" "n,a,a,a"))
(use (match_operand 3 "immediate_operand" "X,R,X,X"))
(clobber (match_scratch 4 "=X,X,X,&a"))]
"(GET_MODE (operands[2]) == Pmode || GET_MODE (operands[2]) == VOIDmode)
&& GET_MODE (operands[4]) == Pmode"
"#"
[(set_attr "type" "cs")
(set_attr "cpu_facility" "*,*,z10,*")])
(define_split
[(set (match_operand:BLK 0 "memory_operand" "")
(match_operand:BLK 1 "memory_operand" ""))
(use (match_operand 2 "const_int_operand" ""))
(use (match_operand 3 "immediate_operand" ""))
(clobber (scratch))]
"reload_completed"
[(parallel
[(set (match_dup 0) (match_dup 1))
(use (match_dup 2))])]
"operands[2] = GEN_INT ((INTVAL (operands[2]) & 0xff) + 1);")
(define_split
[(set (match_operand:BLK 0 "memory_operand" "")
(match_operand:BLK 1 "memory_operand" ""))
(use (match_operand 2 "register_operand" ""))
(use (match_operand 3 "memory_operand" ""))
(clobber (scratch))]
"reload_completed"
[(parallel
[(unspec [(match_dup 2) (match_dup 3)
(const_int 0)] UNSPEC_EXECUTE)
(set (match_dup 0) (match_dup 1))
(use (const_int 1))])]
"")
(define_split
[(set (match_operand:BLK 0 "memory_operand" "")
(match_operand:BLK 1 "memory_operand" ""))
(use (match_operand 2 "register_operand" ""))
(use (const:BLK (unspec:BLK [(const_int 0)] UNSPEC_INSN)))
(clobber (scratch))]
"TARGET_Z10 && reload_completed"
[(parallel
[(unspec [(match_dup 2) (const_int 0)
(label_ref (match_dup 3))] UNSPEC_EXECUTE)
(set (match_dup 0) (match_dup 1))
(use (const_int 1))])]
"operands[3] = gen_label_rtx ();")
(define_split
[(set (match_operand:BLK 0 "memory_operand" "")
(match_operand:BLK 1 "memory_operand" ""))
(use (match_operand 2 "register_operand" ""))
(use (const:BLK (unspec:BLK [(const_int 0)] UNSPEC_INSN)))
(clobber (match_operand 3 "register_operand" ""))]
"reload_completed && TARGET_CPU_ZARCH"
[(set (match_dup 3) (label_ref (match_dup 4)))
(parallel
[(unspec [(match_dup 2) (mem:BLK (match_dup 3))
(label_ref (match_dup 4))] UNSPEC_EXECUTE)
(set (match_dup 0) (match_dup 1))
(use (const_int 1))])]
"operands[4] = gen_label_rtx ();")
; Move a block of arbitrary length.
(define_expand "movmem_long"
[(parallel
[(clobber (match_dup 2))
(clobber (match_dup 3))
(set (match_operand:BLK 0 "memory_operand" "")
(match_operand:BLK 1 "memory_operand" ""))
(use (match_operand 2 "general_operand" ""))
(use (match_dup 3))
(clobber (reg:CC CC_REGNUM))])]
""
{
enum machine_mode sreg_mode = TARGET_ZARCH ? DImode : SImode;
enum machine_mode dreg_mode = TARGET_ZARCH ? TImode : DImode;
rtx reg0 = gen_reg_rtx (dreg_mode);
rtx reg1 = gen_reg_rtx (dreg_mode);
rtx addr0 = gen_lowpart (Pmode, gen_highpart (sreg_mode, reg0));
rtx addr1 = gen_lowpart (Pmode, gen_highpart (sreg_mode, reg1));
rtx len0 = gen_lowpart (Pmode, reg0);
rtx len1 = gen_lowpart (Pmode, reg1);
emit_clobber (reg0);
emit_move_insn (addr0, force_operand (XEXP (operands[0], 0), NULL_RTX));
emit_move_insn (len0, operands[2]);
emit_clobber (reg1);
emit_move_insn (addr1, force_operand (XEXP (operands[1], 0), NULL_RTX));
emit_move_insn (len1, operands[2]);
operands[0] = replace_equiv_address_nv (operands[0], addr0);
operands[1] = replace_equiv_address_nv (operands[1], addr1);
operands[2] = reg0;
operands[3] = reg1;
})
(define_insn "*movmem_long"
[(clobber (match_operand: 0 "register_operand" "=d"))
(clobber (match_operand: 1 "register_operand" "=d"))
(set (mem:BLK (subreg:P (match_operand: 2 "register_operand" "0") 0))
(mem:BLK (subreg:P (match_operand: 3 "register_operand" "1") 0)))
(use (match_dup 2))
(use (match_dup 3))
(clobber (reg:CC CC_REGNUM))]
"TARGET_64BIT || !TARGET_ZARCH"
"mvcle\t%0,%1,0\;jo\t.-4"
[(set_attr "length" "8")
(set_attr "type" "vs")])
(define_insn "*movmem_long_31z"
[(clobber (match_operand:TI 0 "register_operand" "=d"))
(clobber (match_operand:TI 1 "register_operand" "=d"))
(set (mem:BLK (subreg:SI (match_operand:TI 2 "register_operand" "0") 4))
(mem:BLK (subreg:SI (match_operand:TI 3 "register_operand" "1") 4)))
(use (match_dup 2))
(use (match_dup 3))
(clobber (reg:CC CC_REGNUM))]
"!TARGET_64BIT && TARGET_ZARCH"
"mvcle\t%0,%1,0\;jo\t.-4"
[(set_attr "length" "8")
(set_attr "type" "vs")])
;
; Test data class.
;
(define_expand "signbit2"
[(set (reg:CCZ CC_REGNUM)
(unspec:CCZ [(match_operand:FP_ALL 1 "register_operand" "f")
(match_dup 2)]
UNSPEC_TDC_INSN))
(set (match_operand:SI 0 "register_operand" "=d")
(unspec:SI [(reg:CCZ CC_REGNUM)] UNSPEC_CCZ_TO_INT))]
"TARGET_HARD_FLOAT"
{
operands[2] = GEN_INT (S390_TDC_SIGNBIT_SET);
})
(define_expand "isinf2"
[(set (reg:CCZ CC_REGNUM)
(unspec:CCZ [(match_operand:FP_ALL 1 "register_operand" "f")
(match_dup 2)]
UNSPEC_TDC_INSN))
(set (match_operand:SI 0 "register_operand" "=d")
(unspec:SI [(reg:CCZ CC_REGNUM)] UNSPEC_CCZ_TO_INT))]
"TARGET_HARD_FLOAT"
{
operands[2] = GEN_INT (S390_TDC_INFINITY);
})
; This insn is used to generate all variants of the Test Data Class
; instruction, namely tcxb, tcdb, and tceb. The insn's first operand
; is the register to be tested and the second one is the bit mask
; specifying the required test(s).
;
(define_insn "*TDC_insn_"
[(set (reg:CCZ CC_REGNUM)
(unspec:CCZ [(match_operand:FP_ALL 0 "register_operand" "f")
(match_operand:SI 1 "const_int_operand")] UNSPEC_TDC_INSN))]
"TARGET_HARD_FLOAT"
"t<_d>c\t%0,%1"
[(set_attr "op_type" "RXE")
(set_attr "type" "fsimp")])
(define_insn_and_split "*ccz_to_int"
[(set (match_operand:SI 0 "register_operand" "=d")
(unspec:SI [(match_operand:CCZ 1 "register_operand" "0")]
UNSPEC_CCZ_TO_INT))]
""
"#"
"reload_completed"
[(set (match_dup 0) (lshiftrt:SI (match_dup 0) (const_int 28)))])
;
; setmemM instruction pattern(s).
;
(define_expand "setmem"
[(set (match_operand:BLK 0 "memory_operand" "")
(match_operand:QI 2 "general_operand" ""))
(use (match_operand:GPR 1 "general_operand" ""))
(match_operand 3 "" "")]
""
"s390_expand_setmem (operands[0], operands[1], operands[2]); DONE;")
; Clear a block that is up to 256 bytes in length.
; The block length is taken as (operands[1] % 256) + 1.
(define_expand "clrmem_short"
[(parallel
[(set (match_operand:BLK 0 "memory_operand" "")
(const_int 0))
(use (match_operand 1 "nonmemory_operand" ""))
(use (const:BLK (unspec:BLK [(const_int 0)] UNSPEC_INSN)))
(clobber (match_dup 2))
(clobber (reg:CC CC_REGNUM))])]
""
"operands[2] = gen_rtx_SCRATCH (Pmode);")
(define_insn "*clrmem_short"
[(set (match_operand:BLK 0 "memory_operand" "=Q,Q,Q,Q")
(const_int 0))
(use (match_operand 1 "nonmemory_operand" "n,a,a,a"))
(use (match_operand 2 "immediate_operand" "X,R,X,X"))
(clobber (match_scratch 3 "=X,X,X,&a"))
(clobber (reg:CC CC_REGNUM))]
"(GET_MODE (operands[1]) == Pmode || GET_MODE (operands[1]) == VOIDmode)
&& GET_MODE (operands[3]) == Pmode"
"#"
[(set_attr "type" "cs")
(set_attr "cpu_facility" "*,*,z10,*")])
(define_split
[(set (match_operand:BLK 0 "memory_operand" "")
(const_int 0))
(use (match_operand 1 "const_int_operand" ""))
(use (match_operand 2 "immediate_operand" ""))
(clobber (scratch))
(clobber (reg:CC CC_REGNUM))]
"reload_completed"
[(parallel
[(set (match_dup 0) (const_int 0))
(use (match_dup 1))
(clobber (reg:CC CC_REGNUM))])]
"operands[1] = GEN_INT ((INTVAL (operands[1]) & 0xff) + 1);")
(define_split
[(set (match_operand:BLK 0 "memory_operand" "")
(const_int 0))
(use (match_operand 1 "register_operand" ""))
(use (match_operand 2 "memory_operand" ""))
(clobber (scratch))
(clobber (reg:CC CC_REGNUM))]
"reload_completed"
[(parallel
[(unspec [(match_dup 1) (match_dup 2)
(const_int 0)] UNSPEC_EXECUTE)
(set (match_dup 0) (const_int 0))
(use (const_int 1))
(clobber (reg:CC CC_REGNUM))])]
"")
(define_split
[(set (match_operand:BLK 0 "memory_operand" "")
(const_int 0))
(use (match_operand 1 "register_operand" ""))
(use (const:BLK (unspec:BLK [(const_int 0)] UNSPEC_INSN)))
(clobber (scratch))
(clobber (reg:CC CC_REGNUM))]
"TARGET_Z10 && reload_completed"
[(parallel
[(unspec [(match_dup 1) (const_int 0)
(label_ref (match_dup 3))] UNSPEC_EXECUTE)
(set (match_dup 0) (const_int 0))
(use (const_int 1))
(clobber (reg:CC CC_REGNUM))])]
"operands[3] = gen_label_rtx ();")
(define_split
[(set (match_operand:BLK 0 "memory_operand" "")
(const_int 0))
(use (match_operand 1 "register_operand" ""))
(use (const:BLK (unspec:BLK [(const_int 0)] UNSPEC_INSN)))
(clobber (match_operand 2 "register_operand" ""))
(clobber (reg:CC CC_REGNUM))]
"reload_completed && TARGET_CPU_ZARCH"
[(set (match_dup 2) (label_ref (match_dup 3)))
(parallel
[(unspec [(match_dup 1) (mem:BLK (match_dup 2))
(label_ref (match_dup 3))] UNSPEC_EXECUTE)
(set (match_dup 0) (const_int 0))
(use (const_int 1))
(clobber (reg:CC CC_REGNUM))])]
"operands[3] = gen_label_rtx ();")
; Initialize a block of arbitrary length with (operands[2] % 256).
(define_expand "setmem_long"
[(parallel
[(clobber (match_dup 1))
(set (match_operand:BLK 0 "memory_operand" "")
(match_operand 2 "shift_count_or_setmem_operand" ""))
(use (match_operand 1 "general_operand" ""))
(use (match_dup 3))
(clobber (reg:CC CC_REGNUM))])]
""
{
enum machine_mode sreg_mode = TARGET_ZARCH ? DImode : SImode;
enum machine_mode dreg_mode = TARGET_ZARCH ? TImode : DImode;
rtx reg0 = gen_reg_rtx (dreg_mode);
rtx reg1 = gen_reg_rtx (dreg_mode);
rtx addr0 = gen_lowpart (Pmode, gen_highpart (sreg_mode, reg0));
rtx len0 = gen_lowpart (Pmode, reg0);
emit_clobber (reg0);
emit_move_insn (addr0, force_operand (XEXP (operands[0], 0), NULL_RTX));
emit_move_insn (len0, operands[1]);
emit_move_insn (reg1, const0_rtx);
operands[0] = replace_equiv_address_nv (operands[0], addr0);
operands[1] = reg0;
operands[3] = reg1;
})
(define_insn "*setmem_long"
[(clobber (match_operand: 0 "register_operand" "=d"))
(set (mem:BLK (subreg:P (match_operand: 3 "register_operand" "0") 0))
(match_operand 2 "shift_count_or_setmem_operand" "Y"))
(use (match_dup 3))
(use (match_operand: 1 "register_operand" "d"))
(clobber (reg:CC CC_REGNUM))]
"TARGET_64BIT || !TARGET_ZARCH"
"mvcle\t%0,%1,%Y2\;jo\t.-4"
[(set_attr "length" "8")
(set_attr "type" "vs")])
(define_insn "*setmem_long_and"
[(clobber (match_operand: 0 "register_operand" "=d"))
(set (mem:BLK (subreg:P (match_operand: 3 "register_operand" "0") 0))
(and (match_operand 2 "shift_count_or_setmem_operand" "Y")
(match_operand 4 "const_int_operand" "n")))
(use (match_dup 3))
(use (match_operand: 1 "register_operand" "d"))
(clobber (reg:CC CC_REGNUM))]
"(TARGET_64BIT || !TARGET_ZARCH) &&
(INTVAL (operands[4]) & 255) == 255"
"mvcle\t%0,%1,%Y2\;jo\t.-4"
[(set_attr "length" "8")
(set_attr "type" "vs")])
(define_insn "*setmem_long_31z"
[(clobber (match_operand:TI 0 "register_operand" "=d"))
(set (mem:BLK (subreg:SI (match_operand:TI 3 "register_operand" "0") 4))
(match_operand 2 "shift_count_or_setmem_operand" "Y"))
(use (match_dup 3))
(use (match_operand:TI 1 "register_operand" "d"))
(clobber (reg:CC CC_REGNUM))]
"!TARGET_64BIT && TARGET_ZARCH"
"mvcle\t%0,%1,%Y2\;jo\t.-4"
[(set_attr "length" "8")
(set_attr "type" "vs")])
;
; cmpmemM instruction pattern(s).
;
(define_expand "cmpmemsi"
[(set (match_operand:SI 0 "register_operand" "")
(compare:SI (match_operand:BLK 1 "memory_operand" "")
(match_operand:BLK 2 "memory_operand" "") ) )
(use (match_operand:SI 3 "general_operand" ""))
(use (match_operand:SI 4 "" ""))]
""
"s390_expand_cmpmem (operands[0], operands[1],
operands[2], operands[3]); DONE;")
; Compare a block that is up to 256 bytes in length.
; The block length is taken as (operands[2] % 256) + 1.
(define_expand "cmpmem_short"
[(parallel
[(set (reg:CCU CC_REGNUM)
(compare:CCU (match_operand:BLK 0 "memory_operand" "")
(match_operand:BLK 1 "memory_operand" "")))
(use (match_operand 2 "nonmemory_operand" ""))
(use (const:BLK (unspec:BLK [(const_int 0)] UNSPEC_INSN)))
(clobber (match_dup 3))])]
""
"operands[3] = gen_rtx_SCRATCH (Pmode);")
(define_insn "*cmpmem_short"
[(set (reg:CCU CC_REGNUM)
(compare:CCU (match_operand:BLK 0 "memory_operand" "Q,Q,Q,Q")
(match_operand:BLK 1 "memory_operand" "Q,Q,Q,Q")))
(use (match_operand 2 "nonmemory_operand" "n,a,a,a"))
(use (match_operand 3 "immediate_operand" "X,R,X,X"))
(clobber (match_scratch 4 "=X,X,X,&a"))]
"(GET_MODE (operands[2]) == Pmode || GET_MODE (operands[2]) == VOIDmode)
&& GET_MODE (operands[4]) == Pmode"
"#"
[(set_attr "type" "cs")
(set_attr "cpu_facility" "*,*,z10,*")])
(define_split
[(set (reg:CCU CC_REGNUM)
(compare:CCU (match_operand:BLK 0 "memory_operand" "")
(match_operand:BLK 1 "memory_operand" "")))
(use (match_operand 2 "const_int_operand" ""))
(use (match_operand 3 "immediate_operand" ""))
(clobber (scratch))]
"reload_completed"
[(parallel
[(set (reg:CCU CC_REGNUM) (compare:CCU (match_dup 0) (match_dup 1)))
(use (match_dup 2))])]
"operands[2] = GEN_INT ((INTVAL (operands[2]) & 0xff) + 1);")
(define_split
[(set (reg:CCU CC_REGNUM)
(compare:CCU (match_operand:BLK 0 "memory_operand" "")
(match_operand:BLK 1 "memory_operand" "")))
(use (match_operand 2 "register_operand" ""))
(use (match_operand 3 "memory_operand" ""))
(clobber (scratch))]
"reload_completed"
[(parallel
[(unspec [(match_dup 2) (match_dup 3)
(const_int 0)] UNSPEC_EXECUTE)
(set (reg:CCU CC_REGNUM) (compare:CCU (match_dup 0) (match_dup 1)))
(use (const_int 1))])]
"")
(define_split
[(set (reg:CCU CC_REGNUM)
(compare:CCU (match_operand:BLK 0 "memory_operand" "")
(match_operand:BLK 1 "memory_operand" "")))
(use (match_operand 2 "register_operand" ""))
(use (const:BLK (unspec:BLK [(const_int 0)] UNSPEC_INSN)))
(clobber (scratch))]
"TARGET_Z10 && reload_completed"
[(parallel
[(unspec [(match_dup 2) (const_int 0)
(label_ref (match_dup 4))] UNSPEC_EXECUTE)
(set (reg:CCU CC_REGNUM) (compare:CCU (match_dup 0) (match_dup 1)))
(use (const_int 1))])]
"operands[4] = gen_label_rtx ();")
(define_split
[(set (reg:CCU CC_REGNUM)
(compare:CCU (match_operand:BLK 0 "memory_operand" "")
(match_operand:BLK 1 "memory_operand" "")))
(use (match_operand 2 "register_operand" ""))
(use (const:BLK (unspec:BLK [(const_int 0)] UNSPEC_INSN)))
(clobber (match_operand 3 "register_operand" ""))]
"reload_completed && TARGET_CPU_ZARCH"
[(set (match_dup 3) (label_ref (match_dup 4)))
(parallel
[(unspec [(match_dup 2) (mem:BLK (match_dup 3))
(label_ref (match_dup 4))] UNSPEC_EXECUTE)
(set (reg:CCU CC_REGNUM) (compare:CCU (match_dup 0) (match_dup 1)))
(use (const_int 1))])]
"operands[4] = gen_label_rtx ();")
; Compare a block of arbitrary length.
(define_expand "cmpmem_long"
[(parallel
[(clobber (match_dup 2))
(clobber (match_dup 3))
(set (reg:CCU CC_REGNUM)
(compare:CCU (match_operand:BLK 0 "memory_operand" "")
(match_operand:BLK 1 "memory_operand" "")))
(use (match_operand 2 "general_operand" ""))
(use (match_dup 3))])]
""
{
enum machine_mode sreg_mode = TARGET_ZARCH ? DImode : SImode;
enum machine_mode dreg_mode = TARGET_ZARCH ? TImode : DImode;
rtx reg0 = gen_reg_rtx (dreg_mode);
rtx reg1 = gen_reg_rtx (dreg_mode);
rtx addr0 = gen_lowpart (Pmode, gen_highpart (sreg_mode, reg0));
rtx addr1 = gen_lowpart (Pmode, gen_highpart (sreg_mode, reg1));
rtx len0 = gen_lowpart (Pmode, reg0);
rtx len1 = gen_lowpart (Pmode, reg1);
emit_clobber (reg0);
emit_move_insn (addr0, force_operand (XEXP (operands[0], 0), NULL_RTX));
emit_move_insn (len0, operands[2]);
emit_clobber (reg1);
emit_move_insn (addr1, force_operand (XEXP (operands[1], 0), NULL_RTX));
emit_move_insn (len1, operands[2]);
operands[0] = replace_equiv_address_nv (operands[0], addr0);
operands[1] = replace_equiv_address_nv (operands[1], addr1);
operands[2] = reg0;
operands[3] = reg1;
})
(define_insn "*cmpmem_long"
[(clobber (match_operand: 0 "register_operand" "=d"))
(clobber (match_operand: 1 "register_operand" "=d"))
(set (reg:CCU CC_REGNUM)
(compare:CCU (mem:BLK (subreg:P (match_operand: 2 "register_operand" "0") 0))
(mem:BLK (subreg:P (match_operand: 3 "register_operand" "1") 0))))
(use (match_dup 2))
(use (match_dup 3))]
"TARGET_64BIT || !TARGET_ZARCH"
"clcle\t%0,%1,0\;jo\t.-4"
[(set_attr "length" "8")
(set_attr "type" "vs")])
(define_insn "*cmpmem_long_31z"
[(clobber (match_operand:TI 0 "register_operand" "=d"))
(clobber (match_operand:TI 1 "register_operand" "=d"))
(set (reg:CCU CC_REGNUM)
(compare:CCU (mem:BLK (subreg:SI (match_operand:TI 2 "register_operand" "0") 4))
(mem:BLK (subreg:SI (match_operand:TI 3 "register_operand" "1") 4))))
(use (match_dup 2))
(use (match_dup 3))]
"!TARGET_64BIT && TARGET_ZARCH"
"clcle\t%0,%1,0\;jo\t.-4"
[(set_attr "op_type" "NN")
(set_attr "type" "vs")
(set_attr "length" "8")])
; Convert CCUmode condition code to integer.
; Result is zero if EQ, positive if LTU, negative if GTU.
(define_insn_and_split "cmpint"
[(set (match_operand:SI 0 "register_operand" "=d")
(unspec:SI [(match_operand:CCU 1 "register_operand" "0")]
UNSPEC_CCU_TO_INT))
(clobber (reg:CC CC_REGNUM))]
""
"#"
"reload_completed"
[(set (match_dup 0) (ashift:SI (match_dup 0) (const_int 2)))
(parallel
[(set (match_dup 0) (ashiftrt:SI (match_dup 0) (const_int 30)))
(clobber (reg:CC CC_REGNUM))])])
(define_insn_and_split "*cmpint_cc"
[(set (reg CC_REGNUM)
(compare (unspec:SI [(match_operand:CCU 1 "register_operand" "0")]
UNSPEC_CCU_TO_INT)
(const_int 0)))
(set (match_operand:SI 0 "register_operand" "=d")
(unspec:SI [(match_dup 1)] UNSPEC_CCU_TO_INT))]
"s390_match_ccmode (insn, CCSmode)"
"#"
"&& reload_completed"
[(set (match_dup 0) (ashift:SI (match_dup 0) (const_int 2)))
(parallel
[(set (match_dup 2) (match_dup 3))
(set (match_dup 0) (ashiftrt:SI (match_dup 0) (const_int 30)))])]
{
rtx result = gen_rtx_ASHIFTRT (SImode, operands[0], GEN_INT (30));
operands[2] = SET_DEST (XVECEXP (PATTERN (curr_insn), 0, 0));
operands[3] = gen_rtx_COMPARE (GET_MODE (operands[2]), result, const0_rtx);
})
(define_insn_and_split "*cmpint_sign"
[(set (match_operand:DI 0 "register_operand" "=d")
(sign_extend:DI (unspec:SI [(match_operand:CCU 1 "register_operand" "0")]
UNSPEC_CCU_TO_INT)))
(clobber (reg:CC CC_REGNUM))]
"TARGET_ZARCH"
"#"
"&& reload_completed"
[(set (match_dup 0) (ashift:DI (match_dup 0) (const_int 34)))
(parallel
[(set (match_dup 0) (ashiftrt:DI (match_dup 0) (const_int 62)))
(clobber (reg:CC CC_REGNUM))])])
(define_insn_and_split "*cmpint_sign_cc"
[(set (reg CC_REGNUM)
(compare (ashiftrt:DI (ashift:DI (subreg:DI
(unspec:SI [(match_operand:CCU 1 "register_operand" "0")]
UNSPEC_CCU_TO_INT) 0)
(const_int 32)) (const_int 32))
(const_int 0)))
(set (match_operand:DI 0 "register_operand" "=d")
(sign_extend:DI (unspec:SI [(match_dup 1)] UNSPEC_CCU_TO_INT)))]
"s390_match_ccmode (insn, CCSmode) && TARGET_ZARCH"
"#"
"&& reload_completed"
[(set (match_dup 0) (ashift:DI (match_dup 0) (const_int 34)))
(parallel
[(set (match_dup 2) (match_dup 3))
(set (match_dup 0) (ashiftrt:DI (match_dup 0) (const_int 62)))])]
{
rtx result = gen_rtx_ASHIFTRT (DImode, operands[0], GEN_INT (62));
operands[2] = SET_DEST (XVECEXP (PATTERN (curr_insn), 0, 0));
operands[3] = gen_rtx_COMPARE (GET_MODE (operands[2]), result, const0_rtx);
})
;;
;;- Conversion instructions.
;;
(define_insn "*sethighpartsi"
[(set (match_operand:SI 0 "register_operand" "=d,d")
(unspec:SI [(match_operand:BLK 1 "s_operand" "Q,S")
(match_operand 2 "const_int_operand" "n,n")] UNSPEC_ICM))
(clobber (reg:CC CC_REGNUM))]
""
"@
icm\t%0,%2,%S1
icmy\t%0,%2,%S1"
[(set_attr "op_type" "RS,RSY")
(set_attr "z10prop" "z10_super_E1,z10_super_E1")])
(define_insn "*sethighpartdi_64"
[(set (match_operand:DI 0 "register_operand" "=d")
(unspec:DI [(match_operand:BLK 1 "s_operand" "QS")
(match_operand 2 "const_int_operand" "n")] UNSPEC_ICM))
(clobber (reg:CC CC_REGNUM))]
"TARGET_ZARCH"
"icmh\t%0,%2,%S1"
[(set_attr "op_type" "RSY")
(set_attr "z10prop" "z10_super")])
(define_insn "*sethighpartdi_31"
[(set (match_operand:DI 0 "register_operand" "=d,d")
(unspec:DI [(match_operand:BLK 1 "s_operand" "Q,S")
(match_operand 2 "const_int_operand" "n,n")] UNSPEC_ICM))
(clobber (reg:CC CC_REGNUM))]
"!TARGET_ZARCH"
"@
icm\t%0,%2,%S1
icmy\t%0,%2,%S1"
[(set_attr "op_type" "RS,RSY")
(set_attr "z10prop" "z10_super_E1,z10_super_E1")])
(define_insn_and_split "*extzv"
[(set (match_operand:GPR 0 "register_operand" "=d")
(zero_extract:GPR (match_operand:QI 1 "s_operand" "QS")
(match_operand 2 "const_int_operand" "n")
(const_int 0)))
(clobber (reg:CC CC_REGNUM))]
"INTVAL (operands[2]) > 0
&& INTVAL (operands[2]) <= GET_MODE_BITSIZE (SImode)"
"#"
"&& reload_completed"
[(parallel
[(set (match_dup 0) (unspec:GPR [(match_dup 1) (match_dup 3)] UNSPEC_ICM))
(clobber (reg:CC CC_REGNUM))])
(set (match_dup 0) (lshiftrt:GPR (match_dup 0) (match_dup 2)))]
{
int bitsize = INTVAL (operands[2]);
int size = (bitsize - 1) / BITS_PER_UNIT + 1; /* round up */
int mask = ((1ul << size) - 1) << (GET_MODE_SIZE (SImode) - size);
operands[1] = adjust_address (operands[1], BLKmode, 0);
set_mem_size (operands[1], GEN_INT (size));
operands[2] = GEN_INT (GET_MODE_BITSIZE (mode) - bitsize);
operands[3] = GEN_INT (mask);
})
(define_insn_and_split "*extv"
[(set (match_operand:GPR 0 "register_operand" "=d")
(sign_extract:GPR (match_operand:QI 1 "s_operand" "QS")
(match_operand 2 "const_int_operand" "n")
(const_int 0)))
(clobber (reg:CC CC_REGNUM))]
"INTVAL (operands[2]) > 0
&& INTVAL (operands[2]) <= GET_MODE_BITSIZE (SImode)"
"#"
"&& reload_completed"
[(parallel
[(set (match_dup 0) (unspec:GPR [(match_dup 1) (match_dup 3)] UNSPEC_ICM))
(clobber (reg:CC CC_REGNUM))])
(parallel
[(set (match_dup 0) (ashiftrt:GPR (match_dup 0) (match_dup 2)))
(clobber (reg:CC CC_REGNUM))])]
{
int bitsize = INTVAL (operands[2]);
int size = (bitsize - 1) / BITS_PER_UNIT + 1; /* round up */
int mask = ((1ul << size) - 1) << (GET_MODE_SIZE (SImode) - size);
operands[1] = adjust_address (operands[1], BLKmode, 0);
set_mem_size (operands[1], GEN_INT (size));
operands[2] = GEN_INT (GET_MODE_BITSIZE (mode) - bitsize);
operands[3] = GEN_INT (mask);
})
;
; insv instruction patterns
;
(define_expand "insv"
[(set (zero_extract (match_operand 0 "nonimmediate_operand" "")
(match_operand 1 "const_int_operand" "")
(match_operand 2 "const_int_operand" ""))
(match_operand 3 "general_operand" ""))]
""
{
if (s390_expand_insv (operands[0], operands[1], operands[2], operands[3]))
DONE;
FAIL;
})
(define_insn "*insv_z10"
[(set (zero_extract:GPR (match_operand:GPR 0 "nonimmediate_operand" "+d")
(match_operand 1 "const_int_operand" "I")
(match_operand 2 "const_int_operand" "I"))
(match_operand:GPR 3 "nonimmediate_operand" "d"))
(clobber (reg:CC CC_REGNUM))]
"TARGET_Z10
&& (INTVAL (operands[1]) + INTVAL (operands[2])) <=
GET_MODE_BITSIZE (mode)"
{
int start = INTVAL (operands[2]);
int size = INTVAL (operands[1]);
int offset = 64 - GET_MODE_BITSIZE (mode);
operands[2] = GEN_INT (offset + start); /* start bit position */
operands[1] = GEN_INT (offset + start + size - 1); /* end bit position */
operands[4] = GEN_INT (GET_MODE_BITSIZE (mode) -
start - size); /* left shift count */
return "risbg\t%0,%3,%b2,%b1,%b4";
}
[(set_attr "op_type" "RIE")
(set_attr "z10prop" "z10_super_E1")])
; and op1 with a mask being 1 for the selected bits and 0 for the rest
; and op3=op0 with a mask being 0 for the selected bits and 1 for the rest
(define_insn "*insv_z10_noshift"
[(set (match_operand:GPR 0 "nonimmediate_operand" "=d")
(ior:GPR (and:GPR (match_operand:GPR 1 "nonimmediate_operand" "d")
(match_operand 2 "const_int_operand" "n"))
(and:GPR (match_operand:GPR 3 "nonimmediate_operand" "0")
(match_operand 4 "const_int_operand" "n"))))
(clobber (reg:CC CC_REGNUM))]
"TARGET_Z10
&& s390_contiguous_bitmask_p (INTVAL (operands[2]),
GET_MODE_BITSIZE (mode), NULL, NULL)
&& INTVAL (operands[2]) == ~(INTVAL (operands[4]))"
{
int start;
int size;
s390_contiguous_bitmask_p (INTVAL (operands[2]),
GET_MODE_BITSIZE (mode), &start, &size);
operands[5] = GEN_INT (64 - start - size); /* start bit position */
operands[6] = GEN_INT (64 - 1 - start); /* end bit position */
operands[7] = const0_rtx; /* left shift count */
return "risbg\t%0,%1,%b5,%b6,%b7";
}
[(set_attr "op_type" "RIE")
(set_attr "z10prop" "z10_super_E1")])
; and op1 with a mask being 1 for the selected bits and 0 for the rest
(define_insn "*insv_or_z10_noshift"
[(set (match_operand:GPR 0 "nonimmediate_operand" "=d")
(ior:GPR (and:GPR (match_operand:GPR 1 "nonimmediate_operand" "d")
(match_operand 2 "const_int_operand" "n"))
(match_operand:GPR 3 "nonimmediate_operand" "0")))
(clobber (reg:CC CC_REGNUM))]
"TARGET_Z10
&& s390_contiguous_bitmask_p (INTVAL (operands[2]),
GET_MODE_BITSIZE (mode), NULL, NULL)"
{
int start;
int size;
s390_contiguous_bitmask_p (INTVAL (operands[2]),
GET_MODE_BITSIZE (mode), &start, &size);
operands[4] = GEN_INT (64 - start - size); /* start bit position */
operands[5] = GEN_INT (64 - 1 - start); /* end bit position */
operands[6] = const0_rtx; /* left shift count */
return "rosbg\t%0,%1,%b4,%b5,%b6";
}
[(set_attr "op_type" "RIE")])
(define_insn "*insv_mem_reg"
[(set (zero_extract:W (match_operand:QI 0 "memory_operand" "+Q,S")
(match_operand 1 "const_int_operand" "n,n")
(const_int 0))
(match_operand:W 2 "register_operand" "d,d"))]
"INTVAL (operands[1]) > 0
&& INTVAL (operands[1]) <= GET_MODE_BITSIZE (SImode)
&& INTVAL (operands[1]) % BITS_PER_UNIT == 0"
{
int size = INTVAL (operands[1]) / BITS_PER_UNIT;
operands[1] = GEN_INT ((1ul << size) - 1);
return (which_alternative == 0) ? "stcm\t%2,%1,%S0"
: "stcmy\t%2,%1,%S0";
}
[(set_attr "op_type" "RS,RSY")
(set_attr "z10prop" "z10_super,z10_super")])
(define_insn "*insvdi_mem_reghigh"
[(set (zero_extract:DI (match_operand:QI 0 "memory_operand" "+QS")
(match_operand 1 "const_int_operand" "n")
(const_int 0))
(lshiftrt:DI (match_operand:DI 2 "register_operand" "d")
(const_int 32)))]
"TARGET_ZARCH
&& INTVAL (operands[1]) > 0
&& INTVAL (operands[1]) <= GET_MODE_BITSIZE (SImode)
&& INTVAL (operands[1]) % BITS_PER_UNIT == 0"
{
int size = INTVAL (operands[1]) / BITS_PER_UNIT;
operands[1] = GEN_INT ((1ul << size) - 1);
return "stcmh\t%2,%1,%S0";
}
[(set_attr "op_type" "RSY")
(set_attr "z10prop" "z10_super")])
(define_insn "*insvdi_reg_imm"
[(set (zero_extract:DI (match_operand:DI 0 "register_operand" "+d")
(const_int 16)
(match_operand 1 "const_int_operand" "n"))
(match_operand:DI 2 "const_int_operand" "n"))]
"TARGET_ZARCH
&& INTVAL (operands[1]) >= 0
&& INTVAL (operands[1]) < BITS_PER_WORD
&& INTVAL (operands[1]) % 16 == 0"
{
switch (BITS_PER_WORD - INTVAL (operands[1]))
{
case 64: return "iihh\t%0,%x2"; break;
case 48: return "iihl\t%0,%x2"; break;
case 32: return "iilh\t%0,%x2"; break;
case 16: return "iill\t%0,%x2"; break;
default: gcc_unreachable();
}
}
[(set_attr "op_type" "RI")
(set_attr "z10prop" "z10_super_E1")])
; Update the left-most 32 bit of a DI.
(define_insn "*insv_h_di_reg_extimm"
[(set (zero_extract:DI (match_operand:DI 0 "register_operand" "+d")
(const_int 32)
(const_int 0))
(match_operand:DI 1 "const_int_operand" "n"))]
"TARGET_EXTIMM"
"iihf\t%0,%o1"
[(set_attr "op_type" "RIL")
(set_attr "z10prop" "z10_fwd_E1")])
; Update the right-most 32 bit of a DI, or the whole of a SI.
(define_insn "*insv_l_reg_extimm"
[(set (zero_extract:P (match_operand:P 0 "register_operand" "+d")
(const_int 32)
(match_operand 1 "const_int_operand" "n"))
(match_operand:P 2 "const_int_operand" "n"))]
"TARGET_EXTIMM
&& BITS_PER_WORD - INTVAL (operands[1]) == 32"
"iilf\t%0,%o2"
[(set_attr "op_type" "RIL")
(set_attr "z10prop" "z10_fwd_A1")])
;
; extendsidi2 instruction pattern(s).
;
(define_expand "extendsidi2"
[(set (match_operand:DI 0 "register_operand" "")
(sign_extend:DI (match_operand:SI 1 "nonimmediate_operand" "")))]
""
{
if (!TARGET_ZARCH)
{
emit_clobber (operands[0]);
emit_move_insn (gen_highpart (SImode, operands[0]), operands[1]);
emit_move_insn (gen_lowpart (SImode, operands[0]), const0_rtx);
emit_insn (gen_ashrdi3 (operands[0], operands[0], GEN_INT (32)));
DONE;
}
})
(define_insn "*extendsidi2"
[(set (match_operand:DI 0 "register_operand" "=d,d,d")
(sign_extend:DI (match_operand:SI 1 "nonimmediate_operand" "d,RT,b")))]
"TARGET_ZARCH"
"@
lgfr\t%0,%1
lgf\t%0,%1
lgfrl\t%0,%1"
[(set_attr "op_type" "RRE,RXY,RIL")
(set_attr "type" "*,*,larl")
(set_attr "cpu_facility" "*,*,z10")
(set_attr "z10prop" "z10_super_E1,z10_super_E1,z10_super_E1")])
;
; extend(hi|qi)(si|di)2 instruction pattern(s).
;
(define_expand "extend2"
[(set (match_operand:DSI 0 "register_operand" "")
(sign_extend:DSI (match_operand:HQI 1 "nonimmediate_operand" "")))]
""
{
if (mode == DImode && !TARGET_ZARCH)
{
rtx tmp = gen_reg_rtx (SImode);
emit_insn (gen_extendsi2 (tmp, operands[1]));
emit_insn (gen_extendsidi2 (operands[0], tmp));
DONE;
}
else if (!TARGET_EXTIMM)
{
rtx bitcount = GEN_INT (GET_MODE_BITSIZE (mode) -
GET_MODE_BITSIZE (mode));
operands[1] = gen_lowpart (mode, operands[1]);
emit_insn (gen_ashl3 (operands[0], operands[1], bitcount));
emit_insn (gen_ashr3 (operands[0], operands[0], bitcount));
DONE;
}
})
;
; extendhidi2 instruction pattern(s).
;
(define_insn "*extendhidi2_extimm"
[(set (match_operand:DI 0 "register_operand" "=d,d,d")
(sign_extend:DI (match_operand:HI 1 "general_operand" "d,RT,b")))]
"TARGET_ZARCH && TARGET_EXTIMM"
"@
lghr\t%0,%1
lgh\t%0,%1
lghrl\t%0,%1"
[(set_attr "op_type" "RRE,RXY,RIL")
(set_attr "type" "*,*,larl")
(set_attr "cpu_facility" "extimm,extimm,z10")
(set_attr "z10prop" "z10_super_E1,z10_super_E1,z10_super_E1")])
(define_insn "*extendhidi2"
[(set (match_operand:DI 0 "register_operand" "=d")
(sign_extend:DI (match_operand:HI 1 "memory_operand" "RT")))]
"TARGET_ZARCH"
"lgh\t%0,%1"
[(set_attr "op_type" "RXY")
(set_attr "z10prop" "z10_super_E1")])
;
; extendhisi2 instruction pattern(s).
;
(define_insn "*extendhisi2_extimm"
[(set (match_operand:SI 0 "register_operand" "=d,d,d,d")
(sign_extend:SI (match_operand:HI 1 "nonimmediate_operand" " d,R,T,b")))]
"TARGET_EXTIMM"
"@
lhr\t%0,%1
lh\t%0,%1
lhy\t%0,%1
lhrl\t%0,%1"
[(set_attr "op_type" "RRE,RX,RXY,RIL")
(set_attr "type" "*,*,*,larl")
(set_attr "cpu_facility" "extimm,extimm,extimm,z10")
(set_attr "z10prop" "z10_super_E1,z10_super_E1,z10_super_E1,z10_super_E1")])
(define_insn "*extendhisi2"
[(set (match_operand:SI 0 "register_operand" "=d,d")
(sign_extend:SI (match_operand:HI 1 "memory_operand" "R,T")))]
"!TARGET_EXTIMM"
"@
lh\t%0,%1
lhy\t%0,%1"
[(set_attr "op_type" "RX,RXY")
(set_attr "z10prop" "z10_super_E1,z10_super_E1")])
;
; extendqi(si|di)2 instruction pattern(s).
;
; lbr, lgbr, lb, lgb
(define_insn "*extendqi2_extimm"
[(set (match_operand:GPR 0 "register_operand" "=d,d")
(sign_extend:GPR (match_operand:QI 1 "nonimmediate_operand" "d,RT")))]
"TARGET_EXTIMM"
"@
lbr\t%0,%1
lb\t%0,%1"
[(set_attr "op_type" "RRE,RXY")
(set_attr "z10prop" "z10_super_E1,z10_super_E1")])
; lb, lgb
(define_insn "*extendqi2"
[(set (match_operand:GPR 0 "register_operand" "=d")
(sign_extend:GPR (match_operand:QI 1 "memory_operand" "RT")))]
"!TARGET_EXTIMM && TARGET_LONG_DISPLACEMENT"
"lb\t%0,%1"
[(set_attr "op_type" "RXY")
(set_attr "z10prop" "z10_super_E1")])
(define_insn_and_split "*extendqi2_short_displ"
[(set (match_operand:GPR 0 "register_operand" "=d")
(sign_extend:GPR (match_operand:QI 1 "s_operand" "Q")))
(clobber (reg:CC CC_REGNUM))]
"!TARGET_EXTIMM && !TARGET_LONG_DISPLACEMENT"
"#"
"&& reload_completed"
[(parallel
[(set (match_dup 0) (unspec:GPR [(match_dup 1) (const_int 8)] UNSPEC_ICM))
(clobber (reg:CC CC_REGNUM))])
(parallel
[(set (match_dup 0) (ashiftrt:GPR (match_dup 0) (match_dup 2)))
(clobber (reg:CC CC_REGNUM))])]
{
operands[1] = adjust_address (operands[1], BLKmode, 0);
set_mem_size (operands[1], GEN_INT (GET_MODE_SIZE (QImode)));
operands[2] = GEN_INT (GET_MODE_BITSIZE (mode)
- GET_MODE_BITSIZE (QImode));
})
;
; zero_extendsidi2 instruction pattern(s).
;
(define_expand "zero_extendsidi2"
[(set (match_operand:DI 0 "register_operand" "")
(zero_extend:DI (match_operand:SI 1 "nonimmediate_operand" "")))]
""
{
if (!TARGET_ZARCH)
{
emit_clobber (operands[0]);
emit_move_insn (gen_lowpart (SImode, operands[0]), operands[1]);
emit_move_insn (gen_highpart (SImode, operands[0]), const0_rtx);
DONE;
}
})
(define_insn "*zero_extendsidi2"
[(set (match_operand:DI 0 "register_operand" "=d,d,d")
(zero_extend:DI (match_operand:SI 1 "nonimmediate_operand" "d,RT,b")))]
"TARGET_ZARCH"
"@
llgfr\t%0,%1
llgf\t%0,%1
llgfrl\t%0,%1"
[(set_attr "op_type" "RRE,RXY,RIL")
(set_attr "type" "*,*,larl")
(set_attr "cpu_facility" "*,*,z10")
(set_attr "z10prop" "z10_fwd_E1,z10_fwd_A3,z10_fwd_A3")])
;
; LLGT-type instructions (zero-extend from 31 bit to 64 bit).
;
(define_insn "*llgt_sidi"
[(set (match_operand:DI 0 "register_operand" "=d")
(and:DI (subreg:DI (match_operand:SI 1 "memory_operand" "RT") 0)
(const_int 2147483647)))]
"TARGET_ZARCH"
"llgt\t%0,%1"
[(set_attr "op_type" "RXE")
(set_attr "z10prop" "z10_super_E1")])
(define_insn_and_split "*llgt_sidi_split"
[(set (match_operand:DI 0 "register_operand" "=d")
(and:DI (subreg:DI (match_operand:SI 1 "memory_operand" "RT") 0)
(const_int 2147483647)))
(clobber (reg:CC CC_REGNUM))]
"TARGET_ZARCH"
"#"
"&& reload_completed"
[(set (match_dup 0)
(and:DI (subreg:DI (match_dup 1) 0)
(const_int 2147483647)))]
"")
(define_insn "*llgt_sisi"
[(set (match_operand:SI 0 "register_operand" "=d,d")
(and:SI (match_operand:SI 1 "nonimmediate_operand" "d,RT")
(const_int 2147483647)))]
"TARGET_ZARCH"
"@
llgtr\t%0,%1
llgt\t%0,%1"
[(set_attr "op_type" "RRE,RXE")
(set_attr "z10prop" "z10_super_E1,z10_super_E1")])
(define_insn "*llgt_didi"
[(set (match_operand:DI 0 "register_operand" "=d,d")
(and:DI (match_operand:DI 1 "nonimmediate_operand" "d,o")
(const_int 2147483647)))]
"TARGET_ZARCH"
"@
llgtr\t%0,%1
llgt\t%0,%N1"
[(set_attr "op_type" "RRE,RXE")
(set_attr "z10prop" "z10_super_E1,z10_super_E1")])
(define_split
[(set (match_operand:DSI 0 "register_operand" "")
(and:DSI (match_operand:DSI 1 "nonimmediate_operand" "")
(const_int 2147483647)))
(clobber (reg:CC CC_REGNUM))]
"TARGET_ZARCH && reload_completed"
[(set (match_dup 0)
(and:DSI (match_dup 1)
(const_int 2147483647)))]
"")
;
; zero_extend(hi|qi)(si|di)2 instruction pattern(s).
;
(define_expand "zero_extenddi2"
[(set (match_operand:DI 0 "register_operand" "")
(zero_extend:DI (match_operand:HQI 1 "nonimmediate_operand" "")))]
""
{
if (!TARGET_ZARCH)
{
rtx tmp = gen_reg_rtx (SImode);
emit_insn (gen_zero_extendsi2 (tmp, operands[1]));
emit_insn (gen_zero_extendsidi2 (operands[0], tmp));
DONE;
}
else if (!TARGET_EXTIMM)
{
rtx bitcount = GEN_INT (GET_MODE_BITSIZE(DImode) -
GET_MODE_BITSIZE(mode));
operands[1] = gen_lowpart (DImode, operands[1]);
emit_insn (gen_ashldi3 (operands[0], operands[1], bitcount));
emit_insn (gen_lshrdi3 (operands[0], operands[0], bitcount));
DONE;
}
})
(define_expand "zero_extendsi2"
[(set (match_operand:SI 0 "register_operand" "")
(zero_extend:SI (match_operand:HQI 1 "nonimmediate_operand" "")))]
""
{
if (!TARGET_EXTIMM)
{
operands[1] = gen_lowpart (SImode, operands[1]);
emit_insn (gen_andsi3 (operands[0], operands[1],
GEN_INT ((1 << GET_MODE_BITSIZE(mode)) - 1)));
DONE;
}
})
; llhrl, llghrl
(define_insn "*zero_extendhi2_z10"
[(set (match_operand:GPR 0 "register_operand" "=d,d,d")
(zero_extend:GPR (match_operand:HI 1 "nonimmediate_operand" "d,RT,b")))]
"TARGET_Z10"
"@
llhr\t%0,%1
llh\t%0,%1
llhrl\t%0,%1"
[(set_attr "op_type" "RXY,RRE,RIL")
(set_attr "type" "*,*,larl")
(set_attr "cpu_facility" "*,*,z10")
(set_attr "z10prop" "z10_super_E1,z10_fwd_A3,z10_fwd_A3")])
; llhr, llcr, llghr, llgcr, llh, llc, llgh, llgc
(define_insn "*zero_extend2_extimm"
[(set (match_operand:GPR 0 "register_operand" "=d,d")
(zero_extend:GPR (match_operand:HQI 1 "nonimmediate_operand" "d,RT")))]
"TARGET_EXTIMM"
"@
llr\t%0,%1
ll\t%0,%1"
[(set_attr "op_type" "RRE,RXY")
(set_attr "z10prop" "z10_super_E1,z10_fwd_A3")])
; llgh, llgc
(define_insn "*zero_extend2"
[(set (match_operand:GPR 0 "register_operand" "=d")
(zero_extend:GPR (match_operand:HQI 1 "memory_operand" "RT")))]
"TARGET_ZARCH && !TARGET_EXTIMM"
"llg\t%0,%1"
[(set_attr "op_type" "RXY")
(set_attr "z10prop" "z10_fwd_A3")])
(define_insn_and_split "*zero_extendhisi2_31"
[(set (match_operand:SI 0 "register_operand" "=&d")
(zero_extend:SI (match_operand:HI 1 "s_operand" "QS")))
(clobber (reg:CC CC_REGNUM))]
"!TARGET_ZARCH"
"#"
"&& reload_completed"
[(set (match_dup 0) (const_int 0))
(parallel
[(set (strict_low_part (match_dup 2)) (match_dup 1))
(clobber (reg:CC CC_REGNUM))])]
"operands[2] = gen_lowpart (HImode, operands[0]);")
(define_insn_and_split "*zero_extendqisi2_31"
[(set (match_operand:SI 0 "register_operand" "=&d")
(zero_extend:SI (match_operand:QI 1 "memory_operand" "RT")))]
"!TARGET_ZARCH"
"#"
"&& reload_completed"
[(set (match_dup 0) (const_int 0))
(set (strict_low_part (match_dup 2)) (match_dup 1))]
"operands[2] = gen_lowpart (QImode, operands[0]);")
;
; zero_extendqihi2 instruction pattern(s).
;
(define_expand "zero_extendqihi2"
[(set (match_operand:HI 0 "register_operand" "")
(zero_extend:HI (match_operand:QI 1 "register_operand" "")))]
"TARGET_ZARCH && !TARGET_EXTIMM"
{
operands[1] = gen_lowpart (HImode, operands[1]);
emit_insn (gen_andhi3 (operands[0], operands[1], GEN_INT (0xff)));
DONE;
})
(define_insn "*zero_extendqihi2_64"
[(set (match_operand:HI 0 "register_operand" "=d")
(zero_extend:HI (match_operand:QI 1 "memory_operand" "RT")))]
"TARGET_ZARCH && !TARGET_EXTIMM"
"llgc\t%0,%1"
[(set_attr "op_type" "RXY")
(set_attr "z10prop" "z10_fwd_A3")])
(define_insn_and_split "*zero_extendqihi2_31"
[(set (match_operand:HI 0 "register_operand" "=&d")
(zero_extend:HI (match_operand:QI 1 "memory_operand" "RT")))]
"!TARGET_ZARCH"
"#"
"&& reload_completed"
[(set (match_dup 0) (const_int 0))
(set (strict_low_part (match_dup 2)) (match_dup 1))]
"operands[2] = gen_lowpart (QImode, operands[0]);")
;
; fixuns_trunc(dd|td)di2 instruction pattern(s).
;
(define_expand "fixuns_truncdddi2"
[(parallel
[(set (match_operand:DI 0 "register_operand" "")
(unsigned_fix:DI (match_operand:DD 1 "register_operand" "")))
(unspec:DI [(const_int 5)] UNSPEC_ROUND)
(clobber (reg:CC CC_REGNUM))])]
"TARGET_HARD_DFP"
{
if (!TARGET_Z196)
{
rtx label1 = gen_label_rtx ();
rtx label2 = gen_label_rtx ();
rtx temp = gen_reg_rtx (TDmode);
REAL_VALUE_TYPE cmp, sub;
decimal_real_from_string (&cmp, "9223372036854775808.0"); /* 2^63 */
decimal_real_from_string (&sub, "18446744073709551616.0"); /* 2^64 */
/* 2^63 can't be represented as 64bit DFP number with full precision. The
solution is doing the check and the subtraction in TD mode and using a
TD -> DI convert afterwards. */
emit_insn (gen_extendddtd2 (temp, operands[1]));
temp = force_reg (TDmode, temp);
emit_cmp_and_jump_insns (temp,
CONST_DOUBLE_FROM_REAL_VALUE (cmp, TDmode),
LT, NULL_RTX, VOIDmode, 0, label1);
emit_insn (gen_subtd3 (temp, temp,
CONST_DOUBLE_FROM_REAL_VALUE (sub, TDmode)));
emit_insn (gen_fix_trunctddi2_dfp (operands[0], temp, GEN_INT (11)));
emit_jump (label2);
emit_label (label1);
emit_insn (gen_fix_truncdddi2_dfp (operands[0], operands[1], GEN_INT (9)));
emit_label (label2);
DONE;
}
})
(define_expand "fixuns_trunctddi2"
[(parallel
[(set (match_operand:DI 0 "register_operand" "")
(unsigned_fix:DI (match_operand:TD 1 "register_operand" "")))
(unspec:DI [(const_int 5)] UNSPEC_ROUND)
(clobber (reg:CC CC_REGNUM))])]
"TARGET_HARD_DFP"
{
if (!TARGET_Z196)
{
rtx label1 = gen_label_rtx ();
rtx label2 = gen_label_rtx ();
rtx temp = gen_reg_rtx (TDmode);
REAL_VALUE_TYPE cmp, sub;
operands[1] = force_reg (TDmode, operands[1]);
decimal_real_from_string (&cmp, "9223372036854775808.0"); /* 2^63 */
decimal_real_from_string (&sub, "18446744073709551616.0"); /* 2^64 */
emit_cmp_and_jump_insns (operands[1],
CONST_DOUBLE_FROM_REAL_VALUE (cmp, TDmode),
LT, NULL_RTX, VOIDmode, 0, label1);
emit_insn (gen_subtd3 (temp, operands[1],
CONST_DOUBLE_FROM_REAL_VALUE (sub, TDmode)));
emit_insn (gen_fix_trunctddi2_dfp (operands[0], temp, GEN_INT (11)));
emit_jump (label2);
emit_label (label1);
emit_insn (gen_fix_trunctddi2_dfp (operands[0], operands[1], GEN_INT (9)));
emit_label (label2);
DONE;
}
})
;
; fixuns_trunc(sf|df|tf)(si|di)2 and fix_trunc(sf|df|tf)(si|di)2
; instruction pattern(s).
;
(define_expand "fixuns_trunc2"
[(parallel
[(set (match_operand:GPR 0 "register_operand" "")
(unsigned_fix:GPR (match_operand:BFP 1 "register_operand" "")))
(unspec:GPR [(const_int 5)] UNSPEC_ROUND)
(clobber (reg:CC CC_REGNUM))])]
"TARGET_HARD_FLOAT"
{
if (!TARGET_Z196)
{
rtx label1 = gen_label_rtx ();
rtx label2 = gen_label_rtx ();
rtx temp = gen_reg_rtx (mode);
REAL_VALUE_TYPE cmp, sub;
operands[1] = force_reg (mode, operands[1]);
real_2expN (&cmp, GET_MODE_BITSIZE(mode) - 1, mode);
real_2expN (&sub, GET_MODE_BITSIZE(mode), mode);
emit_cmp_and_jump_insns (operands[1],
CONST_DOUBLE_FROM_REAL_VALUE (cmp, mode),
LT, NULL_RTX, VOIDmode, 0, label1);
emit_insn (gen_sub3 (temp, operands[1],
CONST_DOUBLE_FROM_REAL_VALUE (sub, mode)));
emit_insn (gen_fix_trunc2_bfp (operands[0], temp,
GEN_INT (7)));
emit_jump (label2);
emit_label (label1);
emit_insn (gen_fix_trunc2_bfp (operands[0],
operands[1], GEN_INT (5)));
emit_label (label2);
DONE;
}
})
; fixuns_trunc(td|dd)si2 expander
(define_expand "fixuns_truncsi2"
[(parallel
[(set (match_operand:SI 0 "register_operand" "")
(unsigned_fix:SI (match_operand:DFP 1 "register_operand" "")))
(unspec:SI [(const_int 5)] UNSPEC_ROUND)
(clobber (reg:CC CC_REGNUM))])]
"TARGET_Z196 && TARGET_HARD_DFP"
"")
; fixuns_trunc(tf|df|sf|td|dd)(di|si)2 instruction patterns.
; clfebr, clfdbr, clfxbr, clgebr, clgdbr, clgxbr
; clfdtr, clfxtr, clgdtr, clgxtr
(define_insn "*fixuns_trunc2_z196"
[(set (match_operand:GPR 0 "register_operand" "=r")
(unsigned_fix:GPR (match_operand:FP 1 "register_operand" "f")))
(unspec:GPR [(match_operand:GPR 2 "immediate_operand" "K")] UNSPEC_ROUND)
(clobber (reg:CC CC_REGNUM))]
"TARGET_Z196"
"clr\t%0,%h2,%1,0"
[(set_attr "op_type" "RRF")
(set_attr "type" "ftoi")])
(define_expand "fix_trunc2"
[(set (match_operand:GPR 0 "register_operand" "")
(fix:GPR (match_operand:DSF 1 "register_operand" "")))]
"TARGET_HARD_FLOAT"
{
emit_insn (gen_fix_trunc