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