Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bytecodealliance
GitHub Repository: bytecodealliance/wasmtime
Path: blob/main/cranelift/codegen/src/isa/s390x/inst/mod.rs
3088 views
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]
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 {
76
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.
102
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.
333
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.
343
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.
359
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).
374
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.
404
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
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
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> {
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
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
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
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
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
1118
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
1136
fn is_trap(&self) -> bool {
1137
match self {
1138
Self::Trap { .. } => true,
1139
_ => false,
1140
}
1141
}
1142
1143
fn is_args(&self) -> bool {
1144
match self {
1145
Self::Args { .. } => true,
1146
_ => false,
1147
}
1148
}
1149
1150
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
1163
fn is_mem_access(&self) -> bool {
1164
panic!("TODO FILL ME OUT")
1165
}
1166
1167
fn is_safepoint(&self) -> bool {
1168
match self {
1169
Inst::Call { .. } => true,
1170
_ => false,
1171
}
1172
}
1173
1174
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
1184
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
1195
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
1205
fn gen_nop_units() -> Vec<Vec<u8>> {
1206
vec![vec![0x07, 0x07]]
1207
}
1208
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
1227
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
1235
fn gen_jump(target: MachLabel) -> Inst {
1236
Inst::Jump { dest: target }
1237
}
1238
1239
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
1250
fn ref_type_regclass(_: &settings::Flags) -> RegClass {
1251
RegClass::Int
1252
}
1253
1254
fn gen_dummy_use(reg: Reg) -> Inst {
1255
Inst::DummyUse { reg }
1256
}
1257
1258
fn function_alignment() -> FunctionAlignment {
1259
FunctionAlignment {
1260
minimum: 4,
1261
preferred: 4,
1262
}
1263
}
1264
}
1265
1266
//=============================================================================
1267
// Pretty-printing of instructions.
1268
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 {
1284
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.
3574
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).
3588
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.
3604
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.
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?
3642
fn supports_veneer(self) -> bool {
3643
false
3644
}
3645
3646
/// How large is the veneer, if supported?
3647
fn veneer_size(self) -> CodeOffset {
3648
0
3649
}
3650
3651
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.
3657
fn generate_veneer(
3658
self,
3659
_buffer: &mut [u8],
3660
_veneer_offset: CodeOffset,
3661
) -> (CodeOffset, LabelUse) {
3662
unreachable!();
3663
}
3664
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
3674