1use crate::binemit::{Addend, CodeOffset, Reloc};
4use crate::ir::types::{F16, F32, F64, F128, I8, I8X16, I16, I32, I64, I128};
5use crate::ir::{MemFlagsData, Type, types};
6use crate::isa::{CallConv, FunctionAlignment};
7use crate::machinst::*;
8use crate::{CodegenError, CodegenResult, settings};
9
10use crate::machinst::{PrettyPrint, Reg, RegClass, Writable};
11
12use alloc::string::{String, ToString};
13use alloc::vec::Vec;
14use core::fmt::Write;
15use core::slice;
16use smallvec::{SmallVec, smallvec};
17
18pub(crate) mod regs;
19pub use self::regs::*;
20pub mod imms;
21pub use self::imms::*;
22pub mod args;
23pub use self::args::*;
24pub mod emit;
25pub(crate) use self::emit::*;
26use crate::isa::aarch64::abi::AArch64MachineDeps;
27
28pub(crate) mod unwind;
29
30#[cfg(test)]
31mod emit_tests;
32
33pub use crate::isa::aarch64::lower::isle::generated_code::{
37 ALUOp, ALUOp3, AMode, APIKey, AtomicRMWLoopOp, AtomicRMWOp, BitOp, BranchTargetType, FPUOp1,
38 FPUOp2, FPUOp3, FpuRoundMode, FpuToIntOp, IntToFpuOp, MInst as Inst, MoveWideOp, VecALUModOp,
39 VecALUOp, VecExtendOp, VecLanesOp, VecMisc2, VecPairOp, VecRRLongOp, VecRRNarrowOp,
40 VecRRPairLongOp, VecRRRLongModOp, VecRRRLongOp, VecShiftImmModOp, VecShiftImmOp,
41};
42
43#[derive(Copy, Clone, Debug)]
45pub enum FPUOpRI {
46 UShr32(FPURightShiftImm),
48 UShr64(FPURightShiftImm),
50}
51
52#[derive(Copy, Clone, Debug)]
56pub enum FPUOpRIMod {
57 Sli32(FPULeftShiftImm),
59 Sli64(FPULeftShiftImm),
61}
62
63impl BitOp {
64 pub fn op_str(&self) -> &'static str {
66 match self {
67 BitOp::RBit => "rbit",
68 BitOp::Clz => "clz",
69 BitOp::Cls => "cls",
70 BitOp::Rev16 => "rev16",
71 BitOp::Rev32 => "rev32",
72 BitOp::Rev64 => "rev64",
73 }
74 }
75}
76
77#[derive(Clone, Debug)]
80pub struct ReturnCallInfo<T> {
81 pub dest: T,
83 pub uses: CallArgList,
85 pub new_stack_arg_size: u32,
89 pub key: Option<APIKey>,
91 pub sign_return_address_all: bool,
93}
94
95fn count_zero_half_words(mut value: u64, num_half_words: u8) -> usize {
96 let mut count = 0;
97 for _ in 0..num_half_words {
98 if value & 0xffff == 0 {
99 count += 1;
100 }
101 value >>= 16;
102 }
103
104 count
105}
106
107impl Inst {
108 pub fn load_constant(rd: Writable<Reg>, value: u64) -> SmallVec<[Inst; 4]> {
111 if let Some(imm) = MoveWideConst::maybe_from_u64(value) {
116 smallvec![Inst::MovWide {
118 op: MoveWideOp::MovZ,
119 rd,
120 imm,
121 size: OperandSize::Size64
122 }]
123 } else if let Some(imm) = MoveWideConst::maybe_from_u64(!value) {
124 smallvec![Inst::MovWide {
126 op: MoveWideOp::MovN,
127 rd,
128 imm,
129 size: OperandSize::Size64
130 }]
131 } else if let Some(imml) = ImmLogic::maybe_from_u64(value, I64) {
132 smallvec![Inst::AluRRImmLogic {
134 alu_op: ALUOp::Orr,
135 size: OperandSize::Size64,
136 rd,
137 rn: zero_reg(),
138 imml,
139 }]
140 } else {
141 let mut insts = smallvec![];
142
143 let (num_half_words, size, negated) = if value >> 32 == 0 {
145 (2, OperandSize::Size32, (!value << 32) >> 32)
146 } else {
147 (4, OperandSize::Size64, !value)
148 };
149
150 let first_is_inverted = count_zero_half_words(negated, num_half_words)
153 > count_zero_half_words(value, num_half_words);
154
155 let ignored_halfword = if first_is_inverted { 0xffff } else { 0 };
158
159 let halfwords: SmallVec<[_; 4]> = (0..num_half_words)
160 .filter_map(|i| {
161 let imm16 = (value >> (16 * i)) & 0xffff;
162 if imm16 == ignored_halfword {
163 None
164 } else {
165 Some((i, imm16))
166 }
167 })
168 .collect();
169
170 let mut prev_result = None;
171 for (i, imm16) in halfwords {
172 let shift = i * 16;
173
174 if let Some(rn) = prev_result {
175 let imm = MoveWideConst::maybe_with_shift(imm16 as u16, shift).unwrap();
176 insts.push(Inst::MovK { rd, rn, imm, size });
177 } else {
178 if first_is_inverted {
179 let imm =
180 MoveWideConst::maybe_with_shift(((!imm16) & 0xffff) as u16, shift)
181 .unwrap();
182 insts.push(Inst::MovWide {
183 op: MoveWideOp::MovN,
184 rd,
185 imm,
186 size,
187 });
188 } else {
189 let imm = MoveWideConst::maybe_with_shift(imm16 as u16, shift).unwrap();
190 insts.push(Inst::MovWide {
191 op: MoveWideOp::MovZ,
192 rd,
193 imm,
194 size,
195 });
196 }
197 }
198
199 prev_result = Some(rd.to_reg());
200 }
201
202 assert!(prev_result.is_some());
203
204 insts
205 }
206 }
207
208 pub fn gen_load(into_reg: Writable<Reg>, mem: AMode, ty: Type, flags: MemFlagsData) -> Inst {
210 match ty {
211 I8 => Inst::ULoad8 {
212 rd: into_reg,
213 mem,
214 flags,
215 },
216 I16 => Inst::ULoad16 {
217 rd: into_reg,
218 mem,
219 flags,
220 },
221 I32 => Inst::ULoad32 {
222 rd: into_reg,
223 mem,
224 flags,
225 },
226 I64 => Inst::ULoad64 {
227 rd: into_reg,
228 mem,
229 flags,
230 },
231 _ => {
232 if ty.is_vector() || ty.is_float() {
233 let bits = ty_bits(ty);
234 let rd = into_reg;
235
236 match bits {
237 128 => Inst::FpuLoad128 { rd, mem, flags },
238 64 => Inst::FpuLoad64 { rd, mem, flags },
239 32 => Inst::FpuLoad32 { rd, mem, flags },
240 16 => Inst::FpuLoad16 { rd, mem, flags },
241 _ => unimplemented!("gen_load({})", ty),
242 }
243 } else {
244 unimplemented!("gen_load({})", ty);
245 }
246 }
247 }
248 }
249
250 pub fn gen_store(mem: AMode, from_reg: Reg, ty: Type, flags: MemFlagsData) -> Inst {
252 match ty {
253 I8 => Inst::Store8 {
254 rd: from_reg,
255 mem,
256 flags,
257 },
258 I16 => Inst::Store16 {
259 rd: from_reg,
260 mem,
261 flags,
262 },
263 I32 => Inst::Store32 {
264 rd: from_reg,
265 mem,
266 flags,
267 },
268 I64 => Inst::Store64 {
269 rd: from_reg,
270 mem,
271 flags,
272 },
273 _ => {
274 if ty.is_vector() || ty.is_float() {
275 let bits = ty_bits(ty);
276 let rd = from_reg;
277
278 match bits {
279 128 => Inst::FpuStore128 { rd, mem, flags },
280 64 => Inst::FpuStore64 { rd, mem, flags },
281 32 => Inst::FpuStore32 { rd, mem, flags },
282 16 => Inst::FpuStore16 { rd, mem, flags },
283 _ => unimplemented!("gen_store({})", ty),
284 }
285 } else {
286 unimplemented!("gen_store({})", ty);
287 }
288 }
289 }
290 }
291
292 pub fn mem_type(&self) -> Option<Type> {
296 match self {
297 Inst::ULoad8 { .. } => Some(I8),
298 Inst::SLoad8 { .. } => Some(I8),
299 Inst::ULoad16 { .. } => Some(I16),
300 Inst::SLoad16 { .. } => Some(I16),
301 Inst::ULoad32 { .. } => Some(I32),
302 Inst::SLoad32 { .. } => Some(I32),
303 Inst::ULoad64 { .. } => Some(I64),
304 Inst::FpuLoad16 { .. } => Some(F16),
305 Inst::FpuLoad32 { .. } => Some(F32),
306 Inst::FpuLoad64 { .. } => Some(F64),
307 Inst::FpuLoad128 { .. } => Some(I8X16),
308 Inst::Store8 { .. } => Some(I8),
309 Inst::Store16 { .. } => Some(I16),
310 Inst::Store32 { .. } => Some(I32),
311 Inst::Store64 { .. } => Some(I64),
312 Inst::FpuStore16 { .. } => Some(F16),
313 Inst::FpuStore32 { .. } => Some(F32),
314 Inst::FpuStore64 { .. } => Some(F64),
315 Inst::FpuStore128 { .. } => Some(I8X16),
316 _ => None,
317 }
318 }
319}
320
321fn memarg_operands(memarg: &mut AMode, collector: &mut impl OperandVisitor) {
325 match memarg {
326 AMode::Unscaled { rn, .. } | AMode::UnsignedOffset { rn, .. } => {
327 collector.reg_use(rn);
328 }
329 AMode::RegReg { rn, rm, .. }
330 | AMode::RegScaled { rn, rm, .. }
331 | AMode::RegScaledExtended { rn, rm, .. }
332 | AMode::RegExtended { rn, rm, .. } => {
333 collector.reg_use(rn);
334 collector.reg_use(rm);
335 }
336 AMode::Label { .. } => {}
337 AMode::SPPreIndexed { .. } | AMode::SPPostIndexed { .. } => {}
338 AMode::FPOffset { .. } | AMode::IncomingArg { .. } => {}
339 AMode::SPOffset { .. } | AMode::SlotOffset { .. } => {}
340 AMode::RegOffset { rn, .. } => {
341 collector.reg_use(rn);
342 }
343 AMode::Const { .. } => {}
344 }
345}
346
347fn pairmemarg_operands(pairmemarg: &mut PairAMode, collector: &mut impl OperandVisitor) {
348 match pairmemarg {
349 PairAMode::SignedOffset { reg, .. } => {
350 collector.reg_use(reg);
351 }
352 PairAMode::SPPreIndexed { .. } | PairAMode::SPPostIndexed { .. } => {}
353 }
354}
355
356fn aarch64_get_operands(inst: &mut Inst, collector: &mut impl OperandVisitor) {
357 match inst {
358 Inst::AluRRR { rd, rn, rm, .. } => {
359 collector.reg_def(rd);
360 collector.reg_use(rn);
361 collector.reg_use(rm);
362 }
363 Inst::AluRRRR { rd, rn, rm, ra, .. } => {
364 collector.reg_def(rd);
365 collector.reg_use(rn);
366 collector.reg_use(rm);
367 collector.reg_use(ra);
368 }
369 Inst::AluRRImm12 { rd, rn, .. } => {
370 collector.reg_def(rd);
371 collector.reg_use(rn);
372 }
373 Inst::AluRRImmLogic { rd, rn, .. } => {
374 collector.reg_def(rd);
375 collector.reg_use(rn);
376 }
377 Inst::AluRRImmShift { rd, rn, .. } => {
378 collector.reg_def(rd);
379 collector.reg_use(rn);
380 }
381 Inst::AluRRRShift { rd, rn, rm, .. } => {
382 collector.reg_def(rd);
383 collector.reg_use(rn);
384 collector.reg_use(rm);
385 }
386 Inst::AluRRRExtend { rd, rn, rm, .. } => {
387 collector.reg_def(rd);
388 collector.reg_use(rn);
389 collector.reg_use(rm);
390 }
391 Inst::BitRR { rd, rn, .. } => {
392 collector.reg_def(rd);
393 collector.reg_use(rn);
394 }
395 Inst::ULoad8 { rd, mem, .. }
396 | Inst::SLoad8 { rd, mem, .. }
397 | Inst::ULoad16 { rd, mem, .. }
398 | Inst::SLoad16 { rd, mem, .. }
399 | Inst::ULoad32 { rd, mem, .. }
400 | Inst::SLoad32 { rd, mem, .. }
401 | Inst::ULoad64 { rd, mem, .. } => {
402 collector.reg_def(rd);
403 memarg_operands(mem, collector);
404 }
405 Inst::Store8 { rd, mem, .. }
406 | Inst::Store16 { rd, mem, .. }
407 | Inst::Store32 { rd, mem, .. }
408 | Inst::Store64 { rd, mem, .. } => {
409 collector.reg_use(rd);
410 memarg_operands(mem, collector);
411 }
412 Inst::StoreP64 { rt, rt2, mem, .. } => {
413 collector.reg_use(rt);
414 collector.reg_use(rt2);
415 pairmemarg_operands(mem, collector);
416 }
417 Inst::LoadP64 { rt, rt2, mem, .. } => {
418 collector.reg_def(rt);
419 collector.reg_def(rt2);
420 pairmemarg_operands(mem, collector);
421 }
422 Inst::Mov { rd, rm, .. } => {
423 collector.reg_def(rd);
424 collector.reg_use(rm);
425 }
426 Inst::MovFromPReg { rd, rm } => {
427 debug_assert!(rd.to_reg().is_virtual());
428 collector.reg_def(rd);
429 collector.reg_fixed_nonallocatable(*rm);
430 }
431 Inst::MovToPReg { rd, rm } => {
432 debug_assert!(rm.is_virtual());
433 collector.reg_fixed_nonallocatable(*rd);
434 collector.reg_use(rm);
435 }
436 Inst::MovK { rd, rn, .. } => {
437 collector.reg_use(rn);
438 collector.reg_reuse_def(rd, 0); }
440 Inst::MovWide { rd, .. } => {
441 collector.reg_def(rd);
442 }
443 Inst::CSel { rd, rn, rm, .. } => {
444 collector.reg_def(rd);
445 collector.reg_use(rn);
446 collector.reg_use(rm);
447 }
448 Inst::CSNeg { rd, rn, rm, .. } => {
449 collector.reg_def(rd);
450 collector.reg_use(rn);
451 collector.reg_use(rm);
452 }
453 Inst::CSet { rd, .. } | Inst::CSetm { rd, .. } => {
454 collector.reg_def(rd);
455 }
456 Inst::CCmp { rn, rm, .. } => {
457 collector.reg_use(rn);
458 collector.reg_use(rm);
459 }
460 Inst::CCmpImm { rn, .. } => {
461 collector.reg_use(rn);
462 }
463 Inst::AtomicRMWLoop {
464 op,
465 addr,
466 operand,
467 oldval,
468 scratch1,
469 scratch2,
470 ..
471 } => {
472 collector.reg_fixed_use(addr, xreg(25));
473 collector.reg_fixed_use(operand, xreg(26));
474 collector.reg_fixed_def(oldval, xreg(27));
475 collector.reg_fixed_def(scratch1, xreg(24));
476 if *op != AtomicRMWLoopOp::Xchg {
477 collector.reg_fixed_def(scratch2, xreg(28));
478 }
479 }
480 Inst::AtomicRMW { rs, rt, rn, .. } => {
481 collector.reg_use(rs);
482 collector.reg_def(rt);
483 collector.reg_use(rn);
484 }
485 Inst::AtomicCAS { rd, rs, rt, rn, .. } => {
486 collector.reg_reuse_def(rd, 1); collector.reg_use(rs);
488 collector.reg_use(rt);
489 collector.reg_use(rn);
490 }
491 Inst::AtomicCAS128 { args } => {
492 let AtomicCAS128Args {
493 rd_lo,
494 rd_hi,
495 rs_lo,
496 rs_hi,
497 rt_lo,
498 rt_hi,
499 rn,
500 flags: _,
501 } = &mut **args;
502 collector.reg_fixed_use(rs_lo, xreg(24));
505 collector.reg_fixed_use(rs_hi, xreg(25));
506 collector.reg_fixed_def(rd_lo, xreg(24));
507 collector.reg_fixed_def(rd_hi, xreg(25));
508 collector.reg_fixed_use(rt_lo, xreg(26));
509 collector.reg_fixed_use(rt_hi, xreg(27));
510 collector.reg_fixed_use(rn, xreg(28));
511 }
512 Inst::AtomicCASLoop {
513 addr,
514 expected,
515 replacement,
516 oldval,
517 scratch,
518 ..
519 } => {
520 collector.reg_fixed_use(addr, xreg(25));
521 collector.reg_fixed_use(expected, xreg(26));
522 collector.reg_fixed_use(replacement, xreg(28));
523 collector.reg_fixed_def(oldval, xreg(27));
524 collector.reg_fixed_def(scratch, xreg(24));
525 }
526 Inst::LoadAcquire { rt, rn, .. } => {
527 collector.reg_use(rn);
528 collector.reg_def(rt);
529 }
530 Inst::StoreRelease { rt, rn, .. } => {
531 collector.reg_use(rn);
532 collector.reg_use(rt);
533 }
534 Inst::Fence {} | Inst::Csdb {} => {}
535 Inst::FpuMove32 { rd, rn } => {
536 collector.reg_def(rd);
537 collector.reg_use(rn);
538 }
539 Inst::FpuMove64 { rd, rn } => {
540 collector.reg_def(rd);
541 collector.reg_use(rn);
542 }
543 Inst::FpuMove128 { rd, rn } => {
544 collector.reg_def(rd);
545 collector.reg_use(rn);
546 }
547 Inst::FpuMoveFromVec { rd, rn, .. } => {
548 collector.reg_def(rd);
549 collector.reg_use(rn);
550 }
551 Inst::FpuExtend { rd, rn, .. } => {
552 collector.reg_def(rd);
553 collector.reg_use(rn);
554 }
555 Inst::FpuRR { rd, rn, .. } => {
556 collector.reg_def(rd);
557 collector.reg_use(rn);
558 }
559 Inst::FpuRRR { rd, rn, rm, .. } => {
560 collector.reg_def(rd);
561 collector.reg_use(rn);
562 collector.reg_use(rm);
563 }
564 Inst::FpuRRI { rd, rn, .. } => {
565 collector.reg_def(rd);
566 collector.reg_use(rn);
567 }
568 Inst::FpuRRIMod { rd, ri, rn, .. } => {
569 collector.reg_reuse_def(rd, 1); collector.reg_use(ri);
571 collector.reg_use(rn);
572 }
573 Inst::FpuRRRR { rd, rn, rm, ra, .. } => {
574 collector.reg_def(rd);
575 collector.reg_use(rn);
576 collector.reg_use(rm);
577 collector.reg_use(ra);
578 }
579 Inst::VecMisc { rd, rn, .. } => {
580 collector.reg_def(rd);
581 collector.reg_use(rn);
582 }
583
584 Inst::VecLanes { rd, rn, .. } => {
585 collector.reg_def(rd);
586 collector.reg_use(rn);
587 }
588 Inst::VecShiftImm { rd, rn, .. } => {
589 collector.reg_def(rd);
590 collector.reg_use(rn);
591 }
592 Inst::VecShiftImmMod { rd, ri, rn, .. } => {
593 collector.reg_reuse_def(rd, 1); collector.reg_use(ri);
595 collector.reg_use(rn);
596 }
597 Inst::VecExtract { rd, rn, rm, .. } => {
598 collector.reg_def(rd);
599 collector.reg_use(rn);
600 collector.reg_use(rm);
601 }
602 Inst::VecTbl { rd, rn, rm } => {
603 collector.reg_use(rn);
604 collector.reg_use(rm);
605 collector.reg_def(rd);
606 }
607 Inst::VecTblExt { rd, ri, rn, rm } => {
608 collector.reg_use(rn);
609 collector.reg_use(rm);
610 collector.reg_reuse_def(rd, 3); collector.reg_use(ri);
612 }
613
614 Inst::VecTbl2 { rd, rn, rn2, rm } => {
615 collector.reg_fixed_use(rn, vreg(30));
619 collector.reg_fixed_use(rn2, vreg(31));
620 collector.reg_use(rm);
621 collector.reg_def(rd);
622 }
623 Inst::VecTbl2Ext {
624 rd,
625 ri,
626 rn,
627 rn2,
628 rm,
629 } => {
630 collector.reg_fixed_use(rn, vreg(30));
634 collector.reg_fixed_use(rn2, vreg(31));
635 collector.reg_use(rm);
636 collector.reg_reuse_def(rd, 4); collector.reg_use(ri);
638 }
639 Inst::VecLoadReplicate { rd, rn, .. } => {
640 collector.reg_def(rd);
641 collector.reg_use(rn);
642 }
643 Inst::VecCSel { rd, rn, rm, .. } => {
644 collector.reg_def(rd);
645 collector.reg_use(rn);
646 collector.reg_use(rm);
647 }
648 Inst::FpuCmp { rn, rm, .. } => {
649 collector.reg_use(rn);
650 collector.reg_use(rm);
651 }
652 Inst::FpuLoad16 { rd, mem, .. } => {
653 collector.reg_def(rd);
654 memarg_operands(mem, collector);
655 }
656 Inst::FpuLoad32 { rd, mem, .. } => {
657 collector.reg_def(rd);
658 memarg_operands(mem, collector);
659 }
660 Inst::FpuLoad64 { rd, mem, .. } => {
661 collector.reg_def(rd);
662 memarg_operands(mem, collector);
663 }
664 Inst::FpuLoad128 { rd, mem, .. } => {
665 collector.reg_def(rd);
666 memarg_operands(mem, collector);
667 }
668 Inst::FpuStore16 { rd, mem, .. } => {
669 collector.reg_use(rd);
670 memarg_operands(mem, collector);
671 }
672 Inst::FpuStore32 { rd, mem, .. } => {
673 collector.reg_use(rd);
674 memarg_operands(mem, collector);
675 }
676 Inst::FpuStore64 { rd, mem, .. } => {
677 collector.reg_use(rd);
678 memarg_operands(mem, collector);
679 }
680 Inst::FpuStore128 { rd, mem, .. } => {
681 collector.reg_use(rd);
682 memarg_operands(mem, collector);
683 }
684 Inst::FpuLoadP64 { rt, rt2, mem, .. } => {
685 collector.reg_def(rt);
686 collector.reg_def(rt2);
687 pairmemarg_operands(mem, collector);
688 }
689 Inst::FpuStoreP64 { rt, rt2, mem, .. } => {
690 collector.reg_use(rt);
691 collector.reg_use(rt2);
692 pairmemarg_operands(mem, collector);
693 }
694 Inst::FpuLoadP128 { rt, rt2, mem, .. } => {
695 collector.reg_def(rt);
696 collector.reg_def(rt2);
697 pairmemarg_operands(mem, collector);
698 }
699 Inst::FpuStoreP128 { rt, rt2, mem, .. } => {
700 collector.reg_use(rt);
701 collector.reg_use(rt2);
702 pairmemarg_operands(mem, collector);
703 }
704 Inst::FpuToInt { rd, rn, .. } => {
705 collector.reg_def(rd);
706 collector.reg_use(rn);
707 }
708 Inst::IntToFpu { rd, rn, .. } => {
709 collector.reg_def(rd);
710 collector.reg_use(rn);
711 }
712 Inst::FpuCSel16 { rd, rn, rm, .. }
713 | Inst::FpuCSel32 { rd, rn, rm, .. }
714 | Inst::FpuCSel64 { rd, rn, rm, .. } => {
715 collector.reg_def(rd);
716 collector.reg_use(rn);
717 collector.reg_use(rm);
718 }
719 Inst::FpuRound { rd, rn, .. } => {
720 collector.reg_def(rd);
721 collector.reg_use(rn);
722 }
723 Inst::MovToFpu { rd, rn, .. } => {
724 collector.reg_def(rd);
725 collector.reg_use(rn);
726 }
727 Inst::FpuMoveFPImm { rd, .. } => {
728 collector.reg_def(rd);
729 }
730 Inst::MovToVec { rd, ri, rn, .. } => {
731 collector.reg_reuse_def(rd, 1); collector.reg_use(ri);
733 collector.reg_use(rn);
734 }
735 Inst::MovFromVec { rd, rn, .. } | Inst::MovFromVecSigned { rd, rn, .. } => {
736 collector.reg_def(rd);
737 collector.reg_use(rn);
738 }
739 Inst::VecDup { rd, rn, .. } => {
740 collector.reg_def(rd);
741 collector.reg_use(rn);
742 }
743 Inst::VecDupFromFpu { rd, rn, .. } => {
744 collector.reg_def(rd);
745 collector.reg_use(rn);
746 }
747 Inst::VecDupFPImm { rd, .. } => {
748 collector.reg_def(rd);
749 }
750 Inst::VecDupImm { rd, .. } => {
751 collector.reg_def(rd);
752 }
753 Inst::VecExtend { rd, rn, .. } => {
754 collector.reg_def(rd);
755 collector.reg_use(rn);
756 }
757 Inst::VecMovElement { rd, ri, rn, .. } => {
758 collector.reg_reuse_def(rd, 1); collector.reg_use(ri);
760 collector.reg_use(rn);
761 }
762 Inst::VecRRLong { rd, rn, .. } => {
763 collector.reg_def(rd);
764 collector.reg_use(rn);
765 }
766 Inst::VecRRNarrowLow { rd, rn, .. } => {
767 collector.reg_use(rn);
768 collector.reg_def(rd);
769 }
770 Inst::VecRRNarrowHigh { rd, ri, rn, .. } => {
771 collector.reg_use(rn);
772 collector.reg_reuse_def(rd, 2); collector.reg_use(ri);
774 }
775 Inst::VecRRPair { rd, rn, .. } => {
776 collector.reg_def(rd);
777 collector.reg_use(rn);
778 }
779 Inst::VecRRRLong { rd, rn, rm, .. } => {
780 collector.reg_def(rd);
781 collector.reg_use(rn);
782 collector.reg_use(rm);
783 }
784 Inst::VecRRRLongMod { rd, ri, rn, rm, .. } => {
785 collector.reg_reuse_def(rd, 1); collector.reg_use(ri);
787 collector.reg_use(rn);
788 collector.reg_use(rm);
789 }
790 Inst::VecRRPairLong { rd, rn, .. } => {
791 collector.reg_def(rd);
792 collector.reg_use(rn);
793 }
794 Inst::VecRRR { rd, rn, rm, .. } => {
795 collector.reg_def(rd);
796 collector.reg_use(rn);
797 collector.reg_use(rm);
798 }
799 Inst::VecRRRMod { rd, ri, rn, rm, .. } | Inst::VecFmlaElem { rd, ri, rn, rm, .. } => {
800 collector.reg_reuse_def(rd, 1); collector.reg_use(ri);
802 collector.reg_use(rn);
803 collector.reg_use(rm);
804 }
805 Inst::MovToNZCV { rn } => {
806 collector.reg_use(rn);
807 }
808 Inst::MovFromNZCV { rd } => {
809 collector.reg_def(rd);
810 }
811 Inst::Extend { rd, rn, .. } => {
812 collector.reg_def(rd);
813 collector.reg_use(rn);
814 }
815 Inst::Args { args } => {
816 for ArgPair { vreg, preg } in args {
817 collector.reg_fixed_def(vreg, *preg);
818 }
819 }
820 Inst::Rets { rets } => {
821 for RetPair { vreg, preg } in rets {
822 collector.reg_fixed_use(vreg, *preg);
823 }
824 }
825 Inst::Ret { .. } | Inst::AuthenticatedRet { .. } => {}
826 Inst::Jump { .. } => {}
827 Inst::Call { info, .. } => {
828 let CallInfo { uses, defs, .. } = &mut **info;
829 for CallArgPair { vreg, preg } in uses {
830 collector.reg_fixed_use(vreg, *preg);
831 }
832 for CallRetPair { vreg, location } in defs {
833 match location {
834 RetLocation::Reg(preg, ..) => collector.reg_fixed_def(vreg, *preg),
835 RetLocation::Stack(..) => collector.any_def(vreg),
836 }
837 }
838 collector.reg_clobbers(info.clobbers);
839 if let Some(try_call_info) = &mut info.try_call_info {
840 try_call_info.collect_operands(collector);
841 }
842 }
843 Inst::CallInd { info, .. } => {
844 let CallInfo {
845 dest, uses, defs, ..
846 } = &mut **info;
847 collector.reg_use(dest);
848 for CallArgPair { vreg, preg } in uses {
849 collector.reg_fixed_use(vreg, *preg);
850 }
851 for CallRetPair { vreg, location } in defs {
852 match location {
853 RetLocation::Reg(preg, ..) => collector.reg_fixed_def(vreg, *preg),
854 RetLocation::Stack(..) => collector.any_def(vreg),
855 }
856 }
857 collector.reg_clobbers(info.clobbers);
858 if let Some(try_call_info) = &mut info.try_call_info {
859 try_call_info.collect_operands(collector);
860 }
861 }
862 Inst::ReturnCall { info } => {
863 for CallArgPair { vreg, preg } in &mut info.uses {
864 collector.reg_fixed_use(vreg, *preg);
865 }
866 }
867 Inst::ReturnCallInd { info } => {
868 collector.reg_fixed_use(&mut info.dest, xreg(1));
873 for CallArgPair { vreg, preg } in &mut info.uses {
874 collector.reg_fixed_use(vreg, *preg);
875 }
876 }
877 Inst::CondBr { kind, .. } => match kind {
878 CondBrKind::Zero(rt, _) | CondBrKind::NotZero(rt, _) => collector.reg_use(rt),
879 CondBrKind::Cond(_) => {}
880 },
881 Inst::TestBitAndBranch { rn, .. } => {
882 collector.reg_use(rn);
883 }
884 Inst::IndirectBr { rn, .. } => {
885 collector.reg_use(rn);
886 }
887 Inst::Nop0 | Inst::Nop4 => {}
888 Inst::Brk => {}
889 Inst::Udf { .. } => {}
890 Inst::TrapIf { kind, .. } => match kind {
891 CondBrKind::Zero(rt, _) | CondBrKind::NotZero(rt, _) => collector.reg_use(rt),
892 CondBrKind::Cond(_) => {}
893 },
894 Inst::Adr { rd, .. } | Inst::Adrp { rd, .. } => {
895 collector.reg_def(rd);
896 }
897 Inst::Word4 { .. } | Inst::Word8 { .. } => {}
898 Inst::JTSequence {
899 ridx, rtmp1, rtmp2, ..
900 } => {
901 collector.reg_use(ridx);
902 collector.reg_early_def(rtmp1);
903 collector.reg_early_def(rtmp2);
904 }
905 Inst::LoadExtNameGot { rd, .. }
906 | Inst::LoadExtNameNear { rd, .. }
907 | Inst::LoadExtNameFar { rd, .. } => {
908 collector.reg_def(rd);
909 }
910 Inst::LoadAddr { rd, mem } => {
911 collector.reg_def(rd);
912 memarg_operands(mem, collector);
913 }
914 Inst::Paci { .. } | Inst::Xpaclri => {
915 }
918 Inst::Bti { .. } => {}
919
920 Inst::ElfTlsGetAddr { rd, tmp, .. } => {
921 collector.reg_fixed_def(rd, regs::xreg(0));
928 collector.reg_early_def(tmp);
929 }
930 Inst::MachOTlsGetAddr { rd, .. } => {
931 collector.reg_fixed_def(rd, regs::xreg(0));
932 let mut clobbers =
933 AArch64MachineDeps::get_regs_clobbered_by_call(CallConv::AppleAarch64, false);
934 clobbers.remove(regs::xreg_preg(0));
935 collector.reg_clobbers(clobbers);
936 }
937 Inst::Unwind { .. } => {}
938 Inst::EmitIsland { .. } => {}
939 Inst::DummyUse { reg } => {
940 collector.reg_use(reg);
941 }
942 Inst::LabelAddress { dst, .. } => {
943 collector.reg_def(dst);
944 }
945 Inst::SequencePoint { .. } => {}
946 Inst::StackProbeLoop { start, end, .. } => {
947 collector.reg_early_def(start);
948 collector.reg_use(end);
949 }
950 }
951}
952
953impl MachInst for Inst {
957 type ABIMachineSpec = AArch64MachineDeps;
958 type LabelUse = LabelUse;
959
960 const TRAP_OPCODE: &'static [u8] = &0xc11f_u32.to_le_bytes();
963
964 fn get_operands(&mut self, collector: &mut impl OperandVisitor) {
965 aarch64_get_operands(self, collector);
966 }
967
968 fn is_move(&self) -> Option<(Writable<Reg>, Reg)> {
969 match self {
970 &Inst::Mov {
971 size: OperandSize::Size64,
972 rd,
973 rm,
974 } => Some((rd, rm)),
975 &Inst::FpuMove64 { rd, rn } => Some((rd, rn)),
976 &Inst::FpuMove128 { rd, rn } => Some((rd, rn)),
977 _ => None,
978 }
979 }
980
981 fn is_included_in_clobbers(&self) -> bool {
982 let (caller, callee, is_exception) = match self {
983 Inst::Args { .. } => return false,
984 Inst::Call { info } => (
985 info.caller_conv,
986 info.callee_conv,
987 info.try_call_info.is_some(),
988 ),
989 Inst::CallInd { info } => (
990 info.caller_conv,
991 info.callee_conv,
992 info.try_call_info.is_some(),
993 ),
994 _ => return true,
995 };
996
997 let caller_clobbers = AArch64MachineDeps::get_regs_clobbered_by_call(caller, false);
1009 let callee_clobbers = AArch64MachineDeps::get_regs_clobbered_by_call(callee, is_exception);
1010
1011 let mut all_clobbers = caller_clobbers;
1012 all_clobbers.union_from(callee_clobbers);
1013 all_clobbers != caller_clobbers
1014 }
1015
1016 fn is_trap(&self) -> bool {
1017 match self {
1018 Self::Udf { .. } => true,
1019 _ => false,
1020 }
1021 }
1022
1023 fn is_args(&self) -> bool {
1024 match self {
1025 Self::Args { .. } => true,
1026 _ => false,
1027 }
1028 }
1029
1030 fn call_type(&self) -> CallType {
1031 match self {
1032 Inst::Call { .. }
1033 | Inst::CallInd { .. }
1034 | Inst::ElfTlsGetAddr { .. }
1035 | Inst::MachOTlsGetAddr { .. } => CallType::Regular,
1036
1037 Inst::ReturnCall { .. } | Inst::ReturnCallInd { .. } => CallType::TailCall,
1038
1039 _ => CallType::None,
1040 }
1041 }
1042
1043 fn is_term(&self) -> MachTerminator {
1044 match self {
1045 &Inst::Rets { .. } => MachTerminator::Ret,
1046 &Inst::ReturnCall { .. } | &Inst::ReturnCallInd { .. } => MachTerminator::RetCall,
1047 &Inst::Jump { .. } => MachTerminator::Branch,
1048 &Inst::CondBr { .. } => MachTerminator::Branch,
1049 &Inst::TestBitAndBranch { .. } => MachTerminator::Branch,
1050 &Inst::IndirectBr { .. } => MachTerminator::Branch,
1051 &Inst::JTSequence { .. } => MachTerminator::Branch,
1052 &Inst::Call { ref info } if info.try_call_info.is_some() => MachTerminator::Branch,
1053 &Inst::CallInd { ref info } if info.try_call_info.is_some() => MachTerminator::Branch,
1054 _ => MachTerminator::None,
1055 }
1056 }
1057
1058 fn is_mem_access(&self) -> bool {
1059 match self {
1060 &Inst::ULoad8 { .. }
1061 | &Inst::SLoad8 { .. }
1062 | &Inst::ULoad16 { .. }
1063 | &Inst::SLoad16 { .. }
1064 | &Inst::ULoad32 { .. }
1065 | &Inst::SLoad32 { .. }
1066 | &Inst::ULoad64 { .. }
1067 | &Inst::LoadP64 { .. }
1068 | &Inst::FpuLoad16 { .. }
1069 | &Inst::FpuLoad32 { .. }
1070 | &Inst::FpuLoad64 { .. }
1071 | &Inst::FpuLoad128 { .. }
1072 | &Inst::FpuLoadP64 { .. }
1073 | &Inst::FpuLoadP128 { .. }
1074 | &Inst::Store8 { .. }
1075 | &Inst::Store16 { .. }
1076 | &Inst::Store32 { .. }
1077 | &Inst::Store64 { .. }
1078 | &Inst::StoreP64 { .. }
1079 | &Inst::FpuStore16 { .. }
1080 | &Inst::FpuStore32 { .. }
1081 | &Inst::FpuStore64 { .. }
1082 | &Inst::FpuStore128 { .. } => true,
1083 _ => false,
1085 }
1086 }
1087
1088 fn gen_move(to_reg: Writable<Reg>, from_reg: Reg, ty: Type) -> Inst {
1089 let bits = ty.bits();
1090
1091 assert!(bits <= 128);
1092 assert!(to_reg.to_reg().class() == from_reg.class());
1093 match from_reg.class() {
1094 RegClass::Int => Inst::Mov {
1095 size: OperandSize::Size64,
1096 rd: to_reg,
1097 rm: from_reg,
1098 },
1099 RegClass::Float => {
1100 if bits > 64 {
1101 Inst::FpuMove128 {
1102 rd: to_reg,
1103 rn: from_reg,
1104 }
1105 } else {
1106 Inst::FpuMove64 {
1107 rd: to_reg,
1108 rn: from_reg,
1109 }
1110 }
1111 }
1112 RegClass::Vector => unreachable!(),
1113 }
1114 }
1115
1116 fn is_safepoint(&self) -> bool {
1117 match self {
1118 Inst::Call { .. } | Inst::CallInd { .. } => true,
1119 _ => false,
1120 }
1121 }
1122
1123 fn gen_dummy_use(reg: Reg) -> Inst {
1124 Inst::DummyUse { reg }
1125 }
1126
1127 fn gen_nop(preferred_size: usize) -> Inst {
1128 if preferred_size == 0 {
1129 return Inst::Nop0;
1130 }
1131 assert!(preferred_size >= 4);
1133 Inst::Nop4
1134 }
1135
1136 fn gen_nop_units() -> Vec<Vec<u8>> {
1137 vec![vec![0x1f, 0x20, 0x03, 0xd5]]
1138 }
1139
1140 fn rc_for_type(ty: &Type) -> CodegenResult<(&[RegClass], &[Type])> {
1141 match *ty {
1142 I8 | I16 | I32 | I64 => Ok((&[RegClass::Int], slice::from_ref(ty))),
1143 F16 | F32 | F64 | F128 => Ok((&[RegClass::Float], slice::from_ref(ty))),
1144 I128 => Ok((&[RegClass::Int, RegClass::Int], &[I64, I64])),
1145 _ if ty.is_vector() && ty.bits() <= 128 => {
1146 let types = &[types::I8X2, types::I8X4, types::I8X8, types::I8X16];
1147 Ok((
1148 &[RegClass::Float],
1149 slice::from_ref(&types[ty.bytes().ilog2() as usize - 1]),
1150 ))
1151 }
1152 _ if ty.is_dynamic_vector() => Ok((&[RegClass::Float], &[I8X16])),
1153 _ => Err(CodegenError::Unsupported(format!(
1154 "Unexpected SSA-value type: {ty}"
1155 ))),
1156 }
1157 }
1158
1159 fn canonical_type_for_rc(rc: RegClass) -> Type {
1160 match rc {
1161 RegClass::Float => types::I8X16,
1162 RegClass::Int => types::I64,
1163 RegClass::Vector => unreachable!(),
1164 }
1165 }
1166
1167 fn gen_jump(target: MachLabel) -> Inst {
1168 Inst::Jump {
1169 dest: BranchTarget::Label(target),
1170 }
1171 }
1172
1173 fn worst_case_size() -> CodeOffset {
1174 44
1182 }
1183
1184 fn worst_case_island_growth() -> CodeOffset {
1185 128
1195 }
1196
1197 fn gen_block_start(
1198 is_indirect_branch_target: bool,
1199 is_forward_edge_cfi_enabled: bool,
1200 ) -> Option<Self> {
1201 if is_indirect_branch_target && is_forward_edge_cfi_enabled {
1202 Some(Inst::Bti {
1203 targets: BranchTargetType::J,
1204 })
1205 } else {
1206 None
1207 }
1208 }
1209
1210 fn function_alignment() -> FunctionAlignment {
1211 FunctionAlignment {
1214 minimum: 4,
1215 preferred: 32,
1216 }
1217 }
1218}
1219
1220fn mem_finalize_for_show(mem: &AMode, access_ty: Type, state: &EmitState) -> (String, String) {
1224 let (mem_insts, mem) = mem_finalize(None, mem, access_ty, state);
1225 let mut mem_str = mem_insts
1226 .into_iter()
1227 .map(|inst| inst.print_with_state(&mut EmitState::default()))
1228 .collect::<Vec<_>>()
1229 .join(" ; ");
1230 if !mem_str.is_empty() {
1231 mem_str += " ; ";
1232 }
1233
1234 let mem = mem.pretty_print(access_ty.bytes() as u8);
1235 (mem_str, mem)
1236}
1237
1238fn pretty_print_try_call(info: &TryCallInfo) -> String {
1239 format!(
1240 "; b {:?}; catch [{}]",
1241 info.continuation,
1242 info.pretty_print_dests()
1243 )
1244}
1245
1246impl Inst {
1247 #[expect(
1248 missing_docs,
1249 reason = "exposed for cranelift-isle/veri pretty-printing"
1250 )]
1251 pub fn print_with_state(&self, state: &mut EmitState) -> String {
1252 fn op_name(alu_op: ALUOp) -> &'static str {
1253 match alu_op {
1254 ALUOp::Add => "add",
1255 ALUOp::Sub => "sub",
1256 ALUOp::Orr => "orr",
1257 ALUOp::And => "and",
1258 ALUOp::AndS => "ands",
1259 ALUOp::Eor => "eor",
1260 ALUOp::AddS => "adds",
1261 ALUOp::SubS => "subs",
1262 ALUOp::SMulH => "smulh",
1263 ALUOp::UMulH => "umulh",
1264 ALUOp::SDiv => "sdiv",
1265 ALUOp::UDiv => "udiv",
1266 ALUOp::AndNot => "bic",
1267 ALUOp::OrrNot => "orn",
1268 ALUOp::EorNot => "eon",
1269 ALUOp::Extr => "extr",
1270 ALUOp::Lsr => "lsr",
1271 ALUOp::Asr => "asr",
1272 ALUOp::Lsl => "lsl",
1273 ALUOp::Adc => "adc",
1274 ALUOp::AdcS => "adcs",
1275 ALUOp::Sbc => "sbc",
1276 ALUOp::SbcS => "sbcs",
1277 }
1278 }
1279
1280 match self {
1281 &Inst::Nop0 => "nop-zero-len".to_string(),
1282 &Inst::Nop4 => "nop".to_string(),
1283 &Inst::AluRRR {
1284 alu_op,
1285 size,
1286 rd,
1287 rn,
1288 rm,
1289 } => {
1290 let op = op_name(alu_op);
1291 let rd = pretty_print_ireg(rd.to_reg(), size);
1292 let rn = pretty_print_ireg(rn, size);
1293 let rm = pretty_print_ireg(rm, size);
1294 format!("{op} {rd}, {rn}, {rm}")
1295 }
1296 &Inst::AluRRRR {
1297 alu_op,
1298 size,
1299 rd,
1300 rn,
1301 rm,
1302 ra,
1303 } => {
1304 let (op, da_size) = match alu_op {
1305 ALUOp3::MAdd => ("madd", size),
1306 ALUOp3::MSub => ("msub", size),
1307 ALUOp3::UMAddL => ("umaddl", OperandSize::Size64),
1308 ALUOp3::SMAddL => ("smaddl", OperandSize::Size64),
1309 };
1310 let rd = pretty_print_ireg(rd.to_reg(), da_size);
1311 let rn = pretty_print_ireg(rn, size);
1312 let rm = pretty_print_ireg(rm, size);
1313 let ra = pretty_print_ireg(ra, da_size);
1314
1315 format!("{op} {rd}, {rn}, {rm}, {ra}")
1316 }
1317 &Inst::AluRRImm12 {
1318 alu_op,
1319 size,
1320 rd,
1321 rn,
1322 ref imm12,
1323 } => {
1324 let op = op_name(alu_op);
1325 let rd = pretty_print_ireg(rd.to_reg(), size);
1326 let rn = pretty_print_ireg(rn, size);
1327
1328 if imm12.bits == 0 && alu_op == ALUOp::Add && size.is64() {
1329 format!("mov {rd}, {rn}")
1331 } else {
1332 let imm12 = imm12.pretty_print(0);
1333 format!("{op} {rd}, {rn}, {imm12}")
1334 }
1335 }
1336 &Inst::AluRRImmLogic {
1337 alu_op,
1338 size,
1339 rd,
1340 rn,
1341 ref imml,
1342 } => {
1343 let op = op_name(alu_op);
1344 let rd = pretty_print_ireg(rd.to_reg(), size);
1345 let rn = pretty_print_ireg(rn, size);
1346 let imml = imml.pretty_print(0);
1347 format!("{op} {rd}, {rn}, {imml}")
1348 }
1349 &Inst::AluRRImmShift {
1350 alu_op,
1351 size,
1352 rd,
1353 rn,
1354 ref immshift,
1355 } => {
1356 let op = op_name(alu_op);
1357 let rd = pretty_print_ireg(rd.to_reg(), size);
1358 let rn = pretty_print_ireg(rn, size);
1359 let immshift = immshift.pretty_print(0);
1360 format!("{op} {rd}, {rn}, {immshift}")
1361 }
1362 &Inst::AluRRRShift {
1363 alu_op,
1364 size,
1365 rd,
1366 rn,
1367 rm,
1368 ref shiftop,
1369 } => {
1370 let op = op_name(alu_op);
1371 let rd = pretty_print_ireg(rd.to_reg(), size);
1372 let rn = pretty_print_ireg(rn, size);
1373 let rm = pretty_print_ireg(rm, size);
1374 let shiftop = shiftop.pretty_print(0);
1375 format!("{op} {rd}, {rn}, {rm}, {shiftop}")
1376 }
1377 &Inst::AluRRRExtend {
1378 alu_op,
1379 size,
1380 rd,
1381 rn,
1382 rm,
1383 ref extendop,
1384 } => {
1385 let op = op_name(alu_op);
1386 let rd = pretty_print_ireg(rd.to_reg(), size);
1387 let rn = pretty_print_ireg(rn, size);
1388 let rm = pretty_print_ireg(rm, size);
1389 let extendop = extendop.pretty_print(0);
1390 format!("{op} {rd}, {rn}, {rm}, {extendop}")
1391 }
1392 &Inst::BitRR { op, size, rd, rn } => {
1393 let op = op.op_str();
1394 let rd = pretty_print_ireg(rd.to_reg(), size);
1395 let rn = pretty_print_ireg(rn, size);
1396 format!("{op} {rd}, {rn}")
1397 }
1398 &Inst::ULoad8 { rd, ref mem, .. }
1399 | &Inst::SLoad8 { rd, ref mem, .. }
1400 | &Inst::ULoad16 { rd, ref mem, .. }
1401 | &Inst::SLoad16 { rd, ref mem, .. }
1402 | &Inst::ULoad32 { rd, ref mem, .. }
1403 | &Inst::SLoad32 { rd, ref mem, .. }
1404 | &Inst::ULoad64 { rd, ref mem, .. } => {
1405 let is_unscaled = match &mem {
1406 &AMode::Unscaled { .. } => true,
1407 _ => false,
1408 };
1409 let (op, size) = match (self, is_unscaled) {
1410 (&Inst::ULoad8 { .. }, false) => ("ldrb", OperandSize::Size32),
1411 (&Inst::ULoad8 { .. }, true) => ("ldurb", OperandSize::Size32),
1412 (&Inst::SLoad8 { .. }, false) => ("ldrsb", OperandSize::Size64),
1413 (&Inst::SLoad8 { .. }, true) => ("ldursb", OperandSize::Size64),
1414 (&Inst::ULoad16 { .. }, false) => ("ldrh", OperandSize::Size32),
1415 (&Inst::ULoad16 { .. }, true) => ("ldurh", OperandSize::Size32),
1416 (&Inst::SLoad16 { .. }, false) => ("ldrsh", OperandSize::Size64),
1417 (&Inst::SLoad16 { .. }, true) => ("ldursh", OperandSize::Size64),
1418 (&Inst::ULoad32 { .. }, false) => ("ldr", OperandSize::Size32),
1419 (&Inst::ULoad32 { .. }, true) => ("ldur", OperandSize::Size32),
1420 (&Inst::SLoad32 { .. }, false) => ("ldrsw", OperandSize::Size64),
1421 (&Inst::SLoad32 { .. }, true) => ("ldursw", OperandSize::Size64),
1422 (&Inst::ULoad64 { .. }, false) => ("ldr", OperandSize::Size64),
1423 (&Inst::ULoad64 { .. }, true) => ("ldur", OperandSize::Size64),
1424 _ => unreachable!(),
1425 };
1426
1427 let rd = pretty_print_ireg(rd.to_reg(), size);
1428 let mem = mem.clone();
1429 let access_ty = self.mem_type().unwrap();
1430 let (mem_str, mem) = mem_finalize_for_show(&mem, access_ty, state);
1431
1432 format!("{mem_str}{op} {rd}, {mem}")
1433 }
1434 &Inst::Store8 { rd, ref mem, .. }
1435 | &Inst::Store16 { rd, ref mem, .. }
1436 | &Inst::Store32 { rd, ref mem, .. }
1437 | &Inst::Store64 { rd, ref mem, .. } => {
1438 let is_unscaled = match &mem {
1439 &AMode::Unscaled { .. } => true,
1440 _ => false,
1441 };
1442 let (op, size) = match (self, is_unscaled) {
1443 (&Inst::Store8 { .. }, false) => ("strb", OperandSize::Size32),
1444 (&Inst::Store8 { .. }, true) => ("sturb", OperandSize::Size32),
1445 (&Inst::Store16 { .. }, false) => ("strh", OperandSize::Size32),
1446 (&Inst::Store16 { .. }, true) => ("sturh", OperandSize::Size32),
1447 (&Inst::Store32 { .. }, false) => ("str", OperandSize::Size32),
1448 (&Inst::Store32 { .. }, true) => ("stur", OperandSize::Size32),
1449 (&Inst::Store64 { .. }, false) => ("str", OperandSize::Size64),
1450 (&Inst::Store64 { .. }, true) => ("stur", OperandSize::Size64),
1451 _ => unreachable!(),
1452 };
1453
1454 let rd = pretty_print_ireg(rd, size);
1455 let mem = mem.clone();
1456 let access_ty = self.mem_type().unwrap();
1457 let (mem_str, mem) = mem_finalize_for_show(&mem, access_ty, state);
1458
1459 format!("{mem_str}{op} {rd}, {mem}")
1460 }
1461 &Inst::StoreP64 {
1462 rt, rt2, ref mem, ..
1463 } => {
1464 let rt = pretty_print_ireg(rt, OperandSize::Size64);
1465 let rt2 = pretty_print_ireg(rt2, OperandSize::Size64);
1466 let mem = mem.clone();
1467 let mem = mem.pretty_print_default();
1468 format!("stp {rt}, {rt2}, {mem}")
1469 }
1470 &Inst::LoadP64 {
1471 rt, rt2, ref mem, ..
1472 } => {
1473 let rt = pretty_print_ireg(rt.to_reg(), OperandSize::Size64);
1474 let rt2 = pretty_print_ireg(rt2.to_reg(), OperandSize::Size64);
1475 let mem = mem.clone();
1476 let mem = mem.pretty_print_default();
1477 format!("ldp {rt}, {rt2}, {mem}")
1478 }
1479 &Inst::Mov { size, rd, rm } => {
1480 let rd = pretty_print_ireg(rd.to_reg(), size);
1481 let rm = pretty_print_ireg(rm, size);
1482 format!("mov {rd}, {rm}")
1483 }
1484 &Inst::MovFromPReg { rd, rm } => {
1485 let rd = pretty_print_ireg(rd.to_reg(), OperandSize::Size64);
1486 let rm = show_ireg_sized(rm.into(), OperandSize::Size64);
1487 format!("mov {rd}, {rm}")
1488 }
1489 &Inst::MovToPReg { rd, rm } => {
1490 let rd = show_ireg_sized(rd.into(), OperandSize::Size64);
1491 let rm = pretty_print_ireg(rm, OperandSize::Size64);
1492 format!("mov {rd}, {rm}")
1493 }
1494 &Inst::MovWide {
1495 op,
1496 rd,
1497 ref imm,
1498 size,
1499 } => {
1500 let op_str = match op {
1501 MoveWideOp::MovZ => "movz",
1502 MoveWideOp::MovN => "movn",
1503 };
1504 let rd = pretty_print_ireg(rd.to_reg(), size);
1505 let imm = imm.pretty_print(0);
1506 format!("{op_str} {rd}, {imm}")
1507 }
1508 &Inst::MovK {
1509 rd,
1510 rn,
1511 ref imm,
1512 size,
1513 } => {
1514 let rn = pretty_print_ireg(rn, size);
1515 let rd = pretty_print_ireg(rd.to_reg(), size);
1516 let imm = imm.pretty_print(0);
1517 format!("movk {rd}, {rn}, {imm}")
1518 }
1519 &Inst::CSel { rd, rn, rm, cond } => {
1520 let rd = pretty_print_ireg(rd.to_reg(), OperandSize::Size64);
1521 let rn = pretty_print_ireg(rn, OperandSize::Size64);
1522 let rm = pretty_print_ireg(rm, OperandSize::Size64);
1523 let cond = cond.pretty_print(0);
1524 format!("csel {rd}, {rn}, {rm}, {cond}")
1525 }
1526 &Inst::CSNeg { rd, rn, rm, cond } => {
1527 let rd = pretty_print_ireg(rd.to_reg(), OperandSize::Size64);
1528 let rn = pretty_print_ireg(rn, OperandSize::Size64);
1529 let rm = pretty_print_ireg(rm, OperandSize::Size64);
1530 let cond = cond.pretty_print(0);
1531 format!("csneg {rd}, {rn}, {rm}, {cond}")
1532 }
1533 &Inst::CSet { rd, cond } => {
1534 let rd = pretty_print_ireg(rd.to_reg(), OperandSize::Size64);
1535 let cond = cond.pretty_print(0);
1536 format!("cset {rd}, {cond}")
1537 }
1538 &Inst::CSetm { rd, cond } => {
1539 let rd = pretty_print_ireg(rd.to_reg(), OperandSize::Size64);
1540 let cond = cond.pretty_print(0);
1541 format!("csetm {rd}, {cond}")
1542 }
1543 &Inst::CCmp {
1544 size,
1545 rn,
1546 rm,
1547 nzcv,
1548 cond,
1549 } => {
1550 let rn = pretty_print_ireg(rn, size);
1551 let rm = pretty_print_ireg(rm, size);
1552 let nzcv = nzcv.pretty_print(0);
1553 let cond = cond.pretty_print(0);
1554 format!("ccmp {rn}, {rm}, {nzcv}, {cond}")
1555 }
1556 &Inst::CCmpImm {
1557 size,
1558 rn,
1559 imm,
1560 nzcv,
1561 cond,
1562 } => {
1563 let rn = pretty_print_ireg(rn, size);
1564 let imm = imm.pretty_print(0);
1565 let nzcv = nzcv.pretty_print(0);
1566 let cond = cond.pretty_print(0);
1567 format!("ccmp {rn}, {imm}, {nzcv}, {cond}")
1568 }
1569 &Inst::AtomicRMW {
1570 rs, rt, rn, ty, op, ..
1571 } => {
1572 let op = match op {
1573 AtomicRMWOp::Add => "ldaddal",
1574 AtomicRMWOp::Clr => "ldclral",
1575 AtomicRMWOp::Eor => "ldeoral",
1576 AtomicRMWOp::Set => "ldsetal",
1577 AtomicRMWOp::Smax => "ldsmaxal",
1578 AtomicRMWOp::Umax => "ldumaxal",
1579 AtomicRMWOp::Smin => "ldsminal",
1580 AtomicRMWOp::Umin => "lduminal",
1581 AtomicRMWOp::Swp => "swpal",
1582 };
1583
1584 let size = OperandSize::from_ty(ty);
1585 let rs = pretty_print_ireg(rs, size);
1586 let rt = pretty_print_ireg(rt.to_reg(), size);
1587 let rn = pretty_print_ireg(rn, OperandSize::Size64);
1588
1589 let ty_suffix = match ty {
1590 I8 => "b",
1591 I16 => "h",
1592 _ => "",
1593 };
1594 format!("{op}{ty_suffix} {rs}, {rt}, [{rn}]")
1595 }
1596 &Inst::AtomicRMWLoop {
1597 ty,
1598 op,
1599 addr,
1600 operand,
1601 oldval,
1602 scratch1,
1603 scratch2,
1604 ..
1605 } => {
1606 let op = match op {
1607 AtomicRMWLoopOp::Add => "add",
1608 AtomicRMWLoopOp::Sub => "sub",
1609 AtomicRMWLoopOp::Eor => "eor",
1610 AtomicRMWLoopOp::Orr => "orr",
1611 AtomicRMWLoopOp::And => "and",
1612 AtomicRMWLoopOp::Nand => "nand",
1613 AtomicRMWLoopOp::Smin => "smin",
1614 AtomicRMWLoopOp::Smax => "smax",
1615 AtomicRMWLoopOp::Umin => "umin",
1616 AtomicRMWLoopOp::Umax => "umax",
1617 AtomicRMWLoopOp::Xchg => "xchg",
1618 };
1619 let addr = pretty_print_ireg(addr, OperandSize::Size64);
1620 let operand = pretty_print_ireg(operand, OperandSize::Size64);
1621 let oldval = pretty_print_ireg(oldval.to_reg(), OperandSize::Size64);
1622 let scratch1 = pretty_print_ireg(scratch1.to_reg(), OperandSize::Size64);
1623 let scratch2 = pretty_print_ireg(scratch2.to_reg(), OperandSize::Size64);
1624 format!(
1625 "atomic_rmw_loop_{}_{} addr={} operand={} oldval={} scratch1={} scratch2={}",
1626 op,
1627 ty.bits(),
1628 addr,
1629 operand,
1630 oldval,
1631 scratch1,
1632 scratch2,
1633 )
1634 }
1635 &Inst::AtomicCAS {
1636 rd, rs, rt, rn, ty, ..
1637 } => {
1638 let op = match ty {
1639 I8 => "casalb",
1640 I16 => "casalh",
1641 I32 | I64 => "casal",
1642 _ => panic!("Unsupported type: {ty}"),
1643 };
1644 let size = OperandSize::from_ty(ty);
1645 let rd = pretty_print_ireg(rd.to_reg(), size);
1646 let rs = pretty_print_ireg(rs, size);
1647 let rt = pretty_print_ireg(rt, size);
1648 let rn = pretty_print_ireg(rn, OperandSize::Size64);
1649
1650 format!("{op} {rd}, {rs}, {rt}, [{rn}]")
1651 }
1652 Inst::AtomicCAS128 { args } => {
1653 let &AtomicCAS128Args {
1654 rd_lo,
1655 rd_hi,
1656 rs_lo,
1657 rs_hi,
1658 rt_lo,
1659 rt_hi,
1660 rn,
1661 flags: _,
1662 } = &**args;
1663 let size = OperandSize::Size64;
1664 let rd_lo = pretty_print_ireg(rd_lo.to_reg(), size);
1665 let rd_hi = pretty_print_ireg(rd_hi.to_reg(), size);
1666 let rs_lo = pretty_print_ireg(rs_lo, size);
1667 let rs_hi = pretty_print_ireg(rs_hi, size);
1668 let rt_lo = pretty_print_ireg(rt_lo, size);
1669 let rt_hi = pretty_print_ireg(rt_hi, size);
1670 let rn = pretty_print_ireg(rn, size);
1671
1672 format!("caspal {rd_lo}, {rd_hi}, {rs_lo}, {rs_hi}, {rt_lo}, {rt_hi}, [{rn}]")
1673 }
1674 &Inst::AtomicCASLoop {
1675 ty,
1676 addr,
1677 expected,
1678 replacement,
1679 oldval,
1680 scratch,
1681 ..
1682 } => {
1683 let addr = pretty_print_ireg(addr, OperandSize::Size64);
1684 let expected = pretty_print_ireg(expected, OperandSize::Size64);
1685 let replacement = pretty_print_ireg(replacement, OperandSize::Size64);
1686 let oldval = pretty_print_ireg(oldval.to_reg(), OperandSize::Size64);
1687 let scratch = pretty_print_ireg(scratch.to_reg(), OperandSize::Size64);
1688 format!(
1689 "atomic_cas_loop_{} addr={}, expect={}, replacement={}, oldval={}, scratch={}",
1690 ty.bits(),
1691 addr,
1692 expected,
1693 replacement,
1694 oldval,
1695 scratch,
1696 )
1697 }
1698 &Inst::LoadAcquire {
1699 access_ty, rt, rn, ..
1700 } => {
1701 let (op, ty) = match access_ty {
1702 I8 => ("ldarb", I32),
1703 I16 => ("ldarh", I32),
1704 I32 => ("ldar", I32),
1705 I64 => ("ldar", I64),
1706 _ => panic!("Unsupported type: {access_ty}"),
1707 };
1708 let size = OperandSize::from_ty(ty);
1709 let rn = pretty_print_ireg(rn, OperandSize::Size64);
1710 let rt = pretty_print_ireg(rt.to_reg(), size);
1711 format!("{op} {rt}, [{rn}]")
1712 }
1713 &Inst::StoreRelease {
1714 access_ty, rt, rn, ..
1715 } => {
1716 let (op, ty) = match access_ty {
1717 I8 => ("stlrb", I32),
1718 I16 => ("stlrh", I32),
1719 I32 => ("stlr", I32),
1720 I64 => ("stlr", I64),
1721 _ => panic!("Unsupported type: {access_ty}"),
1722 };
1723 let size = OperandSize::from_ty(ty);
1724 let rn = pretty_print_ireg(rn, OperandSize::Size64);
1725 let rt = pretty_print_ireg(rt, size);
1726 format!("{op} {rt}, [{rn}]")
1727 }
1728 &Inst::Fence {} => {
1729 format!("dmb ish")
1730 }
1731 &Inst::Csdb {} => {
1732 format!("csdb")
1733 }
1734 &Inst::FpuMove32 { rd, rn } => {
1735 let rd = pretty_print_vreg_scalar(rd.to_reg(), ScalarSize::Size32);
1736 let rn = pretty_print_vreg_scalar(rn, ScalarSize::Size32);
1737 format!("fmov {rd}, {rn}")
1738 }
1739 &Inst::FpuMove64 { rd, rn } => {
1740 let rd = pretty_print_vreg_scalar(rd.to_reg(), ScalarSize::Size64);
1741 let rn = pretty_print_vreg_scalar(rn, ScalarSize::Size64);
1742 format!("fmov {rd}, {rn}")
1743 }
1744 &Inst::FpuMove128 { rd, rn } => {
1745 let rd = pretty_print_reg(rd.to_reg());
1746 let rn = pretty_print_reg(rn);
1747 format!("mov {rd}.16b, {rn}.16b")
1748 }
1749 &Inst::FpuMoveFromVec { rd, rn, idx, size } => {
1750 let rd = pretty_print_vreg_scalar(rd.to_reg(), size.lane_size());
1751 let rn = pretty_print_vreg_element(rn, idx as usize, size.lane_size());
1752 format!("mov {rd}, {rn}")
1753 }
1754 &Inst::FpuExtend { rd, rn, size } => {
1755 let rd = pretty_print_vreg_scalar(rd.to_reg(), size);
1756 let rn = pretty_print_vreg_scalar(rn, size);
1757 format!("fmov {rd}, {rn}")
1758 }
1759 &Inst::FpuRR {
1760 fpu_op,
1761 size,
1762 rd,
1763 rn,
1764 } => {
1765 let op = match fpu_op {
1766 FPUOp1::Abs => "fabs",
1767 FPUOp1::Neg => "fneg",
1768 FPUOp1::Sqrt => "fsqrt",
1769 FPUOp1::Cvt32To64 | FPUOp1::Cvt64To32 => "fcvt",
1770 };
1771 let dst_size = match fpu_op {
1772 FPUOp1::Cvt32To64 => ScalarSize::Size64,
1773 FPUOp1::Cvt64To32 => ScalarSize::Size32,
1774 _ => size,
1775 };
1776 let rd = pretty_print_vreg_scalar(rd.to_reg(), dst_size);
1777 let rn = pretty_print_vreg_scalar(rn, size);
1778 format!("{op} {rd}, {rn}")
1779 }
1780 &Inst::FpuRRR {
1781 fpu_op,
1782 size,
1783 rd,
1784 rn,
1785 rm,
1786 } => {
1787 let op = match fpu_op {
1788 FPUOp2::Add => "fadd",
1789 FPUOp2::Sub => "fsub",
1790 FPUOp2::Mul => "fmul",
1791 FPUOp2::Div => "fdiv",
1792 FPUOp2::Max => "fmax",
1793 FPUOp2::Min => "fmin",
1794 };
1795 let rd = pretty_print_vreg_scalar(rd.to_reg(), size);
1796 let rn = pretty_print_vreg_scalar(rn, size);
1797 let rm = pretty_print_vreg_scalar(rm, size);
1798 format!("{op} {rd}, {rn}, {rm}")
1799 }
1800 &Inst::FpuRRI { fpu_op, rd, rn } => {
1801 let (op, imm, vector) = match fpu_op {
1802 FPUOpRI::UShr32(imm) => ("ushr", imm.pretty_print(0), true),
1803 FPUOpRI::UShr64(imm) => ("ushr", imm.pretty_print(0), false),
1804 };
1805
1806 let (rd, rn) = if vector {
1807 (
1808 pretty_print_vreg_vector(rd.to_reg(), VectorSize::Size32x2),
1809 pretty_print_vreg_vector(rn, VectorSize::Size32x2),
1810 )
1811 } else {
1812 (
1813 pretty_print_vreg_scalar(rd.to_reg(), ScalarSize::Size64),
1814 pretty_print_vreg_scalar(rn, ScalarSize::Size64),
1815 )
1816 };
1817 format!("{op} {rd}, {rn}, {imm}")
1818 }
1819 &Inst::FpuRRIMod { fpu_op, rd, ri, rn } => {
1820 let (op, imm, vector) = match fpu_op {
1821 FPUOpRIMod::Sli32(imm) => ("sli", imm.pretty_print(0), true),
1822 FPUOpRIMod::Sli64(imm) => ("sli", imm.pretty_print(0), false),
1823 };
1824
1825 let (rd, ri, rn) = if vector {
1826 (
1827 pretty_print_vreg_vector(rd.to_reg(), VectorSize::Size32x2),
1828 pretty_print_vreg_vector(ri, VectorSize::Size32x2),
1829 pretty_print_vreg_vector(rn, VectorSize::Size32x2),
1830 )
1831 } else {
1832 (
1833 pretty_print_vreg_scalar(rd.to_reg(), ScalarSize::Size64),
1834 pretty_print_vreg_scalar(ri, ScalarSize::Size64),
1835 pretty_print_vreg_scalar(rn, ScalarSize::Size64),
1836 )
1837 };
1838 format!("{op} {rd}, {ri}, {rn}, {imm}")
1839 }
1840 &Inst::FpuRRRR {
1841 fpu_op,
1842 size,
1843 rd,
1844 rn,
1845 rm,
1846 ra,
1847 } => {
1848 let op = match fpu_op {
1849 FPUOp3::MAdd => "fmadd",
1850 FPUOp3::MSub => "fmsub",
1851 FPUOp3::NMAdd => "fnmadd",
1852 FPUOp3::NMSub => "fnmsub",
1853 };
1854 let rd = pretty_print_vreg_scalar(rd.to_reg(), size);
1855 let rn = pretty_print_vreg_scalar(rn, size);
1856 let rm = pretty_print_vreg_scalar(rm, size);
1857 let ra = pretty_print_vreg_scalar(ra, size);
1858 format!("{op} {rd}, {rn}, {rm}, {ra}")
1859 }
1860 &Inst::FpuCmp { size, rn, rm } => {
1861 let rn = pretty_print_vreg_scalar(rn, size);
1862 let rm = pretty_print_vreg_scalar(rm, size);
1863 format!("fcmp {rn}, {rm}")
1864 }
1865 &Inst::FpuLoad16 { rd, ref mem, .. } => {
1866 let rd = pretty_print_vreg_scalar(rd.to_reg(), ScalarSize::Size16);
1867 let mem = mem.clone();
1868 let access_ty = self.mem_type().unwrap();
1869 let (mem_str, mem) = mem_finalize_for_show(&mem, access_ty, state);
1870 format!("{mem_str}ldr {rd}, {mem}")
1871 }
1872 &Inst::FpuLoad32 { rd, ref mem, .. } => {
1873 let rd = pretty_print_vreg_scalar(rd.to_reg(), ScalarSize::Size32);
1874 let mem = mem.clone();
1875 let access_ty = self.mem_type().unwrap();
1876 let (mem_str, mem) = mem_finalize_for_show(&mem, access_ty, state);
1877 format!("{mem_str}ldr {rd}, {mem}")
1878 }
1879 &Inst::FpuLoad64 { rd, ref mem, .. } => {
1880 let rd = pretty_print_vreg_scalar(rd.to_reg(), ScalarSize::Size64);
1881 let mem = mem.clone();
1882 let access_ty = self.mem_type().unwrap();
1883 let (mem_str, mem) = mem_finalize_for_show(&mem, access_ty, state);
1884 format!("{mem_str}ldr {rd}, {mem}")
1885 }
1886 &Inst::FpuLoad128 { rd, ref mem, .. } => {
1887 let rd = pretty_print_reg(rd.to_reg());
1888 let rd = "q".to_string() + &rd[1..];
1889 let mem = mem.clone();
1890 let access_ty = self.mem_type().unwrap();
1891 let (mem_str, mem) = mem_finalize_for_show(&mem, access_ty, state);
1892 format!("{mem_str}ldr {rd}, {mem}")
1893 }
1894 &Inst::FpuStore16 { rd, ref mem, .. } => {
1895 let rd = pretty_print_vreg_scalar(rd, ScalarSize::Size16);
1896 let mem = mem.clone();
1897 let access_ty = self.mem_type().unwrap();
1898 let (mem_str, mem) = mem_finalize_for_show(&mem, access_ty, state);
1899 format!("{mem_str}str {rd}, {mem}")
1900 }
1901 &Inst::FpuStore32 { rd, ref mem, .. } => {
1902 let rd = pretty_print_vreg_scalar(rd, ScalarSize::Size32);
1903 let mem = mem.clone();
1904 let access_ty = self.mem_type().unwrap();
1905 let (mem_str, mem) = mem_finalize_for_show(&mem, access_ty, state);
1906 format!("{mem_str}str {rd}, {mem}")
1907 }
1908 &Inst::FpuStore64 { rd, ref mem, .. } => {
1909 let rd = pretty_print_vreg_scalar(rd, ScalarSize::Size64);
1910 let mem = mem.clone();
1911 let access_ty = self.mem_type().unwrap();
1912 let (mem_str, mem) = mem_finalize_for_show(&mem, access_ty, state);
1913 format!("{mem_str}str {rd}, {mem}")
1914 }
1915 &Inst::FpuStore128 { rd, ref mem, .. } => {
1916 let rd = pretty_print_reg(rd);
1917 let rd = "q".to_string() + &rd[1..];
1918 let mem = mem.clone();
1919 let access_ty = self.mem_type().unwrap();
1920 let (mem_str, mem) = mem_finalize_for_show(&mem, access_ty, state);
1921 format!("{mem_str}str {rd}, {mem}")
1922 }
1923 &Inst::FpuLoadP64 {
1924 rt, rt2, ref mem, ..
1925 } => {
1926 let rt = pretty_print_vreg_scalar(rt.to_reg(), ScalarSize::Size64);
1927 let rt2 = pretty_print_vreg_scalar(rt2.to_reg(), ScalarSize::Size64);
1928 let mem = mem.clone();
1929 let mem = mem.pretty_print_default();
1930
1931 format!("ldp {rt}, {rt2}, {mem}")
1932 }
1933 &Inst::FpuStoreP64 {
1934 rt, rt2, ref mem, ..
1935 } => {
1936 let rt = pretty_print_vreg_scalar(rt, ScalarSize::Size64);
1937 let rt2 = pretty_print_vreg_scalar(rt2, ScalarSize::Size64);
1938 let mem = mem.clone();
1939 let mem = mem.pretty_print_default();
1940
1941 format!("stp {rt}, {rt2}, {mem}")
1942 }
1943 &Inst::FpuLoadP128 {
1944 rt, rt2, ref mem, ..
1945 } => {
1946 let rt = pretty_print_vreg_scalar(rt.to_reg(), ScalarSize::Size128);
1947 let rt2 = pretty_print_vreg_scalar(rt2.to_reg(), ScalarSize::Size128);
1948 let mem = mem.clone();
1949 let mem = mem.pretty_print_default();
1950
1951 format!("ldp {rt}, {rt2}, {mem}")
1952 }
1953 &Inst::FpuStoreP128 {
1954 rt, rt2, ref mem, ..
1955 } => {
1956 let rt = pretty_print_vreg_scalar(rt, ScalarSize::Size128);
1957 let rt2 = pretty_print_vreg_scalar(rt2, ScalarSize::Size128);
1958 let mem = mem.clone();
1959 let mem = mem.pretty_print_default();
1960
1961 format!("stp {rt}, {rt2}, {mem}")
1962 }
1963 &Inst::FpuToInt { op, rd, rn } => {
1964 let (op, sizesrc, sizedest) = match op {
1965 FpuToIntOp::F32ToI32 => ("fcvtzs", ScalarSize::Size32, OperandSize::Size32),
1966 FpuToIntOp::F32ToU32 => ("fcvtzu", ScalarSize::Size32, OperandSize::Size32),
1967 FpuToIntOp::F32ToI64 => ("fcvtzs", ScalarSize::Size32, OperandSize::Size64),
1968 FpuToIntOp::F32ToU64 => ("fcvtzu", ScalarSize::Size32, OperandSize::Size64),
1969 FpuToIntOp::F64ToI32 => ("fcvtzs", ScalarSize::Size64, OperandSize::Size32),
1970 FpuToIntOp::F64ToU32 => ("fcvtzu", ScalarSize::Size64, OperandSize::Size32),
1971 FpuToIntOp::F64ToI64 => ("fcvtzs", ScalarSize::Size64, OperandSize::Size64),
1972 FpuToIntOp::F64ToU64 => ("fcvtzu", ScalarSize::Size64, OperandSize::Size64),
1973 };
1974 let rd = pretty_print_ireg(rd.to_reg(), sizedest);
1975 let rn = pretty_print_vreg_scalar(rn, sizesrc);
1976 format!("{op} {rd}, {rn}")
1977 }
1978 &Inst::IntToFpu { op, rd, rn } => {
1979 let (op, sizesrc, sizedest) = match op {
1980 IntToFpuOp::I32ToF32 => ("scvtf", OperandSize::Size32, ScalarSize::Size32),
1981 IntToFpuOp::U32ToF32 => ("ucvtf", OperandSize::Size32, ScalarSize::Size32),
1982 IntToFpuOp::I64ToF32 => ("scvtf", OperandSize::Size64, ScalarSize::Size32),
1983 IntToFpuOp::U64ToF32 => ("ucvtf", OperandSize::Size64, ScalarSize::Size32),
1984 IntToFpuOp::I32ToF64 => ("scvtf", OperandSize::Size32, ScalarSize::Size64),
1985 IntToFpuOp::U32ToF64 => ("ucvtf", OperandSize::Size32, ScalarSize::Size64),
1986 IntToFpuOp::I64ToF64 => ("scvtf", OperandSize::Size64, ScalarSize::Size64),
1987 IntToFpuOp::U64ToF64 => ("ucvtf", OperandSize::Size64, ScalarSize::Size64),
1988 };
1989 let rd = pretty_print_vreg_scalar(rd.to_reg(), sizedest);
1990 let rn = pretty_print_ireg(rn, sizesrc);
1991 format!("{op} {rd}, {rn}")
1992 }
1993 &Inst::FpuCSel16 { rd, rn, rm, cond } => {
1994 let rd = pretty_print_vreg_scalar(rd.to_reg(), ScalarSize::Size16);
1995 let rn = pretty_print_vreg_scalar(rn, ScalarSize::Size16);
1996 let rm = pretty_print_vreg_scalar(rm, ScalarSize::Size16);
1997 let cond = cond.pretty_print(0);
1998 format!("fcsel {rd}, {rn}, {rm}, {cond}")
1999 }
2000 &Inst::FpuCSel32 { rd, rn, rm, cond } => {
2001 let rd = pretty_print_vreg_scalar(rd.to_reg(), ScalarSize::Size32);
2002 let rn = pretty_print_vreg_scalar(rn, ScalarSize::Size32);
2003 let rm = pretty_print_vreg_scalar(rm, ScalarSize::Size32);
2004 let cond = cond.pretty_print(0);
2005 format!("fcsel {rd}, {rn}, {rm}, {cond}")
2006 }
2007 &Inst::FpuCSel64 { rd, rn, rm, cond } => {
2008 let rd = pretty_print_vreg_scalar(rd.to_reg(), ScalarSize::Size64);
2009 let rn = pretty_print_vreg_scalar(rn, ScalarSize::Size64);
2010 let rm = pretty_print_vreg_scalar(rm, ScalarSize::Size64);
2011 let cond = cond.pretty_print(0);
2012 format!("fcsel {rd}, {rn}, {rm}, {cond}")
2013 }
2014 &Inst::FpuRound { op, rd, rn } => {
2015 let (inst, size) = match op {
2016 FpuRoundMode::Minus32 => ("frintm", ScalarSize::Size32),
2017 FpuRoundMode::Minus64 => ("frintm", ScalarSize::Size64),
2018 FpuRoundMode::Plus32 => ("frintp", ScalarSize::Size32),
2019 FpuRoundMode::Plus64 => ("frintp", ScalarSize::Size64),
2020 FpuRoundMode::Zero32 => ("frintz", ScalarSize::Size32),
2021 FpuRoundMode::Zero64 => ("frintz", ScalarSize::Size64),
2022 FpuRoundMode::Nearest32 => ("frintn", ScalarSize::Size32),
2023 FpuRoundMode::Nearest64 => ("frintn", ScalarSize::Size64),
2024 };
2025 let rd = pretty_print_vreg_scalar(rd.to_reg(), size);
2026 let rn = pretty_print_vreg_scalar(rn, size);
2027 format!("{inst} {rd}, {rn}")
2028 }
2029 &Inst::MovToFpu { rd, rn, size } => {
2030 let operand_size = size.operand_size();
2031 let rd = pretty_print_vreg_scalar(rd.to_reg(), size);
2032 let rn = pretty_print_ireg(rn, operand_size);
2033 format!("fmov {rd}, {rn}")
2034 }
2035 &Inst::FpuMoveFPImm { rd, imm, size } => {
2036 let imm = imm.pretty_print(0);
2037 let rd = pretty_print_vreg_scalar(rd.to_reg(), size);
2038
2039 format!("fmov {rd}, {imm}")
2040 }
2041 &Inst::MovToVec {
2042 rd,
2043 ri,
2044 rn,
2045 idx,
2046 size,
2047 } => {
2048 let rd = pretty_print_vreg_element(rd.to_reg(), idx as usize, size.lane_size());
2049 let ri = pretty_print_vreg_element(ri, idx as usize, size.lane_size());
2050 let rn = pretty_print_ireg(rn, size.operand_size());
2051 format!("mov {rd}, {ri}, {rn}")
2052 }
2053 &Inst::MovFromVec { rd, rn, idx, size } => {
2054 let op = match size {
2055 ScalarSize::Size8 => "umov",
2056 ScalarSize::Size16 => "umov",
2057 ScalarSize::Size32 => "mov",
2058 ScalarSize::Size64 => "mov",
2059 _ => unimplemented!(),
2060 };
2061 let rd = pretty_print_ireg(rd.to_reg(), size.operand_size());
2062 let rn = pretty_print_vreg_element(rn, idx as usize, size);
2063 format!("{op} {rd}, {rn}")
2064 }
2065 &Inst::MovFromVecSigned {
2066 rd,
2067 rn,
2068 idx,
2069 size,
2070 scalar_size,
2071 } => {
2072 let rd = pretty_print_ireg(rd.to_reg(), scalar_size);
2073 let rn = pretty_print_vreg_element(rn, idx as usize, size.lane_size());
2074 format!("smov {rd}, {rn}")
2075 }
2076 &Inst::VecDup { rd, rn, size } => {
2077 let rd = pretty_print_vreg_vector(rd.to_reg(), size);
2078 let rn = pretty_print_ireg(rn, size.operand_size());
2079 format!("dup {rd}, {rn}")
2080 }
2081 &Inst::VecDupFromFpu { rd, rn, size, lane } => {
2082 let rd = pretty_print_vreg_vector(rd.to_reg(), size);
2083 let rn = pretty_print_vreg_element(rn, lane.into(), size.lane_size());
2084 format!("dup {rd}, {rn}")
2085 }
2086 &Inst::VecDupFPImm { rd, imm, size } => {
2087 let imm = imm.pretty_print(0);
2088 let rd = pretty_print_vreg_vector(rd.to_reg(), size);
2089
2090 format!("fmov {rd}, {imm}")
2091 }
2092 &Inst::VecDupImm {
2093 rd,
2094 imm,
2095 invert,
2096 size,
2097 } => {
2098 let imm = imm.pretty_print(0);
2099 let op = if invert { "mvni" } else { "movi" };
2100 let rd = pretty_print_vreg_vector(rd.to_reg(), size);
2101
2102 format!("{op} {rd}, {imm}")
2103 }
2104 &Inst::VecExtend {
2105 t,
2106 rd,
2107 rn,
2108 high_half,
2109 lane_size,
2110 } => {
2111 let vec64 = VectorSize::from_lane_size(lane_size.narrow(), false);
2112 let vec128 = VectorSize::from_lane_size(lane_size.narrow(), true);
2113 let rd_size = VectorSize::from_lane_size(lane_size, true);
2114 let (op, rn_size) = match (t, high_half) {
2115 (VecExtendOp::Sxtl, false) => ("sxtl", vec64),
2116 (VecExtendOp::Sxtl, true) => ("sxtl2", vec128),
2117 (VecExtendOp::Uxtl, false) => ("uxtl", vec64),
2118 (VecExtendOp::Uxtl, true) => ("uxtl2", vec128),
2119 };
2120 let rd = pretty_print_vreg_vector(rd.to_reg(), rd_size);
2121 let rn = pretty_print_vreg_vector(rn, rn_size);
2122 format!("{op} {rd}, {rn}")
2123 }
2124 &Inst::VecMovElement {
2125 rd,
2126 ri,
2127 rn,
2128 dest_idx,
2129 src_idx,
2130 size,
2131 } => {
2132 let rd =
2133 pretty_print_vreg_element(rd.to_reg(), dest_idx as usize, size.lane_size());
2134 let ri = pretty_print_vreg_element(ri, dest_idx as usize, size.lane_size());
2135 let rn = pretty_print_vreg_element(rn, src_idx as usize, size.lane_size());
2136 format!("mov {rd}, {ri}, {rn}")
2137 }
2138 &Inst::VecRRLong {
2139 op,
2140 rd,
2141 rn,
2142 high_half,
2143 } => {
2144 let (op, rd_size, size, suffix) = match (op, high_half) {
2145 (VecRRLongOp::Fcvtl16, false) => {
2146 ("fcvtl", VectorSize::Size32x4, VectorSize::Size16x4, "")
2147 }
2148 (VecRRLongOp::Fcvtl16, true) => {
2149 ("fcvtl2", VectorSize::Size32x4, VectorSize::Size16x8, "")
2150 }
2151 (VecRRLongOp::Fcvtl32, false) => {
2152 ("fcvtl", VectorSize::Size64x2, VectorSize::Size32x2, "")
2153 }
2154 (VecRRLongOp::Fcvtl32, true) => {
2155 ("fcvtl2", VectorSize::Size64x2, VectorSize::Size32x4, "")
2156 }
2157 (VecRRLongOp::Shll8, false) => {
2158 ("shll", VectorSize::Size16x8, VectorSize::Size8x8, ", #8")
2159 }
2160 (VecRRLongOp::Shll8, true) => {
2161 ("shll2", VectorSize::Size16x8, VectorSize::Size8x16, ", #8")
2162 }
2163 (VecRRLongOp::Shll16, false) => {
2164 ("shll", VectorSize::Size32x4, VectorSize::Size16x4, ", #16")
2165 }
2166 (VecRRLongOp::Shll16, true) => {
2167 ("shll2", VectorSize::Size32x4, VectorSize::Size16x8, ", #16")
2168 }
2169 (VecRRLongOp::Shll32, false) => {
2170 ("shll", VectorSize::Size64x2, VectorSize::Size32x2, ", #32")
2171 }
2172 (VecRRLongOp::Shll32, true) => {
2173 ("shll2", VectorSize::Size64x2, VectorSize::Size32x4, ", #32")
2174 }
2175 };
2176 let rd = pretty_print_vreg_vector(rd.to_reg(), rd_size);
2177 let rn = pretty_print_vreg_vector(rn, size);
2178
2179 format!("{op} {rd}, {rn}{suffix}")
2180 }
2181 &Inst::VecRRNarrowLow {
2182 op,
2183 rd,
2184 rn,
2185 lane_size,
2186 ..
2187 }
2188 | &Inst::VecRRNarrowHigh {
2189 op,
2190 rd,
2191 rn,
2192 lane_size,
2193 ..
2194 } => {
2195 let vec64 = VectorSize::from_lane_size(lane_size, false);
2196 let vec128 = VectorSize::from_lane_size(lane_size, true);
2197 let rn_size = VectorSize::from_lane_size(lane_size.widen(), true);
2198 let high_half = match self {
2199 &Inst::VecRRNarrowLow { .. } => false,
2200 &Inst::VecRRNarrowHigh { .. } => true,
2201 _ => unreachable!(),
2202 };
2203 let (op, rd_size) = match (op, high_half) {
2204 (VecRRNarrowOp::Xtn, false) => ("xtn", vec64),
2205 (VecRRNarrowOp::Xtn, true) => ("xtn2", vec128),
2206 (VecRRNarrowOp::Sqxtn, false) => ("sqxtn", vec64),
2207 (VecRRNarrowOp::Sqxtn, true) => ("sqxtn2", vec128),
2208 (VecRRNarrowOp::Sqxtun, false) => ("sqxtun", vec64),
2209 (VecRRNarrowOp::Sqxtun, true) => ("sqxtun2", vec128),
2210 (VecRRNarrowOp::Uqxtn, false) => ("uqxtn", vec64),
2211 (VecRRNarrowOp::Uqxtn, true) => ("uqxtn2", vec128),
2212 (VecRRNarrowOp::Fcvtn, false) => ("fcvtn", vec64),
2213 (VecRRNarrowOp::Fcvtn, true) => ("fcvtn2", vec128),
2214 };
2215 let rn = pretty_print_vreg_vector(rn, rn_size);
2216 let rd = pretty_print_vreg_vector(rd.to_reg(), rd_size);
2217 let ri = match self {
2218 &Inst::VecRRNarrowLow { .. } => "".to_string(),
2219 &Inst::VecRRNarrowHigh { ri, .. } => {
2220 format!("{}, ", pretty_print_vreg_vector(ri, rd_size))
2221 }
2222 _ => unreachable!(),
2223 };
2224
2225 format!("{op} {rd}, {ri}{rn}")
2226 }
2227 &Inst::VecRRPair { op, rd, rn } => {
2228 let op = match op {
2229 VecPairOp::Addp => "addp",
2230 };
2231 let rd = pretty_print_vreg_scalar(rd.to_reg(), ScalarSize::Size64);
2232 let rn = pretty_print_vreg_vector(rn, VectorSize::Size64x2);
2233
2234 format!("{op} {rd}, {rn}")
2235 }
2236 &Inst::VecRRPairLong { op, rd, rn } => {
2237 let (op, dest, src) = match op {
2238 VecRRPairLongOp::Saddlp8 => {
2239 ("saddlp", VectorSize::Size16x8, VectorSize::Size8x16)
2240 }
2241 VecRRPairLongOp::Saddlp16 => {
2242 ("saddlp", VectorSize::Size32x4, VectorSize::Size16x8)
2243 }
2244 VecRRPairLongOp::Uaddlp8 => {
2245 ("uaddlp", VectorSize::Size16x8, VectorSize::Size8x16)
2246 }
2247 VecRRPairLongOp::Uaddlp16 => {
2248 ("uaddlp", VectorSize::Size32x4, VectorSize::Size16x8)
2249 }
2250 };
2251 let rd = pretty_print_vreg_vector(rd.to_reg(), dest);
2252 let rn = pretty_print_vreg_vector(rn, src);
2253
2254 format!("{op} {rd}, {rn}")
2255 }
2256 &Inst::VecRRR {
2257 rd,
2258 rn,
2259 rm,
2260 alu_op,
2261 size,
2262 } => {
2263 let (op, size) = match alu_op {
2264 VecALUOp::Sqadd => ("sqadd", size),
2265 VecALUOp::Uqadd => ("uqadd", size),
2266 VecALUOp::Sqsub => ("sqsub", size),
2267 VecALUOp::Uqsub => ("uqsub", size),
2268 VecALUOp::Cmeq => ("cmeq", size),
2269 VecALUOp::Cmge => ("cmge", size),
2270 VecALUOp::Cmgt => ("cmgt", size),
2271 VecALUOp::Cmhs => ("cmhs", size),
2272 VecALUOp::Cmhi => ("cmhi", size),
2273 VecALUOp::Fcmeq => ("fcmeq", size),
2274 VecALUOp::Fcmgt => ("fcmgt", size),
2275 VecALUOp::Fcmge => ("fcmge", size),
2276 VecALUOp::Umaxp => ("umaxp", size),
2277 VecALUOp::Add => ("add", size),
2278 VecALUOp::Sub => ("sub", size),
2279 VecALUOp::Mul => ("mul", size),
2280 VecALUOp::Sshl => ("sshl", size),
2281 VecALUOp::Ushl => ("ushl", size),
2282 VecALUOp::Umin => ("umin", size),
2283 VecALUOp::Smin => ("smin", size),
2284 VecALUOp::Umax => ("umax", size),
2285 VecALUOp::Smax => ("smax", size),
2286 VecALUOp::Urhadd => ("urhadd", size),
2287 VecALUOp::Fadd => ("fadd", size),
2288 VecALUOp::Fsub => ("fsub", size),
2289 VecALUOp::Fdiv => ("fdiv", size),
2290 VecALUOp::Fmax => ("fmax", size),
2291 VecALUOp::Fmin => ("fmin", size),
2292 VecALUOp::Fmul => ("fmul", size),
2293 VecALUOp::Addp => ("addp", size),
2294 VecALUOp::Zip1 => ("zip1", size),
2295 VecALUOp::Zip2 => ("zip2", size),
2296 VecALUOp::Sqrdmulh => ("sqrdmulh", size),
2297 VecALUOp::Uzp1 => ("uzp1", size),
2298 VecALUOp::Uzp2 => ("uzp2", size),
2299 VecALUOp::Trn1 => ("trn1", size),
2300 VecALUOp::Trn2 => ("trn2", size),
2301
2302 VecALUOp::And => ("and", size.as_scalar8_vector()),
2305 VecALUOp::Bic => ("bic", size.as_scalar8_vector()),
2306 VecALUOp::Orr => ("orr", size.as_scalar8_vector()),
2307 VecALUOp::Orn => ("orn", size.as_scalar8_vector()),
2308 VecALUOp::Eor => ("eor", size.as_scalar8_vector()),
2309 };
2310 let rd = pretty_print_vreg_vector(rd.to_reg(), size);
2311 let rn = pretty_print_vreg_vector(rn, size);
2312 let rm = pretty_print_vreg_vector(rm, size);
2313 format!("{op} {rd}, {rn}, {rm}")
2314 }
2315 &Inst::VecRRRMod {
2316 rd,
2317 ri,
2318 rn,
2319 rm,
2320 alu_op,
2321 size,
2322 } => {
2323 let (op, size) = match alu_op {
2324 VecALUModOp::Bsl => ("bsl", VectorSize::Size8x16),
2325 VecALUModOp::Fmla => ("fmla", size),
2326 VecALUModOp::Fmls => ("fmls", size),
2327 VecALUModOp::Sdot => ("sdot", VectorSize::Size32x4),
2330 VecALUModOp::Usdot => ("usdot", VectorSize::Size32x4),
2331 };
2332 let rd = pretty_print_vreg_vector(rd.to_reg(), size);
2333 let ri = pretty_print_vreg_vector(ri, size);
2334 let rn = pretty_print_vreg_vector(rn, size);
2335 let rm = pretty_print_vreg_vector(rm, size);
2336 format!("{op} {rd}, {ri}, {rn}, {rm}")
2337 }
2338 &Inst::VecFmlaElem {
2339 rd,
2340 ri,
2341 rn,
2342 rm,
2343 alu_op,
2344 size,
2345 idx,
2346 } => {
2347 let (op, size) = match alu_op {
2348 VecALUModOp::Fmla => ("fmla", size),
2349 VecALUModOp::Fmls => ("fmls", size),
2350 _ => unreachable!(),
2351 };
2352 let rd = pretty_print_vreg_vector(rd.to_reg(), size);
2353 let ri = pretty_print_vreg_vector(ri, size);
2354 let rn = pretty_print_vreg_vector(rn, size);
2355 let rm = pretty_print_vreg_element(rm, idx.into(), size.lane_size());
2356 format!("{op} {rd}, {ri}, {rn}, {rm}")
2357 }
2358 &Inst::VecRRRLong {
2359 rd,
2360 rn,
2361 rm,
2362 alu_op,
2363 high_half,
2364 } => {
2365 let (op, dest_size, src_size) = match (alu_op, high_half) {
2366 (VecRRRLongOp::Smull8, false) => {
2367 ("smull", VectorSize::Size16x8, VectorSize::Size8x8)
2368 }
2369 (VecRRRLongOp::Smull8, true) => {
2370 ("smull2", VectorSize::Size16x8, VectorSize::Size8x16)
2371 }
2372 (VecRRRLongOp::Smull16, false) => {
2373 ("smull", VectorSize::Size32x4, VectorSize::Size16x4)
2374 }
2375 (VecRRRLongOp::Smull16, true) => {
2376 ("smull2", VectorSize::Size32x4, VectorSize::Size16x8)
2377 }
2378 (VecRRRLongOp::Smull32, false) => {
2379 ("smull", VectorSize::Size64x2, VectorSize::Size32x2)
2380 }
2381 (VecRRRLongOp::Smull32, true) => {
2382 ("smull2", VectorSize::Size64x2, VectorSize::Size32x4)
2383 }
2384 (VecRRRLongOp::Umull8, false) => {
2385 ("umull", VectorSize::Size16x8, VectorSize::Size8x8)
2386 }
2387 (VecRRRLongOp::Umull8, true) => {
2388 ("umull2", VectorSize::Size16x8, VectorSize::Size8x16)
2389 }
2390 (VecRRRLongOp::Umull16, false) => {
2391 ("umull", VectorSize::Size32x4, VectorSize::Size16x4)
2392 }
2393 (VecRRRLongOp::Umull16, true) => {
2394 ("umull2", VectorSize::Size32x4, VectorSize::Size16x8)
2395 }
2396 (VecRRRLongOp::Umull32, false) => {
2397 ("umull", VectorSize::Size64x2, VectorSize::Size32x2)
2398 }
2399 (VecRRRLongOp::Umull32, true) => {
2400 ("umull2", VectorSize::Size64x2, VectorSize::Size32x4)
2401 }
2402 };
2403 let rd = pretty_print_vreg_vector(rd.to_reg(), dest_size);
2404 let rn = pretty_print_vreg_vector(rn, src_size);
2405 let rm = pretty_print_vreg_vector(rm, src_size);
2406 format!("{op} {rd}, {rn}, {rm}")
2407 }
2408 &Inst::VecRRRLongMod {
2409 rd,
2410 ri,
2411 rn,
2412 rm,
2413 alu_op,
2414 high_half,
2415 } => {
2416 let (op, dest_size, src_size) = match (alu_op, high_half) {
2417 (VecRRRLongModOp::Umlal8, false) => {
2418 ("umlal", VectorSize::Size16x8, VectorSize::Size8x8)
2419 }
2420 (VecRRRLongModOp::Umlal8, true) => {
2421 ("umlal2", VectorSize::Size16x8, VectorSize::Size8x16)
2422 }
2423 (VecRRRLongModOp::Umlal16, false) => {
2424 ("umlal", VectorSize::Size32x4, VectorSize::Size16x4)
2425 }
2426 (VecRRRLongModOp::Umlal16, true) => {
2427 ("umlal2", VectorSize::Size32x4, VectorSize::Size16x8)
2428 }
2429 (VecRRRLongModOp::Umlal32, false) => {
2430 ("umlal", VectorSize::Size64x2, VectorSize::Size32x2)
2431 }
2432 (VecRRRLongModOp::Umlal32, true) => {
2433 ("umlal2", VectorSize::Size64x2, VectorSize::Size32x4)
2434 }
2435 };
2436 let rd = pretty_print_vreg_vector(rd.to_reg(), dest_size);
2437 let ri = pretty_print_vreg_vector(ri, dest_size);
2438 let rn = pretty_print_vreg_vector(rn, src_size);
2439 let rm = pretty_print_vreg_vector(rm, src_size);
2440 format!("{op} {rd}, {ri}, {rn}, {rm}")
2441 }
2442 &Inst::VecMisc { op, rd, rn, size } => {
2443 let (op, size, suffix) = match op {
2444 VecMisc2::Neg => ("neg", size, ""),
2445 VecMisc2::Abs => ("abs", size, ""),
2446 VecMisc2::Fabs => ("fabs", size, ""),
2447 VecMisc2::Fneg => ("fneg", size, ""),
2448 VecMisc2::Fsqrt => ("fsqrt", size, ""),
2449 VecMisc2::Rev16 => ("rev16", size, ""),
2450 VecMisc2::Rev32 => ("rev32", size, ""),
2451 VecMisc2::Rev64 => ("rev64", size, ""),
2452 VecMisc2::Fcvtzs => ("fcvtzs", size, ""),
2453 VecMisc2::Fcvtzu => ("fcvtzu", size, ""),
2454 VecMisc2::Scvtf => ("scvtf", size, ""),
2455 VecMisc2::Ucvtf => ("ucvtf", size, ""),
2456 VecMisc2::Frintn => ("frintn", size, ""),
2457 VecMisc2::Frintz => ("frintz", size, ""),
2458 VecMisc2::Frintm => ("frintm", size, ""),
2459 VecMisc2::Frintp => ("frintp", size, ""),
2460 VecMisc2::Cnt => ("cnt", size, ""),
2461 VecMisc2::Cmeq0 => ("cmeq", size, ", #0"),
2462 VecMisc2::Cmge0 => ("cmge", size, ", #0"),
2463 VecMisc2::Cmgt0 => ("cmgt", size, ", #0"),
2464 VecMisc2::Cmle0 => ("cmle", size, ", #0"),
2465 VecMisc2::Cmlt0 => ("cmlt", size, ", #0"),
2466 VecMisc2::Fcmeq0 => ("fcmeq", size, ", #0.0"),
2467 VecMisc2::Fcmge0 => ("fcmge", size, ", #0.0"),
2468 VecMisc2::Fcmgt0 => ("fcmgt", size, ", #0.0"),
2469 VecMisc2::Fcmle0 => ("fcmle", size, ", #0.0"),
2470 VecMisc2::Fcmlt0 => ("fcmlt", size, ", #0.0"),
2471
2472 VecMisc2::Not => ("mvn", size.as_scalar8_vector(), ""),
2475 };
2476 let rd = pretty_print_vreg_vector(rd.to_reg(), size);
2477 let rn = pretty_print_vreg_vector(rn, size);
2478 format!("{op} {rd}, {rn}{suffix}")
2479 }
2480 &Inst::VecLanes { op, rd, rn, size } => {
2481 let op = match op {
2482 VecLanesOp::Uminv => "uminv",
2483 VecLanesOp::Addv => "addv",
2484 };
2485 let rd = pretty_print_vreg_scalar(rd.to_reg(), size.lane_size());
2486 let rn = pretty_print_vreg_vector(rn, size);
2487 format!("{op} {rd}, {rn}")
2488 }
2489 &Inst::VecShiftImm {
2490 op,
2491 rd,
2492 rn,
2493 size,
2494 imm,
2495 } => {
2496 let op = match op {
2497 VecShiftImmOp::Shl => "shl",
2498 VecShiftImmOp::Ushr => "ushr",
2499 VecShiftImmOp::Sshr => "sshr",
2500 };
2501 let rd = pretty_print_vreg_vector(rd.to_reg(), size);
2502 let rn = pretty_print_vreg_vector(rn, size);
2503 format!("{op} {rd}, {rn}, #{imm}")
2504 }
2505 &Inst::VecShiftImmMod {
2506 op,
2507 rd,
2508 ri,
2509 rn,
2510 size,
2511 imm,
2512 } => {
2513 let op = match op {
2514 VecShiftImmModOp::Sli => "sli",
2515 };
2516 let rd = pretty_print_vreg_vector(rd.to_reg(), size);
2517 let ri = pretty_print_vreg_vector(ri, size);
2518 let rn = pretty_print_vreg_vector(rn, size);
2519 format!("{op} {rd}, {ri}, {rn}, #{imm}")
2520 }
2521 &Inst::VecExtract { rd, rn, rm, imm4 } => {
2522 let rd = pretty_print_vreg_vector(rd.to_reg(), VectorSize::Size8x16);
2523 let rn = pretty_print_vreg_vector(rn, VectorSize::Size8x16);
2524 let rm = pretty_print_vreg_vector(rm, VectorSize::Size8x16);
2525 format!("ext {rd}, {rn}, {rm}, #{imm4}")
2526 }
2527 &Inst::VecTbl { rd, rn, rm } => {
2528 let rn = pretty_print_vreg_vector(rn, VectorSize::Size8x16);
2529 let rm = pretty_print_vreg_vector(rm, VectorSize::Size8x16);
2530 let rd = pretty_print_vreg_vector(rd.to_reg(), VectorSize::Size8x16);
2531 format!("tbl {rd}, {{ {rn} }}, {rm}")
2532 }
2533 &Inst::VecTblExt { rd, ri, rn, rm } => {
2534 let rn = pretty_print_vreg_vector(rn, VectorSize::Size8x16);
2535 let rm = pretty_print_vreg_vector(rm, VectorSize::Size8x16);
2536 let rd = pretty_print_vreg_vector(rd.to_reg(), VectorSize::Size8x16);
2537 let ri = pretty_print_vreg_vector(ri, VectorSize::Size8x16);
2538 format!("tbx {rd}, {ri}, {{ {rn} }}, {rm}")
2539 }
2540 &Inst::VecTbl2 { rd, rn, rn2, rm } => {
2541 let rn = pretty_print_vreg_vector(rn, VectorSize::Size8x16);
2542 let rn2 = pretty_print_vreg_vector(rn2, VectorSize::Size8x16);
2543 let rm = pretty_print_vreg_vector(rm, VectorSize::Size8x16);
2544 let rd = pretty_print_vreg_vector(rd.to_reg(), VectorSize::Size8x16);
2545 format!("tbl {rd}, {{ {rn}, {rn2} }}, {rm}")
2546 }
2547 &Inst::VecTbl2Ext {
2548 rd,
2549 ri,
2550 rn,
2551 rn2,
2552 rm,
2553 } => {
2554 let rn = pretty_print_vreg_vector(rn, VectorSize::Size8x16);
2555 let rn2 = pretty_print_vreg_vector(rn2, VectorSize::Size8x16);
2556 let rm = pretty_print_vreg_vector(rm, VectorSize::Size8x16);
2557 let rd = pretty_print_vreg_vector(rd.to_reg(), VectorSize::Size8x16);
2558 let ri = pretty_print_vreg_vector(ri, VectorSize::Size8x16);
2559 format!("tbx {rd}, {ri}, {{ {rn}, {rn2} }}, {rm}")
2560 }
2561 &Inst::VecLoadReplicate { rd, rn, size, .. } => {
2562 let rd = pretty_print_vreg_vector(rd.to_reg(), size);
2563 let rn = pretty_print_reg(rn);
2564
2565 format!("ld1r {{ {rd} }}, [{rn}]")
2566 }
2567 &Inst::VecCSel { rd, rn, rm, cond } => {
2568 let rd = pretty_print_vreg_vector(rd.to_reg(), VectorSize::Size8x16);
2569 let rn = pretty_print_vreg_vector(rn, VectorSize::Size8x16);
2570 let rm = pretty_print_vreg_vector(rm, VectorSize::Size8x16);
2571 let cond = cond.pretty_print(0);
2572 format!("vcsel {rd}, {rn}, {rm}, {cond} (if-then-else diamond)")
2573 }
2574 &Inst::MovToNZCV { rn } => {
2575 let rn = pretty_print_reg(rn);
2576 format!("msr nzcv, {rn}")
2577 }
2578 &Inst::MovFromNZCV { rd } => {
2579 let rd = pretty_print_reg(rd.to_reg());
2580 format!("mrs {rd}, nzcv")
2581 }
2582 &Inst::Extend {
2583 rd,
2584 rn,
2585 signed: false,
2586 from_bits: 1,
2587 ..
2588 } => {
2589 let rd = pretty_print_ireg(rd.to_reg(), OperandSize::Size32);
2590 let rn = pretty_print_ireg(rn, OperandSize::Size32);
2591 format!("and {rd}, {rn}, #1")
2592 }
2593 &Inst::Extend {
2594 rd,
2595 rn,
2596 signed: false,
2597 from_bits: 32,
2598 to_bits: 64,
2599 } => {
2600 let rd = pretty_print_ireg(rd.to_reg(), OperandSize::Size32);
2604 let rn = pretty_print_ireg(rn, OperandSize::Size32);
2605 format!("mov {rd}, {rn}")
2606 }
2607 &Inst::Extend {
2608 rd,
2609 rn,
2610 signed,
2611 from_bits,
2612 to_bits,
2613 } => {
2614 assert!(from_bits <= to_bits);
2615 let op = match (signed, from_bits) {
2616 (false, 8) => "uxtb",
2617 (true, 8) => "sxtb",
2618 (false, 16) => "uxth",
2619 (true, 16) => "sxth",
2620 (true, 32) => "sxtw",
2621 (true, _) => "sbfx",
2622 (false, _) => "ubfx",
2623 };
2624 if op == "sbfx" || op == "ubfx" {
2625 let dest_size = OperandSize::from_bits(to_bits);
2626 let rd = pretty_print_ireg(rd.to_reg(), dest_size);
2627 let rn = pretty_print_ireg(rn, dest_size);
2628 format!("{op} {rd}, {rn}, #0, #{from_bits}")
2629 } else {
2630 let dest_size = if signed {
2631 OperandSize::from_bits(to_bits)
2632 } else {
2633 OperandSize::Size32
2634 };
2635 let rd = pretty_print_ireg(rd.to_reg(), dest_size);
2636 let rn = pretty_print_ireg(rn, OperandSize::from_bits(from_bits));
2637 format!("{op} {rd}, {rn}")
2638 }
2639 }
2640 &Inst::Call { ref info } => {
2641 let try_call = info
2642 .try_call_info
2643 .as_ref()
2644 .map(|tci| pretty_print_try_call(tci))
2645 .unwrap_or_default();
2646 format!("bl 0{try_call}")
2647 }
2648 &Inst::CallInd { ref info } => {
2649 let rn = pretty_print_reg(info.dest);
2650 let try_call = info
2651 .try_call_info
2652 .as_ref()
2653 .map(|tci| pretty_print_try_call(tci))
2654 .unwrap_or_default();
2655 format!("blr {rn}{try_call}")
2656 }
2657 &Inst::ReturnCall { ref info } => {
2658 let mut s = format!(
2659 "return_call {:?} new_stack_arg_size:{}",
2660 info.dest, info.new_stack_arg_size
2661 );
2662 for ret in &info.uses {
2663 let preg = pretty_print_reg(ret.preg);
2664 let vreg = pretty_print_reg(ret.vreg);
2665 write!(&mut s, " {vreg}={preg}").unwrap();
2666 }
2667 s
2668 }
2669 &Inst::ReturnCallInd { ref info } => {
2670 let callee = pretty_print_reg(info.dest);
2671 let mut s = format!(
2672 "return_call_ind {callee} new_stack_arg_size:{}",
2673 info.new_stack_arg_size
2674 );
2675 for ret in &info.uses {
2676 let preg = pretty_print_reg(ret.preg);
2677 let vreg = pretty_print_reg(ret.vreg);
2678 write!(&mut s, " {vreg}={preg}").unwrap();
2679 }
2680 s
2681 }
2682 &Inst::Args { ref args } => {
2683 let mut s = "args".to_string();
2684 for arg in args {
2685 let preg = pretty_print_reg(arg.preg);
2686 let def = pretty_print_reg(arg.vreg.to_reg());
2687 write!(&mut s, " {def}={preg}").unwrap();
2688 }
2689 s
2690 }
2691 &Inst::Rets { ref rets } => {
2692 let mut s = "rets".to_string();
2693 for ret in rets {
2694 let preg = pretty_print_reg(ret.preg);
2695 let vreg = pretty_print_reg(ret.vreg);
2696 write!(&mut s, " {vreg}={preg}").unwrap();
2697 }
2698 s
2699 }
2700 &Inst::Ret {} => "ret".to_string(),
2701 &Inst::AuthenticatedRet { key, is_hint } => {
2702 let key = match key {
2703 APIKey::AZ => "az",
2704 APIKey::BZ => "bz",
2705 APIKey::ASP => "asp",
2706 APIKey::BSP => "bsp",
2707 };
2708 match is_hint {
2709 false => format!("reta{key}"),
2710 true => format!("auti{key} ; ret"),
2711 }
2712 }
2713 &Inst::Jump { ref dest } => {
2714 let dest = dest.pretty_print(0);
2715 format!("b {dest}")
2716 }
2717 &Inst::CondBr {
2718 ref taken,
2719 ref not_taken,
2720 ref kind,
2721 } => {
2722 let taken = taken.pretty_print(0);
2723 let not_taken = not_taken.pretty_print(0);
2724 match kind {
2725 &CondBrKind::Zero(reg, size) => {
2726 let reg = pretty_print_reg_sized(reg, size);
2727 format!("cbz {reg}, {taken} ; b {not_taken}")
2728 }
2729 &CondBrKind::NotZero(reg, size) => {
2730 let reg = pretty_print_reg_sized(reg, size);
2731 format!("cbnz {reg}, {taken} ; b {not_taken}")
2732 }
2733 &CondBrKind::Cond(c) => {
2734 let c = c.pretty_print(0);
2735 format!("b.{c} {taken} ; b {not_taken}")
2736 }
2737 }
2738 }
2739 &Inst::TestBitAndBranch {
2740 kind,
2741 ref taken,
2742 ref not_taken,
2743 rn,
2744 bit,
2745 } => {
2746 let cond = match kind {
2747 TestBitAndBranchKind::Z => "z",
2748 TestBitAndBranchKind::NZ => "nz",
2749 };
2750 let taken = taken.pretty_print(0);
2751 let not_taken = not_taken.pretty_print(0);
2752 let rn = pretty_print_reg(rn);
2753 format!("tb{cond} {rn}, #{bit}, {taken} ; b {not_taken}")
2754 }
2755 &Inst::IndirectBr { rn, .. } => {
2756 let rn = pretty_print_reg(rn);
2757 format!("br {rn}")
2758 }
2759 &Inst::Brk => "brk #0xf000".to_string(),
2760 &Inst::Udf { .. } => "udf #0xc11f".to_string(),
2761 &Inst::TrapIf {
2762 ref kind,
2763 trap_code,
2764 } => match kind {
2765 &CondBrKind::Zero(reg, size) => {
2766 let reg = pretty_print_reg_sized(reg, size);
2767 format!("cbz {reg}, #trap={trap_code}")
2768 }
2769 &CondBrKind::NotZero(reg, size) => {
2770 let reg = pretty_print_reg_sized(reg, size);
2771 format!("cbnz {reg}, #trap={trap_code}")
2772 }
2773 &CondBrKind::Cond(c) => {
2774 let c = c.pretty_print(0);
2775 format!("b.{c} #trap={trap_code}")
2776 }
2777 },
2778 &Inst::Adr { rd, off } => {
2779 let rd = pretty_print_reg(rd.to_reg());
2780 format!("adr {rd}, pc+{off}")
2781 }
2782 &Inst::Adrp { rd, off } => {
2783 let rd = pretty_print_reg(rd.to_reg());
2784 let byte_offset = off * 4096;
2786 format!("adrp {rd}, pc+{byte_offset}")
2787 }
2788 &Inst::Word4 { data } => format!("data.i32 {data}"),
2789 &Inst::Word8 { data } => format!("data.i64 {data}"),
2790 &Inst::JTSequence {
2791 default,
2792 ref targets,
2793 ridx,
2794 rtmp1,
2795 rtmp2,
2796 ..
2797 } => {
2798 let ridx = pretty_print_reg(ridx);
2799 let rtmp1 = pretty_print_reg(rtmp1.to_reg());
2800 let rtmp2 = pretty_print_reg(rtmp2.to_reg());
2801 let default_target = BranchTarget::Label(default).pretty_print(0);
2802 format!(
2803 concat!(
2804 "b.hs {} ; ",
2805 "csel {}, xzr, {}, hs ; ",
2806 "csdb ; ",
2807 "adr {}, pc+16 ; ",
2808 "ldrsw {}, [{}, {}, uxtw #2] ; ",
2809 "add {}, {}, {} ; ",
2810 "br {} ; ",
2811 "jt_entries {:?}"
2812 ),
2813 default_target,
2814 rtmp2,
2815 ridx,
2816 rtmp1,
2817 rtmp2,
2818 rtmp1,
2819 rtmp2,
2820 rtmp1,
2821 rtmp1,
2822 rtmp2,
2823 rtmp1,
2824 targets
2825 )
2826 }
2827 &Inst::LoadExtNameGot { rd, ref name } => {
2828 let rd = pretty_print_reg(rd.to_reg());
2829 format!("load_ext_name_got {rd}, {name:?}")
2830 }
2831 &Inst::LoadExtNameNear {
2832 rd,
2833 ref name,
2834 offset,
2835 } => {
2836 let rd = pretty_print_reg(rd.to_reg());
2837 format!("load_ext_name_near {rd}, {name:?}+{offset}")
2838 }
2839 &Inst::LoadExtNameFar {
2840 rd,
2841 ref name,
2842 offset,
2843 } => {
2844 let rd = pretty_print_reg(rd.to_reg());
2845 format!("load_ext_name_far {rd}, {name:?}+{offset}")
2846 }
2847 &Inst::LoadAddr { rd, ref mem } => {
2848 let mem = mem.clone();
2853 let (mem_insts, mem) = mem_finalize(None, &mem, I8, state);
2854 let mut ret = String::new();
2855 for inst in mem_insts.into_iter() {
2856 ret.push_str(&inst.print_with_state(&mut EmitState::default()));
2857 }
2858 let (reg, index_reg, offset) = match mem {
2859 AMode::RegExtended { rn, rm, extendop } => (rn, Some((rm, extendop)), 0),
2860 AMode::Unscaled { rn, simm9 } => (rn, None, simm9.value()),
2861 AMode::UnsignedOffset { rn, uimm12 } => (rn, None, uimm12.value() as i32),
2862 _ => panic!("Unsupported case for LoadAddr: {mem:?}"),
2863 };
2864 let abs_offset = if offset < 0 {
2865 -offset as u64
2866 } else {
2867 offset as u64
2868 };
2869 let alu_op = if offset < 0 { ALUOp::Sub } else { ALUOp::Add };
2870
2871 if let Some((idx, extendop)) = index_reg {
2872 let add = Inst::AluRRRExtend {
2873 alu_op: ALUOp::Add,
2874 size: OperandSize::Size64,
2875 rd,
2876 rn: reg,
2877 rm: idx,
2878 extendop,
2879 };
2880
2881 ret.push_str(&add.print_with_state(&mut EmitState::default()));
2882 } else if offset == 0 {
2883 let mov = Inst::gen_move(rd, reg, I64);
2884 ret.push_str(&mov.print_with_state(&mut EmitState::default()));
2885 } else if let Some(imm12) = Imm12::maybe_from_u64(abs_offset) {
2886 let add = Inst::AluRRImm12 {
2887 alu_op,
2888 size: OperandSize::Size64,
2889 rd,
2890 rn: reg,
2891 imm12,
2892 };
2893 ret.push_str(&add.print_with_state(&mut EmitState::default()));
2894 } else {
2895 let tmp = writable_spilltmp_reg();
2896 for inst in Inst::load_constant(tmp, abs_offset).into_iter() {
2897 ret.push_str(&inst.print_with_state(&mut EmitState::default()));
2898 }
2899 let add = Inst::AluRRR {
2900 alu_op,
2901 size: OperandSize::Size64,
2902 rd,
2903 rn: reg,
2904 rm: tmp.to_reg(),
2905 };
2906 ret.push_str(&add.print_with_state(&mut EmitState::default()));
2907 }
2908 ret
2909 }
2910 &Inst::Paci { key } => {
2911 let key = match key {
2912 APIKey::AZ => "az",
2913 APIKey::BZ => "bz",
2914 APIKey::ASP => "asp",
2915 APIKey::BSP => "bsp",
2916 };
2917
2918 "paci".to_string() + key
2919 }
2920 &Inst::Xpaclri => "xpaclri".to_string(),
2921 &Inst::Bti { targets } => {
2922 let targets = match targets {
2923 BranchTargetType::None => "",
2924 BranchTargetType::C => " c",
2925 BranchTargetType::J => " j",
2926 BranchTargetType::JC => " jc",
2927 };
2928
2929 "bti".to_string() + targets
2930 }
2931 &Inst::EmitIsland { needed_space } => format!("emit_island {needed_space}"),
2932
2933 &Inst::ElfTlsGetAddr {
2934 ref symbol,
2935 rd,
2936 tmp,
2937 } => {
2938 let rd = pretty_print_reg(rd.to_reg());
2939 let tmp = pretty_print_reg(tmp.to_reg());
2940 format!("elf_tls_get_addr {}, {}, {}", rd, tmp, symbol.display(None))
2941 }
2942 &Inst::MachOTlsGetAddr { ref symbol, rd } => {
2943 let rd = pretty_print_reg(rd.to_reg());
2944 format!("macho_tls_get_addr {}, {}", rd, symbol.display(None))
2945 }
2946 &Inst::Unwind { ref inst } => {
2947 format!("unwind {inst:?}")
2948 }
2949 &Inst::DummyUse { reg } => {
2950 let reg = pretty_print_reg(reg);
2951 format!("dummy_use {reg}")
2952 }
2953 &Inst::LabelAddress { dst, label } => {
2954 let dst = pretty_print_reg(dst.to_reg());
2955 format!("label_address {dst}, {label:?}")
2956 }
2957 &Inst::SequencePoint {} => {
2958 format!("sequence_point")
2959 }
2960 &Inst::StackProbeLoop { start, end, step } => {
2961 let start = pretty_print_reg(start.to_reg());
2962 let end = pretty_print_reg(end);
2963 let step = step.pretty_print(0);
2964 format!("stack_probe_loop {start}, {end}, {step}")
2965 }
2966 }
2967 }
2968}
2969
2970#[derive(Clone, Copy, Debug, PartialEq, Eq)]
2975pub enum LabelUse {
2976 Branch14,
2979 Branch19,
2982 Branch26,
2985 Ldr19,
2988 Adr21,
2991 PCRel32,
2994}
2995
2996impl MachInstLabelUse for LabelUse {
2997 const ALIGN: CodeOffset = 4;
2999
3000 fn max_pos_range(self) -> CodeOffset {
3002 match self {
3003 LabelUse::Branch14 => (1 << 15) - 1,
3007 LabelUse::Branch19 => (1 << 20) - 1,
3008 LabelUse::Branch26 => (1 << 27) - 1,
3009 LabelUse::Ldr19 => (1 << 20) - 1,
3010 LabelUse::Adr21 => (1 << 20) - 1,
3013 LabelUse::PCRel32 => 0x7fffffff,
3014 }
3015 }
3016
3017 fn max_neg_range(self) -> CodeOffset {
3019 self.max_pos_range() + 1
3022 }
3023
3024 fn patch_size(self) -> CodeOffset {
3026 4
3028 }
3029
3030 fn patch(self, buffer: &mut [u8], use_offset: CodeOffset, label_offset: CodeOffset) {
3032 let pc_rel = (label_offset as i64) - (use_offset as i64);
3033 debug_assert!(pc_rel <= self.max_pos_range() as i64);
3034 debug_assert!(pc_rel >= -(self.max_neg_range() as i64));
3035 let pc_rel = pc_rel as u32;
3036 let insn_word = u32::from_le_bytes([buffer[0], buffer[1], buffer[2], buffer[3]]);
3037 let mask = match self {
3038 LabelUse::Branch14 => 0x0007ffe0, LabelUse::Branch19 => 0x00ffffe0, LabelUse::Branch26 => 0x03ffffff, LabelUse::Ldr19 => 0x00ffffe0, LabelUse::Adr21 => 0x60ffffe0, LabelUse::PCRel32 => 0xffffffff,
3044 };
3045 let pc_rel_shifted = match self {
3046 LabelUse::Adr21 | LabelUse::PCRel32 => pc_rel,
3047 _ => {
3048 debug_assert!(pc_rel & 3 == 0);
3049 pc_rel >> 2
3050 }
3051 };
3052 let pc_rel_inserted = match self {
3053 LabelUse::Branch14 => (pc_rel_shifted & 0x3fff) << 5,
3054 LabelUse::Branch19 | LabelUse::Ldr19 => (pc_rel_shifted & 0x7ffff) << 5,
3055 LabelUse::Branch26 => pc_rel_shifted & 0x3ffffff,
3056 LabelUse::Adr21 => (pc_rel_shifted & 0x1ffffc) << 3 | (pc_rel_shifted & 3) << 29,
3059 LabelUse::PCRel32 => pc_rel_shifted,
3060 };
3061 let is_add = match self {
3062 LabelUse::PCRel32 => true,
3063 _ => false,
3064 };
3065 let insn_word = if is_add {
3066 insn_word.wrapping_add(pc_rel_inserted)
3067 } else {
3068 (insn_word & !mask) | pc_rel_inserted
3069 };
3070 buffer[0..4].clone_from_slice(&u32::to_le_bytes(insn_word));
3071 }
3072
3073 fn supports_veneer(self) -> bool {
3075 match self {
3076 LabelUse::Branch14 | LabelUse::Branch19 => true, LabelUse::Branch26 => true, _ => false,
3079 }
3080 }
3081
3082 fn veneer_size(self) -> CodeOffset {
3084 match self {
3085 LabelUse::Branch14 | LabelUse::Branch19 => 4,
3086 LabelUse::Branch26 => 20,
3087 _ => unreachable!(),
3088 }
3089 }
3090
3091 fn worst_case_veneer_size() -> CodeOffset {
3092 20
3093 }
3094
3095 fn generate_veneer(
3098 self,
3099 buffer: &mut [u8],
3100 veneer_offset: CodeOffset,
3101 ) -> (CodeOffset, LabelUse) {
3102 match self {
3103 LabelUse::Branch14 | LabelUse::Branch19 => {
3104 let insn_word = 0b000101 << 26;
3107 buffer[0..4].clone_from_slice(&u32::to_le_bytes(insn_word));
3108 (veneer_offset, LabelUse::Branch26)
3109 }
3110
3111 LabelUse::Branch26 => {
3122 let tmp1 = regs::spilltmp_reg();
3123 let tmp1_w = regs::writable_spilltmp_reg();
3124 let tmp2 = regs::tmp2_reg();
3125 let tmp2_w = regs::writable_tmp2_reg();
3126 let ldr = emit::enc_ldst_imm19(0b1001_1000, 16 / 4, tmp1);
3128 let adr = emit::enc_adr(12, tmp2_w);
3130 let add = emit::enc_arith_rrr(0b10001011_000, 0, tmp1_w, tmp1, tmp2);
3132 let br = emit::enc_br(tmp1);
3134 buffer[0..4].clone_from_slice(&u32::to_le_bytes(ldr));
3135 buffer[4..8].clone_from_slice(&u32::to_le_bytes(adr));
3136 buffer[8..12].clone_from_slice(&u32::to_le_bytes(add));
3137 buffer[12..16].clone_from_slice(&u32::to_le_bytes(br));
3138 (veneer_offset + 16, LabelUse::PCRel32)
3141 }
3142
3143 _ => panic!("Unsupported label-reference type for veneer generation!"),
3144 }
3145 }
3146
3147 fn from_reloc(reloc: Reloc, addend: Addend) -> Option<LabelUse> {
3148 match (reloc, addend) {
3149 (Reloc::Arm64Call, 0) => Some(LabelUse::Branch26),
3150 _ => None,
3151 }
3152 }
3153}
3154
3155#[cfg(test)]
3156mod tests {
3157 use super::*;
3158
3159 #[test]
3160 fn inst_size_test() {
3161 assert_eq!(32, core::mem::size_of::<Inst>());
3164 }
3165}