Files
wasmtime/cranelift/codegen/src/isa/x64/inst.isle

2058 lines
71 KiB
Common Lisp

;; Extern type definitions and constructors for the x64 `MachInst` type.
;;;; `MInst` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Don't build `MInst` variants directly, in general. Instead, use the
;; instruction-emitting helpers defined further down.
(type MInst nodebug
(enum
;; Nops of various sizes, including zero.
(Nop (len u8))
;; =========================================
;; Integer instructions.
;; Integer arithmetic/bit-twiddling.
(AluRmiR (size OperandSize) ;; 4 or 8
(op AluRmiROpcode)
(src1 Reg)
(src2 RegMemImm)
(dst WritableReg))
;; Instructions on general-purpose registers that only read src and
;; defines dst (dst is not modified). `bsr`, etc.
(UnaryRmR (size OperandSize) ;; 2, 4, or 8
(op UnaryRmROpcode)
(src GprMem)
(dst WritableGpr))
;; Bitwise not.
(Not (size OperandSize) ;; 1, 2, 4, or 8
(src Gpr)
(dst WritableGpr))
;; Integer negation.
(Neg (size OperandSize) ;; 1, 2, 4, or 8
(src Gpr)
(dst WritableGpr))
;; Integer quotient and remainder: (div idiv) $rax $rdx (reg addr)
(Div (size OperandSize) ;; 1, 2, 4, or 8
(signed bool)
(divisor RegMem)
(dividend Reg)
(dst_quotient WritableReg)
(dst_remainder WritableReg))
;; The high (and low) bits of a (un)signed multiply: `RDX:RAX := RAX *
;; rhs`.
(MulHi (size OperandSize)
(signed bool)
(src1 Reg)
(src2 RegMem)
(dst_lo WritableReg)
(dst_hi WritableReg))
;; A synthetic sequence to implement the right inline checks for
;; remainder and division, assuming the dividend is in %rax.
;;
;; Puts the result back into %rax if is_div, %rdx if !is_div, to mimic
;; what the div instruction does.
;;
;; The generated code sequence is described in the emit's function match
;; arm for this instruction.
;;
;; Note: %rdx is marked as modified by this instruction, to avoid an
;; early clobber problem with the temporary and divisor registers. Make
;; sure to zero %rdx right before this instruction, or you might run into
;; regalloc failures where %rdx is live before its first def!
(CheckedDivOrRemSeq (kind DivOrRemKind)
(size OperandSize)
(dividend Reg)
;; The divisor operand. Note it's marked as modified
;; so that it gets assigned a register different from
;; the temporary.
(divisor WritableReg)
(dst_quotient WritableReg)
(dst_remainder WritableReg)
(tmp OptionWritableReg))
;; Do a sign-extend based on the sign of the value in rax into rdx: (cwd
;; cdq cqo) or al into ah: (cbw)
(SignExtendData (size OperandSize) ;; 1, 2, 4, or 8
(src Reg)
(dst WritableReg))
;; Constant materialization: (imm32 imm64) reg.
;;
;; Either: movl $imm32, %reg32 or movabsq $imm64, %reg32.
(Imm (dst_size OperandSize) ;; 4 or 8
(simm64 u64)
(dst WritableReg))
;; GPR to GPR move: mov (64 32) reg reg.
(MovRR (size OperandSize) ;; 4 or 8
(src Reg)
(dst WritableReg))
;; Zero-extended loads, except for 64 bits: movz (bl bq wl wq lq) addr
;; reg.
;;
;; Note that the lq variant doesn't really exist since the default
;; zero-extend rule makes it unnecessary. For that case we emit the
;; equivalent "movl AM, reg32".
(MovzxRmR (ext_mode ExtMode)
(src RegMem)
(dst WritableReg))
;; A plain 64-bit integer load, since MovZX_RM_R can't represent that.
(Mov64MR (src SyntheticAmode)
(dst WritableReg))
;; Loads the memory address of addr into dst.
(LoadEffectiveAddress (addr SyntheticAmode)
(dst WritableGpr))
;; Sign-extended loads and moves: movs (bl bq wl wq lq) addr reg.
(MovsxRmR (ext_mode ExtMode)
(src RegMem)
(dst WritableReg))
;; Integer stores: mov (b w l q) reg addr.
(MovRM (size OperandSize) ;; 1, 2, 4, or 8
(src Reg)
(dst SyntheticAmode))
;; Arithmetic shifts: (shl shr sar) (b w l q) imm reg.
(ShiftR (size OperandSize) ;; 1, 2, 4, or 8
(kind ShiftKind)
(src Reg)
;; shift count: `Imm8Reg::Imm8(0 .. #bits-in-type - 1)` or
;; `Imm8Reg::Reg(r)` where `r` get's move mitosis'd into `%cl`.
(num_bits Imm8Reg)
(dst WritableReg))
;; Arithmetic SIMD shifts.
(XmmRmiReg (opcode SseOpcode)
(src1 Xmm)
(src2 XmmMemImm)
(dst WritableXmm))
;; Integer comparisons/tests: cmp or test (b w l q) (reg addr imm) reg.
(CmpRmiR (size OperandSize) ;; 1, 2, 4, or 8
(opcode CmpOpcode)
(src RegMemImm)
(dst Reg))
;; Materializes the requested condition code in the destinaton reg.
(Setcc (cc CC)
(dst WritableReg))
;; Integer conditional move.
;;
;; Overwrites the destination register.
(Cmove (size OperandSize)
(cc CC)
(consequent RegMem)
(alternative Reg)
(dst WritableReg))
;; =========================================
;; Stack manipulation.
;; pushq (reg addr imm)
(Push64 (src RegMemImm))
;; popq reg
(Pop64 (dst WritableReg))
;; =========================================
;; Floating-point operations.
;; XMM (scalar or vector) binary op: (add sub and or xor mul adc? sbb?)
;; (32 64) (reg addr) reg
(XmmRmR (op SseOpcode)
(src1 Xmm)
(src2 XmmMem)
(dst WritableXmm))
;; XMM (scalar or vector) binary op that relies on the EVEX prefix.
(XmmRmREvex (op Avx512Opcode)
(src1 XmmMem)
(src2 Xmm)
(dst WritableXmm))
;; XMM (scalar or vector) unary op: mov between XMM registers (32 64)
;; (reg addr) reg, sqrt, etc.
;;
;; This differs from XMM_RM_R in that the dst register of XmmUnaryRmR is
;; not used in the computation of the instruction dst value and so does
;; not have to be a previously valid value. This is characteristic of mov
;; instructions.
(XmmUnaryRmR (op SseOpcode)
(src XmmMem)
(dst WritableXmm))
;; XMM (scalar or vector) unary op that relies on the EVEX prefix.
(XmmUnaryRmREvex (op Avx512Opcode)
(src XmmMem)
(dst WritableXmm))
;; XMM (scalar or vector) unary op (from xmm to reg/mem): stores, movd,
;; movq
(XmmMovRM (op SseOpcode)
(src Reg)
(dst SyntheticAmode))
;; XMM (vector) unary op (to move a constant value into an xmm register):
;; movups
(XmmLoadConst (src VCodeConstant)
(dst WritableReg)
(ty Type))
;; XMM (scalar) unary op (from xmm to integer reg): movd, movq,
;; cvtts{s,d}2si
(XmmToGpr (op SseOpcode)
(src Xmm)
(dst WritableGpr)
(dst_size OperandSize))
;; XMM (scalar) unary op (from integer to float reg): movd, movq,
;; cvtsi2s{s,d}
(GprToXmm (op SseOpcode)
(src RegMem)
(dst WritableXmm)
(src_size OperandSize))
;; Converts an unsigned int64 to a float32/float64.
(CvtUint64ToFloatSeq (dst_size OperandSize) ;; 4 or 8
;; A copy of the source register, fed by
;; lowering. It is marked as modified during
;; register allocation to make sure that the
;; temporary registers differ from the src register,
;; since both registers are live at the same time in
;; the generated code sequence.
(src WritableGpr)
(dst WritableXmm)
(tmp_gpr1 WritableGpr)
(tmp_gpr2 WritableGpr))
;; Converts a scalar xmm to a signed int32/int64.
(CvtFloatToSintSeq (dst_size OperandSize)
(src_size OperandSize)
(is_saturating bool)
;; A copy of the source register, fed by
;; lowering. It is marked as modified during
;; register allocation to make sure that the
;; temporary registers differ from the src register,
;; since both registers are live at the same time in
;; the generated code sequence.
(src WritableXmm)
(dst WritableGpr)
(tmp_gpr WritableGpr)
(tmp_xmm WritableXmm))
;; Converts a scalar xmm to an unsigned int32/int64.
(CvtFloatToUintSeq (dst_size OperandSize)
(src_size OperandSize)
(is_saturating bool)
;; A copy of the source register, fed by
;; lowering. It is marked as modified during
;; register allocation to make sure that the
;; temporary registers differ from the src register,
;; since both registers are live at the same time in
;; the generated code sequence.
(src WritableXmm)
(dst WritableGpr)
(tmp_gpr WritableGpr)
(tmp_xmm WritableXmm))
;; A sequence to compute min/max with the proper NaN semantics for xmm
;; registers.
(XmmMinMaxSeq (size OperandSize)
(is_min bool)
(lhs Reg)
(rhs_dst WritableReg))
;; XMM (scalar) conditional move.
;;
;; Overwrites the destination register if cc is set.
(XmmCmove (size OperandSize)
(cc CC)
(src RegMem)
(dst WritableReg))
;; Float comparisons/tests: cmp (b w l q) (reg addr imm) reg.
(XmmCmpRmR (op SseOpcode)
(src RegMem)
(dst Reg))
;; A binary XMM instruction with an 8-bit immediate: e.g. cmp (ps pd) imm
;; (reg addr) reg
;;
;; Note: this has to use `Reg*`, not `Xmm*`, operands because it is used
;; in various lane insertion and extraction instructions that move
;; between XMMs and GPRs.
(XmmRmRImm (op SseOpcode)
(src1 Reg)
(src2 RegMem)
(dst WritableReg)
(imm u8)
(size OperandSize))
;; =========================================
;; Control flow instructions.
;; Direct call: call simm32.
(CallKnown (dest ExternalName)
(uses VecReg)
(defs VecWritableReg)
(opcode Opcode))
;; Indirect call: callq (reg mem)
(CallUnknown (dest RegMem)
(uses VecReg)
(defs VecWritableReg)
(opcode Opcode))
;; Return.
(Ret)
;; A placeholder instruction, generating no code, meaning that a function
;; epilogue must be inserted there.
(EpiloguePlaceholder)
;; Jump to a known target: jmp simm32.
(JmpKnown (dst MachLabel))
;; One-way conditional branch: jcond cond target.
;;
;; This instruction is useful when we have conditional jumps depending on
;; more than two conditions, see for instance the lowering of Brz/brnz
;; with Fcmp inputs.
;;
;; A note of caution: in contexts where the branch target is another
;; block, this has to be the same successor as the one specified in the
;; terminator branch of the current block. Otherwise, this might confuse
;; register allocation by creating new invisible edges.
(JmpIf (cc CC)
(taken MachLabel))
;; Two-way conditional branch: jcond cond target target.
;;
;; Emitted as a compound sequence; the MachBuffer will shrink it as
;; appropriate.
(JmpCond (cc CC)
(taken MachLabel)
(not_taken MachLabel))
;; Jump-table sequence, as one compound instruction (see note in lower.rs
;; for rationale).
;;
;; The generated code sequence is described in the emit's function match
;; arm for this instruction.
;;
;; See comment in lowering about the temporaries signedness.
(JmpTableSeq (idx Reg)
(tmp1 WritableReg)
(tmp2 WritableReg)
(default_target MachLabel)
(targets VecMachLabel)
(targets_for_term VecMachLabel))
;; Indirect jump: jmpq (reg mem).
(JmpUnknown (target RegMem))
;; Traps if the condition code is set.
(TrapIf (cc CC)
(trap_code TrapCode))
;; A debug trap.
(Hlt)
;; An instruction that will always trigger the illegal instruction
;; exception.
(Ud2 (trap_code TrapCode))
;; Loads an external symbol in a register, with a relocation:
;;
;; movq $name@GOTPCREL(%rip), dst if PIC is enabled, or
;; movabsq $name, dst otherwise.
(LoadExtName (dst WritableReg)
(name BoxExternalName)
(offset i64))
;; =========================================
;; Instructions pertaining to atomic memory accesses.
;; A standard (native) `lock cmpxchg src, (amode)`, with register
;; conventions:
;;
;; `mem` (read) address
;; `replacement` (read) replacement value
;; %rax (modified) in: expected value, out: value that was actually at `dst`
;; %rflags is written. Do not assume anything about it after the instruction.
;;
;; The instruction "succeeded" iff the lowest `ty` bits of %rax
;; afterwards are the same as they were before.
(LockCmpxchg (ty Type) ;; I8, I16, I32, or I64
(replacement Reg)
(expected Reg)
(mem SyntheticAmode)
(dst_old WritableReg))
;; A synthetic instruction, based on a loop around a native `lock
;; cmpxchg` instruction.
;;
;; This atomically modifies a value in memory and returns the old value.
;; The sequence consists of an initial "normal" load from `dst`, followed
;; by a loop which computes the new value and tries to compare-and-swap
;; ("CAS") it into `dst`, using the native instruction `lock
;; cmpxchg{b,w,l,q}` . The loop iterates until the CAS is successful.
;; If there is no contention, there will be only one pass through the
;; loop body. The sequence does *not* perform any explicit memory fence
;; instructions (mfence/sfence/lfence).
;;
;; Note that the transaction is atomic in the sense that, as observed by
;; some other thread, `dst` either has the initial or final value, but no
;; other. It isn't atomic in the sense of guaranteeing that no other
;; thread writes to `dst` in between the initial load and the CAS -- but
;; that would cause the CAS to fail unless the other thread's last write
;; before the CAS wrote the same value that was already there. In other
;; words, this implementation suffers (unavoidably) from the A-B-A
;; problem.
;;
;; This instruction sequence has fixed register uses as follows:
;;
;; %r9 (read) address
;; %r10 (read) second operand for `op`
;; %r11 (written) scratch reg; value afterwards has no meaning
;; %rax (written) the old value at %r9
;; %rflags is written. Do not assume anything about it after the instruction.
(AtomicRmwSeq (ty Type) ;; I8, I16, I32, or I64
(op AtomicRmwOp)
(address Reg)
(operand Reg)
(temp WritableReg)
(dst_old WritableReg))
;; A memory fence (mfence, lfence or sfence).
(Fence (kind FenceKind))
;; =========================================
;; Meta-instructions generating no code.
;; Marker, no-op in generated code: SP "virtual offset" is adjusted.
;;
;; This controls how `MemArg::NominalSPOffset` args are lowered.
(VirtualSPOffsetAdj (offset i64))
;; Provides a way to tell the register allocator that the upcoming
;; sequence of instructions will overwrite `dst` so it should be
;; considered as a `def`; use this with care.
;;
;; This is useful when we have a sequence of instructions whose register
;; usages are nominally `mod`s, but such that the combination of
;; operations creates a result that is independent of the initial
;; register value. It's thus semantically a `def`, not a `mod`, when all
;; the instructions are taken together, so we want to ensure the register
;; is defined (its live-range starts) prior to the sequence to keep
;; analyses happy.
;;
;; One alternative would be a compound instruction that somehow
;; encapsulates the others and reports its own `def`s/`use`s/`mod`s; this
;; adds complexity (the instruction list is no longer flat) and requires
;; knowledge about semantics and initial-value independence anyway.
(XmmUninitializedValue (dst WritableXmm))
;; A call to the `ElfTlsGetAddr` libcall. Returns address of TLS symbol
;; in `rax`.
(ElfTlsGetAddr (symbol ExternalName))
;; A Mach-O TLS symbol access. Returns address of the TLS symbol in
;; `rax`.
(MachOTlsGetAddr (symbol ExternalName))
;; A definition of a value label.
(ValueLabelMarker (reg Reg)
(label ValueLabel))
;; An unwind pseudoinstruction describing the state of the machine at
;; this program point.
(Unwind (inst UnwindInst))))
(type OperandSize extern
(enum Size8
Size16
Size32
Size64))
(type VCodeConstant (primitive VCodeConstant))
(type FenceKind extern
(enum MFence
LFence
SFence))
;; Get the `OperandSize` for a given `Type`, rounding smaller types up to 32 bits.
(decl operand_size_of_type_32_64 (Type) OperandSize)
(extern constructor operand_size_of_type_32_64 operand_size_of_type_32_64)
;; Get the true `OperandSize` for a given `Type`, with no rounding.
(decl raw_operand_size_of_type (Type) OperandSize)
(extern constructor raw_operand_size_of_type raw_operand_size_of_type)
;; Get the bit width of an `OperandSize`.
(decl operand_size_bits (OperandSize) u16)
(rule (operand_size_bits (OperandSize.Size8)) 8)
(rule (operand_size_bits (OperandSize.Size16)) 16)
(rule (operand_size_bits (OperandSize.Size32)) 32)
(rule (operand_size_bits (OperandSize.Size64)) 64)
(type AluRmiROpcode extern
(enum Add
Adc
Sub
Sbb
And
Or
Xor
Mul
And8
Or8))
(type UnaryRmROpcode extern
(enum Bsr
Bsf
Lzcnt
Tzcnt
Popcnt))
(type DivOrRemKind extern
(enum SignedDiv
UnsignedDiv
SignedRem
UnsignedRem))
(type SseOpcode extern
(enum Addps
Addpd
Addss
Addsd
Andps
Andpd
Andnps
Andnpd
Blendvpd
Blendvps
Comiss
Comisd
Cmpps
Cmppd
Cmpss
Cmpsd
Cvtdq2ps
Cvtdq2pd
Cvtpd2ps
Cvtps2pd
Cvtsd2ss
Cvtsd2si
Cvtsi2ss
Cvtsi2sd
Cvtss2si
Cvtss2sd
Cvttpd2dq
Cvttps2dq
Cvttss2si
Cvttsd2si
Divps
Divpd
Divss
Divsd
Insertps
Maxps
Maxpd
Maxss
Maxsd
Minps
Minpd
Minss
Minsd
Movaps
Movapd
Movd
Movdqa
Movdqu
Movlhps
Movmskps
Movmskpd
Movq
Movss
Movsd
Movups
Movupd
Mulps
Mulpd
Mulss
Mulsd
Orps
Orpd
Pabsb
Pabsw
Pabsd
Packssdw
Packsswb
Packusdw
Packuswb
Paddb
Paddd
Paddq
Paddw
Paddsb
Paddsw
Paddusb
Paddusw
Palignr
Pand
Pandn
Pavgb
Pavgw
Pblendvb
Pcmpeqb
Pcmpeqw
Pcmpeqd
Pcmpeqq
Pcmpgtb
Pcmpgtw
Pcmpgtd
Pcmpgtq
Pextrb
Pextrw
Pextrd
Pinsrb
Pinsrw
Pinsrd
Pmaddubsw
Pmaddwd
Pmaxsb
Pmaxsw
Pmaxsd
Pmaxub
Pmaxuw
Pmaxud
Pminsb
Pminsw
Pminsd
Pminub
Pminuw
Pminud
Pmovmskb
Pmovsxbd
Pmovsxbw
Pmovsxbq
Pmovsxwd
Pmovsxwq
Pmovsxdq
Pmovzxbd
Pmovzxbw
Pmovzxbq
Pmovzxwd
Pmovzxwq
Pmovzxdq
Pmuldq
Pmulhw
Pmulhuw
Pmulhrsw
Pmulld
Pmullw
Pmuludq
Por
Pshufb
Pshufd
Psllw
Pslld
Psllq
Psraw
Psrad
Psrlw
Psrld
Psrlq
Psubb
Psubd
Psubq
Psubw
Psubsb
Psubsw
Psubusb
Psubusw
Ptest
Punpckhbw
Punpckhwd
Punpcklbw
Punpcklwd
Pxor
Rcpss
Roundps
Roundpd
Roundss
Roundsd
Rsqrtss
Shufps
Sqrtps
Sqrtpd
Sqrtss
Sqrtsd
Subps
Subpd
Subss
Subsd
Ucomiss
Ucomisd
Unpcklps
Xorps
Xorpd))
(type CmpOpcode extern
(enum Cmp
Test))
(type RegMemImm extern
(enum
(Reg (reg Reg))
(Mem (addr SyntheticAmode))
(Imm (simm32 u32))))
;; Put the given clif value into a `RegMemImm` operand.
;;
;; Asserts that the value fits into a single register, and doesn't require
;; multiple registers for its representation (like `i128` for example).
;;
;; As a side effect, this marks the value as used.
(decl put_in_reg_mem_imm (Value) RegMemImm)
(extern constructor put_in_reg_mem_imm put_in_reg_mem_imm)
(type RegMem extern
(enum
(Reg (reg Reg))
(Mem (addr SyntheticAmode))))
;; Put the given clif value into a `RegMem` operand.
;;
;; Asserts that the value fits into a single register, and doesn't require
;; multiple registers for its representation (like `i128` for example).
;;
;; As a side effect, this marks the value as used.
(decl put_in_reg_mem (Value) RegMem)
(extern constructor put_in_reg_mem put_in_reg_mem)
(type SyntheticAmode extern (enum))
(decl synthetic_amode_to_reg_mem (SyntheticAmode) RegMem)
(extern constructor synthetic_amode_to_reg_mem synthetic_amode_to_reg_mem)
(type Amode extern (enum))
(decl amode_imm_reg_reg_shift (u32 Gpr Gpr u8) Amode)
(extern constructor amode_imm_reg_reg_shift amode_imm_reg_reg_shift)
(decl amode_to_synthetic_amode (Amode) SyntheticAmode)
(extern constructor amode_to_synthetic_amode amode_to_synthetic_amode)
(type ShiftKind extern
(enum ShiftLeft
ShiftRightLogical
ShiftRightArithmetic
RotateLeft
RotateRight))
(type Imm8Reg extern
(enum (Imm8 (imm u8))
(Reg (reg Reg))))
;; Put the given clif value into a `Imm8Reg` operand, masked to the bit width of
;; the given type.
;;
;; Asserts that the value fits into a single register, and doesn't require
;; multiple registers for its representation (like `i128` for example).
;;
;; As a side effect, this marks the value as used.
;;
;; This is used when lowering various shifts and rotates.
(decl put_masked_in_imm8_reg (Value Type) Imm8Reg)
(extern constructor put_masked_in_imm8_reg put_masked_in_imm8_reg)
(type CC extern
(enum O
NO
B
NB
Z
NZ
BE
NBE
S
NS
L
NL
LE
NLE
P
NP))
(type Avx512Opcode extern
(enum Vcvtudq2ps
Vpabsq
Vpermi2b
Vpmullq
Vpopcntb))
(type FcmpImm extern
(enum Equal
LessThan
LessThanOrEqual
Unordered
NotEqual
UnorderedOrGreaterThanOrEqual
UnorderedOrGreaterThan
Ordered))
(decl encode_fcmp_imm (FcmpImm) u8)
(extern constructor encode_fcmp_imm encode_fcmp_imm)
;;;; Newtypes for Different Register Classes ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(type Gpr (primitive Gpr))
(type WritableGpr (primitive WritableGpr))
(type GprMem extern (enum))
(type GprMemImm extern (enum))
(type Xmm (primitive Xmm))
(type WritableXmm (primitive WritableXmm))
(type XmmMem extern (enum))
(type XmmMemImm extern (enum))
;; Convert a `WritableGpr` to a `WritableReg`.
(decl writable_gpr_to_reg (WritableGpr) WritableReg)
(extern constructor writable_gpr_to_reg writable_gpr_to_reg)
;; Convert a `WritableXmm` to a `WritableReg`.
(decl writable_xmm_to_reg (WritableXmm) WritableReg)
(extern constructor writable_xmm_to_reg writable_xmm_to_reg)
;; Convert a `WritableReg` to a `WritableXmm`.
(decl writable_reg_to_xmm (WritableReg) WritableXmm)
(extern constructor writable_reg_to_xmm writable_reg_to_xmm)
;; Convert a `WritableXmm` to an `Xmm`.
(decl writable_xmm_to_xmm (WritableXmm) Xmm)
(extern constructor writable_xmm_to_xmm writable_xmm_to_xmm)
;; Convert a `WritableGpr` to an `Gpr`.
(decl writable_gpr_to_gpr (WritableGpr) Gpr)
(extern constructor writable_gpr_to_gpr writable_gpr_to_gpr)
;; Convert an `Gpr` to a `Reg`.
(decl gpr_to_reg (Gpr) Reg)
(extern constructor gpr_to_reg gpr_to_reg)
;; Convert an `Xmm` to a `Reg`.
(decl xmm_to_reg (Xmm) Reg)
(extern constructor xmm_to_reg xmm_to_reg)
;; Convert an `Xmm` into an `XmmMemImm`.
(decl xmm_to_xmm_mem_imm (Xmm) XmmMemImm)
(extern constructor xmm_to_xmm_mem_imm xmm_to_xmm_mem_imm)
;; Allocate a new temporary GPR register.
(decl temp_writable_gpr () WritableGpr)
(extern constructor temp_writable_gpr temp_writable_gpr)
;; Allocate a new temporary XMM register.
(decl temp_writable_xmm () WritableXmm)
(extern constructor temp_writable_xmm temp_writable_xmm)
;; Construct a new `XmmMem` from the given `RegMem`.
;;
;; Asserts that the `RegMem`'s register, if any, is an XMM register.
(decl reg_mem_to_xmm_mem (RegMem) XmmMem)
(extern constructor reg_mem_to_xmm_mem reg_mem_to_xmm_mem)
;; Construct a new `GprMemImm` from the given `RegMemImm`.
;;
;; Asserts that the `RegMemImm`'s register, if any, is an GPR register.
(decl gpr_mem_imm_new (RegMemImm) GprMemImm)
(extern constructor gpr_mem_imm_new gpr_mem_imm_new)
;; Construct a new `XmmMemImm` from the given `RegMemImm`.
;;
;; Asserts that the `RegMemImm`'s register, if any, is an XMM register.
(decl xmm_mem_imm_new (RegMemImm) XmmMemImm)
(extern constructor xmm_mem_imm_new xmm_mem_imm_new)
;; Construct a new `XmmMem` from an `Xmm`.
(decl xmm_to_xmm_mem (Xmm) XmmMem)
(extern constructor xmm_to_xmm_mem xmm_to_xmm_mem)
;; Construct a new `XmmMem` from an `RegMem`.
(decl xmm_mem_to_reg_mem (XmmMem) RegMem)
(extern constructor xmm_mem_to_reg_mem xmm_mem_to_reg_mem)
;; Convert a `GprMem` to a `RegMem`.
(decl gpr_mem_to_reg_mem (GprMem) RegMem)
(extern constructor gpr_mem_to_reg_mem gpr_mem_to_reg_mem)
;; Construct a new `Xmm` from a `Reg`.
;;
;; Asserts that the register is a XMM.
(decl xmm_new (Reg) Xmm)
(extern constructor xmm_new xmm_new)
;; Construct a new `Gpr` from a `Reg`.
;;
;; Asserts that the register is a GPR.
(decl gpr_new (Reg) Gpr)
(extern constructor gpr_new gpr_new)
;; Construct a new `GprMem` from a `RegMem`.
;;
;; Asserts that the `RegMem`'s register, if any, is a GPR.
(decl reg_mem_to_gpr_mem (RegMem) GprMem)
(extern constructor reg_mem_to_gpr_mem reg_mem_to_gpr_mem)
;; Construct a `GprMem` from a `Reg`.
;;
;; Asserts that the `Reg` is a GPR.
(decl reg_to_gpr_mem (Reg) GprMem)
(extern constructor reg_to_gpr_mem reg_to_gpr_mem)
;; Put a value into a GPR.
;;
;; Asserts that the value goes into a GPR.
(decl put_in_gpr (Value) Gpr)
(rule (put_in_gpr val)
(gpr_new (put_in_reg val)))
;; Put a value into a `GprMem`.
;;
;; Asserts that the value goes into a GPR.
(decl put_in_gpr_mem (Value) GprMem)
(rule (put_in_gpr_mem val)
(reg_mem_to_gpr_mem (put_in_reg_mem val)))
;; Put a value into a `GprMemImm`.
;;
;; Asserts that the value goes into a GPR.
(decl put_in_gpr_mem_imm (Value) GprMemImm)
(rule (put_in_gpr_mem_imm val)
(gpr_mem_imm_new (put_in_reg_mem_imm val)))
;; Put a value into a XMM.
;;
;; Asserts that the value goes into a XMM.
(decl put_in_xmm (Value) Xmm)
(rule (put_in_xmm val)
(xmm_new (put_in_reg val)))
;; Put a value into a `XmmMem`.
;;
;; Asserts that the value goes into a XMM.
(decl put_in_xmm_mem (Value) XmmMem)
(rule (put_in_xmm_mem val)
(reg_mem_to_xmm_mem (put_in_reg_mem val)))
;; Put a value into a `XmmMemImm`.
;;
;; Asserts that the value goes into a XMM.
(decl put_in_xmm_mem_imm (Value) XmmMemImm)
(rule (put_in_xmm_mem_imm val)
(xmm_mem_imm_new (put_in_reg_mem_imm val)))
;; Construct a `ValueRegs` out of a single GPR register.
(decl value_gpr (Gpr) ValueRegs)
(rule (value_gpr x)
(value_reg (gpr_to_reg x)))
;; Construct a `ValueRegs` out of two GPR registers.
(decl value_gprs (Gpr Gpr) ValueRegs)
(rule (value_gprs x y)
(value_regs (gpr_to_reg x) (gpr_to_reg y)))
;; Construct a `ValueRegs` out of a single XMM register.
(decl value_xmm (Xmm) ValueRegs)
(rule (value_xmm x)
(value_reg (xmm_to_reg x)))
;;;; Helpers for Getting Particular Physical Registers ;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; These should only be used for legalization purposes, when we can't otherwise
;; rely on something like `Inst::mov_mitosis` to put an operand into the
;; appropriate physical register for whatever reason.
(decl xmm0 () WritableXmm)
(extern constructor xmm0 xmm0)
;;;; Helpers for Querying Enabled ISA Extensions ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(decl avx512vl_enabled () Type)
(extern extractor avx512vl_enabled avx512vl_enabled)
(decl avx512dq_enabled () Type)
(extern extractor avx512dq_enabled avx512dq_enabled)
(decl avx512f_enabled () Type)
(extern extractor avx512f_enabled avx512f_enabled)
;;;; Helpers for Merging and Sinking Immediates/Loads ;;;;;;;;;;;;;;;;;;;;;;;;;
;; Extract a constant `Imm8Reg.Imm8` from a value operand.
(decl imm8_from_value (Imm8Reg) Value)
(extern extractor imm8_from_value imm8_from_value)
;; Mask a constant to the bit-width of the given type and package it into an
;; `Imm8Reg.Imm8`. This is used for shifts and rotates, so that we don't try and
;; shift/rotate more bits than the type has available, per Cranelift's
;; semantics.
(decl const_to_type_masked_imm8 (u64 Type) Imm8Reg)
(extern constructor const_to_type_masked_imm8 const_to_type_masked_imm8)
;; Extract a constant `RegMemImm.Imm` from a value operand.
(decl simm32_from_value (RegMemImm) Value)
(extern extractor simm32_from_value simm32_from_value)
;; Extract a constant `RegMemImm.Imm` from an `Imm64` immediate.
(decl simm32_from_imm64 (RegMemImm) Imm64)
(extern extractor simm32_from_imm64 simm32_from_imm64)
;; A load that can be sunk into another operation.
(type SinkableLoad extern (enum))
;; Extract a `SinkableLoad` that works with `RegMemImm.Mem` from a value
;; operand.
(decl sinkable_load (SinkableLoad) Value)
(extern extractor sinkable_load sinkable_load)
;; Sink a `SinkableLoad` into a `RegMemImm.Mem`.
;;
;; This is a side-effectful operation that notifies the context that the
;; instruction that produced the `SinkableImm` has been sunk into another
;; instruction, and no longer needs to be lowered.
(decl sink_load (SinkableLoad) RegMemImm)
(extern constructor sink_load sink_load)
;;;; Helpers for Sign/Zero Extending ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(type ExtKind extern
(enum None
SignExtend
ZeroExtend))
(type ExtendKind (enum Sign Zero))
(type ExtMode extern (enum BL BQ WL WQ LQ))
;; `ExtMode::new`
(decl ext_mode (u16 u16) ExtMode)
(extern constructor ext_mode ext_mode)
;; Put the given value into a register, but extended as the given type.
(decl extend_to_reg (Value Type ExtendKind) Reg)
;; If the value is already of the requested type, no extending is necessary.
(rule (extend_to_reg (and val (value_type ty)) =ty _kind)
(put_in_reg val))
(rule (extend_to_reg (and val (value_type from_ty))
to_ty
kind)
(let ((from_bits u16 (ty_bits_u16 from_ty))
;; Use `operand_size_of_type` so that the we clamp the output to 32-
;; or 64-bit width types.
(to_bits u16 (operand_size_bits (operand_size_of_type_32_64 to_ty))))
(extend kind
to_ty
(ext_mode from_bits to_bits)
(put_in_reg_mem val))))
;; Do a sign or zero extension of the given `RegMem`.
(decl extend (ExtendKind Type ExtMode RegMem) Reg)
;; Zero extending uses `movzx`.
(rule (extend (ExtendKind.Zero) ty mode src)
(movzx ty mode src))
;; Sign extending uses `movsx`.
(rule (extend (ExtendKind.Sign) ty mode src)
(movsx ty mode src))
;;;; Helpers for Working SSE tidbits ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Determine the appropriate operation for xor-ing vectors of the specified type
(decl sse_xor_op (Type) SseOpcode)
(rule (sse_xor_op $F32X4) (SseOpcode.Xorps))
(rule (sse_xor_op $F64X2) (SseOpcode.Xorpd))
(rule (sse_xor_op (multi_lane _bits _lanes)) (SseOpcode.Pxor))
;; Performs an xor operation of the two operands specified.
(decl sse_xor (Type Xmm XmmMem) Xmm)
(rule (sse_xor ty x y) (xmm_rm_r ty (sse_xor_op ty) x y))
;; Determine the appropriate operation to compare two vectors of the specified
;; type.
(decl sse_cmp_op (Type) SseOpcode)
(rule (sse_cmp_op (multi_lane 8 16)) (SseOpcode.Pcmpeqb))
(rule (sse_cmp_op (multi_lane 16 8)) (SseOpcode.Pcmpeqw))
(rule (sse_cmp_op (multi_lane 32 4)) (SseOpcode.Pcmpeqd))
(rule (sse_cmp_op (multi_lane 64 2)) (SseOpcode.Pcmpeqq))
(rule (sse_cmp_op $F32X4) (SseOpcode.Cmpps))
(rule (sse_cmp_op $F64X2) (SseOpcode.Cmppd))
;; Generates a register value which has an all-ones pattern of the specified
;; type.
;;
;; Note that this is accomplished by comparing a fresh register with itself,
;; which for integers is always true. Also note that the comparison is always
;; done for integers, it doesn't actually take the input `ty` into account. This
;; is because we're comparing a fresh register to itself and we don't know the
;; previous contents of the register. If a floating-point comparison is used
;; then it runs the risk of comparing NaN against NaN and not actually producing
;; an all-ones mask. By using integer comparision operations we're guaranteeed
;; that everything is equal to itself.
(decl vector_all_ones (Type) Xmm)
(rule (vector_all_ones ty)
(let ((wr WritableXmm (temp_writable_xmm))
(r Xmm (writable_xmm_to_xmm wr))
(_ Unit (emit (MInst.XmmRmR (sse_cmp_op $I32X4)
r
(xmm_to_xmm_mem r)
wr))))
r))
;; Helper for creating an SSE register holding an `i64x2` from two `i64` values.
(decl make_i64x2_from_lanes (GprMem GprMem) Xmm)
(rule (make_i64x2_from_lanes lo hi)
(let ((dst_xmm_w WritableXmm (temp_writable_xmm))
(dst_reg_w WritableReg (writable_xmm_to_reg dst_xmm_w))
(dst_xmm_r Xmm (writable_xmm_to_xmm dst_xmm_w))
(dst_reg_r Reg (xmm_to_reg dst_xmm_r))
(_0 Unit (emit (MInst.XmmUninitializedValue dst_xmm_w)))
(_1 Unit (emit (MInst.XmmRmRImm (SseOpcode.Pinsrd)
dst_reg_r
(gpr_mem_to_reg_mem lo)
dst_reg_w
0
(OperandSize.Size64))))
(_2 Unit (emit (MInst.XmmRmRImm (SseOpcode.Pinsrd)
dst_reg_r
(gpr_mem_to_reg_mem hi)
dst_reg_w
1
(OperandSize.Size64)))))
dst_xmm_r))
;; Move a `RegMemImm.Reg` operand to an XMM register, if necessary.
(decl mov_rmi_to_xmm (RegMemImm) XmmMemImm)
(rule (mov_rmi_to_xmm rmi @ (RegMemImm.Mem _)) (xmm_mem_imm_new rmi))
(rule (mov_rmi_to_xmm rmi @ (RegMemImm.Imm _)) (xmm_mem_imm_new rmi))
(rule (mov_rmi_to_xmm (RegMemImm.Reg r))
(xmm_to_xmm_mem_imm (gpr_to_xmm (SseOpcode.Movd)
(reg_to_gpr_mem r)
(OperandSize.Size32))))
;;;; Helpers for Emitting Loads ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Load a value into a register.
(decl x64_load (Type SyntheticAmode ExtKind) Reg)
(rule (x64_load (fits_in_32 ty) addr (ExtKind.SignExtend))
(movsx ty
(ext_mode (ty_bytes ty) 8)
(synthetic_amode_to_reg_mem addr)))
(rule (x64_load $I64 addr _ext_kind)
(let ((dst WritableReg (temp_writable_reg $I64))
(_ Unit (emit (MInst.Mov64MR addr dst))))
(writable_reg_to_reg dst)))
(rule (x64_load $F32 addr _ext_kind)
(xmm_to_reg (xmm_unary_rm_r (SseOpcode.Movss)
(reg_mem_to_xmm_mem (synthetic_amode_to_reg_mem addr)))))
(rule (x64_load $F64 addr _ext_kind)
(xmm_to_reg (xmm_unary_rm_r (SseOpcode.Movsd)
(reg_mem_to_xmm_mem (synthetic_amode_to_reg_mem addr)))))
(rule (x64_load $F32X4 addr _ext_kind)
(xmm_to_reg (xmm_unary_rm_r (SseOpcode.Movups)
(reg_mem_to_xmm_mem (synthetic_amode_to_reg_mem addr)))))
(rule (x64_load $F64X2 addr _ext_kind)
(xmm_to_reg (xmm_unary_rm_r (SseOpcode.Movupd)
(reg_mem_to_xmm_mem (synthetic_amode_to_reg_mem addr)))))
(rule (x64_load (multi_lane _bits _lanes) addr _ext_kind)
(xmm_to_reg (xmm_unary_rm_r (SseOpcode.Movdqu)
(reg_mem_to_xmm_mem (synthetic_amode_to_reg_mem addr)))))
;;;; Instruction Constructors ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; These constructors create SSA-style `MInst`s. It is their responsibility to
;; maintain the invariant that each temporary register they allocate and define
;; only gets defined the once.
;; Helper for emitting `MInst.AluRmiR` instructions.
(decl alu_rmi_r (Type AluRmiROpcode Reg RegMemImm) Reg)
(rule (alu_rmi_r ty opcode src1 src2)
(let ((dst WritableReg (temp_writable_reg ty))
(size OperandSize (operand_size_of_type_32_64 ty))
(_ Unit (emit (MInst.AluRmiR size opcode src1 src2 dst))))
(writable_reg_to_reg dst)))
;; Helper for emitting `add` instructions.
(decl add (Type Reg RegMemImm) Reg)
(rule (add ty src1 src2)
(alu_rmi_r ty
(AluRmiROpcode.Add)
src1
src2))
;; Helper for creating `add` instructions whose flags are also used.
(decl add_with_flags (Type Reg RegMemImm) ProducesFlags)
(rule (add_with_flags ty src1 src2)
(let ((dst WritableReg (temp_writable_reg ty)))
(ProducesFlags.ProducesFlags (MInst.AluRmiR (operand_size_of_type_32_64 ty)
(AluRmiROpcode.Add)
src1
src2
dst)
(writable_reg_to_reg dst))))
;; Helper for creating `adc` instructions.
(decl adc (Type Reg RegMemImm) ConsumesFlags)
(rule (adc ty src1 src2)
(let ((dst WritableReg (temp_writable_reg ty)))
(ConsumesFlags.ConsumesFlags (MInst.AluRmiR (operand_size_of_type_32_64 ty)
(AluRmiROpcode.Adc)
src1
src2
dst)
(writable_reg_to_reg dst))))
;; Helper for emitting `sub` instructions.
(decl sub (Type Reg RegMemImm) Reg)
(rule (sub ty src1 src2)
(alu_rmi_r ty
(AluRmiROpcode.Sub)
src1
src2))
;; Helper for creating `sub` instructions whose flags are also used.
(decl sub_with_flags (Type Reg RegMemImm) ProducesFlags)
(rule (sub_with_flags ty src1 src2)
(let ((dst WritableReg (temp_writable_reg ty)))
(ProducesFlags.ProducesFlags (MInst.AluRmiR (operand_size_of_type_32_64 ty)
(AluRmiROpcode.Sub)
src1
src2
dst)
(writable_reg_to_reg dst))))
;; Helper for creating `sbb` instructions.
(decl sbb (Type Reg RegMemImm) ConsumesFlags)
(rule (sbb ty src1 src2)
(let ((dst WritableReg (temp_writable_reg ty)))
(ConsumesFlags.ConsumesFlags (MInst.AluRmiR (operand_size_of_type_32_64 ty)
(AluRmiROpcode.Sbb)
src1
src2
dst)
(writable_reg_to_reg dst))))
;; Helper for creating `mul` instructions.
(decl mul (Type Reg RegMemImm) Reg)
(rule (mul ty src1 src2)
(alu_rmi_r ty
(AluRmiROpcode.Mul)
src1
src2))
;; Helper for emitting `and` instructions.
;;
;; Use `m_` prefix (short for "mach inst") to disambiguate with the ISLE-builtin
;; `and` operator.
(decl x64_and (Type Reg RegMemImm) Reg)
(rule (x64_and ty src1 src2)
(alu_rmi_r ty
(AluRmiROpcode.And)
src1
src2))
;; Helper for emitting `or` instructions.
(decl or (Type Reg RegMemImm) Reg)
(rule (or ty src1 src2)
(alu_rmi_r ty
(AluRmiROpcode.Or)
src1
src2))
;; Helper for emitting `xor` instructions.
(decl xor (Type Reg RegMemImm) Reg)
(rule (xor ty src1 src2)
(alu_rmi_r ty
(AluRmiROpcode.Xor)
src1
src2))
;; Helper for emitting immediates.
(decl imm (Type u64) Reg)
;; Integer immediates.
(rule (imm (fits_in_64 ty) simm64)
(let ((dst WritableReg (temp_writable_reg ty))
(size OperandSize (operand_size_of_type_32_64 ty))
(_ Unit (emit (MInst.Imm size simm64 dst))))
(writable_reg_to_reg dst)))
;; `f32` immediates.
(rule (imm $F32 bits)
(xmm_to_reg (gpr_to_xmm (SseOpcode.Movd)
(reg_mem_to_gpr_mem (RegMem.Reg (imm $I32 bits)))
(OperandSize.Size32))))
;; `f64` immediates.
(rule (imm $F64 bits)
(xmm_to_reg (gpr_to_xmm (SseOpcode.Movq)
(reg_mem_to_gpr_mem (RegMem.Reg (imm $I64 bits)))
(OperandSize.Size64))))
(decl nonzero_u64_fits_in_u32 (u64) u64)
(extern extractor nonzero_u64_fits_in_u32 nonzero_u64_fits_in_u32)
;; Special case for when a 64-bit immediate fits into 32-bits. We can use a
;; 32-bit move that zero-extends the value, which has a smaller encoding.
(rule (imm $I64 (nonzero_u64_fits_in_u32 x))
(let ((dst WritableReg (temp_writable_reg $I64))
(_ Unit (emit (MInst.Imm (OperandSize.Size32) x dst))))
(writable_reg_to_reg dst)))
;; Special case for integer zero immediates: turn them into an `xor r, r`.
(rule (imm (fits_in_64 ty) 0)
(let ((wr WritableReg (temp_writable_reg ty))
(r Reg (writable_reg_to_reg wr))
(size OperandSize (operand_size_of_type_32_64 ty))
(_ Unit (emit (MInst.AluRmiR size
(AluRmiROpcode.Xor)
r
(RegMemImm.Reg r)
wr))))
r))
;; Special case for zero immediates with vector types, they turn into an xor
;; specific to the vector type.
(rule (imm ty @ (multi_lane _bits _lanes) 0)
(let ((wr WritableXmm (temp_writable_xmm))
(r Xmm (writable_xmm_to_xmm wr))
(_ Unit (emit (MInst.XmmRmR (sse_xor_op ty)
r
(xmm_to_xmm_mem r)
wr))))
(xmm_to_reg r)))
;; Special case for `f32` zero immediates to use `xorps`.
(rule (imm $F32 0)
(let ((wr WritableXmm (temp_writable_xmm))
(r Xmm (writable_xmm_to_xmm wr))
(_ Unit (emit (MInst.XmmRmR (SseOpcode.Xorps)
r
(xmm_to_xmm_mem r)
wr))))
(xmm_to_reg r)))
;; TODO: use cmpeqps for all 1s
;; Special case for `f64` zero immediates to use `xorpd`.
(rule (imm $F64 0)
(let ((wr WritableXmm (temp_writable_xmm))
(r Xmm (writable_xmm_to_xmm wr))
(_ Unit (emit (MInst.XmmRmR (SseOpcode.Xorpd)
r
(xmm_to_xmm_mem r)
wr))))
(xmm_to_reg r)))
;; TODO: use cmpeqpd for all 1s
;; Helper for creating `MInst.ShifR` instructions.
(decl shift_r (Type ShiftKind Reg Imm8Reg) Reg)
(rule (shift_r ty kind src1 src2)
(let ((dst WritableReg (temp_writable_reg ty))
;; Use actual 8/16-bit instructions when appropriate: we
;; rely on their shift-amount-masking semantics.
(size OperandSize (raw_operand_size_of_type ty))
(_ Unit (emit (MInst.ShiftR size kind src1 src2 dst))))
(writable_reg_to_reg dst)))
;; Helper for creating `rotl` instructions (prefixed with "m_", short for "mach
;; inst", to disambiguate this from clif's `rotl`).
(decl x64_rotl (Type Reg Imm8Reg) Reg)
(rule (x64_rotl ty src1 src2)
(shift_r ty (ShiftKind.RotateLeft) src1 src2))
;; Helper for creating `rotr` instructions (prefixed with "m_", short for "mach
;; inst", to disambiguate this from clif's `rotr`).
(decl x64_rotr (Type Reg Imm8Reg) Reg)
(rule (x64_rotr ty src1 src2)
(shift_r ty (ShiftKind.RotateRight) src1 src2))
;; Helper for creating `shl` instructions.
(decl shl (Type Reg Imm8Reg) Reg)
(rule (shl ty src1 src2)
(shift_r ty (ShiftKind.ShiftLeft) src1 src2))
;; Helper for creating logical shift-right instructions.
(decl shr (Type Reg Imm8Reg) Reg)
(rule (shr ty src1 src2)
(shift_r ty (ShiftKind.ShiftRightLogical) src1 src2))
;; Helper for creating arithmetic shift-right instructions.
(decl sar (Type Reg Imm8Reg) Reg)
(rule (sar ty src1 src2)
(shift_r ty (ShiftKind.ShiftRightArithmetic) src1 src2))
;; Helper for creating `MInst.CmpRmiR` instructions.
(decl cmp_rmi_r (OperandSize CmpOpcode RegMemImm Reg) ProducesFlags)
(rule (cmp_rmi_r size opcode src1 src2)
(ProducesFlags.ProducesFlags (MInst.CmpRmiR size
opcode
src1
src2)
(invalid_reg)))
;; Helper for creating `cmp` instructions.
(decl cmp (OperandSize RegMemImm Reg) ProducesFlags)
(rule (cmp size src1 src2)
(cmp_rmi_r size (CmpOpcode.Cmp) src1 src2))
;; Helper for creating `test` instructions.
(decl test (OperandSize RegMemImm Reg) ProducesFlags)
(rule (test size src1 src2)
(cmp_rmi_r size (CmpOpcode.Test) src1 src2))
;; Helper for creating `MInst.Cmove` instructions.
(decl cmove (Type CC RegMem Reg) ConsumesFlags)
(rule (cmove ty cc consequent alternative)
(let ((dst WritableReg (temp_writable_reg ty))
(size OperandSize (operand_size_of_type_32_64 ty)))
(ConsumesFlags.ConsumesFlags (MInst.Cmove size cc consequent alternative dst)
(writable_reg_to_reg dst))))
;; Helper for creating `MInst.MovzxRmR` instructions.
(decl movzx (Type ExtMode RegMem) Reg)
(rule (movzx ty mode src)
(let ((dst WritableReg (temp_writable_reg ty))
(_ Unit (emit (MInst.MovzxRmR mode src dst))))
(writable_reg_to_reg dst)))
;; Helper for creating `MInst.MovsxRmR` instructions.
(decl movsx (Type ExtMode RegMem) Reg)
(rule (movsx ty mode src)
(let ((dst WritableReg (temp_writable_reg ty))
(_ Unit (emit (MInst.MovsxRmR mode src dst))))
(writable_reg_to_reg dst)))
;; Helper for creating `MInst.XmmRmR` instructions.
(decl xmm_rm_r (Type SseOpcode Xmm XmmMem) Xmm)
(rule (xmm_rm_r ty op src1 src2)
(let ((dst WritableXmm (temp_writable_xmm))
(_ Unit (emit (MInst.XmmRmR op src1 src2 dst))))
(writable_xmm_to_xmm dst)))
;; Helper for creating `paddb` instructions.
(decl paddb (Xmm XmmMem) Xmm)
(rule (paddb src1 src2)
(xmm_rm_r $I8X16 (SseOpcode.Paddb) src1 src2))
;; Helper for creating `paddw` instructions.
(decl paddw (Xmm XmmMem) Xmm)
(rule (paddw src1 src2)
(xmm_rm_r $I16X8 (SseOpcode.Paddw) src1 src2))
;; Helper for creating `paddd` instructions.
(decl paddd (Xmm XmmMem) Xmm)
(rule (paddd src1 src2)
(xmm_rm_r $I32X4 (SseOpcode.Paddd) src1 src2))
;; Helper for creating `paddq` instructions.
(decl paddq (Xmm XmmMem) Xmm)
(rule (paddq src1 src2)
(xmm_rm_r $I64X2 (SseOpcode.Paddq) src1 src2))
;; Helper for creating `paddsb` instructions.
(decl paddsb (Xmm XmmMem) Xmm)
(rule (paddsb src1 src2)
(xmm_rm_r $I8X16 (SseOpcode.Paddsb) src1 src2))
;; Helper for creating `paddsw` instructions.
(decl paddsw (Xmm XmmMem) Xmm)
(rule (paddsw src1 src2)
(xmm_rm_r $I16X8 (SseOpcode.Paddsw) src1 src2))
;; Helper for creating `paddusb` instructions.
(decl paddusb (Xmm XmmMem) Xmm)
(rule (paddusb src1 src2)
(xmm_rm_r $I8X16 (SseOpcode.Paddusb) src1 src2))
;; Helper for creating `paddusw` instructions.
(decl paddusw (Xmm XmmMem) Xmm)
(rule (paddusw src1 src2)
(xmm_rm_r $I16X8 (SseOpcode.Paddusw) src1 src2))
;; Helper for creating `psubb` instructions.
(decl psubb (Xmm XmmMem) Xmm)
(rule (psubb src1 src2)
(xmm_rm_r $I8X16 (SseOpcode.Psubb) src1 src2))
;; Helper for creating `psubw` instructions.
(decl psubw (Xmm XmmMem) Xmm)
(rule (psubw src1 src2)
(xmm_rm_r $I16X8 (SseOpcode.Psubw) src1 src2))
;; Helper for creating `psubd` instructions.
(decl psubd (Xmm XmmMem) Xmm)
(rule (psubd src1 src2)
(xmm_rm_r $I32X4 (SseOpcode.Psubd) src1 src2))
;; Helper for creating `psubq` instructions.
(decl psubq (Xmm XmmMem) Xmm)
(rule (psubq src1 src2)
(xmm_rm_r $I64X2 (SseOpcode.Psubq) src1 src2))
;; Helper for creating `psubsb` instructions.
(decl psubsb (Xmm XmmMem) Xmm)
(rule (psubsb src1 src2)
(xmm_rm_r $I8X16 (SseOpcode.Psubsb) src1 src2))
;; Helper for creating `psubsw` instructions.
(decl psubsw (Xmm XmmMem) Xmm)
(rule (psubsw src1 src2)
(xmm_rm_r $I16X8 (SseOpcode.Psubsw) src1 src2))
;; Helper for creating `psubusb` instructions.
(decl psubusb (Xmm XmmMem) Xmm)
(rule (psubusb src1 src2)
(xmm_rm_r $I8X16 (SseOpcode.Psubusb) src1 src2))
;; Helper for creating `psubusw` instructions.
(decl psubusw (Xmm XmmMem) Xmm)
(rule (psubusw src1 src2)
(xmm_rm_r $I16X8 (SseOpcode.Psubusw) src1 src2))
;; Helper for creating `pavgb` instructions.
(decl pavgb (Xmm XmmMem) Xmm)
(rule (pavgb src1 src2)
(xmm_rm_r $I8X16 (SseOpcode.Pavgb) src1 src2))
;; Helper for creating `pavgw` instructions.
(decl pavgw (Xmm XmmMem) Xmm)
(rule (pavgw src1 src2)
(xmm_rm_r $I16X8 (SseOpcode.Pavgw) src1 src2))
;; Helper for creating `pand` instructions.
(decl pand (Xmm XmmMem) Xmm)
(rule (pand src1 src2)
(xmm_rm_r $F32X4 (SseOpcode.Pand) src1 src2))
;; Helper for creating `andps` instructions.
(decl andps (Xmm XmmMem) Xmm)
(rule (andps src1 src2)
(xmm_rm_r $F32X4 (SseOpcode.Andps) src1 src2))
;; Helper for creating `andpd` instructions.
(decl andpd (Xmm XmmMem) Xmm)
(rule (andpd src1 src2)
(xmm_rm_r $F64X2 (SseOpcode.Andpd) src1 src2))
;; Helper for creating `por` instructions.
(decl por (Xmm XmmMem) Xmm)
(rule (por src1 src2)
(xmm_rm_r $F32X4 (SseOpcode.Por) src1 src2))
;; Helper for creating `orps` instructions.
(decl orps (Xmm XmmMem) Xmm)
(rule (orps src1 src2)
(xmm_rm_r $F32X4 (SseOpcode.Orps) src1 src2))
;; Helper for creating `orpd` instructions.
(decl orpd (Xmm XmmMem) Xmm)
(rule (orpd src1 src2)
(xmm_rm_r $F64X2 (SseOpcode.Orpd) src1 src2))
;; Helper for creating `pxor` instructions.
(decl pxor (Xmm XmmMem) Xmm)
(rule (pxor src1 src2)
(xmm_rm_r $I8X16 (SseOpcode.Pxor) src1 src2))
;; Helper for creating `xorps` instructions.
(decl xorps (Xmm XmmMem) Xmm)
(rule (xorps src1 src2)
(xmm_rm_r $F32X4 (SseOpcode.Xorps) src1 src2))
;; Helper for creating `xorpd` instructions.
(decl xorpd (Xmm XmmMem) Xmm)
(rule (xorpd src1 src2)
(xmm_rm_r $F64X2 (SseOpcode.Xorpd) src1 src2))
;; Helper for creating `pmullw` instructions.
(decl pmullw (Xmm XmmMem) Xmm)
(rule (pmullw src1 src2)
(xmm_rm_r $I16X8 (SseOpcode.Pmullw) src1 src2))
;; Helper for creating `pmulld` instructions.
(decl pmulld (Xmm XmmMem) Xmm)
(rule (pmulld src1 src2)
(xmm_rm_r $I16X8 (SseOpcode.Pmulld) src1 src2))
;; Helper for creating `pmulhw` instructions.
(decl pmulhw (Xmm XmmMem) Xmm)
(rule (pmulhw src1 src2)
(xmm_rm_r $I16X8 (SseOpcode.Pmulhw) src1 src2))
;; Helper for creating `pmulhuw` instructions.
(decl pmulhuw (Xmm XmmMem) Xmm)
(rule (pmulhuw src1 src2)
(xmm_rm_r $I16X8 (SseOpcode.Pmulhuw) src1 src2))
;; Helper for creating `pmuldq` instructions.
(decl pmuldq (Xmm XmmMem) Xmm)
(rule (pmuldq src1 src2)
(xmm_rm_r $I16X8 (SseOpcode.Pmuldq) src1 src2))
;; Helper for creating `pmuludq` instructions.
(decl pmuludq (Xmm XmmMem) Xmm)
(rule (pmuludq src1 src2)
(xmm_rm_r $I64X2 (SseOpcode.Pmuludq) src1 src2))
;; Helper for creating `punpckhwd` instructions.
(decl punpckhwd (Xmm XmmMem) Xmm)
(rule (punpckhwd src1 src2)
(xmm_rm_r $I16X8 (SseOpcode.Punpckhwd) src1 src2))
;; Helper for creating `punpcklwd` instructions.
(decl punpcklwd (Xmm XmmMem) Xmm)
(rule (punpcklwd src1 src2)
(xmm_rm_r $I16X8 (SseOpcode.Punpcklwd) src1 src2))
;; Helper for creating `andnps` instructions.
(decl andnps (Xmm XmmMem) Xmm)
(rule (andnps src1 src2)
(xmm_rm_r $F32X4 (SseOpcode.Andnps) src1 src2))
;; Helper for creating `andnpd` instructions.
(decl andnpd (Xmm XmmMem) Xmm)
(rule (andnpd src1 src2)
(xmm_rm_r $F64X2 (SseOpcode.Andnpd) src1 src2))
;; Helper for creating `pandn` instructions.
(decl pandn (Xmm XmmMem) Xmm)
(rule (pandn src1 src2)
(xmm_rm_r $F64X2 (SseOpcode.Pandn) src1 src2))
(decl sse_blend_op (Type) SseOpcode)
(rule (sse_blend_op $F32X4) (SseOpcode.Blendvps))
(rule (sse_blend_op $F64X2) (SseOpcode.Blendvpd))
(rule (sse_blend_op (multi_lane _bits _lanes)) (SseOpcode.Pblendvb))
(decl sse_mov_op (Type) SseOpcode)
(rule (sse_mov_op $F32X4) (SseOpcode.Movaps))
(rule (sse_mov_op $F64X2) (SseOpcode.Movapd))
(rule (sse_mov_op (multi_lane _bits _lanes)) (SseOpcode.Movdqa))
;; Helper for creating `blendvp{d,s}` and `pblendvb` instructions.
(decl sse_blend (Type XmmMem XmmMem Xmm) Xmm)
(rule (sse_blend ty mask src1 src2)
;; Move the mask into `xmm0`, as blend instructions implicitly operate on
;; that register. (This kind of thing would normally happen inside of
;; `Inst::mov_mitosis`, but has to happen here, where we still have the
;; mask register, because the mask is implicit and doesn't appear in the
;; `Inst` itself.)
(let ((mask2 WritableXmm (xmm0))
(_ Unit (emit (MInst.XmmUnaryRmR (sse_mov_op ty)
mask
mask2))))
(xmm_rm_r ty (sse_blend_op ty) src2 src1)))
;; Helper for creating `blendvpd` instructions.
(decl blendvpd (Xmm XmmMem Xmm) Xmm)
(rule (blendvpd src1 src2 mask)
;; Move the mask into `xmm0`, as `blendvpd` implicitly operates on that
;; register. (This kind of thing would normally happen inside of
;; `Inst::mov_mitosis`, but has to happen here, where we still have the
;; mask register, because the mask is implicit and doesn't appear in the
;; `Inst` itself.)
(let ((mask2 WritableXmm (xmm0))
(_ Unit (emit (MInst.XmmUnaryRmR (SseOpcode.Movapd)
(xmm_to_xmm_mem mask)
mask2))))
(xmm_rm_r $F64X2 (SseOpcode.Blendvpd) src1 src2)))
;; Helper for creating `movsd` instructions.
(decl movsd (Xmm XmmMem) Xmm)
(rule (movsd src1 src2)
(xmm_rm_r $I8X16 (SseOpcode.Movsd) src1 src2))
;; Helper for creating `movlhps` instructions.
(decl movlhps (Xmm XmmMem) Xmm)
(rule (movlhps src1 src2)
(xmm_rm_r $I8X16 (SseOpcode.Movlhps) src1 src2))
;; Helper for creating `pmaxsb` instructions.
(decl pmaxsb (Xmm XmmMem) Xmm)
(rule (pmaxsb src1 src2)
(xmm_rm_r $I8X16 (SseOpcode.Pmaxsb) src1 src2))
;; Helper for creating `pmaxsw` instructions.
(decl pmaxsw (Xmm XmmMem) Xmm)
(rule (pmaxsw src1 src2)
(xmm_rm_r $I8X16 (SseOpcode.Pmaxsw) src1 src2))
;; Helper for creating `pmaxsd` instructions.
(decl pmaxsd (Xmm XmmMem) Xmm)
(rule (pmaxsd src1 src2)
(xmm_rm_r $I8X16 (SseOpcode.Pmaxsd) src1 src2))
;; Helper for creating `pminsb` instructions.
(decl pminsb (Xmm XmmMem) Xmm)
(rule (pminsb src1 src2)
(xmm_rm_r $I8X16 (SseOpcode.Pminsb) src1 src2))
;; Helper for creating `pminsw` instructions.
(decl pminsw (Xmm XmmMem) Xmm)
(rule (pminsw src1 src2)
(xmm_rm_r $I8X16 (SseOpcode.Pminsw) src1 src2))
;; Helper for creating `pminsd` instructions.
(decl pminsd (Xmm XmmMem) Xmm)
(rule (pminsd src1 src2)
(xmm_rm_r $I8X16 (SseOpcode.Pminsd) src1 src2))
;; Helper for creating `pmaxub` instructions.
(decl pmaxub (Xmm XmmMem) Xmm)
(rule (pmaxub src1 src2)
(xmm_rm_r $I8X16 (SseOpcode.Pmaxub) src1 src2))
;; Helper for creating `pmaxuw` instructions.
(decl pmaxuw (Xmm XmmMem) Xmm)
(rule (pmaxuw src1 src2)
(xmm_rm_r $I8X16 (SseOpcode.Pmaxuw) src1 src2))
;; Helper for creating `pmaxud` instructions.
(decl pmaxud (Xmm XmmMem) Xmm)
(rule (pmaxud src1 src2)
(xmm_rm_r $I8X16 (SseOpcode.Pmaxud) src1 src2))
;; Helper for creating `pminub` instructions.
(decl pminub (Xmm XmmMem) Xmm)
(rule (pminub src1 src2)
(xmm_rm_r $I8X16 (SseOpcode.Pminub) src1 src2))
;; Helper for creating `pminuw` instructions.
(decl pminuw (Xmm XmmMem) Xmm)
(rule (pminuw src1 src2)
(xmm_rm_r $I8X16 (SseOpcode.Pminuw) src1 src2))
;; Helper for creating `pminud` instructions.
(decl pminud (Xmm XmmMem) Xmm)
(rule (pminud src1 src2)
(xmm_rm_r $I8X16 (SseOpcode.Pminud) src1 src2))
;; Helper for creating `punpcklbw` instructions.
(decl punpcklbw (Xmm XmmMem) Xmm)
(rule (punpcklbw src1 src2)
(xmm_rm_r $I8X16 (SseOpcode.Punpcklbw) src1 src2))
;; Helper for creating `punpckhbw` instructions.
(decl punpckhbw (Xmm XmmMem) Xmm)
(rule (punpckhbw src1 src2)
(xmm_rm_r $I8X16 (SseOpcode.Punpckhbw) src1 src2))
;; Helper for creating `packsswb` instructions.
(decl packsswb (Xmm XmmMem) Xmm)
(rule (packsswb src1 src2)
(xmm_rm_r $I8X16 (SseOpcode.Packsswb) src1 src2))
;; Helper for creating `MInst.XmmRmRImm` instructions.
(decl xmm_rm_r_imm (SseOpcode Reg RegMem u8 OperandSize) Xmm)
(rule (xmm_rm_r_imm op src1 src2 imm size)
(let ((dst WritableXmm (temp_writable_xmm))
(_ Unit (emit (MInst.XmmRmRImm op
src1
src2
(writable_xmm_to_reg dst)
imm
size))))
(writable_xmm_to_xmm dst)))
;; Helper for creating `palignr` instructions.
(decl palignr (Xmm XmmMem u8 OperandSize) Xmm)
(rule (palignr src1 src2 imm size)
(xmm_rm_r_imm (SseOpcode.Palignr)
(xmm_to_reg src1)
(xmm_mem_to_reg_mem src2)
imm
size))
;; Helper for creating `cmpps` instructions.
(decl cmpps (Xmm XmmMem FcmpImm) Xmm)
(rule (cmpps src1 src2 imm)
(xmm_rm_r_imm (SseOpcode.Cmpps)
(xmm_to_reg src1)
(xmm_mem_to_reg_mem src2)
(encode_fcmp_imm imm)
(OperandSize.Size32)))
;; Helper for creating `pinsrb` instructions.
(decl pinsrb (Xmm GprMem u8) Xmm)
(rule (pinsrb src1 src2 lane)
(xmm_rm_r_imm (SseOpcode.Pinsrb)
(xmm_to_reg src1)
(gpr_mem_to_reg_mem src2)
lane
(OperandSize.Size32)))
;; Helper for creating `pinsrw` instructions.
(decl pinsrw (Xmm GprMem u8) Xmm)
(rule (pinsrw src1 src2 lane)
(xmm_rm_r_imm (SseOpcode.Pinsrw)
(xmm_to_reg src1)
(gpr_mem_to_reg_mem src2)
lane
(OperandSize.Size32)))
;; Helper for creating `pinsrd` instructions.
(decl pinsrd (Xmm GprMem u8 OperandSize) Xmm)
(rule (pinsrd src1 src2 lane size)
(xmm_rm_r_imm (SseOpcode.Pinsrd)
(xmm_to_reg src1)
(gpr_mem_to_reg_mem src2)
lane
size))
;; Helper for creating `insertps` instructions.
(decl insertps (Xmm XmmMem u8) Xmm)
(rule (insertps src1 src2 lane)
(xmm_rm_r_imm (SseOpcode.Insertps)
(xmm_to_reg src1)
(xmm_mem_to_reg_mem src2)
lane
(OperandSize.Size32)))
;; Helper for creating `pshufd` instructions.
(decl pshufd (XmmMem u8 OperandSize) Xmm)
(rule (pshufd src imm size)
(let ((w_dst WritableXmm (temp_writable_xmm))
(dst Xmm (writable_xmm_to_xmm w_dst))
(_ Unit (emit (MInst.XmmRmRImm (SseOpcode.Pshufd)
(xmm_to_reg dst)
(xmm_mem_to_reg_mem src)
(writable_xmm_to_reg w_dst)
imm
size))))
dst))
;; Helper for creating `MInst.XmmUnaryRmR` instructions.
(decl xmm_unary_rm_r (SseOpcode XmmMem) Xmm)
(rule (xmm_unary_rm_r op src)
(let ((dst WritableXmm (temp_writable_xmm))
(_ Unit (emit (MInst.XmmUnaryRmR op src dst))))
(writable_xmm_to_xmm dst)))
;; Helper for creating `pmovsxbw` instructions.
(decl pmovsxbw (XmmMem) Xmm)
(rule (pmovsxbw src)
(xmm_unary_rm_r (SseOpcode.Pmovsxbw) src))
;; Helper for creating `pmovzxbw` instructions.
(decl pmovzxbw (XmmMem) Xmm)
(rule (pmovzxbw src)
(xmm_unary_rm_r (SseOpcode.Pmovzxbw) src))
;; Helper for creating `pabsb` instructions.
(decl pabsb (XmmMem) Xmm)
(rule (pabsb src)
(xmm_unary_rm_r (SseOpcode.Pabsb) src))
;; Helper for creating `pabsw` instructions.
(decl pabsw (XmmMem) Xmm)
(rule (pabsw src)
(xmm_unary_rm_r (SseOpcode.Pabsw) src))
;; Helper for creating `pabsd` instructions.
(decl pabsd (XmmMem) Xmm)
(rule (pabsd src)
(xmm_unary_rm_r (SseOpcode.Pabsd) src))
;; Helper for creating `MInst.XmmUnaryRmREvex` instructions.
(decl xmm_unary_rm_r_evex (Avx512Opcode XmmMem) Xmm)
(rule (xmm_unary_rm_r_evex op src)
(let ((dst WritableXmm (temp_writable_xmm))
(_ Unit (emit (MInst.XmmUnaryRmREvex op src dst))))
(writable_xmm_to_xmm dst)))
;; Helper for creating `vpabsq` instructions.
(decl vpabsq (XmmMem) Xmm)
(rule (vpabsq src)
(xmm_unary_rm_r_evex (Avx512Opcode.Vpabsq) src))
;; Helper for creating `MInst.XmmRmREvex` instructions.
(decl xmm_rm_r_evex (Avx512Opcode XmmMem Xmm) Xmm)
(rule (xmm_rm_r_evex op src1 src2)
(let ((dst WritableXmm (temp_writable_xmm))
(_ Unit (emit (MInst.XmmRmREvex op
src1
src2
dst))))
(writable_xmm_to_xmm dst)))
;; Helper for creating `vpmullq` instructions.
;;
;; Requires AVX-512 vl and dq.
(decl vpmullq (XmmMem Xmm) Xmm)
(rule (vpmullq src1 src2)
(xmm_rm_r_evex (Avx512Opcode.Vpmullq)
src1
src2))
;; Helper for creating `MInst.MulHi` instructions.
;;
;; Returns the (lo, hi) register halves of the multiplication.
(decl mul_hi (Type bool Reg RegMem) ValueRegs)
(rule (mul_hi ty signed src1 src2)
(let ((dst_lo WritableReg (temp_writable_reg ty))
(dst_hi WritableReg (temp_writable_reg ty))
(size OperandSize (operand_size_of_type_32_64 ty))
(_ Unit (emit (MInst.MulHi size
signed
src1
src2
dst_lo
dst_hi))))
(value_regs (writable_reg_to_reg dst_lo)
(writable_reg_to_reg dst_hi))))
;; Helper for creating `mul` instructions that return both the lower and
;; (unsigned) higher halves of the result.
(decl mulhi_u (Type Reg RegMem) ValueRegs)
(rule (mulhi_u ty src1 src2)
(mul_hi ty $false src1 src2))
;; Helper for creating `MInst.XmmRmiXmm` instructions.
(decl xmm_rmi_xmm (SseOpcode Xmm XmmMemImm) Xmm)
(rule (xmm_rmi_xmm op src1 src2)
(let ((dst WritableXmm (temp_writable_xmm))
(_ Unit (emit (MInst.XmmRmiReg op
src1
src2
dst))))
(writable_xmm_to_xmm dst)))
;; Helper for creating `psllw` instructions.
(decl psllw (Xmm XmmMemImm) Xmm)
(rule (psllw src1 src2)
(xmm_rmi_xmm (SseOpcode.Psllw) src1 src2))
;; Helper for creating `pslld` instructions.
(decl pslld (Xmm XmmMemImm) Xmm)
(rule (pslld src1 src2)
(xmm_rmi_xmm (SseOpcode.Pslld) src1 src2))
;; Helper for creating `psllq` instructions.
(decl psllq (Xmm XmmMemImm) Xmm)
(rule (psllq src1 src2)
(xmm_rmi_xmm (SseOpcode.Psllq) src1 src2))
;; Helper for creating `psrlw` instructions.
(decl psrlw (Xmm XmmMemImm) Xmm)
(rule (psrlw src1 src2)
(xmm_rmi_xmm (SseOpcode.Psrlw) src1 src2))
;; Helper for creating `psrld` instructions.
(decl psrld (Xmm XmmMemImm) Xmm)
(rule (psrld src1 src2)
(xmm_rmi_xmm (SseOpcode.Psrld) src1 src2))
;; Helper for creating `psrlq` instructions.
(decl psrlq (Xmm XmmMemImm) Xmm)
(rule (psrlq src1 src2)
(xmm_rmi_xmm (SseOpcode.Psrlq) src1 src2))
;; Helper for creating `psraw` instructions.
(decl psraw (Xmm XmmMemImm) Xmm)
(rule (psraw src1 src2)
(xmm_rmi_xmm (SseOpcode.Psraw) src1 src2))
;; Helper for creating `psrad` instructions.
(decl psrad (Xmm XmmMemImm) Xmm)
(rule (psrad src1 src2)
(xmm_rmi_xmm (SseOpcode.Psrad) src1 src2))
;; Helper for creating `pextrd` instructions.
(decl pextrd (Type Xmm u8) Gpr)
(rule (pextrd ty src lane)
(let ((w_dst WritableGpr (temp_writable_gpr))
(r_dst Gpr (writable_gpr_to_gpr w_dst))
(_ Unit (emit (MInst.XmmRmRImm (SseOpcode.Pextrd)
(gpr_to_reg r_dst)
(RegMem.Reg (xmm_to_reg src))
(writable_gpr_to_reg w_dst)
lane
(operand_size_of_type_32_64 (lane_type ty))))))
r_dst))
;; Helper for creating `cmppd` instructions.
;;
;; Note that `Size32` is intentional despite this being used for 64-bit
;; operations, since this presumably induces the correct encoding of the
;; instruction.
(decl cmppd (Xmm XmmMem FcmpImm) Xmm)
(rule (cmppd src1 src2 imm)
(xmm_rm_r_imm (SseOpcode.Cmppd)
(xmm_to_reg src1)
(xmm_mem_to_reg_mem src2)
(encode_fcmp_imm imm)
(OperandSize.Size32)))
;; Helper for creating `MInst.GprToXmm` instructions.
(decl gpr_to_xmm (SseOpcode GprMem OperandSize) Xmm)
(rule (gpr_to_xmm op src size)
(let ((dst WritableXmm (temp_writable_xmm))
(_ Unit (emit (MInst.GprToXmm op (gpr_mem_to_reg_mem src) dst size))))
(writable_xmm_to_xmm dst)))
;; Helper for creating `not` instructions.
(decl not (Type Gpr) Gpr)
(rule (not ty src)
(let ((dst WritableGpr (temp_writable_gpr))
(size OperandSize (operand_size_of_type_32_64 ty))
(_ Unit (emit (MInst.Not size src dst))))
(writable_gpr_to_gpr dst)))
;; Helper for creating `neg` instructions.
(decl neg (Type Gpr) Gpr)
(rule (neg ty src)
(let ((dst WritableGpr (temp_writable_gpr))
(size OperandSize (operand_size_of_type_32_64 ty))
(_ Unit (emit (MInst.Neg size src dst))))
(writable_gpr_to_gpr dst)))
(decl lea (SyntheticAmode) Gpr)
(rule (lea addr)
(let ((dst WritableGpr (temp_writable_gpr))
(_ Unit (emit (MInst.LoadEffectiveAddress addr dst))))
(writable_gpr_to_gpr dst)))
;; Helper for creating `ud2` instructions.
(decl ud2 (TrapCode) SideEffectNoResult)
(rule (ud2 code)
(SideEffectNoResult.Inst (MInst.Ud2 code)))