1pub use emit_state::EmitState;
4
5use crate::binemit::{Addend, CodeOffset, Reloc};
6use crate::ir::{types, ExternalName, LibCall, TrapCode, Type};
7use crate::isa::x64::abi::X64ABIMachineSpec;
8use crate::isa::x64::inst::regs::{pretty_print_reg, show_ireg_sized};
9use crate::isa::x64::settings as x64_settings;
10use crate::isa::{CallConv, FunctionAlignment};
11use crate::{machinst::*, trace};
12use crate::{settings, CodegenError, CodegenResult};
13use alloc::boxed::Box;
14use alloc::vec::Vec;
15use core::slice;
16use cranelift_assembler_x64 as asm;
17use smallvec::{smallvec, SmallVec};
18use std::fmt::{self, Write};
19use std::string::{String, ToString};
20
21pub mod args;
22mod emit;
23mod emit_state;
24#[cfg(test)]
25mod emit_tests;
26pub mod external;
27pub mod regs;
28mod stack_switch;
29pub mod unwind;
30
31use args::*;
32
33pub use super::lower::isle::generated_code::AtomicRmwSeqOp;
38pub use super::lower::isle::generated_code::MInst as Inst;
39
40#[derive(Clone, Debug)]
42pub struct ReturnCallInfo<T> {
43 pub dest: T,
45
46 pub new_stack_arg_size: u32,
49
50 pub uses: CallArgList,
52
53 pub tmp: WritableGpr,
55}
56
57#[test]
58#[cfg(target_pointer_width = "64")]
59fn inst_size_test() {
60 assert_eq!(48, std::mem::size_of::<Inst>());
63}
64
65pub(crate) fn low32_will_sign_extend_to_64(x: u64) -> bool {
66 let xs = x as i64;
67 xs == ((xs << 32) >> 32)
68}
69
70impl Inst {
71 fn available_in_any_isa(&self) -> SmallVec<[InstructionSet; 2]> {
76 match self {
77 Inst::AtomicRmwSeq { .. }
80 | Inst::Bswap { .. }
81 | Inst::CallKnown { .. }
82 | Inst::CallUnknown { .. }
83 | Inst::ReturnCallKnown { .. }
84 | Inst::ReturnCallUnknown { .. }
85 | Inst::CheckedSRemSeq { .. }
86 | Inst::CheckedSRemSeq8 { .. }
87 | Inst::Cmove { .. }
88 | Inst::CmpRmiR { .. }
89 | Inst::CvtFloatToSintSeq { .. }
90 | Inst::CvtFloatToUintSeq { .. }
91 | Inst::CvtUint64ToFloatSeq { .. }
92 | Inst::Div { .. }
93 | Inst::Div8 { .. }
94 | Inst::Fence { .. }
95 | Inst::Hlt
96 | Inst::Imm { .. }
97 | Inst::JmpCond { .. }
98 | Inst::JmpCondOr { .. }
99 | Inst::WinchJmpIf { .. }
100 | Inst::JmpKnown { .. }
101 | Inst::JmpTableSeq { .. }
102 | Inst::JmpUnknown { .. }
103 | Inst::LoadEffectiveAddress { .. }
104 | Inst::LoadExtName { .. }
105 | Inst::LockCmpxchg { .. }
106 | Inst::LockXadd { .. }
107 | Inst::Xchg { .. }
108 | Inst::Mov64MR { .. }
109 | Inst::MovImmM { .. }
110 | Inst::MovRM { .. }
111 | Inst::MovRR { .. }
112 | Inst::MovFromPReg { .. }
113 | Inst::MovToPReg { .. }
114 | Inst::MovsxRmR { .. }
115 | Inst::MovzxRmR { .. }
116 | Inst::Mul { .. }
117 | Inst::Mul8 { .. }
118 | Inst::IMul { .. }
119 | Inst::IMulImm { .. }
120 | Inst::Neg { .. }
121 | Inst::Not { .. }
122 | Inst::Nop { .. }
123 | Inst::Pop64 { .. }
124 | Inst::Push64 { .. }
125 | Inst::StackProbeLoop { .. }
126 | Inst::Args { .. }
127 | Inst::Rets { .. }
128 | Inst::Ret { .. }
129 | Inst::Setcc { .. }
130 | Inst::ShiftR { .. }
131 | Inst::SignExtendData { .. }
132 | Inst::StackSwitchBasic { .. }
133 | Inst::TrapIf { .. }
134 | Inst::TrapIfAnd { .. }
135 | Inst::TrapIfOr { .. }
136 | Inst::Ud2 { .. }
137 | Inst::XmmCmove { .. }
138 | Inst::XmmCmpRmR { .. }
139 | Inst::XmmMinMaxSeq { .. }
140 | Inst::XmmUninitializedValue { .. }
141 | Inst::GprUninitializedValue { .. }
142 | Inst::ElfTlsGetAddr { .. }
143 | Inst::MachOTlsGetAddr { .. }
144 | Inst::CoffTlsGetAddr { .. }
145 | Inst::Unwind { .. }
146 | Inst::DummyUse { .. } => smallvec![],
147
148 Inst::LockCmpxchg16b { .. }
149 | Inst::Atomic128RmwSeq { .. }
150 | Inst::Atomic128XchgSeq { .. } => smallvec![InstructionSet::CMPXCHG16b],
151
152 Inst::AluRmRVex { op, .. } => op.available_from(),
153 Inst::UnaryRmR { op, .. } => op.available_from(),
154 Inst::UnaryRmRVex { op, .. } => op.available_from(),
155 Inst::UnaryRmRImmVex { op, .. } => op.available_from(),
156
157 Inst::GprToXmm { op, .. }
159 | Inst::XmmMovRM { op, .. }
160 | Inst::XmmMovRMImm { op, .. }
161 | Inst::XmmRmiReg { opcode: op, .. }
162 | Inst::XmmRmR { op, .. }
163 | Inst::XmmRmRUnaligned { op, .. }
164 | Inst::XmmRmRBlend { op, .. }
165 | Inst::XmmRmRImm { op, .. }
166 | Inst::XmmToGpr { op, .. }
167 | Inst::XmmToGprImm { op, .. }
168 | Inst::XmmUnaryRmRImm { op, .. }
169 | Inst::XmmUnaryRmRUnaligned { op, .. }
170 | Inst::XmmUnaryRmR { op, .. }
171 | Inst::CvtIntToFloat { op, .. } => smallvec![op.available_from()],
172
173 Inst::XmmUnaryRmREvex { op, .. }
174 | Inst::XmmRmREvex { op, .. }
175 | Inst::XmmRmREvex3 { op, .. }
176 | Inst::XmmUnaryRmRImmEvex { op, .. } => op.available_from(),
177
178 Inst::XmmRmiRVex { op, .. }
179 | Inst::XmmRmRVex3 { op, .. }
180 | Inst::XmmRmRImmVex { op, .. }
181 | Inst::XmmRmRBlendVex { op, .. }
182 | Inst::XmmVexPinsr { op, .. }
183 | Inst::XmmUnaryRmRVex { op, .. }
184 | Inst::XmmUnaryRmRImmVex { op, .. }
185 | Inst::XmmMovRMVex { op, .. }
186 | Inst::XmmMovRMImmVex { op, .. }
187 | Inst::XmmToGprImmVex { op, .. }
188 | Inst::XmmToGprVex { op, .. }
189 | Inst::GprToXmmVex { op, .. }
190 | Inst::CvtIntToFloatVex { op, .. }
191 | Inst::XmmCmpRmRVex { op, .. } => op.available_from(),
192
193 Inst::MulX { .. } => smallvec![InstructionSet::BMI2],
194
195 Inst::External { inst } => {
196 use cranelift_assembler_x64::Feature::*;
197 let mut features = smallvec![];
198 for f in inst.features() {
199 match f {
200 _64b | compat => {}
201 sse => features.push(InstructionSet::SSE),
202 sse2 => features.push(InstructionSet::SSE2),
203 }
204 }
205 features
206 }
207 }
208 }
209}
210
211impl Inst {
214 pub(crate) fn nop(len: u8) -> Self {
215 debug_assert!(len <= 15);
216 Self::Nop { len }
217 }
218
219 pub(crate) fn addq_mi(dst: Writable<Reg>, simm32: i32) -> Self {
220 let inst = if let Ok(simm8) = i8::try_from(simm32) {
221 asm::inst::addq_mi_sxb::new(dst, simm8).into()
222 } else {
223 asm::inst::addq_mi_sxl::new(dst, simm32).into()
224 };
225 Inst::External { inst }
226 }
227
228 pub(crate) fn subq_mi(dst: Writable<Reg>, simm32: i32) -> Self {
229 let inst = if let Ok(simm8) = i8::try_from(simm32) {
230 asm::inst::subq_mi_sxb::new(dst, simm8).into()
231 } else {
232 asm::inst::subq_mi_sxl::new(dst, simm32).into()
233 };
234 Inst::External { inst }
235 }
236
237 #[allow(dead_code)]
238 pub(crate) fn unary_rm_r(
239 size: OperandSize,
240 op: UnaryRmROpcode,
241 src: RegMem,
242 dst: Writable<Reg>,
243 ) -> Self {
244 src.assert_regclass_is(RegClass::Int);
245 debug_assert!(dst.to_reg().class() == RegClass::Int);
246 debug_assert!(size.is_one_of(&[
247 OperandSize::Size16,
248 OperandSize::Size32,
249 OperandSize::Size64
250 ]));
251 Self::UnaryRmR {
252 size,
253 op,
254 src: GprMem::unwrap_new(src),
255 dst: WritableGpr::from_writable_reg(dst).unwrap(),
256 }
257 }
258
259 pub(crate) fn not(size: OperandSize, src: Writable<Reg>) -> Inst {
260 debug_assert_eq!(src.to_reg().class(), RegClass::Int);
261 Inst::Not {
262 size,
263 src: Gpr::unwrap_new(src.to_reg()),
264 dst: WritableGpr::from_writable_reg(src).unwrap(),
265 }
266 }
267
268 pub(crate) fn div(
269 size: OperandSize,
270 sign: DivSignedness,
271 trap: TrapCode,
272 divisor: RegMem,
273 dividend_lo: Gpr,
274 dividend_hi: Gpr,
275 dst_quotient: WritableGpr,
276 dst_remainder: WritableGpr,
277 ) -> Inst {
278 divisor.assert_regclass_is(RegClass::Int);
279 Inst::Div {
280 size,
281 sign,
282 trap,
283 divisor: GprMem::unwrap_new(divisor),
284 dividend_lo,
285 dividend_hi,
286 dst_quotient,
287 dst_remainder,
288 }
289 }
290
291 pub(crate) fn div8(
292 sign: DivSignedness,
293 trap: TrapCode,
294 divisor: RegMem,
295 dividend: Gpr,
296 dst: WritableGpr,
297 ) -> Inst {
298 divisor.assert_regclass_is(RegClass::Int);
299 Inst::Div8 {
300 sign,
301 trap,
302 divisor: GprMem::unwrap_new(divisor),
303 dividend,
304 dst,
305 }
306 }
307
308 pub(crate) fn imm(dst_size: OperandSize, simm64: u64, dst: Writable<Reg>) -> Inst {
309 debug_assert!(dst_size.is_one_of(&[OperandSize::Size32, OperandSize::Size64]));
310 debug_assert!(dst.to_reg().class() == RegClass::Int);
311 let dst_size = match dst_size {
314 OperandSize::Size64 if simm64 > u32::max_value() as u64 => OperandSize::Size64,
315 _ => OperandSize::Size32,
316 };
317 Inst::Imm {
318 dst_size,
319 simm64,
320 dst: WritableGpr::from_writable_reg(dst).unwrap(),
321 }
322 }
323
324 pub(crate) fn mov_r_r(size: OperandSize, src: Reg, dst: Writable<Reg>) -> Inst {
325 debug_assert!(size.is_one_of(&[OperandSize::Size32, OperandSize::Size64]));
326 debug_assert!(src.class() == RegClass::Int);
327 debug_assert!(dst.to_reg().class() == RegClass::Int);
328 let src = Gpr::unwrap_new(src);
329 let dst = WritableGpr::from_writable_reg(dst).unwrap();
330 Inst::MovRR { size, src, dst }
331 }
332
333 pub(crate) fn xmm_unary_rm_r(op: SseOpcode, src: RegMem, dst: Writable<Reg>) -> Inst {
335 src.assert_regclass_is(RegClass::Float);
336 debug_assert!(dst.to_reg().class() == RegClass::Float);
337 Inst::XmmUnaryRmR {
338 op,
339 src: XmmMemAligned::unwrap_new(src),
340 dst: WritableXmm::from_writable_reg(dst).unwrap(),
341 }
342 }
343
344 pub(crate) fn xmm_rm_r(op: SseOpcode, src: RegMem, dst: Writable<Reg>) -> Self {
345 src.assert_regclass_is(RegClass::Float);
346 debug_assert!(dst.to_reg().class() == RegClass::Float);
347 Inst::XmmRmR {
348 op,
349 src1: Xmm::unwrap_new(dst.to_reg()),
350 src2: XmmMemAligned::unwrap_new(src),
351 dst: WritableXmm::from_writable_reg(dst).unwrap(),
352 }
353 }
354
355 #[cfg(test)]
356 pub(crate) fn xmm_rmr_vex3(op: AvxOpcode, src3: RegMem, src2: Reg, dst: Writable<Reg>) -> Self {
357 src3.assert_regclass_is(RegClass::Float);
358 debug_assert!(src2.class() == RegClass::Float);
359 debug_assert!(dst.to_reg().class() == RegClass::Float);
360 Inst::XmmRmRVex3 {
361 op,
362 src3: XmmMem::unwrap_new(src3),
363 src2: Xmm::unwrap_new(src2),
364 src1: Xmm::unwrap_new(dst.to_reg()),
365 dst: WritableXmm::from_writable_reg(dst).unwrap(),
366 }
367 }
368
369 pub(crate) fn xmm_mov_r_m(op: SseOpcode, src: Reg, dst: impl Into<SyntheticAmode>) -> Inst {
370 debug_assert!(src.class() == RegClass::Float);
371 Inst::XmmMovRM {
372 op,
373 src: Xmm::unwrap_new(src),
374 dst: dst.into(),
375 }
376 }
377
378 pub(crate) fn xmm_to_gpr(
379 op: SseOpcode,
380 src: Reg,
381 dst: Writable<Reg>,
382 dst_size: OperandSize,
383 ) -> Inst {
384 debug_assert!(src.class() == RegClass::Float);
385 debug_assert!(dst.to_reg().class() == RegClass::Int);
386 debug_assert!(dst_size.is_one_of(&[OperandSize::Size32, OperandSize::Size64]));
387 Inst::XmmToGpr {
388 op,
389 src: Xmm::unwrap_new(src),
390 dst: WritableGpr::from_writable_reg(dst).unwrap(),
391 dst_size,
392 }
393 }
394
395 pub(crate) fn gpr_to_xmm(
396 op: SseOpcode,
397 src: RegMem,
398 src_size: OperandSize,
399 dst: Writable<Reg>,
400 ) -> Inst {
401 src.assert_regclass_is(RegClass::Int);
402 debug_assert!(src_size.is_one_of(&[OperandSize::Size32, OperandSize::Size64]));
403 debug_assert!(dst.to_reg().class() == RegClass::Float);
404 Inst::GprToXmm {
405 op,
406 src: GprMem::unwrap_new(src),
407 dst: WritableXmm::from_writable_reg(dst).unwrap(),
408 src_size,
409 }
410 }
411
412 pub(crate) fn xmm_cmp_rm_r(op: SseOpcode, src1: Reg, src2: RegMem) -> Inst {
413 src2.assert_regclass_is(RegClass::Float);
414 debug_assert!(src1.class() == RegClass::Float);
415 let src2 = XmmMemAligned::unwrap_new(src2);
416 let src1 = Xmm::unwrap_new(src1);
417 Inst::XmmCmpRmR { op, src1, src2 }
418 }
419
420 #[allow(dead_code)]
421 pub(crate) fn xmm_min_max_seq(
422 size: OperandSize,
423 is_min: bool,
424 lhs: Reg,
425 rhs: Reg,
426 dst: Writable<Reg>,
427 ) -> Inst {
428 debug_assert!(size.is_one_of(&[OperandSize::Size32, OperandSize::Size64]));
429 debug_assert_eq!(lhs.class(), RegClass::Float);
430 debug_assert_eq!(rhs.class(), RegClass::Float);
431 debug_assert_eq!(dst.to_reg().class(), RegClass::Float);
432 Inst::XmmMinMaxSeq {
433 size,
434 is_min,
435 lhs: Xmm::unwrap_new(lhs),
436 rhs: Xmm::unwrap_new(rhs),
437 dst: WritableXmm::from_writable_reg(dst).unwrap(),
438 }
439 }
440
441 pub(crate) fn movzx_rm_r(ext_mode: ExtMode, src: RegMem, dst: Writable<Reg>) -> Inst {
442 src.assert_regclass_is(RegClass::Int);
443 debug_assert!(dst.to_reg().class() == RegClass::Int);
444 let src = GprMem::unwrap_new(src);
445 let dst = WritableGpr::from_writable_reg(dst).unwrap();
446 Inst::MovzxRmR { ext_mode, src, dst }
447 }
448
449 pub(crate) fn movsx_rm_r(ext_mode: ExtMode, src: RegMem, dst: Writable<Reg>) -> Inst {
450 src.assert_regclass_is(RegClass::Int);
451 debug_assert!(dst.to_reg().class() == RegClass::Int);
452 let src = GprMem::unwrap_new(src);
453 let dst = WritableGpr::from_writable_reg(dst).unwrap();
454 Inst::MovsxRmR { ext_mode, src, dst }
455 }
456
457 pub(crate) fn mov64_m_r(src: impl Into<SyntheticAmode>, dst: Writable<Reg>) -> Inst {
458 debug_assert!(dst.to_reg().class() == RegClass::Int);
459 Inst::Mov64MR {
460 src: src.into(),
461 dst: WritableGpr::from_writable_reg(dst).unwrap(),
462 }
463 }
464
465 pub(crate) fn mov_r_m(size: OperandSize, src: Reg, dst: impl Into<SyntheticAmode>) -> Inst {
466 debug_assert!(src.class() == RegClass::Int);
467 Inst::MovRM {
468 size,
469 src: Gpr::unwrap_new(src),
470 dst: dst.into(),
471 }
472 }
473
474 pub(crate) fn lea(addr: impl Into<SyntheticAmode>, dst: Writable<Reg>) -> Inst {
475 debug_assert!(dst.to_reg().class() == RegClass::Int);
476 Inst::LoadEffectiveAddress {
477 addr: addr.into(),
478 dst: WritableGpr::from_writable_reg(dst).unwrap(),
479 size: OperandSize::Size64,
480 }
481 }
482
483 pub(crate) fn shift_r(
484 size: OperandSize,
485 kind: ShiftKind,
486 num_bits: Imm8Gpr,
487 src: Reg,
488 dst: Writable<Reg>,
489 ) -> Inst {
490 if let &Imm8Reg::Imm8 { imm: num_bits } = num_bits.as_imm8_reg() {
491 debug_assert!(num_bits < size.to_bits());
492 }
493 debug_assert!(dst.to_reg().class() == RegClass::Int);
494 Inst::ShiftR {
495 size,
496 kind,
497 src: Gpr::unwrap_new(src),
498 num_bits,
499 dst: WritableGpr::from_writable_reg(dst).unwrap(),
500 }
501 }
502
503 pub(crate) fn cmp_rmi_r(size: OperandSize, src1: Reg, src2: RegMemImm) -> Inst {
506 src2.assert_regclass_is(RegClass::Int);
507 debug_assert_eq!(src1.class(), RegClass::Int);
508 Inst::CmpRmiR {
509 size,
510 src1: Gpr::unwrap_new(src1),
511 src2: GprMemImm::unwrap_new(src2),
512 opcode: CmpOpcode::Cmp,
513 }
514 }
515
516 pub(crate) fn trap(trap_code: TrapCode) -> Inst {
517 Inst::Ud2 { trap_code }
518 }
519
520 pub(crate) fn trap_if(cc: CC, trap_code: TrapCode) -> Inst {
521 Inst::TrapIf { cc, trap_code }
522 }
523
524 pub(crate) fn cmove(size: OperandSize, cc: CC, src: RegMem, dst: Writable<Reg>) -> Inst {
525 debug_assert!(size.is_one_of(&[
526 OperandSize::Size16,
527 OperandSize::Size32,
528 OperandSize::Size64
529 ]));
530 debug_assert!(dst.to_reg().class() == RegClass::Int);
531 Inst::Cmove {
532 size,
533 cc,
534 consequent: GprMem::unwrap_new(src),
535 alternative: Gpr::unwrap_new(dst.to_reg()),
536 dst: WritableGpr::from_writable_reg(dst).unwrap(),
537 }
538 }
539
540 pub(crate) fn push64(src: RegMemImm) -> Inst {
541 src.assert_regclass_is(RegClass::Int);
542 let src = GprMemImm::unwrap_new(src);
543 Inst::Push64 { src }
544 }
545
546 pub(crate) fn pop64(dst: Writable<Reg>) -> Inst {
547 debug_assert!(dst.to_reg().class() == RegClass::Int);
548 let dst = WritableGpr::from_writable_reg(dst).unwrap();
549 Inst::Pop64 { dst }
550 }
551
552 pub(crate) fn call_known(info: Box<CallInfo<ExternalName>>) -> Inst {
553 Inst::CallKnown { info }
554 }
555
556 pub(crate) fn call_unknown(info: Box<CallInfo<RegMem>>) -> Inst {
557 info.dest.assert_regclass_is(RegClass::Int);
558 Inst::CallUnknown { info }
559 }
560
561 pub(crate) fn ret(stack_bytes_to_pop: u32) -> Inst {
562 Inst::Ret { stack_bytes_to_pop }
563 }
564
565 pub(crate) fn jmp_known(dst: MachLabel) -> Inst {
566 Inst::JmpKnown { dst }
567 }
568
569 pub(crate) fn jmp_unknown(target: RegMem) -> Inst {
570 target.assert_regclass_is(RegClass::Int);
571 Inst::JmpUnknown { target }
572 }
573
574 pub(crate) fn load(
578 ty: Type,
579 from_addr: impl Into<SyntheticAmode>,
580 to_reg: Writable<Reg>,
581 ext_kind: ExtKind,
582 ) -> Inst {
583 let rc = to_reg.to_reg().class();
584 match rc {
585 RegClass::Int => {
586 let ext_mode = match ty.bytes() {
587 1 => Some(ExtMode::BQ),
588 2 => Some(ExtMode::WQ),
589 4 => Some(ExtMode::LQ),
590 8 => None,
591 _ => unreachable!("the type should never use a scalar load: {}", ty),
592 };
593 if let Some(ext_mode) = ext_mode {
594 match ext_kind {
596 ExtKind::SignExtend => {
597 Inst::movsx_rm_r(ext_mode, RegMem::mem(from_addr), to_reg)
598 }
599 ExtKind::ZeroExtend => {
600 Inst::movzx_rm_r(ext_mode, RegMem::mem(from_addr), to_reg)
601 }
602 ExtKind::None => {
603 panic!("expected an extension kind for extension mode: {ext_mode:?}")
604 }
605 }
606 } else {
607 Inst::mov64_m_r(from_addr, to_reg)
609 }
610 }
611 RegClass::Float => {
612 let opcode = match ty {
613 types::F16 | types::I8X2 => {
614 panic!("loading a f16 or i8x2 requires multiple instructions")
615 }
616 _ if (ty.is_float() || ty.is_vector()) && ty.bits() == 32 => SseOpcode::Movss,
617 _ if (ty.is_float() || ty.is_vector()) && ty.bits() == 64 => SseOpcode::Movsd,
618 types::F32X4 => SseOpcode::Movups,
619 types::F64X2 => SseOpcode::Movupd,
620 _ if (ty.is_float() || ty.is_vector()) && ty.bits() == 128 => SseOpcode::Movdqu,
621 _ => unimplemented!("unable to load type: {}", ty),
622 };
623 Inst::xmm_unary_rm_r(opcode, RegMem::mem(from_addr), to_reg)
624 }
625 RegClass::Vector => unreachable!(),
626 }
627 }
628
629 pub(crate) fn store(ty: Type, from_reg: Reg, to_addr: impl Into<SyntheticAmode>) -> Inst {
631 let rc = from_reg.class();
632 match rc {
633 RegClass::Int => Inst::mov_r_m(OperandSize::from_ty(ty), from_reg, to_addr),
634 RegClass::Float => {
635 let opcode = match ty {
636 types::F16 | types::I8X2 => {
637 panic!("storing a f16 or i8x2 requires multiple instructions")
638 }
639 _ if (ty.is_float() || ty.is_vector()) && ty.bits() == 32 => SseOpcode::Movss,
640 _ if (ty.is_float() || ty.is_vector()) && ty.bits() == 64 => SseOpcode::Movsd,
641 types::F32X4 => SseOpcode::Movups,
642 types::F64X2 => SseOpcode::Movupd,
643 _ if (ty.is_float() || ty.is_vector()) && ty.bits() == 128 => SseOpcode::Movdqu,
644 _ => unimplemented!("unable to store type: {}", ty),
645 };
646 Inst::xmm_mov_r_m(opcode, from_reg, to_addr)
647 }
648 RegClass::Vector => unreachable!(),
649 }
650 }
651}
652
653impl PrettyPrint for Inst {
657 fn pretty_print(&self, _size: u8) -> String {
658 fn ljustify(s: String) -> String {
659 let w = 7;
660 if s.len() >= w {
661 s
662 } else {
663 let need = usize::min(w, w - s.len());
664 s + &format!("{nil: <width$}", nil = "", width = need)
665 }
666 }
667
668 fn ljustify2(s1: String, s2: String) -> String {
669 ljustify(s1 + &s2)
670 }
671
672 fn suffix_lq(size: OperandSize) -> String {
673 match size {
674 OperandSize::Size32 => "l",
675 OperandSize::Size64 => "q",
676 _ => unreachable!(),
677 }
678 .to_string()
679 }
680
681 #[allow(dead_code)]
682 fn suffix_lqb(size: OperandSize) -> String {
683 match size {
684 OperandSize::Size32 => "l",
685 OperandSize::Size64 => "q",
686 _ => unreachable!(),
687 }
688 .to_string()
689 }
690
691 fn suffix_bwlq(size: OperandSize) -> String {
692 match size {
693 OperandSize::Size8 => "b".to_string(),
694 OperandSize::Size16 => "w".to_string(),
695 OperandSize::Size32 => "l".to_string(),
696 OperandSize::Size64 => "q".to_string(),
697 }
698 }
699
700 match self {
701 Inst::Nop { len } => format!("{} len={}", ljustify("nop".to_string()), len),
702
703 Inst::AluRmRVex {
704 size,
705 op,
706 src1,
707 src2,
708 dst,
709 } => {
710 let size_bytes = size.to_bytes();
711 let dst = pretty_print_reg(dst.to_reg().to_reg(), size.to_bytes());
712 let src1 = pretty_print_reg(src1.to_reg(), size_bytes);
713 let src2 = src2.pretty_print(size_bytes);
714 let op = ljustify2(op.to_string(), String::new());
715 format!("{op} {src2}, {src1}, {dst}")
716 }
717 Inst::UnaryRmR { src, dst, op, size } => {
718 let dst = pretty_print_reg(dst.to_reg().to_reg(), size.to_bytes());
719 let src = src.pretty_print(size.to_bytes());
720 let op = ljustify2(op.to_string(), suffix_bwlq(*size));
721 format!("{op} {src}, {dst}")
722 }
723
724 Inst::UnaryRmRVex { src, dst, op, size } => {
725 let dst = pretty_print_reg(dst.to_reg().to_reg(), size.to_bytes());
726 let src = src.pretty_print(size.to_bytes());
727 let op = ljustify2(op.to_string(), suffix_bwlq(*size));
728 format!("{op} {src}, {dst}")
729 }
730
731 Inst::UnaryRmRImmVex {
732 src,
733 dst,
734 op,
735 size,
736 imm,
737 } => {
738 let dst = pretty_print_reg(dst.to_reg().to_reg(), size.to_bytes());
739 let src = src.pretty_print(size.to_bytes());
740 format!(
741 "{} ${imm}, {src}, {dst}",
742 ljustify2(op.to_string(), suffix_bwlq(*size))
743 )
744 }
745
746 Inst::Not { size, src, dst } => {
747 let src = pretty_print_reg(src.to_reg(), size.to_bytes());
748 let dst = pretty_print_reg(dst.to_reg().to_reg(), size.to_bytes());
749 let op = ljustify2("not".to_string(), suffix_bwlq(*size));
750 format!("{op} {src}, {dst}")
751 }
752
753 Inst::Neg { size, src, dst } => {
754 let src = pretty_print_reg(src.to_reg(), size.to_bytes());
755 let dst = pretty_print_reg(dst.to_reg().to_reg(), size.to_bytes());
756 let op = ljustify2("neg".to_string(), suffix_bwlq(*size));
757 format!("{op} {src}, {dst}")
758 }
759
760 Inst::Div {
761 size,
762 sign,
763 trap,
764 divisor,
765 dividend_lo,
766 dividend_hi,
767 dst_quotient,
768 dst_remainder,
769 } => {
770 let divisor = divisor.pretty_print(size.to_bytes());
771 let dividend_lo = pretty_print_reg(dividend_lo.to_reg(), size.to_bytes());
772 let dividend_hi = pretty_print_reg(dividend_hi.to_reg(), size.to_bytes());
773 let dst_quotient =
774 pretty_print_reg(dst_quotient.to_reg().to_reg(), size.to_bytes());
775 let dst_remainder =
776 pretty_print_reg(dst_remainder.to_reg().to_reg(), size.to_bytes());
777 let op = ljustify(match sign {
778 DivSignedness::Signed => "idiv".to_string(),
779 DivSignedness::Unsigned => "div".to_string(),
780 });
781 format!(
782 "{op} {dividend_lo}, {dividend_hi}, {divisor}, {dst_quotient}, {dst_remainder} ; trap={trap}"
783 )
784 }
785
786 Inst::Div8 {
787 sign,
788 trap,
789 divisor,
790 dividend,
791 dst,
792 } => {
793 let divisor = divisor.pretty_print(1);
794 let dividend = pretty_print_reg(dividend.to_reg(), 1);
795 let dst = pretty_print_reg(dst.to_reg().to_reg(), 1);
796 let op = ljustify(match sign {
797 DivSignedness::Signed => "idiv".to_string(),
798 DivSignedness::Unsigned => "div".to_string(),
799 });
800 format!("{op} {dividend}, {divisor}, {dst} ; trap={trap}")
801 }
802
803 Inst::Mul {
804 size,
805 signed,
806 src1,
807 src2,
808 dst_lo,
809 dst_hi,
810 } => {
811 let src1 = pretty_print_reg(src1.to_reg(), size.to_bytes());
812 let dst_lo = pretty_print_reg(dst_lo.to_reg().to_reg(), size.to_bytes());
813 let dst_hi = pretty_print_reg(dst_hi.to_reg().to_reg(), size.to_bytes());
814 let src2 = src2.pretty_print(size.to_bytes());
815 let suffix = suffix_bwlq(*size);
816 let op = ljustify(if *signed {
817 format!("imul{suffix}")
818 } else {
819 format!("mul{suffix}")
820 });
821 format!("{op} {src1}, {src2}, {dst_lo}, {dst_hi}")
822 }
823
824 Inst::MulX {
825 size,
826 src1,
827 src2,
828 dst_lo,
829 dst_hi,
830 } => {
831 let src1 = pretty_print_reg(src1.to_reg(), size.to_bytes());
832 let dst_hi = pretty_print_reg(dst_hi.to_reg().to_reg(), size.to_bytes());
833 let dst_lo = if dst_lo.to_reg().is_invalid_sentinel() {
834 dst_hi.clone()
835 } else {
836 pretty_print_reg(dst_lo.to_reg().to_reg(), size.to_bytes())
837 };
838 let src2 = src2.pretty_print(size.to_bytes());
839 let suffix = suffix_bwlq(*size);
840 let op = ljustify(format!("mulx{suffix}"));
841 format!("{op} {src1}, {src2}, {dst_lo}, {dst_hi}")
842 }
843
844 Inst::Mul8 {
845 signed,
846 src1,
847 src2,
848 dst,
849 } => {
850 let src1 = pretty_print_reg(src1.to_reg(), 1);
851 let dst = pretty_print_reg(dst.to_reg().to_reg(), 1);
852 let src2 = src2.pretty_print(1);
853 let op = ljustify(if *signed {
854 "imulb".to_string()
855 } else {
856 "mulb".to_string()
857 });
858 format!("{op} {src1}, {src2}, {dst}")
859 }
860
861 Inst::IMul {
862 size,
863 src1,
864 src2,
865 dst,
866 } => {
867 let src1 = pretty_print_reg(src1.to_reg(), size.to_bytes());
868 let dst = pretty_print_reg(dst.to_reg().to_reg(), size.to_bytes());
869 let src2 = src2.pretty_print(size.to_bytes());
870 let suffix = suffix_bwlq(*size);
871 let op = ljustify(format!("imul{suffix}"));
872 format!("{op} {src1}, {src2}, {dst}")
873 }
874
875 Inst::IMulImm {
876 size,
877 src1,
878 src2,
879 dst,
880 } => {
881 let dst = pretty_print_reg(dst.to_reg().to_reg(), size.to_bytes());
882 let src1 = src1.pretty_print(size.to_bytes());
883 let suffix = suffix_bwlq(*size);
884 let op = ljustify(format!("imul{suffix}"));
885 format!("{op} {src1}, {src2:#x}, {dst}")
886 }
887
888 Inst::CheckedSRemSeq {
889 size,
890 divisor,
891 dividend_lo,
892 dividend_hi,
893 dst_quotient,
894 dst_remainder,
895 } => {
896 let divisor = pretty_print_reg(divisor.to_reg(), size.to_bytes());
897 let dividend_lo = pretty_print_reg(dividend_lo.to_reg(), size.to_bytes());
898 let dividend_hi = pretty_print_reg(dividend_hi.to_reg(), size.to_bytes());
899 let dst_quotient =
900 pretty_print_reg(dst_quotient.to_reg().to_reg(), size.to_bytes());
901 let dst_remainder =
902 pretty_print_reg(dst_remainder.to_reg().to_reg(), size.to_bytes());
903 format!(
904 "checked_srem_seq {dividend_lo}, {dividend_hi}, \
905 {divisor}, {dst_quotient}, {dst_remainder}",
906 )
907 }
908
909 Inst::CheckedSRemSeq8 {
910 divisor,
911 dividend,
912 dst,
913 } => {
914 let divisor = pretty_print_reg(divisor.to_reg(), 1);
915 let dividend = pretty_print_reg(dividend.to_reg(), 1);
916 let dst = pretty_print_reg(dst.to_reg().to_reg(), 1);
917 format!("checked_srem_seq {dividend}, {divisor}, {dst}")
918 }
919
920 Inst::SignExtendData { size, src, dst } => {
921 let src = pretty_print_reg(src.to_reg(), size.to_bytes());
922 let dst = pretty_print_reg(dst.to_reg().to_reg(), size.to_bytes());
923 let op = match size {
924 OperandSize::Size8 => "cbw",
925 OperandSize::Size16 => "cwd",
926 OperandSize::Size32 => "cdq",
927 OperandSize::Size64 => "cqo",
928 };
929 format!("{op} {src}, {dst}")
930 }
931
932 Inst::XmmUnaryRmR { op, src, dst, .. } => {
933 let dst = pretty_print_reg(dst.to_reg().to_reg(), op.src_size());
934 let src = src.pretty_print(op.src_size());
935 let op = ljustify(op.to_string());
936 format!("{op} {src}, {dst}")
937 }
938
939 Inst::XmmUnaryRmRUnaligned { op, src, dst, .. } => {
940 let dst = pretty_print_reg(dst.to_reg().to_reg(), op.src_size());
941 let src = src.pretty_print(op.src_size());
942 let op = ljustify(op.to_string());
943 format!("{op} {src}, {dst}")
944 }
945
946 Inst::XmmUnaryRmRImm {
947 op, src, dst, imm, ..
948 } => {
949 let dst = pretty_print_reg(dst.to_reg().to_reg(), op.src_size());
950 let src = src.pretty_print(op.src_size());
951 let op = ljustify(op.to_string());
952 format!("{op} ${imm}, {src}, {dst}")
953 }
954
955 Inst::XmmUnaryRmRVex { op, src, dst, .. } => {
956 let dst = pretty_print_reg(dst.to_reg().to_reg(), 8);
957 let src = src.pretty_print(8);
958 let op = ljustify(op.to_string());
959 format!("{op} {src}, {dst}")
960 }
961
962 Inst::XmmUnaryRmRImmVex {
963 op, src, dst, imm, ..
964 } => {
965 let dst = pretty_print_reg(dst.to_reg().to_reg(), 8);
966 let src = src.pretty_print(8);
967 let op = ljustify(op.to_string());
968 format!("{op} ${imm}, {src}, {dst}")
969 }
970
971 Inst::XmmUnaryRmREvex { op, src, dst, .. } => {
972 let dst = pretty_print_reg(dst.to_reg().to_reg(), 8);
973 let src = src.pretty_print(8);
974 let op = ljustify(op.to_string());
975 format!("{op} {src}, {dst}")
976 }
977
978 Inst::XmmUnaryRmRImmEvex {
979 op, src, dst, imm, ..
980 } => {
981 let dst = pretty_print_reg(dst.to_reg().to_reg(), 8);
982 let src = src.pretty_print(8);
983 let op = ljustify(op.to_string());
984 format!("{op} ${imm}, {src}, {dst}")
985 }
986
987 Inst::XmmMovRM { op, src, dst, .. } => {
988 let src = pretty_print_reg(src.to_reg(), 8);
989 let dst = dst.pretty_print(8);
990 let op = ljustify(op.to_string());
991 format!("{op} {src}, {dst}")
992 }
993
994 Inst::XmmMovRMVex { op, src, dst, .. } => {
995 let src = pretty_print_reg(src.to_reg(), 8);
996 let dst = dst.pretty_print(8);
997 let op = ljustify(op.to_string());
998 format!("{op} {src}, {dst}")
999 }
1000
1001 Inst::XmmMovRMImm {
1002 op, src, dst, imm, ..
1003 } => {
1004 let src = pretty_print_reg(src.to_reg(), 8);
1005 let dst = dst.pretty_print(8);
1006 let op = ljustify(op.to_string());
1007 format!("{op} ${imm}, {src}, {dst}")
1008 }
1009
1010 Inst::XmmMovRMImmVex {
1011 op, src, dst, imm, ..
1012 } => {
1013 let src = pretty_print_reg(src.to_reg(), 8);
1014 let dst = dst.pretty_print(8);
1015 let op = ljustify(op.to_string());
1016 format!("{op} ${imm}, {src}, {dst}")
1017 }
1018
1019 Inst::XmmRmR {
1020 op,
1021 src1,
1022 src2,
1023 dst,
1024 ..
1025 } => {
1026 let src1 = pretty_print_reg(src1.to_reg(), 8);
1027 let dst = pretty_print_reg(dst.to_reg().to_reg(), 8);
1028 let src2 = src2.pretty_print(8);
1029 let op = ljustify(op.to_string());
1030 format!("{op} {src1}, {src2}, {dst}")
1031 }
1032
1033 Inst::XmmRmRUnaligned {
1034 op,
1035 src1,
1036 src2,
1037 dst,
1038 ..
1039 } => {
1040 let src1 = pretty_print_reg(src1.to_reg(), 8);
1041 let dst = pretty_print_reg(dst.to_reg().to_reg(), 8);
1042 let src2 = src2.pretty_print(8);
1043 let op = ljustify(op.to_string());
1044 format!("{op} {src1}, {src2}, {dst}")
1045 }
1046
1047 Inst::XmmRmRBlend {
1048 op,
1049 src1,
1050 src2,
1051 mask,
1052 dst,
1053 } => {
1054 let src1 = pretty_print_reg(src1.to_reg(), 8);
1055 let mask = mask.to_reg();
1056 let mask = if mask.is_virtual() {
1057 format!(" <{}>", show_ireg_sized(mask, 8))
1058 } else {
1059 debug_assert_eq!(mask, regs::xmm0());
1060 String::new()
1061 };
1062 let dst = pretty_print_reg(dst.to_reg().to_reg(), 8);
1063 let src2 = src2.pretty_print(8);
1064 let op = ljustify(op.to_string());
1065 format!("{op} {src1}, {src2}, {dst}{mask}")
1066 }
1067
1068 Inst::XmmRmiRVex {
1069 op,
1070 src1,
1071 src2,
1072 dst,
1073 ..
1074 } => {
1075 let dst = pretty_print_reg(dst.to_reg().to_reg(), 8);
1076 let src1 = pretty_print_reg(src1.to_reg(), 8);
1077 let src2 = src2.pretty_print(8);
1078 let op = ljustify(op.to_string());
1079 format!("{op} {src1}, {src2}, {dst}")
1080 }
1081
1082 Inst::XmmRmRImmVex {
1083 op,
1084 src1,
1085 src2,
1086 dst,
1087 imm,
1088 ..
1089 } => {
1090 let dst = pretty_print_reg(dst.to_reg().to_reg(), 8);
1091 let src1 = pretty_print_reg(src1.to_reg(), 8);
1092 let src2 = src2.pretty_print(8);
1093 let op = ljustify(op.to_string());
1094 format!("{op} ${imm}, {src1}, {src2}, {dst}")
1095 }
1096
1097 Inst::XmmVexPinsr {
1098 op,
1099 src1,
1100 src2,
1101 dst,
1102 imm,
1103 ..
1104 } => {
1105 let dst = pretty_print_reg(dst.to_reg().to_reg(), 8);
1106 let src1 = pretty_print_reg(src1.to_reg(), 8);
1107 let src2 = src2.pretty_print(8);
1108 let op = ljustify(op.to_string());
1109 format!("{op} ${imm}, {src1}, {src2}, {dst}")
1110 }
1111
1112 Inst::XmmRmRVex3 {
1113 op,
1114 src1,
1115 src2,
1116 src3,
1117 dst,
1118 ..
1119 } => {
1120 let src1 = pretty_print_reg(src1.to_reg(), 8);
1121 let dst = pretty_print_reg(dst.to_reg().to_reg(), 8);
1122 let src2 = pretty_print_reg(src2.to_reg(), 8);
1123 let src3 = src3.pretty_print(8);
1124 let op = ljustify(op.to_string());
1125 format!("{op} {src1}, {src2}, {src3}, {dst}")
1126 }
1127
1128 Inst::XmmRmRBlendVex {
1129 op,
1130 src1,
1131 src2,
1132 mask,
1133 dst,
1134 ..
1135 } => {
1136 let src1 = pretty_print_reg(src1.to_reg(), 8);
1137 let dst = pretty_print_reg(dst.to_reg().to_reg(), 8);
1138 let src2 = src2.pretty_print(8);
1139 let mask = pretty_print_reg(mask.to_reg(), 8);
1140 let op = ljustify(op.to_string());
1141 format!("{op} {src1}, {src2}, {mask}, {dst}")
1142 }
1143
1144 Inst::XmmRmREvex {
1145 op,
1146 src1,
1147 src2,
1148 dst,
1149 ..
1150 } => {
1151 let src1 = pretty_print_reg(src1.to_reg(), 8);
1152 let src2 = src2.pretty_print(8);
1153 let dst = pretty_print_reg(dst.to_reg().to_reg(), 8);
1154 let op = ljustify(op.to_string());
1155 format!("{op} {src2}, {src1}, {dst}")
1156 }
1157
1158 Inst::XmmRmREvex3 {
1159 op,
1160 src1,
1161 src2,
1162 src3,
1163 dst,
1164 ..
1165 } => {
1166 let src1 = pretty_print_reg(src1.to_reg(), 8);
1167 let src2 = pretty_print_reg(src2.to_reg(), 8);
1168 let src3 = src3.pretty_print(8);
1169 let dst = pretty_print_reg(dst.to_reg().to_reg(), 8);
1170 let op = ljustify(op.to_string());
1171 format!("{op} {src3}, {src2}, {src1}, {dst}")
1172 }
1173
1174 Inst::XmmMinMaxSeq {
1175 lhs,
1176 rhs,
1177 dst,
1178 is_min,
1179 size,
1180 } => {
1181 let rhs = pretty_print_reg(rhs.to_reg(), 8);
1182 let lhs = pretty_print_reg(lhs.to_reg(), 8);
1183 let dst = pretty_print_reg(dst.to_reg().to_reg(), 8);
1184 let op = ljustify2(
1185 if *is_min {
1186 "xmm min seq ".to_string()
1187 } else {
1188 "xmm max seq ".to_string()
1189 },
1190 format!("f{}", size.to_bits()),
1191 );
1192 format!("{op} {lhs}, {rhs}, {dst}")
1193 }
1194
1195 Inst::XmmRmRImm {
1196 op,
1197 src1,
1198 src2,
1199 dst,
1200 imm,
1201 size,
1202 ..
1203 } => {
1204 let src1 = pretty_print_reg(*src1, 8);
1205 let dst = pretty_print_reg(dst.to_reg(), 8);
1206 let src2 = src2.pretty_print(8);
1207 let op = ljustify(format!(
1208 "{}{}",
1209 op.to_string(),
1210 if *size == OperandSize::Size64 {
1211 ".w"
1212 } else {
1213 ""
1214 }
1215 ));
1216 format!("{op} ${imm}, {src1}, {src2}, {dst}")
1217 }
1218
1219 Inst::XmmUninitializedValue { dst } => {
1220 let dst = pretty_print_reg(dst.to_reg().to_reg(), 8);
1221 let op = ljustify("uninit".into());
1222 format!("{op} {dst}")
1223 }
1224
1225 Inst::GprUninitializedValue { dst } => {
1226 let dst = pretty_print_reg(dst.to_reg().to_reg(), 8);
1227 let op = ljustify("uninit".into());
1228 format!("{op} {dst}")
1229 }
1230
1231 Inst::XmmToGpr {
1232 op,
1233 src,
1234 dst,
1235 dst_size,
1236 } => {
1237 let dst_size = dst_size.to_bytes();
1238 let src = pretty_print_reg(src.to_reg(), 8);
1239 let dst = pretty_print_reg(dst.to_reg().to_reg(), dst_size);
1240 let op = ljustify(op.to_string());
1241 format!("{op} {src}, {dst}")
1242 }
1243
1244 Inst::XmmToGprVex {
1245 op,
1246 src,
1247 dst,
1248 dst_size,
1249 } => {
1250 let dst_size = dst_size.to_bytes();
1251 let src = pretty_print_reg(src.to_reg(), 8);
1252 let dst = pretty_print_reg(dst.to_reg().to_reg(), dst_size);
1253 let op = ljustify(op.to_string());
1254 format!("{op} {src}, {dst}")
1255 }
1256
1257 Inst::XmmToGprImm { op, src, dst, imm } => {
1258 let src = pretty_print_reg(src.to_reg(), 8);
1259 let dst = pretty_print_reg(dst.to_reg().to_reg(), 8);
1260 let op = ljustify(op.to_string());
1261 format!("{op} ${imm}, {src}, {dst}")
1262 }
1263
1264 Inst::XmmToGprImmVex { op, src, dst, imm } => {
1265 let src = pretty_print_reg(src.to_reg(), 8);
1266 let dst = pretty_print_reg(dst.to_reg().to_reg(), 8);
1267 let op = ljustify(op.to_string());
1268 format!("{op} ${imm}, {src}, {dst}")
1269 }
1270
1271 Inst::GprToXmm {
1272 op,
1273 src,
1274 src_size,
1275 dst,
1276 } => {
1277 let dst = pretty_print_reg(dst.to_reg().to_reg(), 8);
1278 let src = src.pretty_print(src_size.to_bytes());
1279 let op = ljustify(op.to_string());
1280 format!("{op} {src}, {dst}")
1281 }
1282
1283 Inst::GprToXmmVex {
1284 op,
1285 src,
1286 src_size,
1287 dst,
1288 } => {
1289 let dst = pretty_print_reg(dst.to_reg().to_reg(), 8);
1290 let src = src.pretty_print(src_size.to_bytes());
1291 let op = ljustify(op.to_string());
1292 format!("{op} {src}, {dst}")
1293 }
1294
1295 Inst::XmmCmpRmR { op, src1, src2 } => {
1296 let src1 = pretty_print_reg(src1.to_reg(), 8);
1297 let src2 = src2.pretty_print(8);
1298 let op = ljustify(op.to_string());
1299 format!("{op} {src2}, {src1}")
1300 }
1301
1302 Inst::CvtIntToFloat {
1303 op,
1304 src1,
1305 src2,
1306 dst,
1307 src2_size,
1308 } => {
1309 let src1 = pretty_print_reg(src1.to_reg(), 8);
1310 let dst = pretty_print_reg(*dst.to_reg(), 8);
1311 let src2 = src2.pretty_print(src2_size.to_bytes());
1312 let op = ljustify(op.to_string());
1313 format!("{op} {src1}, {src2}, {dst}")
1314 }
1315
1316 Inst::CvtIntToFloatVex {
1317 op,
1318 src1,
1319 src2,
1320 dst,
1321 src2_size,
1322 } => {
1323 let dst = pretty_print_reg(*dst.to_reg(), 8);
1324 let src1 = pretty_print_reg(src1.to_reg(), 8);
1325 let src2 = src2.pretty_print(src2_size.to_bytes());
1326 let op = ljustify(op.to_string());
1327 format!("{op} {src1}, {src2}, {dst}")
1328 }
1329
1330 Inst::XmmCmpRmRVex { op, src1, src2 } => {
1331 let src1 = pretty_print_reg(src1.to_reg(), 8);
1332 let src2 = src2.pretty_print(8);
1333 format!("{} {src2}, {src1}", ljustify(op.to_string()))
1334 }
1335
1336 Inst::CvtUint64ToFloatSeq {
1337 src,
1338 dst,
1339 dst_size,
1340 tmp_gpr1,
1341 tmp_gpr2,
1342 ..
1343 } => {
1344 let src = pretty_print_reg(src.to_reg(), 8);
1345 let dst = pretty_print_reg(dst.to_reg().to_reg(), dst_size.to_bytes());
1346 let tmp_gpr1 = pretty_print_reg(tmp_gpr1.to_reg().to_reg(), 8);
1347 let tmp_gpr2 = pretty_print_reg(tmp_gpr2.to_reg().to_reg(), 8);
1348 let op = ljustify(format!(
1349 "u64_to_{}_seq",
1350 if *dst_size == OperandSize::Size64 {
1351 "f64"
1352 } else {
1353 "f32"
1354 }
1355 ));
1356 format!("{op} {src}, {dst}, {tmp_gpr1}, {tmp_gpr2}")
1357 }
1358
1359 Inst::CvtFloatToSintSeq {
1360 src,
1361 dst,
1362 src_size,
1363 dst_size,
1364 tmp_xmm,
1365 tmp_gpr,
1366 is_saturating,
1367 } => {
1368 let src = pretty_print_reg(src.to_reg(), src_size.to_bytes());
1369 let dst = pretty_print_reg(dst.to_reg().to_reg(), dst_size.to_bytes());
1370 let tmp_gpr = pretty_print_reg(tmp_gpr.to_reg().to_reg(), 8);
1371 let tmp_xmm = pretty_print_reg(tmp_xmm.to_reg().to_reg(), 8);
1372 let op = ljustify(format!(
1373 "cvt_float{}_to_sint{}{}_seq",
1374 src_size.to_bits(),
1375 dst_size.to_bits(),
1376 if *is_saturating { "_sat" } else { "" },
1377 ));
1378 format!("{op} {src}, {dst}, {tmp_gpr}, {tmp_xmm}")
1379 }
1380
1381 Inst::CvtFloatToUintSeq {
1382 src,
1383 dst,
1384 src_size,
1385 dst_size,
1386 tmp_gpr,
1387 tmp_xmm,
1388 tmp_xmm2,
1389 is_saturating,
1390 } => {
1391 let src = pretty_print_reg(src.to_reg(), src_size.to_bytes());
1392 let dst = pretty_print_reg(dst.to_reg().to_reg(), dst_size.to_bytes());
1393 let tmp_gpr = pretty_print_reg(tmp_gpr.to_reg().to_reg(), 8);
1394 let tmp_xmm = pretty_print_reg(tmp_xmm.to_reg().to_reg(), 8);
1395 let tmp_xmm2 = pretty_print_reg(tmp_xmm2.to_reg().to_reg(), 8);
1396 let op = ljustify(format!(
1397 "cvt_float{}_to_uint{}{}_seq",
1398 src_size.to_bits(),
1399 dst_size.to_bits(),
1400 if *is_saturating { "_sat" } else { "" },
1401 ));
1402 format!("{op} {src}, {dst}, {tmp_gpr}, {tmp_xmm}, {tmp_xmm2}")
1403 }
1404
1405 Inst::Imm {
1406 dst_size,
1407 simm64,
1408 dst,
1409 } => {
1410 let dst = pretty_print_reg(dst.to_reg().to_reg(), dst_size.to_bytes());
1411 if *dst_size == OperandSize::Size64 {
1412 let op = ljustify("movabsq".to_string());
1413 let imm = *simm64 as i64;
1414 format!("{op} ${imm}, {dst}")
1415 } else {
1416 let op = ljustify("movl".to_string());
1417 let imm = (*simm64 as u32) as i32;
1418 format!("{op} ${imm}, {dst}")
1419 }
1420 }
1421
1422 Inst::MovImmM { size, simm32, dst } => {
1423 let dst = dst.pretty_print(size.to_bytes());
1424 let suffix = suffix_bwlq(*size);
1425 let imm = match *size {
1426 OperandSize::Size8 => ((*simm32 as u8) as i8).to_string(),
1427 OperandSize::Size16 => ((*simm32 as u16) as i16).to_string(),
1428 OperandSize::Size32 => simm32.to_string(),
1429 OperandSize::Size64 => (*simm32 as i64).to_string(),
1430 };
1431 let op = ljustify2("mov".to_string(), suffix);
1432 format!("{op} ${imm}, {dst}")
1433 }
1434
1435 Inst::MovRR { size, src, dst } => {
1436 let src = pretty_print_reg(src.to_reg(), size.to_bytes());
1437 let dst = pretty_print_reg(dst.to_reg().to_reg(), size.to_bytes());
1438 let op = ljustify2("mov".to_string(), suffix_lq(*size));
1439 format!("{op} {src}, {dst}")
1440 }
1441
1442 Inst::MovFromPReg { src, dst } => {
1443 let src: Reg = (*src).into();
1444 let src = regs::show_ireg_sized(src, 8);
1445 let dst = pretty_print_reg(dst.to_reg().to_reg(), 8);
1446 let op = ljustify("movq".to_string());
1447 format!("{op} {src}, {dst}")
1448 }
1449
1450 Inst::MovToPReg { src, dst } => {
1451 let src = pretty_print_reg(src.to_reg(), 8);
1452 let dst: Reg = (*dst).into();
1453 let dst = regs::show_ireg_sized(dst, 8);
1454 let op = ljustify("movq".to_string());
1455 format!("{op} {src}, {dst}")
1456 }
1457
1458 Inst::MovzxRmR {
1459 ext_mode, src, dst, ..
1460 } => {
1461 let dst_size = if *ext_mode == ExtMode::LQ {
1462 4
1463 } else {
1464 ext_mode.dst_size()
1465 };
1466 let dst = pretty_print_reg(dst.to_reg().to_reg(), dst_size);
1467 let src = src.pretty_print(ext_mode.src_size());
1468
1469 if *ext_mode == ExtMode::LQ {
1470 let op = ljustify("movl".to_string());
1471 format!("{op} {src}, {dst}")
1472 } else {
1473 let op = ljustify2("movz".to_string(), ext_mode.to_string());
1474 format!("{op} {src}, {dst}")
1475 }
1476 }
1477
1478 Inst::Mov64MR { src, dst, .. } => {
1479 let dst = pretty_print_reg(dst.to_reg().to_reg(), 8);
1480 let src = src.pretty_print(8);
1481 let op = ljustify("movq".to_string());
1482 format!("{op} {src}, {dst}")
1483 }
1484
1485 Inst::LoadEffectiveAddress { addr, dst, size } => {
1486 let dst = pretty_print_reg(dst.to_reg().to_reg(), size.to_bytes());
1487 let addr = addr.pretty_print(8);
1488 let op = ljustify("lea".to_string());
1489 format!("{op} {addr}, {dst}")
1490 }
1491
1492 Inst::MovsxRmR {
1493 ext_mode, src, dst, ..
1494 } => {
1495 let dst = pretty_print_reg(dst.to_reg().to_reg(), ext_mode.dst_size());
1496 let src = src.pretty_print(ext_mode.src_size());
1497 let op = ljustify2("movs".to_string(), ext_mode.to_string());
1498 format!("{op} {src}, {dst}")
1499 }
1500
1501 Inst::MovRM { size, src, dst, .. } => {
1502 let src = pretty_print_reg(src.to_reg(), size.to_bytes());
1503 let dst = dst.pretty_print(size.to_bytes());
1504 let op = ljustify2("mov".to_string(), suffix_bwlq(*size));
1505 format!("{op} {src}, {dst}")
1506 }
1507
1508 Inst::ShiftR {
1509 size,
1510 kind,
1511 num_bits,
1512 src,
1513 dst,
1514 ..
1515 } => {
1516 let src = pretty_print_reg(src.to_reg(), size.to_bytes());
1517 let dst = pretty_print_reg(dst.to_reg().to_reg(), size.to_bytes());
1518 match num_bits.as_imm8_reg() {
1519 &Imm8Reg::Reg { reg } => {
1520 let reg = pretty_print_reg(reg, 1);
1521 let op = ljustify2(kind.to_string(), suffix_bwlq(*size));
1522 format!("{op} {reg}, {src}, {dst}")
1523 }
1524
1525 &Imm8Reg::Imm8 { imm: num_bits } => {
1526 let op = ljustify2(kind.to_string(), suffix_bwlq(*size));
1527 format!("{op} ${num_bits}, {src}, {dst}")
1528 }
1529 }
1530 }
1531
1532 Inst::XmmRmiReg {
1533 opcode,
1534 src1,
1535 src2,
1536 dst,
1537 ..
1538 } => {
1539 let src1 = pretty_print_reg(src1.to_reg(), 8);
1540 let dst = pretty_print_reg(dst.to_reg().to_reg(), 8);
1541 let src2 = src2.pretty_print(8);
1542 let op = ljustify(opcode.to_string());
1543 format!("{op} {src1}, {src2}, {dst}")
1544 }
1545
1546 Inst::CmpRmiR {
1547 size,
1548 src1,
1549 src2,
1550 opcode,
1551 } => {
1552 let src1 = pretty_print_reg(src1.to_reg(), size.to_bytes());
1553 let src2 = src2.pretty_print(size.to_bytes());
1554 let op = match opcode {
1555 CmpOpcode::Cmp => "cmp",
1556 CmpOpcode::Test => "test",
1557 };
1558 let op = ljustify2(op.to_string(), suffix_bwlq(*size));
1559 format!("{op} {src2}, {src1}")
1560 }
1561
1562 Inst::Setcc { cc, dst } => {
1563 let dst = pretty_print_reg(dst.to_reg().to_reg(), 1);
1564 let op = ljustify2("set".to_string(), cc.to_string());
1565 format!("{op} {dst}")
1566 }
1567
1568 Inst::Bswap { size, src, dst } => {
1569 let src = pretty_print_reg(src.to_reg(), size.to_bytes());
1570 let dst = pretty_print_reg(dst.to_reg().to_reg(), size.to_bytes());
1571 let op = ljustify2("bswap".to_string(), suffix_bwlq(*size));
1572 format!("{op} {src}, {dst}")
1573 }
1574
1575 Inst::Cmove {
1576 size,
1577 cc,
1578 consequent,
1579 alternative,
1580 dst,
1581 } => {
1582 let alternative = pretty_print_reg(alternative.to_reg(), size.to_bytes());
1583 let dst = pretty_print_reg(dst.to_reg().to_reg(), size.to_bytes());
1584 let consequent = consequent.pretty_print(size.to_bytes());
1585 let op = ljustify(format!("cmov{}{}", cc.to_string(), suffix_bwlq(*size)));
1586 format!("{op} {consequent}, {alternative}, {dst}")
1587 }
1588
1589 Inst::XmmCmove {
1590 ty,
1591 cc,
1592 consequent,
1593 alternative,
1594 dst,
1595 ..
1596 } => {
1597 let size = u8::try_from(ty.bytes()).unwrap();
1598 let alternative = pretty_print_reg(alternative.to_reg(), size);
1599 let dst = pretty_print_reg(dst.to_reg().to_reg(), size);
1600 let consequent = pretty_print_reg(consequent.to_reg(), size);
1601 let suffix = match *ty {
1602 types::F64 => "sd",
1603 types::F32 => "ss",
1604 types::F16 => "ss",
1605 types::F32X4 => "aps",
1606 types::F64X2 => "apd",
1607 _ => "dqa",
1608 };
1609 let cc = cc.invert();
1610 format!(
1611 "mov{suffix} {alternative}, {dst}; \
1612 j{cc} $next; \
1613 mov{suffix} {consequent}, {dst}; \
1614 $next:"
1615 )
1616 }
1617
1618 Inst::Push64 { src } => {
1619 let src = src.pretty_print(8);
1620 let op = ljustify("pushq".to_string());
1621 format!("{op} {src}")
1622 }
1623
1624 Inst::StackProbeLoop {
1625 tmp,
1626 frame_size,
1627 guard_size,
1628 } => {
1629 let tmp = pretty_print_reg(tmp.to_reg(), 8);
1630 let op = ljustify("stack_probe_loop".to_string());
1631 format!("{op} {tmp}, frame_size={frame_size}, guard_size={guard_size}")
1632 }
1633
1634 Inst::Pop64 { dst } => {
1635 let dst = pretty_print_reg(dst.to_reg().to_reg(), 8);
1636 let op = ljustify("popq".to_string());
1637 format!("{op} {dst}")
1638 }
1639
1640 Inst::CallKnown { info } => {
1641 let op = ljustify("call".to_string());
1642 let try_call = info
1643 .try_call_info
1644 .as_ref()
1645 .map(|tci| pretty_print_try_call(tci))
1646 .unwrap_or_default();
1647 format!("{op} {:?}{try_call}", info.dest)
1648 }
1649
1650 Inst::CallUnknown { info } => {
1651 let dest = info.dest.pretty_print(8);
1652 let op = ljustify("call".to_string());
1653 let try_call = info
1654 .try_call_info
1655 .as_ref()
1656 .map(|tci| pretty_print_try_call(tci))
1657 .unwrap_or_default();
1658 format!("{op} *{dest}{try_call}")
1659 }
1660
1661 Inst::ReturnCallKnown { info } => {
1662 let ReturnCallInfo {
1663 uses,
1664 new_stack_arg_size,
1665 tmp,
1666 dest,
1667 } = &**info;
1668 let tmp = pretty_print_reg(tmp.to_reg().to_reg(), 8);
1669 let mut s = format!("return_call_known {dest:?} ({new_stack_arg_size}) tmp={tmp}");
1670 for ret in uses {
1671 let preg = regs::show_reg(ret.preg);
1672 let vreg = pretty_print_reg(ret.vreg, 8);
1673 write!(&mut s, " {vreg}={preg}").unwrap();
1674 }
1675 s
1676 }
1677
1678 Inst::ReturnCallUnknown { info } => {
1679 let ReturnCallInfo {
1680 uses,
1681 new_stack_arg_size,
1682 tmp,
1683 dest,
1684 } = &**info;
1685 let callee = pretty_print_reg(*dest, 8);
1686 let tmp = pretty_print_reg(tmp.to_reg().to_reg(), 8);
1687 let mut s =
1688 format!("return_call_unknown {callee} ({new_stack_arg_size}) tmp={tmp}");
1689 for ret in uses {
1690 let preg = regs::show_reg(ret.preg);
1691 let vreg = pretty_print_reg(ret.vreg, 8);
1692 write!(&mut s, " {vreg}={preg}").unwrap();
1693 }
1694 s
1695 }
1696
1697 Inst::Args { args } => {
1698 let mut s = "args".to_string();
1699 for arg in args {
1700 let preg = regs::show_reg(arg.preg);
1701 let def = pretty_print_reg(arg.vreg.to_reg(), 8);
1702 write!(&mut s, " {def}={preg}").unwrap();
1703 }
1704 s
1705 }
1706
1707 Inst::Rets { rets } => {
1708 let mut s = "rets".to_string();
1709 for ret in rets {
1710 let preg = regs::show_reg(ret.preg);
1711 let vreg = pretty_print_reg(ret.vreg, 8);
1712 write!(&mut s, " {vreg}={preg}").unwrap();
1713 }
1714 s
1715 }
1716
1717 Inst::Ret { stack_bytes_to_pop } => {
1718 let mut s = "ret".to_string();
1719 if *stack_bytes_to_pop != 0 {
1720 write!(&mut s, " {stack_bytes_to_pop}").unwrap();
1721 }
1722 s
1723 }
1724
1725 Inst::StackSwitchBasic {
1726 store_context_ptr,
1727 load_context_ptr,
1728 in_payload0,
1729 out_payload0,
1730 } => {
1731 let store_context_ptr = pretty_print_reg(**store_context_ptr, 8);
1732 let load_context_ptr = pretty_print_reg(**load_context_ptr, 8);
1733 let in_payload0 = pretty_print_reg(**in_payload0, 8);
1734 let out_payload0 = pretty_print_reg(*out_payload0.to_reg(), 8);
1735 format!("{out_payload0} = stack_switch_basic {store_context_ptr}, {load_context_ptr}, {in_payload0}")
1736 }
1737
1738 Inst::JmpKnown { dst } => {
1739 let op = ljustify("jmp".to_string());
1740 let dst = dst.to_string();
1741 format!("{op} {dst}")
1742 }
1743
1744 Inst::WinchJmpIf { cc, taken } => {
1745 let taken = taken.to_string();
1746 let op = ljustify2("j".to_string(), cc.to_string());
1747 format!("{op} {taken}")
1748 }
1749
1750 Inst::JmpCondOr {
1751 cc1,
1752 cc2,
1753 taken,
1754 not_taken,
1755 } => {
1756 let taken = taken.to_string();
1757 let not_taken = not_taken.to_string();
1758 let op = ljustify(format!("j{cc1},{cc2}"));
1759 format!("{op} {taken}; j {not_taken}")
1760 }
1761
1762 Inst::JmpCond {
1763 cc,
1764 taken,
1765 not_taken,
1766 } => {
1767 let taken = taken.to_string();
1768 let not_taken = not_taken.to_string();
1769 let op = ljustify2("j".to_string(), cc.to_string());
1770 format!("{op} {taken}; j {not_taken}")
1771 }
1772
1773 Inst::JmpTableSeq {
1774 idx, tmp1, tmp2, ..
1775 } => {
1776 let idx = pretty_print_reg(*idx, 8);
1777 let tmp1 = pretty_print_reg(tmp1.to_reg(), 8);
1778 let tmp2 = pretty_print_reg(tmp2.to_reg(), 8);
1779 let op = ljustify("br_table".into());
1780 format!("{op} {idx}, {tmp1}, {tmp2}")
1781 }
1782
1783 Inst::JmpUnknown { target } => {
1784 let target = target.pretty_print(8);
1785 let op = ljustify("jmp".to_string());
1786 format!("{op} *{target}")
1787 }
1788
1789 Inst::TrapIf { cc, trap_code, .. } => {
1790 format!("j{cc} #trap={trap_code}")
1791 }
1792
1793 Inst::TrapIfAnd {
1794 cc1,
1795 cc2,
1796 trap_code,
1797 ..
1798 } => {
1799 let cc1 = cc1.invert();
1800 let cc2 = cc2.invert();
1801 format!("trap_if_and {cc1}, {cc2}, {trap_code}")
1802 }
1803
1804 Inst::TrapIfOr {
1805 cc1,
1806 cc2,
1807 trap_code,
1808 ..
1809 } => {
1810 let cc2 = cc2.invert();
1811 format!("trap_if_or {cc1}, {cc2}, {trap_code}")
1812 }
1813
1814 Inst::LoadExtName {
1815 dst, name, offset, ..
1816 } => {
1817 let dst = pretty_print_reg(dst.to_reg(), 8);
1818 let name = name.display(None);
1819 let op = ljustify("load_ext_name".into());
1820 format!("{op} {name}+{offset}, {dst}")
1821 }
1822
1823 Inst::LockCmpxchg {
1824 ty,
1825 replacement,
1826 expected,
1827 mem,
1828 dst_old,
1829 ..
1830 } => {
1831 let size = ty.bytes() as u8;
1832 let replacement = pretty_print_reg(*replacement, size);
1833 let expected = pretty_print_reg(*expected, size);
1834 let dst_old = pretty_print_reg(dst_old.to_reg(), size);
1835 let mem = mem.pretty_print(size);
1836 let suffix = suffix_bwlq(OperandSize::from_bytes(size as u32));
1837 format!(
1838 "lock cmpxchg{suffix} {replacement}, {mem}, expected={expected}, dst_old={dst_old}"
1839 )
1840 }
1841
1842 Inst::LockCmpxchg16b {
1843 replacement_low,
1844 replacement_high,
1845 expected_low,
1846 expected_high,
1847 mem,
1848 dst_old_low,
1849 dst_old_high,
1850 ..
1851 } => {
1852 let replacement_low = pretty_print_reg(*replacement_low, 8);
1853 let replacement_high = pretty_print_reg(*replacement_high, 8);
1854 let expected_low = pretty_print_reg(*expected_low, 8);
1855 let expected_high = pretty_print_reg(*expected_high, 8);
1856 let dst_old_low = pretty_print_reg(dst_old_low.to_reg(), 8);
1857 let dst_old_high = pretty_print_reg(dst_old_high.to_reg(), 8);
1858 let mem = mem.pretty_print(16);
1859 format!(
1860 "lock cmpxchg16b {mem}, replacement={replacement_high}:{replacement_low}, expected={expected_high}:{expected_low}, dst_old={dst_old_high}:{dst_old_low}"
1861 )
1862 }
1863
1864 Inst::LockXadd {
1865 size,
1866 operand,
1867 mem,
1868 dst_old,
1869 } => {
1870 let operand = pretty_print_reg(*operand, size.to_bytes());
1871 let dst_old = pretty_print_reg(dst_old.to_reg(), size.to_bytes());
1872 let mem = mem.pretty_print(size.to_bytes());
1873 let suffix = suffix_bwlq(*size);
1874 format!("lock xadd{suffix} {operand}, {mem}, dst_old={dst_old}")
1875 }
1876
1877 Inst::Xchg {
1878 size,
1879 operand,
1880 mem,
1881 dst_old,
1882 } => {
1883 let operand = pretty_print_reg(*operand, size.to_bytes());
1884 let dst_old = pretty_print_reg(dst_old.to_reg(), size.to_bytes());
1885 let mem = mem.pretty_print(size.to_bytes());
1886 let suffix = suffix_bwlq(*size);
1887 format!("xchg{suffix} {operand}, {mem}, dst_old={dst_old}")
1888 }
1889
1890 Inst::AtomicRmwSeq { ty, op, .. } => {
1891 let ty = ty.bits();
1892 format!(
1893 "atomically {{ {ty}_bits_at_[%r9] {op:?}= %r10; %rax = old_value_at_[%r9]; %r11, %rflags = trash }}"
1894 )
1895 }
1896
1897 Inst::Atomic128RmwSeq {
1898 op,
1899 mem,
1900 operand_low,
1901 operand_high,
1902 temp_low,
1903 temp_high,
1904 dst_old_low,
1905 dst_old_high,
1906 } => {
1907 let operand_low = pretty_print_reg(*operand_low, 8);
1908 let operand_high = pretty_print_reg(*operand_high, 8);
1909 let temp_low = pretty_print_reg(temp_low.to_reg(), 8);
1910 let temp_high = pretty_print_reg(temp_high.to_reg(), 8);
1911 let dst_old_low = pretty_print_reg(dst_old_low.to_reg(), 8);
1912 let dst_old_high = pretty_print_reg(dst_old_high.to_reg(), 8);
1913 let mem = mem.pretty_print(16);
1914 format!("atomically {{ {dst_old_high}:{dst_old_low} = {mem}; {temp_high}:{temp_low} = {dst_old_high}:{dst_old_low} {op:?} {operand_high}:{operand_low}; {mem} = {temp_high}:{temp_low} }}")
1915 }
1916
1917 Inst::Atomic128XchgSeq {
1918 mem,
1919 operand_low,
1920 operand_high,
1921 dst_old_low,
1922 dst_old_high,
1923 } => {
1924 let operand_low = pretty_print_reg(*operand_low, 8);
1925 let operand_high = pretty_print_reg(*operand_high, 8);
1926 let dst_old_low = pretty_print_reg(dst_old_low.to_reg(), 8);
1927 let dst_old_high = pretty_print_reg(dst_old_high.to_reg(), 8);
1928 let mem = mem.pretty_print(16);
1929 format!("atomically {{ {dst_old_high}:{dst_old_low} = {mem}; {mem} = {operand_high}:{operand_low} }}")
1930 }
1931
1932 Inst::Fence { kind } => match kind {
1933 FenceKind::MFence => "mfence".to_string(),
1934 FenceKind::LFence => "lfence".to_string(),
1935 FenceKind::SFence => "sfence".to_string(),
1936 },
1937
1938 Inst::Hlt => "hlt".into(),
1939
1940 Inst::Ud2 { trap_code } => format!("ud2 {trap_code}"),
1941
1942 Inst::ElfTlsGetAddr { symbol, dst } => {
1943 let dst = pretty_print_reg(dst.to_reg().to_reg(), 8);
1944 format!("{dst} = elf_tls_get_addr {symbol:?}")
1945 }
1946
1947 Inst::MachOTlsGetAddr { symbol, dst } => {
1948 let dst = pretty_print_reg(dst.to_reg().to_reg(), 8);
1949 format!("{dst} = macho_tls_get_addr {symbol:?}")
1950 }
1951
1952 Inst::CoffTlsGetAddr { symbol, dst, tmp } => {
1953 let dst = pretty_print_reg(dst.to_reg().to_reg(), 8);
1954 let tmp = tmp.to_reg().to_reg();
1955
1956 let mut s = format!("{dst} = coff_tls_get_addr {symbol:?}");
1957 if tmp.is_virtual() {
1958 let tmp = show_ireg_sized(tmp, 8);
1959 write!(&mut s, ", {tmp}").unwrap();
1960 };
1961
1962 s
1963 }
1964
1965 Inst::Unwind { inst } => format!("unwind {inst:?}"),
1966
1967 Inst::DummyUse { reg } => {
1968 let reg = pretty_print_reg(*reg, 8);
1969 format!("dummy_use {reg}")
1970 }
1971
1972 Inst::External { inst } => {
1973 format!("{inst}")
1974 }
1975 }
1976 }
1977}
1978
1979fn pretty_print_try_call(info: &TryCallInfo) -> String {
1980 let dests = info
1981 .exception_dests
1982 .iter()
1983 .map(|(tag, label)| format!("{tag:?}: {label:?}"))
1984 .collect::<Vec<_>>()
1985 .join(", ");
1986 format!("; jmp {:?}; catch [{dests}]", info.continuation)
1987}
1988
1989impl fmt::Debug for Inst {
1990 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
1991 write!(fmt, "{}", self.pretty_print_inst(&mut Default::default()))
1992 }
1993}
1994
1995fn x64_get_operands(inst: &mut Inst, collector: &mut impl OperandVisitor) {
1996 match inst {
2006 Inst::AluRmRVex {
2007 src1, src2, dst, ..
2008 } => {
2009 collector.reg_def(dst);
2010 collector.reg_use(src1);
2011 src2.get_operands(collector);
2012 }
2013 Inst::Not { src, dst, .. } => {
2014 collector.reg_use(src);
2015 collector.reg_reuse_def(dst, 0);
2016 }
2017 Inst::Neg { src, dst, .. } => {
2018 collector.reg_use(src);
2019 collector.reg_reuse_def(dst, 0);
2020 }
2021 Inst::Div {
2022 divisor,
2023 dividend_lo,
2024 dividend_hi,
2025 dst_quotient,
2026 dst_remainder,
2027 ..
2028 } => {
2029 divisor.get_operands(collector);
2030 collector.reg_fixed_use(dividend_lo, regs::rax());
2031 collector.reg_fixed_use(dividend_hi, regs::rdx());
2032 collector.reg_fixed_def(dst_quotient, regs::rax());
2033 collector.reg_fixed_def(dst_remainder, regs::rdx());
2034 }
2035 Inst::CheckedSRemSeq {
2036 divisor,
2037 dividend_lo,
2038 dividend_hi,
2039 dst_quotient,
2040 dst_remainder,
2041 ..
2042 } => {
2043 collector.reg_use(divisor);
2044 collector.reg_fixed_use(dividend_lo, regs::rax());
2045 collector.reg_fixed_use(dividend_hi, regs::rdx());
2046 collector.reg_fixed_def(dst_quotient, regs::rax());
2047 collector.reg_fixed_def(dst_remainder, regs::rdx());
2048 }
2049 Inst::Div8 {
2050 divisor,
2051 dividend,
2052 dst,
2053 ..
2054 } => {
2055 divisor.get_operands(collector);
2056 collector.reg_fixed_use(dividend, regs::rax());
2057 collector.reg_fixed_def(dst, regs::rax());
2058 }
2059 Inst::CheckedSRemSeq8 {
2060 divisor,
2061 dividend,
2062 dst,
2063 ..
2064 } => {
2065 collector.reg_use(divisor);
2066 collector.reg_fixed_use(dividend, regs::rax());
2067 collector.reg_fixed_def(dst, regs::rax());
2068 }
2069 Inst::Mul {
2070 src1,
2071 src2,
2072 dst_lo,
2073 dst_hi,
2074 ..
2075 } => {
2076 collector.reg_fixed_use(src1, regs::rax());
2077 collector.reg_fixed_def(dst_lo, regs::rax());
2078 collector.reg_fixed_def(dst_hi, regs::rdx());
2079 src2.get_operands(collector);
2080 }
2081 Inst::Mul8 {
2082 src1, src2, dst, ..
2083 } => {
2084 collector.reg_fixed_use(src1, regs::rax());
2085 collector.reg_fixed_def(dst, regs::rax());
2086 src2.get_operands(collector);
2087 }
2088 Inst::IMul {
2089 src1, src2, dst, ..
2090 } => {
2091 collector.reg_use(src1);
2092 collector.reg_reuse_def(dst, 0);
2093 src2.get_operands(collector);
2094 }
2095 Inst::IMulImm { src1, dst, .. } => {
2096 collector.reg_def(dst);
2097 src1.get_operands(collector);
2098 }
2099 Inst::MulX {
2100 src1,
2101 src2,
2102 dst_lo,
2103 dst_hi,
2104 ..
2105 } => {
2106 if !dst_lo.to_reg().is_invalid_sentinel() {
2107 collector.reg_def(dst_lo);
2108 }
2109 collector.reg_def(dst_hi);
2110 collector.reg_fixed_use(src1, regs::rdx());
2111 src2.get_operands(collector);
2112 }
2113 Inst::SignExtendData { size, src, dst } => {
2114 match size {
2115 OperandSize::Size8 => {
2116 collector.reg_fixed_use(src, regs::rax());
2119 collector.reg_fixed_def(dst, regs::rax());
2120 }
2121 _ => {
2122 collector.reg_fixed_use(src, regs::rax());
2125 collector.reg_fixed_def(dst, regs::rdx());
2126 }
2127 }
2128 }
2129 Inst::UnaryRmR { src, dst, .. }
2130 | Inst::UnaryRmRVex { src, dst, .. }
2131 | Inst::UnaryRmRImmVex { src, dst, .. } => {
2132 collector.reg_def(dst);
2133 src.get_operands(collector);
2134 }
2135 Inst::XmmUnaryRmR { src, dst, .. } | Inst::XmmUnaryRmRImm { src, dst, .. } => {
2136 collector.reg_def(dst);
2137 src.get_operands(collector);
2138 }
2139 Inst::XmmUnaryRmREvex { src, dst, .. }
2140 | Inst::XmmUnaryRmRImmEvex { src, dst, .. }
2141 | Inst::XmmUnaryRmRUnaligned { src, dst, .. }
2142 | Inst::XmmUnaryRmRVex { src, dst, .. }
2143 | Inst::XmmUnaryRmRImmVex { src, dst, .. } => {
2144 collector.reg_def(dst);
2145 src.get_operands(collector);
2146 }
2147 Inst::XmmRmR {
2148 src1, src2, dst, ..
2149 } => {
2150 collector.reg_use(src1);
2151 collector.reg_reuse_def(dst, 0);
2152 src2.get_operands(collector);
2153 }
2154 Inst::XmmRmRUnaligned {
2155 src1, src2, dst, ..
2156 } => {
2157 collector.reg_use(src1);
2158 collector.reg_reuse_def(dst, 0);
2159 src2.get_operands(collector);
2160 }
2161 Inst::XmmRmRBlend {
2162 src1,
2163 src2,
2164 mask,
2165 dst,
2166 op,
2167 } => {
2168 assert!(matches!(
2169 op,
2170 SseOpcode::Blendvpd | SseOpcode::Blendvps | SseOpcode::Pblendvb
2171 ));
2172 collector.reg_use(src1);
2173 collector.reg_fixed_use(mask, regs::xmm0());
2174 collector.reg_reuse_def(dst, 0);
2175 src2.get_operands(collector);
2176 }
2177 Inst::XmmRmiRVex {
2178 src1, src2, dst, ..
2179 } => {
2180 collector.reg_def(dst);
2181 collector.reg_use(src1);
2182 src2.get_operands(collector);
2183 }
2184 Inst::XmmRmRImmVex {
2185 src1, src2, dst, ..
2186 } => {
2187 collector.reg_def(dst);
2188 collector.reg_use(src1);
2189 src2.get_operands(collector);
2190 }
2191 Inst::XmmVexPinsr {
2192 src1, src2, dst, ..
2193 } => {
2194 collector.reg_def(dst);
2195 collector.reg_use(src1);
2196 src2.get_operands(collector);
2197 }
2198 Inst::XmmRmRVex3 {
2199 src1,
2200 src2,
2201 src3,
2202 dst,
2203 ..
2204 } => {
2205 collector.reg_use(src1);
2206 collector.reg_reuse_def(dst, 0);
2207 collector.reg_use(src2);
2208 src3.get_operands(collector);
2209 }
2210 Inst::XmmRmRBlendVex {
2211 src1,
2212 src2,
2213 mask,
2214 dst,
2215 ..
2216 } => {
2217 collector.reg_def(dst);
2218 collector.reg_use(src1);
2219 src2.get_operands(collector);
2220 collector.reg_use(mask);
2221 }
2222 Inst::XmmRmREvex {
2223 op,
2224 src1,
2225 src2,
2226 dst,
2227 ..
2228 } => {
2229 assert_ne!(*op, Avx512Opcode::Vpermi2b);
2230 collector.reg_use(src1);
2231 src2.get_operands(collector);
2232 collector.reg_def(dst);
2233 }
2234 Inst::XmmRmREvex3 {
2235 op,
2236 src1,
2237 src2,
2238 src3,
2239 dst,
2240 ..
2241 } => {
2242 assert_eq!(*op, Avx512Opcode::Vpermi2b);
2243 collector.reg_use(src1);
2244 collector.reg_use(src2);
2245 src3.get_operands(collector);
2246 collector.reg_reuse_def(dst, 0); }
2248 Inst::XmmRmRImm {
2249 src1, src2, dst, ..
2250 } => {
2251 collector.reg_use(src1);
2252 collector.reg_reuse_def(dst, 0);
2253 src2.get_operands(collector);
2254 }
2255 Inst::XmmUninitializedValue { dst } => collector.reg_def(dst),
2256 Inst::GprUninitializedValue { dst } => collector.reg_def(dst),
2257 Inst::XmmMinMaxSeq { lhs, rhs, dst, .. } => {
2258 collector.reg_use(rhs);
2259 collector.reg_use(lhs);
2260 collector.reg_reuse_def(dst, 0); }
2262 Inst::XmmRmiReg {
2263 src1, src2, dst, ..
2264 } => {
2265 collector.reg_use(src1);
2266 collector.reg_reuse_def(dst, 0); src2.get_operands(collector);
2268 }
2269 Inst::XmmMovRM { src, dst, .. }
2270 | Inst::XmmMovRMVex { src, dst, .. }
2271 | Inst::XmmMovRMImm { src, dst, .. }
2272 | Inst::XmmMovRMImmVex { src, dst, .. } => {
2273 collector.reg_use(src);
2274 dst.get_operands(collector);
2275 }
2276 Inst::XmmCmpRmR { src1, src2, .. } => {
2277 collector.reg_use(src1);
2278 src2.get_operands(collector);
2279 }
2280 Inst::XmmCmpRmRVex { src1, src2, .. } => {
2281 collector.reg_use(src1);
2282 src2.get_operands(collector);
2283 }
2284 Inst::Imm { dst, .. } => {
2285 collector.reg_def(dst);
2286 }
2287 Inst::MovRR { src, dst, .. } => {
2288 collector.reg_use(src);
2289 collector.reg_def(dst);
2290 }
2291 Inst::MovFromPReg { dst, src } => {
2292 debug_assert!(dst.to_reg().to_reg().is_virtual());
2293 collector.reg_fixed_nonallocatable(*src);
2294 collector.reg_def(dst);
2295 }
2296 Inst::MovToPReg { dst, src } => {
2297 debug_assert!(src.to_reg().is_virtual());
2298 collector.reg_use(src);
2299 collector.reg_fixed_nonallocatable(*dst);
2300 }
2301 Inst::XmmToGpr { src, dst, .. }
2302 | Inst::XmmToGprVex { src, dst, .. }
2303 | Inst::XmmToGprImm { src, dst, .. }
2304 | Inst::XmmToGprImmVex { src, dst, .. } => {
2305 collector.reg_use(src);
2306 collector.reg_def(dst);
2307 }
2308 Inst::GprToXmm { src, dst, .. } | Inst::GprToXmmVex { src, dst, .. } => {
2309 collector.reg_def(dst);
2310 src.get_operands(collector);
2311 }
2312 Inst::CvtIntToFloat {
2313 src1, src2, dst, ..
2314 } => {
2315 collector.reg_use(src1);
2316 collector.reg_reuse_def(dst, 0);
2317 src2.get_operands(collector);
2318 }
2319 Inst::CvtIntToFloatVex {
2320 src1, src2, dst, ..
2321 } => {
2322 collector.reg_def(dst);
2323 collector.reg_use(src1);
2324 src2.get_operands(collector);
2325 }
2326 Inst::CvtUint64ToFloatSeq {
2327 src,
2328 dst,
2329 tmp_gpr1,
2330 tmp_gpr2,
2331 ..
2332 } => {
2333 collector.reg_use(src);
2334 collector.reg_early_def(dst);
2335 collector.reg_early_def(tmp_gpr1);
2336 collector.reg_early_def(tmp_gpr2);
2337 }
2338 Inst::CvtFloatToSintSeq {
2339 src,
2340 dst,
2341 tmp_xmm,
2342 tmp_gpr,
2343 ..
2344 } => {
2345 collector.reg_use(src);
2346 collector.reg_early_def(dst);
2347 collector.reg_early_def(tmp_gpr);
2348 collector.reg_early_def(tmp_xmm);
2349 }
2350 Inst::CvtFloatToUintSeq {
2351 src,
2352 dst,
2353 tmp_gpr,
2354 tmp_xmm,
2355 tmp_xmm2,
2356 ..
2357 } => {
2358 collector.reg_use(src);
2359 collector.reg_early_def(dst);
2360 collector.reg_early_def(tmp_gpr);
2361 collector.reg_early_def(tmp_xmm);
2362 collector.reg_early_def(tmp_xmm2);
2363 }
2364
2365 Inst::MovImmM { dst, .. } => {
2366 dst.get_operands(collector);
2367 }
2368
2369 Inst::MovzxRmR { src, dst, .. } => {
2370 collector.reg_def(dst);
2371 src.get_operands(collector);
2372 }
2373 Inst::Mov64MR { src, dst, .. } => {
2374 collector.reg_def(dst);
2375 src.get_operands(collector);
2376 }
2377 Inst::LoadEffectiveAddress { addr: src, dst, .. } => {
2378 collector.reg_def(dst);
2379 src.get_operands(collector);
2380 }
2381 Inst::MovsxRmR { src, dst, .. } => {
2382 collector.reg_def(dst);
2383 src.get_operands(collector);
2384 }
2385 Inst::MovRM { src, dst, .. } => {
2386 collector.reg_use(src);
2387 dst.get_operands(collector);
2388 }
2389 Inst::ShiftR {
2390 num_bits, src, dst, ..
2391 } => {
2392 collector.reg_use(src);
2393 collector.reg_reuse_def(dst, 0);
2394 if let Imm8Reg::Reg { reg } = num_bits.as_imm8_reg_mut() {
2395 collector.reg_fixed_use(reg, regs::rcx());
2396 }
2397 }
2398 Inst::CmpRmiR { src1, src2, .. } => {
2399 collector.reg_use(src1);
2400 src2.get_operands(collector);
2401 }
2402 Inst::Setcc { dst, .. } => {
2403 collector.reg_def(dst);
2404 }
2405 Inst::Bswap { src, dst, .. } => {
2406 collector.reg_use(src);
2407 collector.reg_reuse_def(dst, 0);
2408 }
2409 Inst::Cmove {
2410 consequent,
2411 alternative,
2412 dst,
2413 ..
2414 } => {
2415 collector.reg_use(alternative);
2416 collector.reg_reuse_def(dst, 0);
2417 consequent.get_operands(collector);
2418 }
2419 Inst::XmmCmove {
2420 consequent,
2421 alternative,
2422 dst,
2423 ..
2424 } => {
2425 collector.reg_use(alternative);
2426 collector.reg_reuse_def(dst, 0);
2427 collector.reg_use(consequent);
2428 }
2429 Inst::Push64 { src } => {
2430 src.get_operands(collector);
2431 }
2432 Inst::Pop64 { dst } => {
2433 collector.reg_def(dst);
2434 }
2435 Inst::StackProbeLoop { tmp, .. } => {
2436 collector.reg_early_def(tmp);
2437 }
2438
2439 Inst::CallKnown { info } => {
2440 let CallInfo {
2445 uses,
2446 defs,
2447 clobbers,
2448 dest,
2449 ..
2450 } = &mut **info;
2451 debug_assert_ne!(*dest, ExternalName::LibCall(LibCall::Probestack));
2452 for CallArgPair { vreg, preg } in uses {
2453 collector.reg_fixed_use(vreg, *preg);
2454 }
2455 for CallRetPair { vreg, location } in defs {
2456 match location {
2457 RetLocation::Reg(preg, ..) => collector.reg_fixed_def(vreg, *preg),
2458 RetLocation::Stack(..) => collector.any_def(vreg),
2459 }
2460 }
2461 collector.reg_clobbers(*clobbers);
2462 }
2463
2464 Inst::CallUnknown { info } => {
2465 let CallInfo {
2466 uses,
2467 defs,
2468 clobbers,
2469 callee_conv,
2470 dest,
2471 ..
2472 } = &mut **info;
2473 match dest {
2474 RegMem::Reg { reg } if *callee_conv == CallConv::Winch => {
2475 collector.reg_fixed_use(reg, regs::r10());
2479 }
2480 _ => dest.get_operands(collector),
2481 }
2482 for CallArgPair { vreg, preg } in uses {
2483 collector.reg_fixed_use(vreg, *preg);
2484 }
2485 for CallRetPair { vreg, location } in defs {
2486 match location {
2487 RetLocation::Reg(preg, ..) => collector.reg_fixed_def(vreg, *preg),
2488 RetLocation::Stack(..) => collector.any_def(vreg),
2489 }
2490 }
2491 collector.reg_clobbers(*clobbers);
2492 }
2493 Inst::StackSwitchBasic {
2494 store_context_ptr,
2495 load_context_ptr,
2496 in_payload0,
2497 out_payload0,
2498 } => {
2499 collector.reg_use(load_context_ptr);
2500 collector.reg_use(store_context_ptr);
2501 collector.reg_fixed_use(in_payload0, stack_switch::payload_register());
2502 collector.reg_fixed_def(out_payload0, stack_switch::payload_register());
2503
2504 let mut clobbers = crate::isa::x64::abi::ALL_CLOBBERS;
2505 clobbers.remove(
2507 stack_switch::payload_register()
2508 .to_real_reg()
2509 .unwrap()
2510 .into(),
2511 );
2512 collector.reg_clobbers(clobbers);
2513 }
2514
2515 Inst::ReturnCallKnown { info } => {
2516 let ReturnCallInfo {
2517 dest, uses, tmp, ..
2518 } = &mut **info;
2519 collector.reg_fixed_def(tmp, regs::r11());
2520 debug_assert_ne!(*dest, ExternalName::LibCall(LibCall::Probestack));
2522 for CallArgPair { vreg, preg } in uses {
2523 collector.reg_fixed_use(vreg, *preg);
2524 }
2525 }
2526
2527 Inst::ReturnCallUnknown { info } => {
2528 let ReturnCallInfo {
2529 dest, uses, tmp, ..
2530 } = &mut **info;
2531
2532 collector.reg_fixed_use(dest, regs::r10());
2538
2539 collector.reg_fixed_def(tmp, regs::r11());
2540 for CallArgPair { vreg, preg } in uses {
2541 collector.reg_fixed_use(vreg, *preg);
2542 }
2543 }
2544
2545 Inst::JmpTableSeq {
2546 idx, tmp1, tmp2, ..
2547 } => {
2548 collector.reg_use(idx);
2549 collector.reg_early_def(tmp1);
2550 collector.reg_def(tmp2);
2554 }
2555
2556 Inst::JmpUnknown { target } => {
2557 target.get_operands(collector);
2558 }
2559
2560 Inst::LoadExtName { dst, .. } => {
2561 collector.reg_def(dst);
2562 }
2563
2564 Inst::LockCmpxchg {
2565 replacement,
2566 expected,
2567 mem,
2568 dst_old,
2569 ..
2570 } => {
2571 collector.reg_use(replacement);
2572 collector.reg_fixed_use(expected, regs::rax());
2573 collector.reg_fixed_def(dst_old, regs::rax());
2574 mem.get_operands(collector);
2575 }
2576
2577 Inst::LockCmpxchg16b {
2578 replacement_low,
2579 replacement_high,
2580 expected_low,
2581 expected_high,
2582 mem,
2583 dst_old_low,
2584 dst_old_high,
2585 ..
2586 } => {
2587 collector.reg_fixed_use(replacement_low, regs::rbx());
2588 collector.reg_fixed_use(replacement_high, regs::rcx());
2589 collector.reg_fixed_use(expected_low, regs::rax());
2590 collector.reg_fixed_use(expected_high, regs::rdx());
2591 collector.reg_fixed_def(dst_old_low, regs::rax());
2592 collector.reg_fixed_def(dst_old_high, regs::rdx());
2593 mem.get_operands(collector);
2594 }
2595
2596 Inst::LockXadd {
2597 operand,
2598 mem,
2599 dst_old,
2600 ..
2601 } => {
2602 collector.reg_use(operand);
2603 collector.reg_reuse_def(dst_old, 0);
2604 mem.get_operands(collector);
2605 }
2606
2607 Inst::Xchg {
2608 operand,
2609 mem,
2610 dst_old,
2611 ..
2612 } => {
2613 collector.reg_use(operand);
2614 collector.reg_reuse_def(dst_old, 0);
2615 mem.get_operands(collector);
2616 }
2617
2618 Inst::AtomicRmwSeq {
2619 operand,
2620 temp,
2621 dst_old,
2622 mem,
2623 ..
2624 } => {
2625 collector.reg_late_use(operand);
2626 collector.reg_early_def(temp);
2627 collector.reg_fixed_def(dst_old, regs::rax());
2630 mem.get_operands_late(collector)
2631 }
2632
2633 Inst::Atomic128RmwSeq {
2634 operand_low,
2635 operand_high,
2636 temp_low,
2637 temp_high,
2638 dst_old_low,
2639 dst_old_high,
2640 mem,
2641 ..
2642 } => {
2643 collector.reg_late_use(operand_low);
2645 collector.reg_late_use(operand_high);
2646 collector.reg_fixed_def(temp_low, regs::rbx());
2647 collector.reg_fixed_def(temp_high, regs::rcx());
2648 collector.reg_fixed_def(dst_old_low, regs::rax());
2649 collector.reg_fixed_def(dst_old_high, regs::rdx());
2650 mem.get_operands_late(collector)
2651 }
2652
2653 Inst::Atomic128XchgSeq {
2654 operand_low,
2655 operand_high,
2656 dst_old_low,
2657 dst_old_high,
2658 mem,
2659 ..
2660 } => {
2661 collector.reg_fixed_late_use(operand_low, regs::rbx());
2663 collector.reg_fixed_late_use(operand_high, regs::rcx());
2664 collector.reg_fixed_def(dst_old_low, regs::rax());
2665 collector.reg_fixed_def(dst_old_high, regs::rdx());
2666 mem.get_operands_late(collector)
2667 }
2668
2669 Inst::Args { args } => {
2670 for ArgPair { vreg, preg } in args {
2671 collector.reg_fixed_def(vreg, *preg);
2672 }
2673 }
2674
2675 Inst::Rets { rets } => {
2676 for RetPair { vreg, preg } in rets {
2679 collector.reg_fixed_use(vreg, *preg);
2680 }
2681 }
2682
2683 Inst::JmpKnown { .. }
2684 | Inst::WinchJmpIf { .. }
2685 | Inst::JmpCond { .. }
2686 | Inst::JmpCondOr { .. }
2687 | Inst::Ret { .. }
2688 | Inst::Nop { .. }
2689 | Inst::TrapIf { .. }
2690 | Inst::TrapIfAnd { .. }
2691 | Inst::TrapIfOr { .. }
2692 | Inst::Hlt
2693 | Inst::Ud2 { .. }
2694 | Inst::Fence { .. } => {
2695 }
2697
2698 Inst::ElfTlsGetAddr { dst, .. } | Inst::MachOTlsGetAddr { dst, .. } => {
2699 collector.reg_fixed_def(dst, regs::rax());
2700 let mut clobbers =
2707 X64ABIMachineSpec::get_regs_clobbered_by_call(CallConv::SystemV, false);
2708 clobbers.remove(regs::gpr_preg(regs::ENC_RAX));
2709 collector.reg_clobbers(clobbers);
2710 }
2711
2712 Inst::CoffTlsGetAddr { dst, tmp, .. } => {
2713 collector.reg_fixed_def(dst, regs::rax());
2718
2719 collector.reg_fixed_def(tmp, regs::rcx());
2721 }
2722
2723 Inst::Unwind { .. } => {}
2724
2725 Inst::DummyUse { reg } => {
2726 collector.reg_use(reg);
2727 }
2728
2729 Inst::External { inst } => {
2730 inst.visit(&mut external::RegallocVisitor { collector });
2731 }
2732 }
2733}
2734
2735impl MachInst for Inst {
2739 type ABIMachineSpec = X64ABIMachineSpec;
2740
2741 fn get_operands(&mut self, collector: &mut impl OperandVisitor) {
2742 x64_get_operands(self, collector)
2743 }
2744
2745 fn is_move(&self) -> Option<(Writable<Reg>, Reg)> {
2746 match self {
2747 Self::MovRR { size, src, dst, .. } if *size == OperandSize::Size64 => {
2752 Some((dst.to_writable_reg(), src.to_reg()))
2753 }
2754 Self::XmmUnaryRmR { op, src, dst, .. }
2759 if *op == SseOpcode::Movss
2760 || *op == SseOpcode::Movsd
2761 || *op == SseOpcode::Movaps
2762 || *op == SseOpcode::Movapd
2763 || *op == SseOpcode::Movups
2764 || *op == SseOpcode::Movupd
2765 || *op == SseOpcode::Movdqa
2766 || *op == SseOpcode::Movdqu =>
2767 {
2768 if let RegMem::Reg { reg } = src.clone().to_reg_mem() {
2769 Some((dst.to_writable_reg(), reg))
2770 } else {
2771 None
2772 }
2773 }
2774 _ => None,
2775 }
2776 }
2777
2778 fn is_included_in_clobbers(&self) -> bool {
2779 match self {
2780 &Inst::Args { .. } => false,
2781 _ => true,
2782 }
2783 }
2784
2785 fn is_trap(&self) -> bool {
2786 match self {
2787 Self::Ud2 { .. } => true,
2788 _ => false,
2789 }
2790 }
2791
2792 fn is_args(&self) -> bool {
2793 match self {
2794 Self::Args { .. } => true,
2795 _ => false,
2796 }
2797 }
2798
2799 fn is_term(&self) -> MachTerminator {
2800 match self {
2801 &Self::Rets { .. } => MachTerminator::Ret,
2803 &Self::ReturnCallKnown { .. } | &Self::ReturnCallUnknown { .. } => {
2804 MachTerminator::RetCall
2805 }
2806 &Self::JmpKnown { .. } => MachTerminator::Branch,
2807 &Self::JmpCond { .. } => MachTerminator::Branch,
2808 &Self::JmpCondOr { .. } => MachTerminator::Branch,
2809 &Self::JmpTableSeq { .. } => MachTerminator::Branch,
2810 &Self::CallKnown { ref info } if info.try_call_info.is_some() => MachTerminator::Branch,
2811 &Self::CallUnknown { ref info } if info.try_call_info.is_some() => {
2812 MachTerminator::Branch
2813 }
2814 _ => MachTerminator::None,
2816 }
2817 }
2818
2819 fn is_low_level_branch(&self) -> bool {
2820 match self {
2821 &Self::WinchJmpIf { .. } => true,
2822 _ => false,
2823 }
2824 }
2825
2826 fn is_mem_access(&self) -> bool {
2827 panic!("TODO FILL ME OUT")
2828 }
2829
2830 fn gen_move(dst_reg: Writable<Reg>, src_reg: Reg, ty: Type) -> Inst {
2831 trace!(
2832 "Inst::gen_move {:?} -> {:?} (type: {:?})",
2833 src_reg,
2834 dst_reg.to_reg(),
2835 ty
2836 );
2837 let rc_dst = dst_reg.to_reg().class();
2838 let rc_src = src_reg.class();
2839 debug_assert!(rc_dst == rc_src);
2841 match rc_dst {
2842 RegClass::Int => Inst::mov_r_r(OperandSize::Size64, src_reg, dst_reg),
2843 RegClass::Float => {
2844 let opcode = match ty {
2849 types::F16 | types::F32 | types::F64 | types::F32X4 => SseOpcode::Movaps,
2850 types::F64X2 => SseOpcode::Movapd,
2851 _ if (ty.is_float() || ty.is_vector()) && ty.bits() <= 128 => SseOpcode::Movdqa,
2852 _ => unimplemented!("unable to move type: {}", ty),
2853 };
2854 Inst::xmm_unary_rm_r(opcode, RegMem::reg(src_reg), dst_reg)
2855 }
2856 RegClass::Vector => unreachable!(),
2857 }
2858 }
2859
2860 fn gen_nop(preferred_size: usize) -> Inst {
2861 Inst::nop(std::cmp::min(preferred_size, 15) as u8)
2862 }
2863
2864 fn rc_for_type(ty: Type) -> CodegenResult<(&'static [RegClass], &'static [Type])> {
2865 match ty {
2866 types::I8 => Ok((&[RegClass::Int], &[types::I8])),
2867 types::I16 => Ok((&[RegClass::Int], &[types::I16])),
2868 types::I32 => Ok((&[RegClass::Int], &[types::I32])),
2869 types::I64 => Ok((&[RegClass::Int], &[types::I64])),
2870 types::F16 => Ok((&[RegClass::Float], &[types::F16])),
2871 types::F32 => Ok((&[RegClass::Float], &[types::F32])),
2872 types::F64 => Ok((&[RegClass::Float], &[types::F64])),
2873 types::F128 => Ok((&[RegClass::Float], &[types::F128])),
2874 types::I128 => Ok((&[RegClass::Int, RegClass::Int], &[types::I64, types::I64])),
2875 _ if ty.is_vector() && ty.bits() <= 128 => {
2876 let types = &[types::I8X2, types::I8X4, types::I8X8, types::I8X16];
2877 Ok((
2878 &[RegClass::Float],
2879 slice::from_ref(&types[ty.bytes().ilog2() as usize - 1]),
2880 ))
2881 }
2882 _ => Err(CodegenError::Unsupported(format!(
2883 "Unexpected SSA-value type: {ty}"
2884 ))),
2885 }
2886 }
2887
2888 fn canonical_type_for_rc(rc: RegClass) -> Type {
2889 match rc {
2890 RegClass::Float => types::I8X16,
2891 RegClass::Int => types::I64,
2892 RegClass::Vector => unreachable!(),
2893 }
2894 }
2895
2896 fn gen_jump(label: MachLabel) -> Inst {
2897 Inst::jmp_known(label)
2898 }
2899
2900 fn gen_imm_u64(value: u64, dst: Writable<Reg>) -> Option<Self> {
2901 Some(Inst::imm(OperandSize::Size64, value, dst))
2902 }
2903
2904 fn gen_imm_f64(value: f64, tmp: Writable<Reg>, dst: Writable<Reg>) -> SmallVec<[Self; 2]> {
2905 let imm_to_gpr = Inst::imm(OperandSize::Size64, value.to_bits(), tmp);
2906 let gpr_to_xmm = Self::gpr_to_xmm(
2907 SseOpcode::Movd,
2908 tmp.to_reg().into(),
2909 OperandSize::Size64,
2910 dst,
2911 );
2912 smallvec![imm_to_gpr, gpr_to_xmm]
2913 }
2914
2915 fn gen_dummy_use(reg: Reg) -> Self {
2916 Inst::DummyUse { reg }
2917 }
2918
2919 fn worst_case_size() -> CodeOffset {
2920 15
2921 }
2922
2923 fn ref_type_regclass(_: &settings::Flags) -> RegClass {
2924 RegClass::Int
2925 }
2926
2927 fn is_safepoint(&self) -> bool {
2928 match self {
2929 Inst::CallKnown { .. } | Inst::CallUnknown { .. } => true,
2930 _ => false,
2931 }
2932 }
2933
2934 fn function_alignment() -> FunctionAlignment {
2935 FunctionAlignment {
2936 minimum: 1,
2937 preferred: 32,
2940 }
2941 }
2942
2943 type LabelUse = LabelUse;
2944
2945 const TRAP_OPCODE: &'static [u8] = &[0x0f, 0x0b];
2946}
2947
2948pub struct EmitInfo {
2950 pub(super) flags: settings::Flags,
2951 isa_flags: x64_settings::Flags,
2952}
2953
2954impl EmitInfo {
2955 pub fn new(flags: settings::Flags, isa_flags: x64_settings::Flags) -> Self {
2957 Self { flags, isa_flags }
2958 }
2959}
2960
2961impl MachInstEmit for Inst {
2962 type State = EmitState;
2963 type Info = EmitInfo;
2964
2965 fn emit(&self, sink: &mut MachBuffer<Inst>, info: &Self::Info, state: &mut Self::State) {
2966 emit::emit(self, sink, info, state);
2967 }
2968
2969 fn pretty_print_inst(&self, _: &mut Self::State) -> String {
2970 PrettyPrint::pretty_print(self, 0)
2971 }
2972}
2973
2974#[derive(Clone, Copy, Debug, PartialEq, Eq)]
2976pub enum LabelUse {
2977 JmpRel32,
2981
2982 PCRel32,
2985}
2986
2987impl MachInstLabelUse for LabelUse {
2988 const ALIGN: CodeOffset = 1;
2989
2990 fn max_pos_range(self) -> CodeOffset {
2991 match self {
2992 LabelUse::JmpRel32 | LabelUse::PCRel32 => 0x7fff_ffff,
2993 }
2994 }
2995
2996 fn max_neg_range(self) -> CodeOffset {
2997 match self {
2998 LabelUse::JmpRel32 | LabelUse::PCRel32 => 0x8000_0000,
2999 }
3000 }
3001
3002 fn patch_size(self) -> CodeOffset {
3003 match self {
3004 LabelUse::JmpRel32 | LabelUse::PCRel32 => 4,
3005 }
3006 }
3007
3008 fn patch(self, buffer: &mut [u8], use_offset: CodeOffset, label_offset: CodeOffset) {
3009 let pc_rel = (label_offset as i64) - (use_offset as i64);
3010 debug_assert!(pc_rel <= self.max_pos_range() as i64);
3011 debug_assert!(pc_rel >= -(self.max_neg_range() as i64));
3012 let pc_rel = pc_rel as u32;
3013 match self {
3014 LabelUse::JmpRel32 => {
3015 let addend = u32::from_le_bytes([buffer[0], buffer[1], buffer[2], buffer[3]]);
3016 let value = pc_rel.wrapping_add(addend).wrapping_sub(4);
3017 buffer.copy_from_slice(&value.to_le_bytes()[..]);
3018 }
3019 LabelUse::PCRel32 => {
3020 let addend = u32::from_le_bytes([buffer[0], buffer[1], buffer[2], buffer[3]]);
3021 let value = pc_rel.wrapping_add(addend);
3022 buffer.copy_from_slice(&value.to_le_bytes()[..]);
3023 }
3024 }
3025 }
3026
3027 fn supports_veneer(self) -> bool {
3028 match self {
3029 LabelUse::JmpRel32 | LabelUse::PCRel32 => false,
3030 }
3031 }
3032
3033 fn veneer_size(self) -> CodeOffset {
3034 match self {
3035 LabelUse::JmpRel32 | LabelUse::PCRel32 => 0,
3036 }
3037 }
3038
3039 fn worst_case_veneer_size() -> CodeOffset {
3040 0
3041 }
3042
3043 fn generate_veneer(self, _: &mut [u8], _: CodeOffset) -> (CodeOffset, LabelUse) {
3044 match self {
3045 LabelUse::JmpRel32 | LabelUse::PCRel32 => {
3046 panic!("Veneer not supported for JumpRel32 label-use.");
3047 }
3048 }
3049 }
3050
3051 fn from_reloc(reloc: Reloc, addend: Addend) -> Option<Self> {
3052 match (reloc, addend) {
3053 (Reloc::X86CallPCRel4, -4) => Some(LabelUse::JmpRel32),
3054 _ => None,
3055 }
3056 }
3057}