;;- Machine description for GNU compiler -- S/390 / zSeries version.
;; Copyright (C) 1999-2022 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_c_enum "unspec" [
; Miscellaneous
UNSPEC_ROUND
UNSPEC_ICM
UNSPEC_TIE
; Convert CC into a str comparison result and copy it into an
; integer register
; cc0->0, cc1->1, cc2->-1, (cc3->-1)
UNSPEC_STRCMPCC_TO_INT
; Copy CC as is into the lower 2 bits of an integer register
UNSPEC_CC_TO_INT
; The right hand side of an setmem
UNSPEC_REPLICATE_BYTE
; GOT/PLT and lt-relative accesses
UNSPEC_LTREL_OFFSET
UNSPEC_POOL_OFFSET
UNSPEC_GOTENT
UNSPEC_GOT
UNSPEC_GOTOFF
UNSPEC_PLT31
UNSPEC_PLTOFF
; Literal pool
UNSPEC_RELOAD_BASE
UNSPEC_MAIN_BASE
UNSPEC_LTREF
UNSPEC_INSN
UNSPEC_EXECUTE
UNSPEC_EXECUTE_JUMP
; Atomic Support
UNSPEC_MB
UNSPEC_MOVA
; TLS relocation specifiers
UNSPEC_TLSGD
UNSPEC_TLSLDM
UNSPEC_NTPOFF
UNSPEC_DTPOFF
UNSPEC_GOTNTPOFF
UNSPEC_INDNTPOFF
; TLS support
UNSPEC_TLSLDM_NTPOFF
UNSPEC_TLS_LOAD
UNSPEC_GET_TP
; String Functions
UNSPEC_SRST
UNSPEC_MVST
; Stack Smashing Protector
UNSPEC_SP_SET
UNSPEC_SP_TEST
; Split stack support
UNSPEC_STACK_CHECK
; Test Data Class (TDC)
UNSPEC_TDC_INSN
; Byte-wise Population Count
UNSPEC_POPCNT
UNSPEC_COPYSIGN
; Load FP Integer
UNSPEC_FPINT_FLOOR
UNSPEC_FPINT_BTRUNC
UNSPEC_FPINT_ROUND
UNSPEC_FPINT_CEIL
UNSPEC_FPINT_NEARBYINT
UNSPEC_FPINT_RINT
UNSPEC_LCBB
; Vector
UNSPEC_VEC_SMULT_HI
UNSPEC_VEC_UMULT_HI
UNSPEC_VEC_SMULT_LO
UNSPEC_VEC_SMULT_EVEN
UNSPEC_VEC_UMULT_EVEN
UNSPEC_VEC_SMULT_ODD
UNSPEC_VEC_UMULT_ODD
UNSPEC_VEC_VMAL
UNSPEC_VEC_VMAH
UNSPEC_VEC_VMALH
UNSPEC_VEC_VMAE
UNSPEC_VEC_VMALE
UNSPEC_VEC_VMAO
UNSPEC_VEC_VMALO
UNSPEC_VEC_GATHER
UNSPEC_VEC_EXTRACT
UNSPEC_VEC_INSERT_AND_ZERO
UNSPEC_VEC_LOAD_BNDRY
UNSPEC_VEC_LOAD_LEN
UNSPEC_VEC_LOAD_LEN_R
UNSPEC_VEC_PACK
UNSPEC_VEC_PACK_SATURATE
UNSPEC_VEC_PACK_SATURATE_CC
UNSPEC_VEC_PACK_SATURATE_GENCC
UNSPEC_VEC_PACK_UNSIGNED_SATURATE
UNSPEC_VEC_PACK_UNSIGNED_SATURATE_CC
UNSPEC_VEC_PACK_UNSIGNED_SATURATE_GENCC
UNSPEC_VEC_PERM
UNSPEC_VEC_EXTEND
UNSPEC_VEC_STORE_LEN
UNSPEC_VEC_STORE_LEN_R
UNSPEC_VEC_VBPERM
UNSPEC_VEC_UNPACKH
UNSPEC_VEC_UNPACKH_L
UNSPEC_VEC_UNPACKL
UNSPEC_VEC_UNPACKL_L
UNSPEC_VEC_ADDC
UNSPEC_VEC_ADDE_U128
UNSPEC_VEC_ADDEC_U128
UNSPEC_VEC_AVG
UNSPEC_VEC_AVGU
UNSPEC_VEC_CHECKSUM
UNSPEC_VEC_GFMSUM
UNSPEC_VEC_GFMSUM_128
UNSPEC_VEC_GFMSUM_ACCUM
UNSPEC_VEC_GFMSUM_ACCUM_128
UNSPEC_VEC_SET
UNSPEC_VEC_VSUMG
UNSPEC_VEC_VSUMQ
UNSPEC_VEC_VSUM
UNSPEC_VEC_RL_MASK
UNSPEC_VEC_SLL
UNSPEC_VEC_SLB
UNSPEC_VEC_SLDBYTE
UNSPEC_VEC_SLDBIT
UNSPEC_VEC_SRDBIT
UNSPEC_VEC_SRAL
UNSPEC_VEC_SRAB
UNSPEC_VEC_SRL
UNSPEC_VEC_SRLB
UNSPEC_VEC_SUBC
UNSPEC_VEC_SUBE_U128
UNSPEC_VEC_SUBEC_U128
UNSPEC_VEC_TEST_MASK
UNSPEC_VEC_VFAE
UNSPEC_VEC_VFAECC
UNSPEC_VEC_VFEE
UNSPEC_VEC_VFEECC
UNSPEC_VEC_VFENE
UNSPEC_VEC_VFENECC
UNSPEC_VEC_VISTR
UNSPEC_VEC_VISTRCC
UNSPEC_VEC_VSTRC
UNSPEC_VEC_VSTRCCC
UNSPEC_VEC_VSTRS
UNSPEC_VEC_VSTRSCC
UNSPEC_VEC_VCDGB
UNSPEC_VEC_VCDLGB
UNSPEC_VEC_VCGDB
UNSPEC_VEC_VCLGDB
UNSPEC_VEC_VFI
UNSPEC_VEC_VFLL ; vector fp load lengthened
UNSPEC_VEC_VFLR ; vector fp load rounded
UNSPEC_VEC_VFTCI
UNSPEC_VEC_VFTCICC
UNSPEC_VEC_MSUM
UNSPEC_VEC_VFMIN
UNSPEC_VEC_VFMAX
UNSPEC_VEC_ELTSWAP
UNSPEC_NNPA_VCLFNHS_V8HI
UNSPEC_NNPA_VCLFNLS_V8HI
UNSPEC_NNPA_VCRNFS_V8HI
UNSPEC_NNPA_VCFN_V8HI
UNSPEC_NNPA_VCNF_V8HI
])
;;
;; UNSPEC_VOLATILE usage
;;
(define_c_enum "unspecv" [
; Blockage
UNSPECV_BLOCKAGE
; TPF Support
UNSPECV_TPF_PROLOGUE
UNSPECV_TPF_EPILOGUE
; Literal pool
UNSPECV_POOL
UNSPECV_POOL_SECTION
UNSPECV_POOL_ALIGN
UNSPECV_POOL_ENTRY
UNSPECV_MAIN_POOL
; TLS support
UNSPECV_SET_TP
; Atomic Support
UNSPECV_CAS
UNSPECV_ATOMIC_OP
; Non-branch nops used for compare-and-branch adjustments on z10
UNSPECV_NOP_LR_0
UNSPECV_NOP_LR_1
; Hotpatching (unremovable NOPs)
UNSPECV_NOP_2_BYTE
UNSPECV_NOP_4_BYTE
UNSPECV_NOP_6_BYTE
; Transactional Execution support
UNSPECV_TBEGIN
UNSPECV_TBEGIN_TDB
UNSPECV_TBEGINC
UNSPECV_TEND
UNSPECV_TABORT
UNSPECV_ETND
UNSPECV_NTSTG
UNSPECV_PPA
; Set and get floating point control register
UNSPECV_SFPC
UNSPECV_EFPC
; Split stack support
UNSPECV_SPLIT_STACK_CALL
UNSPECV_OSC_BREAK
])
;;
;; Registers
;;
; Registers with special meaning
(define_constants
[
; Sibling call register.
(SIBCALL_REGNUM 1)
; A call-clobbered reg which can be used in indirect branch thunks
(INDIRECT_BRANCH_THUNK_REGNUM 1)
; Literal pool base register.
(BASE_REGNUM 13)
; Return address register.
(RETURN_REGNUM 14)
; Stack pointer register.
(STACK_REGNUM 15)
; 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)
(GPR1_REGNUM 1)
(GPR2_REGNUM 2)
(GPR6_REGNUM 6)
; Floating point registers.
(FPR0_REGNUM 16)
(FPR1_REGNUM 20)
(FPR2_REGNUM 17)
(FPR3_REGNUM 21)
(FPR4_REGNUM 18)
(FPR5_REGNUM 22)
(FPR6_REGNUM 19)
(FPR7_REGNUM 23)
(FPR8_REGNUM 24)
(FPR9_REGNUM 28)
(FPR10_REGNUM 25)
(FPR11_REGNUM 29)
(FPR12_REGNUM 26)
(FPR13_REGNUM 30)
(FPR14_REGNUM 27)
(FPR15_REGNUM 31)
(VR0_REGNUM 16)
(VR16_REGNUM 38)
(VR23_REGNUM 45)
(VR24_REGNUM 46)
(VR31_REGNUM 53)
])
; Rounding modes for binary floating point numbers
(define_constants
[(BFP_RND_CURRENT 0)
(BFP_RND_NEAREST_TIE_AWAY_FROM_0 1)
(BFP_RND_PREP_FOR_SHORT_PREC 3)
(BFP_RND_NEAREST_TIE_TO_EVEN 4)
(BFP_RND_TOWARD_0 5)
(BFP_RND_TOWARD_INF 6)
(BFP_RND_TOWARD_MINF 7)])
; Rounding modes for decimal floating point numbers
; 1-7 were introduced with the floating point extension facility
; available with z196
; With these rounding modes (1-7) a quantum exception might occur
; which is suppressed for the other modes.
(define_constants
[(DFP_RND_CURRENT 0)
(DFP_RND_NEAREST_TIE_AWAY_FROM_0_QUANTEXC 1)
(DFP_RND_CURRENT_QUANTEXC 2)
(DFP_RND_PREP_FOR_SHORT_PREC_QUANTEXC 3)
(DFP_RND_NEAREST_TIE_TO_EVEN_QUANTEXC 4)
(DFP_RND_TOWARD_0_QUANTEXC 5)
(DFP_RND_TOWARD_INF_QUANTEXC 6)
(DFP_RND_TOWARD_MINF_QUANTEXC 7)
(DFP_RND_NEAREST_TIE_TO_EVEN 8)
(DFP_RND_TOWARD_0 9)
(DFP_RND_TOWARD_INF 10)
(DFP_RND_TOWARD_MINF 11)
(DFP_RND_NEAREST_TIE_AWAY_FROM_0 12)
(DFP_RND_NEAREST_TIE_TO_0 13)
(DFP_RND_AWAY_FROM_0 14)
(DFP_RND_PREP_FOR_SHORT_PREC 15)])
;;
;; 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_FPRX2 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)
; Decide whether current DFP or BFD rounding mode should be used
; for the conversion.
(PFPO_RND_MODE_DFP 0)
(PFPO_RND_MODE_BFP 1)
])
;; PPA constants
; Immediate values which can be used as the third operand to the
; perform processor assist instruction
(define_constants
[(PPA_TX_ABORT 1)
(PPA_OOO_BARRIER 15)])
; Immediate operands for tbegin and tbeginc
(define_constants [(TBEGIN_MASK 65292)]) ; 0xff0c
(define_constants [(TBEGINC_MASK 65288)]) ; 0xff08
;; 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,SIL,RRS,RIS,VRI,VRR,VRS,VRV,VRX,VSI"
(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")
(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"))
; mnemonics which only get defined through if_then_else currently
; don't get added to the list values automatically and hence need to
; be listed here.
(define_attr "mnemonic" "b,bas,basr,bc,bcr_flush,unknown" (const_string "unknown"))
;; 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") (const_int 4)]
(const_int 6)))
;; Processor type. This attribute must exactly match the processor_type
;; enumeration in s390.h.
(define_attr "cpu" "z900,z990,z9_109,z9_ec,z10,z196,zEC12,z13,z14,z15,z16"
(const (symbol_ref "s390_tune_attr")))
(define_attr "cpu_facility"
"standard,ieee,zarch,cpu_zarch,longdisp,extimm,dfp,z10,z196,zEC12,vx,z13,z14,vxe,z15,vxe2,z16,nnpa"
(const_string "standard"))
(define_attr "enabled" ""
(cond [(eq_attr "cpu_facility" "standard")
(const_int 1)
(and (eq_attr "cpu_facility" "ieee")
(match_test "TARGET_CPU_IEEE_FLOAT"))
(const_int 1)
(and (eq_attr "cpu_facility" "zarch")
(match_test "TARGET_ZARCH"))
(const_int 1)
(and (eq_attr "cpu_facility" "longdisp")
(match_test "TARGET_LONG_DISPLACEMENT"))
(const_int 1)
(and (eq_attr "cpu_facility" "extimm")
(match_test "TARGET_EXTIMM"))
(const_int 1)
(and (eq_attr "cpu_facility" "dfp")
(match_test "TARGET_DFP"))
(const_int 1)
(eq_attr "cpu_facility" "cpu_zarch")
(const_int 1)
(and (eq_attr "cpu_facility" "z10")
(match_test "TARGET_Z10"))
(const_int 1)
(and (eq_attr "cpu_facility" "z196")
(match_test "TARGET_Z196"))
(const_int 1)
(and (eq_attr "cpu_facility" "zEC12")
(match_test "TARGET_ZEC12"))
(const_int 1)
(and (eq_attr "cpu_facility" "vx")
(match_test "TARGET_VX"))
(const_int 1)
(and (eq_attr "cpu_facility" "z13")
(match_test "TARGET_Z13"))
(const_int 1)
(and (eq_attr "cpu_facility" "z14")
(match_test "TARGET_Z14"))
(const_int 1)
(and (eq_attr "cpu_facility" "vxe")
(match_test "TARGET_VXE"))
(const_int 1)
(and (eq_attr "cpu_facility" "z15")
(match_test "TARGET_Z15"))
(const_int 1)
(and (eq_attr "cpu_facility" "vxe2")
(match_test "TARGET_VXE2"))
(const_int 1)
(and (eq_attr "cpu_facility" "z16")
(match_test "TARGET_Z16"))
(const_int 1)
(and (eq_attr "cpu_facility" "nnpa")
(match_test "TARGET_NNPA"))
(const_int 1)
]
(const_int 0)))
;; Whether an instruction supports relative long addressing.
;; Currently this corresponds to RIL-b and RIL-c instruction formats,
;; but having a separate attribute, as opposed to reusing op_type,
;; provides additional flexibility.
(define_attr "relative_long" "no,yes" (const_string "no"))
;; Pipeline description for z900.
(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")
;; Pipeline description for zEC12
(include "2827.md")
;; Pipeline description for z13
(include "2964.md")
;; Pipeline description for z14
(include "3906.md")
;; Pipeline description for z15
(include "8561.md")
;; Pipeline description for z16
(include "3931.md")
;; Predicates
(include "predicates.md")
;; Constraint definitions
(include "constraints.md")
;; Other includes
(include "tpf.md")
;; Iterators
(define_mode_iterator ALL [TI DI SI HI QI TF FPRX2 DF SF TD DD SD V1QI V2QI
V4QI V8QI V16QI V1HI V2HI V4HI V8HI V1SI V2SI V4SI
V1DI V2DI V1SF V2SF V4SF V1TI V1DF V2DF V1TF])
;; These mode iterators allow floating point patterns to be generated from the
;; same template.
(define_mode_iterator FP_ALL [(TF "!TARGET_VXE") (FPRX2 "TARGET_VXE") DF SF
(TD "TARGET_HARD_DFP") (DD "TARGET_HARD_DFP")
(SD "TARGET_HARD_DFP")])
(define_mode_iterator FP [(TF "!TARGET_VXE") (FPRX2 "TARGET_VXE") DF SF
(TD "TARGET_HARD_DFP") (DD "TARGET_HARD_DFP")])
;; Like FP, but without a condition on TF. Useful for expanders that must be
;; the same for FP and VR variants of TF.
(define_mode_iterator FP_ANYTF [TF (FPRX2 "TARGET_VXE") DF SF
(TD "TARGET_HARD_DFP")
(DD "TARGET_HARD_DFP")])
(define_mode_iterator BFP [(TF "!TARGET_VXE") (FPRX2 "TARGET_VXE") 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 "!TARGET_VXE") (FPRX2 "TARGET_VXE") TD])
; 32 bit int<->fp conversion instructions are available since VXE2 (z15).
(define_mode_iterator VX_CONV_BFP [DF (SF "TARGET_VXE2")])
(define_mode_iterator VX_CONV_INT [DI (SI "TARGET_VXE2")])
;; 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 DGPR [(TI "TARGET_ZARCH") DI SI])
(define_mode_iterator DSI [DI SI])
(define_mode_iterator TDI [TI DI])
;; 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")])
;; Used by the umul pattern to express modes having half the size.
(define_mode_attr DWH [(TI "DI") (DI "SI")])
(define_mode_attr dwh [(TI "di") (DI "si")])
;; 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 DINT [(TI "TARGET_ZARCH") DI SI HI QI])
(define_mode_iterator SINT [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 allows r[ox]sbg to be defined with the same template
(define_code_iterator IXOR [ior xor])
;; This is used for merging the nand/nor and and/or with complement patterns
(define_code_iterator ANDOR [and ior])
(define_code_attr bitops_name [(and "and") (ior "or")])
(define_code_attr inv_bitops_name [(and "or") (ior "and")])
(define_code_attr inv_no [(and "o") (ior "n")])
;; This iterator is used to expand the patterns for the nearest
;; integer functions.
(define_int_iterator FPINT [UNSPEC_FPINT_FLOOR UNSPEC_FPINT_BTRUNC
UNSPEC_FPINT_ROUND UNSPEC_FPINT_CEIL
UNSPEC_FPINT_NEARBYINT])
(define_int_attr fpint_name [(UNSPEC_FPINT_FLOOR "floor")
(UNSPEC_FPINT_BTRUNC "btrunc")
(UNSPEC_FPINT_ROUND "round")
(UNSPEC_FPINT_CEIL "ceil")
(UNSPEC_FPINT_NEARBYINT "nearbyint")])
(define_int_attr fpint_roundingmode [(UNSPEC_FPINT_FLOOR "7")
(UNSPEC_FPINT_BTRUNC "5")
(UNSPEC_FPINT_ROUND "1")
(UNSPEC_FPINT_CEIL "6")
(UNSPEC_FPINT_NEARBYINT "0")])
;; 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 "or") (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") (FPRX2 "x") (DF "d") (SF "e") (TD "x")
(DD "d") (SD "e") (V4SF "e") (V2DF "d")])
;; 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")])
;; 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.
;; These mode attributes are supposed to be used in the `enabled' insn
;; attribute to disable certain alternatives for certain modes.
(define_mode_attr nBFP [(TF "0") (FPRX2 "0") (DF "0") (SF "0") (TD "*")
(DD "*") (DD "*")])
(define_mode_attr nDFP [(TF "*") (FPRX2 "*") (DF "*") (SF "*") (TD "0")
(DD "0") (DD "0")])
(define_mode_attr DSF [(TF "0") (FPRX2 "0") (DF "*") (SF "*") (TD "0")
(DD "0") (SD "0")])
(define_mode_attr DFDI [(TF "0") (FPRX2 "0") (DF "*") (SF "0")
(TD "0") (DD "0") (DD "0")
(TI "0") (DI "*") (SI "0")])
(define_mode_attr SFSI [(TF "0") (FPRX2 "0") (DF "0") (SF "*")
(TD "0") (DD "0") (DD "0")
(TI "0") (DI "0") (SI "*")])
(define_mode_attr DF [(TF "0") (FPRX2 "0") (DF "*") (SF "0")
(TD "0") (DD "0") (DD "0")
(TI "0") (DI "0") (SI "0")])
(define_mode_attr SF [(TF "0") (FPRX2 "0") (DF "0") (SF "*")
(TD "0") (DD "0") (DD "0")
(TI "0") (DI "0") (SI "0")])
;; 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") (FPRX2 "0") (DF "f") (SF "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") (FPRX2 "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 "") (FPRX2 "") (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 TDI templates, a string like "csg".
(define_mode_attr td [(TI "d") (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") (FPRX2 "DF") (TD "DD")])
;; Maximum unsigned integer that fits in MODE.
(define_mode_attr max_uint [(HI "65535") (QI "255")])
;; Start and end field computations for RISBG et al.
(define_mode_attr bfstart [(DI "s") (SI "t")])
(define_mode_attr bfend [(DI "e") (SI "f")])
;; In place of GET_MODE_BITSIZE (mode)
(define_mode_attr bitsize [(DI "64") (SI "32") (HI "16") (QI "8")])
;; 64 - bitsize
(define_mode_attr bitoff [(DI "0") (SI "32") (HI "48") (QI "56")])
(define_mode_attr bitoff_plus [(DI "") (SI "32+") (HI "48+") (QI "56+")])
;; In place of GET_MODE_SIZE (mode)
(define_mode_attr modesize [(DI "8") (SI "4")])
;; Allow return and simple_return to be defined from a single template.
(define_code_iterator ANY_RETURN [return simple_return])
;; Facilitate dispatching TFmode expanders on z14+.
(define_mode_attr tf_fpr [(TF "_fpr") (FPRX2 "") (DF "") (SF "") (TD "")
(DD "") (SD "")])
;; Mode names as seen in type mode_attr values.
(define_mode_attr type [(TF "tf") (FPRX2 "tf") (DF "df") (SF "sf") (TD "td")
(DD "dd") (SD "sd")])
; Condition code modes generated by vector fp comparisons. These will
; be used also in single element mode.
(define_mode_iterator VFCMP [CCVEQ CCVFH CCVFHE])
; Used with VFCMP to expand part of the mnemonic
; For fp we have a mismatch: eq in the insn name - e in asm
(define_mode_attr asm_fcmp [(CCVEQ "e") (CCVFH "h") (CCVFHE "he")])
(define_mode_attr insn_cmp [(CCVEQ "eq") (CCVIH "h") (CCVIHU "hl") (CCVFH "h") (CCVFHE "he")])
;; Subst pattern definitions
(include "subst.md")
(include "vector.md")
;;
;;- 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 "cpu_facility" "*,longdisp")
(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,T") 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,T")
(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") ])
; Peephole to combine a load-and-test from volatile memory which combine does
; not do.
(define_peephole2
[(set (match_operand:GPR 0 "register_operand")
(match_operand:GPR 2 "memory_operand"))
(set (reg CC_REGNUM)
(compare (match_dup 0) (match_operand:GPR 1 "const0_operand")))]
"s390_match_ccmode (peep2_next_insn (1), CCSmode) && TARGET_EXTIMM
&& GENERAL_REG_P (operands[0])
&& satisfies_constraint_T (operands[2])
&& !contains_constant_pool_address_p (operands[2])"
[(parallel
[(set (reg:CCS CC_REGNUM)
(compare:CCS (match_dup 2) (match_dup 1)))
(set (match_dup 0) (match_dup 2))])])
; ltr, lt, ltgr, ltg
(define_insn "*tst_cconly_extimm"
[(set (reg CC_REGNUM)
(compare (match_operand:GPR 0 "nonimmediate_operand" "d,T")
(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 "cpu_facility" "*,*,longdisp")
(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 "cpu_facility" "*,*,longdisp")
(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 "cpu_facility" "*,longdisp,*")
(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 "cpu_facility" "*,longdisp,*")
(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 "cpu_facility" "*,longdisp,*")
(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 "cpu_facility" "*,longdisp")
(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 "cpu_facility" "*,longdisp")
(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,T,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 "cpu_facility" "*,*,*,*,longdisp,*")
(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,T,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")
(set_attr "relative_long" "*,*,yes")])
(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" "*,longdisp,z10")
(set_attr "type" "*,*,larl")
(set_attr "z196prop" "z196_cracked,z196_cracked,z196_cracked")
(set_attr "relative_long" "*,*,yes")])
(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" "T,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")
(set_attr "relative_long" "*,yes")])
; 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,*,longdisp,z10")
(set_attr "type" "*,*,*,*,*,*,larl")
(set_attr "z10prop" "z10_super_c,z10_super,z10_super,z10_super,z10_super,z10_super,z10_super")
(set_attr "relative_long" "*,*,*,*,*,*,yes")])
; 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")
(set_attr "relative_long" "yes")])
; 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")
(set_attr "relative_long" "yes")])
(define_insn "*cmpdi_ccu_zero"
[(set (reg CC_REGNUM)
(compare (zero_extend:DI (match_operand:SI 1 "nonimmediate_operand"
"d,T,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")
(set_attr "relative_long" "*,*,yes")])
(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,T,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,*,*")
(set_attr "relative_long" "*,*,yes,*,*,*,*")])
(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,*,longdisp,*,*")
(set_attr "type" "*,*,larl,*,*,*,*,*")
(set_attr "z10prop" "z10_super_c,z10_super,z10_super,z10_super,z10_super,z10_super,*,*")
(set_attr "relative_long" "*,*,yes,*,*,*,*,*")])
(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" "*,longdisp,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 "cpu_facility" "*,longdisp,*,longdisp,*,*")
(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
; load and test instructions turn a signaling NaN into a quiet NaN. Thus they
; may only be used if the target register is dead afterwards or if fast math
; is enabled. The former is done via a peephole optimization. Note, load and
; test instructions may only be used for (in)equality comparisons because
; relational comparisons must treat a quiet NaN like a signaling NaN which is
; not the case for load and test instructions. For fast math insn
; "cmp_ccs_0_fastmath" applies.
; See testcases load-and-test-fp-{1,2}.c
(define_peephole2
[(set (match_operand:FP 0 "register_operand")
(match_operand:FP 1 "const0_operand"))
(set (reg:CCZ CC_REGNUM)
(compare:CCZ (match_operand:FP 2 "register_operand")
(match_operand:FP 3 "register_operand")))]
"TARGET_HARD_FLOAT
&& FP_REG_P (operands[2])
&& REGNO (operands[0]) == REGNO (operands[3])
&& peep2_reg_dead_p (2, operands[0])
&& peep2_reg_dead_p (2, operands[2])"
[(parallel
[(set (reg:CCZ CC_REGNUM)
(compare:CCZ (match_dup 2) (match_dup 1)))
(clobber (match_dup 2))])]
"")
; ltxbr, ltdbr, ltebr, ltxtr, ltdtr
(define_insn "*cmp_ccz_0"
[(set (reg:CCZ CC_REGNUM)
(compare:CCZ (match_operand:FP 0 "register_operand" "f")
(match_operand:FP 1 "const0_operand")))
(clobber (match_operand:FP 2 "register_operand" "=0"))]
"TARGET_HARD_FLOAT"
"ltr\t%0,%0"
[(set_attr "op_type" "RRE")
(set_attr "type" "fsimp")])
(define_insn "*cmp_ccs_0_fastmath"
[(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
&& !flag_trapping_math
&& !flag_signaling_nans"
"ltr\t%0,%0"
[(set_attr "op_type" "RRE")
(set_attr "type" "fsimp")])
; VX: TFmode in FPR pairs: use cxbr instead of wfcxb
; cxtr, cdtr, cxbr, cdbr, cebr, cdb, ceb, wfcsb, wfcdb
(define_insn "*cmp_ccs"
[(set (reg CC_REGNUM)
(compare (match_operand:FP 0 "register_operand" "f,f,v,v")
(match_operand:FP 1 "general_operand" "f,R,v,v")))]
"s390_match_ccmode(insn, CCSmode) && TARGET_HARD_FLOAT"
"@
cr\t%0,%1
cb\t%0,%1
wfcdb\t%0,%1
wfcsb\t%0,%1"
[(set_attr "op_type" "RRE,RXE,VRR,VRR")
(set_attr "cpu_facility" "*,*,vx,vxe")
(set_attr "enabled" "*,,,")])
; VX: TFmode in VR: use wfcxb
(define_insn "*cmptf_ccs"
[(set (reg CC_REGNUM)
(compare (match_operand:TF 0 "register_operand" "v")
(match_operand:TF 1 "register_operand" "v")))]
"s390_match_ccmode(insn, CCSmode) && TARGET_VXE"
"wfcxb\t%0,%1"
[(set_attr "op_type" "VRR")
(set_attr "cpu_facility" "vxe")])
; VX: TFmode in FPR pairs: use kxbr instead of wfkxb
; kxtr, kdtr, kxbr, kdbr, kebr, kdb, keb, wfksb, wfkdb
(define_insn "*cmp_ccsfps"
[(set (reg CC_REGNUM)
(compare (match_operand:FP 0 "register_operand" "f,f,v,v")
(match_operand:FP 1 "general_operand" "f,R,v,v")))]
"s390_match_ccmode (insn, CCSFPSmode) && TARGET_HARD_FLOAT"
"@
kr\t%0,%1
kb\t%0,%1
wfkdb\t%0,%1
wfksb\t%0,%1"
[(set_attr "op_type" "RRE,RXE,VRR,VRR")
(set_attr "cpu_facility" "*,*,vx,vxe")
(set_attr "enabled" "*,,,")])
; VX: TFmode in VR: use wfkxb
(define_insn "*cmptf_ccsfps"
[(set (reg CC_REGNUM)
(compare (match_operand:TF 0 "register_operand" "v")
(match_operand:TF 1 "register_operand" "v")))]
"s390_match_ccmode (insn, CCSFPSmode) && TARGET_VXE"
"wfkxb\t%0,%1"
[(set_attr "op_type" "VRR")
(set_attr "cpu_facility" "vxe")])
; 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).
;
; Separate out the register pair alternative since constraints (P) are
; not able to deal with const_wide_int's. But predicates do.
(define_insn "*movti_bigconst"
[(set (match_operand:TI 0 "register_operand" "=d")
(match_operand:TI 1 "reload_const_wide_int_operand" ""))]
"TARGET_ZARCH"
"#")
; FIXME: More constants are possible by enabling jxx, jyy constraints
; for TImode (use double-int for the calculations)
(define_insn "movti"
[(set (match_operand:TI 0 "nonimmediate_operand" "=d,S,v, v, v,v,d,v,R,d, d, d, d, d,o")
(match_operand:TI 1 "general_operand" " S,d,v,j00,jm1,d,v,R,v,K,NxHD0,Os,NxSD0,dT,d"))]
"TARGET_ZARCH"
"@
lmg\t%0,%N0,%S1
stmg\t%1,%N1,%S0
vlr\t%v0,%v1
vzero\t%v0
vone\t%v0
vlvgp\t%v0,%1,%N1
#
vl\t%v0,%1%A1
vst\t%v1,%0%A0
#
#
#
#
#
#"
[(set_attr "op_type" "RSY,RSY,VRR,VRI,VRI,VRR,*,VRX,VRX,*,*,*,*,*,*")
(set_attr "type" "lm,stm,*,*,*,*,*,*,*,*,*,*,*,*,*")
(set_attr "cpu_facility" "*,*,vx,vx,vx,vx,vx,vx,vx,*,*,*,extimm,*,*")])
(define_split
[(set (match_operand:TI 0 "nonimmediate_operand" "")
(match_operand:TI 1 "general_operand" ""))]
"TARGET_ZARCH && reload_completed
&& !s_operand (operands[0], TImode)
&& !s_operand (operands[1], TImode)
&& 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
&& !s_operand (operands[0], TImode)
&& !s_operand (operands[1], TImode)
&& 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);
})
; Use part of the TImode target reg to perform the address
; calculation. If the TImode value is supposed to be copied into a VR
; this splitter is not necessary.
(define_split
[(set (match_operand:TI 0 "register_operand" "")
(match_operand:TI 1 "memory_operand" ""))]
"TARGET_ZARCH && reload_completed
&& !VECTOR_REG_P (operands[0])
&& !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);
})
; Split a VR -> GPR TImode move into 2 vector load GR from VR element.
; For the higher order bits we do simply a DImode move while the
; second part is done via vec extract. Both will end up as vlgvg.
(define_split
[(set (match_operand:TI 0 "register_operand" "")
(match_operand:TI 1 "register_operand" ""))]
"TARGET_VX && reload_completed
&& GENERAL_REG_P (operands[0])
&& VECTOR_REG_P (operands[1])"
[(set (match_dup 2) (match_dup 4))
(set (match_dup 3) (unspec:DI [(match_dup 5) (const_int 1)]
UNSPEC_VEC_EXTRACT))]
{
operands[2] = operand_subword (operands[0], 0, 0, TImode);
operands[3] = operand_subword (operands[0], 1, 0, TImode);
operands[4] = gen_rtx_REG (DImode, REGNO (operands[1]));
operands[5] = gen_rtx_REG (V2DImode, REGNO (operands[1]));
})
;
; 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:ALL 0 "memory_operand" "")
(match_operand:ALL 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:ALL 0 "register_operand" "=d")
(match_operand:ALL 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;
})
; Not all the indirect memory access instructions support the full
; format (long disp + index + base). So whenever a move from/to such
; an address is required and the instruction cannot deal with it we do
; a load address into a scratch register first and use this as the new
; base register.
; This in particular is used for:
; - non-offsetable memory accesses for multiword moves
; - full vector reg moves with long displacements
(define_expand "reload_la_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_la_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_64"
[(set (match_operand:DI 0 "nonimmediate_operand"
"=d, d, d, d, d, d, d, d,f,d,!*f,d,d,d,d,T,!*f,!*f,!*f,!R,!T,b,Q,d,t,Q,t,v,v,v,d,v,R,d")
(match_operand:DI 1 "general_operand"
" K,N0HD0,N1HD0,N2HD0,N3HD0,Os,N0SD0,N1SD0,d,f,j00,L,b,d,T,d, *f, R, T,*f,*f,d,K,t,d,t,Q,K,v,d,v,R,v,ZL"))]
"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
lzdr\t%0
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
vleig\t%v0,%h1,0
vlr\t%v0,%v1
vlvgg\t%v0,%1,0
vlgvg\t%0,%v1,0
vleg\t%v0,%1,0
vsteg\t%v1,%0,0
larl\t%0,%1%K1"
[(set_attr "op_type" "RI,RI,RI,RI,RI,RIL,RIL,RIL,RRE,RRE,RRE,RXY,RIL,RRE,RXY,
RXY,RR,RX,RXY,RX,RXY,RIL,SIL,*,*,RS,RS,VRI,VRR,VRS,VRS,
VRX,VRX,RIL")
(set_attr "type" "*,*,*,*,*,*,*,*,floaddf,floaddf,fsimpdf,la,larl,lr,load,store,
floaddf,floaddf,floaddf,fstoredf,fstoredf,larl,*,*,*,*,
*,*,*,*,*,*,*,larl")
(set_attr "cpu_facility" "*,*,*,*,*,extimm,extimm,extimm,dfp,dfp,*,longdisp,
z10,*,*,*,*,*,longdisp,*,longdisp,
z10,z10,*,*,*,*,vx,vx,vx,vx,vx,vx,*")
(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,
*,
*,
*,
*,*,*,*,*,*,*,
z10_super_A1")
(set_attr "relative_long" "*,*,*,*,*,*,*,*,*,*,*,
*,yes,*,*,*,*,*,*,*,*,
yes,*,*,*,*,*,*,*,*,*,
*,*,yes")
])
; Splitters for loading TLS pointer from UNSPEC_GET_TP.
; UNSPEC_GET_TP is used instead of %a0:P, since the latter is a hard register,
; and those are not handled by Partial Redundancy Elimination (gcse.cc), which
; results in generation of redundant thread pointer loads.
(define_insn_and_split "*get_tp_31"
[(set (match_operand:SI 0 "register_operand" "=r")
(unspec:SI [(match_operand:SI 1 "register_operand" "t")]
UNSPEC_GET_TP))]
""
"#"
"&& reload_completed"
[(set (match_dup 0) (match_dup 1))])
(define_insn_and_split "*get_tp_64"
[(set (match_operand:DI 0 "register_operand" "=r")
(unspec:DI [(match_operand:DI 1 "register_operand" "t")]
UNSPEC_GET_TP))]
"TARGET_ZARCH"
"#"
"&& reload_completed"
[(set (match_dup 2) (match_dup 4))
(set (match_dup 0) (ashift:DI (match_dup 0) (const_int 32)))
(set (strict_low_part (match_dup 3)) (match_dup 5))]
"operands[2] = gen_lowpart (SImode, operands[0]);
operands[3] = s390_gen_lowpart_subreg (SImode, operands[0]);
s390_split_access_reg (operands[1], &operands[5], &operands[4]);")
; Splitters for storing TLS pointer to %a0:DI.
(define_split
[(set (match_operand:DI 0 "register_operand" "")
(match_operand:DI 1 "register_operand" ""))]
"TARGET_ZARCH && ACCESS_REG_P (operands[0]) && reload_completed
&& 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]) && reload_completed
&& !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,!*f,!R,!T,d")
(match_operand:DI 1 "general_operand"
" Q,S,d,d,dPT,d, *f, R, T,j00,*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
lzdr\t%0
std\t%1,%0
stdy\t%1,%0
#"
[(set_attr "op_type" "RS,RSY,RS,RSY,*,*,RR,RX,RXY,RRE,RX,RXY,*")
(set_attr "type" "lm,lm,stm,stm,*,*,floaddf,floaddf,floaddf,fsimpdf,fstoredf,fstoredf,*")
(set_attr "cpu_facility" "*,longdisp,*,longdisp,*,*,*,*,longdisp,*,*,longdisp,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
&& !s_operand (operands[0], DImode)
&& !s_operand (operands[1], DImode)
&& 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
&& !s_operand (operands[0], DImode)
&& !s_operand (operands[1], DImode)
&& 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" "ZR,ZT"))]
"TARGET_64BIT"
"@
la\t%0,%a1
lay\t%0,%a1"
[(set_attr "op_type" "RX,RXY")
(set_attr "type" "la")
(set_attr "cpu_facility" "*,longdisp")
(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)))]
"")
; Split loading of 64-bit constants into GPRs into llihf + oilf -
; counterintuitively, using oilf is faster than iilf. oilf clobbers
; cc, so cc must be dead.
(define_peephole2
[(set (match_operand:DI 0 "register_operand" "")
(match_operand:DI 1 "memory_operand" ""))]
"TARGET_64BIT
&& TARGET_EXTIMM
&& GENERAL_REG_P (operands[0])
&& s390_const_int_pool_entry_p (operands[1], nullptr)
&& peep2_reg_dead_p (1, gen_rtx_REG (CCmode, CC_REGNUM))"
[(set (match_dup 0) (match_dup 2))
(parallel
[(set (match_dup 0) (ior:DI (match_dup 0) (match_dup 3)))
(clobber (reg:CC CC_REGNUM))])]
{
HOST_WIDE_INT val;
bool ok = s390_const_int_pool_entry_p (operands[1], &val);
gcc_assert (ok);
operands[2] = GEN_INT (val & 0xFFFFFFFF00000000ULL);
operands[3] = GEN_INT (val & 0x00000000FFFFFFFFULL);
})
;
; 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
&& !FP_REG_P (operands[0])"
"larl\t%0,%1%K1"
[(set_attr "op_type" "RIL")
(set_attr "type" "larl")
(set_attr "z10prop" "z10_fwd_A1")
(set_attr "relative_long" "yes")])
(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,!*f,!*f,!R,!T,d,t,Q,b,Q,t,v,v,v,d,v,R")
(match_operand:SI 1 "general_operand"
" K,N0HS0,N1HS0,Os,L,b,d,R,T,d,d, *f, *f, R, R, T,*f,*f,t,d,t,d,K,Q,K,v,d,v,R,v"))]
"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
ldr\t%0,%1
ler\t%0,%1
lde\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
vleif\t%v0,%h1,0
vlr\t%v0,%v1
vlvgf\t%v0,%1,0
vlgvf\t%0,%v1,0
vlef\t%v0,%1,0
vstef\t%v1,%0,0"
[(set_attr "op_type" "RI,RI,RI,RIL,RXY,RIL,RR,RX,RXY,RX,RXY,
RR,RR,RXE,RX,RXY,RX,RXY,RRE,RRE,RS,RIL,SIL,RS,VRI,VRR,VRS,VRS,VRX,VRX")
(set_attr "type" "*,
*,
*,
*,
la,
larl,
lr,
load,
load,
store,
store,
floadsf,
floadsf,
floadsf,
floadsf,
floadsf,
fstoresf,
fstoresf,
*,
*,
*,
larl,
*,
*,*,*,*,*,*,*")
(set_attr "cpu_facility" "*,*,*,extimm,longdisp,z10,*,*,longdisp,*,longdisp,
vx,*,vx,*,longdisp,*,longdisp,*,*,*,z10,z10,*,vx,vx,vx,vx,vx,vx")
(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,
*,*,*,*,*,*,*")
(set_attr "relative_long" "*,*,*,*,*,yes,*,*,*,*,
*,*,*,*,*,*,*,*,*,*,
*,yes,*,*,*,*,*,*,*,*")])
(define_insn "*movsi_esa"
[(set (match_operand:SI 0 "nonimmediate_operand" "=d,d,d,R,!*f,!*f,!*f,!*f,!R,d,t,Q,t")
(match_operand:SI 1 "general_operand" "K,d,R,d, *f, *f, R, R,*f,t,d,t,Q"))]
"!TARGET_ZARCH"
"@
lhi\t%0,%h1
lr\t%0,%1
l\t%0,%1
st\t%1,%0
ldr\t%0,%1
ler\t%0,%1
lde\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,RR,RXE,RX,RX,RRE,RRE,RS,RS")
(set_attr "type" "*,lr,load,store,floadsf,floadsf,floadsf,floadsf,fstoresf,*,*,*,*")
(set_attr "z10prop" "z10_fwd_A1,z10_fr_E1,z10_fwd_A3,z10_rec,*,*,*,*,*,z10_super_E1,
z10_super,*,*")
(set_attr "cpu_facility" "*,*,*,*,vx,*,vx,*,*,*,*,*,*")
])
(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" "ZR,ZT"))]
"!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 "cpu_facility" "*,longdisp")
(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" "ZR,ZT")
(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 "cpu_facility" "*,longdisp")
(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" "ZR,ZT"))
(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 "cpu_facility" "*,longdisp")
(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 (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,v,v,v,d,v,R")
(match_operand:HI 1 "general_operand" " d,n,R,T,b,d,d,d,K,K,v,d,v,R,v"))]
""
"@
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
vleih\t%v0,%h1,0
vlr\t%v0,%v1
vlvgh\t%v0,%1,0
vlgvh\t%0,%v1,0
vleh\t%v0,%1,0
vsteh\t%v1,%0,0"
[(set_attr "op_type" "RR,RI,RX,RXY,RIL,RX,RXY,RIL,SIL,VRI,VRR,VRS,VRS,VRX,VRX")
(set_attr "type" "lr,*,*,*,larl,store,store,store,*,*,*,*,*,*,*")
(set_attr "cpu_facility" "*,*,*,longdisp,z10,*,longdisp,z10,z10,vx,vx,vx,vx,vx,vx")
(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,*,*,*,*,*,*")
(set_attr "relative_long" "*,*,*,*,yes,*,*,yes,*,*,*,*,*,*,*")])
(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 (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,v,v,v,d,v,R")
(match_operand:QI 1 "general_operand" " d,n,R,T,d,d,n,n,?Q,K,v,d,v,R,v"))]
""
"@
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
#
vleib\t%v0,%b1,0
vlr\t%v0,%v1
vlvgb\t%v0,%1,0
vlgvb\t%0,%v1,0
vleb\t%v0,%1,0
vsteb\t%v1,%0,0"
[(set_attr "op_type" "RR,RI,RX,RXY,RX,RXY,SI,SIY,SS,VRI,VRR,VRS,VRS,VRX,VRX")
(set_attr "type" "lr,*,*,*,store,store,store,store,*,*,*,*,*,*,*")
(set_attr "cpu_facility" "*,*,*,longdisp,*,longdisp,*,longdisp,*,vx,vx,vx,vx,vx,vx")
(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]);")
;
; movstrict instruction pattern(s).
;
(define_insn "movstrictqi"
[(set (strict_low_part (match_operand:QI 0 "subreg_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 "cpu_facility" "*,longdisp")
(set_attr "z10prop" "z10_super_E1,z10_super_E1")])
(define_insn "movstricthi"
[(set (strict_low_part (match_operand:HI 0 "subreg_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 "cpu_facility" "*,longdisp")
(set_attr "z10prop" "z10_super_E1,z10_super_E1")])
(define_insn "movstrictsi"
[(set (strict_low_part (match_operand:SI 0 "subreg_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 "cpu_facility" "*,*,longdisp,*")
(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,S, d,o")
(match_operand:TD_TF 1 "general_operand" " G,f,o,f,S,d,dT,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
&& !s_operand (operands[0], mode)
&& !s_operand (operands[1], mode)
&& 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
&& !s_operand (operands[0], mode)
&& !s_operand (operands[1], mode)
&& 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
&& GENERAL_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,d,b,T,v,v,v,d,v,R")
(match_operand:DD_DF 1 "general_operand"
" G,f,d,f,R,T,f,f,G,d,b,T,d,d,v,G,d,v,R,v"))]
"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
lgrl\t%0,%1
lg\t%0,%1
stgrl\t%1,%0
stg\t%1,%0
vlr\t%v0,%v1
vleig\t%v0,0,0
vlvgg\t%v0,%1,0
vlgvg\t%0,%v1,0
vleg\t%0,%1,0
vsteg\t%1,%0,0"
[(set_attr "op_type" "RRE,RR,RRE,RRE,RX,RXY,RX,RXY,RI,RRE,RIL,RXY,RIL,RXY,VRR,VRI,VRS,VRS,VRX,VRX")
(set_attr "type" "fsimpdf,floaddf,floaddf,floaddf,floaddf,floaddf,
fstoredf,fstoredf,*,lr,load,load,store,store,*,*,*,*,load,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,*,*,*,*,longdisp,*,longdisp,*,*,z10,*,z10,*,vx,vx,vx,vx,vx,vx")
(set_attr "relative_long" "*,*,*,*,*,*,*,*,*,*,yes,*,yes,*,*,*,*,*,*,*")])
(define_insn "*mov_64"
[(set (match_operand:DD_DF 0 "nonimmediate_operand" "=f,f,f,f,R,T,d,d,d,d,b,T")
(match_operand:DD_DF 1 "general_operand" " G,f,R,T,f,f,G,d,b,T,d,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
lgrl\t%0,%1
lg\t%0,%1
stgrl\t%1,%0
stg\t%1,%0"
[(set_attr "op_type" "RRE,RR,RX,RXY,RX,RXY,RI,RRE,RIL,RXY,RIL,RXY")
(set_attr "type" "fsimpdf,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,*,*,longdisp,*,longdisp,*,*,z10,*,z10,*")
(set_attr "relative_long" "*,*,*,*,*,*,*,*,yes,*,*,*")])
(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,dPT,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,*,*,longdisp,*,longdisp,*,longdisp,*,longdisp,*,*")])
(define_split
[(set (match_operand:DD_DF 0 "nonimmediate_operand" "")
(match_operand:DD_DF 1 "general_operand" ""))]
"!TARGET_ZARCH && reload_completed
&& !s_operand (operands[0], mode)
&& !s_operand (operands[1], mode)
&& 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
&& !s_operand (operands[0], mode)
&& !s_operand (operands[1], mode)
&& 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,f,f,R,T,d,d,d,d,d,b,R,T,v,v,v,d,v,R")
(match_operand:SD_SF 1 "general_operand"
" G,f,f,R,R,T,f,f,G,d,b,R,T,d,d,d,v,G,d,v,R,v"))]
""
"@
lzer\t%0
ldr\t%0,%1
ler\t%0,%1
lde\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
lrl\t%0,%1
l\t%0,%1
ly\t%0,%1
strl\t%1,%0
st\t%1,%0
sty\t%1,%0
vlr\t%v0,%v1
vleif\t%v0,0,0
vlvgf\t%v0,%1,0
vlgvf\t%0,%v1,0
vlef\t%0,%1,0
vstef\t%1,%0,0"
[(set_attr "op_type" "RRE,RR,RR,RXE,RX,RXY,RX,RXY,RI,RR,RIL,RX,RXY,RIL,RX,RXY,VRR,VRI,VRS,VRS,VRX,VRX")
(set_attr "type" "fsimpsf,fsimpsf,fload,fload,fload,fload,
fstore,fstore,*,lr,load,load,load,store,store,store,*,*,*,*,load,store")
(set_attr "z10prop" "*,*,*,*,*,*,*,*,z10_fwd_A1,z10_fr_E1,z10_fr_E1,z10_fwd_A3,z10_fwd_A3,z10_rec,z10_rec,z10_rec,*,*,*,*,*,*")
(set_attr "cpu_facility" "z196,vx,*,vx,*,longdisp,*,longdisp,*,*,z10,*,longdisp,z10,*,longdisp,vx,vx,vx,vx,vx,vx")
(set_attr "relative_long" "*,*,*,*,*,*,*,*,*,*,yes,*,*,yes,*,*,*,*,*,*,*,*")])
;
; 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
l\t%0,%1
ly\t%0,%1
st\t%1,%0
sty\t%1,%0"
[(set_attr "op_type" "RR,RI,RRE,RX,RXY,RX,RXY")
(set_attr "type" "lr,*,*,load,load,store,store")
(set_attr "cpu_facility" "*,*,*,*,longdisp,*,longdisp")
(set_attr "z10prop" "z10_fr_E1,z10_super,*,z10_fwd_A3,z10_fwd_A3,z10_rec,z10_rec")
(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" ""))])]
"((INTVAL (operands[2]) > 16 && INTVAL (operands[5]) > 16)
|| (INTVAL (operands[2]) + INTVAL (operands[5]) <= 16))
&& 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]));")
(define_peephole2
[(parallel
[(set (match_operand:BLK 0 "plus16_Q_operand" "")
(match_operand:BLK 1 "plus16_Q_operand" ""))
(use (match_operand 2 "const_int_operand" ""))])]
"INTVAL (operands[2]) > 16 && INTVAL (operands[2]) <= 32"
[(parallel
[(set (match_dup 0) (match_dup 1))
(use (const_int 16))])
(parallel
[(set (match_dup 3) (match_dup 4))
(use (match_dup 5))])]
"operands[3] = change_address (operands[0], VOIDmode,
plus_constant (Pmode, XEXP (operands[0], 0), 16));
operands[4] = change_address (operands[1], VOIDmode,
plus_constant (Pmode, XEXP (operands[1], 0), 16));
operands[5] = GEN_INT (INTVAL (operands[2]) - 16);")
;
; 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"
{
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 (gen_rtx_REG (mode, regno + i),
change_address (operands[1], mode,
plus_constant (Pmode, 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" "S"))])]
"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 "cpu_facility" "*,longdisp")
(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"
{
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 (change_address (operands[0], mode,
plus_constant (Pmode, 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" "=S")
(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 "cpu_facility" "*,longdisp")
(set_attr "type" "stm")])
;;
;; String instructions.
;;
(define_insn "*execute_rl"
[(match_parallel 0 "execute_operation"
[(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")
(set_attr "relative_long" "yes")])
(define_insn "*execute"
[(match_parallel 0 "execute_operation"
[(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"
[(match_operand:P 0 "register_operand" "") ; result
(match_operand:BLK 1 "memory_operand" "") ; input string
(match_operand:SI 2 "immediate_operand" "") ; search character
(match_operand:SI 3 "immediate_operand" "")] ; known alignment
""
{
if (!TARGET_VX || operands[2] != const0_rtx)
emit_insn (gen_strlen_srst (operands[0], operands[1],
operands[2], operands[3]));
else
s390_expand_vec_strlen (operands[0], operands[1], operands[3]);
DONE;
})
(define_expand "strlen_srst"
[(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_STRCMPCC_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"
[(match_operand 0 "register_operand" "")
(match_operand 1 "memory_operand" "")
(match_operand 2 "memory_operand" "")]
""
{
if (TARGET_64BIT)
emit_insn (gen_movstrdi (operands[0], operands[1], operands[2]));
else
emit_insn (gen_movstrsi (operands[0], operands[1], operands[2]));
DONE;
})
(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:P 0 "register_operand" "")
(unspec:P [(match_dup 1)
(match_dup 2)
(reg:SI 0)] UNSPEC_MVST))
(clobber (reg:CC CC_REGNUM))])]
""
{
rtx addr1, addr2;
if (TARGET_VX && optimize_function_for_speed_p (cfun))
{
s390_expand_vec_movstr (operands[0], operands[1], operands[2]);
DONE;
}
addr1 = gen_reg_rtx (Pmode);
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:P [(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")])
;
; cpymemM instruction pattern(s).
;
(define_expand "cpymem"
[(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 "" "")]
""
{
if (s390_expand_cpymem (operands[0], operands[1], operands[2]))
DONE;
else
FAIL;
})
; Move a block that is up to 256 bytes in length.
; The block length is taken as (operands[2] % 256) + 1.
(define_expand "cpymem_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 "*cpymem_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:P 4 "=X,X,X,&a"))]
"(GET_MODE (operands[2]) == Pmode || GET_MODE (operands[2]) == VOIDmode)"
"#"
[(set_attr "type" "cs")
(set_attr "cpu_facility" "*,*,z10,cpu_zarch")])
(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"
[(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 "cpymem_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))])]
""
{
machine_mode sreg_mode = TARGET_ZARCH ? DImode : SImode;
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 "*cpymem_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 "*cpymem_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_CC_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_CC_TO_INT))]
"TARGET_HARD_FLOAT"
{
operands[2] = GEN_INT (S390_TDC_INFINITY);
})
; This extracts CC into a GPR properly shifted. The actual IPM
; instruction will be issued by reload. The constraint of operand 1
; forces reload to use a GPR. So reload will issue a movcc insn for
; copying CC into a GPR first.
(define_insn_and_split "*cc_to_int"
[(set (match_operand:SI 0 "nonimmediate_operand" "=d")
(unspec:SI [(match_operand 1 "register_operand" "0")]
UNSPEC_CC_TO_INT))]
""
"#"
"reload_completed"
[(set (match_dup 0) (lshiftrt:SI (match_dup 0) (const_int 28)))])
; 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).
;
; tcxb, tcdb, tceb, tdcxt, tdcdt, tdcet
(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")])
;
; 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:P 3 "=X,X,X,&a"))
(clobber (reg:CC CC_REGNUM))]
"(GET_MODE (operands[1]) == Pmode || GET_MODE (operands[1]) == VOIDmode)"
"#"
[(set_attr "type" "cs")
(set_attr "cpu_facility" "*,*,z10,cpu_zarch")])
(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"
[(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" "")
(unspec:BLK [(match_operand:P 2 "setmem_operand" "")
(match_dup 4)] UNSPEC_REPLICATE_BYTE))
(use (match_dup 3))
(clobber (reg:CC CC_REGNUM))])]
""
{
machine_mode sreg_mode = TARGET_ZARCH ? DImode : SImode;
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;
operands[4] = gen_lowpart (Pmode, operands[1]);
})
; Patterns for 31 bit + Esa and 64 bit + Zarch.
(define_insn "*setmem_long"
[(clobber (match_operand: 0 "register_operand" "=d"))
(set (mem:BLK (subreg:P (match_operand: 3 "register_operand" "0") 0))
(unspec:BLK [(match_operand:P 2 "setmem_operand" "Y")
(subreg:P (match_dup 3) )]
UNSPEC_REPLICATE_BYTE))
(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))
(unspec:BLK [(zero_extend:P (match_operand:QI 2 "setmem_operand" "Y"))
(subreg:P (match_dup 3) )]
UNSPEC_REPLICATE_BYTE))
(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")])
; Variants for 31 bit + Zarch, necessary because of the odd in-register offsets
; of the SImode subregs.
(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))
(unspec:BLK [(match_operand:SI 2 "setmem_operand" "Y")
(subreg:SI (match_dup 3) 12)] UNSPEC_REPLICATE_BYTE))
(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")])
(define_insn "*setmem_long_and_31z"
[(clobber (match_operand:TI 0 "register_operand" "=d"))
(set (mem:BLK (subreg:SI (match_operand:TI 3 "register_operand" "0") 4))
(unspec:BLK [(zero_extend:SI (match_operand:QI 2 "setmem_operand" "Y"))
(subreg:SI (match_dup 3) 12)] UNSPEC_REPLICATE_BYTE))
(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 "" ""))]
""
{
if (s390_expand_cmpmem (operands[0], operands[1],
operands[2], operands[3]))
DONE;
else
FAIL;
})
; 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:P 4 "=X,X,X,&a"))]
"(GET_MODE (operands[2]) == Pmode || GET_MODE (operands[2]) == VOIDmode)"
"#"
[(set_attr "type" "cs")
(set_attr "cpu_facility" "*,*,z10,cpu_zarch")])
(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"
[(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))])]
""
{
machine_mode sreg_mode = TARGET_ZARCH ? DImode : SImode;
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_STRCMPCC_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_STRCMPCC_TO_INT)
(const_int 0)))
(set (match_operand:SI 0 "register_operand" "=d")
(unspec:SI [(match_dup 1)] UNSPEC_STRCMPCC_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_STRCMPCC_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_STRCMPCC_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_STRCMPCC_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 "cpu_facility" "*,longdisp")
(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" "S")
(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 "cpu_facility" "*,longdisp")
(set_attr "z10prop" "z10_super_E1,z10_super_E1")])
;
; extv instruction patterns
;
; FIXME: This expander needs to be converted from DI to GPR as well
; after resolving some issues with it.
(define_expand "extzv"
[(parallel
[(set (match_operand:DI 0 "register_operand" "=d")
(zero_extract:DI
(match_operand:DI 1 "register_operand" "d")
(match_operand 2 "const_int_operand" "") ; size
(match_operand 3 "const_int_operand" ""))) ; start
(clobber (reg:CC CC_REGNUM))])]
"TARGET_Z10"
{
if (! EXTRACT_ARGS_IN_RANGE (INTVAL (operands[2]), INTVAL (operands[3]), 64))
FAIL;
/* Starting with zEC12 there is risbgn not clobbering CC. */
if (TARGET_ZEC12)
{
emit_move_insn (operands[0],
gen_rtx_ZERO_EXTRACT (DImode,
operands[1],
operands[2],
operands[3]));
DONE;
}
})
(define_insn "*extzv"
[(set (match_operand:GPR 0 "register_operand" "=d")
(zero_extract:GPR
(match_operand:GPR 1 "register_operand" "d")
(match_operand 2 "const_int_operand" "") ; size
(match_operand 3 "const_int_operand" ""))) ; start
]
"
&& EXTRACT_ARGS_IN_RANGE (INTVAL (operands[2]), INTVAL (operands[3]),
GET_MODE_BITSIZE (mode))"
"\t%0,%1,64-%2,128+63,%3+%2" ; dst, src, start, end, shift
[(set_attr "op_type" "RIE")
(set_attr "z10prop" "z10_super_E1")])
; 64 bit: (a & -16) | ((b >> 8) & 15)
(define_insn "*extzvdi_lshiftrt"
[(set (zero_extract:DI (match_operand:DI 0 "register_operand" "+d")
(match_operand 1 "const_int_operand" "") ; size
(match_operand 2 "const_int_operand" "")) ; start
(lshiftrt:DI (match_operand:DI 3 "register_operand" "d")
(match_operand:DI 4 "nonzero_shift_count_operand" "")))]
"
&& EXTRACT_ARGS_IN_RANGE (INTVAL (operands[1]), INTVAL (operands[2]), 64)
&& 64 - UINTVAL (operands[4]) >= UINTVAL (operands[1])"
"\t%0,%3,%2,%2+%1-1,128-%2-%1-%4"
[(set_attr "op_type" "RIE")
(set_attr "z10prop" "z10_super_E1")])
; (a & -16) | ((b >> 8) & 15)
(define_insn "*_ior_and_sr_ze"
[(set (match_operand:DSI 0 "register_operand" "=d")
(ior:DSI (and:DSI
(match_operand:DSI 1 "register_operand" "0")
(match_operand:DSI 2 "const_int_operand" ""))
(zero_extract:DSI
(match_operand:DSI 3 "register_operand" "d")
(match_operand 4 "const_int_operand" "") ; size
(match_operand 5 "const_int_operand" "")) ; start
))]
"
&& EXTRACT_ARGS_IN_RANGE (INTVAL (operands[4]), INTVAL (operands[5]), )
&& UINTVAL (operands[2]) == (HOST_WIDE_INT_M1U << UINTVAL (operands[4]))"
"\t%0,%3,64-%4,63,(64-)+%4+%5"
[(set_attr "op_type" "RIE")
(set_attr "z10prop" "z10_super_E1")])
; ((int)foo >> 10) & 1;
(define_insn "*extract1bitdi"
[(set (match_operand:DI 0 "register_operand" "=d")
(ne:DI (zero_extract:DI
(match_operand:DI 1 "register_operand" "d")
(const_int 1) ; size
(match_operand 2 "const_int_operand" "")) ; start
(const_int 0)))]
"
&& EXTRACT_ARGS_IN_RANGE (1, INTVAL (operands[2]), 64)"
"\t%0,%1,64-1,128+63,%2+1" ; dst, src, start, end, shift
[(set_attr "op_type" "RIE")
(set_attr "z10prop" "z10_super_E1")])
(define_insn "*_and_subregdi_rotr"
[(set (match_operand:DI 0 "register_operand" "=d")
(and:DI (subreg:DI
(rotate:SINT (match_operand:SINT 1 "register_operand" "d")
(match_operand:SINT 2 "const_int_operand" "")) 0)
(match_operand:DI 3 "contiguous_bitmask_operand" "")))]
"
&& (UINTVAL (operands[3])
< (HOST_WIDE_INT_1U << (UINTVAL (operands[2]) & 0x3f)))"
"\t%0,%1,%s3,128+%e3,%2" ; dst, src, start, end, shift
[(set_attr "op_type" "RIE")
(set_attr "z10prop" "z10_super_E1")])
(define_insn "*_and_subregdi_rotl"
[(set (match_operand:DI 0 "register_operand" "=d")
(and:DI (subreg:DI
(rotate:SINT (match_operand:SINT 1 "register_operand" "d")
(match_operand:SINT 2 "const_int_operand" "")) 0)
(match_operand:DI 3 "contiguous_bitmask_operand" "")))]
"
&& !(UINTVAL (operands[3])
& ((HOST_WIDE_INT_1U << (UINTVAL (operands[2]) & 0x3f)) - 1))"
"\t%0,%1,%s3,128+%e3,%2" ; dst, src, start, end, shift
[(set_attr "op_type" "RIE")
(set_attr "z10prop" "z10_super_E1")])
(define_insn "*_di_and_rot"
[(set (match_operand:DI 0 "register_operand" "=d")
(and:DI (rotate:DI (match_operand:DI 1 "register_operand" "d")
(match_operand:DI 2 "const_int_operand" ""))
(match_operand:DI 3 "contiguous_bitmask_operand" "")))]
""
"\t%0,%1,%s3,128+%e3,%2" ; dst, src, start, end, shift
[(set_attr "op_type" "RIE")
(set_attr "z10prop" "z10_super_E1")])
(define_insn_and_split "*pre_z10_extzv"
[(set (match_operand:GPR 0 "register_operand" "=d")
(zero_extract:GPR (match_operand:QI 1 "s_operand" "S")
(match_operand 2 "nonzero_shift_count_operand" "")
(const_int 0)))
(clobber (reg:CC CC_REGNUM))]
"!TARGET_Z10"
"#"
"&& 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 */
unsigned HOST_WIDE_INT mask
= ((HOST_WIDE_INT_1U << size) - 1) << (GET_MODE_SIZE (SImode) - size);
operands[1] = adjust_address (operands[1], BLKmode, 0);
set_mem_size (operands[1], size);
operands[2] = GEN_INT ( - bitsize);
operands[3] = GEN_INT (mask);
})
(define_insn_and_split "*pre_z10_extv"
[(set (match_operand:GPR 0 "register_operand" "=d")
(sign_extract:GPR (match_operand:QI 1 "s_operand" "S")
(match_operand 2 "nonzero_shift_count_operand" "")
(const_int 0)))
(clobber (reg:CC CC_REGNUM))]
""
"#"
"&& 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 */
unsigned HOST_WIDE_INT mask
= ((HOST_WIDE_INT_1U << size) - 1) << (GET_MODE_SIZE (SImode) - size);
operands[1] = adjust_address (operands[1], BLKmode, 0);
set_mem_size (operands[1], size);
operands[2] = GEN_INT ( - 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;
})
; The normal RTL expansion will never generate a zero_extract where
; the location operand isn't word mode. However, we do this in the
; back-end when generating atomic operations. See s390_two_part_insv.
(define_insn "*insv"
[(set (zero_extract:GPR (match_operand:GPR 0 "nonimmediate_operand" "+d")
(match_operand 1 "const_int_operand" "I") ; size
(match_operand 2 "const_int_operand" "I")) ; pos
(match_operand:GPR 3 "nonimmediate_operand" "d"))]
"
&& EXTRACT_ARGS_IN_RANGE (INTVAL (operands[1]), INTVAL (operands[2]),
GET_MODE_BITSIZE (mode))
&& (INTVAL (operands[1]) + INTVAL (operands[2])) <= "
"\t%0,%3,%2,%2+%1-1,-%2-%1"
[(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_noshift"
[(set (match_operand:GPR 0 "nonimmediate_operand" "=d,d")
(ior:GPR (and:GPR (match_operand:GPR 1 "nonimmediate_operand" "d,0")
(match_operand:GPR 2 "contiguous_bitmask_operand" ""))
(and:GPR (match_operand:GPR 3 "nonimmediate_operand" "0,d")
(match_operand:GPR 4 "const_int_operand" ""))))]
" && INTVAL (operands[2]) == ~INTVAL (operands[4])"
"@
\t%0,%1,%2,%