1use crate::ir;
4use crate::ir::types::*;
5
6use crate::isa;
7
8use crate::isa::CallConv;
9use crate::isa::riscv64::inst::*;
10use crate::machinst::*;
11
12use crate::CodegenResult;
13use crate::ir::LibCall;
14use crate::ir::Signature;
15use crate::isa::riscv64::settings::Flags as RiscvFlags;
16use crate::isa::unwind::UnwindInst;
17use crate::settings;
18use alloc::boxed::Box;
19use alloc::vec::Vec;
20use regalloc2::{MachineEnv, PReg, PRegSet};
21
22use smallvec::{SmallVec, smallvec};
23use std::borrow::ToOwned;
24use std::sync::OnceLock;
25
26pub(crate) type Riscv64Callee = Callee<Riscv64MachineDeps>;
28
29pub struct Riscv64MachineDeps;
32
33impl IsaFlags for RiscvFlags {}
34
35impl RiscvFlags {
36 pub(crate) fn min_vec_reg_size(&self) -> u64 {
37 let entries = [
38 (self.has_zvl65536b(), 65536),
39 (self.has_zvl32768b(), 32768),
40 (self.has_zvl16384b(), 16384),
41 (self.has_zvl8192b(), 8192),
42 (self.has_zvl4096b(), 4096),
43 (self.has_zvl2048b(), 2048),
44 (self.has_zvl1024b(), 1024),
45 (self.has_zvl512b(), 512),
46 (self.has_zvl256b(), 256),
47 (self.has_v(), 128),
50 (self.has_zvl128b(), 128),
51 (self.has_zvl64b(), 64),
52 (self.has_zvl32b(), 32),
53 ];
54
55 for (has_flag, size) in entries.into_iter() {
56 if !has_flag {
57 continue;
58 }
59
60 return std::cmp::min(size, 1024);
63 }
64
65 return 0;
66 }
67}
68
69impl ABIMachineSpec for Riscv64MachineDeps {
70 type I = Inst;
71 type F = RiscvFlags;
72
73 const STACK_ARG_RET_SIZE_LIMIT: u32 = 128 * 1024 * 1024;
77
78 fn word_bits() -> u32 {
79 64
80 }
81
82 fn stack_align(_call_conv: isa::CallConv) -> u32 {
84 16
85 }
86
87 fn compute_arg_locs(
88 call_conv: isa::CallConv,
89 flags: &settings::Flags,
90 params: &[ir::AbiParam],
91 args_or_rets: ArgsOrRets,
92 add_ret_area_ptr: bool,
93 mut args: ArgsAccumulator,
94 ) -> CodegenResult<(u32, Option<usize>)> {
95 assert_ne!(
98 call_conv,
99 isa::CallConv::Winch,
100 "riscv64 does not support the 'winch' calling convention yet"
101 );
102
103 let (x_start, x_end, f_start, f_end) = match args_or_rets {
106 ArgsOrRets::Args => (10, 17, 10, 17),
107 ArgsOrRets::Rets => (10, 11, 10, 11),
108 };
109 let mut next_x_reg = x_start;
110 let mut next_f_reg = f_start;
111 let mut next_stack: u32 = 0;
113
114 let ret_area_ptr = if add_ret_area_ptr {
115 assert!(ArgsOrRets::Args == args_or_rets);
116 next_x_reg += 1;
117 Some(ABIArg::reg(
118 x_reg(x_start).to_real_reg().unwrap(),
119 I64,
120 ir::ArgumentExtension::None,
121 ir::ArgumentPurpose::Normal,
122 ))
123 } else {
124 None
125 };
126
127 for param in params {
128 if let ir::ArgumentPurpose::StructArgument(_) = param.purpose {
129 panic!(
130 "StructArgument parameters are not supported on riscv64. \
131 Use regular pointer arguments instead."
132 );
133 }
134
135 let (rcs, reg_tys) = Inst::rc_for_type(param.value_type)?;
137 let mut slots = ABIArgSlotVec::new();
138 for (rc, reg_ty) in rcs.iter().zip(reg_tys.iter()) {
139 let next_reg = if (next_x_reg <= x_end) && *rc == RegClass::Int {
140 let x = Some(x_reg(next_x_reg));
141 next_x_reg += 1;
142 x
143 } else if (next_f_reg <= f_end) && *rc == RegClass::Float {
144 let x = Some(f_reg(next_f_reg));
145 next_f_reg += 1;
146 x
147 } else {
148 None
149 };
150 if let Some(reg) = next_reg {
151 slots.push(ABIArgSlot::Reg {
152 reg: reg.to_real_reg().unwrap(),
153 ty: *reg_ty,
154 extension: param.extension,
155 });
156 } else {
157 if args_or_rets == ArgsOrRets::Rets && !flags.enable_multi_ret_implicit_sret() {
158 return Err(crate::CodegenError::Unsupported(
159 "Too many return values to fit in registers. \
160 Use a StructReturn argument instead. (#9510)"
161 .to_owned(),
162 ));
163 }
164
165 let size = reg_ty.bits() / 8;
168 let size = std::cmp::max(size, 8);
169 debug_assert!(size.is_power_of_two());
171 next_stack = align_to(next_stack, size);
172 slots.push(ABIArgSlot::Stack {
173 offset: next_stack as i64,
174 ty: *reg_ty,
175 extension: param.extension,
176 });
177 next_stack += size;
178 }
179 }
180 args.push(ABIArg::Slots {
181 slots,
182 purpose: param.purpose,
183 });
184 }
185 let pos = if let Some(ret_area_ptr) = ret_area_ptr {
186 args.push_non_formal(ret_area_ptr);
187 Some(args.args().len() - 1)
188 } else {
189 None
190 };
191
192 next_stack = align_to(next_stack, Self::stack_align(call_conv));
193
194 Ok((next_stack, pos))
195 }
196
197 fn gen_load_stack(mem: StackAMode, into_reg: Writable<Reg>, ty: Type) -> Inst {
198 Inst::gen_load(into_reg, mem.into(), ty, MemFlags::trusted())
199 }
200
201 fn gen_store_stack(mem: StackAMode, from_reg: Reg, ty: Type) -> Inst {
202 Inst::gen_store(mem.into(), from_reg, ty, MemFlags::trusted())
203 }
204
205 fn gen_move(to_reg: Writable<Reg>, from_reg: Reg, ty: Type) -> Inst {
206 Inst::gen_move(to_reg, from_reg, ty)
207 }
208
209 fn gen_extend(
210 to_reg: Writable<Reg>,
211 from_reg: Reg,
212 signed: bool,
213 from_bits: u8,
214 to_bits: u8,
215 ) -> Inst {
216 assert!(from_bits < to_bits);
217 Inst::Extend {
218 rd: to_reg,
219 rn: from_reg,
220 signed,
221 from_bits,
222 to_bits,
223 }
224 }
225
226 fn get_ext_mode(
227 _call_conv: isa::CallConv,
228 specified: ir::ArgumentExtension,
229 ) -> ir::ArgumentExtension {
230 specified
231 }
232
233 fn gen_args(args: Vec<ArgPair>) -> Inst {
234 Inst::Args { args }
235 }
236
237 fn gen_rets(rets: Vec<RetPair>) -> Inst {
238 Inst::Rets { rets }
239 }
240
241 fn get_stacklimit_reg(_call_conv: isa::CallConv) -> Reg {
242 spilltmp_reg()
243 }
244
245 fn gen_add_imm(
246 _call_conv: isa::CallConv,
247 into_reg: Writable<Reg>,
248 from_reg: Reg,
249 imm: u32,
250 ) -> SmallInstVec<Inst> {
251 let mut insts = SmallInstVec::new();
252 if let Some(imm12) = Imm12::maybe_from_u64(imm as u64) {
253 insts.push(Inst::AluRRImm12 {
254 alu_op: AluOPRRI::Addi,
255 rd: into_reg,
256 rs: from_reg,
257 imm12,
258 });
259 } else {
260 insts.extend(Inst::load_constant_u32(
261 writable_spilltmp_reg2(),
262 imm as u64,
263 ));
264 insts.push(Inst::AluRRR {
265 alu_op: AluOPRRR::Add,
266 rd: into_reg,
267 rs1: spilltmp_reg2(),
268 rs2: from_reg,
269 });
270 }
271 insts
272 }
273
274 fn gen_stack_lower_bound_trap(limit_reg: Reg) -> SmallInstVec<Inst> {
275 let mut insts = SmallVec::new();
276 insts.push(Inst::TrapIf {
277 cc: IntCC::UnsignedLessThan,
278 rs1: stack_reg(),
279 rs2: limit_reg,
280 trap_code: ir::TrapCode::STACK_OVERFLOW,
281 });
282 insts
283 }
284
285 fn gen_get_stack_addr(mem: StackAMode, into_reg: Writable<Reg>) -> Inst {
286 Inst::LoadAddr {
287 rd: into_reg,
288 mem: mem.into(),
289 }
290 }
291
292 fn gen_load_base_offset(into_reg: Writable<Reg>, base: Reg, offset: i32, ty: Type) -> Inst {
293 let mem = AMode::RegOffset(base, offset as i64);
294 Inst::gen_load(into_reg, mem, ty, MemFlags::trusted())
295 }
296
297 fn gen_store_base_offset(base: Reg, offset: i32, from_reg: Reg, ty: Type) -> Inst {
298 let mem = AMode::RegOffset(base, offset as i64);
299 Inst::gen_store(mem, from_reg, ty, MemFlags::trusted())
300 }
301
302 fn gen_sp_reg_adjust(amount: i32) -> SmallInstVec<Inst> {
303 let mut insts = SmallVec::new();
304
305 if amount == 0 {
306 return insts;
307 }
308
309 if let Some(imm) = Imm12::maybe_from_i64(amount as i64) {
310 insts.push(Inst::AluRRImm12 {
311 alu_op: AluOPRRI::Addi,
312 rd: writable_stack_reg(),
313 rs: stack_reg(),
314 imm12: imm,
315 })
316 } else {
317 let tmp = writable_spilltmp_reg();
318 insts.extend(Inst::load_constant_u64(tmp, amount as i64 as u64));
319 insts.push(Inst::AluRRR {
320 alu_op: AluOPRRR::Add,
321 rd: writable_stack_reg(),
322 rs1: stack_reg(),
323 rs2: tmp.to_reg(),
324 });
325 }
326
327 insts
328 }
329
330 fn gen_prologue_frame_setup(
331 _call_conv: isa::CallConv,
332 flags: &settings::Flags,
333 _isa_flags: &RiscvFlags,
334 frame_layout: &FrameLayout,
335 ) -> SmallInstVec<Inst> {
336 let mut insts = SmallVec::new();
337
338 if frame_layout.setup_area_size > 0 {
339 insts.extend(Self::gen_sp_reg_adjust(-16));
344 insts.push(Inst::gen_store(
345 AMode::SPOffset(8),
346 link_reg(),
347 I64,
348 MemFlags::trusted(),
349 ));
350 insts.push(Inst::gen_store(
351 AMode::SPOffset(0),
352 fp_reg(),
353 I64,
354 MemFlags::trusted(),
355 ));
356
357 if flags.unwind_info() {
358 insts.push(Inst::Unwind {
359 inst: UnwindInst::PushFrameRegs {
360 offset_upward_to_caller_sp: frame_layout.setup_area_size,
361 },
362 });
363 }
364 insts.push(Inst::Mov {
365 rd: writable_fp_reg(),
366 rm: stack_reg(),
367 ty: I64,
368 });
369 }
370
371 insts
372 }
373 fn gen_epilogue_frame_restore(
375 call_conv: isa::CallConv,
376 _flags: &settings::Flags,
377 _isa_flags: &RiscvFlags,
378 frame_layout: &FrameLayout,
379 ) -> SmallInstVec<Inst> {
380 let mut insts = SmallVec::new();
381
382 if frame_layout.setup_area_size > 0 {
383 insts.push(Inst::gen_load(
384 writable_link_reg(),
385 AMode::SPOffset(8),
386 I64,
387 MemFlags::trusted(),
388 ));
389 insts.push(Inst::gen_load(
390 writable_fp_reg(),
391 AMode::SPOffset(0),
392 I64,
393 MemFlags::trusted(),
394 ));
395 insts.extend(Self::gen_sp_reg_adjust(16));
396 }
397
398 if call_conv == isa::CallConv::Tail && frame_layout.tail_args_size > 0 {
399 insts.extend(Self::gen_sp_reg_adjust(
400 frame_layout.tail_args_size.try_into().unwrap(),
401 ));
402 }
403
404 insts
405 }
406
407 fn gen_return(
408 _call_conv: isa::CallConv,
409 _isa_flags: &RiscvFlags,
410 _frame_layout: &FrameLayout,
411 ) -> SmallInstVec<Inst> {
412 smallvec![Inst::Ret {}]
413 }
414
415 fn gen_probestack(insts: &mut SmallInstVec<Self::I>, frame_size: u32) {
416 insts.extend(Inst::load_constant_u32(writable_a0(), frame_size as u64));
417 let mut info = CallInfo::empty(
418 ExternalName::LibCall(LibCall::Probestack),
419 CallConv::SystemV,
420 );
421 info.uses.push(CallArgPair {
422 vreg: a0(),
423 preg: a0(),
424 });
425 insts.push(Inst::Call {
426 info: Box::new(info),
427 });
428 }
429
430 fn gen_clobber_save(
431 _call_conv: isa::CallConv,
432 flags: &settings::Flags,
433 frame_layout: &FrameLayout,
434 ) -> SmallVec<[Inst; 16]> {
435 let mut insts = SmallVec::new();
436 let setup_frame = frame_layout.setup_area_size > 0;
437
438 let incoming_args_diff = frame_layout.tail_args_size - frame_layout.incoming_args_size;
439 if incoming_args_diff > 0 {
440 insts.extend(Self::gen_sp_reg_adjust(-(incoming_args_diff as i32)));
442
443 if setup_frame {
444 insts.push(Inst::gen_store(
447 AMode::SPOffset(8),
448 link_reg(),
449 I64,
450 MemFlags::trusted(),
451 ));
452 insts.push(Inst::gen_load(
453 writable_fp_reg(),
454 AMode::SPOffset(i64::from(incoming_args_diff)),
455 I64,
456 MemFlags::trusted(),
457 ));
458 insts.push(Inst::gen_store(
459 AMode::SPOffset(0),
460 fp_reg(),
461 I64,
462 MemFlags::trusted(),
463 ));
464
465 insts.push(Inst::gen_move(writable_fp_reg(), stack_reg(), I64));
467 }
468 }
469
470 if flags.unwind_info() && setup_frame {
471 insts.push(Inst::Unwind {
474 inst: UnwindInst::DefineNewFrame {
475 offset_downward_to_clobbers: frame_layout.clobber_size,
476 offset_upward_to_caller_sp: frame_layout.setup_area_size,
477 },
478 });
479 }
480
481 let stack_size = frame_layout.clobber_size
484 + frame_layout.fixed_frame_storage_size
485 + frame_layout.outgoing_args_size;
486
487 if stack_size > 0 {
490 insts.extend(Self::gen_sp_reg_adjust(-(stack_size as i32)));
491
492 let mut cur_offset = 8;
493 for reg in &frame_layout.clobbered_callee_saves {
494 let r_reg = reg.to_reg();
495 let ty = match r_reg.class() {
496 RegClass::Int => I64,
497 RegClass::Float => F64,
498 RegClass::Vector => unimplemented!("Vector Clobber Saves"),
499 };
500 insts.push(Inst::gen_store(
501 AMode::SPOffset((stack_size - cur_offset) as i64),
502 Reg::from(reg.to_reg()),
503 ty,
504 MemFlags::trusted(),
505 ));
506
507 if flags.unwind_info() {
508 insts.push(Inst::Unwind {
509 inst: UnwindInst::SaveReg {
510 clobber_offset: frame_layout.clobber_size - cur_offset,
511 reg: r_reg,
512 },
513 });
514 }
515
516 cur_offset += 8
517 }
518 }
519 insts
520 }
521
522 fn gen_clobber_restore(
523 _call_conv: isa::CallConv,
524 _flags: &settings::Flags,
525 frame_layout: &FrameLayout,
526 ) -> SmallVec<[Inst; 16]> {
527 let mut insts = SmallVec::new();
528
529 let stack_size = frame_layout.clobber_size
530 + frame_layout.fixed_frame_storage_size
531 + frame_layout.outgoing_args_size;
532
533 let mut cur_offset = 8;
534 for reg in &frame_layout.clobbered_callee_saves {
535 let rreg = reg.to_reg();
536 let ty = match rreg.class() {
537 RegClass::Int => I64,
538 RegClass::Float => F64,
539 RegClass::Vector => unimplemented!("Vector Clobber Restores"),
540 };
541 insts.push(Inst::gen_load(
542 reg.map(Reg::from),
543 AMode::SPOffset(i64::from(stack_size - cur_offset)),
544 ty,
545 MemFlags::trusted(),
546 ));
547 cur_offset += 8
548 }
549
550 if stack_size > 0 {
551 insts.extend(Self::gen_sp_reg_adjust(stack_size as i32));
552 }
553
554 insts
555 }
556
557 fn gen_memcpy<F: FnMut(Type) -> Writable<Reg>>(
558 call_conv: isa::CallConv,
559 dst: Reg,
560 src: Reg,
561 size: usize,
562 mut alloc_tmp: F,
563 ) -> SmallVec<[Self::I; 8]> {
564 let mut insts = SmallVec::new();
565 let arg0 = Writable::from_reg(x_reg(10));
566 let arg1 = Writable::from_reg(x_reg(11));
567 let arg2 = Writable::from_reg(x_reg(12));
568 let tmp = alloc_tmp(Self::word_type());
569 insts.extend(Inst::load_constant_u64(tmp, size as u64));
570 insts.push(Inst::Call {
571 info: Box::new(CallInfo {
572 dest: ExternalName::LibCall(LibCall::Memcpy),
573 uses: smallvec![
574 CallArgPair {
575 vreg: dst,
576 preg: arg0.to_reg()
577 },
578 CallArgPair {
579 vreg: src,
580 preg: arg1.to_reg()
581 },
582 CallArgPair {
583 vreg: tmp.to_reg(),
584 preg: arg2.to_reg()
585 }
586 ],
587 defs: smallvec![],
588 clobbers: Self::get_regs_clobbered_by_call(call_conv, false),
589 caller_conv: call_conv,
590 callee_conv: call_conv,
591 callee_pop_size: 0,
592 try_call_info: None,
593 }),
594 });
595 insts
596 }
597
598 fn get_number_of_spillslots_for_value(
599 rc: RegClass,
600 _target_vector_bytes: u32,
601 isa_flags: &RiscvFlags,
602 ) -> u32 {
603 match rc {
605 RegClass::Int => 1,
606 RegClass::Float => 1,
607 RegClass::Vector => (isa_flags.min_vec_reg_size() / 8) as u32,
608 }
609 }
610
611 fn get_machine_env(_flags: &settings::Flags, _call_conv: isa::CallConv) -> &MachineEnv {
612 static MACHINE_ENV: OnceLock<MachineEnv> = OnceLock::new();
613 MACHINE_ENV.get_or_init(create_reg_environment)
614 }
615
616 fn get_regs_clobbered_by_call(
617 call_conv_of_callee: isa::CallConv,
618 is_exception: bool,
619 ) -> PRegSet {
620 match call_conv_of_callee {
621 isa::CallConv::Tail if is_exception => ALL_CLOBBERS,
622 _ => DEFAULT_CLOBBERS,
623 }
624 }
625
626 fn compute_frame_layout(
627 _call_conv: isa::CallConv,
628 flags: &settings::Flags,
629 _sig: &Signature,
630 regs: &[Writable<RealReg>],
631 is_leaf: bool,
632 incoming_args_size: u32,
633 tail_args_size: u32,
634 stackslots_size: u32,
635 fixed_frame_storage_size: u32,
636 outgoing_args_size: u32,
637 ) -> FrameLayout {
638 let mut regs: Vec<Writable<RealReg>> = regs
639 .iter()
640 .cloned()
641 .filter(|r| DEFAULT_CALLEE_SAVES.contains(r.to_reg().into()))
642 .collect();
643
644 regs.sort_unstable();
645
646 let clobber_size = compute_clobber_size(®s);
648
649 let setup_area_size = if flags.preserve_frame_pointers()
651 || !is_leaf
652 || incoming_args_size > 0
655 || clobber_size > 0
656 || fixed_frame_storage_size > 0
657 {
658 16 } else {
660 0
661 };
662
663 FrameLayout {
665 incoming_args_size,
666 tail_args_size,
667 setup_area_size,
668 clobber_size,
669 fixed_frame_storage_size,
670 stackslots_size,
671 outgoing_args_size,
672 clobbered_callee_saves: regs,
673 }
674 }
675
676 fn gen_inline_probestack(
677 insts: &mut SmallInstVec<Self::I>,
678 _call_conv: isa::CallConv,
679 frame_size: u32,
680 guard_size: u32,
681 ) {
682 const PROBE_MAX_UNROLL: u32 = 3;
684
685 let probe_count = frame_size / guard_size;
688 if probe_count == 0 {
689 return;
691 }
692
693 let tmp = Writable::from_reg(x_reg(28)); if probe_count <= PROBE_MAX_UNROLL {
697 Self::gen_probestack_unroll(insts, tmp, guard_size, probe_count)
698 } else {
699 insts.push(Inst::StackProbeLoop {
700 guard_size,
701 probe_count,
702 tmp,
703 });
704 }
705 }
706
707 fn retval_temp_reg(_call_conv_of_callee: isa::CallConv) -> Writable<Reg> {
708 Writable::from_reg(regs::x_reg(12))
711 }
712
713 fn exception_payload_regs(call_conv: isa::CallConv) -> &'static [Reg] {
714 const PAYLOAD_REGS: &'static [Reg] = &[regs::a0(), regs::a1()];
715 match call_conv {
716 isa::CallConv::SystemV | isa::CallConv::Tail => PAYLOAD_REGS,
717 _ => &[],
718 }
719 }
720}
721
722const DEFAULT_CALLEE_SAVES: PRegSet = PRegSet::empty()
724 .with(px_reg(2))
726 .with(px_reg(8))
727 .with(px_reg(9))
728 .with(px_reg(18))
729 .with(px_reg(19))
730 .with(px_reg(20))
731 .with(px_reg(21))
732 .with(px_reg(22))
733 .with(px_reg(23))
734 .with(px_reg(24))
735 .with(px_reg(25))
736 .with(px_reg(26))
737 .with(px_reg(27))
738 .with(pf_reg(8))
740 .with(pf_reg(18))
741 .with(pf_reg(19))
742 .with(pf_reg(20))
743 .with(pf_reg(21))
744 .with(pf_reg(22))
745 .with(pf_reg(23))
746 .with(pf_reg(24))
747 .with(pf_reg(25))
748 .with(pf_reg(26))
749 .with(pf_reg(27));
750
751fn compute_clobber_size(clobbers: &[Writable<RealReg>]) -> u32 {
752 let mut clobbered_size = 0;
753 for reg in clobbers {
754 match reg.to_reg().class() {
755 RegClass::Int => {
756 clobbered_size += 8;
757 }
758 RegClass::Float => {
759 clobbered_size += 8;
760 }
761 RegClass::Vector => unimplemented!("Vector Size Clobbered"),
762 }
763 }
764 align_to(clobbered_size, 16)
765}
766
767const DEFAULT_CLOBBERS: PRegSet = PRegSet::empty()
768 .with(px_reg(1))
769 .with(px_reg(5))
770 .with(px_reg(6))
771 .with(px_reg(7))
772 .with(px_reg(10))
773 .with(px_reg(11))
774 .with(px_reg(12))
775 .with(px_reg(13))
776 .with(px_reg(14))
777 .with(px_reg(15))
778 .with(px_reg(16))
779 .with(px_reg(17))
780 .with(px_reg(28))
781 .with(px_reg(29))
782 .with(px_reg(30))
783 .with(px_reg(31))
784 .with(pf_reg(0))
786 .with(pf_reg(1))
787 .with(pf_reg(2))
788 .with(pf_reg(3))
789 .with(pf_reg(4))
790 .with(pf_reg(5))
791 .with(pf_reg(6))
792 .with(pf_reg(7))
793 .with(pf_reg(9))
794 .with(pf_reg(10))
795 .with(pf_reg(11))
796 .with(pf_reg(12))
797 .with(pf_reg(13))
798 .with(pf_reg(14))
799 .with(pf_reg(15))
800 .with(pf_reg(16))
801 .with(pf_reg(17))
802 .with(pf_reg(28))
803 .with(pf_reg(29))
804 .with(pf_reg(30))
805 .with(pf_reg(31))
806 .with(pv_reg(0))
808 .with(pv_reg(1))
809 .with(pv_reg(2))
810 .with(pv_reg(3))
811 .with(pv_reg(4))
812 .with(pv_reg(5))
813 .with(pv_reg(6))
814 .with(pv_reg(7))
815 .with(pv_reg(8))
816 .with(pv_reg(9))
817 .with(pv_reg(10))
818 .with(pv_reg(11))
819 .with(pv_reg(12))
820 .with(pv_reg(13))
821 .with(pv_reg(14))
822 .with(pv_reg(15))
823 .with(pv_reg(16))
824 .with(pv_reg(17))
825 .with(pv_reg(18))
826 .with(pv_reg(19))
827 .with(pv_reg(20))
828 .with(pv_reg(21))
829 .with(pv_reg(22))
830 .with(pv_reg(23))
831 .with(pv_reg(24))
832 .with(pv_reg(25))
833 .with(pv_reg(26))
834 .with(pv_reg(27))
835 .with(pv_reg(28))
836 .with(pv_reg(29))
837 .with(pv_reg(30))
838 .with(pv_reg(31));
839
840const ALL_CLOBBERS: PRegSet = PRegSet::empty()
841 .with(px_reg(3))
843 .with(px_reg(4))
844 .with(px_reg(5))
845 .with(px_reg(6))
846 .with(px_reg(7))
847 .with(px_reg(8))
848 .with(px_reg(9))
849 .with(px_reg(10))
850 .with(px_reg(11))
851 .with(px_reg(12))
852 .with(px_reg(13))
853 .with(px_reg(14))
854 .with(px_reg(15))
855 .with(px_reg(16))
856 .with(px_reg(17))
857 .with(px_reg(18))
858 .with(px_reg(19))
859 .with(px_reg(20))
860 .with(px_reg(21))
861 .with(px_reg(22))
862 .with(px_reg(23))
863 .with(px_reg(24))
864 .with(px_reg(25))
865 .with(px_reg(26))
866 .with(px_reg(27))
867 .with(px_reg(28))
868 .with(px_reg(29))
869 .with(px_reg(30))
870 .with(px_reg(31))
871 .with(pf_reg(0))
873 .with(pf_reg(1))
874 .with(pf_reg(2))
875 .with(pf_reg(3))
876 .with(pf_reg(4))
877 .with(pf_reg(5))
878 .with(pf_reg(6))
879 .with(pf_reg(7))
880 .with(pf_reg(8))
881 .with(pf_reg(9))
882 .with(pf_reg(10))
883 .with(pf_reg(11))
884 .with(pf_reg(12))
885 .with(pf_reg(13))
886 .with(pf_reg(14))
887 .with(pf_reg(15))
888 .with(pf_reg(16))
889 .with(pf_reg(17))
890 .with(pf_reg(18))
891 .with(pf_reg(19))
892 .with(pf_reg(20))
893 .with(pf_reg(21))
894 .with(pf_reg(22))
895 .with(pf_reg(23))
896 .with(pf_reg(24))
897 .with(pf_reg(25))
898 .with(pf_reg(26))
899 .with(pf_reg(27))
900 .with(pf_reg(28))
901 .with(pf_reg(29))
902 .with(pf_reg(30))
903 .with(pf_reg(31))
904 .with(pv_reg(0))
906 .with(pv_reg(1))
907 .with(pv_reg(2))
908 .with(pv_reg(3))
909 .with(pv_reg(4))
910 .with(pv_reg(5))
911 .with(pv_reg(6))
912 .with(pv_reg(7))
913 .with(pv_reg(8))
914 .with(pv_reg(9))
915 .with(pv_reg(10))
916 .with(pv_reg(11))
917 .with(pv_reg(12))
918 .with(pv_reg(13))
919 .with(pv_reg(14))
920 .with(pv_reg(15))
921 .with(pv_reg(16))
922 .with(pv_reg(17))
923 .with(pv_reg(18))
924 .with(pv_reg(19))
925 .with(pv_reg(20))
926 .with(pv_reg(21))
927 .with(pv_reg(22))
928 .with(pv_reg(23))
929 .with(pv_reg(24))
930 .with(pv_reg(25))
931 .with(pv_reg(26))
932 .with(pv_reg(27))
933 .with(pv_reg(28))
934 .with(pv_reg(29))
935 .with(pv_reg(30))
936 .with(pv_reg(31));
937
938fn create_reg_environment() -> MachineEnv {
939 let preferred_regs_by_class: [Vec<PReg>; 3] = {
950 let x_registers: Vec<PReg> = (10..=15).map(px_reg).collect();
951 let f_registers: Vec<PReg> = (10..=15).map(pf_reg).collect();
952 let v_registers: Vec<PReg> = (8..=15).map(pv_reg).collect();
953
954 [x_registers, f_registers, v_registers]
955 };
956
957 let non_preferred_regs_by_class: [Vec<PReg>; 3] = {
958 let x_registers: Vec<PReg> = (5..=7)
963 .chain(16..=17)
964 .chain(28..=29)
965 .chain(9..=9)
968 .chain(18..=27)
970 .map(px_reg)
971 .collect();
972
973 let f_registers: Vec<PReg> = (0..=7)
975 .chain(16..=17)
976 .chain(28..=31)
977 .chain(8..=9)
980 .chain(18..=27)
981 .map(pf_reg)
982 .collect();
983
984 let v_registers = (0..=7).chain(16..=31).map(pv_reg).collect();
985
986 [x_registers, f_registers, v_registers]
987 };
988
989 MachineEnv {
990 preferred_regs_by_class,
991 non_preferred_regs_by_class,
992 fixed_stack_slots: vec![],
993 scratch_by_class: [None, None, None],
994 }
995}
996
997impl Riscv64MachineDeps {
998 fn gen_probestack_unroll(
999 insts: &mut SmallInstVec<Inst>,
1000 tmp: Writable<Reg>,
1001 guard_size: u32,
1002 probe_count: u32,
1003 ) {
1004 insts.extend(Inst::load_constant_u64(tmp, (-(guard_size as i64)) as u64));
1016
1017 for _ in 0..probe_count {
1018 insts.push(Inst::AluRRR {
1019 alu_op: AluOPRRR::Add,
1020 rd: writable_stack_reg(),
1021 rs1: stack_reg(),
1022 rs2: tmp.to_reg(),
1023 });
1024
1025 insts.push(Inst::gen_store(
1026 AMode::SPOffset(0),
1027 zero_reg(),
1028 I32,
1029 MemFlags::trusted(),
1030 ));
1031 }
1032
1033 insts.extend(Self::gen_sp_reg_adjust((guard_size * probe_count) as i32));
1035 }
1036}