1use core::cmp::Reverse;
4
5use crate::CodegenResult;
6use crate::FxHashSet;
7use crate::ir;
8use crate::ir::MemFlagsData;
9use crate::ir::types;
10use crate::ir::types::*;
11use crate::ir::{ExternalName, LibCall, Signature, dynamic_to_fixed};
12use crate::isa;
13use crate::isa::aarch64::{inst::*, settings as aarch64_settings};
14use crate::isa::unwind::UnwindInst;
15use crate::isa::winch;
16use crate::machinst::*;
17use crate::settings;
18use alloc::borrow::ToOwned;
19use alloc::boxed::Box;
20use alloc::vec::Vec;
21use regalloc2::{MachineEnv, PReg, PRegSet};
22use smallvec::{SmallVec, smallvec};
23
24pub(crate) type AArch64Callee = Callee<AArch64MachineDeps>;
29
30impl From<StackAMode> for AMode {
31 fn from(stack: StackAMode) -> AMode {
32 match stack {
33 StackAMode::IncomingArg(off, stack_args_size) => AMode::IncomingArg {
34 off: i64::from(stack_args_size) - off,
35 },
36 StackAMode::Slot(off) => AMode::SlotOffset { off },
37 StackAMode::OutgoingArg(off) => AMode::SPOffset { off },
38 }
39 }
40}
41
42fn compute_clobber_size(
45 call_conv: isa::CallConv,
46 clobbered_callee_saves: &[Writable<RealReg>],
47) -> u32 {
48 let mut int_regs = 0;
49 let mut vec_regs = 0;
50 for ® in clobbered_callee_saves {
51 match reg.to_reg().class() {
52 RegClass::Int => {
53 int_regs += 1;
54 }
55 RegClass::Float => {
56 vec_regs += 1;
57 }
58 RegClass::Vector => unreachable!(),
59 }
60 }
61
62 let int_save_bytes = (int_regs + (int_regs & 1)) * 8;
64 let vec_save_bytes = if call_conv == isa::CallConv::PreserveAll {
65 vec_regs * 16
68 } else {
69 let vec_reg_size = 8;
76 let vec_save_padding = vec_regs & 1;
77 (vec_regs + vec_save_padding) * vec_reg_size
79 };
80
81 int_save_bytes + vec_save_bytes
82}
83
84fn add_macho_compact_unwind_paired_regs(regs: &mut Vec<Writable<RealReg>>) {
87 let int_regs: FxHashSet<_> = regs
88 .iter()
89 .filter_map(|r| {
90 if r.to_reg().class() == RegClass::Int {
91 Some(r.to_reg().hw_enc())
92 } else {
93 None
94 }
95 })
96 .collect();
97 for (a, b) in [(19, 20), (21, 22), (23, 24), (25, 26), (27, 28)] {
98 if int_regs.contains(&a) && !int_regs.contains(&b) {
99 regs.push(Writable::from_reg(xreg(b).to_real_reg().unwrap()))
100 } else if int_regs.contains(&b) && !int_regs.contains(&a) {
101 regs.push(Writable::from_reg(xreg(a).to_real_reg().unwrap()))
102 }
103 }
104
105 let fp_regs: FxHashSet<_> = regs
106 .iter()
107 .filter_map(|r| {
108 if r.to_reg().class() == RegClass::Float {
109 Some(r.to_reg().hw_enc())
110 } else {
111 None
112 }
113 })
114 .collect();
115 for (a, b) in [(8, 9), (10, 11), (12, 13), (14, 15)] {
116 if fp_regs.contains(&a) && !fp_regs.contains(&b) {
117 regs.push(Writable::from_reg(vreg(b).to_real_reg().unwrap()))
118 } else if fp_regs.contains(&b) && !fp_regs.contains(&a) {
119 regs.push(Writable::from_reg(vreg(a).to_real_reg().unwrap()))
120 }
121 }
122}
123
124pub struct AArch64MachineDeps;
127
128impl IsaFlags for aarch64_settings::Flags {
129 fn is_forward_edge_cfi_enabled(&self) -> bool {
130 self.use_bti()
131 }
132}
133
134impl ABIMachineSpec for AArch64MachineDeps {
135 type I = Inst;
136
137 type F = aarch64_settings::Flags;
138
139 const STACK_ARG_RET_SIZE_LIMIT: u32 = 128 * 1024 * 1024;
143
144 fn word_bits() -> u32 {
145 64
146 }
147
148 fn stack_align(_call_conv: isa::CallConv) -> u32 {
150 16
151 }
152
153 fn compute_arg_locs(
154 call_conv: isa::CallConv,
155 flags: &settings::Flags,
156 params: &[ir::AbiParam],
157 args_or_rets: ArgsOrRets,
158 add_ret_area_ptr: bool,
159 mut args: ArgsAccumulator,
160 ) -> CodegenResult<(u32, Option<usize>)> {
161 let is_apple_cc = call_conv == isa::CallConv::AppleAarch64;
162 let is_winch_return = call_conv == isa::CallConv::Winch && args_or_rets == ArgsOrRets::Rets;
163
164 let mut next_xreg = if call_conv == isa::CallConv::Tail {
179 2
189 } else {
190 0
191 };
192 let mut next_vreg = 0;
193 let mut next_stack: u32 = 0;
194
195 let max_per_class_reg_vals = 8; let mut remaining_reg_vals = 16;
202
203 let ret_area_ptr = if add_ret_area_ptr {
204 debug_assert_eq!(args_or_rets, ArgsOrRets::Args);
205 if call_conv != isa::CallConv::Winch {
206 Some(ABIArg::reg(
209 xreg(8).to_real_reg().unwrap(),
210 I64,
211 ir::ArgumentExtension::None,
212 ir::ArgumentPurpose::Normal,
213 ))
214 } else {
215 next_xreg += 1;
219 Some(ABIArg::reg(
220 xreg(0).to_real_reg().unwrap(),
221 I64,
222 ir::ArgumentExtension::None,
223 ir::ArgumentPurpose::Normal,
224 ))
225 }
226 } else {
227 None
228 };
229
230 for (i, param) in params.into_iter().enumerate() {
231 if is_apple_cc && param.value_type == types::F128 && !flags.enable_llvm_abi_extensions()
232 {
233 panic!(
234 "f128 args/return values not supported for apple_aarch64 unless LLVM ABI extensions are enabled"
235 );
236 }
237
238 let (rcs, reg_types) = Inst::rc_for_type(param.value_type)?;
239
240 if let ir::ArgumentPurpose::StructReturn = param.purpose {
241 assert!(
242 call_conv != isa::CallConv::Tail,
243 "support for StructReturn parameters is not implemented for the `tail` \
244 calling convention yet",
245 );
246 }
247
248 if let ir::ArgumentPurpose::StructArgument(_) = param.purpose {
249 panic!(
250 "StructArgument parameters are not supported on arm64. \
251 Use regular pointer arguments instead."
252 );
253 }
254
255 if let ir::ArgumentPurpose::StructReturn = param.purpose {
256 assert!(
259 param.value_type == types::I64,
260 "StructReturn must be a pointer sized integer"
261 );
262 args.push(ABIArg::Slots {
263 slots: smallvec![ABIArgSlot::Reg {
264 reg: xreg(8).to_real_reg().unwrap(),
265 ty: types::I64,
266 extension: param.extension,
267 },],
268 purpose: ir::ArgumentPurpose::StructReturn,
269 });
270 continue;
271 }
272
273 let is_multi_reg = rcs.len() >= 2;
294 if is_multi_reg {
295 assert!(
296 rcs.len() == 2,
297 "Unable to handle multi reg params with more than 2 regs"
298 );
299 assert!(
300 rcs == &[RegClass::Int, RegClass::Int],
301 "Unable to handle non i64 regs"
302 );
303
304 let reg_class_space = max_per_class_reg_vals - next_xreg;
305 let reg_space = remaining_reg_vals;
306
307 if reg_space >= 2 && reg_class_space >= 2 {
308 if !is_apple_cc && next_xreg % 2 != 0 {
313 next_xreg += 1;
314 }
315
316 let lower_reg = xreg(next_xreg);
317 let upper_reg = xreg(next_xreg + 1);
318
319 args.push(ABIArg::Slots {
320 slots: smallvec![
321 ABIArgSlot::Reg {
322 reg: lower_reg.to_real_reg().unwrap(),
323 ty: reg_types[0],
324 extension: param.extension,
325 },
326 ABIArgSlot::Reg {
327 reg: upper_reg.to_real_reg().unwrap(),
328 ty: reg_types[1],
329 extension: param.extension,
330 },
331 ],
332 purpose: param.purpose,
333 });
334
335 next_xreg += 2;
336 remaining_reg_vals -= 2;
337 continue;
338 }
339 } else {
340 let rc = rcs[0];
342 let next_reg = match rc {
343 RegClass::Int => &mut next_xreg,
344 RegClass::Float => &mut next_vreg,
345 RegClass::Vector => unreachable!(),
346 };
347
348 let push_to_reg = if is_winch_return {
349 i == params.len() - 1
351 } else {
352 *next_reg < max_per_class_reg_vals && remaining_reg_vals > 0
354 };
355
356 if push_to_reg {
357 let reg = match rc {
358 RegClass::Int => xreg(*next_reg),
359 RegClass::Float => vreg(*next_reg),
360 RegClass::Vector => unreachable!(),
361 };
362 let ty = if param.value_type.is_dynamic_vector() {
364 dynamic_to_fixed(param.value_type)
365 } else {
366 param.value_type
367 };
368 args.push(ABIArg::reg(
369 reg.to_real_reg().unwrap(),
370 ty,
371 param.extension,
372 param.purpose,
373 ));
374 *next_reg += 1;
375 remaining_reg_vals -= 1;
376 continue;
377 }
378 }
379
380 if args_or_rets == ArgsOrRets::Rets && !flags.enable_multi_ret_implicit_sret() {
383 return Err(crate::CodegenError::Unsupported(
384 "Too many return values to fit in registers. \
385 Use a StructReturn argument instead. (#9510)"
386 .to_owned(),
387 ));
388 }
389
390 let size = (ty_bits(param.value_type) / 8) as u32;
392
393 let size = if (is_apple_cc || is_winch_return)
403 && (args_or_rets == ArgsOrRets::Args
404 || param.extension == ir::ArgumentExtension::None)
405 {
406 size
407 } else {
408 core::cmp::max(size, 8)
409 };
410
411 if !is_winch_return {
412 debug_assert!(size.is_power_of_two());
414 next_stack = align_to(next_stack, size);
415 }
416
417 let slots = reg_types
418 .iter()
419 .copied()
420 .scan(next_stack, |next_stack, ty| {
422 let slot_offset = *next_stack as i64;
423 *next_stack += (ty_bits(ty) / 8) as u32;
424
425 Some((ty, slot_offset))
426 })
427 .map(|(ty, offset)| ABIArgSlot::Stack {
428 offset,
429 ty,
430 extension: param.extension,
431 })
432 .collect();
433
434 args.push(ABIArg::Slots {
435 slots,
436 purpose: param.purpose,
437 });
438
439 next_stack += size;
440 }
441
442 let extra_arg = if let Some(ret_area_ptr) = ret_area_ptr {
443 args.push_non_formal(ret_area_ptr);
444 Some(args.args().len() - 1)
445 } else {
446 None
447 };
448
449 if is_winch_return {
450 winch::reverse_stack(args, next_stack, false);
451 }
452
453 next_stack = align_to(next_stack, 16);
454
455 Ok((next_stack, extra_arg))
456 }
457
458 fn gen_load_stack(mem: StackAMode, into_reg: Writable<Reg>, ty: Type) -> Inst {
459 Inst::gen_load(into_reg, mem.into(), ty, MemFlagsData::trusted())
460 }
461
462 fn gen_store_stack(mem: StackAMode, from_reg: Reg, ty: Type) -> Inst {
463 Inst::gen_store(mem.into(), from_reg, ty, MemFlagsData::trusted())
464 }
465
466 fn gen_move(to_reg: Writable<Reg>, from_reg: Reg, ty: Type) -> Inst {
467 Inst::gen_move(to_reg, from_reg, ty)
468 }
469
470 fn gen_extend(
471 to_reg: Writable<Reg>,
472 from_reg: Reg,
473 signed: bool,
474 from_bits: u8,
475 to_bits: u8,
476 ) -> Inst {
477 assert!(from_bits < to_bits);
478 Inst::Extend {
479 rd: to_reg,
480 rn: from_reg,
481 signed,
482 from_bits,
483 to_bits,
484 }
485 }
486
487 fn gen_args(args: Vec<ArgPair>) -> Inst {
488 Inst::Args { args }
489 }
490
491 fn gen_rets(rets: Vec<RetPair>) -> Inst {
492 Inst::Rets { rets }
493 }
494
495 fn gen_add_imm(
496 _call_conv: isa::CallConv,
497 into_reg: Writable<Reg>,
498 from_reg: Reg,
499 imm: u32,
500 ) -> SmallInstVec<Inst> {
501 let imm = imm as u64;
502 let mut insts = SmallVec::new();
503 if let Some(imm12) = Imm12::maybe_from_u64(imm) {
504 insts.push(Inst::AluRRImm12 {
505 alu_op: ALUOp::Add,
506 size: OperandSize::Size64,
507 rd: into_reg,
508 rn: from_reg,
509 imm12,
510 });
511 } else {
512 let scratch2 = writable_tmp2_reg();
513 assert_ne!(scratch2.to_reg(), from_reg);
514 insts.extend(Inst::load_constant(scratch2, imm));
518 insts.push(Inst::AluRRRExtend {
519 alu_op: ALUOp::Add,
520 size: OperandSize::Size64,
521 rd: into_reg,
522 rn: from_reg,
523 rm: scratch2.to_reg(),
524 extendop: ExtendOp::UXTX,
525 });
526 }
527 insts
528 }
529
530 fn gen_stack_lower_bound_trap(limit_reg: Reg) -> SmallInstVec<Inst> {
531 let mut insts = SmallVec::new();
532 insts.push(Inst::AluRRRExtend {
533 alu_op: ALUOp::SubS,
534 size: OperandSize::Size64,
535 rd: writable_zero_reg(),
536 rn: stack_reg(),
537 rm: limit_reg,
538 extendop: ExtendOp::UXTX,
539 });
540 insts.push(Inst::TrapIf {
541 trap_code: ir::TrapCode::STACK_OVERFLOW,
542 kind: CondBrKind::Cond(Cond::Lo),
545 });
546 insts
547 }
548
549 fn gen_get_stack_addr(mem: StackAMode, into_reg: Writable<Reg>) -> Inst {
550 let mem = mem.into();
552 Inst::LoadAddr { rd: into_reg, mem }
553 }
554
555 fn get_stacklimit_reg(_call_conv: isa::CallConv) -> Reg {
556 spilltmp_reg()
557 }
558
559 fn gen_load_base_offset(into_reg: Writable<Reg>, base: Reg, offset: i32, ty: Type) -> Inst {
560 let mem = AMode::RegOffset {
561 rn: base,
562 off: offset as i64,
563 };
564 Inst::gen_load(into_reg, mem, ty, MemFlagsData::trusted())
565 }
566
567 fn gen_store_base_offset(base: Reg, offset: i32, from_reg: Reg, ty: Type) -> Inst {
568 let mem = AMode::RegOffset {
569 rn: base,
570 off: offset as i64,
571 };
572 Inst::gen_store(mem, from_reg, ty, MemFlagsData::trusted())
573 }
574
575 fn gen_sp_reg_adjust(amount: i32) -> SmallInstVec<Inst> {
576 if amount == 0 {
577 return SmallVec::new();
578 }
579
580 let (amount, is_sub) = if amount > 0 {
581 (amount as u64, false)
582 } else {
583 (-amount as u64, true)
584 };
585
586 let alu_op = if is_sub { ALUOp::Sub } else { ALUOp::Add };
587
588 let mut ret = SmallVec::new();
589 if let Some(imm12) = Imm12::maybe_from_u64(amount) {
590 let adj_inst = Inst::AluRRImm12 {
591 alu_op,
592 size: OperandSize::Size64,
593 rd: writable_stack_reg(),
594 rn: stack_reg(),
595 imm12,
596 };
597 ret.push(adj_inst);
598 } else {
599 let tmp = writable_spilltmp_reg();
600 let const_inst = Inst::load_constant(tmp, amount);
603 let adj_inst = Inst::AluRRRExtend {
604 alu_op,
605 size: OperandSize::Size64,
606 rd: writable_stack_reg(),
607 rn: stack_reg(),
608 rm: tmp.to_reg(),
609 extendop: ExtendOp::UXTX,
610 };
611 ret.extend(const_inst);
612 ret.push(adj_inst);
613 }
614 ret
615 }
616
617 fn gen_prologue_frame_setup(
618 call_conv: isa::CallConv,
619 flags: &settings::Flags,
620 isa_flags: &aarch64_settings::Flags,
621 frame_layout: &FrameLayout,
622 ) -> SmallInstVec<Inst> {
623 let setup_frame = frame_layout.setup_area_size > 0;
624 let mut insts = SmallVec::new();
625
626 match Self::select_api_key(isa_flags, call_conv, setup_frame) {
627 Some(key) => {
628 insts.push(Inst::Paci { key });
629 if flags.unwind_info() {
630 insts.push(Inst::Unwind {
631 inst: UnwindInst::Aarch64SetPointerAuth {
632 return_addresses: true,
633 },
634 });
635 }
636 }
637 None => {
638 if isa_flags.use_bti() {
639 insts.push(Inst::Bti {
640 targets: BranchTargetType::C,
641 });
642 }
643
644 if flags.unwind_info() && call_conv == isa::CallConv::AppleAarch64 {
645 insts.push(Inst::Unwind {
647 inst: UnwindInst::Aarch64SetPointerAuth {
648 return_addresses: false,
649 },
650 });
651 }
652 }
653 }
654
655 if setup_frame {
656 insts.push(Inst::StoreP64 {
658 rt: fp_reg(),
659 rt2: link_reg(),
660 mem: PairAMode::SPPreIndexed {
661 simm7: SImm7Scaled::maybe_from_i64(-16, types::I64).unwrap(),
662 },
663 flags: MemFlagsData::trusted(),
664 });
665
666 if flags.unwind_info() {
667 insts.push(Inst::Unwind {
668 inst: UnwindInst::PushFrameRegs {
669 offset_upward_to_caller_sp: frame_layout.setup_area_size,
670 },
671 });
672 }
673
674 insts.push(Inst::AluRRImm12 {
677 alu_op: ALUOp::Add,
678 size: OperandSize::Size64,
679 rd: writable_fp_reg(),
680 rn: stack_reg(),
681 imm12: Imm12 {
682 bits: 0,
683 shift12: false,
684 },
685 });
686 }
687
688 insts
689 }
690
691 fn gen_epilogue_frame_restore(
692 call_conv: isa::CallConv,
693 _flags: &settings::Flags,
694 _isa_flags: &aarch64_settings::Flags,
695 frame_layout: &FrameLayout,
696 ) -> SmallInstVec<Inst> {
697 let setup_frame = frame_layout.setup_area_size > 0;
698 let mut insts = SmallVec::new();
699
700 if setup_frame {
701 insts.push(Inst::LoadP64 {
707 rt: writable_fp_reg(),
708 rt2: writable_link_reg(),
709 mem: PairAMode::SPPostIndexed {
710 simm7: SImm7Scaled::maybe_from_i64(16, types::I64).unwrap(),
711 },
712 flags: MemFlagsData::trusted(),
713 });
714 }
715
716 if call_conv == isa::CallConv::Tail && frame_layout.tail_args_size > 0 {
717 insts.extend(Self::gen_sp_reg_adjust(
718 frame_layout.tail_args_size.try_into().unwrap(),
719 ));
720 }
721
722 insts
723 }
724
725 fn gen_return(
726 call_conv: isa::CallConv,
727 isa_flags: &aarch64_settings::Flags,
728 frame_layout: &FrameLayout,
729 ) -> SmallInstVec<Inst> {
730 let setup_frame = frame_layout.setup_area_size > 0;
731
732 match Self::select_api_key(isa_flags, call_conv, setup_frame) {
733 Some(key) => {
734 smallvec![Inst::AuthenticatedRet {
735 key,
736 is_hint: !isa_flags.has_pauth(),
737 }]
738 }
739 None => {
740 smallvec![Inst::Ret {}]
741 }
742 }
743 }
744
745 fn gen_probestack(_insts: &mut SmallInstVec<Self::I>, _: u32) {
746 unimplemented!("Stack probing is unimplemented on AArch64");
749 }
750
751 fn gen_inline_probestack(
752 insts: &mut SmallInstVec<Self::I>,
753 _call_conv: isa::CallConv,
754 frame_size: u32,
755 guard_size: u32,
756 ) {
757 const PROBE_MAX_UNROLL: u32 = 3;
761
762 let probe_count = frame_size / guard_size;
765 if probe_count == 0 {
766 } else if probe_count <= PROBE_MAX_UNROLL {
768 Self::gen_probestack_unroll(insts, guard_size, probe_count)
769 } else {
770 Self::gen_probestack_loop(insts, frame_size, guard_size)
771 }
772 }
773
774 fn gen_clobber_save(
775 call_conv: isa::CallConv,
776 flags: &settings::Flags,
777 frame_layout: &FrameLayout,
778 ) -> SmallVec<[Inst; 16]> {
779 let (clobbered_int, clobbered_vec) = frame_layout.clobbered_callee_saves_by_class();
780
781 let mut insts = SmallVec::new();
782 let setup_frame = frame_layout.setup_area_size > 0;
783
784 let incoming_args_diff = frame_layout.tail_args_size - frame_layout.incoming_args_size;
787 if incoming_args_diff > 0 {
788 insts.extend(Self::gen_sp_reg_adjust(-(incoming_args_diff as i32)));
790 if flags.unwind_info() {
791 insts.push(Inst::Unwind {
792 inst: UnwindInst::StackAlloc {
793 size: incoming_args_diff,
794 },
795 });
796 }
797
798 if setup_frame {
800 insts.push(Inst::ULoad64 {
802 rd: regs::writable_fp_reg(),
803 mem: AMode::SPOffset {
804 off: i64::from(incoming_args_diff),
805 },
806 flags: MemFlagsData::trusted(),
807 });
808
809 insts.push(Inst::StoreP64 {
811 rt: fp_reg(),
812 rt2: link_reg(),
813 mem: PairAMode::SignedOffset {
814 reg: regs::stack_reg(),
815 simm7: SImm7Scaled::maybe_from_i64(0, types::I64).unwrap(),
816 },
817 flags: MemFlagsData::trusted(),
818 });
819
820 insts.push(Self::gen_move(
822 regs::writable_fp_reg(),
823 regs::stack_reg(),
824 types::I64,
825 ));
826 }
827 }
828
829 if flags.unwind_info() && setup_frame {
830 insts.push(Inst::Unwind {
833 inst: UnwindInst::DefineNewFrame {
834 offset_downward_to_clobbers: frame_layout.clobber_size,
835 offset_upward_to_caller_sp: frame_layout.setup_area_size,
836 },
837 });
838 }
839
840 let mut clobber_offset = frame_layout.clobber_size;
854 let clobber_offset_change = 16;
855 let iter = clobbered_int.chunks_exact(2);
856
857 if let [rd] = iter.remainder() {
858 let rd: Reg = rd.to_reg().into();
859
860 debug_assert_eq!(rd.class(), RegClass::Int);
861 insts.push(Inst::Store64 {
863 rd,
864 mem: AMode::SPPreIndexed {
865 simm9: SImm9::maybe_from_i64(-clobber_offset_change).unwrap(),
866 },
867 flags: MemFlagsData::trusted(),
868 });
869
870 if flags.unwind_info() {
871 clobber_offset -= clobber_offset_change as u32;
872 insts.push(Inst::Unwind {
873 inst: UnwindInst::SaveReg {
874 clobber_offset,
875 reg: rd.to_real_reg().unwrap(),
876 },
877 });
878 }
879 }
880
881 let mut iter = iter.rev();
882
883 while let Some([rt, rt2]) = iter.next() {
884 let rt: Reg = rt.to_reg().into();
886 let rt2: Reg = rt2.to_reg().into();
887
888 debug_assert!(rt.class() == RegClass::Int);
889 debug_assert!(rt2.class() == RegClass::Int);
890
891 insts.push(Inst::StoreP64 {
893 rt,
894 rt2,
895 mem: PairAMode::SPPreIndexed {
896 simm7: SImm7Scaled::maybe_from_i64(-clobber_offset_change, types::I64).unwrap(),
897 },
898 flags: MemFlagsData::trusted(),
899 });
900
901 if flags.unwind_info() {
902 clobber_offset -= clobber_offset_change as u32;
903 insts.push(Inst::Unwind {
904 inst: UnwindInst::SaveReg {
905 clobber_offset,
906 reg: rt.to_real_reg().unwrap(),
907 },
908 });
909 insts.push(Inst::Unwind {
910 inst: UnwindInst::SaveReg {
911 clobber_offset: clobber_offset + (clobber_offset_change / 2) as u32,
912 reg: rt2.to_real_reg().unwrap(),
913 },
914 });
915 }
916 }
917
918 if call_conv == isa::CallConv::PreserveAll {
919 for reg in clobbered_vec.iter().rev() {
921 let inst = Inst::FpuStore128 {
922 rd: reg.to_reg().into(),
923 mem: AMode::SPPreIndexed {
924 simm9: SImm9::maybe_from_i64(-clobber_offset_change).unwrap(),
925 },
926 flags: MemFlagsData::trusted(),
927 };
928 insts.push(inst);
929 }
932 } else {
933 let store_vec_reg_half = |rd| Inst::FpuStore64 {
934 rd,
935 mem: AMode::SPPreIndexed {
936 simm9: SImm9::maybe_from_i64(-clobber_offset_change).unwrap(),
937 },
938 flags: MemFlagsData::trusted(),
939 };
940 let iter = clobbered_vec.chunks_exact(2);
941
942 if let [rd] = iter.remainder() {
943 let rd: Reg = rd.to_reg().into();
944
945 debug_assert_eq!(rd.class(), RegClass::Float);
946 insts.push(store_vec_reg_half(rd));
947
948 if flags.unwind_info() {
949 clobber_offset -= clobber_offset_change as u32;
950 insts.push(Inst::Unwind {
951 inst: UnwindInst::SaveReg {
952 clobber_offset,
953 reg: rd.to_real_reg().unwrap(),
954 },
955 });
956 }
957 }
958
959 let store_vec_reg_half_pair = |rt, rt2| {
960 let clobber_offset_change = 16;
961
962 (
963 Inst::FpuStoreP64 {
964 rt,
965 rt2,
966 mem: PairAMode::SPPreIndexed {
967 simm7: SImm7Scaled::maybe_from_i64(-clobber_offset_change, F64)
968 .unwrap(),
969 },
970 flags: MemFlagsData::trusted(),
971 },
972 clobber_offset_change as u32,
973 )
974 };
975 let mut iter = iter.rev();
976
977 while let Some([rt, rt2]) = iter.next() {
978 let rt: Reg = rt.to_reg().into();
979 let rt2: Reg = rt2.to_reg().into();
980
981 debug_assert_eq!(rt.class(), RegClass::Float);
982 debug_assert_eq!(rt2.class(), RegClass::Float);
983
984 let (inst, clobber_offset_change) = store_vec_reg_half_pair(rt, rt2);
985
986 insts.push(inst);
987
988 if flags.unwind_info() {
989 clobber_offset -= clobber_offset_change;
990 insts.push(Inst::Unwind {
991 inst: UnwindInst::SaveReg {
992 clobber_offset,
993 reg: rt.to_real_reg().unwrap(),
994 },
995 });
996 insts.push(Inst::Unwind {
997 inst: UnwindInst::SaveReg {
998 clobber_offset: clobber_offset + clobber_offset_change / 2,
999 reg: rt2.to_real_reg().unwrap(),
1000 },
1001 });
1002 }
1003 }
1004 }
1005
1006 let stack_size = frame_layout.fixed_frame_storage_size + frame_layout.outgoing_args_size;
1008 if stack_size > 0 {
1009 insts.extend(Self::gen_sp_reg_adjust(-(stack_size as i32)));
1010 if flags.unwind_info() {
1011 insts.push(Inst::Unwind {
1012 inst: UnwindInst::StackAlloc { size: stack_size },
1013 });
1014 }
1015 }
1016
1017 insts
1018 }
1019
1020 fn gen_clobber_restore(
1021 call_conv: isa::CallConv,
1022 _flags: &settings::Flags,
1023 frame_layout: &FrameLayout,
1024 ) -> SmallVec<[Inst; 16]> {
1025 let mut insts = SmallVec::new();
1026 let (clobbered_int, clobbered_vec) = frame_layout.clobbered_callee_saves_by_class();
1027
1028 let stack_size = frame_layout.fixed_frame_storage_size + frame_layout.outgoing_args_size;
1030 if stack_size > 0 {
1031 insts.extend(Self::gen_sp_reg_adjust(stack_size as i32));
1032 }
1033
1034 if call_conv == isa::CallConv::PreserveAll {
1035 for reg in clobbered_vec.iter() {
1036 let inst = Inst::FpuLoad128 {
1037 rd: reg.map(|r| r.into()),
1038 mem: AMode::SPPostIndexed {
1039 simm9: SImm9::maybe_from_i64(16).unwrap(),
1040 },
1041 flags: MemFlagsData::trusted(),
1042 };
1043 insts.push(inst);
1044 }
1047 } else {
1048 let load_vec_reg_half = |rd| Inst::FpuLoad64 {
1049 rd,
1050 mem: AMode::SPPostIndexed {
1051 simm9: SImm9::maybe_from_i64(16).unwrap(),
1052 },
1053 flags: MemFlagsData::trusted(),
1054 };
1055 let load_vec_reg_half_pair = |rt, rt2| Inst::FpuLoadP64 {
1056 rt,
1057 rt2,
1058 mem: PairAMode::SPPostIndexed {
1059 simm7: SImm7Scaled::maybe_from_i64(16, F64).unwrap(),
1060 },
1061 flags: MemFlagsData::trusted(),
1062 };
1063
1064 let mut iter = clobbered_vec.chunks_exact(2);
1065
1066 while let Some([rt, rt2]) = iter.next() {
1067 let rt: Writable<Reg> = rt.map(|r| r.into());
1068 let rt2: Writable<Reg> = rt2.map(|r| r.into());
1069
1070 debug_assert_eq!(rt.to_reg().class(), RegClass::Float);
1071 debug_assert_eq!(rt2.to_reg().class(), RegClass::Float);
1072 insts.push(load_vec_reg_half_pair(rt, rt2));
1073 }
1074
1075 debug_assert!(iter.remainder().len() <= 1);
1076
1077 if let [rd] = iter.remainder() {
1078 let rd: Writable<Reg> = rd.map(|r| r.into());
1079
1080 debug_assert_eq!(rd.to_reg().class(), RegClass::Float);
1081 insts.push(load_vec_reg_half(rd));
1082 }
1083 }
1084
1085 let mut iter = clobbered_int.chunks_exact(2);
1086
1087 while let Some([rt, rt2]) = iter.next() {
1088 let rt: Writable<Reg> = rt.map(|r| r.into());
1089 let rt2: Writable<Reg> = rt2.map(|r| r.into());
1090
1091 debug_assert_eq!(rt.to_reg().class(), RegClass::Int);
1092 debug_assert_eq!(rt2.to_reg().class(), RegClass::Int);
1093 insts.push(Inst::LoadP64 {
1095 rt,
1096 rt2,
1097 mem: PairAMode::SPPostIndexed {
1098 simm7: SImm7Scaled::maybe_from_i64(16, I64).unwrap(),
1099 },
1100 flags: MemFlagsData::trusted(),
1101 });
1102 }
1103
1104 debug_assert!(iter.remainder().len() <= 1);
1105
1106 if let [rd] = iter.remainder() {
1107 let rd: Writable<Reg> = rd.map(|r| r.into());
1108
1109 debug_assert_eq!(rd.to_reg().class(), RegClass::Int);
1110 insts.push(Inst::ULoad64 {
1112 rd,
1113 mem: AMode::SPPostIndexed {
1114 simm9: SImm9::maybe_from_i64(16).unwrap(),
1115 },
1116 flags: MemFlagsData::trusted(),
1117 });
1118 }
1119
1120 insts
1121 }
1122
1123 fn gen_memcpy<F: FnMut(Type) -> Writable<Reg>>(
1124 call_conv: isa::CallConv,
1125 dst: Reg,
1126 src: Reg,
1127 size: usize,
1128 mut alloc_tmp: F,
1129 ) -> SmallVec<[Self::I; 8]> {
1130 let mut insts = SmallVec::new();
1131 let arg0 = writable_xreg(0);
1132 let arg1 = writable_xreg(1);
1133 let arg2 = writable_xreg(2);
1134 let tmp = alloc_tmp(Self::word_type());
1135 insts.extend(Inst::load_constant(tmp, size as u64));
1136 insts.push(Inst::Call {
1137 info: Box::new(CallInfo {
1138 dest: ExternalName::LibCall(LibCall::Memcpy),
1139 uses: smallvec![
1140 CallArgPair {
1141 vreg: dst,
1142 preg: arg0.to_reg()
1143 },
1144 CallArgPair {
1145 vreg: src,
1146 preg: arg1.to_reg()
1147 },
1148 CallArgPair {
1149 vreg: tmp.to_reg(),
1150 preg: arg2.to_reg()
1151 }
1152 ],
1153 defs: smallvec![],
1154 clobbers: Self::get_regs_clobbered_by_call(call_conv, false),
1155 caller_conv: call_conv,
1156 callee_conv: call_conv,
1157 callee_pop_size: 0,
1158 try_call_info: None,
1159 patchable: false,
1160 }),
1161 });
1162 insts
1163 }
1164
1165 fn get_number_of_spillslots_for_value(
1166 rc: RegClass,
1167 vector_size: u32,
1168 _isa_flags: &Self::F,
1169 ) -> u32 {
1170 assert_eq!(vector_size % 8, 0);
1171 match rc {
1173 RegClass::Int => 1,
1174 RegClass::Float => vector_size / 8,
1175 RegClass::Vector => unreachable!(),
1176 }
1177 }
1178
1179 fn get_machine_env(flags: &settings::Flags, _call_conv: isa::CallConv) -> &MachineEnv {
1180 if flags.enable_pinned_reg() {
1181 static MACHINE_ENV: MachineEnv = create_reg_env(true);
1182 &MACHINE_ENV
1183 } else {
1184 static MACHINE_ENV: MachineEnv = create_reg_env(false);
1185 &MACHINE_ENV
1186 }
1187 }
1188
1189 fn get_regs_clobbered_by_call(call_conv: isa::CallConv, is_exception: bool) -> PRegSet {
1190 match (call_conv, is_exception) {
1191 (isa::CallConv::Tail, true) => ALL_CLOBBERS,
1192 (isa::CallConv::Winch, true) => ALL_CLOBBERS,
1193 (isa::CallConv::Winch, false) => WINCH_CLOBBERS,
1194 (isa::CallConv::PreserveAll, true) => ALL_CLOBBERS,
1200 (isa::CallConv::SystemV, _) => DEFAULT_AAPCS_CLOBBERS,
1201 (isa::CallConv::AppleAarch64, true) => DEFAULT_AAPCS_CLOBBERS,
1204 (isa::CallConv::PreserveAll, _) => NO_CLOBBERS,
1205 (_, false) => DEFAULT_AAPCS_CLOBBERS,
1206 (_, true) => panic!("unimplemented clobbers for exn abi of {call_conv:?}"),
1207 }
1208 }
1209
1210 fn get_ext_mode(
1211 call_conv: isa::CallConv,
1212 specified: ir::ArgumentExtension,
1213 ) -> ir::ArgumentExtension {
1214 if call_conv == isa::CallConv::AppleAarch64 {
1215 specified
1216 } else {
1217 ir::ArgumentExtension::None
1218 }
1219 }
1220
1221 fn compute_frame_layout(
1222 call_conv: isa::CallConv,
1223 flags: &settings::Flags,
1224 sig: &Signature,
1225 regs: &[Writable<RealReg>],
1226 function_calls: FunctionCalls,
1227 incoming_args_size: u32,
1228 tail_args_size: u32,
1229 stackslots_size: u32,
1230 fixed_frame_storage_size: u32,
1231 outgoing_args_size: u32,
1232 ) -> FrameLayout {
1233 let mut regs: Vec<Writable<RealReg>> = regs
1234 .iter()
1235 .cloned()
1236 .filter(|r| {
1237 is_reg_saved_in_prologue(call_conv, flags.enable_pinned_reg(), sig, r.to_reg())
1238 })
1239 .collect();
1240
1241 if call_conv == isa::CallConv::AppleAarch64 && flags.enable_compact_unwind_abi() {
1242 add_macho_compact_unwind_paired_regs(&mut regs);
1243 regs.sort_unstable_by_key(|r| {
1247 let reg = r.to_reg();
1248 (reg.class(), Reverse(reg.hw_enc()))
1249 });
1250 } else {
1251 regs.sort_unstable();
1254 }
1255
1256 let clobber_size = compute_clobber_size(call_conv, ®s);
1258
1259 let needs_linkage_frame = flags.preserve_frame_pointers()
1260 || incoming_args_size > 0
1263 || tail_args_size > incoming_args_size
1264 || clobber_size > 0
1265 || fixed_frame_storage_size > 0
1266 || outgoing_args_size > 0;
1267
1268 let setup_area_size = if needs_linkage_frame || function_calls == FunctionCalls::Regular {
1270 16 } else {
1272 0
1273 };
1274
1275 FrameLayout {
1277 word_bytes: 8,
1278 incoming_args_size,
1279 tail_args_size,
1280 setup_area_size,
1281 clobber_size,
1282 fixed_frame_storage_size,
1283 stackslots_size,
1284 outgoing_args_size,
1285 clobbered_callee_saves: regs,
1286 function_calls,
1287 }
1288 }
1289
1290 fn retval_temp_reg(_call_conv_of_callee: isa::CallConv) -> Writable<Reg> {
1291 regs::writable_xreg(9)
1294 }
1295
1296 fn exception_payload_regs(call_conv: isa::CallConv) -> &'static [Reg] {
1297 const PAYLOAD_REGS: &'static [Reg] = &[regs::xreg(0), regs::xreg(1)];
1298 match call_conv {
1299 isa::CallConv::SystemV
1300 | isa::CallConv::Tail
1301 | isa::CallConv::PreserveAll
1302 | isa::CallConv::AppleAarch64 => PAYLOAD_REGS,
1303 _ => &[],
1304 }
1305 }
1306}
1307
1308impl AArch64MachineDeps {
1309 fn gen_probestack_unroll(insts: &mut SmallInstVec<Inst>, guard_size: u32, probe_count: u32) {
1310 for _ in 0..probe_count {
1318 insts.extend(Self::gen_sp_reg_adjust(-(guard_size as i32)));
1319
1320 insts.push(Inst::gen_store(
1321 AMode::SPOffset { off: 0 },
1322 zero_reg(),
1323 I32,
1324 MemFlagsData::trusted(),
1325 ));
1326 }
1327
1328 insts.extend(Self::gen_sp_reg_adjust((guard_size * probe_count) as i32));
1330 }
1331
1332 fn gen_probestack_loop(insts: &mut SmallInstVec<Inst>, frame_size: u32, guard_size: u32) {
1333 let start = writable_spilltmp_reg();
1342 let end = writable_tmp2_reg();
1343 insts.extend(Inst::load_constant(start, 0));
1346 insts.extend(Inst::load_constant(end, frame_size.into()));
1347 insts.push(Inst::StackProbeLoop {
1348 start,
1349 end: end.to_reg(),
1350 step: Imm12::maybe_from_u64(guard_size.into()).unwrap(),
1351 });
1352 }
1353
1354 pub fn select_api_key(
1355 isa_flags: &aarch64_settings::Flags,
1356 call_conv: isa::CallConv,
1357 setup_frame: bool,
1358 ) -> Option<APIKey> {
1359 if isa_flags.sign_return_address() && (setup_frame || isa_flags.sign_return_address_all()) {
1360 Some(if isa_flags.sign_return_address_with_bkey() {
1365 match call_conv {
1366 isa::CallConv::Tail => APIKey::BZ,
1367 _ => APIKey::BSP,
1368 }
1369 } else {
1370 match call_conv {
1371 isa::CallConv::Tail => APIKey::AZ,
1372 _ => APIKey::ASP,
1373 }
1374 })
1375 } else {
1376 None
1377 }
1378 }
1379}
1380
1381fn is_reg_saved_in_prologue(
1384 call_conv: isa::CallConv,
1385 enable_pinned_reg: bool,
1386 sig: &Signature,
1387 r: RealReg,
1388) -> bool {
1389 if call_conv == isa::CallConv::PreserveAll {
1390 return true;
1391 }
1392
1393 let save_z_regs = sig
1395 .params
1396 .iter()
1397 .filter(|p| p.value_type.is_dynamic_vector())
1398 .count()
1399 != 0;
1400
1401 match r.class() {
1402 RegClass::Int => {
1403 if enable_pinned_reg && r.hw_enc() == PINNED_REG {
1408 false
1409 } else {
1410 r.hw_enc() >= 19 && r.hw_enc() <= 28
1411 }
1412 }
1413 RegClass::Float => {
1414 if save_z_regs {
1420 r.hw_enc() >= 8 && r.hw_enc() <= 23
1421 } else {
1422 r.hw_enc() >= 8 && r.hw_enc() <= 15
1424 }
1425 }
1426 RegClass::Vector => unreachable!(),
1427 }
1428}
1429
1430const fn default_aapcs_clobbers() -> PRegSet {
1431 PRegSet::empty()
1432 .with(xreg_preg(0))
1434 .with(xreg_preg(1))
1435 .with(xreg_preg(2))
1436 .with(xreg_preg(3))
1437 .with(xreg_preg(4))
1438 .with(xreg_preg(5))
1439 .with(xreg_preg(6))
1440 .with(xreg_preg(7))
1441 .with(xreg_preg(8))
1442 .with(xreg_preg(9))
1443 .with(xreg_preg(10))
1444 .with(xreg_preg(11))
1445 .with(xreg_preg(12))
1446 .with(xreg_preg(13))
1447 .with(xreg_preg(14))
1448 .with(xreg_preg(15))
1449 .with(xreg_preg(16))
1450 .with(xreg_preg(17))
1451 .with(vreg_preg(0))
1467 .with(vreg_preg(1))
1468 .with(vreg_preg(2))
1469 .with(vreg_preg(3))
1470 .with(vreg_preg(4))
1471 .with(vreg_preg(5))
1472 .with(vreg_preg(6))
1473 .with(vreg_preg(7))
1474 .with(vreg_preg(8))
1475 .with(vreg_preg(9))
1476 .with(vreg_preg(10))
1477 .with(vreg_preg(11))
1478 .with(vreg_preg(12))
1479 .with(vreg_preg(13))
1480 .with(vreg_preg(14))
1481 .with(vreg_preg(15))
1482 .with(vreg_preg(16))
1483 .with(vreg_preg(17))
1484 .with(vreg_preg(18))
1485 .with(vreg_preg(19))
1486 .with(vreg_preg(20))
1487 .with(vreg_preg(21))
1488 .with(vreg_preg(22))
1489 .with(vreg_preg(23))
1490 .with(vreg_preg(24))
1491 .with(vreg_preg(25))
1492 .with(vreg_preg(26))
1493 .with(vreg_preg(27))
1494 .with(vreg_preg(28))
1495 .with(vreg_preg(29))
1496 .with(vreg_preg(30))
1497 .with(vreg_preg(31))
1498}
1499
1500const fn winch_clobbers() -> PRegSet {
1501 PRegSet::empty()
1502 .with(xreg_preg(0))
1503 .with(xreg_preg(1))
1504 .with(xreg_preg(2))
1505 .with(xreg_preg(3))
1506 .with(xreg_preg(4))
1507 .with(xreg_preg(5))
1508 .with(xreg_preg(6))
1509 .with(xreg_preg(7))
1510 .with(xreg_preg(8))
1511 .with(xreg_preg(9))
1512 .with(xreg_preg(10))
1513 .with(xreg_preg(11))
1514 .with(xreg_preg(12))
1515 .with(xreg_preg(13))
1516 .with(xreg_preg(14))
1517 .with(xreg_preg(15))
1518 .with(xreg_preg(16))
1519 .with(xreg_preg(17))
1520 .with(xreg_preg(19))
1524 .with(xreg_preg(20))
1525 .with(xreg_preg(21))
1526 .with(xreg_preg(22))
1527 .with(xreg_preg(23))
1528 .with(xreg_preg(24))
1529 .with(xreg_preg(25))
1530 .with(xreg_preg(26))
1531 .with(xreg_preg(27))
1532 .with(vreg_preg(0))
1537 .with(vreg_preg(1))
1538 .with(vreg_preg(2))
1539 .with(vreg_preg(3))
1540 .with(vreg_preg(4))
1541 .with(vreg_preg(5))
1542 .with(vreg_preg(6))
1543 .with(vreg_preg(7))
1544 .with(vreg_preg(8))
1545 .with(vreg_preg(9))
1546 .with(vreg_preg(10))
1547 .with(vreg_preg(11))
1548 .with(vreg_preg(12))
1549 .with(vreg_preg(13))
1550 .with(vreg_preg(14))
1551 .with(vreg_preg(15))
1552 .with(vreg_preg(16))
1553 .with(vreg_preg(17))
1554 .with(vreg_preg(18))
1555 .with(vreg_preg(19))
1556 .with(vreg_preg(20))
1557 .with(vreg_preg(21))
1558 .with(vreg_preg(22))
1559 .with(vreg_preg(23))
1560 .with(vreg_preg(24))
1561 .with(vreg_preg(25))
1562 .with(vreg_preg(26))
1563 .with(vreg_preg(27))
1564 .with(vreg_preg(28))
1565 .with(vreg_preg(29))
1566 .with(vreg_preg(30))
1567 .with(vreg_preg(31))
1568}
1569
1570const fn all_clobbers() -> PRegSet {
1571 PRegSet::empty()
1572 .with(xreg_preg(0))
1575 .with(xreg_preg(1))
1576 .with(xreg_preg(2))
1577 .with(xreg_preg(3))
1578 .with(xreg_preg(4))
1579 .with(xreg_preg(5))
1580 .with(xreg_preg(6))
1581 .with(xreg_preg(7))
1582 .with(xreg_preg(8))
1583 .with(xreg_preg(9))
1584 .with(xreg_preg(10))
1585 .with(xreg_preg(11))
1586 .with(xreg_preg(12))
1587 .with(xreg_preg(13))
1588 .with(xreg_preg(14))
1589 .with(xreg_preg(15))
1590 .with(xreg_preg(16))
1591 .with(xreg_preg(17))
1592 .with(xreg_preg(18))
1593 .with(xreg_preg(19))
1594 .with(xreg_preg(20))
1595 .with(xreg_preg(21))
1596 .with(xreg_preg(22))
1597 .with(xreg_preg(23))
1598 .with(xreg_preg(24))
1599 .with(xreg_preg(25))
1600 .with(xreg_preg(26))
1601 .with(xreg_preg(27))
1602 .with(xreg_preg(28))
1603 .with(vreg_preg(0))
1605 .with(vreg_preg(1))
1606 .with(vreg_preg(2))
1607 .with(vreg_preg(3))
1608 .with(vreg_preg(4))
1609 .with(vreg_preg(5))
1610 .with(vreg_preg(6))
1611 .with(vreg_preg(7))
1612 .with(vreg_preg(8))
1613 .with(vreg_preg(9))
1614 .with(vreg_preg(10))
1615 .with(vreg_preg(11))
1616 .with(vreg_preg(12))
1617 .with(vreg_preg(13))
1618 .with(vreg_preg(14))
1619 .with(vreg_preg(15))
1620 .with(vreg_preg(16))
1621 .with(vreg_preg(17))
1622 .with(vreg_preg(18))
1623 .with(vreg_preg(19))
1624 .with(vreg_preg(20))
1625 .with(vreg_preg(21))
1626 .with(vreg_preg(22))
1627 .with(vreg_preg(23))
1628 .with(vreg_preg(24))
1629 .with(vreg_preg(25))
1630 .with(vreg_preg(26))
1631 .with(vreg_preg(27))
1632 .with(vreg_preg(28))
1633 .with(vreg_preg(29))
1634 .with(vreg_preg(30))
1635 .with(vreg_preg(31))
1636}
1637
1638const DEFAULT_AAPCS_CLOBBERS: PRegSet = default_aapcs_clobbers();
1639const WINCH_CLOBBERS: PRegSet = winch_clobbers();
1640const ALL_CLOBBERS: PRegSet = all_clobbers();
1641const NO_CLOBBERS: PRegSet = PRegSet::empty();
1642
1643const fn create_reg_env(enable_pinned_reg: bool) -> MachineEnv {
1644 const fn preg(r: Reg) -> PReg {
1645 r.to_real_reg().unwrap().preg()
1646 }
1647
1648 let mut env = MachineEnv {
1649 preferred_regs_by_class: [
1650 PRegSet::empty()
1651 .with(preg(xreg(0)))
1652 .with(preg(xreg(1)))
1653 .with(preg(xreg(2)))
1654 .with(preg(xreg(3)))
1655 .with(preg(xreg(4)))
1656 .with(preg(xreg(5)))
1657 .with(preg(xreg(6)))
1658 .with(preg(xreg(7)))
1659 .with(preg(xreg(8)))
1660 .with(preg(xreg(9)))
1661 .with(preg(xreg(10)))
1662 .with(preg(xreg(11)))
1663 .with(preg(xreg(12)))
1664 .with(preg(xreg(13)))
1665 .with(preg(xreg(14)))
1666 .with(preg(xreg(15))),
1667 PRegSet::empty()
1674 .with(preg(vreg(0)))
1675 .with(preg(vreg(1)))
1676 .with(preg(vreg(2)))
1677 .with(preg(vreg(3)))
1678 .with(preg(vreg(4)))
1679 .with(preg(vreg(5)))
1680 .with(preg(vreg(6)))
1681 .with(preg(vreg(7)))
1682 .with(preg(vreg(16)))
1684 .with(preg(vreg(17)))
1685 .with(preg(vreg(18)))
1686 .with(preg(vreg(19)))
1687 .with(preg(vreg(20)))
1688 .with(preg(vreg(21)))
1689 .with(preg(vreg(22)))
1690 .with(preg(vreg(23)))
1691 .with(preg(vreg(24)))
1692 .with(preg(vreg(25)))
1693 .with(preg(vreg(26)))
1694 .with(preg(vreg(27)))
1695 .with(preg(vreg(28)))
1696 .with(preg(vreg(29)))
1697 .with(preg(vreg(30)))
1698 .with(preg(vreg(31))),
1699 PRegSet::empty(),
1701 ],
1702 non_preferred_regs_by_class: [
1703 PRegSet::empty()
1704 .with(preg(xreg(19)))
1705 .with(preg(xreg(20)))
1706 .with(preg(xreg(22)))
1708 .with(preg(xreg(23)))
1709 .with(preg(xreg(24)))
1710 .with(preg(xreg(25)))
1711 .with(preg(xreg(26)))
1712 .with(preg(xreg(27)))
1713 .with(preg(xreg(28))),
1714 PRegSet::empty()
1715 .with(preg(vreg(8)))
1716 .with(preg(vreg(9)))
1717 .with(preg(vreg(10)))
1718 .with(preg(vreg(11)))
1719 .with(preg(vreg(12)))
1720 .with(preg(vreg(13)))
1721 .with(preg(vreg(14)))
1722 .with(preg(vreg(15))),
1723 PRegSet::empty(),
1725 ],
1726 fixed_stack_slots: vec![],
1727 scratch_by_class: [None, None, None],
1728 };
1729
1730 if !enable_pinned_reg {
1731 debug_assert!(PINNED_REG == 21);
1732 env.non_preferred_regs_by_class[0].add(preg(xreg(PINNED_REG)));
1733 }
1734
1735 env
1736}