1use crate::{
4 constant_pool::ConstantPool,
5 isa::{CallingConvention, reg::Reg},
6 masm::{
7 DivKind, Extend, ExtendKind, ExtendType, IntCmpKind, MulWideKind, OperandSize, RemKind,
8 RoundingMode, ShiftKind, Signed, V128ExtendKind, V128LoadExtendKind, Zero,
9 },
10 reg::writable,
11};
12use cranelift_codegen::{
13 CallInfo, Final, MachBuffer, MachBufferFinalized, MachInst, MachInstEmit, MachInstEmitState,
14 MachLabel, PatchRegion, Writable,
15 ir::{ExternalName, MemFlags, SourceLoc, TrapCode, Type, UserExternalNameRef, types},
16 isa::{
17 unwind::UnwindInst,
18 x64::{
19 AtomicRmwSeqOp, EmitInfo, EmitState, Inst,
20 args::{
21 self, Amode, Avx512Opcode, CC, ExtMode, FromWritableReg, Gpr, GprMem, GprMemImm,
22 RegMem, RegMemImm, SyntheticAmode, WritableGpr, WritableXmm, Xmm, XmmMem,
23 XmmMemImm,
24 },
25 external::{PairedGpr, PairedXmm},
26 settings as x64_settings,
27 },
28 },
29 settings,
30};
31
32use crate::reg::WritableReg;
33use cranelift_assembler_x64 as asm;
34use wasmtime_environ::Unsigned;
35
36use super::address::Address;
37use smallvec::SmallVec;
38
39impl From<Reg> for RegMemImm {
42 fn from(reg: Reg) -> Self {
43 RegMemImm::reg(reg.into())
44 }
45}
46
47impl From<Reg> for RegMem {
48 fn from(value: Reg) -> Self {
49 RegMem::Reg { reg: value.into() }
50 }
51}
52
53impl From<Reg> for WritableGpr {
54 fn from(reg: Reg) -> Self {
55 let writable = Writable::from_reg(reg.into());
56 WritableGpr::from_writable_reg(writable).expect("valid writable gpr")
57 }
58}
59
60impl From<Reg> for WritableXmm {
61 fn from(reg: Reg) -> Self {
62 let writable = Writable::from_reg(reg.into());
63 WritableXmm::from_writable_reg(writable).expect("valid writable xmm")
64 }
65}
66
67fn pair_gpr(reg: WritableReg) -> PairedGpr {
70 assert!(reg.to_reg().is_int());
71 let read = Gpr::unwrap_new(reg.to_reg().into());
72 let write = WritableGpr::from_reg(reg.to_reg().into());
73 PairedGpr { read, write }
74}
75
76impl From<Reg> for asm::Gpr<Gpr> {
77 fn from(reg: Reg) -> Self {
78 asm::Gpr::new(reg.into())
79 }
80}
81
82impl From<Reg> for asm::GprMem<Gpr, Gpr> {
83 fn from(reg: Reg) -> Self {
84 asm::GprMem::Gpr(reg.into())
85 }
86}
87
88fn pair_xmm(reg: WritableReg) -> PairedXmm {
91 assert!(reg.to_reg().is_float());
92 let read = Xmm::unwrap_new(reg.to_reg().into());
93 let write = WritableXmm::from_reg(reg.to_reg().into());
94 PairedXmm { read, write }
95}
96
97impl From<Reg> for asm::Xmm<Xmm> {
98 fn from(reg: Reg) -> Self {
99 asm::Xmm::new(reg.into())
100 }
101}
102
103impl From<Reg> for asm::XmmMem<Xmm, Gpr> {
104 fn from(reg: Reg) -> Self {
105 asm::XmmMem::Xmm(reg.into())
106 }
107}
108
109impl From<Reg> for Gpr {
110 fn from(reg: Reg) -> Self {
111 Gpr::unwrap_new(reg.into())
112 }
113}
114
115impl From<Reg> for GprMem {
116 fn from(value: Reg) -> Self {
117 GprMem::unwrap_new(value.into())
118 }
119}
120
121impl From<Reg> for GprMemImm {
122 fn from(reg: Reg) -> Self {
123 GprMemImm::unwrap_new(reg.into())
124 }
125}
126
127impl From<Reg> for Xmm {
128 fn from(reg: Reg) -> Self {
129 Xmm::unwrap_new(reg.into())
130 }
131}
132
133impl From<Reg> for XmmMem {
134 fn from(value: Reg) -> Self {
135 XmmMem::unwrap_new(value.into())
136 }
137}
138
139impl From<Reg> for XmmMemImm {
140 fn from(value: Reg) -> Self {
141 XmmMemImm::unwrap_new(value.into())
142 }
143}
144
145impl From<OperandSize> for args::OperandSize {
146 fn from(size: OperandSize) -> Self {
147 match size {
148 OperandSize::S8 => Self::Size8,
149 OperandSize::S16 => Self::Size16,
150 OperandSize::S32 => Self::Size32,
151 OperandSize::S64 => Self::Size64,
152 s => panic!("Invalid operand size {s:?}"),
153 }
154 }
155}
156
157impl From<IntCmpKind> for CC {
158 fn from(value: IntCmpKind) -> Self {
159 match value {
160 IntCmpKind::Eq => CC::Z,
161 IntCmpKind::Ne => CC::NZ,
162 IntCmpKind::LtS => CC::L,
163 IntCmpKind::LtU => CC::B,
164 IntCmpKind::GtS => CC::NLE,
165 IntCmpKind::GtU => CC::NBE,
166 IntCmpKind::LeS => CC::LE,
167 IntCmpKind::LeU => CC::BE,
168 IntCmpKind::GeS => CC::NL,
169 IntCmpKind::GeU => CC::NB,
170 }
171 }
172}
173
174impl<T: ExtendType> From<Extend<T>> for ExtMode {
175 fn from(value: Extend<T>) -> Self {
176 match value {
177 Extend::I32Extend8 => ExtMode::BL,
178 Extend::I32Extend16 => ExtMode::WL,
179 Extend::I64Extend8 => ExtMode::BQ,
180 Extend::I64Extend16 => ExtMode::WQ,
181 Extend::I64Extend32 => ExtMode::LQ,
182 Extend::__Kind(_) => unreachable!(),
183 }
184 }
185}
186
187impl From<ExtendKind> for ExtMode {
188 fn from(value: ExtendKind) -> Self {
189 match value {
190 ExtendKind::Signed(s) => s.into(),
191 ExtendKind::Unsigned(u) => u.into(),
192 }
193 }
194}
195
196pub(super) enum VpmovKind {
198 E8x8S,
200 E8x8U,
202 E16x4S,
204 E16x4U,
206 E32x2S,
208 E32x2U,
210}
211
212impl From<V128LoadExtendKind> for VpmovKind {
213 fn from(value: V128LoadExtendKind) -> Self {
214 match value {
215 V128LoadExtendKind::E8x8S => Self::E8x8S,
216 V128LoadExtendKind::E8x8U => Self::E8x8U,
217 V128LoadExtendKind::E16x4S => Self::E16x4S,
218 V128LoadExtendKind::E16x4U => Self::E16x4U,
219 V128LoadExtendKind::E32x2S => Self::E32x2S,
220 V128LoadExtendKind::E32x2U => Self::E32x2U,
221 }
222 }
223}
224
225impl From<V128ExtendKind> for VpmovKind {
226 fn from(value: V128ExtendKind) -> Self {
227 match value {
228 V128ExtendKind::LowI8x16S | V128ExtendKind::HighI8x16S => Self::E8x8S,
229 V128ExtendKind::LowI8x16U => Self::E8x8U,
230 V128ExtendKind::LowI16x8S | V128ExtendKind::HighI16x8S => Self::E16x4S,
231 V128ExtendKind::LowI16x8U => Self::E16x4U,
232 V128ExtendKind::LowI32x4S | V128ExtendKind::HighI32x4S => Self::E32x2S,
233 V128ExtendKind::LowI32x4U => Self::E32x2U,
234 _ => unimplemented!(),
235 }
236 }
237}
238
239pub(super) enum VcmpKind {
241 Eq,
243 Ne,
245 Lt,
247 Le,
249 Unord,
252}
253
254pub(super) enum VcvtKind {
256 I32ToF32,
258 I32ToF64,
260 F64ToF32,
262 F64ToI32,
264 F32ToF64,
266 F32ToI32,
268}
269
270pub(crate) enum VroundMode {
272 TowardNearest,
274 TowardNegativeInfinity,
276 TowardPositiveInfinity,
278 TowardZero,
280}
281
282pub(crate) struct Assembler {
284 buffer: MachBuffer<Inst>,
286 emit_info: EmitInfo,
288 emit_state: EmitState,
290 isa_flags: x64_settings::Flags,
292 pool: ConstantPool,
294}
295
296impl Assembler {
297 pub fn new(shared_flags: settings::Flags, isa_flags: x64_settings::Flags) -> Self {
299 Self {
300 buffer: MachBuffer::<Inst>::new(),
301 emit_state: Default::default(),
302 emit_info: EmitInfo::new(shared_flags, isa_flags.clone()),
303 pool: ConstantPool::new(),
304 isa_flags,
305 }
306 }
307
308 pub fn buffer_mut(&mut self) -> &mut MachBuffer<Inst> {
311 &mut self.buffer
312 }
313
314 pub fn buffer(&self) -> &MachBuffer<Inst> {
316 &self.buffer
317 }
318
319 pub fn add_constant(&mut self, constant: &[u8]) -> Address {
321 let handle = self.pool.register(constant, &mut self.buffer);
322 Address::constant(handle)
323 }
324
325 pub fn load_fp_const(&mut self, dst: WritableReg, constant: &[u8], size: OperandSize) {
327 let addr = self.add_constant(constant);
328 self.xmm_mov_mr(&addr, dst, size, MemFlags::trusted());
329 }
330
331 pub fn finalize(mut self, loc: Option<SourceLoc>) -> MachBufferFinalized<Final> {
333 let stencil = self
334 .buffer
335 .finish(&self.pool.constants(), self.emit_state.ctrl_plane_mut());
336 stencil.apply_base_srcloc(loc.unwrap_or_default())
337 }
338
339 fn emit(&mut self, inst: Inst) {
340 inst.emit(&mut self.buffer, &self.emit_info, &mut self.emit_state);
341 }
342
343 fn to_synthetic_amode(addr: &Address, memflags: MemFlags) -> SyntheticAmode {
344 match *addr {
345 Address::Offset { base, offset } => {
346 let amode = Amode::imm_reg(offset as i32, base.into()).with_flags(memflags);
347 SyntheticAmode::real(amode)
348 }
349 Address::Const(c) => SyntheticAmode::ConstantOffset(c),
350 Address::ImmRegRegShift {
351 simm32,
352 base,
353 index,
354 shift,
355 } => SyntheticAmode::Real(Amode::ImmRegRegShift {
356 simm32,
357 base: base.into(),
358 index: index.into(),
359 shift,
360 flags: memflags,
361 }),
362 }
363 }
364
365 pub fn unwind_inst(&mut self, inst: UnwindInst) {
367 self.emit(Inst::Unwind { inst })
368 }
369
370 pub fn push_r(&mut self, reg: Reg) {
372 let inst = asm::inst::pushq_o::new(reg).into();
373 self.emit(Inst::External { inst });
374 }
375
376 pub fn pop_r(&mut self, dst: WritableReg) {
378 let writable: WritableGpr = dst.map(Into::into);
379 let inst = asm::inst::popq_o::new(writable).into();
380 self.emit(Inst::External { inst });
381 }
382
383 pub fn ret(&mut self) {
385 let inst = asm::inst::retq_zo::new().into();
386 self.emit(Inst::External { inst });
387 }
388
389 pub fn mov_rr(&mut self, src: Reg, dst: WritableReg, size: OperandSize) {
391 let dst: WritableGpr = dst.map(|r| r.into());
392 let inst = match size {
393 OperandSize::S8 => asm::inst::movb_mr::new(dst, src).into(),
394 OperandSize::S16 => asm::inst::movw_mr::new(dst, src).into(),
395 OperandSize::S32 => asm::inst::movl_mr::new(dst, src).into(),
396 OperandSize::S64 => asm::inst::movq_mr::new(dst, src).into(),
397 _ => unreachable!(),
398 };
399 self.emit(Inst::External { inst });
400 }
401
402 pub fn mov_rm(&mut self, src: Reg, addr: &Address, size: OperandSize, flags: MemFlags) {
404 assert!(addr.is_offset());
405 let dst = Self::to_synthetic_amode(addr, flags);
406 let inst = match size {
407 OperandSize::S8 => asm::inst::movb_mr::new(dst, src).into(),
408 OperandSize::S16 => asm::inst::movw_mr::new(dst, src).into(),
409 OperandSize::S32 => asm::inst::movl_mr::new(dst, src).into(),
410 OperandSize::S64 => asm::inst::movq_mr::new(dst, src).into(),
411 _ => unreachable!(),
412 };
413 self.emit(Inst::External { inst });
414 }
415
416 pub fn mov_im(&mut self, src: i32, addr: &Address, size: OperandSize, flags: MemFlags) {
418 assert!(addr.is_offset());
419 let dst = Self::to_synthetic_amode(addr, flags);
420 let inst = match size {
421 OperandSize::S8 => {
422 let src = i8::try_from(src).unwrap();
423 asm::inst::movb_mi::new(dst, src.unsigned()).into()
424 }
425 OperandSize::S16 => {
426 let src = i16::try_from(src).unwrap();
427 asm::inst::movw_mi::new(dst, src.unsigned()).into()
428 }
429 OperandSize::S32 => asm::inst::movl_mi::new(dst, src.unsigned()).into(),
430 OperandSize::S64 => asm::inst::movq_mi_sxl::new(dst, src).into(),
431 _ => unreachable!(),
432 };
433 self.emit(Inst::External { inst });
434 }
435
436 pub fn mov_ir(&mut self, imm: u64, dst: WritableReg, size: OperandSize) {
438 self.emit(Inst::imm(size.into(), imm, dst.map(Into::into)));
439 }
440
441 pub fn movzx_mr(
443 &mut self,
444 addr: &Address,
445 dst: WritableReg,
446 ext: Option<Extend<Zero>>,
447 memflags: MemFlags,
448 ) {
449 let src = Self::to_synthetic_amode(addr, memflags);
450
451 if let Some(ext) = ext {
452 let dst = WritableGpr::from_reg(dst.to_reg().into());
453 let inst = match ext.into() {
454 ExtMode::BL => asm::inst::movzbl_rm::new(dst, src).into(),
455 ExtMode::BQ => asm::inst::movzbq_rm::new(dst, src).into(),
456 ExtMode::WL => asm::inst::movzwl_rm::new(dst, src).into(),
457 ExtMode::WQ => asm::inst::movzwq_rm::new(dst, src).into(),
458 ExtMode::LQ => {
459 asm::inst::movl_rm::new(dst, src).into()
467 }
468 };
469 self.emit(Inst::External { inst });
470 } else {
471 let dst = WritableGpr::from_reg(dst.to_reg().into());
472 let inst = asm::inst::movq_rm::new(dst, src).into();
473 self.emit(Inst::External { inst });
474 }
475 }
476
477 pub fn movsx_mr(
479 &mut self,
480 addr: &Address,
481 dst: WritableReg,
482 ext: Extend<Signed>,
483 memflags: MemFlags,
484 ) {
485 let src = Self::to_synthetic_amode(addr, memflags);
486 let dst = WritableGpr::from_reg(dst.to_reg().into());
487 let inst = match ext.into() {
488 ExtMode::BL => asm::inst::movsbl_rm::new(dst, src).into(),
489 ExtMode::BQ => asm::inst::movsbq_rm::new(dst, src).into(),
490 ExtMode::WL => asm::inst::movswl_rm::new(dst, src).into(),
491 ExtMode::WQ => asm::inst::movswq_rm::new(dst, src).into(),
492 ExtMode::LQ => asm::inst::movslq_rm::new(dst, src).into(),
493 };
494 self.emit(Inst::External { inst });
495 }
496
497 pub fn movzx_rr(&mut self, src: Reg, dst: WritableReg, kind: Extend<Zero>) {
499 let dst = WritableGpr::from_reg(dst.to_reg().into());
500 let inst = match kind.into() {
501 ExtMode::BL => asm::inst::movzbl_rm::new(dst, src).into(),
502 ExtMode::BQ => asm::inst::movzbq_rm::new(dst, src).into(),
503 ExtMode::WL => asm::inst::movzwl_rm::new(dst, src).into(),
504 ExtMode::WQ => asm::inst::movzwq_rm::new(dst, src).into(),
505 ExtMode::LQ => {
506 asm::inst::movl_rm::new(dst, src).into()
513 }
514 };
515 self.emit(Inst::External { inst });
516 }
517
518 pub fn movsx_rr(&mut self, src: Reg, dst: WritableReg, kind: Extend<Signed>) {
520 let dst = WritableGpr::from_reg(dst.to_reg().into());
521 let inst = match kind.into() {
522 ExtMode::BL => asm::inst::movsbl_rm::new(dst, src).into(),
523 ExtMode::BQ => asm::inst::movsbq_rm::new(dst, src).into(),
524 ExtMode::WL => asm::inst::movswl_rm::new(dst, src).into(),
525 ExtMode::WQ => asm::inst::movswq_rm::new(dst, src).into(),
526 ExtMode::LQ => asm::inst::movslq_rm::new(dst, src).into(),
527 };
528 self.emit(Inst::External { inst });
529 }
530
531 pub fn cmov(&mut self, src: Reg, dst: WritableReg, cc: IntCmpKind, size: OperandSize) {
533 use IntCmpKind::*;
534 use OperandSize::*;
535
536 let dst: WritableGpr = dst.map(Into::into);
537 let inst = match size {
538 S8 | S16 | S32 => match cc {
539 Eq => asm::inst::cmovel_rm::new(dst, src).into(),
540 Ne => asm::inst::cmovnel_rm::new(dst, src).into(),
541 LtS => asm::inst::cmovll_rm::new(dst, src).into(),
542 LtU => asm::inst::cmovbl_rm::new(dst, src).into(),
543 GtS => asm::inst::cmovgl_rm::new(dst, src).into(),
544 GtU => asm::inst::cmoval_rm::new(dst, src).into(),
545 LeS => asm::inst::cmovlel_rm::new(dst, src).into(),
546 LeU => asm::inst::cmovbel_rm::new(dst, src).into(),
547 GeS => asm::inst::cmovgel_rm::new(dst, src).into(),
548 GeU => asm::inst::cmovael_rm::new(dst, src).into(),
549 },
550 S64 => match cc {
551 Eq => asm::inst::cmoveq_rm::new(dst, src).into(),
552 Ne => asm::inst::cmovneq_rm::new(dst, src).into(),
553 LtS => asm::inst::cmovlq_rm::new(dst, src).into(),
554 LtU => asm::inst::cmovbq_rm::new(dst, src).into(),
555 GtS => asm::inst::cmovgq_rm::new(dst, src).into(),
556 GtU => asm::inst::cmovaq_rm::new(dst, src).into(),
557 LeS => asm::inst::cmovleq_rm::new(dst, src).into(),
558 LeU => asm::inst::cmovbeq_rm::new(dst, src).into(),
559 GeS => asm::inst::cmovgeq_rm::new(dst, src).into(),
560 GeU => asm::inst::cmovaeq_rm::new(dst, src).into(),
561 },
562 _ => unreachable!(),
563 };
564 self.emit(Inst::External { inst });
565 }
566
567 pub fn xmm_mov_rr(&mut self, src: Reg, dst: WritableReg, size: OperandSize) {
570 let ty = match size {
571 OperandSize::S32 => types::F32,
572 OperandSize::S64 => types::F64,
573 OperandSize::S128 => types::I32X4,
574 OperandSize::S8 | OperandSize::S16 => unreachable!(),
575 };
576 self.emit(Inst::gen_move(dst.map(|r| r.into()), src.into(), ty));
577 }
578
579 pub fn xmm_mov_mr(
581 &mut self,
582 src: &Address,
583 dst: WritableReg,
584 size: OperandSize,
585 flags: MemFlags,
586 ) {
587 use OperandSize::*;
588
589 assert!(dst.to_reg().is_float());
590
591 let src = Self::to_synthetic_amode(src, flags);
592 let dst: WritableXmm = dst.map(|r| r.into());
593 let inst = match size {
594 S32 => asm::inst::movss_a_m::new(dst, src).into(),
595 S64 => asm::inst::movsd_a_m::new(dst, src).into(),
596 S128 => asm::inst::movdqu_a::new(dst, src).into(),
597 S8 | S16 => unreachable!(),
598 };
599 self.emit(Inst::External { inst });
600 }
601
602 pub fn xmm_vpmov_mr(
604 &mut self,
605 src: &Address,
606 dst: WritableReg,
607 kind: VpmovKind,
608 flags: MemFlags,
609 ) {
610 assert!(dst.to_reg().is_float());
611 let src = Self::to_synthetic_amode(src, flags);
612 let dst: WritableXmm = dst.map(|r| r.into());
613 let inst = match kind {
614 VpmovKind::E8x8S => asm::inst::vpmovsxbw_a::new(dst, src).into(),
615 VpmovKind::E8x8U => asm::inst::vpmovzxbw_a::new(dst, src).into(),
616 VpmovKind::E16x4S => asm::inst::vpmovsxwd_a::new(dst, src).into(),
617 VpmovKind::E16x4U => asm::inst::vpmovzxwd_a::new(dst, src).into(),
618 VpmovKind::E32x2S => asm::inst::vpmovsxdq_a::new(dst, src).into(),
619 VpmovKind::E32x2U => asm::inst::vpmovzxdq_a::new(dst, src).into(),
620 };
621 self.emit(Inst::External { inst });
622 }
623
624 pub fn xmm_vpmov_rr(&mut self, src: Reg, dst: WritableReg, kind: VpmovKind) {
626 let dst: WritableXmm = dst.map(|r| r.into());
627 let inst = match kind {
628 VpmovKind::E8x8S => asm::inst::vpmovsxbw_a::new(dst, src).into(),
629 VpmovKind::E8x8U => asm::inst::vpmovzxbw_a::new(dst, src).into(),
630 VpmovKind::E16x4S => asm::inst::vpmovsxwd_a::new(dst, src).into(),
631 VpmovKind::E16x4U => asm::inst::vpmovzxwd_a::new(dst, src).into(),
632 VpmovKind::E32x2S => asm::inst::vpmovsxdq_a::new(dst, src).into(),
633 VpmovKind::E32x2U => asm::inst::vpmovzxdq_a::new(dst, src).into(),
634 };
635 self.emit(Inst::External { inst });
636 }
637
638 pub fn xmm_vpbroadcast_mr(
640 &mut self,
641 src: &Address,
642 dst: WritableReg,
643 size: OperandSize,
644 flags: MemFlags,
645 ) {
646 assert!(dst.to_reg().is_float());
647 let src = Self::to_synthetic_amode(src, flags);
648 let dst: WritableXmm = dst.map(|r| r.into());
649 let inst = match size {
650 OperandSize::S8 => asm::inst::vpbroadcastb_a::new(dst, src).into(),
651 OperandSize::S16 => asm::inst::vpbroadcastw_a::new(dst, src).into(),
652 OperandSize::S32 => asm::inst::vpbroadcastd_a::new(dst, src).into(),
653 _ => unimplemented!(),
654 };
655 self.emit(Inst::External { inst });
656 }
657
658 pub fn xmm_vpbroadcast_rr(&mut self, src: Reg, dst: WritableReg, size: OperandSize) {
660 assert!(src.is_float() && dst.to_reg().is_float());
661 let dst: WritableXmm = dst.map(|r| r.into());
662 let inst = match size {
663 OperandSize::S8 => asm::inst::vpbroadcastb_a::new(dst, src).into(),
664 OperandSize::S16 => asm::inst::vpbroadcastw_a::new(dst, src).into(),
665 OperandSize::S32 => asm::inst::vpbroadcastd_a::new(dst, src).into(),
666 _ => unimplemented!(),
667 };
668 self.emit(Inst::External { inst });
669 }
670
671 pub fn xmm_vpshuf_mr(
673 &mut self,
674 src: &Address,
675 dst: WritableReg,
676 mask: u8,
677 size: OperandSize,
678 flags: MemFlags,
679 ) {
680 let dst: WritableXmm = dst.map(|r| r.into());
681 let src = Self::to_synthetic_amode(src, flags);
682 let inst = match size {
683 OperandSize::S32 => asm::inst::vpshufd_a::new(dst, src, mask).into(),
684 _ => unimplemented!(),
685 };
686 self.emit(Inst::External { inst });
687 }
688
689 pub fn xmm_vpshuf_rr(&mut self, src: Reg, dst: WritableReg, mask: u8, size: OperandSize) {
691 let dst: WritableXmm = dst.map(|r| r.into());
692
693 let inst = match size {
694 OperandSize::S16 => asm::inst::vpshuflw_a::new(dst, src, mask).into(),
695 OperandSize::S32 => asm::inst::vpshufd_a::new(dst, src, mask).into(),
696 _ => unimplemented!(),
697 };
698
699 self.emit(Inst::External { inst });
700 }
701
702 pub fn xmm_mov_rm(&mut self, src: Reg, dst: &Address, size: OperandSize, flags: MemFlags) {
704 use OperandSize::*;
705
706 assert!(src.is_float());
707
708 let dst = Self::to_synthetic_amode(dst, flags);
709 let src: Xmm = src.into();
710 let inst = match size {
711 S32 => asm::inst::movss_c_m::new(dst, src).into(),
712 S64 => asm::inst::movsd_c_m::new(dst, src).into(),
713 S128 => asm::inst::movdqu_b::new(dst, src).into(),
714 S16 | S8 => unreachable!(),
715 };
716 self.emit(Inst::External { inst })
717 }
718
719 pub fn xmm_cmov(&mut self, src: Reg, dst: WritableReg, cc: IntCmpKind, size: OperandSize) {
721 let dst: WritableXmm = dst.map(Into::into);
722 let ty = match size {
723 OperandSize::S32 => types::F32,
724 OperandSize::S64 => types::F64,
725 OperandSize::S128 => types::I32X4,
727 OperandSize::S8 | OperandSize::S16 => unreachable!(),
728 };
729
730 self.emit(Inst::XmmCmove {
731 ty,
732 cc: cc.into(),
733 consequent: Xmm::unwrap_new(src.into()),
734 alternative: dst.to_reg(),
735 dst,
736 })
737 }
738
739 pub fn sub_rr(&mut self, src: Reg, dst: WritableReg, size: OperandSize) {
741 let dst = pair_gpr(dst);
742 let inst = match size {
743 OperandSize::S8 => asm::inst::subb_rm::new(dst, src).into(),
744 OperandSize::S16 => asm::inst::subw_rm::new(dst, src).into(),
745 OperandSize::S32 => asm::inst::subl_rm::new(dst, src).into(),
746 OperandSize::S64 => asm::inst::subq_rm::new(dst, src).into(),
747 OperandSize::S128 => unimplemented!(),
748 };
749 self.emit(Inst::External { inst });
750 }
751
752 pub fn sub_ir(&mut self, imm: i32, dst: WritableReg, size: OperandSize) {
754 let dst = pair_gpr(dst);
755 let inst = match size {
756 OperandSize::S8 => asm::inst::subb_mi::new(dst, u8::try_from(imm).unwrap()).into(),
757 OperandSize::S16 => asm::inst::subw_mi::new(dst, u16::try_from(imm).unwrap()).into(),
758 OperandSize::S32 => asm::inst::subl_mi::new(dst, imm as u32).into(),
759 OperandSize::S64 => asm::inst::subq_mi_sxl::new(dst, imm).into(),
760 OperandSize::S128 => unimplemented!(),
761 };
762 self.emit(Inst::External { inst });
763 }
764
765 pub fn and_rr(&mut self, src: Reg, dst: WritableReg, size: OperandSize) {
767 let dst = pair_gpr(dst);
768 let inst = match size {
769 OperandSize::S8 => asm::inst::andb_rm::new(dst, src).into(),
770 OperandSize::S16 => asm::inst::andw_rm::new(dst, src).into(),
771 OperandSize::S32 => asm::inst::andl_rm::new(dst, src).into(),
772 OperandSize::S64 => asm::inst::andq_rm::new(dst, src).into(),
773 OperandSize::S128 => unimplemented!(),
774 };
775 self.emit(Inst::External { inst });
776 }
777
778 pub fn and_ir(&mut self, imm: i32, dst: WritableReg, size: OperandSize) {
779 let dst = pair_gpr(dst);
780 let inst = match size {
781 OperandSize::S8 => asm::inst::andb_mi::new(dst, u8::try_from(imm).unwrap()).into(),
782 OperandSize::S16 => asm::inst::andw_mi::new(dst, u16::try_from(imm).unwrap()).into(),
783 OperandSize::S32 => asm::inst::andl_mi::new(dst, imm as u32).into(),
784 OperandSize::S64 => asm::inst::andq_mi_sxl::new(dst, imm).into(),
785 OperandSize::S128 => unimplemented!(),
786 };
787 self.emit(Inst::External { inst });
788 }
789
790 pub fn xmm_and_rr(&mut self, src: Reg, dst: WritableReg, size: OperandSize) {
792 let dst = pair_xmm(dst);
793 let inst = match size {
794 OperandSize::S32 => asm::inst::andps_a::new(dst, src).into(),
795 OperandSize::S64 => asm::inst::andpd_a::new(dst, src).into(),
796 OperandSize::S8 | OperandSize::S16 | OperandSize::S128 => unreachable!(),
797 };
798 self.emit(Inst::External { inst });
799 }
800
801 pub fn xmm_andn_rr(&mut self, src: Reg, dst: WritableReg, size: OperandSize) {
803 let dst = pair_xmm(dst);
804 let inst = match size {
805 OperandSize::S32 => asm::inst::andnps_a::new(dst, src).into(),
806 OperandSize::S64 => asm::inst::andnpd_a::new(dst, src).into(),
807 OperandSize::S8 | OperandSize::S16 | OperandSize::S128 => unreachable!(),
808 };
809 self.emit(Inst::External { inst });
810 }
811
812 pub fn gpr_to_xmm(&mut self, src: Reg, dst: WritableReg, size: OperandSize) {
813 let dst: WritableXmm = dst.map(|r| r.into());
814 let inst = match size {
815 OperandSize::S32 => asm::inst::movd_a::new(dst, src).into(),
816 OperandSize::S64 => asm::inst::movq_a::new(dst, src).into(),
817 OperandSize::S8 | OperandSize::S16 | OperandSize::S128 => unreachable!(),
818 };
819
820 self.emit(Inst::External { inst });
821 }
822
823 pub fn xmm_to_gpr(&mut self, src: Reg, dst: WritableReg, size: OperandSize) {
824 let dst: WritableGpr = dst.map(Into::into);
825 let src: Xmm = src.into();
826 let inst = match size {
827 OperandSize::S32 => asm::inst::movd_b::new(dst, src).into(),
828 OperandSize::S64 => asm::inst::movq_b::new(dst, src).into(),
829 OperandSize::S8 | OperandSize::S16 | OperandSize::S128 => unreachable!(),
830 };
831
832 self.emit(Inst::External { inst })
833 }
834
835 pub fn cvt_float_to_sint_seq(
837 &mut self,
838 src: Reg,
839 dst: WritableReg,
840 tmp_gpr: Reg,
841 tmp_xmm: Reg,
842 src_size: OperandSize,
843 dst_size: OperandSize,
844 saturating: bool,
845 ) {
846 self.emit(Inst::CvtFloatToSintSeq {
847 dst_size: dst_size.into(),
848 src_size: src_size.into(),
849 is_saturating: saturating,
850 src: src.into(),
851 dst: dst.map(Into::into),
852 tmp_gpr: tmp_gpr.into(),
853 tmp_xmm: tmp_xmm.into(),
854 });
855 }
856
857 pub fn cvt_float_to_uint_seq(
859 &mut self,
860 src: Reg,
861 dst: WritableReg,
862 tmp_gpr: Reg,
863 tmp_xmm: Reg,
864 tmp_xmm2: Reg,
865 src_size: OperandSize,
866 dst_size: OperandSize,
867 saturating: bool,
868 ) {
869 self.emit(Inst::CvtFloatToUintSeq {
870 dst_size: dst_size.into(),
871 src_size: src_size.into(),
872 is_saturating: saturating,
873 src: src.into(),
874 dst: dst.map(Into::into),
875 tmp_gpr: tmp_gpr.into(),
876 tmp_xmm: tmp_xmm.into(),
877 tmp_xmm2: tmp_xmm2.into(),
878 });
879 }
880
881 pub fn cvt_sint_to_float(
883 &mut self,
884 src: Reg,
885 dst: WritableReg,
886 src_size: OperandSize,
887 dst_size: OperandSize,
888 ) {
889 use OperandSize::*;
890 let dst = pair_xmm(dst);
891 let inst = match (src_size, dst_size) {
892 (S32, S32) => asm::inst::cvtsi2ssl_a::new(dst, src).into(),
893 (S32, S64) => asm::inst::cvtsi2sdl_a::new(dst, src).into(),
894 (S64, S32) => asm::inst::cvtsi2ssq_a::new(dst, src).into(),
895 (S64, S64) => asm::inst::cvtsi2sdq_a::new(dst, src).into(),
896 _ => unreachable!(),
897 };
898 self.emit(Inst::External { inst });
899 }
900
901 pub fn cvt_uint64_to_float_seq(
903 &mut self,
904 src: Reg,
905 dst: WritableReg,
906 tmp_gpr1: Reg,
907 tmp_gpr2: Reg,
908 dst_size: OperandSize,
909 ) {
910 self.emit(Inst::CvtUint64ToFloatSeq {
911 dst_size: dst_size.into(),
912 src: src.into(),
913 dst: dst.map(Into::into),
914 tmp_gpr1: tmp_gpr1.into(),
915 tmp_gpr2: tmp_gpr2.into(),
916 });
917 }
918
919 pub fn cvt_float_to_float(
921 &mut self,
922 src: Reg,
923 dst: WritableReg,
924 src_size: OperandSize,
925 dst_size: OperandSize,
926 ) {
927 use OperandSize::*;
928 let dst = pair_xmm(dst);
929 let inst = match (src_size, dst_size) {
930 (S32, S64) => asm::inst::cvtss2sd_a::new(dst, src).into(),
931 (S64, S32) => asm::inst::cvtsd2ss_a::new(dst, src).into(),
932 _ => unimplemented!(),
933 };
934 self.emit(Inst::External { inst });
935 }
936
937 pub fn or_rr(&mut self, src: Reg, dst: WritableReg, size: OperandSize) {
938 let dst = pair_gpr(dst);
939 let inst = match size {
940 OperandSize::S8 => asm::inst::orb_rm::new(dst, src).into(),
941 OperandSize::S16 => asm::inst::orw_rm::new(dst, src).into(),
942 OperandSize::S32 => asm::inst::orl_rm::new(dst, src).into(),
943 OperandSize::S64 => asm::inst::orq_rm::new(dst, src).into(),
944 OperandSize::S128 => unimplemented!(),
945 };
946 self.emit(Inst::External { inst });
947 }
948
949 pub fn or_ir(&mut self, imm: i32, dst: WritableReg, size: OperandSize) {
950 let dst = pair_gpr(dst);
951 let inst = match size {
952 OperandSize::S8 => asm::inst::orb_mi::new(dst, u8::try_from(imm).unwrap()).into(),
953 OperandSize::S16 => asm::inst::orw_mi::new(dst, u16::try_from(imm).unwrap()).into(),
954 OperandSize::S32 => asm::inst::orl_mi::new(dst, imm as u32).into(),
955 OperandSize::S64 => asm::inst::orq_mi_sxl::new(dst, imm).into(),
956 OperandSize::S128 => unimplemented!(),
957 };
958 self.emit(Inst::External { inst });
959 }
960
961 pub fn xmm_or_rr(&mut self, src: Reg, dst: WritableReg, size: OperandSize) {
962 let dst = pair_xmm(dst);
963 let inst = match size {
964 OperandSize::S32 => asm::inst::orps_a::new(dst, src).into(),
965 OperandSize::S64 => asm::inst::orpd_a::new(dst, src).into(),
966 OperandSize::S8 | OperandSize::S16 | OperandSize::S128 => unreachable!(),
967 };
968 self.emit(Inst::External { inst });
969 }
970
971 pub fn xor_rr(&mut self, src: Reg, dst: WritableReg, size: OperandSize) {
973 let dst = pair_gpr(dst);
974 let inst = match size {
975 OperandSize::S8 => asm::inst::xorb_rm::new(dst, src).into(),
976 OperandSize::S16 => asm::inst::xorw_rm::new(dst, src).into(),
977 OperandSize::S32 => asm::inst::xorl_rm::new(dst, src).into(),
978 OperandSize::S64 => asm::inst::xorq_rm::new(dst, src).into(),
979 OperandSize::S128 => unimplemented!(),
980 };
981 self.emit(Inst::External { inst });
982 }
983
984 pub fn xor_ir(&mut self, imm: i32, dst: WritableReg, size: OperandSize) {
985 let dst = pair_gpr(dst);
986 let inst = match size {
987 OperandSize::S8 => asm::inst::xorb_mi::new(dst, u8::try_from(imm).unwrap()).into(),
988 OperandSize::S16 => asm::inst::xorw_mi::new(dst, u16::try_from(imm).unwrap()).into(),
989 OperandSize::S32 => asm::inst::xorl_mi::new(dst, imm as u32).into(),
990 OperandSize::S64 => asm::inst::xorq_mi_sxl::new(dst, imm).into(),
991 OperandSize::S128 => unimplemented!(),
992 };
993 self.emit(Inst::External { inst });
994 }
995
996 pub fn xmm_xor_rr(&mut self, src: Reg, dst: WritableReg, size: OperandSize) {
998 let dst = pair_xmm(dst);
999 let inst = match size {
1000 OperandSize::S32 => asm::inst::xorps_a::new(dst, src).into(),
1001 OperandSize::S64 => asm::inst::xorpd_a::new(dst, src).into(),
1002 OperandSize::S8 | OperandSize::S16 | OperandSize::S128 => unreachable!(),
1003 };
1004 self.emit(Inst::External { inst });
1005 }
1006
1007 pub fn shift_rr(&mut self, src: Reg, dst: WritableReg, kind: ShiftKind, size: OperandSize) {
1009 let dst = pair_gpr(dst);
1010 let src: Gpr = src.into();
1011 let inst = match (kind, size) {
1012 (ShiftKind::Shl, OperandSize::S32) => asm::inst::shll_mc::new(dst, src).into(),
1013 (ShiftKind::Shl, OperandSize::S64) => asm::inst::shlq_mc::new(dst, src).into(),
1014 (ShiftKind::Shl, _) => todo!(),
1015 (ShiftKind::ShrS, OperandSize::S32) => asm::inst::sarl_mc::new(dst, src).into(),
1016 (ShiftKind::ShrS, OperandSize::S64) => asm::inst::sarq_mc::new(dst, src).into(),
1017 (ShiftKind::ShrS, _) => todo!(),
1018 (ShiftKind::ShrU, OperandSize::S32) => asm::inst::shrl_mc::new(dst, src).into(),
1019 (ShiftKind::ShrU, OperandSize::S64) => asm::inst::shrq_mc::new(dst, src).into(),
1020 (ShiftKind::ShrU, _) => todo!(),
1021 (ShiftKind::Rotl, OperandSize::S32) => asm::inst::roll_mc::new(dst, src).into(),
1022 (ShiftKind::Rotl, OperandSize::S64) => asm::inst::rolq_mc::new(dst, src).into(),
1023 (ShiftKind::Rotl, _) => todo!(),
1024 (ShiftKind::Rotr, OperandSize::S32) => asm::inst::rorl_mc::new(dst, src).into(),
1025 (ShiftKind::Rotr, OperandSize::S64) => asm::inst::rorq_mc::new(dst, src).into(),
1026 (ShiftKind::Rotr, _) => todo!(),
1027 };
1028 self.emit(Inst::External { inst });
1029 }
1030
1031 pub fn shift_ir(&mut self, imm: u8, dst: WritableReg, kind: ShiftKind, size: OperandSize) {
1033 let dst = pair_gpr(dst);
1034 let inst = match (kind, size) {
1035 (ShiftKind::Shl, OperandSize::S32) => asm::inst::shll_mi::new(dst, imm).into(),
1036 (ShiftKind::Shl, OperandSize::S64) => asm::inst::shlq_mi::new(dst, imm).into(),
1037 (ShiftKind::Shl, _) => todo!(),
1038 (ShiftKind::ShrS, OperandSize::S32) => asm::inst::sarl_mi::new(dst, imm).into(),
1039 (ShiftKind::ShrS, OperandSize::S64) => asm::inst::sarq_mi::new(dst, imm).into(),
1040 (ShiftKind::ShrS, _) => todo!(),
1041 (ShiftKind::ShrU, OperandSize::S32) => asm::inst::shrl_mi::new(dst, imm).into(),
1042 (ShiftKind::ShrU, OperandSize::S64) => asm::inst::shrq_mi::new(dst, imm).into(),
1043 (ShiftKind::ShrU, _) => todo!(),
1044 (ShiftKind::Rotl, OperandSize::S32) => asm::inst::roll_mi::new(dst, imm).into(),
1045 (ShiftKind::Rotl, OperandSize::S64) => asm::inst::rolq_mi::new(dst, imm).into(),
1046 (ShiftKind::Rotl, _) => todo!(),
1047 (ShiftKind::Rotr, OperandSize::S32) => asm::inst::rorl_mi::new(dst, imm).into(),
1048 (ShiftKind::Rotr, OperandSize::S64) => asm::inst::rorq_mi::new(dst, imm).into(),
1049 (ShiftKind::Rotr, _) => todo!(),
1050 };
1051 self.emit(Inst::External { inst });
1052 }
1053
1054 pub fn div(&mut self, divisor: Reg, dst: (Reg, Reg), kind: DivKind, size: OperandSize) {
1061 let trap = match kind {
1062 DivKind::Signed => {
1066 self.cmp_ir(divisor, 0, size);
1067 self.emit(Inst::TrapIf {
1068 cc: CC::Z,
1069 trap_code: TrapCode::INTEGER_DIVISION_BY_ZERO,
1070 });
1071
1072 let ext_dst: WritableGpr = dst.1.into();
1075 let ext_src: Gpr = dst.0.into();
1076 let inst = match size {
1077 OperandSize::S32 => asm::inst::cltd_zo::new(ext_dst, ext_src).into(),
1078 OperandSize::S64 => asm::inst::cqto_zo::new(ext_dst, ext_src).into(),
1079 _ => unimplemented!(),
1080 };
1081 self.emit(Inst::External { inst });
1082 TrapCode::INTEGER_OVERFLOW
1083 }
1084
1085 DivKind::Unsigned => {
1091 self.xor_rr(dst.1, writable!(dst.1), size);
1092 TrapCode::INTEGER_DIVISION_BY_ZERO
1093 }
1094 };
1095 let dst0 = pair_gpr(writable!(dst.0));
1096 let dst1 = pair_gpr(writable!(dst.1));
1097 let inst = match (kind, size) {
1098 (DivKind::Signed, OperandSize::S32) => {
1099 asm::inst::idivl_m::new(dst0, dst1, divisor, trap).into()
1100 }
1101 (DivKind::Unsigned, OperandSize::S32) => {
1102 asm::inst::divl_m::new(dst0, dst1, divisor, trap).into()
1103 }
1104 (DivKind::Signed, OperandSize::S64) => {
1105 asm::inst::idivq_m::new(dst0, dst1, divisor, trap).into()
1106 }
1107 (DivKind::Unsigned, OperandSize::S64) => {
1108 asm::inst::divq_m::new(dst0, dst1, divisor, trap).into()
1109 }
1110 _ => todo!(),
1111 };
1112 self.emit(Inst::External { inst });
1113 }
1114
1115 pub fn rem(&mut self, divisor: Reg, dst: (Reg, Reg), kind: RemKind, size: OperandSize) {
1123 match kind {
1124 RemKind::Signed => {
1128 let ext_dst: WritableGpr = dst.1.into();
1129
1130 let ext_src: Gpr = dst.0.into();
1133 let inst = match size {
1134 OperandSize::S32 => asm::inst::cltd_zo::new(ext_dst, ext_src).into(),
1135 OperandSize::S64 => asm::inst::cqto_zo::new(ext_dst, ext_src).into(),
1136 _ => unimplemented!(),
1137 };
1138 self.emit(Inst::External { inst });
1139 self.emit(Inst::CheckedSRemSeq {
1140 size: size.into(),
1141 divisor: divisor.into(),
1142 dividend_lo: dst.0.into(),
1143 dividend_hi: dst.1.into(),
1144 dst_quotient: dst.0.into(),
1145 dst_remainder: dst.1.into(),
1146 });
1147 }
1148
1149 RemKind::Unsigned => {
1152 self.xor_rr(dst.1, writable!(dst.1), size);
1153 let dst0 = pair_gpr(writable!(dst.0));
1154 let dst1 = pair_gpr(writable!(dst.1));
1155 let trap = TrapCode::INTEGER_DIVISION_BY_ZERO;
1156 let inst = match size {
1157 OperandSize::S32 => asm::inst::divl_m::new(dst0, dst1, divisor, trap).into(),
1158 OperandSize::S64 => asm::inst::divq_m::new(dst0, dst1, divisor, trap).into(),
1159 _ => todo!(),
1160 };
1161 self.emit(Inst::External { inst });
1162 }
1163 }
1164 }
1165
1166 pub fn mul_ir(&mut self, imm: i32, dst: WritableReg, size: OperandSize) {
1168 use OperandSize::*;
1169 let src = dst.to_reg();
1170 let dst: WritableGpr = dst.to_reg().into();
1171 let inst = match size {
1172 S16 => asm::inst::imulw_rmi::new(dst, src, u16::try_from(imm).unwrap()).into(),
1173 S32 => asm::inst::imull_rmi::new(dst, src, imm as u32).into(),
1174 S64 => asm::inst::imulq_rmi_sxl::new(dst, src, imm).into(),
1175 S8 | S128 => unimplemented!(),
1176 };
1177 self.emit(Inst::External { inst });
1178 }
1179
1180 pub fn mul_rr(&mut self, src: Reg, dst: WritableReg, size: OperandSize) {
1182 use OperandSize::*;
1183 let dst = pair_gpr(dst);
1184 let inst = match size {
1185 S16 => asm::inst::imulw_rm::new(dst, src).into(),
1186 S32 => asm::inst::imull_rm::new(dst, src).into(),
1187 S64 => asm::inst::imulq_rm::new(dst, src).into(),
1188 S8 | S128 => unimplemented!(),
1189 };
1190 self.emit(Inst::External { inst });
1191 }
1192
1193 pub fn add_ir(&mut self, imm: i32, dst: WritableReg, size: OperandSize) {
1195 let dst = pair_gpr(dst);
1196 let inst = match size {
1197 OperandSize::S8 => asm::inst::addb_mi::new(dst, u8::try_from(imm).unwrap()).into(),
1198 OperandSize::S16 => asm::inst::addw_mi::new(dst, u16::try_from(imm).unwrap()).into(),
1199 OperandSize::S32 => asm::inst::addl_mi::new(dst, imm as u32).into(),
1200 OperandSize::S64 => asm::inst::addq_mi_sxl::new(dst, imm).into(),
1201 OperandSize::S128 => unimplemented!(),
1202 };
1203 self.emit(Inst::External { inst });
1204 }
1205
1206 pub fn add_rr(&mut self, src: Reg, dst: WritableReg, size: OperandSize) {
1208 let dst = pair_gpr(dst);
1209 let inst = match size {
1210 OperandSize::S8 => asm::inst::addb_rm::new(dst, src).into(),
1211 OperandSize::S16 => asm::inst::addw_rm::new(dst, src).into(),
1212 OperandSize::S32 => asm::inst::addl_rm::new(dst, src).into(),
1213 OperandSize::S64 => asm::inst::addq_rm::new(dst, src).into(),
1214 OperandSize::S128 => unimplemented!(),
1215 };
1216 self.emit(Inst::External { inst });
1217 }
1218
1219 pub fn lock_xadd(
1220 &mut self,
1221 addr: Address,
1222 dst: WritableReg,
1223 size: OperandSize,
1224 flags: MemFlags,
1225 ) {
1226 assert!(addr.is_offset());
1227 let mem = Self::to_synthetic_amode(&addr, flags);
1228 let dst = pair_gpr(dst);
1229 let inst = match size {
1230 OperandSize::S8 => asm::inst::lock_xaddb_mr::new(mem, dst).into(),
1231 OperandSize::S16 => asm::inst::lock_xaddw_mr::new(mem, dst).into(),
1232 OperandSize::S32 => asm::inst::lock_xaddl_mr::new(mem, dst).into(),
1233 OperandSize::S64 => asm::inst::lock_xaddq_mr::new(mem, dst).into(),
1234 OperandSize::S128 => unimplemented!(),
1235 };
1236
1237 self.emit(Inst::External { inst });
1238 }
1239
1240 pub fn atomic_rmw_seq(
1241 &mut self,
1242 addr: Address,
1243 operand: Reg,
1244 dst: WritableReg,
1245 temp: WritableReg,
1246 size: OperandSize,
1247 flags: MemFlags,
1248 op: AtomicRmwSeqOp,
1249 ) {
1250 assert!(addr.is_offset());
1251 let mem = Self::to_synthetic_amode(&addr, flags);
1252 self.emit(Inst::AtomicRmwSeq {
1253 ty: Type::int_with_byte_size(size.bytes() as _).unwrap(),
1254 mem,
1255 operand: operand.into(),
1256 temp: temp.map(Into::into),
1257 dst_old: dst.map(Into::into),
1258 op,
1259 });
1260 }
1261
1262 pub fn xchg(&mut self, addr: Address, dst: WritableReg, size: OperandSize, flags: MemFlags) {
1263 assert!(addr.is_offset());
1264 let mem = Self::to_synthetic_amode(&addr, flags);
1265 let dst = pair_gpr(dst);
1266 let inst = match size {
1267 OperandSize::S8 => asm::inst::xchgb_rm::new(dst, mem).into(),
1268 OperandSize::S16 => asm::inst::xchgw_rm::new(dst, mem).into(),
1269 OperandSize::S32 => asm::inst::xchgl_rm::new(dst, mem).into(),
1270 OperandSize::S64 => asm::inst::xchgq_rm::new(dst, mem).into(),
1271 OperandSize::S128 => unimplemented!(),
1272 };
1273
1274 self.emit(Inst::External { inst });
1275 }
1276 pub fn cmpxchg(
1277 &mut self,
1278 addr: Address,
1279 replacement: Reg,
1280 dst: WritableReg,
1281 size: OperandSize,
1282 flags: MemFlags,
1283 ) {
1284 assert!(addr.is_offset());
1285 let mem = Self::to_synthetic_amode(&addr, flags);
1286 let dst = pair_gpr(dst);
1287 let inst = match size {
1288 OperandSize::S8 => asm::inst::lock_cmpxchgb_mr::new(mem, replacement, dst).into(),
1289 OperandSize::S16 => asm::inst::lock_cmpxchgw_mr::new(mem, replacement, dst).into(),
1290 OperandSize::S32 => asm::inst::lock_cmpxchgl_mr::new(mem, replacement, dst).into(),
1291 OperandSize::S64 => asm::inst::lock_cmpxchgq_mr::new(mem, replacement, dst).into(),
1292 OperandSize::S128 => unimplemented!(),
1293 };
1294
1295 self.emit(Inst::External { inst });
1296 }
1297
1298 pub fn cmp_ir(&mut self, src1: Reg, imm: i32, size: OperandSize) {
1299 let inst = match size {
1300 OperandSize::S8 => {
1301 let imm = i8::try_from(imm).unwrap();
1302 asm::inst::cmpb_mi::new(src1, imm.unsigned()).into()
1303 }
1304 OperandSize::S16 => match i8::try_from(imm) {
1305 Ok(imm8) => asm::inst::cmpw_mi_sxb::new(src1, imm8).into(),
1306 Err(_) => {
1307 asm::inst::cmpw_mi::new(src1, i16::try_from(imm).unwrap().unsigned()).into()
1308 }
1309 },
1310 OperandSize::S32 => match i8::try_from(imm) {
1311 Ok(imm8) => asm::inst::cmpl_mi_sxb::new(src1, imm8).into(),
1312 Err(_) => asm::inst::cmpl_mi::new(src1, imm.unsigned()).into(),
1313 },
1314 OperandSize::S64 => match i8::try_from(imm) {
1315 Ok(imm8) => asm::inst::cmpq_mi_sxb::new(src1, imm8).into(),
1316 Err(_) => asm::inst::cmpq_mi::new(src1, imm).into(),
1317 },
1318 OperandSize::S128 => unimplemented!(),
1319 };
1320
1321 self.emit(Inst::External { inst });
1322 }
1323
1324 pub fn cmp_rr(&mut self, src1: Reg, src2: Reg, size: OperandSize) {
1325 let inst = match size {
1326 OperandSize::S8 => asm::inst::cmpb_rm::new(src1, src2).into(),
1327 OperandSize::S16 => asm::inst::cmpw_rm::new(src1, src2).into(),
1328 OperandSize::S32 => asm::inst::cmpl_rm::new(src1, src2).into(),
1329 OperandSize::S64 => asm::inst::cmpq_rm::new(src1, src2).into(),
1330 OperandSize::S128 => unimplemented!(),
1331 };
1332
1333 self.emit(Inst::External { inst });
1334 }
1335
1336 pub fn ucomis(&mut self, src1: Reg, src2: Reg, size: OperandSize) {
1339 let inst = match size {
1340 OperandSize::S32 => asm::inst::ucomiss_a::new(src1, src2).into(),
1341 OperandSize::S64 => asm::inst::ucomisd_a::new(src1, src2).into(),
1342 OperandSize::S8 | OperandSize::S16 | OperandSize::S128 => unreachable!(),
1343 };
1344 self.emit(Inst::External { inst });
1345 }
1346
1347 pub fn popcnt(&mut self, src: Reg, dst: WritableReg, size: OperandSize) {
1348 assert!(
1349 self.isa_flags.has_popcnt() && self.isa_flags.has_sse42(),
1350 "Requires has_popcnt and has_sse42 flags"
1351 );
1352 let dst = WritableGpr::from_reg(dst.to_reg().into());
1353 let inst = match size {
1354 OperandSize::S16 => asm::inst::popcntw_rm::new(dst, src).into(),
1355 OperandSize::S32 => asm::inst::popcntl_rm::new(dst, src).into(),
1356 OperandSize::S64 => asm::inst::popcntq_rm::new(dst, src).into(),
1357 OperandSize::S8 | OperandSize::S128 => unreachable!(),
1358 };
1359 self.emit(Inst::External { inst });
1360 }
1361
1362 pub fn test_rr(&mut self, src1: Reg, src2: Reg, size: OperandSize) {
1364 let inst = match size {
1365 OperandSize::S8 => asm::inst::testb_mr::new(src1, src2).into(),
1366 OperandSize::S16 => asm::inst::testw_mr::new(src1, src2).into(),
1367 OperandSize::S32 => asm::inst::testl_mr::new(src1, src2).into(),
1368 OperandSize::S64 => asm::inst::testq_mr::new(src1, src2).into(),
1369 OperandSize::S128 => unimplemented!(),
1370 };
1371
1372 self.emit(Inst::External { inst });
1373 }
1374
1375 pub fn setcc(&mut self, kind: IntCmpKind, dst: WritableReg) {
1378 self.setcc_impl(kind.into(), dst);
1379 }
1380
1381 pub fn setp(&mut self, dst: WritableReg) {
1384 self.setcc_impl(CC::P, dst);
1385 }
1386
1387 pub fn setnp(&mut self, dst: WritableReg) {
1390 self.setcc_impl(CC::NP, dst);
1391 }
1392
1393 fn setcc_impl(&mut self, cc: CC, dst: WritableReg) {
1394 let dst: WritableGpr = dst.map(Into::into);
1397 let inst = asm::inst::movl_oi::new(dst, 0).into();
1398 self.emit(Inst::External { inst });
1399
1400 let inst = match cc {
1407 CC::O => asm::inst::seto_m::new(dst).into(),
1408 CC::NO => asm::inst::setno_m::new(dst).into(),
1409 CC::B => asm::inst::setb_m::new(dst).into(),
1410 CC::NB => asm::inst::setae_m::new(dst).into(), CC::Z => asm::inst::sete_m::new(dst).into(), CC::NZ => asm::inst::setne_m::new(dst).into(), CC::BE => asm::inst::setbe_m::new(dst).into(),
1414 CC::NBE => asm::inst::seta_m::new(dst).into(), CC::S => asm::inst::sets_m::new(dst).into(),
1416 CC::NS => asm::inst::setns_m::new(dst).into(),
1417 CC::L => asm::inst::setl_m::new(dst).into(),
1418 CC::NL => asm::inst::setge_m::new(dst).into(), CC::LE => asm::inst::setle_m::new(dst).into(),
1420 CC::NLE => asm::inst::setg_m::new(dst).into(), CC::P => asm::inst::setp_m::new(dst).into(),
1422 CC::NP => asm::inst::setnp_m::new(dst).into(),
1423 };
1424 self.emit(Inst::External { inst });
1425 }
1426
1427 pub fn lzcnt(&mut self, src: Reg, dst: WritableReg, size: OperandSize) {
1430 assert!(self.isa_flags.has_lzcnt(), "Requires has_lzcnt flag");
1431 let dst = WritableGpr::from_reg(dst.to_reg().into());
1432 let inst = match size {
1433 OperandSize::S16 => asm::inst::lzcntw_rm::new(dst, src).into(),
1434 OperandSize::S32 => asm::inst::lzcntl_rm::new(dst, src).into(),
1435 OperandSize::S64 => asm::inst::lzcntq_rm::new(dst, src).into(),
1436 OperandSize::S8 | OperandSize::S128 => unreachable!(),
1437 };
1438 self.emit(Inst::External { inst });
1439 }
1440
1441 pub fn tzcnt(&mut self, src: Reg, dst: WritableReg, size: OperandSize) {
1444 assert!(self.isa_flags.has_bmi1(), "Requires has_bmi1 flag");
1445 let dst = WritableGpr::from_reg(dst.to_reg().into());
1446 let inst = match size {
1447 OperandSize::S16 => asm::inst::tzcntw_a::new(dst, src).into(),
1448 OperandSize::S32 => asm::inst::tzcntl_a::new(dst, src).into(),
1449 OperandSize::S64 => asm::inst::tzcntq_a::new(dst, src).into(),
1450 OperandSize::S8 | OperandSize::S128 => unreachable!(),
1451 };
1452 self.emit(Inst::External { inst });
1453 }
1454
1455 pub fn bsr(&mut self, src: Reg, dst: WritableReg, size: OperandSize) {
1458 let dst: WritableGpr = WritableGpr::from_reg(dst.to_reg().into());
1459 let inst = match size {
1460 OperandSize::S16 => asm::inst::bsrw_rm::new(dst, src).into(),
1461 OperandSize::S32 => asm::inst::bsrl_rm::new(dst, src).into(),
1462 OperandSize::S64 => asm::inst::bsrq_rm::new(dst, src).into(),
1463 OperandSize::S8 | OperandSize::S128 => unreachable!(),
1464 };
1465 self.emit(Inst::External { inst });
1466 }
1467
1468 pub fn neg(&mut self, read: Reg, write: WritableReg, size: OperandSize) {
1470 let gpr = PairedGpr {
1471 read: read.into(),
1472 write: WritableGpr::from_reg(write.to_reg().into()),
1473 };
1474 let inst = match size {
1475 OperandSize::S8 => asm::inst::negb_m::new(gpr).into(),
1476 OperandSize::S16 => asm::inst::negw_m::new(gpr).into(),
1477 OperandSize::S32 => asm::inst::negl_m::new(gpr).into(),
1478 OperandSize::S64 => asm::inst::negq_m::new(gpr).into(),
1479 OperandSize::S128 => unreachable!(),
1480 };
1481 self.emit(Inst::External { inst });
1482 }
1483
1484 pub fn bsf(&mut self, src: Reg, dst: WritableReg, size: OperandSize) {
1487 let dst: WritableGpr = WritableGpr::from_reg(dst.to_reg().into());
1488 let inst = match size {
1489 OperandSize::S16 => asm::inst::bsfw_rm::new(dst, src).into(),
1490 OperandSize::S32 => asm::inst::bsfl_rm::new(dst, src).into(),
1491 OperandSize::S64 => asm::inst::bsfq_rm::new(dst, src).into(),
1492 OperandSize::S8 | OperandSize::S128 => unreachable!(),
1493 };
1494 self.emit(Inst::External { inst });
1495 }
1496
1497 pub fn xmm_add_rr(&mut self, src: Reg, dst: WritableReg, size: OperandSize) {
1499 let dst = pair_xmm(dst);
1500 let inst = match size {
1501 OperandSize::S32 => asm::inst::addss_a::new(dst, src).into(),
1502 OperandSize::S64 => asm::inst::addsd_a::new(dst, src).into(),
1503 OperandSize::S8 | OperandSize::S16 | OperandSize::S128 => unreachable!(),
1504 };
1505 self.emit(Inst::External { inst });
1506 }
1507
1508 pub fn xmm_sub_rr(&mut self, src: Reg, dst: WritableReg, size: OperandSize) {
1510 let dst = pair_xmm(dst);
1511 let inst = match size {
1512 OperandSize::S32 => asm::inst::subss_a::new(dst, src).into(),
1513 OperandSize::S64 => asm::inst::subsd_a::new(dst, src).into(),
1514 OperandSize::S8 | OperandSize::S16 | OperandSize::S128 => unreachable!(),
1515 };
1516 self.emit(Inst::External { inst });
1517 }
1518
1519 pub fn xmm_mul_rr(&mut self, src: Reg, dst: WritableReg, size: OperandSize) {
1521 use OperandSize::*;
1522 let dst = pair_xmm(dst);
1523 let inst = match size {
1524 S32 => asm::inst::mulss_a::new(dst, src).into(),
1525 S64 => asm::inst::mulsd_a::new(dst, src).into(),
1526 S8 | S16 | S128 => unreachable!(),
1527 };
1528 self.emit(Inst::External { inst });
1529 }
1530
1531 pub fn xmm_div_rr(&mut self, src: Reg, dst: WritableReg, size: OperandSize) {
1533 let dst = pair_xmm(dst);
1534 let inst = match size {
1535 OperandSize::S32 => asm::inst::divss_a::new(dst, src).into(),
1536 OperandSize::S64 => asm::inst::divsd_a::new(dst, src).into(),
1537 OperandSize::S8 | OperandSize::S16 | OperandSize::S128 => unreachable!(),
1538 };
1539 self.emit(Inst::External { inst });
1540 }
1541
1542 pub fn xmm_min_seq(&mut self, src: Reg, dst: WritableReg, size: OperandSize) {
1544 self.emit(Inst::XmmMinMaxSeq {
1545 size: size.into(),
1546 is_min: true,
1547 lhs: src.into(),
1548 rhs: dst.to_reg().into(),
1549 dst: dst.map(Into::into),
1550 });
1551 }
1552
1553 pub fn xmm_max_seq(&mut self, src: Reg, dst: WritableReg, size: OperandSize) {
1555 self.emit(Inst::XmmMinMaxSeq {
1556 size: size.into(),
1557 is_min: false,
1558 lhs: src.into(),
1559 rhs: dst.to_reg().into(),
1560 dst: dst.map(Into::into),
1561 });
1562 }
1563
1564 pub fn xmm_rounds_rr(
1567 &mut self,
1568 src: Reg,
1569 dst: WritableReg,
1570 mode: RoundingMode,
1571 size: OperandSize,
1572 ) {
1573 let dst = dst.map(|r| r.into());
1574
1575 let imm: u8 = match mode {
1576 RoundingMode::Nearest => 0x00,
1577 RoundingMode::Down => 0x01,
1578 RoundingMode::Up => 0x02,
1579 RoundingMode::Zero => 0x03,
1580 };
1581
1582 let inst = match size {
1583 OperandSize::S32 => asm::inst::roundss_rmi::new(dst, src, imm).into(),
1584 OperandSize::S64 => asm::inst::roundsd_rmi::new(dst, src, imm).into(),
1585 OperandSize::S8 | OperandSize::S16 | OperandSize::S128 => unreachable!(),
1586 };
1587
1588 self.emit(Inst::External { inst });
1589 }
1590
1591 pub fn sqrt(&mut self, src: Reg, dst: WritableReg, size: OperandSize) {
1592 use OperandSize::*;
1593 let dst = pair_xmm(dst);
1594 let inst = match size {
1595 S32 => asm::inst::sqrtss_a::new(dst, src).into(),
1596 S64 => asm::inst::sqrtsd_a::new(dst, src).into(),
1597 S8 | S16 | S128 => unimplemented!(),
1598 };
1599 self.emit(Inst::External { inst });
1600 }
1601
1602 pub fn call_with_reg(&mut self, cc: CallingConvention, callee: Reg) {
1604 self.emit(Inst::CallUnknown {
1605 info: Box::new(CallInfo::empty(RegMem::reg(callee.into()), cc.into())),
1606 });
1607 }
1608
1609 pub fn call_with_name(&mut self, cc: CallingConvention, name: UserExternalNameRef) {
1611 self.emit(Inst::CallKnown {
1612 info: Box::new(CallInfo::empty(ExternalName::user(name), cc.into())),
1613 });
1614 }
1615
1616 pub fn jmp_if(&mut self, cc: impl Into<CC>, taken: MachLabel) {
1618 self.emit(Inst::WinchJmpIf {
1619 cc: cc.into(),
1620 taken,
1621 });
1622 }
1623
1624 pub fn jmp(&mut self, target: MachLabel) {
1626 self.emit(Inst::JmpKnown { dst: target });
1627 }
1628
1629 pub fn jmp_table(
1631 &mut self,
1632 targets: SmallVec<[MachLabel; 4]>,
1633 default: MachLabel,
1634 index: Reg,
1635 tmp1: Reg,
1636 tmp2: Reg,
1637 ) {
1638 self.emit(Inst::JmpTableSeq {
1639 idx: index.into(),
1640 tmp1: Writable::from_reg(tmp1.into()),
1641 tmp2: Writable::from_reg(tmp2.into()),
1642 default_target: default,
1643 targets: Box::new(targets.to_vec()),
1644 })
1645 }
1646
1647 pub fn trap(&mut self, code: TrapCode) {
1649 let inst = asm::inst::ud2_zo::new(code).into();
1650 self.emit(Inst::External { inst });
1651 }
1652
1653 pub fn trapif(&mut self, cc: impl Into<CC>, trap_code: TrapCode) {
1655 self.emit(Inst::TrapIf {
1656 cc: cc.into(),
1657 trap_code,
1658 });
1659 }
1660
1661 pub fn lea(&mut self, addr: &Address, dst: WritableReg, size: OperandSize) {
1663 let addr = Self::to_synthetic_amode(addr, MemFlags::trusted());
1664 let dst: WritableGpr = dst.map(Into::into);
1665 let inst = match size {
1666 OperandSize::S16 => asm::inst::leaw_rm::new(dst, addr).into(),
1667 OperandSize::S32 => asm::inst::leal_rm::new(dst, addr).into(),
1668 OperandSize::S64 => asm::inst::leaq_rm::new(dst, addr).into(),
1669 OperandSize::S8 | OperandSize::S128 => unimplemented!(),
1670 };
1671 self.emit(Inst::External { inst });
1672 }
1673
1674 pub fn adc_rr(&mut self, src: Reg, dst: WritableReg, size: OperandSize) {
1675 let dst = pair_gpr(dst);
1676 let inst = match size {
1677 OperandSize::S8 => asm::inst::adcb_rm::new(dst, src).into(),
1678 OperandSize::S16 => asm::inst::adcw_rm::new(dst, src).into(),
1679 OperandSize::S32 => asm::inst::adcl_rm::new(dst, src).into(),
1680 OperandSize::S64 => asm::inst::adcq_rm::new(dst, src).into(),
1681 OperandSize::S128 => unimplemented!(),
1682 };
1683 self.emit(Inst::External { inst });
1684 }
1685
1686 pub fn sbb_rr(&mut self, src: Reg, dst: WritableReg, size: OperandSize) {
1687 let dst = pair_gpr(dst);
1688 let inst = match size {
1689 OperandSize::S8 => asm::inst::sbbb_rm::new(dst, src).into(),
1690 OperandSize::S16 => asm::inst::sbbw_rm::new(dst, src).into(),
1691 OperandSize::S32 => asm::inst::sbbl_rm::new(dst, src).into(),
1692 OperandSize::S64 => asm::inst::sbbq_rm::new(dst, src).into(),
1693 OperandSize::S128 => unimplemented!(),
1694 };
1695 self.emit(Inst::External { inst });
1696 }
1697
1698 pub fn mul_wide(
1699 &mut self,
1700 dst_lo: WritableReg,
1701 dst_hi: WritableReg,
1702 lhs: Reg,
1703 rhs: Reg,
1704 kind: MulWideKind,
1705 size: OperandSize,
1706 ) {
1707 use MulWideKind::*;
1708 use OperandSize::*;
1709 let rax = asm::Fixed(PairedGpr {
1710 read: lhs.into(),
1711 write: WritableGpr::from_reg(dst_lo.to_reg().into()),
1712 });
1713 let rdx = asm::Fixed(dst_hi.to_reg().into());
1714 if size == S8 {
1715 assert_eq!(dst_lo, dst_hi);
1718 }
1719 let inst = match (size, kind) {
1720 (S8, Unsigned) => asm::inst::mulb_m::new(rax, rhs).into(),
1721 (S8, Signed) => asm::inst::imulb_m::new(rax, rhs).into(),
1722 (S16, Unsigned) => asm::inst::mulw_m::new(rax, rdx, rhs).into(),
1723 (S16, Signed) => asm::inst::imulw_m::new(rax, rdx, rhs).into(),
1724 (S32, Unsigned) => asm::inst::mull_m::new(rax, rdx, rhs).into(),
1725 (S32, Signed) => asm::inst::imull_m::new(rax, rdx, rhs).into(),
1726 (S64, Unsigned) => asm::inst::mulq_m::new(rax, rdx, rhs).into(),
1727 (S64, Signed) => asm::inst::imulq_m::new(rax, rdx, rhs).into(),
1728 (S128, _) => unimplemented!(),
1729 };
1730 self.emit(Inst::External { inst });
1731 }
1732
1733 pub fn xmm_vpshufb_rrm(&mut self, dst: WritableReg, src: Reg, mask: &Address) {
1736 let dst: WritableXmm = dst.map(|r| r.into());
1737 let mask = Self::to_synthetic_amode(mask, MemFlags::trusted());
1738 let inst = asm::inst::vpshufb_b::new(dst, src, mask).into();
1739 self.emit(Inst::External { inst });
1740 }
1741
1742 pub fn xmm_vpshufb_rrr(&mut self, dst: WritableReg, src: Reg, mask: Reg) {
1745 let dst: WritableXmm = dst.map(|r| r.into());
1746 let inst = asm::inst::vpshufb_b::new(dst, src, mask).into();
1747 self.emit(Inst::External { inst });
1748 }
1749
1750 pub fn xmm_vpaddus_rrm(
1755 &mut self,
1756 dst: WritableReg,
1757 src1: Reg,
1758 src2: &Address,
1759 size: OperandSize,
1760 ) {
1761 let dst: WritableXmm = dst.map(|r| r.into());
1762 let src2 = Self::to_synthetic_amode(src2, MemFlags::trusted());
1763 let inst = match size {
1764 OperandSize::S8 => asm::inst::vpaddusb_b::new(dst, src1, src2).into(),
1765 OperandSize::S32 => asm::inst::vpaddusw_b::new(dst, src1, src2).into(),
1766 _ => unimplemented!(),
1767 };
1768 self.emit(Inst::External { inst });
1769 }
1770
1771 pub fn xmm_vpaddus_rrr(&mut self, dst: WritableReg, src1: Reg, src2: Reg, size: OperandSize) {
1776 let dst: WritableXmm = dst.map(|r| r.into());
1777 let inst = match size {
1778 OperandSize::S8 => asm::inst::vpaddusb_b::new(dst, src1, src2).into(),
1779 OperandSize::S16 => asm::inst::vpaddusw_b::new(dst, src1, src2).into(),
1780 _ => unimplemented!(),
1781 };
1782 self.emit(Inst::External { inst });
1783 }
1784
1785 pub fn xmm_vpadds_rrr(&mut self, dst: WritableReg, src1: Reg, src2: Reg, size: OperandSize) {
1787 let dst: WritableXmm = dst.map(|r| r.into());
1788 let inst = match size {
1789 OperandSize::S8 => asm::inst::vpaddsb_b::new(dst, src1, src2).into(),
1790 OperandSize::S16 => asm::inst::vpaddsw_b::new(dst, src1, src2).into(),
1791 _ => unimplemented!(),
1792 };
1793 self.emit(Inst::External { inst });
1794 }
1795
1796 pub fn xmm_vpadd_rmr(
1797 &mut self,
1798 src1: Reg,
1799 src2: &Address,
1800 dst: WritableReg,
1801 size: OperandSize,
1802 ) {
1803 let dst: WritableXmm = dst.map(|r| r.into());
1804 let address = Self::to_synthetic_amode(src2, MemFlags::trusted());
1805 let inst = match size {
1806 OperandSize::S8 => asm::inst::vpaddb_b::new(dst, src1, address).into(),
1807 OperandSize::S16 => asm::inst::vpaddw_b::new(dst, src1, address).into(),
1808 OperandSize::S32 => asm::inst::vpaddd_b::new(dst, src1, address).into(),
1809 _ => unimplemented!(),
1810 };
1811 self.emit(Inst::External { inst });
1812 }
1813
1814 pub fn xmm_vpadd_rrr(&mut self, src1: Reg, src2: Reg, dst: WritableReg, size: OperandSize) {
1817 let dst: WritableXmm = dst.map(|r| r.into());
1818 let inst = match size {
1819 OperandSize::S8 => asm::inst::vpaddb_b::new(dst, src1, src2).into(),
1820 OperandSize::S16 => asm::inst::vpaddw_b::new(dst, src1, src2).into(),
1821 OperandSize::S32 => asm::inst::vpaddd_b::new(dst, src1, src2).into(),
1822 OperandSize::S64 => asm::inst::vpaddq_b::new(dst, src1, src2).into(),
1823 _ => unimplemented!(),
1824 };
1825 self.emit(Inst::External { inst });
1826 }
1827
1828 pub fn mfence(&mut self) {
1829 self.emit(Inst::External {
1830 inst: asm::inst::mfence_zo::new().into(),
1831 });
1832 }
1833
1834 pub(crate) fn xmm_vpextr_rm(
1836 &mut self,
1837 addr: &Address,
1838 src: Reg,
1839 lane: u8,
1840 size: OperandSize,
1841 flags: MemFlags,
1842 ) {
1843 assert!(addr.is_offset());
1844 let dst = Self::to_synthetic_amode(addr, flags);
1845 let inst = match size {
1846 OperandSize::S8 => asm::inst::vpextrb_a::new(dst, src, lane).into(),
1847 OperandSize::S16 => asm::inst::vpextrw_b::new(dst, src, lane).into(),
1848 OperandSize::S32 => asm::inst::vpextrd_a::new(dst, src, lane).into(),
1849 OperandSize::S64 => asm::inst::vpextrq_a::new(dst, src, lane).into(),
1850 _ => unimplemented!(),
1851 };
1852 self.emit(Inst::External { inst });
1853 }
1854
1855 pub fn xmm_vpextr_rr(&mut self, dst: WritableReg, src: Reg, lane: u8, size: OperandSize) {
1857 let dst: WritableGpr = dst.map(|r| r.into());
1858 let inst = match size {
1859 OperandSize::S8 => asm::inst::vpextrb_a::new(dst, src, lane).into(),
1860 OperandSize::S16 => asm::inst::vpextrw_a::new(dst, src, lane).into(),
1861 OperandSize::S32 => asm::inst::vpextrd_a::new(dst, src, lane).into(),
1862 OperandSize::S64 => asm::inst::vpextrq_a::new(dst, src, lane).into(),
1863 _ => unimplemented!(),
1864 };
1865 self.emit(Inst::External { inst });
1866 }
1867
1868 pub fn xmm_vpinsr_rrm(
1871 &mut self,
1872 dst: WritableReg,
1873 src1: Reg,
1874 src2: &Address,
1875 count: u8,
1876 size: OperandSize,
1877 ) {
1878 let src2 = Self::to_synthetic_amode(src2, MemFlags::trusted());
1879 let dst: WritableXmm = dst.map(|r| r.into());
1880
1881 let inst = match size {
1882 OperandSize::S8 => asm::inst::vpinsrb_b::new(dst, src1, src2, count).into(),
1883 OperandSize::S16 => asm::inst::vpinsrw_b::new(dst, src1, src2, count).into(),
1884 OperandSize::S32 => asm::inst::vpinsrd_b::new(dst, src1, src2, count).into(),
1885 OperandSize::S64 => asm::inst::vpinsrq_b::new(dst, src1, src2, count).into(),
1886 OperandSize::S128 => unreachable!(),
1887 };
1888 self.emit(Inst::External { inst });
1889 }
1890
1891 pub fn xmm_vpinsr_rrr(
1894 &mut self,
1895 dst: WritableReg,
1896 src1: Reg,
1897 src2: Reg,
1898 count: u8,
1899 size: OperandSize,
1900 ) {
1901 let dst: WritableXmm = dst.map(|r| r.into());
1902 let inst = match size {
1903 OperandSize::S8 => asm::inst::vpinsrb_b::new(dst, src1, src2, count).into(),
1904 OperandSize::S16 => asm::inst::vpinsrw_b::new(dst, src1, src2, count).into(),
1905 OperandSize::S32 => asm::inst::vpinsrd_b::new(dst, src1, src2, count).into(),
1906 OperandSize::S64 => asm::inst::vpinsrq_b::new(dst, src1, src2, count).into(),
1907 OperandSize::S128 => unreachable!(),
1908 };
1909 self.emit(Inst::External { inst });
1910 }
1911
1912 pub fn xmm_vinsertps_rrm(&mut self, dst: WritableReg, src1: Reg, address: &Address, imm: u8) {
1914 let dst: WritableXmm = dst.map(|r| r.into());
1915 let address = Self::to_synthetic_amode(address, MemFlags::trusted());
1916 let inst = asm::inst::vinsertps_b::new(dst, src1, address, imm).into();
1917 self.emit(Inst::External { inst });
1918 }
1919
1920 pub fn xmm_vinsertps_rrr(&mut self, dst: WritableReg, src1: Reg, src2: Reg, imm: u8) {
1922 let dst: WritableXmm = dst.map(|r| r.into());
1923 let inst = asm::inst::vinsertps_b::new(dst, src1, src2, imm).into();
1924 self.emit(Inst::External { inst });
1925 }
1926
1927 pub fn xmm_vmovsd_rrr(&mut self, dst: WritableReg, src1: Reg, src2: Reg) {
1930 let dst: WritableXmm = dst.map(|r| r.into());
1931 let inst = asm::inst::vmovsd_b::new(dst, src1, src2).into();
1932 self.emit(Inst::External { inst });
1933 }
1934
1935 pub fn xmm_vmovsd_rm(&mut self, dst: WritableReg, src: &Address) {
1938 let src = Self::to_synthetic_amode(src, MemFlags::trusted());
1939 let dst: WritableXmm = dst.map(|r| r.into());
1940 let inst = asm::inst::vmovsd_d::new(dst, src).into();
1941 self.emit(Inst::External { inst });
1942 }
1943
1944 pub fn xmm_vmovlhps_rrm(&mut self, dst: WritableReg, src1: Reg, src2: &Address) {
1948 let src2 = Self::to_synthetic_amode(src2, MemFlags::trusted());
1949 let dst: WritableXmm = dst.map(|r| r.into());
1950 let inst = asm::inst::vmovhps_b::new(dst, src1, src2).into();
1951 self.emit(Inst::External { inst });
1952 }
1953
1954 pub fn xmm_vmovlhps_rrr(&mut self, dst: WritableReg, src1: Reg, src2: Reg) {
1958 let dst: WritableXmm = dst.map(|r| r.into());
1959 let inst = asm::inst::vmovlhps_rvm::new(dst, src1, src2).into();
1960 self.emit(Inst::External { inst });
1961 }
1962
1963 pub fn xmm_vmovdqu_mr(&mut self, src: &Address, dst: WritableReg, flags: MemFlags) {
1965 let src = Self::to_synthetic_amode(src, flags);
1966 let dst: WritableXmm = dst.map(|r| r.into());
1967 let inst = asm::inst::vmovdqu_a::new(dst, src).into();
1968 self.emit(Inst::External { inst });
1969 }
1970
1971 pub fn avx_gpr_to_xmm(&mut self, src: Reg, dst: WritableReg, size: OperandSize) {
1973 let dst: WritableXmm = dst.map(|r| r.into());
1974 let inst = match size {
1975 OperandSize::S32 => asm::inst::vmovd_a::new(dst, src).into(),
1976 OperandSize::S64 => asm::inst::vmovq_a::new(dst, src).into(),
1977 _ => unreachable!(),
1978 };
1979
1980 self.emit(Inst::External { inst });
1981 }
1982
1983 pub fn xmm_vptest(&mut self, src1: Reg, src2: Reg) {
1984 let inst = asm::inst::vptest_rm::new(src1, src2).into();
1985 self.emit(Inst::External { inst });
1986 }
1987
1988 pub fn xmm_vcvt_rr(&mut self, src: Reg, dst: WritableReg, kind: VcvtKind) {
1990 let dst: WritableXmm = dst.map(|x| x.into());
1991 let inst = match kind {
1992 VcvtKind::I32ToF32 => asm::inst::vcvtdq2ps_a::new(dst, src).into(),
1993 VcvtKind::I32ToF64 => asm::inst::vcvtdq2pd_a::new(dst, src).into(),
1994 VcvtKind::F64ToF32 => asm::inst::vcvtpd2ps_a::new(dst, src).into(),
1995 VcvtKind::F64ToI32 => asm::inst::vcvttpd2dq_a::new(dst, src).into(),
1996 VcvtKind::F32ToF64 => asm::inst::vcvtps2pd_a::new(dst, src).into(),
1997 VcvtKind::F32ToI32 => asm::inst::vcvttps2dq_a::new(dst, src).into(),
1998 };
1999 self.emit(Inst::External { inst });
2000 }
2001
2002 pub fn xmm_vsubp_rrr(&mut self, src1: Reg, src2: Reg, dst: WritableReg, size: OperandSize) {
2004 let dst: WritableXmm = dst.map(|r| r.into());
2005 let inst = match size {
2006 OperandSize::S32 => asm::inst::vsubps_b::new(dst, src1, src2).into(),
2007 OperandSize::S64 => asm::inst::vsubpd_b::new(dst, src1, src2).into(),
2008 _ => unimplemented!(),
2009 };
2010 self.emit(Inst::External { inst });
2011 }
2012
2013 pub fn xmm_vpsub_rrr(&mut self, src1: Reg, src2: Reg, dst: WritableReg, size: OperandSize) {
2015 let dst: WritableXmm = dst.map(|r| r.into());
2016 let inst = match size {
2017 OperandSize::S8 => asm::inst::vpsubb_b::new(dst, src1, src2).into(),
2018 OperandSize::S16 => asm::inst::vpsubw_b::new(dst, src1, src2).into(),
2019 OperandSize::S32 => asm::inst::vpsubd_b::new(dst, src1, src2).into(),
2020 OperandSize::S64 => asm::inst::vpsubq_b::new(dst, src1, src2).into(),
2021 _ => unimplemented!(),
2022 };
2023 self.emit(Inst::External { inst });
2024 }
2025
2026 pub fn xmm_vpsubus_rrr(&mut self, dst: WritableReg, src1: Reg, src2: Reg, size: OperandSize) {
2028 let dst: WritableXmm = dst.map(|r| r.into());
2029 let inst = match size {
2030 OperandSize::S8 => asm::inst::vpsubusb_b::new(dst, src1, src2).into(),
2031 OperandSize::S16 => asm::inst::vpsubusw_b::new(dst, src1, src2).into(),
2032 _ => unimplemented!(),
2033 };
2034 self.emit(Inst::External { inst });
2035 }
2036
2037 pub fn xmm_vpsubs_rrr(&mut self, dst: WritableReg, src1: Reg, src2: Reg, size: OperandSize) {
2039 let dst: WritableXmm = dst.map(|r| r.into());
2040 let inst = match size {
2041 OperandSize::S8 => asm::inst::vpsubsb_b::new(dst, src1, src2).into(),
2042 OperandSize::S16 => asm::inst::vpsubsw_b::new(dst, src1, src2).into(),
2043 _ => unimplemented!(),
2044 };
2045 self.emit(Inst::External { inst });
2046 }
2047
2048 pub fn xmm_vaddp_rrm(
2050 &mut self,
2051 src1: Reg,
2052 src2: &Address,
2053 dst: WritableReg,
2054 size: OperandSize,
2055 ) {
2056 let dst: WritableXmm = dst.map(|r| r.into());
2057 let address = Self::to_synthetic_amode(src2, MemFlags::trusted());
2058 let inst = match size {
2059 OperandSize::S32 => asm::inst::vaddps_b::new(dst, src1, address).into(),
2060 OperandSize::S64 => asm::inst::vaddpd_b::new(dst, src1, address).into(),
2061 _ => unimplemented!(),
2062 };
2063 self.emit(Inst::External { inst });
2064 }
2065
2066 pub fn xmm_vaddp_rrr(&mut self, src1: Reg, src2: Reg, dst: WritableReg, size: OperandSize) {
2068 let dst: WritableXmm = dst.map(|r| r.into());
2069 let inst = match size {
2070 OperandSize::S32 => asm::inst::vaddps_b::new(dst, src1, src2).into(),
2071 OperandSize::S64 => asm::inst::vaddpd_b::new(dst, src1, src2).into(),
2072 _ => unimplemented!(),
2073 };
2074 self.emit(Inst::External { inst });
2075 }
2076
2077 pub fn xmm_vpcmpeq_rrm(
2081 &mut self,
2082 dst: WritableReg,
2083 lhs: Reg,
2084 address: &Address,
2085 size: OperandSize,
2086 ) {
2087 let dst: WritableXmm = dst.map(|r| r.into());
2088 let address = Self::to_synthetic_amode(address, MemFlags::trusted());
2089 let inst = match size {
2090 OperandSize::S8 => asm::inst::vpcmpeqb_b::new(dst, lhs, address).into(),
2091 OperandSize::S16 => asm::inst::vpcmpeqw_b::new(dst, lhs, address).into(),
2092 OperandSize::S32 => asm::inst::vpcmpeqd_b::new(dst, lhs, address).into(),
2093 OperandSize::S64 => asm::inst::vpcmpeqq_b::new(dst, lhs, address).into(),
2094 _ => unimplemented!(),
2095 };
2096 self.emit(Inst::External { inst });
2097 }
2098
2099 pub fn xmm_vpcmpeq_rrr(&mut self, dst: WritableReg, lhs: Reg, rhs: Reg, size: OperandSize) {
2102 let dst: WritableXmm = dst.map(|r| r.into());
2103 let inst = match size {
2104 OperandSize::S8 => asm::inst::vpcmpeqb_b::new(dst, lhs, rhs).into(),
2105 OperandSize::S16 => asm::inst::vpcmpeqw_b::new(dst, lhs, rhs).into(),
2106 OperandSize::S32 => asm::inst::vpcmpeqd_b::new(dst, lhs, rhs).into(),
2107 OperandSize::S64 => asm::inst::vpcmpeqq_b::new(dst, lhs, rhs).into(),
2108 _ => unimplemented!(),
2109 };
2110 self.emit(Inst::External { inst });
2111 }
2112
2113 pub fn xmm_vpcmpgt_rrr(&mut self, dst: WritableReg, lhs: Reg, rhs: Reg, size: OperandSize) {
2116 let dst: WritableXmm = dst.map(|r| r.into());
2117 let inst = match size {
2118 OperandSize::S8 => asm::inst::vpcmpgtb_b::new(dst, lhs, rhs).into(),
2119 OperandSize::S16 => asm::inst::vpcmpgtw_b::new(dst, lhs, rhs).into(),
2120 OperandSize::S32 => asm::inst::vpcmpgtd_b::new(dst, lhs, rhs).into(),
2121 OperandSize::S64 => asm::inst::vpcmpgtq_b::new(dst, lhs, rhs).into(),
2122 _ => unimplemented!(),
2123 };
2124 self.emit(Inst::External { inst });
2125 }
2126
2127 pub fn xmm_vpmaxs_rrr(&mut self, dst: WritableReg, lhs: Reg, rhs: Reg, size: OperandSize) {
2130 let dst: WritableXmm = dst.map(|r| r.into());
2131 let inst = match size {
2132 OperandSize::S8 => asm::inst::vpmaxsb_b::new(dst, lhs, rhs).into(),
2133 OperandSize::S16 => asm::inst::vpmaxsw_b::new(dst, lhs, rhs).into(),
2134 OperandSize::S32 => asm::inst::vpmaxsd_b::new(dst, lhs, rhs).into(),
2135 _ => unimplemented!(),
2136 };
2137 self.emit(Inst::External { inst });
2138 }
2139
2140 pub fn xmm_vpmaxu_rrr(&mut self, dst: WritableReg, lhs: Reg, rhs: Reg, size: OperandSize) {
2143 let dst: WritableXmm = dst.map(|r| r.into());
2144 let inst = match size {
2145 OperandSize::S8 => asm::inst::vpmaxub_b::new(dst, lhs, rhs).into(),
2146 OperandSize::S16 => asm::inst::vpmaxuw_b::new(dst, lhs, rhs).into(),
2147 OperandSize::S32 => asm::inst::vpmaxud_b::new(dst, lhs, rhs).into(),
2148 _ => unimplemented!(),
2149 };
2150 self.emit(Inst::External { inst });
2151 }
2152
2153 pub fn xmm_vpmins_rrr(&mut self, dst: WritableReg, lhs: Reg, rhs: Reg, size: OperandSize) {
2156 let dst: WritableXmm = dst.map(|r| r.into());
2157 let inst = match size {
2158 OperandSize::S8 => asm::inst::vpminsb_b::new(dst, lhs, rhs).into(),
2159 OperandSize::S16 => asm::inst::vpminsw_b::new(dst, lhs, rhs).into(),
2160 OperandSize::S32 => asm::inst::vpminsd_b::new(dst, lhs, rhs).into(),
2161 _ => unimplemented!(),
2162 };
2163 self.emit(Inst::External { inst });
2164 }
2165
2166 pub fn xmm_vpminu_rrr(&mut self, dst: WritableReg, lhs: Reg, rhs: Reg, size: OperandSize) {
2169 let dst: WritableXmm = dst.map(|r| r.into());
2170 let inst = match size {
2171 OperandSize::S8 => asm::inst::vpminub_b::new(dst, lhs, rhs).into(),
2172 OperandSize::S16 => asm::inst::vpminuw_b::new(dst, lhs, rhs).into(),
2173 OperandSize::S32 => asm::inst::vpminud_b::new(dst, lhs, rhs).into(),
2174 _ => unimplemented!(),
2175 };
2176 self.emit(Inst::External { inst });
2177 }
2178
2179 pub fn xmm_vcmpp_rrr(
2182 &mut self,
2183 dst: WritableReg,
2184 lhs: Reg,
2185 rhs: Reg,
2186 size: OperandSize,
2187 kind: VcmpKind,
2188 ) {
2189 let dst: WritableXmm = dst.map(|r| r.into());
2190 let imm = match kind {
2191 VcmpKind::Eq => 0,
2192 VcmpKind::Lt => 1,
2193 VcmpKind::Le => 2,
2194 VcmpKind::Unord => 3,
2195 VcmpKind::Ne => 4,
2196 };
2197 let inst = match size {
2198 OperandSize::S32 => asm::inst::vcmpps_b::new(dst, lhs, rhs, imm).into(),
2199 OperandSize::S64 => asm::inst::vcmppd_b::new(dst, lhs, rhs, imm).into(),
2200 _ => unimplemented!(),
2201 };
2202 self.emit(Inst::External { inst });
2203 }
2204
2205 pub fn xmm_vsub_rrm(&mut self, src1: Reg, src2: &Address, dst: WritableReg, size: OperandSize) {
2208 let dst: WritableXmm = dst.map(|r| r.into());
2209 let address = Self::to_synthetic_amode(src2, MemFlags::trusted());
2210 let inst = match size {
2211 OperandSize::S64 => asm::inst::vsubpd_b::new(dst, src1, address).into(),
2212 _ => unimplemented!(),
2213 };
2214 self.emit(Inst::External { inst });
2215 }
2216
2217 pub fn xmm_vsub_rrr(&mut self, src1: Reg, src2: Reg, dst: WritableReg, size: OperandSize) {
2220 let dst: WritableXmm = dst.map(|r| r.into());
2221 let inst = match size {
2222 OperandSize::S32 => asm::inst::vsubps_b::new(dst, src1, src2).into(),
2223 OperandSize::S64 => asm::inst::vsubpd_b::new(dst, src1, src2).into(),
2224 _ => unimplemented!(),
2225 };
2226 self.emit(Inst::External { inst });
2227 }
2228
2229 pub fn xmm_vpackss_rrr(&mut self, src1: Reg, src2: Reg, dst: WritableReg, size: OperandSize) {
2232 let dst: WritableXmm = dst.map(|r| r.into());
2233 let inst = match size {
2234 OperandSize::S8 => asm::inst::vpacksswb_b::new(dst, src1, src2).into(),
2235 OperandSize::S16 => asm::inst::vpackssdw_b::new(dst, src1, src2).into(),
2236 _ => unimplemented!(),
2237 };
2238 self.emit(Inst::External { inst });
2239 }
2240
2241 pub fn xmm_vpackus_rrr(&mut self, src1: Reg, src2: Reg, dst: WritableReg, size: OperandSize) {
2244 let dst: WritableXmm = dst.map(|r| r.into());
2245 let inst = match size {
2246 OperandSize::S8 => asm::inst::vpackuswb_b::new(dst, src1, src2).into(),
2247 OperandSize::S16 => asm::inst::vpackusdw_b::new(dst, src1, src2).into(),
2248 _ => unimplemented!(),
2249 };
2250 self.emit(Inst::External { inst });
2251 }
2252
2253 pub fn xmm_vpalignr_rrr(&mut self, src1: Reg, src2: Reg, dst: WritableReg, imm: u8) {
2256 let dst: WritableXmm = dst.map(|r| r.into());
2257 let inst = asm::inst::vpalignr_b::new(dst, src1, src2, imm).into();
2258 self.emit(Inst::External { inst });
2259 }
2260
2261 pub fn xmm_vunpcklp_rrm(
2264 &mut self,
2265 src1: Reg,
2266 src2: &Address,
2267 dst: WritableReg,
2268 size: OperandSize,
2269 ) {
2270 let dst: WritableXmm = dst.map(|r| r.into());
2271 let address = Self::to_synthetic_amode(src2, MemFlags::trusted());
2272 let inst = match size {
2273 OperandSize::S32 => asm::inst::vunpcklps_b::new(dst, src1, address).into(),
2274 _ => unimplemented!(),
2275 };
2276 self.emit(Inst::External { inst });
2277 }
2278
2279 pub fn xmm_vunpckhp_rrr(&mut self, src1: Reg, src2: Reg, dst: WritableReg, size: OperandSize) {
2282 let dst: WritableXmm = dst.map(|r| r.into());
2283 let inst = match size {
2284 OperandSize::S32 => asm::inst::vunpckhps_b::new(dst, src1, src2).into(),
2285 _ => unimplemented!(),
2286 };
2287 self.emit(Inst::External { inst });
2288 }
2289
2290 pub fn xmm_vpunpckl_rrr(&mut self, src1: Reg, src2: Reg, dst: WritableReg, size: OperandSize) {
2293 let dst: WritableXmm = dst.map(|r| r.into());
2294 let inst = match size {
2295 OperandSize::S8 => asm::inst::vpunpcklbw_b::new(dst, src1, src2).into(),
2296 OperandSize::S16 => asm::inst::vpunpcklwd_b::new(dst, src1, src2).into(),
2297 _ => unimplemented!(),
2298 };
2299 self.emit(Inst::External { inst });
2300 }
2301
2302 pub fn xmm_vpunpckh_rrr(&mut self, src1: Reg, src2: Reg, dst: WritableReg, size: OperandSize) {
2305 let dst: WritableXmm = dst.map(|r| r.into());
2306 let inst = match size {
2307 OperandSize::S8 => asm::inst::vpunpckhbw_b::new(dst, src1, src2).into(),
2308 OperandSize::S16 => asm::inst::vpunpckhwd_b::new(dst, src1, src2).into(),
2309 _ => unimplemented!(),
2310 };
2311 self.emit(Inst::External { inst });
2312 }
2313
2314 pub(crate) fn xmm_rm_rvex3(
2315 &mut self,
2316 op: Avx512Opcode,
2317 src1: Reg,
2318 src2: Reg,
2319 dst: WritableReg,
2320 ) {
2321 self.emit(Inst::XmmRmREvex3 {
2322 op,
2323 src1: dst.to_reg().into(),
2325 src2: src1.into(),
2326 src3: src2.into(),
2327 dst: dst.map(Into::into),
2328 });
2329 }
2330
2331 pub fn xmm_vpmovmsk_rr(
2334 &mut self,
2335 src: Reg,
2336 dst: WritableReg,
2337 src_size: OperandSize,
2338 dst_size: OperandSize,
2339 ) {
2340 assert_eq!(dst_size, OperandSize::S32);
2341 let dst: WritableGpr = dst.map(|r| r.into());
2342 let inst = match src_size {
2343 OperandSize::S8 => asm::inst::vpmovmskb_rm::new(dst, src).into(),
2344 _ => unimplemented!(),
2345 };
2346
2347 self.emit(Inst::External { inst });
2348 }
2349
2350 pub fn xmm_vmovskp_rr(
2353 &mut self,
2354 src: Reg,
2355 dst: WritableReg,
2356 src_size: OperandSize,
2357 dst_size: OperandSize,
2358 ) {
2359 assert_eq!(dst_size, OperandSize::S32);
2360 let dst: WritableGpr = dst.map(|r| r.into());
2361 let inst = match src_size {
2362 OperandSize::S32 => asm::inst::vmovmskps_rm::new(dst, src).into(),
2363 OperandSize::S64 => asm::inst::vmovmskpd_rm::new(dst, src).into(),
2364 _ => unimplemented!(),
2365 };
2366
2367 self.emit(Inst::External { inst });
2368 }
2369
2370 pub fn xmm_vpabs_rr(&mut self, src: Reg, dst: WritableReg, size: OperandSize) {
2373 let dst: WritableXmm = dst.map(|r| r.into());
2374 let inst = match size {
2375 OperandSize::S8 => asm::inst::vpabsb_a::new(dst, src).into(),
2376 OperandSize::S16 => asm::inst::vpabsw_a::new(dst, src).into(),
2377 OperandSize::S32 => asm::inst::vpabsd_a::new(dst, src).into(),
2378 _ => unimplemented!(),
2379 };
2380 self.emit(Inst::External { inst });
2381 }
2382
2383 pub fn xmm_vpsra_rrr(&mut self, src: Reg, amount: Reg, dst: WritableReg, size: OperandSize) {
2386 let dst: WritableXmm = dst.map(|r| r.into());
2387 let inst = match size {
2388 OperandSize::S16 => asm::inst::vpsraw_c::new(dst, src, amount).into(),
2389 OperandSize::S32 => asm::inst::vpsrad_c::new(dst, src, amount).into(),
2390 _ => unimplemented!(),
2391 };
2392 self.emit(Inst::External { inst });
2393 }
2394
2395 pub fn xmm_vpsra_rri(&mut self, src: Reg, dst: WritableReg, imm: u32, size: OperandSize) {
2398 let dst: WritableXmm = dst.map(|r| r.into());
2399 let imm = u8::try_from(imm).expect("immediate must fit in 8 bits");
2400 let inst = match size {
2401 OperandSize::S32 => asm::inst::vpsrad_d::new(dst, src, imm).into(),
2402 _ => unimplemented!(),
2403 };
2404 self.emit(Inst::External { inst });
2405 }
2406
2407 pub fn xmm_vpsll_rri(&mut self, src: Reg, dst: WritableReg, imm: u32, size: OperandSize) {
2409 let dst: WritableXmm = dst.map(|r| r.into());
2410 let imm = u8::try_from(imm).expect("immediate must fit in 8 bits");
2411 let inst = match size {
2412 OperandSize::S32 => asm::inst::vpslld_d::new(dst, src, imm).into(),
2413 OperandSize::S64 => asm::inst::vpsllq_d::new(dst, src, imm).into(),
2414 _ => unimplemented!(),
2415 };
2416 self.emit(Inst::External { inst });
2417 }
2418
2419 pub fn xmm_vpsll_rrr(&mut self, src: Reg, amount: Reg, dst: WritableReg, size: OperandSize) {
2421 let dst: WritableXmm = dst.map(|r| r.into());
2422 let inst = match size {
2423 OperandSize::S16 => asm::inst::vpsllw_c::new(dst, src, amount).into(),
2424 OperandSize::S32 => asm::inst::vpslld_c::new(dst, src, amount).into(),
2425 OperandSize::S64 => asm::inst::vpsllq_c::new(dst, src, amount).into(),
2426 _ => unimplemented!(),
2427 };
2428 self.emit(Inst::External { inst });
2429 }
2430
2431 pub fn xmm_vpsrl_rri(&mut self, src: Reg, dst: WritableReg, imm: u32, size: OperandSize) {
2433 let dst: WritableXmm = dst.map(|r| r.into());
2434 let imm = u8::try_from(imm).expect("immediate must fit in 8 bits");
2435 let inst = match size {
2436 OperandSize::S16 => asm::inst::vpsrlw_d::new(dst, src, imm).into(),
2437 OperandSize::S32 => asm::inst::vpsrld_d::new(dst, src, imm).into(),
2438 OperandSize::S64 => asm::inst::vpsrlq_d::new(dst, src, imm).into(),
2439 _ => unimplemented!(),
2440 };
2441 self.emit(Inst::External { inst });
2442 }
2443
2444 pub fn xmm_vpsrl_rrr(&mut self, src: Reg, amount: Reg, dst: WritableReg, size: OperandSize) {
2446 let dst: WritableXmm = dst.map(|r| r.into());
2447 let inst = match size {
2448 OperandSize::S16 => asm::inst::vpsrlw_c::new(dst, src, amount).into(),
2449 OperandSize::S32 => asm::inst::vpsrld_c::new(dst, src, amount).into(),
2450 OperandSize::S64 => asm::inst::vpsrlq_c::new(dst, src, amount).into(),
2451 _ => unimplemented!(),
2452 };
2453 self.emit(Inst::External { inst });
2454 }
2455
2456 pub fn xmm_vandp_rrm(
2459 &mut self,
2460 src1: Reg,
2461 src2: &Address,
2462 dst: WritableReg,
2463 size: OperandSize,
2464 ) {
2465 let dst: WritableXmm = dst.map(|r| r.into());
2466 let address = Self::to_synthetic_amode(src2, MemFlags::trusted());
2467 let inst = match size {
2468 OperandSize::S32 => asm::inst::vandps_b::new(dst, src1, address).into(),
2469 OperandSize::S64 => asm::inst::vandpd_b::new(dst, src1, address).into(),
2470 _ => unimplemented!(),
2471 };
2472 self.emit(Inst::External { inst });
2473 }
2474
2475 pub fn xmm_vandp_rrr(&mut self, src1: Reg, src2: Reg, dst: WritableReg, size: OperandSize) {
2478 let dst: WritableXmm = dst.map(|r| r.into());
2479 let inst = match size {
2480 OperandSize::S32 => asm::inst::vandps_b::new(dst, src1, src2).into(),
2481 OperandSize::S64 => asm::inst::vandpd_b::new(dst, src1, src2).into(),
2482 _ => unimplemented!(),
2483 };
2484 self.emit(Inst::External { inst });
2485 }
2486
2487 pub fn xmm_vpand_rrm(&mut self, src1: Reg, src2: &Address, dst: WritableReg) {
2490 let dst: WritableXmm = dst.map(|r| r.into());
2491 let address = Self::to_synthetic_amode(&src2, MemFlags::trusted());
2492 let inst = asm::inst::vpand_b::new(dst, src1, address).into();
2493 self.emit(Inst::External { inst });
2494 }
2495
2496 pub fn xmm_vpand_rrr(&mut self, src1: Reg, src2: Reg, dst: WritableReg) {
2499 let dst: WritableXmm = dst.map(|r| r.into());
2500 let inst = asm::inst::vpand_b::new(dst, src1, src2).into();
2501 self.emit(Inst::External { inst });
2502 }
2503
2504 pub fn xmm_vandnp_rrr(&mut self, src1: Reg, src2: Reg, dst: WritableReg, size: OperandSize) {
2507 let dst: WritableXmm = dst.map(|r| r.into());
2508 let inst = match size {
2509 OperandSize::S32 => asm::inst::vandnps_b::new(dst, src1, src2).into(),
2510 OperandSize::S64 => asm::inst::vandnpd_b::new(dst, src1, src2).into(),
2511 _ => unimplemented!(),
2512 };
2513 self.emit(Inst::External { inst });
2514 }
2515
2516 pub fn xmm_vpandn_rrr(&mut self, src1: Reg, src2: Reg, dst: WritableReg) {
2519 let dst: WritableXmm = dst.map(|r| r.into());
2520 let inst = asm::inst::vpandn_b::new(dst, src1, src2).into();
2521 self.emit(Inst::External { inst });
2522 }
2523
2524 pub fn xmm_vorp_rrr(&mut self, src1: Reg, src2: Reg, dst: WritableReg, size: OperandSize) {
2527 let dst: WritableXmm = dst.map(|r| r.into());
2528 let inst = match size {
2529 OperandSize::S32 => asm::inst::vorps_b::new(dst, src1, src2).into(),
2530 OperandSize::S64 => asm::inst::vorpd_b::new(dst, src1, src2).into(),
2531 _ => unimplemented!(),
2532 };
2533 self.emit(Inst::External { inst });
2534 }
2535
2536 pub fn xmm_vpor_rrr(&mut self, dst: WritableReg, src1: Reg, src2: Reg) {
2538 let dst: WritableXmm = dst.map(|r| r.into());
2539 let inst = asm::inst::vpor_b::new(dst, src1, src2).into();
2540 self.emit(Inst::External { inst });
2541 }
2542
2543 pub fn xmm_vxorp_rrr(&mut self, src1: Reg, src2: Reg, dst: WritableReg, size: OperandSize) {
2546 let dst: WritableXmm = dst.map(|r| r.into());
2547 let inst = match size {
2548 OperandSize::S32 => asm::inst::vxorps_b::new(dst, src1, src2).into(),
2549 OperandSize::S64 => asm::inst::vxorpd_b::new(dst, src1, src2).into(),
2550 _ => unimplemented!(),
2551 };
2552 self.emit(Inst::External { inst });
2553 }
2554
2555 pub fn xmm_vpxor_rmr(&mut self, src: Reg, address: &Address, dst: WritableReg) {
2558 let dst: WritableXmm = dst.map(|r| r.into());
2559 let address = Self::to_synthetic_amode(address, MemFlags::trusted());
2560 let inst = asm::inst::vpxor_b::new(dst, src, address).into();
2561 self.emit(Inst::External { inst });
2562 }
2563
2564 pub fn xmm_vpxor_rrr(&mut self, src1: Reg, src2: Reg, dst: WritableReg) {
2567 let dst: WritableXmm = dst.map(|r| r.into());
2568 let inst = asm::inst::vpxor_b::new(dst, src1, src2).into();
2569 self.emit(Inst::External { inst });
2570 }
2571
2572 pub fn xmm_vmaxp_rrr(&mut self, src1: Reg, src2: Reg, dst: WritableReg, size: OperandSize) {
2575 let dst: WritableXmm = dst.map(|r| r.into());
2576 let inst = match size {
2577 OperandSize::S32 => asm::inst::vmaxps_b::new(dst, src1, src2).into(),
2578 OperandSize::S64 => asm::inst::vmaxpd_b::new(dst, src1, src2).into(),
2579 _ => unimplemented!(),
2580 };
2581 self.emit(Inst::External { inst });
2582 }
2583
2584 pub fn xmm_vminp_rrm(
2587 &mut self,
2588 src1: Reg,
2589 src2: &Address,
2590 dst: WritableReg,
2591 size: OperandSize,
2592 ) {
2593 let dst: WritableXmm = dst.map(|r| r.into());
2594 let address = Self::to_synthetic_amode(src2, MemFlags::trusted());
2595 let inst = match size {
2596 OperandSize::S32 => asm::inst::vminps_b::new(dst, src1, address).into(),
2597 OperandSize::S64 => asm::inst::vminpd_b::new(dst, src1, address).into(),
2598 _ => unimplemented!(),
2599 };
2600 self.emit(Inst::External { inst });
2601 }
2602
2603 pub fn xmm_vminp_rrr(&mut self, src1: Reg, src2: Reg, dst: WritableReg, size: OperandSize) {
2606 let dst: WritableXmm = dst.map(|r| r.into());
2607 let inst = match size {
2608 OperandSize::S32 => asm::inst::vminps_b::new(dst, src1, src2).into(),
2609 OperandSize::S64 => asm::inst::vminpd_b::new(dst, src1, src2).into(),
2610 _ => unimplemented!(),
2611 };
2612 self.emit(Inst::External { inst });
2613 }
2614
2615 pub fn xmm_vroundp_rri(
2617 &mut self,
2618 src: Reg,
2619 dst: WritableReg,
2620 mode: VroundMode,
2621 size: OperandSize,
2622 ) {
2623 let dst: WritableXmm = dst.map(|r| r.into());
2624 let imm = match mode {
2625 VroundMode::TowardNearest => 0,
2626 VroundMode::TowardNegativeInfinity => 1,
2627 VroundMode::TowardPositiveInfinity => 2,
2628 VroundMode::TowardZero => 3,
2629 };
2630
2631 let inst = match size {
2632 OperandSize::S32 => asm::inst::vroundps_rmi::new(dst, src, imm).into(),
2633 OperandSize::S64 => asm::inst::vroundpd_rmi::new(dst, src, imm).into(),
2634 _ => unimplemented!(),
2635 };
2636
2637 self.emit(Inst::External { inst });
2638 }
2639
2640 pub fn xmm_vshufp_rrri(
2642 &mut self,
2643 src1: Reg,
2644 src2: Reg,
2645 dst: WritableReg,
2646 imm: u8,
2647 size: OperandSize,
2648 ) {
2649 let dst: WritableXmm = dst.map(|r| r.into());
2650 let inst = match size {
2651 OperandSize::S32 => asm::inst::vshufps_b::new(dst, src1, src2, imm).into(),
2652 _ => unimplemented!(),
2653 };
2654 self.emit(Inst::External { inst });
2655 }
2656
2657 pub fn xmm_vpmulhrs_rrr(&mut self, src1: Reg, src2: Reg, dst: WritableReg, size: OperandSize) {
2664 let dst: WritableXmm = dst.map(|r| r.into());
2665 let inst = match size {
2666 OperandSize::S16 => asm::inst::vpmulhrsw_b::new(dst, src1, src2).into(),
2667 _ => unimplemented!(),
2668 };
2669 self.emit(Inst::External { inst });
2670 }
2671
2672 pub fn xmm_vpmuldq_rrr(&mut self, src1: Reg, src2: Reg, dst: WritableReg) {
2673 let dst: WritableXmm = dst.map(|r| r.into());
2674 let inst = asm::inst::vpmuldq_b::new(dst, src1, src2).into();
2675 self.emit(Inst::External { inst });
2676 }
2677
2678 pub fn xmm_vpmuludq_rrr(&mut self, src1: Reg, src2: Reg, dst: WritableReg) {
2679 let dst: WritableXmm = dst.map(|r| r.into());
2680 let inst = asm::inst::vpmuludq_b::new(dst, src1, src2).into();
2681 self.emit(Inst::External { inst });
2682 }
2683
2684 pub fn xmm_vpmull_rrr(&mut self, src1: Reg, src2: Reg, dst: WritableReg, size: OperandSize) {
2685 let dst: WritableXmm = dst.map(|r| r.into());
2686 let inst = match size {
2687 OperandSize::S16 => asm::inst::vpmullw_b::new(dst, src1, src2).into(),
2688 OperandSize::S32 => asm::inst::vpmulld_b::new(dst, src1, src2).into(),
2689 _ => unimplemented!(),
2690 };
2691 self.emit(Inst::External { inst });
2692 }
2693
2694 pub fn xmm_vmulp_rrr(&mut self, src1: Reg, src2: Reg, dst: WritableReg, size: OperandSize) {
2695 let dst: WritableXmm = dst.map(|r| r.into());
2696 let inst = match size {
2697 OperandSize::S32 => asm::inst::vmulps_b::new(dst, src1, src2).into(),
2698 OperandSize::S64 => asm::inst::vmulpd_b::new(dst, src1, src2).into(),
2699 _ => unimplemented!(),
2700 };
2701 self.emit(Inst::External { inst });
2702 }
2703
2704 pub fn xmm_vpavg_rrr(&mut self, src1: Reg, src2: Reg, dst: WritableReg, size: OperandSize) {
2707 let dst: WritableXmm = dst.map(|r| r.into());
2708 let inst = match size {
2709 OperandSize::S8 => asm::inst::vpavgb_b::new(dst, src1, src2).into(),
2710 OperandSize::S16 => asm::inst::vpavgw_b::new(dst, src1, src2).into(),
2711 _ => unimplemented!(),
2712 };
2713 self.emit(Inst::External { inst });
2714 }
2715
2716 pub fn xmm_vdivp_rrr(&mut self, src1: Reg, src2: Reg, dst: WritableReg, size: OperandSize) {
2719 let dst: WritableXmm = dst.map(|r| r.into());
2720 let inst = match size {
2721 OperandSize::S32 => asm::inst::vdivps_b::new(dst, src1, src2).into(),
2722 OperandSize::S64 => asm::inst::vdivpd_b::new(dst, src1, src2).into(),
2723 _ => unimplemented!(),
2724 };
2725 self.emit(Inst::External { inst });
2726 }
2727
2728 pub fn xmm_vsqrtp_rr(&mut self, src: Reg, dst: WritableReg, size: OperandSize) {
2731 let dst: WritableXmm = dst.map(|r| r.into());
2732 let inst = match size {
2733 OperandSize::S32 => asm::inst::vsqrtps_b::new(dst, src).into(),
2734 OperandSize::S64 => asm::inst::vsqrtpd_b::new(dst, src).into(),
2735 _ => unimplemented!(),
2736 };
2737 self.emit(Inst::External { inst });
2738 }
2739
2740 pub fn xmm_vpmaddubsw_rmr(&mut self, src: Reg, address: &Address, dst: WritableReg) {
2742 let dst: WritableXmm = dst.map(|r| r.into());
2743 let address = Self::to_synthetic_amode(address, MemFlags::trusted());
2744 let inst = asm::inst::vpmaddubsw_b::new(dst, src, address).into();
2745 self.emit(Inst::External { inst });
2746 }
2747
2748 pub fn xmm_vpmaddubsw_rrr(&mut self, src1: Reg, src2: Reg, dst: WritableReg) {
2750 let dst: WritableXmm = dst.map(|r| r.into());
2751 let inst = asm::inst::vpmaddubsw_b::new(dst, src1, src2).into();
2752 self.emit(Inst::External { inst });
2753 }
2754
2755 pub fn xmm_vpmaddwd_rmr(&mut self, src: Reg, address: &Address, dst: WritableReg) {
2757 let dst: WritableXmm = dst.map(|r| r.into());
2758 let address = Self::to_synthetic_amode(address, MemFlags::trusted());
2759 let inst = asm::inst::vpmaddwd_b::new(dst, src, address).into();
2760 self.emit(Inst::External { inst });
2761 }
2762
2763 pub fn xmm_vpmaddwd_rrr(&mut self, src1: Reg, src2: Reg, dst: WritableReg) {
2765 let dst: WritableXmm = dst.map(|r| r.into());
2766 let inst = asm::inst::vpmaddwd_b::new(dst, src1, src2).into();
2767 self.emit(Inst::External { inst });
2768 }
2769}
2770
2771pub(crate) struct PatchableAddToReg {
2775 region: PatchRegion,
2778
2779 constant_offset: usize,
2781}
2782
2783impl PatchableAddToReg {
2784 pub(crate) fn new(reg: Reg, size: OperandSize, asm: &mut Assembler) -> Self {
2791 let open = asm.buffer_mut().start_patchable();
2792 let start = asm.buffer().cur_offset();
2793
2794 let reg = pair_gpr(Writable::from_reg(reg));
2796 let inst = match size {
2797 OperandSize::S32 => asm::inst::addl_mi::new(reg, 0_u32).into(),
2798 OperandSize::S64 => asm::inst::addq_mi_sxl::new(reg, 0_i32).into(),
2799 _ => {
2800 panic!(
2801 "{}-bit addition is not supported, please see the comment on PatchableAddToReg::new",
2802 size.num_bits(),
2803 )
2804 }
2805 };
2806 asm.emit(Inst::External { inst });
2807
2808 let constant_offset = usize::try_from(asm.buffer().cur_offset() - start - 4).unwrap();
2811
2812 let region = asm.buffer_mut().end_patchable(open);
2813
2814 Self {
2815 region,
2816 constant_offset,
2817 }
2818 }
2819
2820 pub(crate) fn finalize(self, val: i32, buffer: &mut MachBuffer<Inst>) {
2824 let slice = self.region.patch(buffer);
2825 debug_assert_eq!(slice.len(), self.constant_offset + 4);
2826 slice[self.constant_offset..].copy_from_slice(val.to_le_bytes().as_slice());
2827 }
2828}