1 //! This module defines s390x-specific machine instruction types.
2 
3 use crate::binemit::{Addend, CodeOffset, Reloc};
4 use crate::ir::{ExternalName, Type, types};
5 use crate::isa::s390x::abi::S390xMachineDeps;
6 use crate::isa::{CallConv, FunctionAlignment};
7 use crate::machinst::*;
8 use crate::{CodegenError, CodegenResult, settings};
9 use alloc::boxed::Box;
10 use alloc::string::{String, ToString};
11 use alloc::vec::Vec;
12 use core::fmt::Write;
13 use smallvec::SmallVec;
14 pub mod regs;
15 pub use self::regs::*;
16 pub mod imms;
17 pub use self::imms::*;
18 pub mod args;
19 pub use self::args::*;
20 pub mod emit;
21 pub use self::emit::*;
22 pub mod unwind;
23 
24 #[cfg(test)]
25 mod emit_tests;
26 
27 //=============================================================================
28 // Instructions (top level): definition
29 
30 pub use crate::isa::s390x::lower::isle::generated_code::{
31     ALUOp, CmpOp, FPUOp1, FPUOp2, FPUOp3, FpuConv128Op, FpuRoundMode, FpuRoundOp, LaneOrder,
32     MInst as Inst, RxSBGOp, ShiftOp, SymbolReloc, UnaryOp, VecBinaryOp, VecFloatCmpOp, VecIntCmpOp,
33     VecIntEltCmpOp, VecShiftOp, VecUnaryOp,
34 };
35 
36 /// The destination of a call instruction.
37 #[derive(Clone, Debug)]
38 pub enum CallInstDest {
39     /// Direct call.
40     Direct { name: ExternalName },
41     /// Indirect call.
42     Indirect { reg: Reg },
43 }
44 
45 /// Additional information for (direct) ReturnCall instructions, left out of line to lower the size of
46 /// the Inst enum.
47 #[derive(Clone, Debug)]
48 pub struct ReturnCallInfo<T> {
49     pub dest: T,
50     pub uses: CallArgList,
51     pub callee_pop_size: u32,
52 }
53 
54 #[test]
inst_size_test()55 fn inst_size_test() {
56     // This test will help with unintentionally growing the size
57     // of the Inst enum.
58     assert_eq!(32, core::mem::size_of::<Inst>());
59 }
60 
61 /// A register pair. Enum so it can be destructured in ISLE.
62 #[derive(Clone, Copy, Debug)]
63 pub struct RegPair {
64     pub hi: Reg,
65     pub lo: Reg,
66 }
67 
68 /// A writable register pair. Enum so it can be destructured in ISLE.
69 #[derive(Clone, Copy, Debug)]
70 pub struct WritableRegPair {
71     pub hi: Writable<Reg>,
72     pub lo: Writable<Reg>,
73 }
74 
75 impl WritableRegPair {
to_regpair(&self) -> RegPair76     pub fn to_regpair(&self) -> RegPair {
77         RegPair {
78             hi: self.hi.to_reg(),
79             lo: self.lo.to_reg(),
80         }
81     }
82 }
83 
84 /// Supported instruction sets
85 #[expect(non_camel_case_types, reason = "matching native names")]
86 #[derive(Debug)]
87 pub(crate) enum InstructionSet {
88     /// Baseline ISA for cranelift is z14.
89     Base,
90     /// Miscellaneous-Instruction-Extensions Facility 3 (z15)
91     MIE3,
92     /// Miscellaneous-Instruction-Extensions Facility 4 (z17)
93     MIE4,
94     /// Vector-Enhancements Facility 2 (z15)
95     VXRS_EXT2,
96     /// Vector-Enhancements Facility 3 (z17)
97     VXRS_EXT3,
98 }
99 
100 impl Inst {
101     /// Retrieve the ISA feature set in which the instruction is available.
available_in_isa(&self) -> InstructionSet102     fn available_in_isa(&self) -> InstructionSet {
103         match self {
104             // These instructions are part of the baseline ISA for cranelift (z14)
105             Inst::Nop0
106             | Inst::Nop2
107             | Inst::AluRRSImm16 { .. }
108             | Inst::AluRR { .. }
109             | Inst::AluRX { .. }
110             | Inst::AluRSImm16 { .. }
111             | Inst::AluRSImm32 { .. }
112             | Inst::AluRUImm32 { .. }
113             | Inst::AluRUImm16Shifted { .. }
114             | Inst::AluRUImm32Shifted { .. }
115             | Inst::ShiftRR { .. }
116             | Inst::RxSBG { .. }
117             | Inst::RxSBGTest { .. }
118             | Inst::SMulWide { .. }
119             | Inst::UMulWide { .. }
120             | Inst::SDivMod32 { .. }
121             | Inst::SDivMod64 { .. }
122             | Inst::UDivMod32 { .. }
123             | Inst::UDivMod64 { .. }
124             | Inst::Flogr { .. }
125             | Inst::CmpRR { .. }
126             | Inst::CmpRX { .. }
127             | Inst::CmpRSImm16 { .. }
128             | Inst::CmpRSImm32 { .. }
129             | Inst::CmpRUImm32 { .. }
130             | Inst::CmpTrapRR { .. }
131             | Inst::CmpTrapRSImm16 { .. }
132             | Inst::CmpTrapRUImm16 { .. }
133             | Inst::AtomicRmw { .. }
134             | Inst::AtomicCas32 { .. }
135             | Inst::AtomicCas64 { .. }
136             | Inst::Fence
137             | Inst::Load32 { .. }
138             | Inst::Load32ZExt8 { .. }
139             | Inst::Load32SExt8 { .. }
140             | Inst::Load32ZExt16 { .. }
141             | Inst::Load32SExt16 { .. }
142             | Inst::Load64 { .. }
143             | Inst::Load64ZExt8 { .. }
144             | Inst::Load64SExt8 { .. }
145             | Inst::Load64ZExt16 { .. }
146             | Inst::Load64SExt16 { .. }
147             | Inst::Load64ZExt32 { .. }
148             | Inst::Load64SExt32 { .. }
149             | Inst::LoadRev16 { .. }
150             | Inst::LoadRev32 { .. }
151             | Inst::LoadRev64 { .. }
152             | Inst::Store8 { .. }
153             | Inst::Store16 { .. }
154             | Inst::Store32 { .. }
155             | Inst::Store64 { .. }
156             | Inst::StoreImm8 { .. }
157             | Inst::StoreImm16 { .. }
158             | Inst::StoreImm32SExt16 { .. }
159             | Inst::StoreImm64SExt16 { .. }
160             | Inst::StoreRev16 { .. }
161             | Inst::StoreRev32 { .. }
162             | Inst::StoreRev64 { .. }
163             | Inst::LoadMultiple64 { .. }
164             | Inst::StoreMultiple64 { .. }
165             | Inst::Mov32 { .. }
166             | Inst::Mov64 { .. }
167             | Inst::MovPReg { .. }
168             | Inst::Mov32Imm { .. }
169             | Inst::Mov32SImm16 { .. }
170             | Inst::Mov64SImm16 { .. }
171             | Inst::Mov64SImm32 { .. }
172             | Inst::Mov64UImm16Shifted { .. }
173             | Inst::Mov64UImm32Shifted { .. }
174             | Inst::Insert64UImm16Shifted { .. }
175             | Inst::Insert64UImm32Shifted { .. }
176             | Inst::LoadAR { .. }
177             | Inst::InsertAR { .. }
178             | Inst::Extend { .. }
179             | Inst::CMov32 { .. }
180             | Inst::CMov64 { .. }
181             | Inst::CMov32SImm16 { .. }
182             | Inst::CMov64SImm16 { .. }
183             | Inst::FpuMove32 { .. }
184             | Inst::FpuMove64 { .. }
185             | Inst::FpuCMov32 { .. }
186             | Inst::FpuCMov64 { .. }
187             | Inst::FpuRR { .. }
188             | Inst::FpuRRR { .. }
189             | Inst::FpuRRRR { .. }
190             | Inst::FpuConv128FromInt { .. }
191             | Inst::FpuConv128ToInt { .. }
192             | Inst::FpuCmp32 { .. }
193             | Inst::FpuCmp64 { .. }
194             | Inst::FpuCmp128 { .. }
195             | Inst::VecShiftRR { .. }
196             | Inst::VecSelect { .. }
197             | Inst::VecPermute { .. }
198             | Inst::VecPermuteDWImm { .. }
199             | Inst::VecFloatCmp { .. }
200             | Inst::VecFloatCmpS { .. }
201             | Inst::VecInt128SCmpHi { .. }
202             | Inst::VecInt128UCmpHi { .. }
203             | Inst::VecLoad { .. }
204             | Inst::VecStore { .. }
205             | Inst::VecLoadReplicate { .. }
206             | Inst::VecMov { .. }
207             | Inst::VecCMov { .. }
208             | Inst::MovToVec128 { .. }
209             | Inst::VecImmByteMask { .. }
210             | Inst::VecImmBitMask { .. }
211             | Inst::VecImmReplicate { .. }
212             | Inst::VecLoadLane { .. }
213             | Inst::VecLoadLaneUndef { .. }
214             | Inst::VecStoreLane { .. }
215             | Inst::VecInsertLane { .. }
216             | Inst::VecInsertLaneUndef { .. }
217             | Inst::VecExtractLane { .. }
218             | Inst::VecInsertLaneImm { .. }
219             | Inst::VecInsertLaneImmUndef { .. }
220             | Inst::VecReplicateLane { .. }
221             | Inst::VecEltRev { .. }
222             | Inst::AllocateArgs { .. }
223             | Inst::Call { .. }
224             | Inst::ReturnCall { .. }
225             | Inst::Args { .. }
226             | Inst::Rets { .. }
227             | Inst::Ret { .. }
228             | Inst::Jump { .. }
229             | Inst::CondBr { .. }
230             | Inst::TrapIf { .. }
231             | Inst::IndirectBr { .. }
232             | Inst::Debugtrap
233             | Inst::Trap { .. }
234             | Inst::JTSequence { .. }
235             | Inst::StackProbeLoop { .. }
236             | Inst::LoadSymbolReloc { .. }
237             | Inst::LoadAddr { .. }
238             | Inst::Loop { .. }
239             | Inst::CondBreak { .. }
240             | Inst::Unwind { .. }
241             | Inst::ElfTlsGetOffset { .. } => InstructionSet::Base,
242 
243             // These depend on the opcode
244             Inst::AluRRR { alu_op, .. } => match alu_op {
245                 ALUOp::NotAnd32 | ALUOp::NotAnd64 => InstructionSet::MIE3,
246                 ALUOp::NotOrr32 | ALUOp::NotOrr64 => InstructionSet::MIE3,
247                 ALUOp::NotXor32 | ALUOp::NotXor64 => InstructionSet::MIE3,
248                 ALUOp::AndNot32 | ALUOp::AndNot64 => InstructionSet::MIE3,
249                 ALUOp::OrrNot32 | ALUOp::OrrNot64 => InstructionSet::MIE3,
250                 _ => InstructionSet::Base,
251             },
252             Inst::UnaryRR { op, .. } => match op {
253                 UnaryOp::PopcntReg => InstructionSet::MIE3,
254                 UnaryOp::Clz64 | UnaryOp::Ctz64 => InstructionSet::MIE4,
255                 _ => InstructionSet::Base,
256             },
257             Inst::FpuRound { op, .. } => match op {
258                 FpuRoundOp::ToSInt32 | FpuRoundOp::FromSInt32 => InstructionSet::VXRS_EXT2,
259                 FpuRoundOp::ToUInt32 | FpuRoundOp::FromUInt32 => InstructionSet::VXRS_EXT2,
260                 FpuRoundOp::ToSInt32x4 | FpuRoundOp::FromSInt32x4 => InstructionSet::VXRS_EXT2,
261                 FpuRoundOp::ToUInt32x4 | FpuRoundOp::FromUInt32x4 => InstructionSet::VXRS_EXT2,
262                 _ => InstructionSet::Base,
263             },
264             Inst::VecRRR { op, .. } => match op {
265                 VecBinaryOp::Mul64x2 | VecBinaryOp::Mul128 => InstructionSet::VXRS_EXT3,
266                 VecBinaryOp::UMulHi64x2 | VecBinaryOp::UMulHi128 => InstructionSet::VXRS_EXT3,
267                 VecBinaryOp::SMulHi64x2 | VecBinaryOp::SMulHi128 => InstructionSet::VXRS_EXT3,
268                 VecBinaryOp::UMulEven64x2 | VecBinaryOp::SMulEven64x2 => InstructionSet::VXRS_EXT3,
269                 VecBinaryOp::UMulOdd64x2 | VecBinaryOp::SMulOdd64x2 => InstructionSet::VXRS_EXT3,
270                 VecBinaryOp::UDiv32x4 | VecBinaryOp::SDiv32x4 => InstructionSet::VXRS_EXT3,
271                 VecBinaryOp::UDiv64x2 | VecBinaryOp::SDiv64x2 => InstructionSet::VXRS_EXT3,
272                 VecBinaryOp::UDiv128 | VecBinaryOp::SDiv128 => InstructionSet::VXRS_EXT3,
273                 VecBinaryOp::URem32x4 | VecBinaryOp::SRem32x4 => InstructionSet::VXRS_EXT3,
274                 VecBinaryOp::URem64x2 | VecBinaryOp::SRem64x2 => InstructionSet::VXRS_EXT3,
275                 VecBinaryOp::URem128 | VecBinaryOp::SRem128 => InstructionSet::VXRS_EXT3,
276                 VecBinaryOp::UMax128 | VecBinaryOp::SMax128 => InstructionSet::VXRS_EXT3,
277                 VecBinaryOp::UMin128 | VecBinaryOp::SMin128 => InstructionSet::VXRS_EXT3,
278                 VecBinaryOp::UAvg128 | VecBinaryOp::SAvg128 => InstructionSet::VXRS_EXT3,
279                 _ => InstructionSet::Base,
280             },
281             &Inst::VecRR { op, .. } => match op {
282                 VecUnaryOp::Abs128 | VecUnaryOp::Neg128 => InstructionSet::VXRS_EXT3,
283                 VecUnaryOp::Clz128 | VecUnaryOp::Ctz128 => InstructionSet::VXRS_EXT3,
284                 VecUnaryOp::UnpackULow64x2 => InstructionSet::VXRS_EXT3,
285                 VecUnaryOp::UnpackUHigh64x2 => InstructionSet::VXRS_EXT3,
286                 VecUnaryOp::UnpackSLow64x2 => InstructionSet::VXRS_EXT3,
287                 VecUnaryOp::UnpackSHigh64x2 => InstructionSet::VXRS_EXT3,
288                 _ => InstructionSet::Base,
289             },
290             &Inst::VecIntCmp { op, .. } | &Inst::VecIntCmpS { op, .. } => match op {
291                 VecIntCmpOp::CmpEq128 => InstructionSet::VXRS_EXT3,
292                 VecIntCmpOp::SCmpHi128 => InstructionSet::VXRS_EXT3,
293                 VecIntCmpOp::UCmpHi128 => InstructionSet::VXRS_EXT3,
294                 _ => InstructionSet::Base,
295             },
296             &Inst::VecIntEltCmp { op, .. } => match op {
297                 VecIntEltCmpOp::SCmp128 => InstructionSet::VXRS_EXT3,
298                 VecIntEltCmpOp::UCmp128 => InstructionSet::VXRS_EXT3,
299                 // We do not use any of the pre-z17 variants of these instructions.
300             },
301 
302             // These are all part of VXRS_EXT2
303             Inst::VecLoadRev { .. }
304             | Inst::VecLoadByte16Rev { .. }
305             | Inst::VecLoadByte32Rev { .. }
306             | Inst::VecLoadByte64Rev { .. }
307             | Inst::VecLoadElt16Rev { .. }
308             | Inst::VecLoadElt32Rev { .. }
309             | Inst::VecLoadElt64Rev { .. }
310             | Inst::VecStoreRev { .. }
311             | Inst::VecStoreByte16Rev { .. }
312             | Inst::VecStoreByte32Rev { .. }
313             | Inst::VecStoreByte64Rev { .. }
314             | Inst::VecStoreElt16Rev { .. }
315             | Inst::VecStoreElt32Rev { .. }
316             | Inst::VecStoreElt64Rev { .. }
317             | Inst::VecLoadReplicateRev { .. }
318             | Inst::VecLoadLaneRev { .. }
319             | Inst::VecLoadLaneRevUndef { .. }
320             | Inst::VecStoreLaneRev { .. } => InstructionSet::VXRS_EXT2,
321 
322             Inst::VecBlend { .. } | Inst::VecEvaluate { .. } => InstructionSet::VXRS_EXT3,
323 
324             Inst::DummyUse { .. } => InstructionSet::Base,
325 
326             Inst::LabelAddress { .. } => InstructionSet::Base,
327 
328             Inst::SequencePoint { .. } => InstructionSet::Base,
329         }
330     }
331 
332     /// Create a 128-bit move instruction.
mov128(to_reg: Writable<Reg>, from_reg: Reg) -> Inst333     pub fn mov128(to_reg: Writable<Reg>, from_reg: Reg) -> Inst {
334         assert!(to_reg.to_reg().class() == RegClass::Float);
335         assert!(from_reg.class() == RegClass::Float);
336         Inst::VecMov {
337             rd: to_reg,
338             rn: from_reg,
339         }
340     }
341 
342     /// Create a 64-bit move instruction.
mov64(to_reg: Writable<Reg>, from_reg: Reg) -> Inst343     pub fn mov64(to_reg: Writable<Reg>, from_reg: Reg) -> Inst {
344         assert!(to_reg.to_reg().class() == from_reg.class());
345         if from_reg.class() == RegClass::Int {
346             Inst::Mov64 {
347                 rd: to_reg,
348                 rm: from_reg,
349             }
350         } else {
351             Inst::FpuMove64 {
352                 rd: to_reg,
353                 rn: from_reg,
354             }
355         }
356     }
357 
358     /// Create a 32-bit move instruction.
mov32(to_reg: Writable<Reg>, from_reg: Reg) -> Inst359     pub fn mov32(to_reg: Writable<Reg>, from_reg: Reg) -> Inst {
360         if from_reg.class() == RegClass::Int {
361             Inst::Mov32 {
362                 rd: to_reg,
363                 rm: from_reg,
364             }
365         } else {
366             Inst::FpuMove32 {
367                 rd: to_reg,
368                 rn: from_reg,
369             }
370         }
371     }
372 
373     /// Generic constructor for a load (zero-extending where appropriate).
gen_load(into_reg: Writable<Reg>, mem: MemArg, ty: Type) -> Inst374     pub fn gen_load(into_reg: Writable<Reg>, mem: MemArg, ty: Type) -> Inst {
375         match ty {
376             types::I8 => Inst::Load64ZExt8 { rd: into_reg, mem },
377             types::I16 => Inst::Load64ZExt16 { rd: into_reg, mem },
378             types::I32 => Inst::Load64ZExt32 { rd: into_reg, mem },
379             types::I64 => Inst::Load64 { rd: into_reg, mem },
380             types::F16 => Inst::VecLoadLaneUndef {
381                 size: 16,
382                 rd: into_reg,
383                 mem,
384                 lane_imm: 0,
385             },
386             types::F32 => Inst::VecLoadLaneUndef {
387                 size: 32,
388                 rd: into_reg,
389                 mem,
390                 lane_imm: 0,
391             },
392             types::F64 => Inst::VecLoadLaneUndef {
393                 size: 64,
394                 rd: into_reg,
395                 mem,
396                 lane_imm: 0,
397             },
398             _ if ty.bits() == 128 => Inst::VecLoad { rd: into_reg, mem },
399             _ => unimplemented!("gen_load({})", ty),
400         }
401     }
402 
403     /// Generic constructor for a store.
gen_store(mem: MemArg, from_reg: Reg, ty: Type) -> Inst404     pub fn gen_store(mem: MemArg, from_reg: Reg, ty: Type) -> Inst {
405         match ty {
406             types::I8 => Inst::Store8 { rd: from_reg, mem },
407             types::I16 => Inst::Store16 { rd: from_reg, mem },
408             types::I32 => Inst::Store32 { rd: from_reg, mem },
409             types::I64 => Inst::Store64 { rd: from_reg, mem },
410             types::F16 => Inst::VecStoreLane {
411                 size: 16,
412                 rd: from_reg,
413                 mem,
414                 lane_imm: 0,
415             },
416             types::F32 => Inst::VecStoreLane {
417                 size: 32,
418                 rd: from_reg,
419                 mem,
420                 lane_imm: 0,
421             },
422             types::F64 => Inst::VecStoreLane {
423                 size: 64,
424                 rd: from_reg,
425                 mem,
426                 lane_imm: 0,
427             },
428             _ if ty.bits() == 128 => Inst::VecStore { rd: from_reg, mem },
429             _ => unimplemented!("gen_store({})", ty),
430         }
431     }
432 }
433 
434 //=============================================================================
435 // Instructions: get_regs
436 
memarg_operands(memarg: &mut MemArg, collector: &mut impl OperandVisitor)437 fn memarg_operands(memarg: &mut MemArg, collector: &mut impl OperandVisitor) {
438     match memarg {
439         MemArg::BXD12 { base, index, .. } | MemArg::BXD20 { base, index, .. } => {
440             collector.reg_use(base);
441             collector.reg_use(index);
442         }
443         MemArg::Label { .. } | MemArg::Constant { .. } | MemArg::Symbol { .. } => {}
444         MemArg::RegOffset { reg, .. } => {
445             collector.reg_use(reg);
446         }
447         MemArg::InitialSPOffset { .. }
448         | MemArg::IncomingArgOffset { .. }
449         | MemArg::OutgoingArgOffset { .. }
450         | MemArg::SlotOffset { .. }
451         | MemArg::SpillOffset { .. } => {}
452     }
453     // mem_finalize might require %r1 to hold (part of) the address.
454     // Conservatively assume this will always be necessary here.
455     collector.reg_fixed_nonallocatable(gpr_preg(1));
456 }
457 
s390x_get_operands(inst: &mut Inst, collector: &mut DenyReuseVisitor<impl OperandVisitor>)458 fn s390x_get_operands(inst: &mut Inst, collector: &mut DenyReuseVisitor<impl OperandVisitor>) {
459     match inst {
460         Inst::AluRRR { rd, rn, rm, .. } => {
461             collector.reg_def(rd);
462             collector.reg_use(rn);
463             collector.reg_use(rm);
464         }
465         Inst::AluRRSImm16 { rd, rn, .. } => {
466             collector.reg_def(rd);
467             collector.reg_use(rn);
468         }
469         Inst::AluRR { rd, ri, rm, .. } => {
470             collector.reg_reuse_def(rd, 1);
471             collector.reg_use(ri);
472             collector.reg_use(rm);
473         }
474         Inst::AluRX { rd, ri, mem, .. } => {
475             collector.reg_reuse_def(rd, 1);
476             collector.reg_use(ri);
477             memarg_operands(mem, collector);
478         }
479         Inst::AluRSImm16 { rd, ri, .. } => {
480             collector.reg_reuse_def(rd, 1);
481             collector.reg_use(ri);
482         }
483         Inst::AluRSImm32 { rd, ri, .. } => {
484             collector.reg_reuse_def(rd, 1);
485             collector.reg_use(ri);
486         }
487         Inst::AluRUImm32 { rd, ri, .. } => {
488             collector.reg_reuse_def(rd, 1);
489             collector.reg_use(ri);
490         }
491         Inst::AluRUImm16Shifted { rd, ri, .. } => {
492             collector.reg_reuse_def(rd, 1);
493             collector.reg_use(ri);
494         }
495         Inst::AluRUImm32Shifted { rd, ri, .. } => {
496             collector.reg_reuse_def(rd, 1);
497             collector.reg_use(ri);
498         }
499         Inst::SMulWide { rd, rn, rm } => {
500             collector.reg_use(rn);
501             collector.reg_use(rm);
502             // FIXME: The pair is hard-coded as %r2/%r3 because regalloc cannot handle pairs. If
503             // that changes, all the hard-coded uses of %r2/%r3 can be changed.
504             collector.reg_fixed_def(&mut rd.hi, gpr(2));
505             collector.reg_fixed_def(&mut rd.lo, gpr(3));
506         }
507         Inst::UMulWide { rd, ri, rn } => {
508             collector.reg_use(rn);
509             collector.reg_fixed_def(&mut rd.hi, gpr(2));
510             collector.reg_fixed_def(&mut rd.lo, gpr(3));
511             collector.reg_fixed_use(ri, gpr(3));
512         }
513         Inst::SDivMod32 { rd, ri, rn } | Inst::SDivMod64 { rd, ri, rn } => {
514             collector.reg_use(rn);
515             collector.reg_fixed_def(&mut rd.hi, gpr(2));
516             collector.reg_fixed_def(&mut rd.lo, gpr(3));
517             collector.reg_fixed_use(ri, gpr(3));
518         }
519         Inst::UDivMod32 { rd, ri, rn } | Inst::UDivMod64 { rd, ri, rn } => {
520             collector.reg_use(rn);
521             collector.reg_fixed_def(&mut rd.hi, gpr(2));
522             collector.reg_fixed_def(&mut rd.lo, gpr(3));
523             collector.reg_fixed_use(&mut ri.hi, gpr(2));
524             collector.reg_fixed_use(&mut ri.lo, gpr(3));
525         }
526         Inst::Flogr { rd, rn } => {
527             collector.reg_use(rn);
528             collector.reg_fixed_def(&mut rd.hi, gpr(2));
529             collector.reg_fixed_def(&mut rd.lo, gpr(3));
530         }
531         Inst::ShiftRR {
532             rd, rn, shift_reg, ..
533         } => {
534             collector.reg_def(rd);
535             collector.reg_use(rn);
536             collector.reg_use(shift_reg);
537         }
538         Inst::RxSBG { rd, ri, rn, .. } => {
539             collector.reg_reuse_def(rd, 1);
540             collector.reg_use(ri);
541             collector.reg_use(rn);
542         }
543         Inst::RxSBGTest { rd, rn, .. } => {
544             collector.reg_use(rd);
545             collector.reg_use(rn);
546         }
547         Inst::UnaryRR { rd, rn, .. } => {
548             collector.reg_def(rd);
549             collector.reg_use(rn);
550         }
551         Inst::CmpRR { rn, rm, .. } => {
552             collector.reg_use(rn);
553             collector.reg_use(rm);
554         }
555         Inst::CmpRX { rn, mem, .. } => {
556             collector.reg_use(rn);
557             memarg_operands(mem, collector);
558         }
559         Inst::CmpRSImm16 { rn, .. } => {
560             collector.reg_use(rn);
561         }
562         Inst::CmpRSImm32 { rn, .. } => {
563             collector.reg_use(rn);
564         }
565         Inst::CmpRUImm32 { rn, .. } => {
566             collector.reg_use(rn);
567         }
568         Inst::CmpTrapRR { rn, rm, .. } => {
569             collector.reg_use(rn);
570             collector.reg_use(rm);
571         }
572         Inst::CmpTrapRSImm16 { rn, .. } => {
573             collector.reg_use(rn);
574         }
575         Inst::CmpTrapRUImm16 { rn, .. } => {
576             collector.reg_use(rn);
577         }
578         Inst::AtomicRmw { rd, rn, mem, .. } => {
579             collector.reg_def(rd);
580             collector.reg_use(rn);
581             memarg_operands(mem, collector);
582         }
583         Inst::AtomicCas32 {
584             rd, ri, rn, mem, ..
585         }
586         | Inst::AtomicCas64 {
587             rd, ri, rn, mem, ..
588         } => {
589             collector.reg_reuse_def(rd, 1);
590             collector.reg_use(ri);
591             collector.reg_use(rn);
592             memarg_operands(mem, collector);
593         }
594         Inst::Fence => {}
595         Inst::Load32 { rd, mem, .. }
596         | Inst::Load32ZExt8 { rd, mem, .. }
597         | Inst::Load32SExt8 { rd, mem, .. }
598         | Inst::Load32ZExt16 { rd, mem, .. }
599         | Inst::Load32SExt16 { rd, mem, .. }
600         | Inst::Load64 { rd, mem, .. }
601         | Inst::Load64ZExt8 { rd, mem, .. }
602         | Inst::Load64SExt8 { rd, mem, .. }
603         | Inst::Load64ZExt16 { rd, mem, .. }
604         | Inst::Load64SExt16 { rd, mem, .. }
605         | Inst::Load64ZExt32 { rd, mem, .. }
606         | Inst::Load64SExt32 { rd, mem, .. }
607         | Inst::LoadRev16 { rd, mem, .. }
608         | Inst::LoadRev32 { rd, mem, .. }
609         | Inst::LoadRev64 { rd, mem, .. } => {
610             collector.reg_def(rd);
611             memarg_operands(mem, collector);
612         }
613         Inst::Store8 { rd, mem, .. }
614         | Inst::Store16 { rd, mem, .. }
615         | Inst::Store32 { rd, mem, .. }
616         | Inst::Store64 { rd, mem, .. }
617         | Inst::StoreRev16 { rd, mem, .. }
618         | Inst::StoreRev32 { rd, mem, .. }
619         | Inst::StoreRev64 { rd, mem, .. } => {
620             collector.reg_use(rd);
621             memarg_operands(mem, collector);
622         }
623         Inst::StoreImm8 { mem, .. }
624         | Inst::StoreImm16 { mem, .. }
625         | Inst::StoreImm32SExt16 { mem, .. }
626         | Inst::StoreImm64SExt16 { mem, .. } => {
627             memarg_operands(mem, collector);
628         }
629         Inst::LoadMultiple64 { rt, rt2, mem, .. } => {
630             memarg_operands(mem, collector);
631             let first_regnum = rt.to_reg().to_real_reg().unwrap().hw_enc();
632             let last_regnum = rt2.to_reg().to_real_reg().unwrap().hw_enc();
633             for regnum in first_regnum..last_regnum + 1 {
634                 collector.reg_fixed_nonallocatable(gpr_preg(regnum));
635             }
636         }
637         Inst::StoreMultiple64 { rt, rt2, mem, .. } => {
638             memarg_operands(mem, collector);
639             let first_regnum = rt.to_real_reg().unwrap().hw_enc();
640             let last_regnum = rt2.to_real_reg().unwrap().hw_enc();
641             for regnum in first_regnum..last_regnum + 1 {
642                 collector.reg_fixed_nonallocatable(gpr_preg(regnum));
643             }
644         }
645         Inst::Mov64 { rd, rm } => {
646             collector.reg_def(rd);
647             collector.reg_use(rm);
648         }
649         Inst::MovPReg { rd, rm } => {
650             collector.reg_def(rd);
651             collector.reg_fixed_nonallocatable(*rm);
652         }
653         Inst::Mov32 { rd, rm } => {
654             collector.reg_def(rd);
655             collector.reg_use(rm);
656         }
657         Inst::Mov32Imm { rd, .. }
658         | Inst::Mov32SImm16 { rd, .. }
659         | Inst::Mov64SImm16 { rd, .. }
660         | Inst::Mov64SImm32 { rd, .. }
661         | Inst::Mov64UImm16Shifted { rd, .. }
662         | Inst::Mov64UImm32Shifted { rd, .. } => {
663             collector.reg_def(rd);
664         }
665         Inst::CMov32 { rd, ri, rm, .. } | Inst::CMov64 { rd, ri, rm, .. } => {
666             collector.reg_reuse_def(rd, 1);
667             collector.reg_use(ri);
668             collector.reg_use(rm);
669         }
670         Inst::CMov32SImm16 { rd, ri, .. } | Inst::CMov64SImm16 { rd, ri, .. } => {
671             collector.reg_reuse_def(rd, 1);
672             collector.reg_use(ri);
673         }
674         Inst::Insert64UImm16Shifted { rd, ri, .. } | Inst::Insert64UImm32Shifted { rd, ri, .. } => {
675             collector.reg_reuse_def(rd, 1);
676             collector.reg_use(ri);
677         }
678         Inst::LoadAR { rd, .. } => {
679             collector.reg_def(rd);
680         }
681         Inst::InsertAR { rd, ri, .. } => {
682             collector.reg_reuse_def(rd, 1);
683             collector.reg_use(ri);
684         }
685         Inst::FpuMove32 { rd, rn } | Inst::FpuMove64 { rd, rn } => {
686             collector.reg_def(rd);
687             collector.reg_use(rn);
688         }
689         Inst::FpuCMov32 { rd, ri, rm, .. } | Inst::FpuCMov64 { rd, ri, rm, .. } => {
690             collector.reg_reuse_def(rd, 1);
691             collector.reg_use(ri);
692             collector.reg_use(rm);
693         }
694         Inst::FpuRR { rd, rn, .. } => {
695             collector.reg_def(rd);
696             collector.reg_use(rn);
697         }
698         Inst::FpuRRR { rd, rn, rm, .. } => {
699             collector.reg_def(rd);
700             collector.reg_use(rn);
701             collector.reg_use(rm);
702         }
703         Inst::FpuRRRR { rd, rn, rm, ra, .. } => {
704             collector.reg_def(rd);
705             collector.reg_use(rn);
706             collector.reg_use(rm);
707             collector.reg_use(ra);
708         }
709         Inst::FpuCmp32 { rn, rm } | Inst::FpuCmp64 { rn, rm } | Inst::FpuCmp128 { rn, rm } => {
710             collector.reg_use(rn);
711             collector.reg_use(rm);
712         }
713         Inst::FpuRound { rd, rn, .. } => {
714             collector.reg_def(rd);
715             collector.reg_use(rn);
716         }
717         Inst::FpuConv128FromInt { rd, rn, .. } => {
718             collector.reg_fixed_def(&mut rd.hi, vr(1));
719             collector.reg_fixed_def(&mut rd.lo, vr(3));
720             collector.reg_use(rn);
721         }
722         Inst::FpuConv128ToInt { rd, rn, .. } => {
723             collector.reg_def(rd);
724             collector.reg_fixed_use(&mut rn.hi, vr(1));
725             collector.reg_fixed_use(&mut rn.lo, vr(3));
726         }
727         Inst::VecRRR { rd, rn, rm, .. } => {
728             collector.reg_def(rd);
729             collector.reg_use(rn);
730             collector.reg_use(rm);
731         }
732         Inst::VecRR { rd, rn, .. } => {
733             collector.reg_def(rd);
734             collector.reg_use(rn);
735         }
736         Inst::VecShiftRR {
737             rd, rn, shift_reg, ..
738         } => {
739             collector.reg_def(rd);
740             collector.reg_use(rn);
741             collector.reg_use(shift_reg);
742         }
743         Inst::VecSelect { rd, rn, rm, ra, .. }
744         | Inst::VecBlend { rd, rn, rm, ra, .. }
745         | Inst::VecPermute { rd, rn, rm, ra, .. }
746         | Inst::VecEvaluate { rd, rn, rm, ra, .. } => {
747             collector.reg_def(rd);
748             collector.reg_use(rn);
749             collector.reg_use(rm);
750             collector.reg_use(ra);
751         }
752         Inst::VecPermuteDWImm { rd, rn, rm, .. } => {
753             collector.reg_def(rd);
754             collector.reg_use(rn);
755             collector.reg_use(rm);
756         }
757         Inst::VecIntCmp { rd, rn, rm, .. } | Inst::VecIntCmpS { rd, rn, rm, .. } => {
758             collector.reg_def(rd);
759             collector.reg_use(rn);
760             collector.reg_use(rm);
761         }
762         Inst::VecFloatCmp { rd, rn, rm, .. } | Inst::VecFloatCmpS { rd, rn, rm, .. } => {
763             collector.reg_def(rd);
764             collector.reg_use(rn);
765             collector.reg_use(rm);
766         }
767         Inst::VecIntEltCmp { rn, rm, .. } => {
768             collector.reg_use(rn);
769             collector.reg_use(rm);
770         }
771         Inst::VecInt128SCmpHi { tmp, rn, rm, .. } | Inst::VecInt128UCmpHi { tmp, rn, rm, .. } => {
772             collector.reg_def(tmp);
773             collector.reg_use(rn);
774             collector.reg_use(rm);
775         }
776         Inst::VecLoad { rd, mem, .. } => {
777             collector.reg_def(rd);
778             memarg_operands(mem, collector);
779         }
780         Inst::VecLoadRev { rd, mem, .. } => {
781             collector.reg_def(rd);
782             memarg_operands(mem, collector);
783         }
784         Inst::VecLoadByte16Rev { rd, mem, .. } => {
785             collector.reg_def(rd);
786             memarg_operands(mem, collector);
787         }
788         Inst::VecLoadByte32Rev { rd, mem, .. } => {
789             collector.reg_def(rd);
790             memarg_operands(mem, collector);
791         }
792         Inst::VecLoadByte64Rev { rd, mem, .. } => {
793             collector.reg_def(rd);
794             memarg_operands(mem, collector);
795         }
796         Inst::VecLoadElt16Rev { rd, mem, .. } => {
797             collector.reg_def(rd);
798             memarg_operands(mem, collector);
799         }
800         Inst::VecLoadElt32Rev { rd, mem, .. } => {
801             collector.reg_def(rd);
802             memarg_operands(mem, collector);
803         }
804         Inst::VecLoadElt64Rev { rd, mem, .. } => {
805             collector.reg_def(rd);
806             memarg_operands(mem, collector);
807         }
808         Inst::VecStore { rd, mem, .. } => {
809             collector.reg_use(rd);
810             memarg_operands(mem, collector);
811         }
812         Inst::VecStoreRev { rd, mem, .. } => {
813             collector.reg_use(rd);
814             memarg_operands(mem, collector);
815         }
816         Inst::VecStoreByte16Rev { rd, mem, .. } => {
817             collector.reg_use(rd);
818             memarg_operands(mem, collector);
819         }
820         Inst::VecStoreByte32Rev { rd, mem, .. } => {
821             collector.reg_use(rd);
822             memarg_operands(mem, collector);
823         }
824         Inst::VecStoreByte64Rev { rd, mem, .. } => {
825             collector.reg_use(rd);
826             memarg_operands(mem, collector);
827         }
828         Inst::VecStoreElt16Rev { rd, mem, .. } => {
829             collector.reg_use(rd);
830             memarg_operands(mem, collector);
831         }
832         Inst::VecStoreElt32Rev { rd, mem, .. } => {
833             collector.reg_use(rd);
834             memarg_operands(mem, collector);
835         }
836         Inst::VecStoreElt64Rev { rd, mem, .. } => {
837             collector.reg_use(rd);
838             memarg_operands(mem, collector);
839         }
840         Inst::VecLoadReplicate { rd, mem, .. } => {
841             collector.reg_def(rd);
842             memarg_operands(mem, collector);
843         }
844         Inst::VecLoadReplicateRev { rd, mem, .. } => {
845             collector.reg_def(rd);
846             memarg_operands(mem, collector);
847         }
848         Inst::VecMov { rd, rn } => {
849             collector.reg_def(rd);
850             collector.reg_use(rn);
851         }
852         Inst::VecCMov { rd, ri, rm, .. } => {
853             collector.reg_reuse_def(rd, 1);
854             collector.reg_use(ri);
855             collector.reg_use(rm);
856         }
857         Inst::MovToVec128 { rd, rn, rm } => {
858             collector.reg_def(rd);
859             collector.reg_use(rn);
860             collector.reg_use(rm);
861         }
862         Inst::VecImmByteMask { rd, .. } => {
863             collector.reg_def(rd);
864         }
865         Inst::VecImmBitMask { rd, .. } => {
866             collector.reg_def(rd);
867         }
868         Inst::VecImmReplicate { rd, .. } => {
869             collector.reg_def(rd);
870         }
871         Inst::VecLoadLane { rd, ri, mem, .. } => {
872             collector.reg_reuse_def(rd, 1);
873             collector.reg_use(ri);
874             memarg_operands(mem, collector);
875         }
876         Inst::VecLoadLaneUndef { rd, mem, .. } => {
877             collector.reg_def(rd);
878             memarg_operands(mem, collector);
879         }
880         Inst::VecStoreLaneRev { rd, mem, .. } => {
881             collector.reg_use(rd);
882             memarg_operands(mem, collector);
883         }
884         Inst::VecLoadLaneRevUndef { rd, mem, .. } => {
885             collector.reg_def(rd);
886             memarg_operands(mem, collector);
887         }
888         Inst::VecStoreLane { rd, mem, .. } => {
889             collector.reg_use(rd);
890             memarg_operands(mem, collector);
891         }
892         Inst::VecLoadLaneRev { rd, ri, mem, .. } => {
893             collector.reg_reuse_def(rd, 1);
894             collector.reg_use(ri);
895             memarg_operands(mem, collector);
896         }
897         Inst::VecInsertLane {
898             rd,
899             ri,
900             rn,
901             lane_reg,
902             ..
903         } => {
904             collector.reg_reuse_def(rd, 1);
905             collector.reg_use(ri);
906             collector.reg_use(rn);
907             collector.reg_use(lane_reg);
908         }
909         Inst::VecInsertLaneUndef {
910             rd, rn, lane_reg, ..
911         } => {
912             collector.reg_def(rd);
913             collector.reg_use(rn);
914             collector.reg_use(lane_reg);
915         }
916         Inst::VecExtractLane {
917             rd, rn, lane_reg, ..
918         } => {
919             collector.reg_def(rd);
920             collector.reg_use(rn);
921             collector.reg_use(lane_reg);
922         }
923         Inst::VecInsertLaneImm { rd, ri, .. } => {
924             collector.reg_reuse_def(rd, 1);
925             collector.reg_use(ri);
926         }
927         Inst::VecInsertLaneImmUndef { rd, .. } => {
928             collector.reg_def(rd);
929         }
930         Inst::VecReplicateLane { rd, rn, .. } => {
931             collector.reg_def(rd);
932             collector.reg_use(rn);
933         }
934         Inst::VecEltRev { rd, rn, .. } => {
935             collector.reg_def(rd);
936             collector.reg_use(rn);
937         }
938         Inst::Extend { rd, rn, .. } => {
939             collector.reg_def(rd);
940             collector.reg_use(rn);
941         }
942         Inst::AllocateArgs { .. } => {}
943         Inst::Call { link, info, .. } => {
944             let CallInfo {
945                 dest,
946                 uses,
947                 defs,
948                 clobbers,
949                 try_call_info,
950                 ..
951             } = &mut **info;
952             match dest {
953                 CallInstDest::Direct { .. } => {}
954                 CallInstDest::Indirect { reg } => collector.reg_use(reg),
955             }
956             for CallArgPair { vreg, preg } in uses {
957                 collector.reg_fixed_use(vreg, *preg);
958             }
959             for CallRetPair { vreg, location } in defs {
960                 match location {
961                     RetLocation::Reg(preg, ..) => collector.reg_fixed_def(vreg, *preg),
962                     RetLocation::Stack(..) => collector.any_def(vreg),
963                 }
964             }
965             let mut clobbers = *clobbers;
966             clobbers.add(link.to_reg().to_real_reg().unwrap().into());
967             collector.reg_clobbers(clobbers);
968             if let Some(try_call_info) = try_call_info {
969                 try_call_info.collect_operands(collector);
970             }
971         }
972         Inst::ReturnCall { info } => {
973             let ReturnCallInfo { dest, uses, .. } = &mut **info;
974             match dest {
975                 CallInstDest::Direct { .. } => {}
976                 CallInstDest::Indirect { reg } => collector.reg_use(reg),
977             }
978             for CallArgPair { vreg, preg } in uses {
979                 collector.reg_fixed_use(vreg, *preg);
980             }
981         }
982         Inst::ElfTlsGetOffset {
983             tls_offset,
984             got,
985             got_offset,
986             ..
987         } => {
988             collector.reg_fixed_use(got, gpr(12));
989             collector.reg_fixed_use(got_offset, gpr(2));
990             collector.reg_fixed_def(tls_offset, gpr(2));
991 
992             let mut clobbers =
993                 S390xMachineDeps::get_regs_clobbered_by_call(CallConv::SystemV, false);
994             clobbers.add(gpr_preg(14));
995             clobbers.remove(gpr_preg(2));
996             collector.reg_clobbers(clobbers);
997         }
998         Inst::Args { args } => {
999             for ArgPair { vreg, preg } in args {
1000                 collector.reg_fixed_def(vreg, *preg);
1001             }
1002         }
1003         Inst::Rets { rets } => {
1004             for RetPair { vreg, preg } in rets {
1005                 collector.reg_fixed_use(vreg, *preg);
1006             }
1007         }
1008         Inst::Ret { .. } => {
1009             // NOTE: we explicitly don't mark the link register as used here, as the use is only in
1010             // the epilog where callee-save registers are restored.
1011         }
1012         Inst::Jump { .. } => {}
1013         Inst::IndirectBr { rn, .. } => {
1014             collector.reg_use(rn);
1015         }
1016         Inst::CondBr { .. } => {}
1017         Inst::Nop0 | Inst::Nop2 => {}
1018         Inst::Debugtrap => {}
1019         Inst::Trap { .. } => {}
1020         Inst::TrapIf { .. } => {}
1021         Inst::JTSequence { ridx, .. } => {
1022             collector.reg_use(ridx);
1023             collector.reg_fixed_nonallocatable(gpr_preg(1));
1024         }
1025         Inst::LoadSymbolReloc { rd, .. } => {
1026             collector.reg_def(rd);
1027             collector.reg_fixed_nonallocatable(gpr_preg(1));
1028         }
1029         Inst::LoadAddr { rd, mem } => {
1030             collector.reg_def(rd);
1031             memarg_operands(mem, collector);
1032         }
1033         Inst::StackProbeLoop { probe_count, .. } => {
1034             collector.reg_early_def(probe_count);
1035         }
1036         Inst::Loop { body, .. } => {
1037             // `reuse_def` constraints can't be permitted in a Loop instruction because the operand
1038             // index will always be relative to the Loop instruction, not the individual
1039             // instruction in the loop body. However, fixed-nonallocatable registers used with
1040             // instructions that would have emitted `reuse_def` constraints are fine.
1041             let mut collector = DenyReuseVisitor {
1042                 inner: collector.inner,
1043                 deny_reuse: true,
1044             };
1045             for inst in body {
1046                 s390x_get_operands(inst, &mut collector);
1047             }
1048         }
1049         Inst::CondBreak { .. } => {}
1050         Inst::Unwind { .. } => {}
1051         Inst::DummyUse { reg } => {
1052             collector.reg_use(reg);
1053         }
1054         Inst::LabelAddress { dst, .. } => {
1055             collector.reg_def(dst);
1056         }
1057         Inst::SequencePoint { .. } => {}
1058     }
1059 }
1060 
1061 struct DenyReuseVisitor<'a, T> {
1062     inner: &'a mut T,
1063     deny_reuse: bool,
1064 }
1065 
1066 impl<T: OperandVisitor> OperandVisitor for DenyReuseVisitor<'_, T> {
add_operand( &mut self, reg: &mut Reg, constraint: regalloc2::OperandConstraint, kind: regalloc2::OperandKind, pos: regalloc2::OperandPos, )1067     fn add_operand(
1068         &mut self,
1069         reg: &mut Reg,
1070         constraint: regalloc2::OperandConstraint,
1071         kind: regalloc2::OperandKind,
1072         pos: regalloc2::OperandPos,
1073     ) {
1074         debug_assert!(
1075             !self.deny_reuse || !matches!(constraint, regalloc2::OperandConstraint::Reuse(_))
1076         );
1077         self.inner.add_operand(reg, constraint, kind, pos);
1078     }
1079 
debug_assert_is_allocatable_preg(&self, reg: regalloc2::PReg, expected: bool)1080     fn debug_assert_is_allocatable_preg(&self, reg: regalloc2::PReg, expected: bool) {
1081         self.inner.debug_assert_is_allocatable_preg(reg, expected);
1082     }
1083 
reg_clobbers(&mut self, regs: regalloc2::PRegSet)1084     fn reg_clobbers(&mut self, regs: regalloc2::PRegSet) {
1085         self.inner.reg_clobbers(regs);
1086     }
1087 }
1088 
1089 //=============================================================================
1090 // Instructions: misc functions and external interface
1091 
1092 impl MachInst for Inst {
1093     type ABIMachineSpec = S390xMachineDeps;
1094     type LabelUse = LabelUse;
1095     const TRAP_OPCODE: &'static [u8] = &[0, 0];
1096 
get_operands(&mut self, collector: &mut impl OperandVisitor)1097     fn get_operands(&mut self, collector: &mut impl OperandVisitor) {
1098         s390x_get_operands(
1099             self,
1100             &mut DenyReuseVisitor {
1101                 inner: collector,
1102                 deny_reuse: false,
1103             },
1104         );
1105     }
1106 
is_move(&self) -> Option<(Writable<Reg>, Reg)>1107     fn is_move(&self) -> Option<(Writable<Reg>, Reg)> {
1108         match self {
1109             &Inst::Mov32 { rd, rm } => Some((rd, rm)),
1110             &Inst::Mov64 { rd, rm } => Some((rd, rm)),
1111             &Inst::FpuMove32 { rd, rn } => Some((rd, rn)),
1112             &Inst::FpuMove64 { rd, rn } => Some((rd, rn)),
1113             &Inst::VecMov { rd, rn } => Some((rd, rn)),
1114             _ => None,
1115         }
1116     }
1117 
is_included_in_clobbers(&self) -> bool1118     fn is_included_in_clobbers(&self) -> bool {
1119         // We exclude call instructions from the clobber-set when they are calls
1120         // from caller to callee with the same ABI. Such calls cannot possibly
1121         // force any new registers to be saved in the prologue, because anything
1122         // that the callee clobbers, the caller is also allowed to clobber. This
1123         // both saves work and enables us to more precisely follow the
1124         // half-caller-save, half-callee-save SysV ABI for some vector
1125         // registers.
1126         match self {
1127             &Inst::Args { .. } => false,
1128             &Inst::Call { ref info, .. } => {
1129                 info.caller_conv != info.callee_conv || info.try_call_info.is_some()
1130             }
1131             &Inst::ElfTlsGetOffset { .. } => false,
1132             _ => true,
1133         }
1134     }
1135 
is_trap(&self) -> bool1136     fn is_trap(&self) -> bool {
1137         match self {
1138             Self::Trap { .. } => true,
1139             _ => false,
1140         }
1141     }
1142 
is_args(&self) -> bool1143     fn is_args(&self) -> bool {
1144         match self {
1145             Self::Args { .. } => true,
1146             _ => false,
1147         }
1148     }
1149 
is_term(&self) -> MachTerminator1150     fn is_term(&self) -> MachTerminator {
1151         match self {
1152             &Inst::Rets { .. } => MachTerminator::Ret,
1153             &Inst::ReturnCall { .. } => MachTerminator::RetCall,
1154             &Inst::Jump { .. } => MachTerminator::Branch,
1155             &Inst::CondBr { .. } => MachTerminator::Branch,
1156             &Inst::IndirectBr { .. } => MachTerminator::Branch,
1157             &Inst::JTSequence { .. } => MachTerminator::Branch,
1158             &Inst::Call { ref info, .. } if info.try_call_info.is_some() => MachTerminator::Branch,
1159             _ => MachTerminator::None,
1160         }
1161     }
1162 
is_mem_access(&self) -> bool1163     fn is_mem_access(&self) -> bool {
1164         panic!("TODO FILL ME OUT")
1165     }
1166 
is_safepoint(&self) -> bool1167     fn is_safepoint(&self) -> bool {
1168         match self {
1169             Inst::Call { .. } => true,
1170             _ => false,
1171         }
1172     }
1173 
call_type(&self) -> CallType1174     fn call_type(&self) -> CallType {
1175         match self {
1176             Inst::Call { .. } | Inst::ElfTlsGetOffset { .. } => CallType::Regular,
1177 
1178             Inst::ReturnCall { .. } => CallType::TailCall,
1179 
1180             _ => CallType::None,
1181         }
1182     }
1183 
gen_move(to_reg: Writable<Reg>, from_reg: Reg, ty: Type) -> Inst1184     fn gen_move(to_reg: Writable<Reg>, from_reg: Reg, ty: Type) -> Inst {
1185         assert!(ty.bits() <= 128);
1186         if ty.bits() <= 32 {
1187             Inst::mov32(to_reg, from_reg)
1188         } else if ty.bits() <= 64 {
1189             Inst::mov64(to_reg, from_reg)
1190         } else {
1191             Inst::mov128(to_reg, from_reg)
1192         }
1193     }
1194 
gen_nop(preferred_size: usize) -> Inst1195     fn gen_nop(preferred_size: usize) -> Inst {
1196         if preferred_size == 0 {
1197             Inst::Nop0
1198         } else {
1199             // We can't give a NOP (or any insn) < 2 bytes.
1200             assert!(preferred_size >= 2);
1201             Inst::Nop2
1202         }
1203     }
1204 
gen_nop_units() -> Vec<Vec<u8>>1205     fn gen_nop_units() -> Vec<Vec<u8>> {
1206         vec![vec![0x07, 0x07]]
1207     }
1208 
rc_for_type(ty: Type) -> CodegenResult<(&'static [RegClass], &'static [Type])>1209     fn rc_for_type(ty: Type) -> CodegenResult<(&'static [RegClass], &'static [Type])> {
1210         match ty {
1211             types::I8 => Ok((&[RegClass::Int], &[types::I8])),
1212             types::I16 => Ok((&[RegClass::Int], &[types::I16])),
1213             types::I32 => Ok((&[RegClass::Int], &[types::I32])),
1214             types::I64 => Ok((&[RegClass::Int], &[types::I64])),
1215             types::F16 => Ok((&[RegClass::Float], &[types::F16])),
1216             types::F32 => Ok((&[RegClass::Float], &[types::F32])),
1217             types::F64 => Ok((&[RegClass::Float], &[types::F64])),
1218             types::F128 => Ok((&[RegClass::Float], &[types::F128])),
1219             types::I128 => Ok((&[RegClass::Float], &[types::I128])),
1220             _ if ty.is_vector() && ty.bits() == 128 => Ok((&[RegClass::Float], &[types::I8X16])),
1221             _ => Err(CodegenError::Unsupported(format!(
1222                 "Unexpected SSA-value type: {ty}"
1223             ))),
1224         }
1225     }
1226 
canonical_type_for_rc(rc: RegClass) -> Type1227     fn canonical_type_for_rc(rc: RegClass) -> Type {
1228         match rc {
1229             RegClass::Int => types::I64,
1230             RegClass::Float => types::I8X16,
1231             RegClass::Vector => unreachable!(),
1232         }
1233     }
1234 
gen_jump(target: MachLabel) -> Inst1235     fn gen_jump(target: MachLabel) -> Inst {
1236         Inst::Jump { dest: target }
1237     }
1238 
worst_case_size() -> CodeOffset1239     fn worst_case_size() -> CodeOffset {
1240         // The maximum size, in bytes, of any `Inst`'s emitted code. We have at least one case of
1241         // an 8-instruction sequence (saturating int-to-float conversions) with three embedded
1242         // 64-bit f64 constants.
1243         //
1244         // Note that inline jump-tables handle island/pool insertion separately, so we do not need
1245         // to account for them here (otherwise the worst case would be 2^31 * 4, clearly not
1246         // feasible for other reasons).
1247         44
1248     }
1249 
ref_type_regclass(_: &settings::Flags) -> RegClass1250     fn ref_type_regclass(_: &settings::Flags) -> RegClass {
1251         RegClass::Int
1252     }
1253 
gen_dummy_use(reg: Reg) -> Inst1254     fn gen_dummy_use(reg: Reg) -> Inst {
1255         Inst::DummyUse { reg }
1256     }
1257 
function_alignment() -> FunctionAlignment1258     fn function_alignment() -> FunctionAlignment {
1259         FunctionAlignment {
1260             minimum: 4,
1261             preferred: 4,
1262         }
1263     }
1264 }
1265 
1266 //=============================================================================
1267 // Pretty-printing of instructions.
1268 
mem_finalize_for_show(mem: &MemArg, state: &EmitState, mi: MemInstType) -> (String, MemArg)1269 fn mem_finalize_for_show(mem: &MemArg, state: &EmitState, mi: MemInstType) -> (String, MemArg) {
1270     let (mem_insts, mem) = mem_finalize(mem, state, mi);
1271     let mut mem_str = mem_insts
1272         .into_iter()
1273         .map(|inst| inst.print_with_state(&mut EmitState::default()))
1274         .collect::<Vec<_>>()
1275         .join(" ; ");
1276     if !mem_str.is_empty() {
1277         mem_str += " ; ";
1278     }
1279 
1280     (mem_str, mem)
1281 }
1282 
1283 impl Inst {
print_with_state(&self, state: &mut EmitState) -> String1284     fn print_with_state(&self, state: &mut EmitState) -> String {
1285         match self {
1286             &Inst::Nop0 => "nop-zero-len".to_string(),
1287             &Inst::Nop2 => "nop".to_string(),
1288             &Inst::AluRRR { alu_op, rd, rn, rm } => {
1289                 let (op, have_rr) = match alu_op {
1290                     ALUOp::Add32 => ("ark", true),
1291                     ALUOp::Add64 => ("agrk", true),
1292                     ALUOp::AddLogical32 => ("alrk", true),
1293                     ALUOp::AddLogical64 => ("algrk", true),
1294                     ALUOp::Sub32 => ("srk", true),
1295                     ALUOp::Sub64 => ("sgrk", true),
1296                     ALUOp::SubLogical32 => ("slrk", true),
1297                     ALUOp::SubLogical64 => ("slgrk", true),
1298                     ALUOp::Mul32 => ("msrkc", true),
1299                     ALUOp::Mul64 => ("msgrkc", true),
1300                     ALUOp::And32 => ("nrk", true),
1301                     ALUOp::And64 => ("ngrk", true),
1302                     ALUOp::Orr32 => ("ork", true),
1303                     ALUOp::Orr64 => ("ogrk", true),
1304                     ALUOp::Xor32 => ("xrk", true),
1305                     ALUOp::Xor64 => ("xgrk", true),
1306                     ALUOp::NotAnd32 => ("nnrk", false),
1307                     ALUOp::NotAnd64 => ("nngrk", false),
1308                     ALUOp::NotOrr32 => ("nork", false),
1309                     ALUOp::NotOrr64 => ("nogrk", false),
1310                     ALUOp::NotXor32 => ("nxrk", false),
1311                     ALUOp::NotXor64 => ("nxgrk", false),
1312                     ALUOp::AndNot32 => ("ncrk", false),
1313                     ALUOp::AndNot64 => ("ncgrk", false),
1314                     ALUOp::OrrNot32 => ("ocrk", false),
1315                     ALUOp::OrrNot64 => ("ocgrk", false),
1316                     _ => unreachable!(),
1317                 };
1318                 if have_rr && rd.to_reg() == rn {
1319                     let inst = Inst::AluRR {
1320                         alu_op,
1321                         rd,
1322                         ri: rd.to_reg(),
1323                         rm,
1324                     };
1325                     return inst.print_with_state(state);
1326                 }
1327                 let rd = pretty_print_reg(rd.to_reg());
1328                 let rn = pretty_print_reg(rn);
1329                 let rm = pretty_print_reg(rm);
1330                 format!("{op} {rd}, {rn}, {rm}")
1331             }
1332             &Inst::AluRRSImm16 {
1333                 alu_op,
1334                 rd,
1335                 rn,
1336                 imm,
1337             } => {
1338                 if rd.to_reg() == rn {
1339                     let inst = Inst::AluRSImm16 {
1340                         alu_op,
1341                         rd,
1342                         ri: rd.to_reg(),
1343                         imm,
1344                     };
1345                     return inst.print_with_state(state);
1346                 }
1347                 let op = match alu_op {
1348                     ALUOp::Add32 => "ahik",
1349                     ALUOp::Add64 => "aghik",
1350                     _ => unreachable!(),
1351                 };
1352                 let rd = pretty_print_reg(rd.to_reg());
1353                 let rn = pretty_print_reg(rn);
1354                 format!("{op} {rd}, {rn}, {imm}")
1355             }
1356             &Inst::AluRR { alu_op, rd, ri, rm } => {
1357                 let op = match alu_op {
1358                     ALUOp::Add32 => "ar",
1359                     ALUOp::Add64 => "agr",
1360                     ALUOp::Add64Ext32 => "agfr",
1361                     ALUOp::AddLogical32 => "alr",
1362                     ALUOp::AddLogical64 => "algr",
1363                     ALUOp::AddLogical64Ext32 => "algfr",
1364                     ALUOp::Sub32 => "sr",
1365                     ALUOp::Sub64 => "sgr",
1366                     ALUOp::Sub64Ext32 => "sgfr",
1367                     ALUOp::SubLogical32 => "slr",
1368                     ALUOp::SubLogical64 => "slgr",
1369                     ALUOp::SubLogical64Ext32 => "slgfr",
1370                     ALUOp::Mul32 => "msr",
1371                     ALUOp::Mul64 => "msgr",
1372                     ALUOp::Mul64Ext32 => "msgfr",
1373                     ALUOp::And32 => "nr",
1374                     ALUOp::And64 => "ngr",
1375                     ALUOp::Orr32 => "or",
1376                     ALUOp::Orr64 => "ogr",
1377                     ALUOp::Xor32 => "xr",
1378                     ALUOp::Xor64 => "xgr",
1379                     _ => unreachable!(),
1380                 };
1381                 let rd = pretty_print_reg_mod(rd, ri);
1382                 let rm = pretty_print_reg(rm);
1383                 format!("{op} {rd}, {rm}")
1384             }
1385             &Inst::AluRX {
1386                 alu_op,
1387                 rd,
1388                 ri,
1389                 ref mem,
1390             } => {
1391                 let (opcode_rx, opcode_rxy) = match alu_op {
1392                     ALUOp::Add32 => (Some("a"), Some("ay")),
1393                     ALUOp::Add32Ext16 => (Some("ah"), Some("ahy")),
1394                     ALUOp::Add64 => (None, Some("ag")),
1395                     ALUOp::Add64Ext16 => (None, Some("agh")),
1396                     ALUOp::Add64Ext32 => (None, Some("agf")),
1397                     ALUOp::AddLogical32 => (Some("al"), Some("aly")),
1398                     ALUOp::AddLogical64 => (None, Some("alg")),
1399                     ALUOp::AddLogical64Ext32 => (None, Some("algf")),
1400                     ALUOp::Sub32 => (Some("s"), Some("sy")),
1401                     ALUOp::Sub32Ext16 => (Some("sh"), Some("shy")),
1402                     ALUOp::Sub64 => (None, Some("sg")),
1403                     ALUOp::Sub64Ext16 => (None, Some("sgh")),
1404                     ALUOp::Sub64Ext32 => (None, Some("sgf")),
1405                     ALUOp::SubLogical32 => (Some("sl"), Some("sly")),
1406                     ALUOp::SubLogical64 => (None, Some("slg")),
1407                     ALUOp::SubLogical64Ext32 => (None, Some("slgf")),
1408                     ALUOp::Mul32 => (Some("ms"), Some("msy")),
1409                     ALUOp::Mul32Ext16 => (Some("mh"), Some("mhy")),
1410                     ALUOp::Mul64 => (None, Some("msg")),
1411                     ALUOp::Mul64Ext16 => (None, Some("mgh")),
1412                     ALUOp::Mul64Ext32 => (None, Some("msgf")),
1413                     ALUOp::And32 => (Some("n"), Some("ny")),
1414                     ALUOp::And64 => (None, Some("ng")),
1415                     ALUOp::Orr32 => (Some("o"), Some("oy")),
1416                     ALUOp::Orr64 => (None, Some("og")),
1417                     ALUOp::Xor32 => (Some("x"), Some("xy")),
1418                     ALUOp::Xor64 => (None, Some("xg")),
1419                     _ => unreachable!(),
1420                 };
1421 
1422                 let rd = pretty_print_reg_mod(rd, ri);
1423                 let mem = mem.clone();
1424                 let (mem_str, mem) = mem_finalize_for_show(
1425                     &mem,
1426                     state,
1427                     MemInstType {
1428                         have_d12: opcode_rx.is_some(),
1429                         have_d20: opcode_rxy.is_some(),
1430                         have_pcrel: false,
1431                         have_unaligned_pcrel: false,
1432                         have_index: true,
1433                     },
1434                 );
1435                 let op = match &mem {
1436                     &MemArg::BXD12 { .. } => opcode_rx,
1437                     &MemArg::BXD20 { .. } => opcode_rxy,
1438                     _ => unreachable!(),
1439                 };
1440                 let mem = mem.pretty_print_default();
1441 
1442                 format!("{}{} {}, {}", mem_str, op.unwrap(), rd, mem)
1443             }
1444             &Inst::AluRSImm16 {
1445                 alu_op,
1446                 rd,
1447                 ri,
1448                 imm,
1449             } => {
1450                 let op = match alu_op {
1451                     ALUOp::Add32 => "ahi",
1452                     ALUOp::Add64 => "aghi",
1453                     ALUOp::Mul32 => "mhi",
1454                     ALUOp::Mul64 => "mghi",
1455                     _ => unreachable!(),
1456                 };
1457                 let rd = pretty_print_reg_mod(rd, ri);
1458                 format!("{op} {rd}, {imm}")
1459             }
1460             &Inst::AluRSImm32 {
1461                 alu_op,
1462                 rd,
1463                 ri,
1464                 imm,
1465             } => {
1466                 let op = match alu_op {
1467                     ALUOp::Add32 => "afi",
1468                     ALUOp::Add64 => "agfi",
1469                     ALUOp::Mul32 => "msfi",
1470                     ALUOp::Mul64 => "msgfi",
1471                     _ => unreachable!(),
1472                 };
1473                 let rd = pretty_print_reg_mod(rd, ri);
1474                 format!("{op} {rd}, {imm}")
1475             }
1476             &Inst::AluRUImm32 {
1477                 alu_op,
1478                 rd,
1479                 ri,
1480                 imm,
1481             } => {
1482                 let op = match alu_op {
1483                     ALUOp::AddLogical32 => "alfi",
1484                     ALUOp::AddLogical64 => "algfi",
1485                     ALUOp::SubLogical32 => "slfi",
1486                     ALUOp::SubLogical64 => "slgfi",
1487                     _ => unreachable!(),
1488                 };
1489                 let rd = pretty_print_reg_mod(rd, ri);
1490                 format!("{op} {rd}, {imm}")
1491             }
1492             &Inst::AluRUImm16Shifted {
1493                 alu_op,
1494                 rd,
1495                 ri,
1496                 imm,
1497             } => {
1498                 let op = match (alu_op, imm.shift) {
1499                     (ALUOp::And32, 0) => "nill",
1500                     (ALUOp::And32, 1) => "nilh",
1501                     (ALUOp::And64, 0) => "nill",
1502                     (ALUOp::And64, 1) => "nilh",
1503                     (ALUOp::And64, 2) => "nihl",
1504                     (ALUOp::And64, 3) => "nihh",
1505                     (ALUOp::Orr32, 0) => "oill",
1506                     (ALUOp::Orr32, 1) => "oilh",
1507                     (ALUOp::Orr64, 0) => "oill",
1508                     (ALUOp::Orr64, 1) => "oilh",
1509                     (ALUOp::Orr64, 2) => "oihl",
1510                     (ALUOp::Orr64, 3) => "oihh",
1511                     _ => unreachable!(),
1512                 };
1513                 let rd = pretty_print_reg_mod(rd, ri);
1514                 format!("{} {}, {}", op, rd, imm.bits)
1515             }
1516             &Inst::AluRUImm32Shifted {
1517                 alu_op,
1518                 rd,
1519                 ri,
1520                 imm,
1521             } => {
1522                 let op = match (alu_op, imm.shift) {
1523                     (ALUOp::And32, 0) => "nilf",
1524                     (ALUOp::And64, 0) => "nilf",
1525                     (ALUOp::And64, 1) => "nihf",
1526                     (ALUOp::Orr32, 0) => "oilf",
1527                     (ALUOp::Orr64, 0) => "oilf",
1528                     (ALUOp::Orr64, 1) => "oihf",
1529                     (ALUOp::Xor32, 0) => "xilf",
1530                     (ALUOp::Xor64, 0) => "xilf",
1531                     (ALUOp::Xor64, 1) => "xihf",
1532                     _ => unreachable!(),
1533                 };
1534                 let rd = pretty_print_reg_mod(rd, ri);
1535                 format!("{} {}, {}", op, rd, imm.bits)
1536             }
1537             &Inst::SMulWide { rd, rn, rm } => {
1538                 let op = "mgrk";
1539                 let rn = pretty_print_reg(rn);
1540                 let rm = pretty_print_reg(rm);
1541                 let rd = pretty_print_regpair(rd.to_regpair());
1542                 format!("{op} {rd}, {rn}, {rm}")
1543             }
1544             &Inst::UMulWide { rd, ri, rn } => {
1545                 let op = "mlgr";
1546                 let rn = pretty_print_reg(rn);
1547                 let rd = pretty_print_regpair_mod_lo(rd, ri);
1548                 format!("{op} {rd}, {rn}")
1549             }
1550             &Inst::SDivMod32 { rd, ri, rn } => {
1551                 let op = "dsgfr";
1552                 let rn = pretty_print_reg(rn);
1553                 let rd = pretty_print_regpair_mod_lo(rd, ri);
1554                 format!("{op} {rd}, {rn}")
1555             }
1556             &Inst::SDivMod64 { rd, ri, rn } => {
1557                 let op = "dsgr";
1558                 let rn = pretty_print_reg(rn);
1559                 let rd = pretty_print_regpair_mod_lo(rd, ri);
1560                 format!("{op} {rd}, {rn}")
1561             }
1562             &Inst::UDivMod32 { rd, ri, rn } => {
1563                 let op = "dlr";
1564                 let rn = pretty_print_reg(rn);
1565                 let rd = pretty_print_regpair_mod(rd, ri);
1566                 format!("{op} {rd}, {rn}")
1567             }
1568             &Inst::UDivMod64 { rd, ri, rn } => {
1569                 let op = "dlgr";
1570                 let rn = pretty_print_reg(rn);
1571                 let rd = pretty_print_regpair_mod(rd, ri);
1572                 format!("{op} {rd}, {rn}")
1573             }
1574             &Inst::Flogr { rd, rn } => {
1575                 let op = "flogr";
1576                 let rn = pretty_print_reg(rn);
1577                 let rd = pretty_print_regpair(rd.to_regpair());
1578                 format!("{op} {rd}, {rn}")
1579             }
1580             &Inst::ShiftRR {
1581                 shift_op,
1582                 rd,
1583                 rn,
1584                 shift_imm,
1585                 shift_reg,
1586             } => {
1587                 let op = match shift_op {
1588                     ShiftOp::RotL32 => "rll",
1589                     ShiftOp::RotL64 => "rllg",
1590                     ShiftOp::LShL32 => "sllk",
1591                     ShiftOp::LShL64 => "sllg",
1592                     ShiftOp::LShR32 => "srlk",
1593                     ShiftOp::LShR64 => "srlg",
1594                     ShiftOp::AShR32 => "srak",
1595                     ShiftOp::AShR64 => "srag",
1596                 };
1597                 let rd = pretty_print_reg(rd.to_reg());
1598                 let rn = pretty_print_reg(rn);
1599                 let shift_reg = if shift_reg != zero_reg() {
1600                     format!("({})", pretty_print_reg(shift_reg))
1601                 } else {
1602                     "".to_string()
1603                 };
1604                 format!("{op} {rd}, {rn}, {shift_imm}{shift_reg}")
1605             }
1606             &Inst::RxSBG {
1607                 op,
1608                 rd,
1609                 ri,
1610                 rn,
1611                 start_bit,
1612                 end_bit,
1613                 rotate_amt,
1614             } => {
1615                 let op = match op {
1616                     RxSBGOp::Insert => "risbgn",
1617                     RxSBGOp::And => "rnsbg",
1618                     RxSBGOp::Or => "rosbg",
1619                     RxSBGOp::Xor => "rxsbg",
1620                 };
1621                 let rd = pretty_print_reg_mod(rd, ri);
1622                 let rn = pretty_print_reg(rn);
1623                 format!(
1624                     "{} {}, {}, {}, {}, {}",
1625                     op,
1626                     rd,
1627                     rn,
1628                     start_bit,
1629                     end_bit,
1630                     (rotate_amt as u8) & 63
1631                 )
1632             }
1633             &Inst::RxSBGTest {
1634                 op,
1635                 rd,
1636                 rn,
1637                 start_bit,
1638                 end_bit,
1639                 rotate_amt,
1640             } => {
1641                 let op = match op {
1642                     RxSBGOp::And => "rnsbg",
1643                     RxSBGOp::Or => "rosbg",
1644                     RxSBGOp::Xor => "rxsbg",
1645                     _ => unreachable!(),
1646                 };
1647                 let rd = pretty_print_reg(rd);
1648                 let rn = pretty_print_reg(rn);
1649                 format!(
1650                     "{} {}, {}, {}, {}, {}",
1651                     op,
1652                     rd,
1653                     rn,
1654                     start_bit | 0x80,
1655                     end_bit,
1656                     (rotate_amt as u8) & 63
1657                 )
1658             }
1659             &Inst::UnaryRR { op, rd, rn } => {
1660                 let (op, extra) = match op {
1661                     UnaryOp::Abs32 => ("lpr", ""),
1662                     UnaryOp::Abs64 => ("lpgr", ""),
1663                     UnaryOp::Abs64Ext32 => ("lpgfr", ""),
1664                     UnaryOp::Neg32 => ("lcr", ""),
1665                     UnaryOp::Neg64 => ("lcgr", ""),
1666                     UnaryOp::Neg64Ext32 => ("lcgfr", ""),
1667                     UnaryOp::PopcntByte => ("popcnt", ""),
1668                     UnaryOp::PopcntReg => ("popcnt", ", 8"),
1669                     UnaryOp::BSwap32 => ("lrvr", ""),
1670                     UnaryOp::BSwap64 => ("lrvgr", ""),
1671                     UnaryOp::Clz64 => ("clzg", ""),
1672                     UnaryOp::Ctz64 => ("ctzg", ""),
1673                 };
1674                 let rd = pretty_print_reg(rd.to_reg());
1675                 let rn = pretty_print_reg(rn);
1676                 format!("{op} {rd}, {rn}{extra}")
1677             }
1678             &Inst::CmpRR { op, rn, rm } => {
1679                 let op = match op {
1680                     CmpOp::CmpS32 => "cr",
1681                     CmpOp::CmpS64 => "cgr",
1682                     CmpOp::CmpS64Ext32 => "cgfr",
1683                     CmpOp::CmpL32 => "clr",
1684                     CmpOp::CmpL64 => "clgr",
1685                     CmpOp::CmpL64Ext32 => "clgfr",
1686                     _ => unreachable!(),
1687                 };
1688                 let rn = pretty_print_reg(rn);
1689                 let rm = pretty_print_reg(rm);
1690                 format!("{op} {rn}, {rm}")
1691             }
1692             &Inst::CmpRX { op, rn, ref mem } => {
1693                 let (opcode_rx, opcode_rxy, opcode_ril) = match op {
1694                     CmpOp::CmpS32 => (Some("c"), Some("cy"), Some("crl")),
1695                     CmpOp::CmpS32Ext16 => (Some("ch"), Some("chy"), Some("chrl")),
1696                     CmpOp::CmpS64 => (None, Some("cg"), Some("cgrl")),
1697                     CmpOp::CmpS64Ext16 => (None, Some("cgh"), Some("cghrl")),
1698                     CmpOp::CmpS64Ext32 => (None, Some("cgf"), Some("cgfrl")),
1699                     CmpOp::CmpL32 => (Some("cl"), Some("cly"), Some("clrl")),
1700                     CmpOp::CmpL32Ext16 => (None, None, Some("clhrl")),
1701                     CmpOp::CmpL64 => (None, Some("clg"), Some("clgrl")),
1702                     CmpOp::CmpL64Ext16 => (None, None, Some("clghrl")),
1703                     CmpOp::CmpL64Ext32 => (None, Some("clgf"), Some("clgfrl")),
1704                 };
1705 
1706                 let rn = pretty_print_reg(rn);
1707                 let mem = mem.clone();
1708                 let (mem_str, mem) = mem_finalize_for_show(
1709                     &mem,
1710                     state,
1711                     MemInstType {
1712                         have_d12: opcode_rx.is_some(),
1713                         have_d20: opcode_rxy.is_some(),
1714                         have_pcrel: opcode_ril.is_some(),
1715                         have_unaligned_pcrel: false,
1716                         have_index: true,
1717                     },
1718                 );
1719                 let op = match &mem {
1720                     &MemArg::BXD12 { .. } => opcode_rx,
1721                     &MemArg::BXD20 { .. } => opcode_rxy,
1722                     &MemArg::Label { .. } | &MemArg::Constant { .. } | &MemArg::Symbol { .. } => {
1723                         opcode_ril
1724                     }
1725                     _ => unreachable!(),
1726                 };
1727                 let mem = mem.pretty_print_default();
1728 
1729                 format!("{}{} {}, {}", mem_str, op.unwrap(), rn, mem)
1730             }
1731             &Inst::CmpRSImm16 { op, rn, imm } => {
1732                 let op = match op {
1733                     CmpOp::CmpS32 => "chi",
1734                     CmpOp::CmpS64 => "cghi",
1735                     _ => unreachable!(),
1736                 };
1737                 let rn = pretty_print_reg(rn);
1738                 format!("{op} {rn}, {imm}")
1739             }
1740             &Inst::CmpRSImm32 { op, rn, imm } => {
1741                 let op = match op {
1742                     CmpOp::CmpS32 => "cfi",
1743                     CmpOp::CmpS64 => "cgfi",
1744                     _ => unreachable!(),
1745                 };
1746                 let rn = pretty_print_reg(rn);
1747                 format!("{op} {rn}, {imm}")
1748             }
1749             &Inst::CmpRUImm32 { op, rn, imm } => {
1750                 let op = match op {
1751                     CmpOp::CmpL32 => "clfi",
1752                     CmpOp::CmpL64 => "clgfi",
1753                     _ => unreachable!(),
1754                 };
1755                 let rn = pretty_print_reg(rn);
1756                 format!("{op} {rn}, {imm}")
1757             }
1758             &Inst::CmpTrapRR {
1759                 op, rn, rm, cond, ..
1760             } => {
1761                 let op = match op {
1762                     CmpOp::CmpS32 => "crt",
1763                     CmpOp::CmpS64 => "cgrt",
1764                     CmpOp::CmpL32 => "clrt",
1765                     CmpOp::CmpL64 => "clgrt",
1766                     _ => unreachable!(),
1767                 };
1768                 let rn = pretty_print_reg(rn);
1769                 let rm = pretty_print_reg(rm);
1770                 let cond = cond.pretty_print_default();
1771                 format!("{op}{cond} {rn}, {rm}")
1772             }
1773             &Inst::CmpTrapRSImm16 {
1774                 op, rn, imm, cond, ..
1775             } => {
1776                 let op = match op {
1777                     CmpOp::CmpS32 => "cit",
1778                     CmpOp::CmpS64 => "cgit",
1779                     _ => unreachable!(),
1780                 };
1781                 let rn = pretty_print_reg(rn);
1782                 let cond = cond.pretty_print_default();
1783                 format!("{op}{cond} {rn}, {imm}")
1784             }
1785             &Inst::CmpTrapRUImm16 {
1786                 op, rn, imm, cond, ..
1787             } => {
1788                 let op = match op {
1789                     CmpOp::CmpL32 => "clfit",
1790                     CmpOp::CmpL64 => "clgit",
1791                     _ => unreachable!(),
1792                 };
1793                 let rn = pretty_print_reg(rn);
1794                 let cond = cond.pretty_print_default();
1795                 format!("{op}{cond} {rn}, {imm}")
1796             }
1797             &Inst::AtomicRmw {
1798                 alu_op,
1799                 rd,
1800                 rn,
1801                 ref mem,
1802             } => {
1803                 let op = match alu_op {
1804                     ALUOp::Add32 => "laa",
1805                     ALUOp::Add64 => "laag",
1806                     ALUOp::AddLogical32 => "laal",
1807                     ALUOp::AddLogical64 => "laalg",
1808                     ALUOp::And32 => "lan",
1809                     ALUOp::And64 => "lang",
1810                     ALUOp::Orr32 => "lao",
1811                     ALUOp::Orr64 => "laog",
1812                     ALUOp::Xor32 => "lax",
1813                     ALUOp::Xor64 => "laxg",
1814                     _ => unreachable!(),
1815                 };
1816 
1817                 let rd = pretty_print_reg(rd.to_reg());
1818                 let rn = pretty_print_reg(rn);
1819                 let mem = mem.clone();
1820                 let (mem_str, mem) = mem_finalize_for_show(
1821                     &mem,
1822                     state,
1823                     MemInstType {
1824                         have_d12: false,
1825                         have_d20: true,
1826                         have_pcrel: false,
1827                         have_unaligned_pcrel: false,
1828                         have_index: false,
1829                     },
1830                 );
1831                 let mem = mem.pretty_print_default();
1832                 format!("{mem_str}{op} {rd}, {rn}, {mem}")
1833             }
1834             &Inst::AtomicCas32 {
1835                 rd,
1836                 ri,
1837                 rn,
1838                 ref mem,
1839             }
1840             | &Inst::AtomicCas64 {
1841                 rd,
1842                 ri,
1843                 rn,
1844                 ref mem,
1845             } => {
1846                 let (opcode_rs, opcode_rsy) = match self {
1847                     &Inst::AtomicCas32 { .. } => (Some("cs"), Some("csy")),
1848                     &Inst::AtomicCas64 { .. } => (None, Some("csg")),
1849                     _ => unreachable!(),
1850                 };
1851 
1852                 let rd = pretty_print_reg_mod(rd, ri);
1853                 let rn = pretty_print_reg(rn);
1854                 let mem = mem.clone();
1855                 let (mem_str, mem) = mem_finalize_for_show(
1856                     &mem,
1857                     state,
1858                     MemInstType {
1859                         have_d12: opcode_rs.is_some(),
1860                         have_d20: opcode_rsy.is_some(),
1861                         have_pcrel: false,
1862                         have_unaligned_pcrel: false,
1863                         have_index: false,
1864                     },
1865                 );
1866                 let op = match &mem {
1867                     &MemArg::BXD12 { .. } => opcode_rs,
1868                     &MemArg::BXD20 { .. } => opcode_rsy,
1869                     _ => unreachable!(),
1870                 };
1871                 let mem = mem.pretty_print_default();
1872 
1873                 format!("{}{} {}, {}, {}", mem_str, op.unwrap(), rd, rn, mem)
1874             }
1875             &Inst::Fence => "bcr 14, 0".to_string(),
1876             &Inst::Load32 { rd, ref mem }
1877             | &Inst::Load32ZExt8 { rd, ref mem }
1878             | &Inst::Load32SExt8 { rd, ref mem }
1879             | &Inst::Load32ZExt16 { rd, ref mem }
1880             | &Inst::Load32SExt16 { rd, ref mem }
1881             | &Inst::Load64 { rd, ref mem }
1882             | &Inst::Load64ZExt8 { rd, ref mem }
1883             | &Inst::Load64SExt8 { rd, ref mem }
1884             | &Inst::Load64ZExt16 { rd, ref mem }
1885             | &Inst::Load64SExt16 { rd, ref mem }
1886             | &Inst::Load64ZExt32 { rd, ref mem }
1887             | &Inst::Load64SExt32 { rd, ref mem }
1888             | &Inst::LoadRev16 { rd, ref mem }
1889             | &Inst::LoadRev32 { rd, ref mem }
1890             | &Inst::LoadRev64 { rd, ref mem } => {
1891                 let (opcode_rx, opcode_rxy, opcode_ril) = match self {
1892                     &Inst::Load32 { .. } => (Some("l"), Some("ly"), Some("lrl")),
1893                     &Inst::Load32ZExt8 { .. } => (None, Some("llc"), None),
1894                     &Inst::Load32SExt8 { .. } => (None, Some("lb"), None),
1895                     &Inst::Load32ZExt16 { .. } => (None, Some("llh"), Some("llhrl")),
1896                     &Inst::Load32SExt16 { .. } => (Some("lh"), Some("lhy"), Some("lhrl")),
1897                     &Inst::Load64 { .. } => (None, Some("lg"), Some("lgrl")),
1898                     &Inst::Load64ZExt8 { .. } => (None, Some("llgc"), None),
1899                     &Inst::Load64SExt8 { .. } => (None, Some("lgb"), None),
1900                     &Inst::Load64ZExt16 { .. } => (None, Some("llgh"), Some("llghrl")),
1901                     &Inst::Load64SExt16 { .. } => (None, Some("lgh"), Some("lghrl")),
1902                     &Inst::Load64ZExt32 { .. } => (None, Some("llgf"), Some("llgfrl")),
1903                     &Inst::Load64SExt32 { .. } => (None, Some("lgf"), Some("lgfrl")),
1904                     &Inst::LoadRev16 { .. } => (None, Some("lrvh"), None),
1905                     &Inst::LoadRev32 { .. } => (None, Some("lrv"), None),
1906                     &Inst::LoadRev64 { .. } => (None, Some("lrvg"), None),
1907                     _ => unreachable!(),
1908                 };
1909 
1910                 let rd = pretty_print_reg(rd.to_reg());
1911                 let mem = mem.clone();
1912                 let (mem_str, mem) = mem_finalize_for_show(
1913                     &mem,
1914                     state,
1915                     MemInstType {
1916                         have_d12: opcode_rx.is_some(),
1917                         have_d20: opcode_rxy.is_some(),
1918                         have_pcrel: opcode_ril.is_some(),
1919                         have_unaligned_pcrel: false,
1920                         have_index: true,
1921                     },
1922                 );
1923                 let op = match &mem {
1924                     &MemArg::BXD12 { .. } => opcode_rx,
1925                     &MemArg::BXD20 { .. } => opcode_rxy,
1926                     &MemArg::Label { .. } | &MemArg::Constant { .. } | &MemArg::Symbol { .. } => {
1927                         opcode_ril
1928                     }
1929                     _ => unreachable!(),
1930                 };
1931                 let mem = mem.pretty_print_default();
1932                 format!("{}{} {}, {}", mem_str, op.unwrap(), rd, mem)
1933             }
1934             &Inst::Store8 { rd, ref mem }
1935             | &Inst::Store16 { rd, ref mem }
1936             | &Inst::Store32 { rd, ref mem }
1937             | &Inst::Store64 { rd, ref mem }
1938             | &Inst::StoreRev16 { rd, ref mem }
1939             | &Inst::StoreRev32 { rd, ref mem }
1940             | &Inst::StoreRev64 { rd, ref mem } => {
1941                 let (opcode_rx, opcode_rxy, opcode_ril) = match self {
1942                     &Inst::Store8 { .. } => (Some("stc"), Some("stcy"), None),
1943                     &Inst::Store16 { .. } => (Some("sth"), Some("sthy"), Some("sthrl")),
1944                     &Inst::Store32 { .. } => (Some("st"), Some("sty"), Some("strl")),
1945                     &Inst::Store64 { .. } => (None, Some("stg"), Some("stgrl")),
1946                     &Inst::StoreRev16 { .. } => (None, Some("strvh"), None),
1947                     &Inst::StoreRev32 { .. } => (None, Some("strv"), None),
1948                     &Inst::StoreRev64 { .. } => (None, Some("strvg"), None),
1949                     _ => unreachable!(),
1950                 };
1951 
1952                 let rd = pretty_print_reg(rd);
1953                 let mem = mem.clone();
1954                 let (mem_str, mem) = mem_finalize_for_show(
1955                     &mem,
1956                     state,
1957                     MemInstType {
1958                         have_d12: opcode_rx.is_some(),
1959                         have_d20: opcode_rxy.is_some(),
1960                         have_pcrel: opcode_ril.is_some(),
1961                         have_unaligned_pcrel: false,
1962                         have_index: true,
1963                     },
1964                 );
1965                 let op = match &mem {
1966                     &MemArg::BXD12 { .. } => opcode_rx,
1967                     &MemArg::BXD20 { .. } => opcode_rxy,
1968                     &MemArg::Label { .. } | &MemArg::Constant { .. } | &MemArg::Symbol { .. } => {
1969                         opcode_ril
1970                     }
1971                     _ => unreachable!(),
1972                 };
1973                 let mem = mem.pretty_print_default();
1974 
1975                 format!("{}{} {}, {}", mem_str, op.unwrap(), rd, mem)
1976             }
1977             &Inst::StoreImm8 { imm, ref mem } => {
1978                 let mem = mem.clone();
1979                 let (mem_str, mem) = mem_finalize_for_show(
1980                     &mem,
1981                     state,
1982                     MemInstType {
1983                         have_d12: true,
1984                         have_d20: true,
1985                         have_pcrel: false,
1986                         have_unaligned_pcrel: false,
1987                         have_index: false,
1988                     },
1989                 );
1990                 let op = match &mem {
1991                     &MemArg::BXD12 { .. } => "mvi",
1992                     &MemArg::BXD20 { .. } => "mviy",
1993                     _ => unreachable!(),
1994                 };
1995                 let mem = mem.pretty_print_default();
1996 
1997                 format!("{mem_str}{op} {mem}, {imm}")
1998             }
1999             &Inst::StoreImm16 { imm, ref mem }
2000             | &Inst::StoreImm32SExt16 { imm, ref mem }
2001             | &Inst::StoreImm64SExt16 { imm, ref mem } => {
2002                 let mem = mem.clone();
2003                 let (mem_str, mem) = mem_finalize_for_show(
2004                     &mem,
2005                     state,
2006                     MemInstType {
2007                         have_d12: false,
2008                         have_d20: true,
2009                         have_pcrel: false,
2010                         have_unaligned_pcrel: false,
2011                         have_index: false,
2012                     },
2013                 );
2014                 let op = match self {
2015                     &Inst::StoreImm16 { .. } => "mvhhi",
2016                     &Inst::StoreImm32SExt16 { .. } => "mvhi",
2017                     &Inst::StoreImm64SExt16 { .. } => "mvghi",
2018                     _ => unreachable!(),
2019                 };
2020                 let mem = mem.pretty_print_default();
2021 
2022                 format!("{mem_str}{op} {mem}, {imm}")
2023             }
2024             &Inst::LoadMultiple64 { rt, rt2, ref mem } => {
2025                 let mem = mem.clone();
2026                 let (mem_str, mem) = mem_finalize_for_show(
2027                     &mem,
2028                     state,
2029                     MemInstType {
2030                         have_d12: false,
2031                         have_d20: true,
2032                         have_pcrel: false,
2033                         have_unaligned_pcrel: false,
2034                         have_index: false,
2035                     },
2036                 );
2037                 let rt = pretty_print_reg(rt.to_reg());
2038                 let rt2 = pretty_print_reg(rt2.to_reg());
2039                 let mem = mem.pretty_print_default();
2040                 format!("{mem_str}lmg {rt}, {rt2}, {mem}")
2041             }
2042             &Inst::StoreMultiple64 { rt, rt2, ref mem } => {
2043                 let mem = mem.clone();
2044                 let (mem_str, mem) = mem_finalize_for_show(
2045                     &mem,
2046                     state,
2047                     MemInstType {
2048                         have_d12: false,
2049                         have_d20: true,
2050                         have_pcrel: false,
2051                         have_unaligned_pcrel: false,
2052                         have_index: false,
2053                     },
2054                 );
2055                 let rt = pretty_print_reg(rt);
2056                 let rt2 = pretty_print_reg(rt2);
2057                 let mem = mem.pretty_print_default();
2058                 format!("{mem_str}stmg {rt}, {rt2}, {mem}")
2059             }
2060             &Inst::Mov64 { rd, rm } => {
2061                 let rd = pretty_print_reg(rd.to_reg());
2062                 let rm = pretty_print_reg(rm);
2063                 format!("lgr {rd}, {rm}")
2064             }
2065             &Inst::MovPReg { rd, rm } => {
2066                 let rd = pretty_print_reg(rd.to_reg());
2067                 let rm = show_reg(rm.into());
2068                 format!("lgr {rd}, {rm}")
2069             }
2070             &Inst::Mov32 { rd, rm } => {
2071                 let rd = pretty_print_reg(rd.to_reg());
2072                 let rm = pretty_print_reg(rm);
2073                 format!("lr {rd}, {rm}")
2074             }
2075             &Inst::Mov32Imm { rd, ref imm } => {
2076                 let rd = pretty_print_reg(rd.to_reg());
2077                 format!("iilf {rd}, {imm}")
2078             }
2079             &Inst::Mov32SImm16 { rd, ref imm } => {
2080                 let rd = pretty_print_reg(rd.to_reg());
2081                 format!("lhi {rd}, {imm}")
2082             }
2083             &Inst::Mov64SImm16 { rd, ref imm } => {
2084                 let rd = pretty_print_reg(rd.to_reg());
2085                 format!("lghi {rd}, {imm}")
2086             }
2087             &Inst::Mov64SImm32 { rd, ref imm } => {
2088                 let rd = pretty_print_reg(rd.to_reg());
2089                 format!("lgfi {rd}, {imm}")
2090             }
2091             &Inst::Mov64UImm16Shifted { rd, ref imm } => {
2092                 let rd = pretty_print_reg(rd.to_reg());
2093                 let op = match imm.shift {
2094                     0 => "llill",
2095                     1 => "llilh",
2096                     2 => "llihl",
2097                     3 => "llihh",
2098                     _ => unreachable!(),
2099                 };
2100                 format!("{} {}, {}", op, rd, imm.bits)
2101             }
2102             &Inst::Mov64UImm32Shifted { rd, ref imm } => {
2103                 let rd = pretty_print_reg(rd.to_reg());
2104                 let op = match imm.shift {
2105                     0 => "llilf",
2106                     1 => "llihf",
2107                     _ => unreachable!(),
2108                 };
2109                 format!("{} {}, {}", op, rd, imm.bits)
2110             }
2111             &Inst::Insert64UImm16Shifted { rd, ri, ref imm } => {
2112                 let rd = pretty_print_reg_mod(rd, ri);
2113                 let op = match imm.shift {
2114                     0 => "iill",
2115                     1 => "iilh",
2116                     2 => "iihl",
2117                     3 => "iihh",
2118                     _ => unreachable!(),
2119                 };
2120                 format!("{} {}, {}", op, rd, imm.bits)
2121             }
2122             &Inst::Insert64UImm32Shifted { rd, ri, ref imm } => {
2123                 let rd = pretty_print_reg_mod(rd, ri);
2124                 let op = match imm.shift {
2125                     0 => "iilf",
2126                     1 => "iihf",
2127                     _ => unreachable!(),
2128                 };
2129                 format!("{} {}, {}", op, rd, imm.bits)
2130             }
2131             &Inst::LoadAR { rd, ar } => {
2132                 let rd = pretty_print_reg(rd.to_reg());
2133                 format!("ear {rd}, %a{ar}")
2134             }
2135             &Inst::InsertAR { rd, ri, ar } => {
2136                 let rd = pretty_print_reg_mod(rd, ri);
2137                 format!("ear {rd}, %a{ar}")
2138             }
2139             &Inst::CMov32 { rd, cond, ri, rm } => {
2140                 let rd = pretty_print_reg_mod(rd, ri);
2141                 let rm = pretty_print_reg(rm);
2142                 let cond = cond.pretty_print_default();
2143                 format!("locr{cond} {rd}, {rm}")
2144             }
2145             &Inst::CMov64 { rd, cond, ri, rm } => {
2146                 let rd = pretty_print_reg_mod(rd, ri);
2147                 let rm = pretty_print_reg(rm);
2148                 let cond = cond.pretty_print_default();
2149                 format!("locgr{cond} {rd}, {rm}")
2150             }
2151             &Inst::CMov32SImm16 {
2152                 rd,
2153                 cond,
2154                 ri,
2155                 ref imm,
2156             } => {
2157                 let rd = pretty_print_reg_mod(rd, ri);
2158                 let cond = cond.pretty_print_default();
2159                 format!("lochi{cond} {rd}, {imm}")
2160             }
2161             &Inst::CMov64SImm16 {
2162                 rd,
2163                 cond,
2164                 ri,
2165                 ref imm,
2166             } => {
2167                 let rd = pretty_print_reg_mod(rd, ri);
2168                 let cond = cond.pretty_print_default();
2169                 format!("locghi{cond} {rd}, {imm}")
2170             }
2171             &Inst::FpuMove32 { rd, rn } => {
2172                 let (rd, rd_fpr) = pretty_print_fpr(rd.to_reg());
2173                 let (rn, rn_fpr) = pretty_print_fpr(rn);
2174                 if rd_fpr.is_some() && rn_fpr.is_some() {
2175                     format!("ler {}, {}", rd_fpr.unwrap(), rn_fpr.unwrap())
2176                 } else {
2177                     format!("vlr {rd}, {rn}")
2178                 }
2179             }
2180             &Inst::FpuMove64 { rd, rn } => {
2181                 let (rd, rd_fpr) = pretty_print_fpr(rd.to_reg());
2182                 let (rn, rn_fpr) = pretty_print_fpr(rn);
2183                 if rd_fpr.is_some() && rn_fpr.is_some() {
2184                     format!("ldr {}, {}", rd_fpr.unwrap(), rn_fpr.unwrap())
2185                 } else {
2186                     format!("vlr {rd}, {rn}")
2187                 }
2188             }
2189             &Inst::FpuCMov32 { rd, cond, rm, .. } => {
2190                 let (rd, rd_fpr) = pretty_print_fpr(rd.to_reg());
2191                 let (rm, rm_fpr) = pretty_print_fpr(rm);
2192                 if rd_fpr.is_some() && rm_fpr.is_some() {
2193                     let cond = cond.invert().pretty_print_default();
2194                     format!("j{} 6 ; ler {}, {}", cond, rd_fpr.unwrap(), rm_fpr.unwrap())
2195                 } else {
2196                     let cond = cond.invert().pretty_print_default();
2197                     format!("j{cond} 10 ; vlr {rd}, {rm}")
2198                 }
2199             }
2200             &Inst::FpuCMov64 { rd, cond, rm, .. } => {
2201                 let (rd, rd_fpr) = pretty_print_fpr(rd.to_reg());
2202                 let (rm, rm_fpr) = pretty_print_fpr(rm);
2203                 if rd_fpr.is_some() && rm_fpr.is_some() {
2204                     let cond = cond.invert().pretty_print_default();
2205                     format!("j{} 6 ; ldr {}, {}", cond, rd_fpr.unwrap(), rm_fpr.unwrap())
2206                 } else {
2207                     let cond = cond.invert().pretty_print_default();
2208                     format!("j{cond} 10 ; vlr {rd}, {rm}")
2209                 }
2210             }
2211             &Inst::FpuRR { fpu_op, rd, rn } => {
2212                 let (op, op_fpr) = match fpu_op {
2213                     FPUOp1::Abs32 => ("wflpsb", Some("lpebr")),
2214                     FPUOp1::Abs64 => ("wflpdb", Some("lpdbr")),
2215                     FPUOp1::Abs128 => ("wflpxb", None),
2216                     FPUOp1::Abs32x4 => ("vflpsb", None),
2217                     FPUOp1::Abs64x2 => ("vflpdb", None),
2218                     FPUOp1::Neg32 => ("wflcsb", Some("lcebr")),
2219                     FPUOp1::Neg64 => ("wflcdb", Some("lcdbr")),
2220                     FPUOp1::Neg128 => ("wflcxb", None),
2221                     FPUOp1::Neg32x4 => ("vflcsb", None),
2222                     FPUOp1::Neg64x2 => ("vflcdb", None),
2223                     FPUOp1::NegAbs32 => ("wflnsb", Some("lnebr")),
2224                     FPUOp1::NegAbs64 => ("wflndb", Some("lndbr")),
2225                     FPUOp1::NegAbs128 => ("wflnxb", None),
2226                     FPUOp1::NegAbs32x4 => ("vflnsb", None),
2227                     FPUOp1::NegAbs64x2 => ("vflndb", None),
2228                     FPUOp1::Sqrt32 => ("wfsqsb", Some("sqebr")),
2229                     FPUOp1::Sqrt64 => ("wfsqdb", Some("sqdbr")),
2230                     FPUOp1::Sqrt128 => ("wfsqxb", None),
2231                     FPUOp1::Sqrt32x4 => ("vfsqsb", None),
2232                     FPUOp1::Sqrt64x2 => ("vfsqdb", None),
2233                     FPUOp1::Cvt32To64 => ("wldeb", Some("ldebr")),
2234                     FPUOp1::Cvt32x4To64x2 => ("vldeb", None),
2235                     FPUOp1::Cvt64To128 => ("wflld", None),
2236                 };
2237 
2238                 let (rd, rd_fpr) = pretty_print_fpr(rd.to_reg());
2239                 let (rn, rn_fpr) = pretty_print_fpr(rn);
2240                 if op_fpr.is_some() && rd_fpr.is_some() && rn_fpr.is_some() {
2241                     format!(
2242                         "{} {}, {}",
2243                         op_fpr.unwrap(),
2244                         rd_fpr.unwrap(),
2245                         rn_fpr.unwrap()
2246                     )
2247                 } else if op.starts_with('w') {
2248                     format!("{} {}, {}", op, rd_fpr.unwrap_or(rd), rn_fpr.unwrap_or(rn))
2249                 } else {
2250                     format!("{op} {rd}, {rn}")
2251                 }
2252             }
2253             &Inst::FpuRRR { fpu_op, rd, rn, rm } => {
2254                 let (op, opt_m6, op_fpr) = match fpu_op {
2255                     FPUOp2::Add32 => ("wfasb", "", Some("aebr")),
2256                     FPUOp2::Add64 => ("wfadb", "", Some("adbr")),
2257                     FPUOp2::Add128 => ("wfaxb", "", None),
2258                     FPUOp2::Add32x4 => ("vfasb", "", None),
2259                     FPUOp2::Add64x2 => ("vfadb", "", None),
2260                     FPUOp2::Sub32 => ("wfssb", "", Some("sebr")),
2261                     FPUOp2::Sub64 => ("wfsdb", "", Some("sdbr")),
2262                     FPUOp2::Sub128 => ("wfsxb", "", None),
2263                     FPUOp2::Sub32x4 => ("vfssb", "", None),
2264                     FPUOp2::Sub64x2 => ("vfsdb", "", None),
2265                     FPUOp2::Mul32 => ("wfmsb", "", Some("meebr")),
2266                     FPUOp2::Mul64 => ("wfmdb", "", Some("mdbr")),
2267                     FPUOp2::Mul128 => ("wfmxb", "", None),
2268                     FPUOp2::Mul32x4 => ("vfmsb", "", None),
2269                     FPUOp2::Mul64x2 => ("vfmdb", "", None),
2270                     FPUOp2::Div32 => ("wfdsb", "", Some("debr")),
2271                     FPUOp2::Div64 => ("wfddb", "", Some("ddbr")),
2272                     FPUOp2::Div128 => ("wfdxb", "", None),
2273                     FPUOp2::Div32x4 => ("vfdsb", "", None),
2274                     FPUOp2::Div64x2 => ("vfddb", "", None),
2275                     FPUOp2::Max32 => ("wfmaxsb", ", 1", None),
2276                     FPUOp2::Max64 => ("wfmaxdb", ", 1", None),
2277                     FPUOp2::Max128 => ("wfmaxxb", ", 1", None),
2278                     FPUOp2::Max32x4 => ("vfmaxsb", ", 1", None),
2279                     FPUOp2::Max64x2 => ("vfmaxdb", ", 1", None),
2280                     FPUOp2::Min32 => ("wfminsb", ", 1", None),
2281                     FPUOp2::Min64 => ("wfmindb", ", 1", None),
2282                     FPUOp2::Min128 => ("wfminxb", ", 1", None),
2283                     FPUOp2::Min32x4 => ("vfminsb", ", 1", None),
2284                     FPUOp2::Min64x2 => ("vfmindb", ", 1", None),
2285                     FPUOp2::MaxPseudo32 => ("wfmaxsb", ", 3", None),
2286                     FPUOp2::MaxPseudo64 => ("wfmaxdb", ", 3", None),
2287                     FPUOp2::MaxPseudo128 => ("wfmaxxb", ", 3", None),
2288                     FPUOp2::MaxPseudo32x4 => ("vfmaxsb", ", 3", None),
2289                     FPUOp2::MaxPseudo64x2 => ("vfmaxdb", ", 3", None),
2290                     FPUOp2::MinPseudo32 => ("wfminsb", ", 3", None),
2291                     FPUOp2::MinPseudo64 => ("wfmindb", ", 3", None),
2292                     FPUOp2::MinPseudo128 => ("wfminxb", ", 3", None),
2293                     FPUOp2::MinPseudo32x4 => ("vfminsb", ", 3", None),
2294                     FPUOp2::MinPseudo64x2 => ("vfmindb", ", 3", None),
2295                 };
2296 
2297                 let (rd, rd_fpr) = pretty_print_fpr(rd.to_reg());
2298                 let (rn, rn_fpr) = pretty_print_fpr(rn);
2299                 let (rm, rm_fpr) = pretty_print_fpr(rm);
2300                 if op_fpr.is_some() && rd == rn && rd_fpr.is_some() && rm_fpr.is_some() {
2301                     format!(
2302                         "{} {}, {}",
2303                         op_fpr.unwrap(),
2304                         rd_fpr.unwrap(),
2305                         rm_fpr.unwrap()
2306                     )
2307                 } else if op.starts_with('w') {
2308                     format!(
2309                         "{} {}, {}, {}{}",
2310                         op,
2311                         rd_fpr.unwrap_or(rd),
2312                         rn_fpr.unwrap_or(rn),
2313                         rm_fpr.unwrap_or(rm),
2314                         opt_m6
2315                     )
2316                 } else {
2317                     format!("{op} {rd}, {rn}, {rm}{opt_m6}")
2318                 }
2319             }
2320             &Inst::FpuRRRR {
2321                 fpu_op,
2322                 rd,
2323                 rn,
2324                 rm,
2325                 ra,
2326             } => {
2327                 let (op, op_fpr) = match fpu_op {
2328                     FPUOp3::MAdd32 => ("wfmasb", Some("maebr")),
2329                     FPUOp3::MAdd64 => ("wfmadb", Some("madbr")),
2330                     FPUOp3::MAdd128 => ("wfmaxb", None),
2331                     FPUOp3::MAdd32x4 => ("vfmasb", None),
2332                     FPUOp3::MAdd64x2 => ("vfmadb", None),
2333                     FPUOp3::MSub32 => ("wfmssb", Some("msebr")),
2334                     FPUOp3::MSub64 => ("wfmsdb", Some("msdbr")),
2335                     FPUOp3::MSub128 => ("wfmsxb", None),
2336                     FPUOp3::MSub32x4 => ("vfmssb", None),
2337                     FPUOp3::MSub64x2 => ("vfmsdb", None),
2338                 };
2339 
2340                 let (rd, rd_fpr) = pretty_print_fpr(rd.to_reg());
2341                 let (rn, rn_fpr) = pretty_print_fpr(rn);
2342                 let (rm, rm_fpr) = pretty_print_fpr(rm);
2343                 let (ra, ra_fpr) = pretty_print_fpr(ra);
2344                 if op_fpr.is_some()
2345                     && rd == ra
2346                     && rd_fpr.is_some()
2347                     && rn_fpr.is_some()
2348                     && rm_fpr.is_some()
2349                 {
2350                     format!(
2351                         "{} {}, {}, {}",
2352                         op_fpr.unwrap(),
2353                         rd_fpr.unwrap(),
2354                         rn_fpr.unwrap(),
2355                         rm_fpr.unwrap()
2356                     )
2357                 } else if op.starts_with('w') {
2358                     format!(
2359                         "{} {}, {}, {}, {}",
2360                         op,
2361                         rd_fpr.unwrap_or(rd),
2362                         rn_fpr.unwrap_or(rn),
2363                         rm_fpr.unwrap_or(rm),
2364                         ra_fpr.unwrap_or(ra)
2365                     )
2366                 } else {
2367                     format!("{op} {rd}, {rn}, {rm}, {ra}")
2368                 }
2369             }
2370             &Inst::FpuCmp32 { rn, rm } => {
2371                 let (rn, rn_fpr) = pretty_print_fpr(rn);
2372                 let (rm, rm_fpr) = pretty_print_fpr(rm);
2373                 if rn_fpr.is_some() && rm_fpr.is_some() {
2374                     format!("cebr {}, {}", rn_fpr.unwrap(), rm_fpr.unwrap())
2375                 } else {
2376                     format!("wfcsb {}, {}", rn_fpr.unwrap_or(rn), rm_fpr.unwrap_or(rm))
2377                 }
2378             }
2379             &Inst::FpuCmp64 { rn, rm } => {
2380                 let (rn, rn_fpr) = pretty_print_fpr(rn);
2381                 let (rm, rm_fpr) = pretty_print_fpr(rm);
2382                 if rn_fpr.is_some() && rm_fpr.is_some() {
2383                     format!("cdbr {}, {}", rn_fpr.unwrap(), rm_fpr.unwrap())
2384                 } else {
2385                     format!("wfcdb {}, {}", rn_fpr.unwrap_or(rn), rm_fpr.unwrap_or(rm))
2386                 }
2387             }
2388             &Inst::FpuCmp128 { rn, rm } => {
2389                 let (rn, rn_fpr) = pretty_print_fpr(rn);
2390                 let (rm, rm_fpr) = pretty_print_fpr(rm);
2391                 format!("wfcxb {}, {}", rn_fpr.unwrap_or(rn), rm_fpr.unwrap_or(rm))
2392             }
2393             &Inst::FpuRound { op, mode, rd, rn } => {
2394                 let mode = match mode {
2395                     FpuRoundMode::Current => 0,
2396                     FpuRoundMode::ToNearest => 1,
2397                     FpuRoundMode::ShorterPrecision => 3,
2398                     FpuRoundMode::ToNearestTiesToEven => 4,
2399                     FpuRoundMode::ToZero => 5,
2400                     FpuRoundMode::ToPosInfinity => 6,
2401                     FpuRoundMode::ToNegInfinity => 7,
2402                 };
2403                 let (opcode, opcode_fpr) = match op {
2404                     FpuRoundOp::Cvt64To32 => ("wledb", Some("ledbra")),
2405                     FpuRoundOp::Cvt64x2To32x4 => ("vledb", None),
2406                     FpuRoundOp::Cvt128To64 => ("wflrx", None),
2407                     FpuRoundOp::Round32 => ("wfisb", Some("fiebr")),
2408                     FpuRoundOp::Round64 => ("wfidb", Some("fidbr")),
2409                     FpuRoundOp::Round128 => ("wfixb", None),
2410                     FpuRoundOp::Round32x4 => ("vfisb", None),
2411                     FpuRoundOp::Round64x2 => ("vfidb", None),
2412                     FpuRoundOp::ToSInt32 => ("wcfeb", None),
2413                     FpuRoundOp::ToSInt64 => ("wcgdb", None),
2414                     FpuRoundOp::ToUInt32 => ("wclfeb", None),
2415                     FpuRoundOp::ToUInt64 => ("wclgdb", None),
2416                     FpuRoundOp::ToSInt32x4 => ("vcfeb", None),
2417                     FpuRoundOp::ToSInt64x2 => ("vcgdb", None),
2418                     FpuRoundOp::ToUInt32x4 => ("vclfeb", None),
2419                     FpuRoundOp::ToUInt64x2 => ("vclgdb", None),
2420                     FpuRoundOp::FromSInt32 => ("wcefb", None),
2421                     FpuRoundOp::FromSInt64 => ("wcdgb", None),
2422                     FpuRoundOp::FromUInt32 => ("wcelfb", None),
2423                     FpuRoundOp::FromUInt64 => ("wcdlgb", None),
2424                     FpuRoundOp::FromSInt32x4 => ("vcefb", None),
2425                     FpuRoundOp::FromSInt64x2 => ("vcdgb", None),
2426                     FpuRoundOp::FromUInt32x4 => ("vcelfb", None),
2427                     FpuRoundOp::FromUInt64x2 => ("vcdlgb", None),
2428                 };
2429 
2430                 let (rd, rd_fpr) = pretty_print_fpr(rd.to_reg());
2431                 let (rn, rn_fpr) = pretty_print_fpr(rn);
2432                 if opcode_fpr.is_some() && rd_fpr.is_some() && rn_fpr.is_some() {
2433                     format!(
2434                         "{} {}, {}, {}{}",
2435                         opcode_fpr.unwrap(),
2436                         rd_fpr.unwrap(),
2437                         mode,
2438                         rn_fpr.unwrap(),
2439                         if opcode_fpr.unwrap().ends_with('a') {
2440                             ", 0"
2441                         } else {
2442                             ""
2443                         }
2444                     )
2445                 } else if opcode.starts_with('w') {
2446                     format!(
2447                         "{} {}, {}, 0, {}",
2448                         opcode,
2449                         rd_fpr.unwrap_or(rd),
2450                         rn_fpr.unwrap_or(rn),
2451                         mode
2452                     )
2453                 } else {
2454                     format!("{opcode} {rd}, {rn}, 0, {mode}")
2455                 }
2456             }
2457             &Inst::FpuConv128FromInt { op, mode, rd, rn } => {
2458                 let mode = match mode {
2459                     FpuRoundMode::Current => 0,
2460                     FpuRoundMode::ToNearest => 1,
2461                     FpuRoundMode::ShorterPrecision => 3,
2462                     FpuRoundMode::ToNearestTiesToEven => 4,
2463                     FpuRoundMode::ToZero => 5,
2464                     FpuRoundMode::ToPosInfinity => 6,
2465                     FpuRoundMode::ToNegInfinity => 7,
2466                 };
2467                 let opcode = match op {
2468                     FpuConv128Op::SInt32 => "cxfbra",
2469                     FpuConv128Op::SInt64 => "cxgbra",
2470                     FpuConv128Op::UInt32 => "cxlfbr",
2471                     FpuConv128Op::UInt64 => "cxlgbr",
2472                 };
2473                 let rd = pretty_print_fp_regpair(rd.to_regpair());
2474                 let rn = pretty_print_reg(rn);
2475                 format!("{opcode} {rd}, {mode}, {rn}, 0")
2476             }
2477             &Inst::FpuConv128ToInt { op, mode, rd, rn } => {
2478                 let mode = match mode {
2479                     FpuRoundMode::Current => 0,
2480                     FpuRoundMode::ToNearest => 1,
2481                     FpuRoundMode::ShorterPrecision => 3,
2482                     FpuRoundMode::ToNearestTiesToEven => 4,
2483                     FpuRoundMode::ToZero => 5,
2484                     FpuRoundMode::ToPosInfinity => 6,
2485                     FpuRoundMode::ToNegInfinity => 7,
2486                 };
2487                 let opcode = match op {
2488                     FpuConv128Op::SInt32 => "cfxbra",
2489                     FpuConv128Op::SInt64 => "cgxbra",
2490                     FpuConv128Op::UInt32 => "clfxbr",
2491                     FpuConv128Op::UInt64 => "clgxbr",
2492                 };
2493                 let rd = pretty_print_reg(rd.to_reg());
2494                 let rn = pretty_print_fp_regpair(rn);
2495                 format!("{opcode} {rd}, {mode}, {rn}, 0")
2496             }
2497 
2498             &Inst::VecRRR { op, rd, rn, rm } => {
2499                 let m5 = match op {
2500                     VecBinaryOp::UDiv32x4 | VecBinaryOp::SDiv32x4 => ", 0",
2501                     VecBinaryOp::UDiv64x2 | VecBinaryOp::SDiv64x2 => ", 0",
2502                     VecBinaryOp::UDiv128 | VecBinaryOp::SDiv128 => ", 0",
2503                     VecBinaryOp::URem32x4 | VecBinaryOp::SRem32x4 => ", 0",
2504                     VecBinaryOp::URem64x2 | VecBinaryOp::SRem64x2 => ", 0",
2505                     VecBinaryOp::URem128 | VecBinaryOp::SRem128 => ", 0",
2506                     _ => "",
2507                 };
2508                 let op = match op {
2509                     VecBinaryOp::Add8x16 => "vab",
2510                     VecBinaryOp::Add16x8 => "vah",
2511                     VecBinaryOp::Add32x4 => "vaf",
2512                     VecBinaryOp::Add64x2 => "vag",
2513                     VecBinaryOp::Add128 => "vaq",
2514                     VecBinaryOp::Sub8x16 => "vsb",
2515                     VecBinaryOp::Sub16x8 => "vsh",
2516                     VecBinaryOp::Sub32x4 => "vsf",
2517                     VecBinaryOp::Sub64x2 => "vsg",
2518                     VecBinaryOp::Sub128 => "vsq",
2519                     VecBinaryOp::Mul8x16 => "vmlb",
2520                     VecBinaryOp::Mul16x8 => "vmlhw",
2521                     VecBinaryOp::Mul32x4 => "vmlf",
2522                     VecBinaryOp::Mul64x2 => "vmlg",
2523                     VecBinaryOp::Mul128 => "vmlq",
2524                     VecBinaryOp::UMulHi8x16 => "vmlhb",
2525                     VecBinaryOp::UMulHi16x8 => "vmlhh",
2526                     VecBinaryOp::UMulHi32x4 => "vmlhf",
2527                     VecBinaryOp::UMulHi64x2 => "vmlhg",
2528                     VecBinaryOp::UMulHi128 => "vmlhq",
2529                     VecBinaryOp::SMulHi8x16 => "vmhb",
2530                     VecBinaryOp::SMulHi16x8 => "vmhh",
2531                     VecBinaryOp::SMulHi32x4 => "vmhf",
2532                     VecBinaryOp::SMulHi64x2 => "vmhg",
2533                     VecBinaryOp::SMulHi128 => "vmhq",
2534                     VecBinaryOp::UMulEven8x16 => "vmleb",
2535                     VecBinaryOp::UMulEven16x8 => "vmleh",
2536                     VecBinaryOp::UMulEven32x4 => "vmlef",
2537                     VecBinaryOp::UMulEven64x2 => "vmleg",
2538                     VecBinaryOp::SMulEven8x16 => "vmeb",
2539                     VecBinaryOp::SMulEven16x8 => "vmeh",
2540                     VecBinaryOp::SMulEven32x4 => "vmef",
2541                     VecBinaryOp::SMulEven64x2 => "vmeg",
2542                     VecBinaryOp::UMulOdd8x16 => "vmlob",
2543                     VecBinaryOp::UMulOdd16x8 => "vmloh",
2544                     VecBinaryOp::UMulOdd32x4 => "vmlof",
2545                     VecBinaryOp::UMulOdd64x2 => "vmlog",
2546                     VecBinaryOp::SMulOdd8x16 => "vmob",
2547                     VecBinaryOp::SMulOdd16x8 => "vmoh",
2548                     VecBinaryOp::SMulOdd32x4 => "vmof",
2549                     VecBinaryOp::SMulOdd64x2 => "vmog",
2550                     VecBinaryOp::SDiv32x4 => "vdf",
2551                     VecBinaryOp::SDiv64x2 => "vdg",
2552                     VecBinaryOp::SDiv128 => "vdq",
2553                     VecBinaryOp::UDiv32x4 => "vdlf",
2554                     VecBinaryOp::UDiv64x2 => "vdlg",
2555                     VecBinaryOp::UDiv128 => "vdlq",
2556                     VecBinaryOp::SRem32x4 => "vrf",
2557                     VecBinaryOp::SRem64x2 => "vrg",
2558                     VecBinaryOp::SRem128 => "vrq",
2559                     VecBinaryOp::URem32x4 => "vrlf",
2560                     VecBinaryOp::URem64x2 => "vrlg",
2561                     VecBinaryOp::URem128 => "vrlq",
2562                     VecBinaryOp::UMax8x16 => "vmxlb",
2563                     VecBinaryOp::UMax16x8 => "vmxlh",
2564                     VecBinaryOp::UMax32x4 => "vmxlf",
2565                     VecBinaryOp::UMax64x2 => "vmxlg",
2566                     VecBinaryOp::UMax128 => "vmxlq",
2567                     VecBinaryOp::SMax8x16 => "vmxb",
2568                     VecBinaryOp::SMax16x8 => "vmxh",
2569                     VecBinaryOp::SMax32x4 => "vmxf",
2570                     VecBinaryOp::SMax64x2 => "vmxg",
2571                     VecBinaryOp::SMax128 => "vmxq",
2572                     VecBinaryOp::UMin8x16 => "vmnlb",
2573                     VecBinaryOp::UMin16x8 => "vmnlh",
2574                     VecBinaryOp::UMin32x4 => "vmnlf",
2575                     VecBinaryOp::UMin64x2 => "vmnlg",
2576                     VecBinaryOp::UMin128 => "vmnlq",
2577                     VecBinaryOp::SMin8x16 => "vmnb",
2578                     VecBinaryOp::SMin16x8 => "vmnh",
2579                     VecBinaryOp::SMin32x4 => "vmnf",
2580                     VecBinaryOp::SMin64x2 => "vmng",
2581                     VecBinaryOp::SMin128 => "vmnq",
2582                     VecBinaryOp::UAvg8x16 => "vavglb",
2583                     VecBinaryOp::UAvg16x8 => "vavglh",
2584                     VecBinaryOp::UAvg32x4 => "vavglf",
2585                     VecBinaryOp::UAvg64x2 => "vavglg",
2586                     VecBinaryOp::UAvg128 => "vavglq",
2587                     VecBinaryOp::SAvg8x16 => "vavgb",
2588                     VecBinaryOp::SAvg16x8 => "vavgh",
2589                     VecBinaryOp::SAvg32x4 => "vavgf",
2590                     VecBinaryOp::SAvg64x2 => "vavgg",
2591                     VecBinaryOp::SAvg128 => "vavgq",
2592                     VecBinaryOp::And128 => "vn",
2593                     VecBinaryOp::Orr128 => "vo",
2594                     VecBinaryOp::Xor128 => "vx",
2595                     VecBinaryOp::NotAnd128 => "vnn",
2596                     VecBinaryOp::NotOrr128 => "vno",
2597                     VecBinaryOp::NotXor128 => "vnx",
2598                     VecBinaryOp::AndNot128 => "vnc",
2599                     VecBinaryOp::OrrNot128 => "voc",
2600                     VecBinaryOp::BitPermute128 => "vbperm",
2601                     VecBinaryOp::LShLByByte128 => "vslb",
2602                     VecBinaryOp::LShRByByte128 => "vsrlb",
2603                     VecBinaryOp::AShRByByte128 => "vsrab",
2604                     VecBinaryOp::LShLByBit128 => "vsl",
2605                     VecBinaryOp::LShRByBit128 => "vsrl",
2606                     VecBinaryOp::AShRByBit128 => "vsra",
2607                     VecBinaryOp::Pack16x8 => "vpkh",
2608                     VecBinaryOp::Pack32x4 => "vpkf",
2609                     VecBinaryOp::Pack64x2 => "vpkg",
2610                     VecBinaryOp::PackUSat16x8 => "vpklsh",
2611                     VecBinaryOp::PackUSat32x4 => "vpklsf",
2612                     VecBinaryOp::PackUSat64x2 => "vpklsg",
2613                     VecBinaryOp::PackSSat16x8 => "vpksh",
2614                     VecBinaryOp::PackSSat32x4 => "vpksf",
2615                     VecBinaryOp::PackSSat64x2 => "vpksg",
2616                     VecBinaryOp::MergeLow8x16 => "vmrlb",
2617                     VecBinaryOp::MergeLow16x8 => "vmrlh",
2618                     VecBinaryOp::MergeLow32x4 => "vmrlf",
2619                     VecBinaryOp::MergeLow64x2 => "vmrlg",
2620                     VecBinaryOp::MergeHigh8x16 => "vmrhb",
2621                     VecBinaryOp::MergeHigh16x8 => "vmrhh",
2622                     VecBinaryOp::MergeHigh32x4 => "vmrhf",
2623                     VecBinaryOp::MergeHigh64x2 => "vmrhg",
2624                 };
2625                 let rd = pretty_print_reg(rd.to_reg());
2626                 let rn = pretty_print_reg(rn);
2627                 let rm = pretty_print_reg(rm);
2628                 format!("{op} {rd}, {rn}, {rm}{m5}")
2629             }
2630             &Inst::VecRR { op, rd, rn } => {
2631                 let op = match op {
2632                     VecUnaryOp::Abs8x16 => "vlpb",
2633                     VecUnaryOp::Abs16x8 => "vlph",
2634                     VecUnaryOp::Abs32x4 => "vlpf",
2635                     VecUnaryOp::Abs64x2 => "vlpg",
2636                     VecUnaryOp::Abs128 => "vlpq",
2637                     VecUnaryOp::Neg8x16 => "vlcb",
2638                     VecUnaryOp::Neg16x8 => "vlch",
2639                     VecUnaryOp::Neg32x4 => "vlcf",
2640                     VecUnaryOp::Neg64x2 => "vlcg",
2641                     VecUnaryOp::Neg128 => "vlcq",
2642                     VecUnaryOp::Popcnt8x16 => "vpopctb",
2643                     VecUnaryOp::Popcnt16x8 => "vpopcth",
2644                     VecUnaryOp::Popcnt32x4 => "vpopctf",
2645                     VecUnaryOp::Popcnt64x2 => "vpopctg",
2646                     VecUnaryOp::Clz8x16 => "vclzb",
2647                     VecUnaryOp::Clz16x8 => "vclzh",
2648                     VecUnaryOp::Clz32x4 => "vclzf",
2649                     VecUnaryOp::Clz64x2 => "vclzg",
2650                     VecUnaryOp::Clz128 => "vclzq",
2651                     VecUnaryOp::Ctz8x16 => "vctzb",
2652                     VecUnaryOp::Ctz16x8 => "vctzh",
2653                     VecUnaryOp::Ctz32x4 => "vctzf",
2654                     VecUnaryOp::Ctz64x2 => "vctzg",
2655                     VecUnaryOp::Ctz128 => "vctzq",
2656                     VecUnaryOp::UnpackULow8x16 => "vupllb",
2657                     VecUnaryOp::UnpackULow16x8 => "vupllh",
2658                     VecUnaryOp::UnpackULow32x4 => "vupllf",
2659                     VecUnaryOp::UnpackULow64x2 => "vupllg",
2660                     VecUnaryOp::UnpackUHigh8x16 => "vuplhb",
2661                     VecUnaryOp::UnpackUHigh16x8 => "vuplhh",
2662                     VecUnaryOp::UnpackUHigh32x4 => "vuplhf",
2663                     VecUnaryOp::UnpackUHigh64x2 => "vuplhg",
2664                     VecUnaryOp::UnpackSLow8x16 => "vuplb",
2665                     VecUnaryOp::UnpackSLow16x8 => "vuplh",
2666                     VecUnaryOp::UnpackSLow32x4 => "vuplf",
2667                     VecUnaryOp::UnpackSLow64x2 => "vuplg",
2668                     VecUnaryOp::UnpackSHigh8x16 => "vuphb",
2669                     VecUnaryOp::UnpackSHigh16x8 => "vuphh",
2670                     VecUnaryOp::UnpackSHigh32x4 => "vuphf",
2671                     VecUnaryOp::UnpackSHigh64x2 => "vuphg",
2672                 };
2673                 let rd = pretty_print_reg(rd.to_reg());
2674                 let rn = pretty_print_reg(rn);
2675                 format!("{op} {rd}, {rn}")
2676             }
2677             &Inst::VecShiftRR {
2678                 shift_op,
2679                 rd,
2680                 rn,
2681                 shift_imm,
2682                 shift_reg,
2683             } => {
2684                 let op = match shift_op {
2685                     VecShiftOp::RotL8x16 => "verllb",
2686                     VecShiftOp::RotL16x8 => "verllh",
2687                     VecShiftOp::RotL32x4 => "verllf",
2688                     VecShiftOp::RotL64x2 => "verllg",
2689                     VecShiftOp::LShL8x16 => "veslb",
2690                     VecShiftOp::LShL16x8 => "veslh",
2691                     VecShiftOp::LShL32x4 => "veslf",
2692                     VecShiftOp::LShL64x2 => "veslg",
2693                     VecShiftOp::LShR8x16 => "vesrlb",
2694                     VecShiftOp::LShR16x8 => "vesrlh",
2695                     VecShiftOp::LShR32x4 => "vesrlf",
2696                     VecShiftOp::LShR64x2 => "vesrlg",
2697                     VecShiftOp::AShR8x16 => "vesrab",
2698                     VecShiftOp::AShR16x8 => "vesrah",
2699                     VecShiftOp::AShR32x4 => "vesraf",
2700                     VecShiftOp::AShR64x2 => "vesrag",
2701                 };
2702                 let rd = pretty_print_reg(rd.to_reg());
2703                 let rn = pretty_print_reg(rn);
2704                 let shift_reg = if shift_reg != zero_reg() {
2705                     format!("({})", pretty_print_reg(shift_reg))
2706                 } else {
2707                     "".to_string()
2708                 };
2709                 format!("{op} {rd}, {rn}, {shift_imm}{shift_reg}")
2710             }
2711             &Inst::VecSelect { rd, rn, rm, ra } => {
2712                 let rd = pretty_print_reg(rd.to_reg());
2713                 let rn = pretty_print_reg(rn);
2714                 let rm = pretty_print_reg(rm);
2715                 let ra = pretty_print_reg(ra);
2716                 format!("vsel {rd}, {rn}, {rm}, {ra}")
2717             }
2718             &Inst::VecBlend { rd, rn, rm, ra } => {
2719                 let rd = pretty_print_reg(rd.to_reg());
2720                 let rn = pretty_print_reg(rn);
2721                 let rm = pretty_print_reg(rm);
2722                 let ra = pretty_print_reg(ra);
2723                 format!("vblend {rd}, {rn}, {rm}, {ra}")
2724             }
2725             &Inst::VecPermute { rd, rn, rm, ra } => {
2726                 let rd = pretty_print_reg(rd.to_reg());
2727                 let rn = pretty_print_reg(rn);
2728                 let rm = pretty_print_reg(rm);
2729                 let ra = pretty_print_reg(ra);
2730                 format!("vperm {rd}, {rn}, {rm}, {ra}")
2731             }
2732             &Inst::VecEvaluate {
2733                 imm,
2734                 rd,
2735                 rn,
2736                 rm,
2737                 ra,
2738             } => {
2739                 let rd = pretty_print_reg(rd.to_reg());
2740                 let rn = pretty_print_reg(rn);
2741                 let rm = pretty_print_reg(rm);
2742                 let ra = pretty_print_reg(ra);
2743                 format!("veval {rd}, {rn}, {rm}, {ra}, {imm}")
2744             }
2745             &Inst::VecPermuteDWImm {
2746                 rd,
2747                 rn,
2748                 rm,
2749                 idx1,
2750                 idx2,
2751             } => {
2752                 let rd = pretty_print_reg(rd.to_reg());
2753                 let rn = pretty_print_reg(rn);
2754                 let rm = pretty_print_reg(rm);
2755                 let m4 = (idx1 & 1) * 4 + (idx2 & 1);
2756                 format!("vpdi {rd}, {rn}, {rm}, {m4}")
2757             }
2758             &Inst::VecIntCmp { op, rd, rn, rm } | &Inst::VecIntCmpS { op, rd, rn, rm } => {
2759                 let op = match op {
2760                     VecIntCmpOp::CmpEq8x16 => "vceqb",
2761                     VecIntCmpOp::CmpEq16x8 => "vceqh",
2762                     VecIntCmpOp::CmpEq32x4 => "vceqf",
2763                     VecIntCmpOp::CmpEq64x2 => "vceqg",
2764                     VecIntCmpOp::CmpEq128 => "vceqq",
2765                     VecIntCmpOp::SCmpHi8x16 => "vchb",
2766                     VecIntCmpOp::SCmpHi16x8 => "vchh",
2767                     VecIntCmpOp::SCmpHi32x4 => "vchf",
2768                     VecIntCmpOp::SCmpHi64x2 => "vchg",
2769                     VecIntCmpOp::SCmpHi128 => "vchq",
2770                     VecIntCmpOp::UCmpHi8x16 => "vchlb",
2771                     VecIntCmpOp::UCmpHi16x8 => "vchlh",
2772                     VecIntCmpOp::UCmpHi32x4 => "vchlf",
2773                     VecIntCmpOp::UCmpHi64x2 => "vchlg",
2774                     VecIntCmpOp::UCmpHi128 => "vchlq",
2775                 };
2776                 let s = match self {
2777                     &Inst::VecIntCmp { .. } => "",
2778                     &Inst::VecIntCmpS { .. } => "s",
2779                     _ => unreachable!(),
2780                 };
2781                 let rd = pretty_print_reg(rd.to_reg());
2782                 let rn = pretty_print_reg(rn);
2783                 let rm = pretty_print_reg(rm);
2784                 format!("{op}{s} {rd}, {rn}, {rm}")
2785             }
2786             &Inst::VecFloatCmp { op, rd, rn, rm } | &Inst::VecFloatCmpS { op, rd, rn, rm } => {
2787                 let op = match op {
2788                     VecFloatCmpOp::CmpEq32x4 => "vfcesb",
2789                     VecFloatCmpOp::CmpEq64x2 => "vfcedb",
2790                     VecFloatCmpOp::CmpHi32x4 => "vfchsb",
2791                     VecFloatCmpOp::CmpHi64x2 => "vfchdb",
2792                     VecFloatCmpOp::CmpHiEq32x4 => "vfchesb",
2793                     VecFloatCmpOp::CmpHiEq64x2 => "vfchedb",
2794                 };
2795                 let s = match self {
2796                     &Inst::VecFloatCmp { .. } => "",
2797                     &Inst::VecFloatCmpS { .. } => "s",
2798                     _ => unreachable!(),
2799                 };
2800                 let rd = pretty_print_reg(rd.to_reg());
2801                 let rn = pretty_print_reg(rn);
2802                 let rm = pretty_print_reg(rm);
2803                 format!("{op}{s} {rd}, {rn}, {rm}")
2804             }
2805             &Inst::VecIntEltCmp { op, rn, rm } => {
2806                 let op = match op {
2807                     VecIntEltCmpOp::SCmp128 => "vecq",
2808                     VecIntEltCmpOp::UCmp128 => "veclq",
2809                 };
2810                 let rn = pretty_print_reg(rn);
2811                 let rm = pretty_print_reg(rm);
2812                 format!("{op} {rn}, {rm}")
2813             }
2814             &Inst::VecInt128SCmpHi { tmp, rn, rm } | &Inst::VecInt128UCmpHi { tmp, rn, rm } => {
2815                 let op = match self {
2816                     &Inst::VecInt128SCmpHi { .. } => "vecg",
2817                     &Inst::VecInt128UCmpHi { .. } => "veclg",
2818                     _ => unreachable!(),
2819                 };
2820                 let tmp = pretty_print_reg(tmp.to_reg());
2821                 let rn = pretty_print_reg(rn);
2822                 let rm = pretty_print_reg(rm);
2823                 format!("{op} {rm}, {rn} ; jne 10 ; vchlgs {tmp}, {rn}, {rm}")
2824             }
2825             &Inst::VecLoad { rd, ref mem }
2826             | &Inst::VecLoadRev { rd, ref mem }
2827             | &Inst::VecLoadByte16Rev { rd, ref mem }
2828             | &Inst::VecLoadByte32Rev { rd, ref mem }
2829             | &Inst::VecLoadByte64Rev { rd, ref mem }
2830             | &Inst::VecLoadElt16Rev { rd, ref mem }
2831             | &Inst::VecLoadElt32Rev { rd, ref mem }
2832             | &Inst::VecLoadElt64Rev { rd, ref mem } => {
2833                 let opcode = match self {
2834                     &Inst::VecLoad { .. } => "vl",
2835                     &Inst::VecLoadRev { .. } => "vlbrq",
2836                     &Inst::VecLoadByte16Rev { .. } => "vlbrh",
2837                     &Inst::VecLoadByte32Rev { .. } => "vlbrf",
2838                     &Inst::VecLoadByte64Rev { .. } => "vlbrg",
2839                     &Inst::VecLoadElt16Rev { .. } => "vlerh",
2840                     &Inst::VecLoadElt32Rev { .. } => "vlerf",
2841                     &Inst::VecLoadElt64Rev { .. } => "vlerg",
2842                     _ => unreachable!(),
2843                 };
2844 
2845                 let rd = pretty_print_reg(rd.to_reg());
2846                 let mem = mem.clone();
2847                 let (mem_str, mem) = mem_finalize_for_show(
2848                     &mem,
2849                     state,
2850                     MemInstType {
2851                         have_d12: true,
2852                         have_d20: false,
2853                         have_pcrel: false,
2854                         have_unaligned_pcrel: false,
2855                         have_index: true,
2856                     },
2857                 );
2858                 let mem = mem.pretty_print_default();
2859                 format!("{mem_str}{opcode} {rd}, {mem}")
2860             }
2861             &Inst::VecStore { rd, ref mem }
2862             | &Inst::VecStoreRev { rd, ref mem }
2863             | &Inst::VecStoreByte16Rev { rd, ref mem }
2864             | &Inst::VecStoreByte32Rev { rd, ref mem }
2865             | &Inst::VecStoreByte64Rev { rd, ref mem }
2866             | &Inst::VecStoreElt16Rev { rd, ref mem }
2867             | &Inst::VecStoreElt32Rev { rd, ref mem }
2868             | &Inst::VecStoreElt64Rev { rd, ref mem } => {
2869                 let opcode = match self {
2870                     &Inst::VecStore { .. } => "vst",
2871                     &Inst::VecStoreRev { .. } => "vstbrq",
2872                     &Inst::VecStoreByte16Rev { .. } => "vstbrh",
2873                     &Inst::VecStoreByte32Rev { .. } => "vstbrf",
2874                     &Inst::VecStoreByte64Rev { .. } => "vstbrg",
2875                     &Inst::VecStoreElt16Rev { .. } => "vsterh",
2876                     &Inst::VecStoreElt32Rev { .. } => "vsterf",
2877                     &Inst::VecStoreElt64Rev { .. } => "vsterg",
2878                     _ => unreachable!(),
2879                 };
2880 
2881                 let rd = pretty_print_reg(rd);
2882                 let mem = mem.clone();
2883                 let (mem_str, mem) = mem_finalize_for_show(
2884                     &mem,
2885                     state,
2886                     MemInstType {
2887                         have_d12: true,
2888                         have_d20: false,
2889                         have_pcrel: false,
2890                         have_unaligned_pcrel: false,
2891                         have_index: true,
2892                     },
2893                 );
2894                 let mem = mem.pretty_print_default();
2895                 format!("{mem_str}{opcode} {rd}, {mem}")
2896             }
2897             &Inst::VecLoadReplicate { size, rd, ref mem }
2898             | &Inst::VecLoadReplicateRev { size, rd, ref mem } => {
2899                 let opcode = match (self, size) {
2900                     (&Inst::VecLoadReplicate { .. }, 8) => "vlrepb",
2901                     (&Inst::VecLoadReplicate { .. }, 16) => "vlreph",
2902                     (&Inst::VecLoadReplicate { .. }, 32) => "vlrepf",
2903                     (&Inst::VecLoadReplicate { .. }, 64) => "vlrepg",
2904                     (&Inst::VecLoadReplicateRev { .. }, 16) => "vlbrreph",
2905                     (&Inst::VecLoadReplicateRev { .. }, 32) => "vlbrrepf",
2906                     (&Inst::VecLoadReplicateRev { .. }, 64) => "vlbrrepg",
2907                     _ => unreachable!(),
2908                 };
2909 
2910                 let rd = pretty_print_reg(rd.to_reg());
2911                 let mem = mem.clone();
2912                 let (mem_str, mem) = mem_finalize_for_show(
2913                     &mem,
2914                     state,
2915                     MemInstType {
2916                         have_d12: true,
2917                         have_d20: false,
2918                         have_pcrel: false,
2919                         have_unaligned_pcrel: false,
2920                         have_index: true,
2921                     },
2922                 );
2923                 let mem = mem.pretty_print_default();
2924                 format!("{mem_str}{opcode} {rd}, {mem}")
2925             }
2926             &Inst::VecMov { rd, rn } => {
2927                 let rd = pretty_print_reg(rd.to_reg());
2928                 let rn = pretty_print_reg(rn);
2929                 format!("vlr {rd}, {rn}")
2930             }
2931             &Inst::VecCMov { rd, cond, ri, rm } => {
2932                 let rd = pretty_print_reg_mod(rd, ri);
2933                 let rm = pretty_print_reg(rm);
2934                 let cond = cond.invert().pretty_print_default();
2935                 format!("j{cond} 10 ; vlr {rd}, {rm}")
2936             }
2937             &Inst::MovToVec128 { rd, rn, rm } => {
2938                 let rd = pretty_print_reg(rd.to_reg());
2939                 let rn = pretty_print_reg(rn);
2940                 let rm = pretty_print_reg(rm);
2941                 format!("vlvgp {rd}, {rn}, {rm}")
2942             }
2943             &Inst::VecImmByteMask { rd, mask } => {
2944                 let rd = pretty_print_reg(rd.to_reg());
2945                 format!("vgbm {rd}, {mask}")
2946             }
2947             &Inst::VecImmBitMask {
2948                 size,
2949                 rd,
2950                 start_bit,
2951                 end_bit,
2952             } => {
2953                 let rd = pretty_print_reg(rd.to_reg());
2954                 let op = match size {
2955                     8 => "vgmb",
2956                     16 => "vgmh",
2957                     32 => "vgmf",
2958                     64 => "vgmg",
2959                     _ => unreachable!(),
2960                 };
2961                 format!("{op} {rd}, {start_bit}, {end_bit}")
2962             }
2963             &Inst::VecImmReplicate { size, rd, imm } => {
2964                 let rd = pretty_print_reg(rd.to_reg());
2965                 let op = match size {
2966                     8 => "vrepib",
2967                     16 => "vrepih",
2968                     32 => "vrepif",
2969                     64 => "vrepig",
2970                     _ => unreachable!(),
2971                 };
2972                 format!("{op} {rd}, {imm}")
2973             }
2974             &Inst::VecLoadLane {
2975                 size,
2976                 rd,
2977                 ref mem,
2978                 lane_imm,
2979                 ..
2980             }
2981             | &Inst::VecLoadLaneRev {
2982                 size,
2983                 rd,
2984                 ref mem,
2985                 lane_imm,
2986                 ..
2987             } => {
2988                 let opcode_vrx = match (self, size) {
2989                     (&Inst::VecLoadLane { .. }, 8) => "vleb",
2990                     (&Inst::VecLoadLane { .. }, 16) => "vleh",
2991                     (&Inst::VecLoadLane { .. }, 32) => "vlef",
2992                     (&Inst::VecLoadLane { .. }, 64) => "vleg",
2993                     (&Inst::VecLoadLaneRev { .. }, 16) => "vlebrh",
2994                     (&Inst::VecLoadLaneRev { .. }, 32) => "vlebrf",
2995                     (&Inst::VecLoadLaneRev { .. }, 64) => "vlebrg",
2996                     _ => unreachable!(),
2997                 };
2998 
2999                 let (rd, _) = pretty_print_fpr(rd.to_reg());
3000                 let mem = mem.clone();
3001                 let (mem_str, mem) = mem_finalize_for_show(
3002                     &mem,
3003                     state,
3004                     MemInstType {
3005                         have_d12: true,
3006                         have_d20: false,
3007                         have_pcrel: false,
3008                         have_unaligned_pcrel: false,
3009                         have_index: true,
3010                     },
3011                 );
3012                 let mem = mem.pretty_print_default();
3013                 format!("{mem_str}{opcode_vrx} {rd}, {mem}, {lane_imm}")
3014             }
3015             &Inst::VecLoadLaneUndef {
3016                 size,
3017                 rd,
3018                 ref mem,
3019                 lane_imm,
3020             }
3021             | &Inst::VecLoadLaneRevUndef {
3022                 size,
3023                 rd,
3024                 ref mem,
3025                 lane_imm,
3026             } => {
3027                 let (opcode_vrx, opcode_rx, opcode_rxy) = match (self, size) {
3028                     (&Inst::VecLoadLaneUndef { .. }, 8) => ("vleb", None, None),
3029                     (&Inst::VecLoadLaneUndef { .. }, 16) => ("vleh", None, None),
3030                     (&Inst::VecLoadLaneUndef { .. }, 32) => ("vlef", Some("le"), Some("ley")),
3031                     (&Inst::VecLoadLaneUndef { .. }, 64) => ("vleg", Some("ld"), Some("ldy")),
3032                     (&Inst::VecLoadLaneRevUndef { .. }, 16) => ("vlebrh", None, None),
3033                     (&Inst::VecLoadLaneRevUndef { .. }, 32) => ("vlebrf", None, None),
3034                     (&Inst::VecLoadLaneRevUndef { .. }, 64) => ("vlebrg", None, None),
3035                     _ => unreachable!(),
3036                 };
3037 
3038                 let (rd, rd_fpr) = pretty_print_fpr(rd.to_reg());
3039                 let mem = mem.clone();
3040                 if lane_imm == 0 && rd_fpr.is_some() && opcode_rx.is_some() {
3041                     let (mem_str, mem) = mem_finalize_for_show(
3042                         &mem,
3043                         state,
3044                         MemInstType {
3045                             have_d12: true,
3046                             have_d20: true,
3047                             have_pcrel: false,
3048                             have_unaligned_pcrel: false,
3049                             have_index: true,
3050                         },
3051                     );
3052                     let op = match &mem {
3053                         &MemArg::BXD12 { .. } => opcode_rx,
3054                         &MemArg::BXD20 { .. } => opcode_rxy,
3055                         _ => unreachable!(),
3056                     };
3057                     let mem = mem.pretty_print_default();
3058                     format!("{}{} {}, {}", mem_str, op.unwrap(), rd_fpr.unwrap(), mem)
3059                 } else {
3060                     let (mem_str, mem) = mem_finalize_for_show(
3061                         &mem,
3062                         state,
3063                         MemInstType {
3064                             have_d12: true,
3065                             have_d20: false,
3066                             have_pcrel: false,
3067                             have_unaligned_pcrel: false,
3068                             have_index: true,
3069                         },
3070                     );
3071                     let mem = mem.pretty_print_default();
3072                     format!("{mem_str}{opcode_vrx} {rd}, {mem}, {lane_imm}")
3073                 }
3074             }
3075             &Inst::VecStoreLane {
3076                 size,
3077                 rd,
3078                 ref mem,
3079                 lane_imm,
3080             }
3081             | &Inst::VecStoreLaneRev {
3082                 size,
3083                 rd,
3084                 ref mem,
3085                 lane_imm,
3086             } => {
3087                 let (opcode_vrx, opcode_rx, opcode_rxy) = match (self, size) {
3088                     (&Inst::VecStoreLane { .. }, 8) => ("vsteb", None, None),
3089                     (&Inst::VecStoreLane { .. }, 16) => ("vsteh", None, None),
3090                     (&Inst::VecStoreLane { .. }, 32) => ("vstef", Some("ste"), Some("stey")),
3091                     (&Inst::VecStoreLane { .. }, 64) => ("vsteg", Some("std"), Some("stdy")),
3092                     (&Inst::VecStoreLaneRev { .. }, 16) => ("vstebrh", None, None),
3093                     (&Inst::VecStoreLaneRev { .. }, 32) => ("vstebrf", None, None),
3094                     (&Inst::VecStoreLaneRev { .. }, 64) => ("vstebrg", None, None),
3095                     _ => unreachable!(),
3096                 };
3097 
3098                 let (rd, rd_fpr) = pretty_print_fpr(rd);
3099                 let mem = mem.clone();
3100                 if lane_imm == 0 && rd_fpr.is_some() && opcode_rx.is_some() {
3101                     let (mem_str, mem) = mem_finalize_for_show(
3102                         &mem,
3103                         state,
3104                         MemInstType {
3105                             have_d12: true,
3106                             have_d20: true,
3107                             have_pcrel: false,
3108                             have_unaligned_pcrel: false,
3109                             have_index: true,
3110                         },
3111                     );
3112                     let op = match &mem {
3113                         &MemArg::BXD12 { .. } => opcode_rx,
3114                         &MemArg::BXD20 { .. } => opcode_rxy,
3115                         _ => unreachable!(),
3116                     };
3117                     let mem = mem.pretty_print_default();
3118                     format!("{}{} {}, {}", mem_str, op.unwrap(), rd_fpr.unwrap(), mem)
3119                 } else {
3120                     let (mem_str, mem) = mem_finalize_for_show(
3121                         &mem,
3122                         state,
3123                         MemInstType {
3124                             have_d12: true,
3125                             have_d20: false,
3126                             have_pcrel: false,
3127                             have_unaligned_pcrel: false,
3128                             have_index: true,
3129                         },
3130                     );
3131                     let mem = mem.pretty_print_default();
3132                     format!("{mem_str}{opcode_vrx} {rd}, {mem}, {lane_imm}",)
3133                 }
3134             }
3135             &Inst::VecInsertLane {
3136                 size,
3137                 rd,
3138                 ri,
3139                 rn,
3140                 lane_imm,
3141                 lane_reg,
3142             } => {
3143                 let op = match size {
3144                     8 => "vlvgb",
3145                     16 => "vlvgh",
3146                     32 => "vlvgf",
3147                     64 => "vlvgg",
3148                     _ => unreachable!(),
3149                 };
3150                 let rd = pretty_print_reg_mod(rd, ri);
3151                 let rn = pretty_print_reg(rn);
3152                 let lane_reg = if lane_reg != zero_reg() {
3153                     format!("({})", pretty_print_reg(lane_reg))
3154                 } else {
3155                     "".to_string()
3156                 };
3157                 format!("{op} {rd}, {rn}, {lane_imm}{lane_reg}")
3158             }
3159             &Inst::VecInsertLaneUndef {
3160                 size,
3161                 rd,
3162                 rn,
3163                 lane_imm,
3164                 lane_reg,
3165             } => {
3166                 let (opcode_vrs, opcode_rre) = match size {
3167                     8 => ("vlvgb", None),
3168                     16 => ("vlvgh", None),
3169                     32 => ("vlvgf", None),
3170                     64 => ("vlvgg", Some("ldgr")),
3171                     _ => unreachable!(),
3172                 };
3173                 let (rd, rd_fpr) = pretty_print_fpr(rd.to_reg());
3174                 let rn = pretty_print_reg(rn);
3175                 let lane_reg = if lane_reg != zero_reg() {
3176                     format!("({})", pretty_print_reg(lane_reg))
3177                 } else {
3178                     "".to_string()
3179                 };
3180                 if opcode_rre.is_some() && lane_imm == 0 && lane_reg.is_empty() && rd_fpr.is_some()
3181                 {
3182                     format!("{} {}, {}", opcode_rre.unwrap(), rd_fpr.unwrap(), rn)
3183                 } else {
3184                     format!("{opcode_vrs} {rd}, {rn}, {lane_imm}{lane_reg}")
3185                 }
3186             }
3187             &Inst::VecExtractLane {
3188                 size,
3189                 rd,
3190                 rn,
3191                 lane_imm,
3192                 lane_reg,
3193             } => {
3194                 let (opcode_vrs, opcode_rre) = match size {
3195                     8 => ("vlgvb", None),
3196                     16 => ("vlgvh", None),
3197                     32 => ("vlgvf", None),
3198                     64 => ("vlgvg", Some("lgdr")),
3199                     _ => unreachable!(),
3200                 };
3201                 let rd = pretty_print_reg(rd.to_reg());
3202                 let (rn, rn_fpr) = pretty_print_fpr(rn);
3203                 let lane_reg = if lane_reg != zero_reg() {
3204                     format!("({})", pretty_print_reg(lane_reg))
3205                 } else {
3206                     "".to_string()
3207                 };
3208                 if opcode_rre.is_some() && lane_imm == 0 && lane_reg.is_empty() && rn_fpr.is_some()
3209                 {
3210                     format!("{} {}, {}", opcode_rre.unwrap(), rd, rn_fpr.unwrap())
3211                 } else {
3212                     format!("{opcode_vrs} {rd}, {rn}, {lane_imm}{lane_reg}")
3213                 }
3214             }
3215             &Inst::VecInsertLaneImm {
3216                 size,
3217                 rd,
3218                 ri,
3219                 imm,
3220                 lane_imm,
3221             } => {
3222                 let op = match size {
3223                     8 => "vleib",
3224                     16 => "vleih",
3225                     32 => "vleif",
3226                     64 => "vleig",
3227                     _ => unreachable!(),
3228                 };
3229                 let rd = pretty_print_reg_mod(rd, ri);
3230                 format!("{op} {rd}, {imm}, {lane_imm}")
3231             }
3232             &Inst::VecInsertLaneImmUndef {
3233                 size,
3234                 rd,
3235                 imm,
3236                 lane_imm,
3237             } => {
3238                 let op = match size {
3239                     8 => "vleib",
3240                     16 => "vleih",
3241                     32 => "vleif",
3242                     64 => "vleig",
3243                     _ => unreachable!(),
3244                 };
3245                 let rd = pretty_print_reg(rd.to_reg());
3246                 format!("{op} {rd}, {imm}, {lane_imm}")
3247             }
3248             &Inst::VecReplicateLane {
3249                 size,
3250                 rd,
3251                 rn,
3252                 lane_imm,
3253             } => {
3254                 let op = match size {
3255                     8 => "vrepb",
3256                     16 => "vreph",
3257                     32 => "vrepf",
3258                     64 => "vrepg",
3259                     _ => unreachable!(),
3260                 };
3261                 let rd = pretty_print_reg(rd.to_reg());
3262                 let rn = pretty_print_reg(rn);
3263                 format!("{op} {rd}, {rn}, {lane_imm}")
3264             }
3265             &Inst::VecEltRev { lane_count, rd, rn } => {
3266                 assert!(lane_count >= 2 && lane_count <= 16);
3267                 let rd = pretty_print_reg(rd.to_reg());
3268                 let rn = pretty_print_reg(rn);
3269                 let mut print = format!("vpdi {rd}, {rn}, {rn}, 4");
3270                 if lane_count >= 4 {
3271                     print = format!("{print} ; verllg {rn}, {rn}, 32");
3272                 }
3273                 if lane_count >= 8 {
3274                     print = format!("{print} ; verllf {rn}, {rn}, 16");
3275                 }
3276                 if lane_count >= 16 {
3277                     print = format!("{print} ; verllh {rn}, {rn}, 8");
3278                 }
3279                 print
3280             }
3281             &Inst::Extend {
3282                 rd,
3283                 rn,
3284                 signed,
3285                 from_bits,
3286                 to_bits,
3287             } => {
3288                 let rd = pretty_print_reg(rd.to_reg());
3289                 let rn = pretty_print_reg(rn);
3290                 let op = match (signed, from_bits, to_bits) {
3291                     (_, 1, 32) => "llcr",
3292                     (_, 1, 64) => "llgcr",
3293                     (false, 8, 32) => "llcr",
3294                     (false, 8, 64) => "llgcr",
3295                     (true, 8, 32) => "lbr",
3296                     (true, 8, 64) => "lgbr",
3297                     (false, 16, 32) => "llhr",
3298                     (false, 16, 64) => "llghr",
3299                     (true, 16, 32) => "lhr",
3300                     (true, 16, 64) => "lghr",
3301                     (false, 32, 64) => "llgfr",
3302                     (true, 32, 64) => "lgfr",
3303                     _ => panic!("Unsupported Extend case: {self:?}"),
3304                 };
3305                 format!("{op} {rd}, {rn}")
3306             }
3307             &Inst::AllocateArgs { size } => {
3308                 state.nominal_sp_offset = size;
3309                 if let Ok(size) = i16::try_from(size) {
3310                     format!("aghi {}, {}", show_reg(stack_reg()), -size)
3311                 } else {
3312                     format!("slgfi {}, {}", show_reg(stack_reg()), size)
3313                 }
3314             }
3315             &Inst::Call { link, ref info } => {
3316                 state.nominal_sp_offset = 0;
3317                 let link = link.to_reg();
3318                 let (opcode, dest) = match &info.dest {
3319                     CallInstDest::Direct { name } => ("brasl", name.display(None).to_string()),
3320                     CallInstDest::Indirect { reg } => ("basr", pretty_print_reg(*reg)),
3321                 };
3322                 state.outgoing_sp_offset = info.callee_pop_size;
3323                 let mut retval_loads = S390xMachineDeps::gen_retval_loads(info)
3324                     .into_iter()
3325                     .map(|inst| inst.print_with_state(state))
3326                     .collect::<Vec<_>>()
3327                     .join(" ; ");
3328                 if !retval_loads.is_empty() {
3329                     retval_loads = " ; ".to_string() + &retval_loads;
3330                 }
3331                 state.outgoing_sp_offset = 0;
3332                 let try_call = if let Some(try_call_info) = &info.try_call_info {
3333                     format!(
3334                         "; jg {:?}; catch [{}]",
3335                         try_call_info.continuation,
3336                         try_call_info.pretty_print_dests()
3337                     )
3338                 } else {
3339                     "".to_string()
3340                 };
3341                 let callee_pop_size = if info.callee_pop_size > 0 {
3342                     format!(" ; callee_pop_size {}", info.callee_pop_size)
3343                 } else {
3344                     "".to_string()
3345                 };
3346                 format!(
3347                     "{} {}, {}{}{}{}",
3348                     opcode,
3349                     show_reg(link),
3350                     dest,
3351                     callee_pop_size,
3352                     retval_loads,
3353                     try_call,
3354                 )
3355             }
3356             &Inst::ReturnCall { ref info } => {
3357                 let (epilogue_insts, temp_dest) = S390xMachineDeps::gen_tail_epilogue(
3358                     state.frame_layout(),
3359                     info.callee_pop_size,
3360                     &info.dest,
3361                 );
3362                 let mut epilogue_str = epilogue_insts
3363                     .into_iter()
3364                     .map(|inst| inst.print_with_state(state))
3365                     .collect::<Vec<_>>()
3366                     .join(" ; ");
3367                 if !epilogue_str.is_empty() {
3368                     epilogue_str += " ; ";
3369                 }
3370                 let (opcode, dest) = match &info.dest {
3371                     CallInstDest::Direct { name } => ("jg", name.display(None).to_string()),
3372                     CallInstDest::Indirect { reg } => {
3373                         ("br", pretty_print_reg(temp_dest.unwrap_or(*reg)))
3374                     }
3375                 };
3376                 let callee_pop_size = if info.callee_pop_size > 0 {
3377                     format!(" ; callee_pop_size {}", info.callee_pop_size)
3378                 } else {
3379                     "".to_string()
3380                 };
3381                 format!("{epilogue_str}{opcode} {dest}{callee_pop_size}")
3382             }
3383             &Inst::ElfTlsGetOffset { ref symbol, .. } => {
3384                 let dest = match &**symbol {
3385                     SymbolReloc::TlsGd { name } => {
3386                         format!("tls_gdcall:{}", name.display(None))
3387                     }
3388                     _ => unreachable!(),
3389                 };
3390                 format!("brasl {}, {}", show_reg(gpr(14)), dest)
3391             }
3392             &Inst::Args { ref args } => {
3393                 let mut s = "args".to_string();
3394                 for arg in args {
3395                     let preg = pretty_print_reg(arg.preg);
3396                     let def = pretty_print_reg(arg.vreg.to_reg());
3397                     write!(&mut s, " {def}={preg}").unwrap();
3398                 }
3399                 s
3400             }
3401             &Inst::Rets { ref rets } => {
3402                 let mut s = "rets".to_string();
3403                 for ret in rets {
3404                     let preg = pretty_print_reg(ret.preg);
3405                     let vreg = pretty_print_reg(ret.vreg);
3406                     write!(&mut s, " {vreg}={preg}").unwrap();
3407                 }
3408                 s
3409             }
3410             &Inst::Ret { link } => {
3411                 let link = show_reg(link);
3412                 format!("br {link}")
3413             }
3414             &Inst::Jump { dest } => {
3415                 let dest = dest.to_string();
3416                 format!("jg {dest}")
3417             }
3418             &Inst::IndirectBr { rn, .. } => {
3419                 let rn = pretty_print_reg(rn);
3420                 format!("br {rn}")
3421             }
3422             &Inst::CondBr {
3423                 taken,
3424                 not_taken,
3425                 cond,
3426             } => {
3427                 let taken = taken.to_string();
3428                 let not_taken = not_taken.to_string();
3429                 let cond = cond.pretty_print_default();
3430                 format!("jg{cond} {taken} ; jg {not_taken}")
3431             }
3432             &Inst::Debugtrap => ".word 0x0001 # debugtrap".to_string(),
3433             &Inst::Trap { trap_code } => {
3434                 format!(".word 0x0000 # trap={trap_code}")
3435             }
3436             &Inst::TrapIf { cond, trap_code } => {
3437                 let cond = cond.pretty_print_default();
3438                 format!("jg{cond} .+2 # trap={trap_code}")
3439             }
3440             &Inst::JTSequence {
3441                 ridx,
3442                 default,
3443                 default_cond,
3444                 ref targets,
3445             } => {
3446                 let ridx = pretty_print_reg(ridx);
3447                 let rtmp = pretty_print_reg(writable_spilltmp_reg().to_reg());
3448                 let jt_entries: String = targets
3449                     .iter()
3450                     .map(|label| format!(" {}", label.to_string()))
3451                     .collect();
3452                 format!(
3453                     concat!(
3454                         "jg{} {} ; ",
3455                         "larl {}, 14 ; ",
3456                         "agf {}, 0({}, {}) ; ",
3457                         "br {} ; ",
3458                         "jt_entries{}"
3459                     ),
3460                     default_cond.pretty_print_default(),
3461                     default.to_string(),
3462                     rtmp,
3463                     rtmp,
3464                     rtmp,
3465                     ridx,
3466                     rtmp,
3467                     jt_entries,
3468                 )
3469             }
3470             &Inst::LoadSymbolReloc {
3471                 rd,
3472                 ref symbol_reloc,
3473             } => {
3474                 let rd = pretty_print_reg(rd.to_reg());
3475                 let tmp = pretty_print_reg(writable_spilltmp_reg().to_reg());
3476                 let symbol = match &**symbol_reloc {
3477                     SymbolReloc::Absolute { name, offset } => {
3478                         format!("{} + {}", name.display(None), offset)
3479                     }
3480                     SymbolReloc::TlsGd { name } => format!("{}@tlsgd", name.display(None)),
3481                 };
3482                 format!("bras {tmp}, 12 ; data {symbol} ; lg {rd}, 0({tmp})")
3483             }
3484             &Inst::LoadAddr { rd, ref mem } => {
3485                 let rd = pretty_print_reg(rd.to_reg());
3486                 let mem = mem.clone();
3487                 let (mem_str, mem) = mem_finalize_for_show(
3488                     &mem,
3489                     state,
3490                     MemInstType {
3491                         have_d12: true,
3492                         have_d20: true,
3493                         have_pcrel: true,
3494                         have_unaligned_pcrel: true,
3495                         have_index: true,
3496                     },
3497                 );
3498                 let op = match &mem {
3499                     &MemArg::BXD12 { .. } => "la",
3500                     &MemArg::BXD20 { .. } => "lay",
3501                     &MemArg::Label { .. } | &MemArg::Constant { .. } | &MemArg::Symbol { .. } => {
3502                         "larl"
3503                     }
3504                     _ => unreachable!(),
3505                 };
3506                 let mem = mem.pretty_print_default();
3507 
3508                 format!("{mem_str}{op} {rd}, {mem}")
3509             }
3510             &Inst::StackProbeLoop {
3511                 probe_count,
3512                 guard_size,
3513             } => {
3514                 let probe_count = pretty_print_reg(probe_count.to_reg());
3515                 let stack_reg = pretty_print_reg(stack_reg());
3516                 format!(
3517                     "0: aghi {stack_reg}, -{guard_size} ; mvi 0({stack_reg}), 0 ; brct {probe_count}, 0b"
3518                 )
3519             }
3520             &Inst::Loop { ref body, cond } => {
3521                 let body = body
3522                     .into_iter()
3523                     .map(|inst| inst.print_with_state(state))
3524                     .collect::<Vec<_>>()
3525                     .join(" ; ");
3526                 let cond = cond.pretty_print_default();
3527                 format!("0: {body} ; jg{cond} 0b ; 1:")
3528             }
3529             &Inst::CondBreak { cond } => {
3530                 let cond = cond.pretty_print_default();
3531                 format!("jg{cond} 1f")
3532             }
3533             &Inst::Unwind { ref inst } => {
3534                 format!("unwind {inst:?}")
3535             }
3536             &Inst::DummyUse { reg } => {
3537                 let reg = pretty_print_reg(reg);
3538                 format!("dummy_use {reg}")
3539             }
3540             &Inst::LabelAddress { dst, label } => {
3541                 let dst = pretty_print_reg(dst.to_reg());
3542                 format!("label_address {dst}, {label:?}")
3543             }
3544             &Inst::SequencePoint {} => {
3545                 format!("sequence_point")
3546             }
3547         }
3548     }
3549 }
3550 
3551 //=============================================================================
3552 // Label fixups and jump veneers.
3553 
3554 /// Different forms of label references for different instruction formats.
3555 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
3556 pub enum LabelUse {
3557     /// RI-format branch.  16-bit signed offset.  PC-relative, offset is imm << 1.
3558     BranchRI,
3559     /// RIL-format branch.  32-bit signed offset.  PC-relative, offset is imm << 1.
3560     BranchRIL,
3561     /// 32-bit PC relative constant offset (from address of constant itself),
3562     /// signed. Used in jump tables.
3563     PCRel32,
3564     /// 32-bit PC relative constant offset (from address of call instruction),
3565     /// signed. Offset is imm << 1.  Used for call relocations.
3566     PCRel32Dbl,
3567 }
3568 
3569 impl MachInstLabelUse for LabelUse {
3570     /// Alignment for veneer code.
3571     const ALIGN: CodeOffset = 2;
3572 
3573     /// Maximum PC-relative range (positive), inclusive.
max_pos_range(self) -> CodeOffset3574     fn max_pos_range(self) -> CodeOffset {
3575         match self {
3576             // 16-bit signed immediate, left-shifted by 1.
3577             LabelUse::BranchRI => ((1 << 15) - 1) << 1,
3578             // 32-bit signed immediate, left-shifted by 1.
3579             LabelUse::BranchRIL => 0xffff_fffe,
3580             // 32-bit signed immediate.
3581             LabelUse::PCRel32 => 0x7fff_ffff,
3582             // 32-bit signed immediate, left-shifted by 1, offset by 2.
3583             LabelUse::PCRel32Dbl => 0xffff_fffc,
3584         }
3585     }
3586 
3587     /// Maximum PC-relative range (negative).
max_neg_range(self) -> CodeOffset3588     fn max_neg_range(self) -> CodeOffset {
3589         match self {
3590             // 16-bit signed immediate, left-shifted by 1.
3591             LabelUse::BranchRI => (1 << 15) << 1,
3592             // 32-bit signed immediate, left-shifted by 1.
3593             // NOTE: This should be 4GB, but CodeOffset is only u32.
3594             LabelUse::BranchRIL => 0xffff_ffff,
3595             // 32-bit signed immediate.
3596             LabelUse::PCRel32 => 0x8000_0000,
3597             // 32-bit signed immediate, left-shifted by 1, offset by 2.
3598             // NOTE: This should be 4GB + 2, but CodeOffset is only u32.
3599             LabelUse::PCRel32Dbl => 0xffff_ffff,
3600         }
3601     }
3602 
3603     /// Size of window into code needed to do the patch.
patch_size(self) -> CodeOffset3604     fn patch_size(self) -> CodeOffset {
3605         match self {
3606             LabelUse::BranchRI => 4,
3607             LabelUse::BranchRIL => 6,
3608             LabelUse::PCRel32 => 4,
3609             LabelUse::PCRel32Dbl => 4,
3610         }
3611     }
3612 
3613     /// Perform the patch.
patch(self, buffer: &mut [u8], use_offset: CodeOffset, label_offset: CodeOffset)3614     fn patch(self, buffer: &mut [u8], use_offset: CodeOffset, label_offset: CodeOffset) {
3615         let pc_rel = (label_offset as i64) - (use_offset as i64);
3616         debug_assert!(pc_rel <= self.max_pos_range() as i64);
3617         debug_assert!(pc_rel >= -(self.max_neg_range() as i64));
3618         debug_assert!(pc_rel & 1 == 0);
3619         let pc_rel_shifted = pc_rel >> 1;
3620 
3621         match self {
3622             LabelUse::BranchRI => {
3623                 buffer[2..4].clone_from_slice(&u16::to_be_bytes(pc_rel_shifted as u16));
3624             }
3625             LabelUse::BranchRIL => {
3626                 buffer[2..6].clone_from_slice(&u32::to_be_bytes(pc_rel_shifted as u32));
3627             }
3628             LabelUse::PCRel32 => {
3629                 let insn_word = u32::from_be_bytes([buffer[0], buffer[1], buffer[2], buffer[3]]);
3630                 let insn_word = insn_word.wrapping_add(pc_rel as u32);
3631                 buffer[0..4].clone_from_slice(&u32::to_be_bytes(insn_word));
3632             }
3633             LabelUse::PCRel32Dbl => {
3634                 let insn_word = u32::from_be_bytes([buffer[0], buffer[1], buffer[2], buffer[3]]);
3635                 let insn_word = insn_word.wrapping_add((pc_rel_shifted + 1) as u32);
3636                 buffer[0..4].clone_from_slice(&u32::to_be_bytes(insn_word));
3637             }
3638         }
3639     }
3640 
3641     /// Is a veneer supported for this label reference type?
supports_veneer(self) -> bool3642     fn supports_veneer(self) -> bool {
3643         false
3644     }
3645 
3646     /// How large is the veneer, if supported?
veneer_size(self) -> CodeOffset3647     fn veneer_size(self) -> CodeOffset {
3648         0
3649     }
3650 
worst_case_veneer_size() -> CodeOffset3651     fn worst_case_veneer_size() -> CodeOffset {
3652         0
3653     }
3654 
3655     /// Generate a veneer into the buffer, given that this veneer is at `veneer_offset`, and return
3656     /// an offset and label-use for the veneer's use of the original label.
generate_veneer( self, _buffer: &mut [u8], _veneer_offset: CodeOffset, ) -> (CodeOffset, LabelUse)3657     fn generate_veneer(
3658         self,
3659         _buffer: &mut [u8],
3660         _veneer_offset: CodeOffset,
3661     ) -> (CodeOffset, LabelUse) {
3662         unreachable!();
3663     }
3664 
from_reloc(reloc: Reloc, addend: Addend) -> Option<Self>3665     fn from_reloc(reloc: Reloc, addend: Addend) -> Option<Self> {
3666         match (reloc, addend) {
3667             (Reloc::S390xPCRel32Dbl, 2) => Some(LabelUse::PCRel32Dbl),
3668             (Reloc::S390xPLTRel32Dbl, 2) => Some(LabelUse::PCRel32Dbl),
3669             _ => None,
3670         }
3671     }
3672 }
3673