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 if flags.unwind_info() && setup_frame {
441 insts.push(Inst::Unwind {
449 inst: UnwindInst::DefineNewFrame {
450 offset_downward_to_clobbers: frame_layout.clobber_size,
451 offset_upward_to_caller_sp: frame_layout.setup_area_size,
452 },
453 });
454 }
455
456 let incoming_args_diff = frame_layout.tail_args_size - frame_layout.incoming_args_size;
457 if incoming_args_diff > 0 {
458 insts.extend(Self::gen_sp_reg_adjust(-(incoming_args_diff as i32)));
460
461 if setup_frame {
462 insts.push(Inst::gen_store(
465 AMode::SPOffset(8),
466 link_reg(),
467 I64,
468 MemFlagsData::trusted(),
469 ));
470 insts.push(Inst::gen_load(
474 writable_spilltmp_reg(),
475 AMode::SPOffset(i64::from(incoming_args_diff)),
476 I64,
477 MemFlagsData::trusted(),
478 ));
479 insts.push(Inst::gen_store(
480 AMode::SPOffset(0),
481 spilltmp_reg(),
482 I64,
483 MemFlagsData::trusted(),
484 ));
485
486 insts.push(Inst::gen_move(writable_fp_reg(), stack_reg(), I64));
488 }
489 }
490
491 let stack_size = frame_layout.clobber_size
494 + frame_layout.fixed_frame_storage_size
495 + frame_layout.outgoing_args_size;
496
497 if stack_size > 0 {
500 insts.extend(Self::gen_sp_reg_adjust(-(stack_size as i32)));
501
502 let mut cur_offset = 0;
503 for reg in &frame_layout.clobbered_callee_saves {
504 let r_reg = reg.to_reg();
505 let ty = match r_reg.class() {
506 RegClass::Int => I64,
507 RegClass::Float => F64,
508 RegClass::Vector => I8X16,
509 };
510 cur_offset = align_to(cur_offset, ty.bytes());
511 insts.push(Inst::gen_store(
512 AMode::SPOffset(i64::from(stack_size - cur_offset - ty.bytes())),
513 Reg::from(reg.to_reg()),
514 ty,
515 MemFlagsData::trusted(),
516 ));
517
518 if flags.unwind_info() {
519 insts.push(Inst::Unwind {
520 inst: UnwindInst::SaveReg {
521 clobber_offset: frame_layout.clobber_size - cur_offset - ty.bytes(),
522 reg: r_reg,
523 },
524 });
525 }
526
527 cur_offset += ty.bytes();
528 assert!(cur_offset <= stack_size);
529 }
530 }
531 insts
532 }
533
534 fn gen_clobber_restore(
535 _call_conv: isa::CallConv,
536 _flags: &settings::Flags,
537 frame_layout: &FrameLayout,
538 ) -> SmallVec<[Inst; 16]> {
539 let mut insts = SmallVec::new();
540
541 let stack_size = frame_layout.clobber_size
542 + frame_layout.fixed_frame_storage_size
543 + frame_layout.outgoing_args_size;
544 let mut cur_offset = 0;
545
546 for reg in &frame_layout.clobbered_callee_saves {
547 let rreg = reg.to_reg();
548 let ty = match rreg.class() {
549 RegClass::Int => I64,
550 RegClass::Float => F64,
551 RegClass::Vector => I8X16,
552 };
553 cur_offset = align_to(cur_offset, ty.bytes());
554 insts.push(Inst::gen_load(
555 reg.map(Reg::from),
556 AMode::SPOffset(i64::from(stack_size - cur_offset - ty.bytes())),
557 ty,
558 MemFlagsData::trusted(),
559 ));
560 cur_offset += ty.bytes();
561 }
562
563 if stack_size > 0 {
564 insts.extend(Self::gen_sp_reg_adjust(stack_size as i32));
565 }
566
567 insts
568 }
569
570 fn gen_memcpy<F: FnMut(Type) -> Writable<Reg>>(
571 call_conv: isa::CallConv,
572 dst: Reg,
573 src: Reg,
574 size: usize,
575 mut alloc_tmp: F,
576 ) -> SmallVec<[Self::I; 8]> {
577 let mut insts = SmallVec::new();
578 let arg0 = Writable::from_reg(x_reg(10));
579 let arg1 = Writable::from_reg(x_reg(11));
580 let arg2 = Writable::from_reg(x_reg(12));
581 let tmp = alloc_tmp(Self::word_type());
582 insts.extend(Inst::load_constant_u64(tmp, size as u64));
583 insts.push(Inst::Call {
584 info: Box::new(CallInfo {
585 dest: ExternalName::LibCall(LibCall::Memcpy),
586 uses: smallvec![
587 CallArgPair {
588 vreg: dst,
589 preg: arg0.to_reg()
590 },
591 CallArgPair {
592 vreg: src,
593 preg: arg1.to_reg()
594 },
595 CallArgPair {
596 vreg: tmp.to_reg(),
597 preg: arg2.to_reg()
598 }
599 ],
600 defs: smallvec![],
601 clobbers: Self::get_regs_clobbered_by_call(call_conv, false),
602 caller_conv: call_conv,
603 callee_conv: call_conv,
604 callee_pop_size: 0,
605 try_call_info: None,
606 patchable: false,
607 }),
608 });
609 insts
610 }
611
612 fn get_number_of_spillslots_for_value(
613 rc: RegClass,
614 _target_vector_bytes: u32,
615 isa_flags: &RiscvFlags,
616 ) -> u32 {
617 match rc {
619 RegClass::Int => 1,
620 RegClass::Float => 1,
621 RegClass::Vector => (isa_flags.min_vec_reg_size() / 8) as u32,
622 }
623 }
624
625 fn get_machine_env(_flags: &settings::Flags, _call_conv: isa::CallConv) -> &MachineEnv {
626 static MACHINE_ENV: MachineEnv = create_reg_environment();
627 &MACHINE_ENV
628 }
629
630 fn get_regs_clobbered_by_call(
631 call_conv_of_callee: isa::CallConv,
632 is_exception: bool,
633 ) -> PRegSet {
634 match call_conv_of_callee {
635 isa::CallConv::Tail if is_exception => ALL_CLOBBERS,
636 isa::CallConv::PreserveAll if is_exception => ALL_CLOBBERS,
642 isa::CallConv::PreserveAll => NO_CLOBBERS,
643 _ => DEFAULT_CLOBBERS,
644 }
645 }
646
647 fn compute_frame_layout(
648 call_conv: isa::CallConv,
649 flags: &settings::Flags,
650 _sig: &Signature,
651 regs: &[Writable<RealReg>],
652 function_calls: FunctionCalls,
653 incoming_args_size: u32,
654 tail_args_size: u32,
655 stackslots_size: u32,
656 fixed_frame_storage_size: u32,
657 outgoing_args_size: u32,
658 ) -> FrameLayout {
659 let is_callee_saved = |reg: &Writable<RealReg>| match call_conv {
660 isa::CallConv::PreserveAll => true,
661 _ => DEFAULT_CALLEE_SAVES.contains(reg.to_reg().into()),
662 };
663 let mut regs: Vec<Writable<RealReg>> =
664 regs.iter().cloned().filter(is_callee_saved).collect();
665
666 regs.sort_unstable();
667
668 let clobber_size = compute_clobber_size(®s);
670
671 let setup_area_size = if flags.preserve_frame_pointers()
673 || function_calls != FunctionCalls::None
674 || incoming_args_size > 0
677 || clobber_size > 0
678 || fixed_frame_storage_size > 0
679 {
680 16 } else {
682 0
683 };
684
685 FrameLayout {
687 word_bytes: 8,
688 incoming_args_size,
689 tail_args_size,
690 setup_area_size,
691 clobber_size,
692 fixed_frame_storage_size,
693 stackslots_size,
694 outgoing_args_size,
695 clobbered_callee_saves: regs,
696 function_calls,
697 }
698 }
699
700 fn gen_inline_probestack(
701 insts: &mut SmallInstVec<Self::I>,
702 call_conv: isa::CallConv,
703 frame_size: u32,
704 guard_size: u32,
705 ) {
706 const PROBE_MAX_UNROLL: u32 = 3;
708
709 let probe_count = frame_size / guard_size;
712 if probe_count == 0 {
713 return;
715 }
716
717 if call_conv == isa::CallConv::PreserveAll {
723 Self::gen_probestack_unroll(insts, writable_spilltmp_reg2(), guard_size, probe_count);
724 return;
725 }
726
727 let tmp = Writable::from_reg(x_reg(28)); if probe_count <= PROBE_MAX_UNROLL {
731 Self::gen_probestack_unroll(insts, tmp, guard_size, probe_count)
732 } else {
733 insts.push(Inst::StackProbeLoop {
734 guard_size,
735 probe_count,
736 tmp,
737 });
738 }
739 }
740
741 fn retval_temp_reg(_call_conv_of_callee: isa::CallConv) -> Writable<Reg> {
742 Writable::from_reg(regs::x_reg(12))
745 }
746
747 fn exception_payload_regs(call_conv: isa::CallConv) -> &'static [Reg] {
748 const PAYLOAD_REGS: &'static [Reg] = &[regs::a0(), regs::a1()];
749 match call_conv {
750 isa::CallConv::SystemV | isa::CallConv::Tail | isa::CallConv::PreserveAll => {
751 PAYLOAD_REGS
752 }
753 _ => &[],
754 }
755 }
756}
757
758const DEFAULT_CALLEE_SAVES: PRegSet = PRegSet::empty()
760 .with(px_reg(2))
762 .with(px_reg(8))
763 .with(px_reg(9))
764 .with(px_reg(18))
765 .with(px_reg(19))
766 .with(px_reg(20))
767 .with(px_reg(21))
768 .with(px_reg(22))
769 .with(px_reg(23))
770 .with(px_reg(24))
771 .with(px_reg(25))
772 .with(px_reg(26))
773 .with(px_reg(27))
774 .with(pf_reg(8))
776 .with(pf_reg(18))
777 .with(pf_reg(19))
778 .with(pf_reg(20))
779 .with(pf_reg(21))
780 .with(pf_reg(22))
781 .with(pf_reg(23))
782 .with(pf_reg(24))
783 .with(pf_reg(25))
784 .with(pf_reg(26))
785 .with(pf_reg(27));
786
787fn compute_clobber_size(clobbers: &[Writable<RealReg>]) -> u32 {
788 let mut clobbered_size = 0;
789 for reg in clobbers {
790 match reg.to_reg().class() {
791 RegClass::Int => {
792 clobbered_size += 8;
793 }
794 RegClass::Float => {
795 clobbered_size += 8;
796 }
797 RegClass::Vector => {
798 clobbered_size = align_to(clobbered_size, 16);
799 clobbered_size += 16;
800 }
801 }
802 }
803 align_to(clobbered_size, 16)
804}
805
806const DEFAULT_CLOBBERS: PRegSet = PRegSet::empty()
807 .with(px_reg(1))
808 .with(px_reg(5))
809 .with(px_reg(6))
810 .with(px_reg(7))
811 .with(px_reg(10))
812 .with(px_reg(11))
813 .with(px_reg(12))
814 .with(px_reg(13))
815 .with(px_reg(14))
816 .with(px_reg(15))
817 .with(px_reg(16))
818 .with(px_reg(17))
819 .with(px_reg(28))
820 .with(px_reg(29))
821 .with(px_reg(30))
822 .with(px_reg(31))
823 .with(pf_reg(0))
825 .with(pf_reg(1))
826 .with(pf_reg(2))
827 .with(pf_reg(3))
828 .with(pf_reg(4))
829 .with(pf_reg(5))
830 .with(pf_reg(6))
831 .with(pf_reg(7))
832 .with(pf_reg(9))
833 .with(pf_reg(10))
834 .with(pf_reg(11))
835 .with(pf_reg(12))
836 .with(pf_reg(13))
837 .with(pf_reg(14))
838 .with(pf_reg(15))
839 .with(pf_reg(16))
840 .with(pf_reg(17))
841 .with(pf_reg(28))
842 .with(pf_reg(29))
843 .with(pf_reg(30))
844 .with(pf_reg(31))
845 .with(pv_reg(0))
847 .with(pv_reg(1))
848 .with(pv_reg(2))
849 .with(pv_reg(3))
850 .with(pv_reg(4))
851 .with(pv_reg(5))
852 .with(pv_reg(6))
853 .with(pv_reg(7))
854 .with(pv_reg(8))
855 .with(pv_reg(9))
856 .with(pv_reg(10))
857 .with(pv_reg(11))
858 .with(pv_reg(12))
859 .with(pv_reg(13))
860 .with(pv_reg(14))
861 .with(pv_reg(15))
862 .with(pv_reg(16))
863 .with(pv_reg(17))
864 .with(pv_reg(18))
865 .with(pv_reg(19))
866 .with(pv_reg(20))
867 .with(pv_reg(21))
868 .with(pv_reg(22))
869 .with(pv_reg(23))
870 .with(pv_reg(24))
871 .with(pv_reg(25))
872 .with(pv_reg(26))
873 .with(pv_reg(27))
874 .with(pv_reg(28))
875 .with(pv_reg(29))
876 .with(pv_reg(30))
877 .with(pv_reg(31));
878
879const ALL_CLOBBERS: PRegSet = PRegSet::empty()
880 .with(px_reg(3))
882 .with(px_reg(4))
883 .with(px_reg(5))
884 .with(px_reg(6))
885 .with(px_reg(7))
886 .with(px_reg(8))
887 .with(px_reg(9))
888 .with(px_reg(10))
889 .with(px_reg(11))
890 .with(px_reg(12))
891 .with(px_reg(13))
892 .with(px_reg(14))
893 .with(px_reg(15))
894 .with(px_reg(16))
895 .with(px_reg(17))
896 .with(px_reg(18))
897 .with(px_reg(19))
898 .with(px_reg(20))
899 .with(px_reg(21))
900 .with(px_reg(22))
901 .with(px_reg(23))
902 .with(px_reg(24))
903 .with(px_reg(25))
904 .with(px_reg(26))
905 .with(px_reg(27))
906 .with(px_reg(28))
907 .with(px_reg(29))
908 .with(px_reg(30))
909 .with(px_reg(31))
910 .with(pf_reg(0))
912 .with(pf_reg(1))
913 .with(pf_reg(2))
914 .with(pf_reg(3))
915 .with(pf_reg(4))
916 .with(pf_reg(5))
917 .with(pf_reg(6))
918 .with(pf_reg(7))
919 .with(pf_reg(8))
920 .with(pf_reg(9))
921 .with(pf_reg(10))
922 .with(pf_reg(11))
923 .with(pf_reg(12))
924 .with(pf_reg(13))
925 .with(pf_reg(14))
926 .with(pf_reg(15))
927 .with(pf_reg(16))
928 .with(pf_reg(17))
929 .with(pf_reg(18))
930 .with(pf_reg(19))
931 .with(pf_reg(20))
932 .with(pf_reg(21))
933 .with(pf_reg(22))
934 .with(pf_reg(23))
935 .with(pf_reg(24))
936 .with(pf_reg(25))
937 .with(pf_reg(26))
938 .with(pf_reg(27))
939 .with(pf_reg(28))
940 .with(pf_reg(29))
941 .with(pf_reg(30))
942 .with(pf_reg(31))
943 .with(pv_reg(0))
945 .with(pv_reg(1))
946 .with(pv_reg(2))
947 .with(pv_reg(3))
948 .with(pv_reg(4))
949 .with(pv_reg(5))
950 .with(pv_reg(6))
951 .with(pv_reg(7))
952 .with(pv_reg(8))
953 .with(pv_reg(9))
954 .with(pv_reg(10))
955 .with(pv_reg(11))
956 .with(pv_reg(12))
957 .with(pv_reg(13))
958 .with(pv_reg(14))
959 .with(pv_reg(15))
960 .with(pv_reg(16))
961 .with(pv_reg(17))
962 .with(pv_reg(18))
963 .with(pv_reg(19))
964 .with(pv_reg(20))
965 .with(pv_reg(21))
966 .with(pv_reg(22))
967 .with(pv_reg(23))
968 .with(pv_reg(24))
969 .with(pv_reg(25))
970 .with(pv_reg(26))
971 .with(pv_reg(27))
972 .with(pv_reg(28))
973 .with(pv_reg(29))
974 .with(pv_reg(30))
975 .with(pv_reg(31));
976
977const NO_CLOBBERS: PRegSet = PRegSet::empty();
978
979const fn create_reg_environment() -> MachineEnv {
980 let preferred_regs_by_class: [PRegSet; 3] = [
991 PRegSet::empty()
992 .with(px_reg(10))
993 .with(px_reg(11))
994 .with(px_reg(12))
995 .with(px_reg(13))
996 .with(px_reg(14))
997 .with(px_reg(15)),
998 PRegSet::empty()
999 .with(pf_reg(10))
1000 .with(pf_reg(11))
1001 .with(pf_reg(12))
1002 .with(pf_reg(13))
1003 .with(pf_reg(14))
1004 .with(pf_reg(15)),
1005 PRegSet::empty()
1006 .with(pv_reg(8))
1007 .with(pv_reg(9))
1008 .with(pv_reg(10))
1009 .with(pv_reg(11))
1010 .with(pv_reg(12))
1011 .with(pv_reg(13))
1012 .with(pv_reg(14))
1013 .with(pv_reg(15)),
1014 ];
1015
1016 let non_preferred_regs_by_class: [PRegSet; 3] = [
1017 PRegSet::empty()
1020 .with(px_reg(5))
1021 .with(px_reg(6))
1022 .with(px_reg(7))
1023 .with(px_reg(16))
1025 .with(px_reg(17))
1026 .with(px_reg(28))
1027 .with(px_reg(29))
1028 .with(px_reg(9))
1031 .with(px_reg(18))
1033 .with(px_reg(19))
1034 .with(px_reg(20))
1035 .with(px_reg(21))
1036 .with(px_reg(22))
1037 .with(px_reg(23))
1038 .with(px_reg(24))
1039 .with(px_reg(25))
1040 .with(px_reg(26))
1041 .with(px_reg(27)),
1042 PRegSet::empty()
1044 .with(pf_reg(0))
1045 .with(pf_reg(1))
1046 .with(pf_reg(2))
1047 .with(pf_reg(3))
1048 .with(pf_reg(4))
1049 .with(pf_reg(5))
1050 .with(pf_reg(6))
1051 .with(pf_reg(7))
1052 .with(pf_reg(16))
1053 .with(pf_reg(17))
1054 .with(pf_reg(28))
1055 .with(pf_reg(29))
1056 .with(pf_reg(30))
1057 .with(pf_reg(31))
1058 .with(pf_reg(8))
1061 .with(pf_reg(9))
1062 .with(pf_reg(18))
1063 .with(pf_reg(19))
1064 .with(pf_reg(20))
1065 .with(pf_reg(21))
1066 .with(pf_reg(22))
1067 .with(pf_reg(23))
1068 .with(pf_reg(24))
1069 .with(pf_reg(25))
1070 .with(pf_reg(26))
1071 .with(pf_reg(27)),
1072 PRegSet::empty()
1073 .with(pv_reg(0))
1074 .with(pv_reg(1))
1075 .with(pv_reg(2))
1076 .with(pv_reg(3))
1077 .with(pv_reg(4))
1078 .with(pv_reg(5))
1079 .with(pv_reg(6))
1080 .with(pv_reg(7))
1081 .with(pv_reg(16))
1082 .with(pv_reg(17))
1083 .with(pv_reg(18))
1084 .with(pv_reg(19))
1085 .with(pv_reg(20))
1086 .with(pv_reg(21))
1087 .with(pv_reg(22))
1088 .with(pv_reg(23))
1089 .with(pv_reg(24))
1090 .with(pv_reg(25))
1091 .with(pv_reg(26))
1092 .with(pv_reg(27))
1093 .with(pv_reg(28))
1094 .with(pv_reg(29))
1095 .with(pv_reg(30))
1096 .with(pv_reg(31)),
1097 ];
1098
1099 MachineEnv {
1100 preferred_regs_by_class,
1101 non_preferred_regs_by_class,
1102 fixed_stack_slots: vec![],
1103 scratch_by_class: [None, None, None],
1104 }
1105}
1106
1107impl Riscv64MachineDeps {
1108 fn gen_probestack_unroll(
1109 insts: &mut SmallInstVec<Inst>,
1110 tmp: Writable<Reg>,
1111 guard_size: u32,
1112 probe_count: u32,
1113 ) {
1114 insts.extend(Inst::load_constant_u64(tmp, (-(guard_size as i64)) as u64));
1126
1127 for _ in 0..probe_count {
1128 insts.push(Inst::AluRRR {
1129 alu_op: AluOPRRR::Add,
1130 rd: writable_stack_reg(),
1131 rs1: stack_reg(),
1132 rs2: tmp.to_reg(),
1133 });
1134
1135 insts.push(Inst::gen_store(
1136 AMode::SPOffset(0),
1137 zero_reg(),
1138 I32,
1139 MemFlagsData::trusted(),
1140 ));
1141 }
1142
1143 insts.extend(Self::gen_sp_reg_adjust((guard_size * probe_count) as i32));
1145 }
1146}