1use super::{PulleyFlags, PulleyTargetKind, inst::*};
4use crate::isa::pulley_shared::PointerWidth;
5use crate::{
6 CodegenResult,
7 ir::{self, MemFlags, Signature, types::*},
8 isa,
9 machinst::*,
10 settings,
11};
12use alloc::vec::Vec;
13use core::marker::PhantomData;
14use cranelift_bitset::ScalarBitSet;
15use regalloc2::{MachineEnv, PReg, PRegSet};
16use smallvec::{SmallVec, smallvec};
17use std::borrow::ToOwned;
18use std::sync::OnceLock;
19
20pub(crate) type PulleyCallee<P> = Callee<PulleyMachineDeps<P>>;
22
23pub struct PulleyMachineDeps<P>
26where
27 P: PulleyTargetKind,
28{
29 _phantom: PhantomData<P>,
30}
31
32impl<P> ABIMachineSpec for PulleyMachineDeps<P>
33where
34 P: PulleyTargetKind,
35{
36 type I = InstAndKind<P>;
37 type F = PulleyFlags;
38
39 const STACK_ARG_RET_SIZE_LIMIT: u32 = 128 * 1024 * 1024;
43
44 fn word_bits() -> u32 {
45 P::pointer_width().bits().into()
46 }
47
48 fn stack_align(_call_conv: isa::CallConv) -> u32 {
50 16
51 }
52
53 fn compute_arg_locs(
54 call_conv: isa::CallConv,
55 flags: &settings::Flags,
56 params: &[ir::AbiParam],
57 args_or_rets: ArgsOrRets,
58 add_ret_area_ptr: bool,
59 mut args: ArgsAccumulator,
60 ) -> CodegenResult<(u32, Option<usize>)> {
61 let x_end = 14;
71 let f_end = 15;
72 let v_end = 15;
73
74 let mut next_x_reg = 0;
75 let mut next_f_reg = 0;
76 let mut next_v_reg = 0;
77 let mut next_stack: u32 = 0;
78
79 let ret_area_ptr = if add_ret_area_ptr {
80 debug_assert_eq!(args_or_rets, ArgsOrRets::Args);
81 next_x_reg += 1;
82 Some(ABIArg::reg(
83 x_reg(next_x_reg - 1).to_real_reg().unwrap(),
84 I64,
85 ir::ArgumentExtension::None,
86 ir::ArgumentPurpose::Normal,
87 ))
88 } else {
89 None
90 };
91
92 for param in params {
93 let (rcs, reg_tys) = Self::I::rc_for_type(param.value_type)?;
96
97 let mut slots = ABIArgSlotVec::new();
98 for (rc, reg_ty) in rcs.iter().zip(reg_tys.iter()) {
99 let next_reg = if (next_x_reg <= x_end) && *rc == RegClass::Int {
100 let x = Some(x_reg(next_x_reg));
101 next_x_reg += 1;
102 x
103 } else if (next_f_reg <= f_end) && *rc == RegClass::Float {
104 let f = Some(f_reg(next_f_reg));
105 next_f_reg += 1;
106 f
107 } else if (next_v_reg <= v_end) && *rc == RegClass::Vector {
108 let v = Some(v_reg(next_v_reg));
109 next_v_reg += 1;
110 v
111 } else {
112 None
113 };
114
115 if let Some(reg) = next_reg {
116 slots.push(ABIArgSlot::Reg {
117 reg: reg.to_real_reg().unwrap(),
118 ty: *reg_ty,
119 extension: param.extension,
120 });
121 } else {
122 if args_or_rets == ArgsOrRets::Rets && !flags.enable_multi_ret_implicit_sret() {
123 return Err(crate::CodegenError::Unsupported(
124 "Too many return values to fit in registers. \
125 Use a StructReturn argument instead. (#9510)"
126 .to_owned(),
127 ));
128 }
129
130 let size = reg_ty.bits() / 8;
133 let size = std::cmp::max(size, 8);
134
135 debug_assert!(size.is_power_of_two());
137 next_stack = align_to(next_stack, size);
138
139 slots.push(ABIArgSlot::Stack {
140 offset: i64::from(next_stack),
141 ty: *reg_ty,
142 extension: param.extension,
143 });
144
145 next_stack += size;
146 }
147 }
148
149 args.push(ABIArg::Slots {
150 slots,
151 purpose: param.purpose,
152 });
153 }
154
155 let pos = if let Some(ret_area_ptr) = ret_area_ptr {
156 args.push_non_formal(ret_area_ptr);
157 Some(args.args().len() - 1)
158 } else {
159 None
160 };
161
162 next_stack = align_to(next_stack, Self::stack_align(call_conv));
163
164 Ok((next_stack, pos))
165 }
166
167 fn gen_load_stack(mem: StackAMode, into_reg: Writable<Reg>, ty: Type) -> Self::I {
168 let mut flags = MemFlags::trusted();
169 if ty.is_vector() {
172 flags.set_endianness(ir::Endianness::Little);
173 }
174 Inst::gen_load(into_reg, mem.into(), ty, flags).into()
175 }
176
177 fn gen_store_stack(mem: StackAMode, from_reg: Reg, ty: Type) -> Self::I {
178 let mut flags = MemFlags::trusted();
179 if ty.is_vector() {
182 flags.set_endianness(ir::Endianness::Little);
183 }
184 Inst::gen_store(mem.into(), from_reg, ty, flags).into()
185 }
186
187 fn gen_move(to_reg: Writable<Reg>, from_reg: Reg, ty: Type) -> Self::I {
188 Self::I::gen_move(to_reg, from_reg, ty)
189 }
190
191 fn gen_extend(
192 dst: Writable<Reg>,
193 src: Reg,
194 signed: bool,
195 from_bits: u8,
196 to_bits: u8,
197 ) -> Self::I {
198 assert!(from_bits < to_bits);
199 let src = XReg::new(src).unwrap();
200 let dst = dst.try_into().unwrap();
201 match (signed, from_bits) {
202 (true, 8) => RawInst::Sext8 { dst, src }.into(),
203 (true, 16) => RawInst::Sext16 { dst, src }.into(),
204 (true, 32) => RawInst::Sext32 { dst, src }.into(),
205 (false, 8) => RawInst::Zext8 { dst, src }.into(),
206 (false, 16) => RawInst::Zext16 { dst, src }.into(),
207 (false, 32) => RawInst::Zext32 { dst, src }.into(),
208 _ => unimplemented!("extend {from_bits} to {to_bits} as signed? {signed}"),
209 }
210 }
211
212 fn get_ext_mode(
213 _call_conv: isa::CallConv,
214 specified: ir::ArgumentExtension,
215 ) -> ir::ArgumentExtension {
216 specified
217 }
218
219 fn gen_args(args: Vec<ArgPair>) -> Self::I {
220 Inst::Args { args }.into()
221 }
222
223 fn gen_rets(rets: Vec<RetPair>) -> Self::I {
224 Inst::Rets { rets }.into()
225 }
226
227 fn get_stacklimit_reg(_call_conv: isa::CallConv) -> Reg {
228 spilltmp_reg()
229 }
230
231 fn gen_add_imm(
232 _call_conv: isa::CallConv,
233 into_reg: Writable<Reg>,
234 from_reg: Reg,
235 imm: u32,
236 ) -> SmallInstVec<Self::I> {
237 let dst = into_reg.try_into().unwrap();
238 let imm = imm as i32;
239 smallvec![
240 RawInst::Xconst32 { dst, imm }.into(),
241 RawInst::Xadd32 {
242 dst,
243 src1: from_reg.try_into().unwrap(),
244 src2: dst.to_reg(),
245 }
246 .into()
247 ]
248 }
249
250 fn gen_stack_lower_bound_trap(_limit_reg: Reg) -> SmallInstVec<Self::I> {
251 unimplemented!("pulley shouldn't need stack bound checks")
252 }
253
254 fn gen_get_stack_addr(mem: StackAMode, dst: Writable<Reg>) -> Self::I {
255 let dst = dst.to_reg();
256 let dst = XReg::new(dst).unwrap();
257 let dst = WritableXReg::from_reg(dst);
258 let mem = mem.into();
259 Inst::LoadAddr { dst, mem }.into()
260 }
261
262 fn gen_load_base_offset(into_reg: Writable<Reg>, base: Reg, offset: i32, ty: Type) -> Self::I {
263 let base = XReg::try_from(base).unwrap();
264 let mem = Amode::RegOffset { base, offset };
265 Inst::gen_load(into_reg, mem, ty, MemFlags::trusted()).into()
266 }
267
268 fn gen_store_base_offset(base: Reg, offset: i32, from_reg: Reg, ty: Type) -> Self::I {
269 let base = XReg::try_from(base).unwrap();
270 let mem = Amode::RegOffset { base, offset };
271 Inst::gen_store(mem, from_reg, ty, MemFlags::trusted()).into()
272 }
273
274 fn gen_sp_reg_adjust(amount: i32) -> SmallInstVec<Self::I> {
275 if amount == 0 {
276 return smallvec![];
277 }
278
279 let inst = if amount < 0 {
280 let amount = amount.checked_neg().unwrap();
281 if let Ok(amt) = u32::try_from(amount) {
282 RawInst::StackAlloc32 { amt }
283 } else {
284 unreachable!()
285 }
286 } else {
287 if let Ok(amt) = u32::try_from(amount) {
288 RawInst::StackFree32 { amt }
289 } else {
290 unreachable!()
291 }
292 };
293 smallvec![inst.into()]
294 }
295
296 fn gen_prologue_frame_setup(
308 _call_conv: isa::CallConv,
309 _flags: &settings::Flags,
310 _isa_flags: &PulleyFlags,
311 frame_layout: &FrameLayout,
312 ) -> SmallInstVec<Self::I> {
313 let mut insts = SmallVec::new();
314
315 let incoming_args_diff = frame_layout.tail_args_size - frame_layout.incoming_args_size;
316 if incoming_args_diff > 0 {
317 insts.extend(Self::gen_sp_reg_adjust(-(incoming_args_diff as i32)));
320 }
321
322 let style = frame_layout.pulley_frame_style();
323
324 match &style {
325 FrameStyle::None => {}
326 FrameStyle::PulleyBasicSetup { frame_size } => {
327 insts.push(RawInst::PushFrame.into());
328 insts.extend(Self::gen_sp_reg_adjust(
329 -i32::try_from(*frame_size).unwrap(),
330 ));
331 }
332 FrameStyle::PulleySetupAndSaveClobbers {
333 frame_size,
334 saved_by_pulley,
335 } => insts.push(
336 RawInst::PushFrameSave {
337 amt: *frame_size,
338 regs: pulley_interpreter::UpperRegSet::from_bitset(*saved_by_pulley),
339 }
340 .into(),
341 ),
342 FrameStyle::Manual { frame_size } => insts.extend(Self::gen_sp_reg_adjust(
343 -i32::try_from(*frame_size).unwrap(),
344 )),
345 }
346
347 for (offset, ty, reg) in frame_layout.manually_managed_clobbers(&style) {
348 insts.push(
349 Inst::gen_store(Amode::SpOffset { offset }, reg, ty, MemFlags::trusted()).into(),
350 );
351 }
352
353 insts
354 }
355
356 fn gen_epilogue_frame_restore(
358 _call_conv: isa::CallConv,
359 _flags: &settings::Flags,
360 _isa_flags: &PulleyFlags,
361 frame_layout: &FrameLayout,
362 ) -> SmallInstVec<Self::I> {
363 let mut insts = SmallVec::new();
364
365 let style = frame_layout.pulley_frame_style();
366
367 for (offset, ty, reg) in frame_layout.manually_managed_clobbers(&style) {
369 insts.push(
370 Inst::gen_load(
371 Writable::from_reg(reg),
372 Amode::SpOffset { offset },
373 ty,
374 MemFlags::trusted(),
375 )
376 .into(),
377 );
378 }
379
380 match &style {
382 FrameStyle::None => {}
383 FrameStyle::PulleyBasicSetup { frame_size } => {
384 insts.extend(Self::gen_sp_reg_adjust(i32::try_from(*frame_size).unwrap()));
385 insts.push(RawInst::PopFrame.into());
386 }
387 FrameStyle::PulleySetupAndSaveClobbers {
388 frame_size,
389 saved_by_pulley,
390 } => insts.push(
391 RawInst::PopFrameRestore {
392 amt: *frame_size,
393 regs: pulley_interpreter::UpperRegSet::from_bitset(*saved_by_pulley),
394 }
395 .into(),
396 ),
397 FrameStyle::Manual { frame_size } => {
398 insts.extend(Self::gen_sp_reg_adjust(i32::try_from(*frame_size).unwrap()))
399 }
400 }
401
402 insts
403 }
404
405 fn gen_return(
406 call_conv: isa::CallConv,
407 _isa_flags: &PulleyFlags,
408 frame_layout: &FrameLayout,
409 ) -> SmallInstVec<Self::I> {
410 let mut insts = SmallVec::new();
411
412 if call_conv == isa::CallConv::Tail && frame_layout.tail_args_size > 0 {
414 insts.extend(Self::gen_sp_reg_adjust(
415 frame_layout.tail_args_size.try_into().unwrap(),
416 ));
417 }
418 insts.push(RawInst::Ret {}.into());
419
420 insts
421 }
422
423 fn gen_probestack(_insts: &mut SmallInstVec<Self::I>, _frame_size: u32) {
424 }
427
428 fn gen_clobber_save(
429 _call_conv: isa::CallConv,
430 _flags: &settings::Flags,
431 _frame_layout: &FrameLayout,
432 ) -> SmallVec<[Self::I; 16]> {
433 SmallVec::new()
436 }
437
438 fn gen_clobber_restore(
439 _call_conv: isa::CallConv,
440 _flags: &settings::Flags,
441 _frame_layout: &FrameLayout,
442 ) -> SmallVec<[Self::I; 16]> {
443 SmallVec::new()
445 }
446
447 fn gen_memcpy<F: FnMut(Type) -> Writable<Reg>>(
448 _call_conv: isa::CallConv,
449 _dst: Reg,
450 _src: Reg,
451 _size: usize,
452 _alloc_tmp: F,
453 ) -> SmallVec<[Self::I; 8]> {
454 todo!()
455 }
456
457 fn get_number_of_spillslots_for_value(
458 rc: RegClass,
459 _target_vector_bytes: u32,
460 _isa_flags: &PulleyFlags,
461 ) -> u32 {
462 let slots_for_8bytes = match P::pointer_width() {
466 PointerWidth::PointerWidth32 => 2,
467 PointerWidth::PointerWidth64 => 1,
468 };
469 match rc {
470 RegClass::Int | RegClass::Float => slots_for_8bytes,
472 RegClass::Vector => 2 * slots_for_8bytes,
474 }
475 }
476
477 fn get_machine_env(_flags: &settings::Flags, _call_conv: isa::CallConv) -> &MachineEnv {
478 static MACHINE_ENV: OnceLock<MachineEnv> = OnceLock::new();
479 MACHINE_ENV.get_or_init(create_reg_environment)
480 }
481
482 fn get_regs_clobbered_by_call(
483 _call_conv_of_callee: isa::CallConv,
484 is_exception: bool,
485 ) -> PRegSet {
486 if is_exception {
487 ALL_CLOBBERS
488 } else {
489 DEFAULT_CLOBBERS
490 }
491 }
492
493 fn compute_frame_layout(
494 _call_conv: isa::CallConv,
495 flags: &settings::Flags,
496 _sig: &Signature,
497 regs: &[Writable<RealReg>],
498 function_calls: FunctionCalls,
499 incoming_args_size: u32,
500 tail_args_size: u32,
501 stackslots_size: u32,
502 fixed_frame_storage_size: u32,
503 outgoing_args_size: u32,
504 ) -> FrameLayout {
505 let mut regs: Vec<Writable<RealReg>> = regs
506 .iter()
507 .cloned()
508 .filter(|r| DEFAULT_CALLEE_SAVES.contains(r.to_reg().into()))
509 .collect();
510
511 regs.sort_unstable();
512
513 let clobber_size = compute_clobber_size(®s);
515
516 let setup_area_size = if flags.preserve_frame_pointers()
518 || function_calls != FunctionCalls::None
519 || incoming_args_size > 0
522 || clobber_size > 0
523 || fixed_frame_storage_size > 0
524 {
525 P::pointer_width().bytes() * 2 } else {
527 0
528 };
529
530 FrameLayout {
531 word_bytes: u32::from(P::pointer_width().bytes()),
532 incoming_args_size,
533 tail_args_size,
534 setup_area_size: setup_area_size.into(),
535 clobber_size,
536 fixed_frame_storage_size,
537 stackslots_size,
538 outgoing_args_size,
539 clobbered_callee_saves: regs,
540 function_calls,
541 }
542 }
543
544 fn gen_inline_probestack(
545 _insts: &mut SmallInstVec<Self::I>,
546 _call_conv: isa::CallConv,
547 _frame_size: u32,
548 _guard_size: u32,
549 ) {
550 }
553
554 fn retval_temp_reg(_call_conv_of_callee: isa::CallConv) -> Writable<Reg> {
555 Writable::from_reg(regs::x_reg(15))
558 }
559
560 fn exception_payload_regs(_call_conv: isa::CallConv) -> &'static [Reg] {
561 const PAYLOAD_REGS: &'static [Reg] = &[
562 Reg::from_real_reg(regs::px_reg(0)),
563 Reg::from_real_reg(regs::px_reg(1)),
564 ];
565 PAYLOAD_REGS
566 }
567}
568
569enum FrameStyle {
574 None,
577
578 PulleyBasicSetup { frame_size: u32 },
581
582 PulleySetupAndSaveClobbers {
589 frame_size: u16,
591 saved_by_pulley: ScalarBitSet<u16>,
593 },
594
595 Manual {
600 frame_size: u32,
602 },
603}
604
605impl FrameLayout {
607 fn setup_frame(&self) -> bool {
609 self.setup_area_size > 0
610 }
611
612 fn stack_size(&self) -> u32 {
615 self.clobber_size + self.fixed_frame_storage_size + self.outgoing_args_size
616 }
617
618 fn pulley_frame_style(&self) -> FrameStyle {
622 let saved_by_pulley = self.clobbered_xregs_saved_by_pulley();
623 match (
624 self.stack_size(),
625 self.setup_frame(),
626 saved_by_pulley.is_empty(),
627 ) {
628 (0, false, true) => FrameStyle::None,
630
631 (0, true, true) => FrameStyle::PulleyBasicSetup { frame_size: 0 },
634
635 (frame_size, true, _) => match frame_size.try_into() {
642 Ok(frame_size) => FrameStyle::PulleySetupAndSaveClobbers {
643 frame_size,
644 saved_by_pulley,
645 },
646 Err(_) => FrameStyle::PulleyBasicSetup { frame_size },
647 },
648
649 (frame_size, false, true) => FrameStyle::Manual { frame_size },
652
653 (_, false, false) => unreachable!(),
656 }
657 }
658
659 fn clobbered_xregs_saved_by_pulley(&self) -> ScalarBitSet<u16> {
662 let mut clobbered: ScalarBitSet<u16> = ScalarBitSet::new();
663 if !self.setup_frame() {
665 return clobbered;
666 }
667 let mut found_manual_clobber = false;
668 for reg in self.clobbered_callee_saves.iter() {
669 let r_reg = reg.to_reg();
670 if r_reg.class() == RegClass::Int {
677 assert!(!found_manual_clobber);
678 if let Some(offset) = r_reg.hw_enc().checked_sub(16) {
679 clobbered.insert(offset);
680 }
681 } else {
682 found_manual_clobber = true;
683 }
684 }
685 clobbered
686 }
687
688 fn manually_managed_clobbers<'a>(
696 &'a self,
697 style: &'a FrameStyle,
698 ) -> impl Iterator<Item = (i32, Type, Reg)> + 'a {
699 let mut offset = self.stack_size();
700 self.clobbered_callee_saves.iter().filter_map(move |reg| {
701 offset -= 8;
706 let r_reg = reg.to_reg();
707 let ty = match r_reg.class() {
708 RegClass::Int => {
709 if let FrameStyle::PulleySetupAndSaveClobbers {
711 saved_by_pulley, ..
712 } = style
713 {
714 if let Some(reg) = r_reg.hw_enc().checked_sub(16) {
715 if saved_by_pulley.contains(reg) {
716 return None;
717 }
718 }
719 }
720 I64
721 }
722 RegClass::Float => F64,
723 RegClass::Vector => unreachable!("no vector registers are callee-save"),
724 };
725 let offset = i32::try_from(offset).unwrap();
726 Some((offset, ty, Reg::from(reg.to_reg())))
727 })
728 }
729}
730
731const DEFAULT_CALLEE_SAVES: PRegSet = PRegSet::empty()
732 .with(px_reg(16))
734 .with(px_reg(17))
735 .with(px_reg(18))
736 .with(px_reg(19))
737 .with(px_reg(20))
738 .with(px_reg(21))
739 .with(px_reg(22))
740 .with(px_reg(23))
741 .with(px_reg(24))
742 .with(px_reg(25))
743 .with(px_reg(26))
744 .with(px_reg(27))
745 .with(px_reg(28))
746 .with(px_reg(29))
747 .with(px_reg(30))
748 .with(px_reg(31))
749 ;
751
752fn compute_clobber_size(clobbers: &[Writable<RealReg>]) -> u32 {
753 let mut clobbered_size = 0;
754 for reg in clobbers {
755 match reg.to_reg().class() {
756 RegClass::Int => {
757 clobbered_size += 8;
758 }
759 RegClass::Float => {
760 clobbered_size += 8;
761 }
762 RegClass::Vector => unimplemented!("Vector Size Clobbered"),
763 }
764 }
765 align_to(clobbered_size, 16)
766}
767
768const DEFAULT_CLOBBERS: PRegSet = PRegSet::empty()
769 .with(px_reg(0))
771 .with(px_reg(1))
772 .with(px_reg(2))
773 .with(px_reg(3))
774 .with(px_reg(4))
775 .with(px_reg(5))
776 .with(px_reg(6))
777 .with(px_reg(7))
778 .with(px_reg(8))
779 .with(px_reg(9))
780 .with(px_reg(10))
781 .with(px_reg(11))
782 .with(px_reg(12))
783 .with(px_reg(13))
784 .with(px_reg(14))
785 .with(px_reg(15))
786 .with(pf_reg(0))
788 .with(pf_reg(1))
789 .with(pf_reg(2))
790 .with(pf_reg(3))
791 .with(pf_reg(4))
792 .with(pf_reg(5))
793 .with(pf_reg(6))
794 .with(pf_reg(7))
795 .with(pf_reg(8))
796 .with(pf_reg(9))
797 .with(pf_reg(10))
798 .with(pf_reg(11))
799 .with(pf_reg(12))
800 .with(pf_reg(13))
801 .with(pf_reg(14))
802 .with(pf_reg(15))
803 .with(pf_reg(16))
804 .with(pf_reg(17))
805 .with(pf_reg(18))
806 .with(pf_reg(19))
807 .with(pf_reg(20))
808 .with(pf_reg(21))
809 .with(pf_reg(22))
810 .with(pf_reg(23))
811 .with(pf_reg(24))
812 .with(pf_reg(25))
813 .with(pf_reg(26))
814 .with(pf_reg(27))
815 .with(pf_reg(28))
816 .with(pf_reg(29))
817 .with(pf_reg(30))
818 .with(pf_reg(31))
819 .with(pv_reg(0))
821 .with(pv_reg(1))
822 .with(pv_reg(2))
823 .with(pv_reg(3))
824 .with(pv_reg(4))
825 .with(pv_reg(5))
826 .with(pv_reg(6))
827 .with(pv_reg(7))
828 .with(pv_reg(8))
829 .with(pv_reg(9))
830 .with(pv_reg(10))
831 .with(pv_reg(11))
832 .with(pv_reg(12))
833 .with(pv_reg(13))
834 .with(pv_reg(14))
835 .with(pv_reg(15))
836 .with(pv_reg(16))
837 .with(pv_reg(17))
838 .with(pv_reg(18))
839 .with(pv_reg(19))
840 .with(pv_reg(20))
841 .with(pv_reg(21))
842 .with(pv_reg(22))
843 .with(pv_reg(23))
844 .with(pv_reg(24))
845 .with(pv_reg(25))
846 .with(pv_reg(26))
847 .with(pv_reg(27))
848 .with(pv_reg(28))
849 .with(pv_reg(29))
850 .with(pv_reg(30))
851 .with(pv_reg(31));
852
853const ALL_CLOBBERS: PRegSet = PRegSet::empty()
854 .with(px_reg(0))
855 .with(px_reg(1))
856 .with(px_reg(2))
857 .with(px_reg(3))
858 .with(px_reg(4))
859 .with(px_reg(5))
860 .with(px_reg(6))
861 .with(px_reg(7))
862 .with(px_reg(8))
863 .with(px_reg(9))
864 .with(px_reg(10))
865 .with(px_reg(11))
866 .with(px_reg(12))
867 .with(px_reg(13))
868 .with(px_reg(14))
869 .with(px_reg(15))
870 .with(px_reg(16))
871 .with(px_reg(17))
872 .with(px_reg(18))
873 .with(px_reg(19))
874 .with(px_reg(20))
875 .with(px_reg(21))
876 .with(px_reg(22))
877 .with(px_reg(23))
878 .with(px_reg(24))
879 .with(px_reg(25))
880 .with(px_reg(26))
881 .with(px_reg(27))
882 .with(px_reg(28))
883 .with(px_reg(29))
884 .with(px_reg(30))
885 .with(px_reg(31))
886 .with(pf_reg(0))
887 .with(pf_reg(1))
888 .with(pf_reg(2))
889 .with(pf_reg(3))
890 .with(pf_reg(4))
891 .with(pf_reg(5))
892 .with(pf_reg(6))
893 .with(pf_reg(7))
894 .with(pf_reg(8))
895 .with(pf_reg(9))
896 .with(pf_reg(10))
897 .with(pf_reg(11))
898 .with(pf_reg(12))
899 .with(pf_reg(13))
900 .with(pf_reg(14))
901 .with(pf_reg(15))
902 .with(pf_reg(16))
903 .with(pf_reg(17))
904 .with(pf_reg(18))
905 .with(pf_reg(19))
906 .with(pf_reg(20))
907 .with(pf_reg(21))
908 .with(pf_reg(22))
909 .with(pf_reg(23))
910 .with(pf_reg(24))
911 .with(pf_reg(25))
912 .with(pf_reg(26))
913 .with(pf_reg(27))
914 .with(pf_reg(28))
915 .with(pf_reg(29))
916 .with(pf_reg(30))
917 .with(pf_reg(31))
918 .with(pv_reg(0))
919 .with(pv_reg(1))
920 .with(pv_reg(2))
921 .with(pv_reg(3))
922 .with(pv_reg(4))
923 .with(pv_reg(5))
924 .with(pv_reg(6))
925 .with(pv_reg(7))
926 .with(pv_reg(8))
927 .with(pv_reg(9))
928 .with(pv_reg(10))
929 .with(pv_reg(11))
930 .with(pv_reg(12))
931 .with(pv_reg(13))
932 .with(pv_reg(14))
933 .with(pv_reg(15))
934 .with(pv_reg(16))
935 .with(pv_reg(17))
936 .with(pv_reg(18))
937 .with(pv_reg(19))
938 .with(pv_reg(20))
939 .with(pv_reg(21))
940 .with(pv_reg(22))
941 .with(pv_reg(23))
942 .with(pv_reg(24))
943 .with(pv_reg(25))
944 .with(pv_reg(26))
945 .with(pv_reg(27))
946 .with(pv_reg(28))
947 .with(pv_reg(29))
948 .with(pv_reg(30))
949 .with(pv_reg(31));
950
951fn create_reg_environment() -> MachineEnv {
952 let preferred_regs_by_class: [Vec<PReg>; 3] = {
957 let x_registers: Vec<PReg> = (0..16).map(|x| px_reg(x)).collect();
958 let f_registers: Vec<PReg> = (0..32).map(|x| pf_reg(x)).collect();
959 let v_registers: Vec<PReg> = (0..32).map(|x| pv_reg(x)).collect();
960 [x_registers, f_registers, v_registers]
961 };
962
963 let non_preferred_regs_by_class: [Vec<PReg>; 3] = {
964 let x_registers: Vec<PReg> = (16..XReg::SPECIAL_START)
965 .map(|x| px_reg(x.into()))
966 .collect();
967 let f_registers: Vec<PReg> = vec![];
968 let v_registers: Vec<PReg> = vec![];
969 [x_registers, f_registers, v_registers]
970 };
971
972 MachineEnv {
973 preferred_regs_by_class,
974 non_preferred_regs_by_class,
975 fixed_stack_slots: vec![],
976 scratch_by_class: [None, None, None],
977 }
978}