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(¶m.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 let callee_pop_size = match call_conv {
717 isa::CallConv::Tail => frame_layout.tail_args_size,
718 isa::CallConv::Winch => frame_layout.incoming_args_size,
719 _ => 0,
720 };
721 if callee_pop_size > 0 {
722 insts.extend(Self::gen_sp_reg_adjust(callee_pop_size.try_into().unwrap()));
723 }
724
725 insts
726 }
727
728 fn gen_return(
729 call_conv: isa::CallConv,
730 isa_flags: &aarch64_settings::Flags,
731 frame_layout: &FrameLayout,
732 ) -> SmallInstVec<Inst> {
733 let setup_frame = frame_layout.setup_area_size > 0;
734
735 match Self::select_api_key(isa_flags, call_conv, setup_frame) {
736 Some(key) => {
737 smallvec![Inst::AuthenticatedRet {
738 key,
739 is_hint: !isa_flags.has_pauth(),
740 }]
741 }
742 None => {
743 smallvec![Inst::Ret {}]
744 }
745 }
746 }
747
748 fn gen_probestack(_insts: &mut SmallInstVec<Self::I>, _: u32) {
749 unimplemented!("Stack probing is unimplemented on AArch64");
752 }
753
754 fn gen_inline_probestack(
755 insts: &mut SmallInstVec<Self::I>,
756 _call_conv: isa::CallConv,
757 frame_size: u32,
758 guard_size: u32,
759 ) {
760 const PROBE_MAX_UNROLL: u32 = 3;
764
765 let probe_count = frame_size / guard_size;
768 if probe_count == 0 {
769 } else if probe_count <= PROBE_MAX_UNROLL {
771 Self::gen_probestack_unroll(insts, guard_size, probe_count)
772 } else {
773 Self::gen_probestack_loop(insts, frame_size, guard_size)
774 }
775 }
776
777 fn gen_clobber_save(
778 call_conv: isa::CallConv,
779 flags: &settings::Flags,
780 frame_layout: &FrameLayout,
781 ) -> SmallVec<[Inst; 16]> {
782 let (clobbered_int, clobbered_vec) = frame_layout.clobbered_callee_saves_by_class();
783
784 let mut insts = SmallVec::new();
785 let setup_frame = frame_layout.setup_area_size > 0;
786
787 if flags.unwind_info() && setup_frame {
788 insts.push(Inst::Unwind {
796 inst: UnwindInst::DefineNewFrame {
797 offset_downward_to_clobbers: frame_layout.clobber_size,
798 offset_upward_to_caller_sp: frame_layout.setup_area_size,
799 },
800 });
801 }
802
803 let incoming_args_diff = frame_layout.tail_args_size - frame_layout.incoming_args_size;
806 if incoming_args_diff > 0 {
807 insts.extend(Self::gen_sp_reg_adjust(-(incoming_args_diff as i32)));
809 if flags.unwind_info() {
810 insts.push(Inst::Unwind {
811 inst: UnwindInst::StackAlloc {
812 size: incoming_args_diff,
813 },
814 });
815 }
816
817 if setup_frame {
819 insts.push(Inst::ULoad64 {
823 rd: writable_spilltmp_reg(),
824 mem: AMode::SPOffset {
825 off: i64::from(incoming_args_diff),
826 },
827 flags: MemFlagsData::trusted(),
828 });
829
830 insts.push(Inst::StoreP64 {
832 rt: spilltmp_reg(),
833 rt2: link_reg(),
834 mem: PairAMode::SignedOffset {
835 reg: regs::stack_reg(),
836 simm7: SImm7Scaled::maybe_from_i64(0, types::I64).unwrap(),
837 },
838 flags: MemFlagsData::trusted(),
839 });
840
841 insts.push(Self::gen_move(
843 regs::writable_fp_reg(),
844 regs::stack_reg(),
845 types::I64,
846 ));
847 }
848 }
849
850 let mut clobber_offset = frame_layout.clobber_size;
864 let clobber_offset_change = 16;
865 let iter = clobbered_int.chunks_exact(2);
866
867 if let [rd] = iter.remainder() {
868 let rd: Reg = rd.to_reg().into();
869
870 debug_assert_eq!(rd.class(), RegClass::Int);
871 insts.push(Inst::Store64 {
873 rd,
874 mem: AMode::SPPreIndexed {
875 simm9: SImm9::maybe_from_i64(-clobber_offset_change).unwrap(),
876 },
877 flags: MemFlagsData::trusted(),
878 });
879
880 if flags.unwind_info() {
881 clobber_offset -= clobber_offset_change as u32;
882 insts.push(Inst::Unwind {
883 inst: UnwindInst::SaveReg {
884 clobber_offset,
885 reg: rd.to_real_reg().unwrap(),
886 },
887 });
888 }
889 }
890
891 let mut iter = iter.rev();
892
893 while let Some([rt, rt2]) = iter.next() {
894 let rt: Reg = rt.to_reg().into();
896 let rt2: Reg = rt2.to_reg().into();
897
898 debug_assert!(rt.class() == RegClass::Int);
899 debug_assert!(rt2.class() == RegClass::Int);
900
901 insts.push(Inst::StoreP64 {
903 rt,
904 rt2,
905 mem: PairAMode::SPPreIndexed {
906 simm7: SImm7Scaled::maybe_from_i64(-clobber_offset_change, types::I64).unwrap(),
907 },
908 flags: MemFlagsData::trusted(),
909 });
910
911 if flags.unwind_info() {
912 clobber_offset -= clobber_offset_change as u32;
913 insts.push(Inst::Unwind {
914 inst: UnwindInst::SaveReg {
915 clobber_offset,
916 reg: rt.to_real_reg().unwrap(),
917 },
918 });
919 insts.push(Inst::Unwind {
920 inst: UnwindInst::SaveReg {
921 clobber_offset: clobber_offset + (clobber_offset_change / 2) as u32,
922 reg: rt2.to_real_reg().unwrap(),
923 },
924 });
925 }
926 }
927
928 if call_conv == isa::CallConv::PreserveAll {
929 for reg in clobbered_vec.iter().rev() {
931 let inst = Inst::FpuStore128 {
932 rd: reg.to_reg().into(),
933 mem: AMode::SPPreIndexed {
934 simm9: SImm9::maybe_from_i64(-clobber_offset_change).unwrap(),
935 },
936 flags: MemFlagsData::trusted(),
937 };
938 insts.push(inst);
939 }
942 } else {
943 let store_vec_reg_half = |rd| Inst::FpuStore64 {
944 rd,
945 mem: AMode::SPPreIndexed {
946 simm9: SImm9::maybe_from_i64(-clobber_offset_change).unwrap(),
947 },
948 flags: MemFlagsData::trusted(),
949 };
950 let iter = clobbered_vec.chunks_exact(2);
951
952 if let [rd] = iter.remainder() {
953 let rd: Reg = rd.to_reg().into();
954
955 debug_assert_eq!(rd.class(), RegClass::Float);
956 insts.push(store_vec_reg_half(rd));
957
958 if flags.unwind_info() {
959 clobber_offset -= clobber_offset_change as u32;
960 insts.push(Inst::Unwind {
961 inst: UnwindInst::SaveReg {
962 clobber_offset,
963 reg: rd.to_real_reg().unwrap(),
964 },
965 });
966 }
967 }
968
969 let store_vec_reg_half_pair = |rt, rt2| {
970 let clobber_offset_change = 16;
971
972 (
973 Inst::FpuStoreP64 {
974 rt,
975 rt2,
976 mem: PairAMode::SPPreIndexed {
977 simm7: SImm7Scaled::maybe_from_i64(-clobber_offset_change, F64)
978 .unwrap(),
979 },
980 flags: MemFlagsData::trusted(),
981 },
982 clobber_offset_change as u32,
983 )
984 };
985 let mut iter = iter.rev();
986
987 while let Some([rt, rt2]) = iter.next() {
988 let rt: Reg = rt.to_reg().into();
989 let rt2: Reg = rt2.to_reg().into();
990
991 debug_assert_eq!(rt.class(), RegClass::Float);
992 debug_assert_eq!(rt2.class(), RegClass::Float);
993
994 let (inst, clobber_offset_change) = store_vec_reg_half_pair(rt, rt2);
995
996 insts.push(inst);
997
998 if flags.unwind_info() {
999 clobber_offset -= clobber_offset_change;
1000 insts.push(Inst::Unwind {
1001 inst: UnwindInst::SaveReg {
1002 clobber_offset,
1003 reg: rt.to_real_reg().unwrap(),
1004 },
1005 });
1006 insts.push(Inst::Unwind {
1007 inst: UnwindInst::SaveReg {
1008 clobber_offset: clobber_offset + clobber_offset_change / 2,
1009 reg: rt2.to_real_reg().unwrap(),
1010 },
1011 });
1012 }
1013 }
1014 }
1015
1016 let stack_size = frame_layout.fixed_frame_storage_size + frame_layout.outgoing_args_size;
1018 if stack_size > 0 {
1019 insts.extend(Self::gen_sp_reg_adjust(-(stack_size as i32)));
1020 if flags.unwind_info() {
1021 insts.push(Inst::Unwind {
1022 inst: UnwindInst::StackAlloc { size: stack_size },
1023 });
1024 }
1025 }
1026
1027 insts
1028 }
1029
1030 fn gen_clobber_restore(
1031 call_conv: isa::CallConv,
1032 _flags: &settings::Flags,
1033 frame_layout: &FrameLayout,
1034 ) -> SmallVec<[Inst; 16]> {
1035 let mut insts = SmallVec::new();
1036 let (clobbered_int, clobbered_vec) = frame_layout.clobbered_callee_saves_by_class();
1037
1038 let stack_size = frame_layout.fixed_frame_storage_size + frame_layout.outgoing_args_size;
1040 if stack_size > 0 {
1041 insts.extend(Self::gen_sp_reg_adjust(stack_size as i32));
1042 }
1043
1044 if call_conv == isa::CallConv::PreserveAll {
1045 for reg in clobbered_vec.iter() {
1046 let inst = Inst::FpuLoad128 {
1047 rd: reg.map(|r| r.into()),
1048 mem: AMode::SPPostIndexed {
1049 simm9: SImm9::maybe_from_i64(16).unwrap(),
1050 },
1051 flags: MemFlagsData::trusted(),
1052 };
1053 insts.push(inst);
1054 }
1057 } else {
1058 let load_vec_reg_half = |rd| Inst::FpuLoad64 {
1059 rd,
1060 mem: AMode::SPPostIndexed {
1061 simm9: SImm9::maybe_from_i64(16).unwrap(),
1062 },
1063 flags: MemFlagsData::trusted(),
1064 };
1065 let load_vec_reg_half_pair = |rt, rt2| Inst::FpuLoadP64 {
1066 rt,
1067 rt2,
1068 mem: PairAMode::SPPostIndexed {
1069 simm7: SImm7Scaled::maybe_from_i64(16, F64).unwrap(),
1070 },
1071 flags: MemFlagsData::trusted(),
1072 };
1073
1074 let mut iter = clobbered_vec.chunks_exact(2);
1075
1076 while let Some([rt, rt2]) = iter.next() {
1077 let rt: Writable<Reg> = rt.map(|r| r.into());
1078 let rt2: Writable<Reg> = rt2.map(|r| r.into());
1079
1080 debug_assert_eq!(rt.to_reg().class(), RegClass::Float);
1081 debug_assert_eq!(rt2.to_reg().class(), RegClass::Float);
1082 insts.push(load_vec_reg_half_pair(rt, rt2));
1083 }
1084
1085 debug_assert!(iter.remainder().len() <= 1);
1086
1087 if let [rd] = iter.remainder() {
1088 let rd: Writable<Reg> = rd.map(|r| r.into());
1089
1090 debug_assert_eq!(rd.to_reg().class(), RegClass::Float);
1091 insts.push(load_vec_reg_half(rd));
1092 }
1093 }
1094
1095 let mut iter = clobbered_int.chunks_exact(2);
1096
1097 while let Some([rt, rt2]) = iter.next() {
1098 let rt: Writable<Reg> = rt.map(|r| r.into());
1099 let rt2: Writable<Reg> = rt2.map(|r| r.into());
1100
1101 debug_assert_eq!(rt.to_reg().class(), RegClass::Int);
1102 debug_assert_eq!(rt2.to_reg().class(), RegClass::Int);
1103 insts.push(Inst::LoadP64 {
1105 rt,
1106 rt2,
1107 mem: PairAMode::SPPostIndexed {
1108 simm7: SImm7Scaled::maybe_from_i64(16, I64).unwrap(),
1109 },
1110 flags: MemFlagsData::trusted(),
1111 });
1112 }
1113
1114 debug_assert!(iter.remainder().len() <= 1);
1115
1116 if let [rd] = iter.remainder() {
1117 let rd: Writable<Reg> = rd.map(|r| r.into());
1118
1119 debug_assert_eq!(rd.to_reg().class(), RegClass::Int);
1120 insts.push(Inst::ULoad64 {
1122 rd,
1123 mem: AMode::SPPostIndexed {
1124 simm9: SImm9::maybe_from_i64(16).unwrap(),
1125 },
1126 flags: MemFlagsData::trusted(),
1127 });
1128 }
1129
1130 insts
1131 }
1132
1133 fn gen_memcpy<F: FnMut(Type) -> Writable<Reg>>(
1134 call_conv: isa::CallConv,
1135 dst: Reg,
1136 src: Reg,
1137 size: usize,
1138 mut alloc_tmp: F,
1139 ) -> SmallVec<[Self::I; 8]> {
1140 let mut insts = SmallVec::new();
1141 let arg0 = writable_xreg(0);
1142 let arg1 = writable_xreg(1);
1143 let arg2 = writable_xreg(2);
1144 let tmp = alloc_tmp(Self::word_type());
1145 insts.extend(Inst::load_constant(tmp, size as u64));
1146 insts.push(Inst::Call {
1147 info: Box::new(CallInfo {
1148 dest: ExternalName::LibCall(LibCall::Memcpy),
1149 uses: smallvec![
1150 CallArgPair {
1151 vreg: dst,
1152 preg: arg0.to_reg()
1153 },
1154 CallArgPair {
1155 vreg: src,
1156 preg: arg1.to_reg()
1157 },
1158 CallArgPair {
1159 vreg: tmp.to_reg(),
1160 preg: arg2.to_reg()
1161 }
1162 ],
1163 defs: smallvec![],
1164 clobbers: Self::get_regs_clobbered_by_call(call_conv, false),
1165 caller_conv: call_conv,
1166 callee_conv: call_conv,
1167 callee_pop_size: 0,
1168 try_call_info: None,
1169 patchable: false,
1170 }),
1171 });
1172 insts
1173 }
1174
1175 fn get_number_of_spillslots_for_value(
1176 rc: RegClass,
1177 vector_size: u32,
1178 _isa_flags: &Self::F,
1179 ) -> u32 {
1180 assert_eq!(vector_size % 8, 0);
1181 match rc {
1183 RegClass::Int => 1,
1184 RegClass::Float => vector_size / 8,
1185 RegClass::Vector => unreachable!(),
1186 }
1187 }
1188
1189 fn get_machine_env(flags: &settings::Flags, _call_conv: isa::CallConv) -> &MachineEnv {
1190 if flags.enable_pinned_reg() {
1191 static MACHINE_ENV: MachineEnv = create_reg_env(true);
1192 &MACHINE_ENV
1193 } else {
1194 static MACHINE_ENV: MachineEnv = create_reg_env(false);
1195 &MACHINE_ENV
1196 }
1197 }
1198
1199 fn get_regs_clobbered_by_call(call_conv: isa::CallConv, is_exception: bool) -> PRegSet {
1200 match (call_conv, is_exception) {
1201 (isa::CallConv::Tail, true) => ALL_CLOBBERS,
1202 (isa::CallConv::Winch, true) => ALL_CLOBBERS,
1203 (isa::CallConv::Winch, false) => WINCH_CLOBBERS,
1204 (isa::CallConv::PreserveAll, true) => ALL_CLOBBERS,
1210 (isa::CallConv::SystemV, _) => DEFAULT_AAPCS_CLOBBERS,
1211 (isa::CallConv::AppleAarch64, true) => DEFAULT_AAPCS_CLOBBERS,
1214 (isa::CallConv::PreserveAll, _) => NO_CLOBBERS,
1215 (_, false) => DEFAULT_AAPCS_CLOBBERS,
1216 (_, true) => panic!("unimplemented clobbers for exn abi of {call_conv:?}"),
1217 }
1218 }
1219
1220 fn get_ext_mode(
1221 call_conv: isa::CallConv,
1222 specified: ir::ArgumentExtension,
1223 location: ABIArgLocation,
1224 ) -> ir::ArgumentExtension {
1225 if call_conv == isa::CallConv::AppleAarch64 && location == ABIArgLocation::Reg {
1231 specified
1232 } else {
1233 ir::ArgumentExtension::None
1234 }
1235 }
1236
1237 fn compute_frame_layout(
1238 call_conv: isa::CallConv,
1239 flags: &settings::Flags,
1240 sig: &Signature,
1241 regs: &[Writable<RealReg>],
1242 function_calls: FunctionCalls,
1243 incoming_args_size: u32,
1244 tail_args_size: u32,
1245 stackslots_size: u32,
1246 fixed_frame_storage_size: u32,
1247 outgoing_args_size: u32,
1248 ) -> FrameLayout {
1249 let mut regs: Vec<Writable<RealReg>> = regs
1250 .iter()
1251 .cloned()
1252 .filter(|r| {
1253 is_reg_saved_in_prologue(call_conv, flags.enable_pinned_reg(), sig, r.to_reg())
1254 })
1255 .collect();
1256
1257 if call_conv == isa::CallConv::AppleAarch64 && flags.enable_compact_unwind_abi() {
1258 add_macho_compact_unwind_paired_regs(&mut regs);
1259 regs.sort_unstable_by_key(|r| {
1263 let reg = r.to_reg();
1264 (reg.class(), Reverse(reg.hw_enc()))
1265 });
1266 } else {
1267 regs.sort_unstable();
1270 }
1271
1272 let clobber_size = compute_clobber_size(call_conv, ®s);
1274
1275 let needs_linkage_frame = flags.preserve_frame_pointers()
1276 || incoming_args_size > 0
1279 || tail_args_size > incoming_args_size
1280 || clobber_size > 0
1281 || fixed_frame_storage_size > 0
1282 || outgoing_args_size > 0;
1283
1284 let setup_area_size = if needs_linkage_frame || function_calls == FunctionCalls::Regular {
1286 16 } else {
1288 0
1289 };
1290
1291 FrameLayout {
1293 word_bytes: 8,
1294 incoming_args_size,
1295 tail_args_size,
1296 setup_area_size,
1297 clobber_size,
1298 fixed_frame_storage_size,
1299 stackslots_size,
1300 outgoing_args_size,
1301 clobbered_callee_saves: regs,
1302 function_calls,
1303 }
1304 }
1305
1306 fn retval_temp_reg(_call_conv_of_callee: isa::CallConv) -> Writable<Reg> {
1307 regs::writable_xreg(9)
1310 }
1311
1312 fn exception_payload_regs(call_conv: isa::CallConv) -> &'static [Reg] {
1313 const PAYLOAD_REGS: &'static [Reg] = &[regs::xreg(0), regs::xreg(1)];
1314 match call_conv {
1315 isa::CallConv::SystemV
1316 | isa::CallConv::Tail
1317 | isa::CallConv::PreserveAll
1318 | isa::CallConv::AppleAarch64 => PAYLOAD_REGS,
1319 _ => &[],
1320 }
1321 }
1322}
1323
1324impl AArch64MachineDeps {
1325 fn gen_probestack_unroll(insts: &mut SmallInstVec<Inst>, guard_size: u32, probe_count: u32) {
1326 for _ in 0..probe_count {
1334 insts.extend(Self::gen_sp_reg_adjust(-(guard_size as i32)));
1335
1336 insts.push(Inst::gen_store(
1337 AMode::SPOffset { off: 0 },
1338 zero_reg(),
1339 I32,
1340 MemFlagsData::trusted(),
1341 ));
1342 }
1343
1344 insts.extend(Self::gen_sp_reg_adjust((guard_size * probe_count) as i32));
1346 }
1347
1348 fn gen_probestack_loop(insts: &mut SmallInstVec<Inst>, frame_size: u32, guard_size: u32) {
1349 let start = writable_spilltmp_reg();
1358 let end = writable_tmp2_reg();
1359 insts.extend(Inst::load_constant(start, 0));
1362 insts.extend(Inst::load_constant(end, frame_size.into()));
1363 insts.push(Inst::StackProbeLoop {
1364 start,
1365 end: end.to_reg(),
1366 step: Imm12::maybe_from_u64(guard_size.into()).unwrap(),
1367 });
1368 }
1369
1370 pub fn select_api_key(
1371 isa_flags: &aarch64_settings::Flags,
1372 call_conv: isa::CallConv,
1373 setup_frame: bool,
1374 ) -> Option<APIKey> {
1375 if isa_flags.sign_return_address() && (setup_frame || isa_flags.sign_return_address_all()) {
1376 Some(if isa_flags.sign_return_address_with_bkey() {
1381 match call_conv {
1382 isa::CallConv::Tail => APIKey::BZ,
1383 _ => APIKey::BSP,
1384 }
1385 } else {
1386 match call_conv {
1387 isa::CallConv::Tail => APIKey::AZ,
1388 _ => APIKey::ASP,
1389 }
1390 })
1391 } else {
1392 None
1393 }
1394 }
1395}
1396
1397fn is_reg_saved_in_prologue(
1400 call_conv: isa::CallConv,
1401 enable_pinned_reg: bool,
1402 sig: &Signature,
1403 r: RealReg,
1404) -> bool {
1405 if call_conv == isa::CallConv::PreserveAll {
1406 return true;
1407 }
1408
1409 let save_z_regs = sig
1411 .params
1412 .iter()
1413 .filter(|p| p.value_type.is_dynamic_vector())
1414 .count()
1415 != 0;
1416
1417 match r.class() {
1418 RegClass::Int => {
1419 if enable_pinned_reg && r.hw_enc() == PINNED_REG {
1424 false
1425 } else {
1426 r.hw_enc() >= 19 && r.hw_enc() <= 28
1427 }
1428 }
1429 RegClass::Float => {
1430 if save_z_regs {
1436 r.hw_enc() >= 8 && r.hw_enc() <= 23
1437 } else {
1438 r.hw_enc() >= 8 && r.hw_enc() <= 15
1440 }
1441 }
1442 RegClass::Vector => unreachable!(),
1443 }
1444}
1445
1446const fn default_aapcs_clobbers() -> PRegSet {
1447 PRegSet::empty()
1448 .with(xreg_preg(0))
1450 .with(xreg_preg(1))
1451 .with(xreg_preg(2))
1452 .with(xreg_preg(3))
1453 .with(xreg_preg(4))
1454 .with(xreg_preg(5))
1455 .with(xreg_preg(6))
1456 .with(xreg_preg(7))
1457 .with(xreg_preg(8))
1458 .with(xreg_preg(9))
1459 .with(xreg_preg(10))
1460 .with(xreg_preg(11))
1461 .with(xreg_preg(12))
1462 .with(xreg_preg(13))
1463 .with(xreg_preg(14))
1464 .with(xreg_preg(15))
1465 .with(xreg_preg(16))
1466 .with(xreg_preg(17))
1467 .with(vreg_preg(0))
1483 .with(vreg_preg(1))
1484 .with(vreg_preg(2))
1485 .with(vreg_preg(3))
1486 .with(vreg_preg(4))
1487 .with(vreg_preg(5))
1488 .with(vreg_preg(6))
1489 .with(vreg_preg(7))
1490 .with(vreg_preg(8))
1491 .with(vreg_preg(9))
1492 .with(vreg_preg(10))
1493 .with(vreg_preg(11))
1494 .with(vreg_preg(12))
1495 .with(vreg_preg(13))
1496 .with(vreg_preg(14))
1497 .with(vreg_preg(15))
1498 .with(vreg_preg(16))
1499 .with(vreg_preg(17))
1500 .with(vreg_preg(18))
1501 .with(vreg_preg(19))
1502 .with(vreg_preg(20))
1503 .with(vreg_preg(21))
1504 .with(vreg_preg(22))
1505 .with(vreg_preg(23))
1506 .with(vreg_preg(24))
1507 .with(vreg_preg(25))
1508 .with(vreg_preg(26))
1509 .with(vreg_preg(27))
1510 .with(vreg_preg(28))
1511 .with(vreg_preg(29))
1512 .with(vreg_preg(30))
1513 .with(vreg_preg(31))
1514}
1515
1516const fn winch_clobbers() -> PRegSet {
1517 PRegSet::empty()
1518 .with(xreg_preg(0))
1519 .with(xreg_preg(1))
1520 .with(xreg_preg(2))
1521 .with(xreg_preg(3))
1522 .with(xreg_preg(4))
1523 .with(xreg_preg(5))
1524 .with(xreg_preg(6))
1525 .with(xreg_preg(7))
1526 .with(xreg_preg(8))
1527 .with(xreg_preg(9))
1528 .with(xreg_preg(10))
1529 .with(xreg_preg(11))
1530 .with(xreg_preg(12))
1531 .with(xreg_preg(13))
1532 .with(xreg_preg(14))
1533 .with(xreg_preg(15))
1534 .with(xreg_preg(16))
1535 .with(xreg_preg(17))
1536 .with(xreg_preg(19))
1540 .with(xreg_preg(20))
1541 .with(xreg_preg(21))
1542 .with(xreg_preg(22))
1543 .with(xreg_preg(23))
1544 .with(xreg_preg(24))
1545 .with(xreg_preg(25))
1546 .with(xreg_preg(26))
1547 .with(xreg_preg(27))
1548 .with(vreg_preg(0))
1553 .with(vreg_preg(1))
1554 .with(vreg_preg(2))
1555 .with(vreg_preg(3))
1556 .with(vreg_preg(4))
1557 .with(vreg_preg(5))
1558 .with(vreg_preg(6))
1559 .with(vreg_preg(7))
1560 .with(vreg_preg(8))
1561 .with(vreg_preg(9))
1562 .with(vreg_preg(10))
1563 .with(vreg_preg(11))
1564 .with(vreg_preg(12))
1565 .with(vreg_preg(13))
1566 .with(vreg_preg(14))
1567 .with(vreg_preg(15))
1568 .with(vreg_preg(16))
1569 .with(vreg_preg(17))
1570 .with(vreg_preg(18))
1571 .with(vreg_preg(19))
1572 .with(vreg_preg(20))
1573 .with(vreg_preg(21))
1574 .with(vreg_preg(22))
1575 .with(vreg_preg(23))
1576 .with(vreg_preg(24))
1577 .with(vreg_preg(25))
1578 .with(vreg_preg(26))
1579 .with(vreg_preg(27))
1580 .with(vreg_preg(28))
1581 .with(vreg_preg(29))
1582 .with(vreg_preg(30))
1583 .with(vreg_preg(31))
1584}
1585
1586const fn all_clobbers() -> PRegSet {
1587 PRegSet::empty()
1588 .with(xreg_preg(0))
1591 .with(xreg_preg(1))
1592 .with(xreg_preg(2))
1593 .with(xreg_preg(3))
1594 .with(xreg_preg(4))
1595 .with(xreg_preg(5))
1596 .with(xreg_preg(6))
1597 .with(xreg_preg(7))
1598 .with(xreg_preg(8))
1599 .with(xreg_preg(9))
1600 .with(xreg_preg(10))
1601 .with(xreg_preg(11))
1602 .with(xreg_preg(12))
1603 .with(xreg_preg(13))
1604 .with(xreg_preg(14))
1605 .with(xreg_preg(15))
1606 .with(xreg_preg(16))
1607 .with(xreg_preg(17))
1608 .with(xreg_preg(18))
1609 .with(xreg_preg(19))
1610 .with(xreg_preg(20))
1611 .with(xreg_preg(21))
1612 .with(xreg_preg(22))
1613 .with(xreg_preg(23))
1614 .with(xreg_preg(24))
1615 .with(xreg_preg(25))
1616 .with(xreg_preg(26))
1617 .with(xreg_preg(27))
1618 .with(xreg_preg(28))
1619 .with(vreg_preg(0))
1621 .with(vreg_preg(1))
1622 .with(vreg_preg(2))
1623 .with(vreg_preg(3))
1624 .with(vreg_preg(4))
1625 .with(vreg_preg(5))
1626 .with(vreg_preg(6))
1627 .with(vreg_preg(7))
1628 .with(vreg_preg(8))
1629 .with(vreg_preg(9))
1630 .with(vreg_preg(10))
1631 .with(vreg_preg(11))
1632 .with(vreg_preg(12))
1633 .with(vreg_preg(13))
1634 .with(vreg_preg(14))
1635 .with(vreg_preg(15))
1636 .with(vreg_preg(16))
1637 .with(vreg_preg(17))
1638 .with(vreg_preg(18))
1639 .with(vreg_preg(19))
1640 .with(vreg_preg(20))
1641 .with(vreg_preg(21))
1642 .with(vreg_preg(22))
1643 .with(vreg_preg(23))
1644 .with(vreg_preg(24))
1645 .with(vreg_preg(25))
1646 .with(vreg_preg(26))
1647 .with(vreg_preg(27))
1648 .with(vreg_preg(28))
1649 .with(vreg_preg(29))
1650 .with(vreg_preg(30))
1651 .with(vreg_preg(31))
1652}
1653
1654const DEFAULT_AAPCS_CLOBBERS: PRegSet = default_aapcs_clobbers();
1655const WINCH_CLOBBERS: PRegSet = winch_clobbers();
1656const ALL_CLOBBERS: PRegSet = all_clobbers();
1657const NO_CLOBBERS: PRegSet = PRegSet::empty();
1658
1659const fn create_reg_env(enable_pinned_reg: bool) -> MachineEnv {
1660 const fn preg(r: Reg) -> PReg {
1661 r.to_real_reg().unwrap().preg()
1662 }
1663
1664 let mut env = MachineEnv {
1665 preferred_regs_by_class: [
1666 PRegSet::empty()
1667 .with(preg(xreg(0)))
1668 .with(preg(xreg(1)))
1669 .with(preg(xreg(2)))
1670 .with(preg(xreg(3)))
1671 .with(preg(xreg(4)))
1672 .with(preg(xreg(5)))
1673 .with(preg(xreg(6)))
1674 .with(preg(xreg(7)))
1675 .with(preg(xreg(8)))
1676 .with(preg(xreg(9)))
1677 .with(preg(xreg(10)))
1678 .with(preg(xreg(11)))
1679 .with(preg(xreg(12)))
1680 .with(preg(xreg(13)))
1681 .with(preg(xreg(14)))
1682 .with(preg(xreg(15))),
1683 PRegSet::empty()
1690 .with(preg(vreg(0)))
1691 .with(preg(vreg(1)))
1692 .with(preg(vreg(2)))
1693 .with(preg(vreg(3)))
1694 .with(preg(vreg(4)))
1695 .with(preg(vreg(5)))
1696 .with(preg(vreg(6)))
1697 .with(preg(vreg(7)))
1698 .with(preg(vreg(16)))
1700 .with(preg(vreg(17)))
1701 .with(preg(vreg(18)))
1702 .with(preg(vreg(19)))
1703 .with(preg(vreg(20)))
1704 .with(preg(vreg(21)))
1705 .with(preg(vreg(22)))
1706 .with(preg(vreg(23)))
1707 .with(preg(vreg(24)))
1708 .with(preg(vreg(25)))
1709 .with(preg(vreg(26)))
1710 .with(preg(vreg(27)))
1711 .with(preg(vreg(28)))
1712 .with(preg(vreg(29)))
1713 .with(preg(vreg(30)))
1714 .with(preg(vreg(31))),
1715 PRegSet::empty(),
1717 ],
1718 non_preferred_regs_by_class: [
1719 PRegSet::empty()
1720 .with(preg(xreg(19)))
1721 .with(preg(xreg(20)))
1722 .with(preg(xreg(22)))
1724 .with(preg(xreg(23)))
1725 .with(preg(xreg(24)))
1726 .with(preg(xreg(25)))
1727 .with(preg(xreg(26)))
1728 .with(preg(xreg(27)))
1729 .with(preg(xreg(28))),
1730 PRegSet::empty()
1731 .with(preg(vreg(8)))
1732 .with(preg(vreg(9)))
1733 .with(preg(vreg(10)))
1734 .with(preg(vreg(11)))
1735 .with(preg(vreg(12)))
1736 .with(preg(vreg(13)))
1737 .with(preg(vreg(14)))
1738 .with(preg(vreg(15))),
1739 PRegSet::empty(),
1741 ],
1742 fixed_stack_slots: vec![],
1743 scratch_by_class: [None, None, None],
1744 };
1745
1746 if !enable_pinned_reg {
1747 debug_assert!(PINNED_REG == 21);
1748 env.non_preferred_regs_by_class[0].add(preg(xreg(PINNED_REG)));
1749 }
1750
1751 env
1752}