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