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(param.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 ) -> ir::ArgumentExtension {
229 specified
230 }
231
232 fn gen_args(args: Vec<ArgPair>) -> Inst {
233 Inst::Args { args }
234 }
235
236 fn gen_rets(rets: Vec<RetPair>) -> Inst {
237 Inst::Rets { rets }
238 }
239
240 fn get_stacklimit_reg(_call_conv: isa::CallConv) -> Reg {
241 spilltmp_reg()
242 }
243
244 fn gen_add_imm(
245 _call_conv: isa::CallConv,
246 into_reg: Writable<Reg>,
247 from_reg: Reg,
248 imm: u32,
249 ) -> SmallInstVec<Inst> {
250 let mut insts = SmallInstVec::new();
251 if let Some(imm12) = Imm12::maybe_from_u64(imm as u64) {
252 insts.push(Inst::AluRRImm12 {
253 alu_op: AluOPRRI::Addi,
254 rd: into_reg,
255 rs: from_reg,
256 imm12,
257 });
258 } else {
259 insts.extend(Inst::load_constant_u32(
260 writable_spilltmp_reg2(),
261 imm as u64,
262 ));
263 insts.push(Inst::AluRRR {
264 alu_op: AluOPRRR::Add,
265 rd: into_reg,
266 rs1: spilltmp_reg2(),
267 rs2: from_reg,
268 });
269 }
270 insts
271 }
272
273 fn gen_stack_lower_bound_trap(limit_reg: Reg) -> SmallInstVec<Inst> {
274 let mut insts = SmallVec::new();
275 insts.push(Inst::TrapIf {
276 cmp: IntegerCompare {
277 kind: IntCC::UnsignedLessThan,
278 rs1: stack_reg(),
279 rs2: limit_reg,
280 },
281 trap_code: ir::TrapCode::STACK_OVERFLOW,
282 });
283 insts
284 }
285
286 fn gen_get_stack_addr(mem: StackAMode, into_reg: Writable<Reg>) -> Inst {
287 Inst::LoadAddr {
288 rd: into_reg,
289 mem: mem.into(),
290 }
291 }
292
293 fn gen_load_base_offset(into_reg: Writable<Reg>, base: Reg, offset: i32, ty: Type) -> Inst {
294 let mem = AMode::RegOffset(base, offset as i64);
295 Inst::gen_load(into_reg, mem, ty, MemFlagsData::trusted())
296 }
297
298 fn gen_store_base_offset(base: Reg, offset: i32, from_reg: Reg, ty: Type) -> Inst {
299 let mem = AMode::RegOffset(base, offset as i64);
300 Inst::gen_store(mem, from_reg, ty, MemFlagsData::trusted())
301 }
302
303 fn gen_sp_reg_adjust(amount: i32) -> SmallInstVec<Inst> {
304 let mut insts = SmallVec::new();
305
306 if amount == 0 {
307 return insts;
308 }
309
310 if let Some(imm) = Imm12::maybe_from_i64(amount as i64) {
311 insts.push(Inst::AluRRImm12 {
312 alu_op: AluOPRRI::Addi,
313 rd: writable_stack_reg(),
314 rs: stack_reg(),
315 imm12: imm,
316 })
317 } else {
318 let tmp = writable_spilltmp_reg();
319 insts.extend(Inst::load_constant_u64(tmp, amount as i64 as u64));
320 insts.push(Inst::AluRRR {
321 alu_op: AluOPRRR::Add,
322 rd: writable_stack_reg(),
323 rs1: stack_reg(),
324 rs2: tmp.to_reg(),
325 });
326 }
327
328 insts
329 }
330
331 fn gen_prologue_frame_setup(
332 _call_conv: isa::CallConv,
333 flags: &settings::Flags,
334 _isa_flags: &RiscvFlags,
335 frame_layout: &FrameLayout,
336 ) -> SmallInstVec<Inst> {
337 let mut insts = SmallVec::new();
338
339 if frame_layout.setup_area_size > 0 {
340 insts.extend(Self::gen_sp_reg_adjust(-16));
345 insts.push(Inst::gen_store(
346 AMode::SPOffset(8),
347 link_reg(),
348 I64,
349 MemFlagsData::trusted(),
350 ));
351 insts.push(Inst::gen_store(
352 AMode::SPOffset(0),
353 fp_reg(),
354 I64,
355 MemFlagsData::trusted(),
356 ));
357
358 if flags.unwind_info() {
359 insts.push(Inst::Unwind {
360 inst: UnwindInst::PushFrameRegs {
361 offset_upward_to_caller_sp: frame_layout.setup_area_size,
362 },
363 });
364 }
365 insts.push(Inst::Mov {
366 rd: writable_fp_reg(),
367 rm: stack_reg(),
368 ty: I64,
369 });
370 }
371
372 insts
373 }
374 fn gen_epilogue_frame_restore(
376 call_conv: isa::CallConv,
377 _flags: &settings::Flags,
378 _isa_flags: &RiscvFlags,
379 frame_layout: &FrameLayout,
380 ) -> SmallInstVec<Inst> {
381 let mut insts = SmallVec::new();
382
383 if frame_layout.setup_area_size > 0 {
384 insts.push(Inst::gen_load(
385 writable_link_reg(),
386 AMode::SPOffset(8),
387 I64,
388 MemFlagsData::trusted(),
389 ));
390 insts.push(Inst::gen_load(
391 writable_fp_reg(),
392 AMode::SPOffset(0),
393 I64,
394 MemFlagsData::trusted(),
395 ));
396 insts.extend(Self::gen_sp_reg_adjust(16));
397 }
398
399 if call_conv == isa::CallConv::Tail && frame_layout.tail_args_size > 0 {
400 insts.extend(Self::gen_sp_reg_adjust(
401 frame_layout.tail_args_size.try_into().unwrap(),
402 ));
403 }
404
405 insts
406 }
407
408 fn gen_return(
409 _call_conv: isa::CallConv,
410 _isa_flags: &RiscvFlags,
411 _frame_layout: &FrameLayout,
412 ) -> SmallInstVec<Inst> {
413 smallvec![Inst::Ret {}]
414 }
415
416 fn gen_probestack(insts: &mut SmallInstVec<Self::I>, frame_size: u32) {
417 insts.extend(Inst::load_constant_u32(writable_a0(), frame_size as u64));
418 let mut info = CallInfo::empty(
419 ExternalName::LibCall(LibCall::Probestack),
420 CallConv::SystemV,
421 );
422 info.uses.push(CallArgPair {
423 vreg: a0(),
424 preg: a0(),
425 });
426 insts.push(Inst::Call {
427 info: Box::new(info),
428 });
429 }
430
431 fn gen_clobber_save(
432 _call_conv: isa::CallConv,
433 flags: &settings::Flags,
434 frame_layout: &FrameLayout,
435 ) -> SmallVec<[Inst; 16]> {
436 let mut insts = SmallVec::new();
437 let setup_frame = frame_layout.setup_area_size > 0;
438
439 let incoming_args_diff = frame_layout.tail_args_size - frame_layout.incoming_args_size;
440 if incoming_args_diff > 0 {
441 insts.extend(Self::gen_sp_reg_adjust(-(incoming_args_diff as i32)));
443
444 if setup_frame {
445 insts.push(Inst::gen_store(
448 AMode::SPOffset(8),
449 link_reg(),
450 I64,
451 MemFlagsData::trusted(),
452 ));
453 insts.push(Inst::gen_load(
454 writable_fp_reg(),
455 AMode::SPOffset(i64::from(incoming_args_diff)),
456 I64,
457 MemFlagsData::trusted(),
458 ));
459 insts.push(Inst::gen_store(
460 AMode::SPOffset(0),
461 fp_reg(),
462 I64,
463 MemFlagsData::trusted(),
464 ));
465
466 insts.push(Inst::gen_move(writable_fp_reg(), stack_reg(), I64));
468 }
469 }
470
471 if flags.unwind_info() && setup_frame {
472 insts.push(Inst::Unwind {
475 inst: UnwindInst::DefineNewFrame {
476 offset_downward_to_clobbers: frame_layout.clobber_size,
477 offset_upward_to_caller_sp: frame_layout.setup_area_size,
478 },
479 });
480 }
481
482 let stack_size = frame_layout.clobber_size
485 + frame_layout.fixed_frame_storage_size
486 + frame_layout.outgoing_args_size;
487
488 if stack_size > 0 {
491 insts.extend(Self::gen_sp_reg_adjust(-(stack_size as i32)));
492
493 let mut cur_offset = 0;
494 for reg in &frame_layout.clobbered_callee_saves {
495 let r_reg = reg.to_reg();
496 let ty = match r_reg.class() {
497 RegClass::Int => I64,
498 RegClass::Float => F64,
499 RegClass::Vector => I8X16,
500 };
501 cur_offset = align_to(cur_offset, ty.bytes());
502 insts.push(Inst::gen_store(
503 AMode::SPOffset(i64::from(stack_size - cur_offset - ty.bytes())),
504 Reg::from(reg.to_reg()),
505 ty,
506 MemFlagsData::trusted(),
507 ));
508
509 if flags.unwind_info() {
510 insts.push(Inst::Unwind {
511 inst: UnwindInst::SaveReg {
512 clobber_offset: frame_layout.clobber_size - cur_offset - ty.bytes(),
513 reg: r_reg,
514 },
515 });
516 }
517
518 cur_offset += ty.bytes();
519 assert!(cur_offset <= stack_size);
520 }
521 }
522 insts
523 }
524
525 fn gen_clobber_restore(
526 _call_conv: isa::CallConv,
527 _flags: &settings::Flags,
528 frame_layout: &FrameLayout,
529 ) -> SmallVec<[Inst; 16]> {
530 let mut insts = SmallVec::new();
531
532 let stack_size = frame_layout.clobber_size
533 + frame_layout.fixed_frame_storage_size
534 + frame_layout.outgoing_args_size;
535 let mut cur_offset = 0;
536
537 for reg in &frame_layout.clobbered_callee_saves {
538 let rreg = reg.to_reg();
539 let ty = match rreg.class() {
540 RegClass::Int => I64,
541 RegClass::Float => F64,
542 RegClass::Vector => I8X16,
543 };
544 cur_offset = align_to(cur_offset, ty.bytes());
545 insts.push(Inst::gen_load(
546 reg.map(Reg::from),
547 AMode::SPOffset(i64::from(stack_size - cur_offset - ty.bytes())),
548 ty,
549 MemFlagsData::trusted(),
550 ));
551 cur_offset += ty.bytes();
552 }
553
554 if stack_size > 0 {
555 insts.extend(Self::gen_sp_reg_adjust(stack_size as i32));
556 }
557
558 insts
559 }
560
561 fn gen_memcpy<F: FnMut(Type) -> Writable<Reg>>(
562 call_conv: isa::CallConv,
563 dst: Reg,
564 src: Reg,
565 size: usize,
566 mut alloc_tmp: F,
567 ) -> SmallVec<[Self::I; 8]> {
568 let mut insts = SmallVec::new();
569 let arg0 = Writable::from_reg(x_reg(10));
570 let arg1 = Writable::from_reg(x_reg(11));
571 let arg2 = Writable::from_reg(x_reg(12));
572 let tmp = alloc_tmp(Self::word_type());
573 insts.extend(Inst::load_constant_u64(tmp, size as u64));
574 insts.push(Inst::Call {
575 info: Box::new(CallInfo {
576 dest: ExternalName::LibCall(LibCall::Memcpy),
577 uses: smallvec![
578 CallArgPair {
579 vreg: dst,
580 preg: arg0.to_reg()
581 },
582 CallArgPair {
583 vreg: src,
584 preg: arg1.to_reg()
585 },
586 CallArgPair {
587 vreg: tmp.to_reg(),
588 preg: arg2.to_reg()
589 }
590 ],
591 defs: smallvec![],
592 clobbers: Self::get_regs_clobbered_by_call(call_conv, false),
593 caller_conv: call_conv,
594 callee_conv: call_conv,
595 callee_pop_size: 0,
596 try_call_info: None,
597 patchable: false,
598 }),
599 });
600 insts
601 }
602
603 fn get_number_of_spillslots_for_value(
604 rc: RegClass,
605 _target_vector_bytes: u32,
606 isa_flags: &RiscvFlags,
607 ) -> u32 {
608 match rc {
610 RegClass::Int => 1,
611 RegClass::Float => 1,
612 RegClass::Vector => (isa_flags.min_vec_reg_size() / 8) as u32,
613 }
614 }
615
616 fn get_machine_env(_flags: &settings::Flags, _call_conv: isa::CallConv) -> &MachineEnv {
617 static MACHINE_ENV: MachineEnv = create_reg_environment();
618 &MACHINE_ENV
619 }
620
621 fn get_regs_clobbered_by_call(
622 call_conv_of_callee: isa::CallConv,
623 is_exception: bool,
624 ) -> PRegSet {
625 match call_conv_of_callee {
626 isa::CallConv::Tail if is_exception => ALL_CLOBBERS,
627 isa::CallConv::PreserveAll if is_exception => ALL_CLOBBERS,
633 isa::CallConv::PreserveAll => NO_CLOBBERS,
634 _ => DEFAULT_CLOBBERS,
635 }
636 }
637
638 fn compute_frame_layout(
639 call_conv: isa::CallConv,
640 flags: &settings::Flags,
641 _sig: &Signature,
642 regs: &[Writable<RealReg>],
643 function_calls: FunctionCalls,
644 incoming_args_size: u32,
645 tail_args_size: u32,
646 stackslots_size: u32,
647 fixed_frame_storage_size: u32,
648 outgoing_args_size: u32,
649 ) -> FrameLayout {
650 let is_callee_saved = |reg: &Writable<RealReg>| match call_conv {
651 isa::CallConv::PreserveAll => true,
652 _ => DEFAULT_CALLEE_SAVES.contains(reg.to_reg().into()),
653 };
654 let mut regs: Vec<Writable<RealReg>> =
655 regs.iter().cloned().filter(is_callee_saved).collect();
656
657 regs.sort_unstable();
658
659 let clobber_size = compute_clobber_size(®s);
661
662 let setup_area_size = if flags.preserve_frame_pointers()
664 || function_calls != FunctionCalls::None
665 || incoming_args_size > 0
668 || clobber_size > 0
669 || fixed_frame_storage_size > 0
670 {
671 16 } else {
673 0
674 };
675
676 FrameLayout {
678 word_bytes: 8,
679 incoming_args_size,
680 tail_args_size,
681 setup_area_size,
682 clobber_size,
683 fixed_frame_storage_size,
684 stackslots_size,
685 outgoing_args_size,
686 clobbered_callee_saves: regs,
687 function_calls,
688 }
689 }
690
691 fn gen_inline_probestack(
692 insts: &mut SmallInstVec<Self::I>,
693 _call_conv: isa::CallConv,
694 frame_size: u32,
695 guard_size: u32,
696 ) {
697 const PROBE_MAX_UNROLL: u32 = 3;
699
700 let probe_count = frame_size / guard_size;
703 if probe_count == 0 {
704 return;
706 }
707
708 let tmp = Writable::from_reg(x_reg(28)); if probe_count <= PROBE_MAX_UNROLL {
712 Self::gen_probestack_unroll(insts, tmp, guard_size, probe_count)
713 } else {
714 insts.push(Inst::StackProbeLoop {
715 guard_size,
716 probe_count,
717 tmp,
718 });
719 }
720 }
721
722 fn retval_temp_reg(_call_conv_of_callee: isa::CallConv) -> Writable<Reg> {
723 Writable::from_reg(regs::x_reg(12))
726 }
727
728 fn exception_payload_regs(call_conv: isa::CallConv) -> &'static [Reg] {
729 const PAYLOAD_REGS: &'static [Reg] = &[regs::a0(), regs::a1()];
730 match call_conv {
731 isa::CallConv::SystemV | isa::CallConv::Tail | isa::CallConv::PreserveAll => {
732 PAYLOAD_REGS
733 }
734 _ => &[],
735 }
736 }
737}
738
739const DEFAULT_CALLEE_SAVES: PRegSet = PRegSet::empty()
741 .with(px_reg(2))
743 .with(px_reg(8))
744 .with(px_reg(9))
745 .with(px_reg(18))
746 .with(px_reg(19))
747 .with(px_reg(20))
748 .with(px_reg(21))
749 .with(px_reg(22))
750 .with(px_reg(23))
751 .with(px_reg(24))
752 .with(px_reg(25))
753 .with(px_reg(26))
754 .with(px_reg(27))
755 .with(pf_reg(8))
757 .with(pf_reg(18))
758 .with(pf_reg(19))
759 .with(pf_reg(20))
760 .with(pf_reg(21))
761 .with(pf_reg(22))
762 .with(pf_reg(23))
763 .with(pf_reg(24))
764 .with(pf_reg(25))
765 .with(pf_reg(26))
766 .with(pf_reg(27));
767
768fn compute_clobber_size(clobbers: &[Writable<RealReg>]) -> u32 {
769 let mut clobbered_size = 0;
770 for reg in clobbers {
771 match reg.to_reg().class() {
772 RegClass::Int => {
773 clobbered_size += 8;
774 }
775 RegClass::Float => {
776 clobbered_size += 8;
777 }
778 RegClass::Vector => {
779 clobbered_size = align_to(clobbered_size, 16);
780 clobbered_size += 16;
781 }
782 }
783 }
784 align_to(clobbered_size, 16)
785}
786
787const DEFAULT_CLOBBERS: PRegSet = PRegSet::empty()
788 .with(px_reg(1))
789 .with(px_reg(5))
790 .with(px_reg(6))
791 .with(px_reg(7))
792 .with(px_reg(10))
793 .with(px_reg(11))
794 .with(px_reg(12))
795 .with(px_reg(13))
796 .with(px_reg(14))
797 .with(px_reg(15))
798 .with(px_reg(16))
799 .with(px_reg(17))
800 .with(px_reg(28))
801 .with(px_reg(29))
802 .with(px_reg(30))
803 .with(px_reg(31))
804 .with(pf_reg(0))
806 .with(pf_reg(1))
807 .with(pf_reg(2))
808 .with(pf_reg(3))
809 .with(pf_reg(4))
810 .with(pf_reg(5))
811 .with(pf_reg(6))
812 .with(pf_reg(7))
813 .with(pf_reg(9))
814 .with(pf_reg(10))
815 .with(pf_reg(11))
816 .with(pf_reg(12))
817 .with(pf_reg(13))
818 .with(pf_reg(14))
819 .with(pf_reg(15))
820 .with(pf_reg(16))
821 .with(pf_reg(17))
822 .with(pf_reg(28))
823 .with(pf_reg(29))
824 .with(pf_reg(30))
825 .with(pf_reg(31))
826 .with(pv_reg(0))
828 .with(pv_reg(1))
829 .with(pv_reg(2))
830 .with(pv_reg(3))
831 .with(pv_reg(4))
832 .with(pv_reg(5))
833 .with(pv_reg(6))
834 .with(pv_reg(7))
835 .with(pv_reg(8))
836 .with(pv_reg(9))
837 .with(pv_reg(10))
838 .with(pv_reg(11))
839 .with(pv_reg(12))
840 .with(pv_reg(13))
841 .with(pv_reg(14))
842 .with(pv_reg(15))
843 .with(pv_reg(16))
844 .with(pv_reg(17))
845 .with(pv_reg(18))
846 .with(pv_reg(19))
847 .with(pv_reg(20))
848 .with(pv_reg(21))
849 .with(pv_reg(22))
850 .with(pv_reg(23))
851 .with(pv_reg(24))
852 .with(pv_reg(25))
853 .with(pv_reg(26))
854 .with(pv_reg(27))
855 .with(pv_reg(28))
856 .with(pv_reg(29))
857 .with(pv_reg(30))
858 .with(pv_reg(31));
859
860const ALL_CLOBBERS: PRegSet = PRegSet::empty()
861 .with(px_reg(3))
863 .with(px_reg(4))
864 .with(px_reg(5))
865 .with(px_reg(6))
866 .with(px_reg(7))
867 .with(px_reg(8))
868 .with(px_reg(9))
869 .with(px_reg(10))
870 .with(px_reg(11))
871 .with(px_reg(12))
872 .with(px_reg(13))
873 .with(px_reg(14))
874 .with(px_reg(15))
875 .with(px_reg(16))
876 .with(px_reg(17))
877 .with(px_reg(18))
878 .with(px_reg(19))
879 .with(px_reg(20))
880 .with(px_reg(21))
881 .with(px_reg(22))
882 .with(px_reg(23))
883 .with(px_reg(24))
884 .with(px_reg(25))
885 .with(px_reg(26))
886 .with(px_reg(27))
887 .with(px_reg(28))
888 .with(px_reg(29))
889 .with(px_reg(30))
890 .with(px_reg(31))
891 .with(pf_reg(0))
893 .with(pf_reg(1))
894 .with(pf_reg(2))
895 .with(pf_reg(3))
896 .with(pf_reg(4))
897 .with(pf_reg(5))
898 .with(pf_reg(6))
899 .with(pf_reg(7))
900 .with(pf_reg(8))
901 .with(pf_reg(9))
902 .with(pf_reg(10))
903 .with(pf_reg(11))
904 .with(pf_reg(12))
905 .with(pf_reg(13))
906 .with(pf_reg(14))
907 .with(pf_reg(15))
908 .with(pf_reg(16))
909 .with(pf_reg(17))
910 .with(pf_reg(18))
911 .with(pf_reg(19))
912 .with(pf_reg(20))
913 .with(pf_reg(21))
914 .with(pf_reg(22))
915 .with(pf_reg(23))
916 .with(pf_reg(24))
917 .with(pf_reg(25))
918 .with(pf_reg(26))
919 .with(pf_reg(27))
920 .with(pf_reg(28))
921 .with(pf_reg(29))
922 .with(pf_reg(30))
923 .with(pf_reg(31))
924 .with(pv_reg(0))
926 .with(pv_reg(1))
927 .with(pv_reg(2))
928 .with(pv_reg(3))
929 .with(pv_reg(4))
930 .with(pv_reg(5))
931 .with(pv_reg(6))
932 .with(pv_reg(7))
933 .with(pv_reg(8))
934 .with(pv_reg(9))
935 .with(pv_reg(10))
936 .with(pv_reg(11))
937 .with(pv_reg(12))
938 .with(pv_reg(13))
939 .with(pv_reg(14))
940 .with(pv_reg(15))
941 .with(pv_reg(16))
942 .with(pv_reg(17))
943 .with(pv_reg(18))
944 .with(pv_reg(19))
945 .with(pv_reg(20))
946 .with(pv_reg(21))
947 .with(pv_reg(22))
948 .with(pv_reg(23))
949 .with(pv_reg(24))
950 .with(pv_reg(25))
951 .with(pv_reg(26))
952 .with(pv_reg(27))
953 .with(pv_reg(28))
954 .with(pv_reg(29))
955 .with(pv_reg(30))
956 .with(pv_reg(31));
957
958const NO_CLOBBERS: PRegSet = PRegSet::empty();
959
960const fn create_reg_environment() -> MachineEnv {
961 let preferred_regs_by_class: [PRegSet; 3] = [
972 PRegSet::empty()
973 .with(px_reg(10))
974 .with(px_reg(11))
975 .with(px_reg(12))
976 .with(px_reg(13))
977 .with(px_reg(14))
978 .with(px_reg(15)),
979 PRegSet::empty()
980 .with(pf_reg(10))
981 .with(pf_reg(11))
982 .with(pf_reg(12))
983 .with(pf_reg(13))
984 .with(pf_reg(14))
985 .with(pf_reg(15)),
986 PRegSet::empty()
987 .with(pv_reg(8))
988 .with(pv_reg(9))
989 .with(pv_reg(10))
990 .with(pv_reg(11))
991 .with(pv_reg(12))
992 .with(pv_reg(13))
993 .with(pv_reg(14))
994 .with(pv_reg(15)),
995 ];
996
997 let non_preferred_regs_by_class: [PRegSet; 3] = [
998 PRegSet::empty()
1001 .with(px_reg(5))
1002 .with(px_reg(6))
1003 .with(px_reg(7))
1004 .with(px_reg(16))
1006 .with(px_reg(17))
1007 .with(px_reg(28))
1008 .with(px_reg(29))
1009 .with(px_reg(9))
1012 .with(px_reg(18))
1014 .with(px_reg(19))
1015 .with(px_reg(20))
1016 .with(px_reg(21))
1017 .with(px_reg(22))
1018 .with(px_reg(23))
1019 .with(px_reg(24))
1020 .with(px_reg(25))
1021 .with(px_reg(26))
1022 .with(px_reg(27)),
1023 PRegSet::empty()
1025 .with(pf_reg(0))
1026 .with(pf_reg(1))
1027 .with(pf_reg(2))
1028 .with(pf_reg(3))
1029 .with(pf_reg(4))
1030 .with(pf_reg(5))
1031 .with(pf_reg(6))
1032 .with(pf_reg(7))
1033 .with(pf_reg(16))
1034 .with(pf_reg(17))
1035 .with(pf_reg(28))
1036 .with(pf_reg(29))
1037 .with(pf_reg(30))
1038 .with(pf_reg(31))
1039 .with(pf_reg(8))
1042 .with(pf_reg(9))
1043 .with(pf_reg(18))
1044 .with(pf_reg(19))
1045 .with(pf_reg(20))
1046 .with(pf_reg(21))
1047 .with(pf_reg(22))
1048 .with(pf_reg(23))
1049 .with(pf_reg(24))
1050 .with(pf_reg(25))
1051 .with(pf_reg(26))
1052 .with(pf_reg(27)),
1053 PRegSet::empty()
1054 .with(pv_reg(0))
1055 .with(pv_reg(1))
1056 .with(pv_reg(2))
1057 .with(pv_reg(3))
1058 .with(pv_reg(4))
1059 .with(pv_reg(5))
1060 .with(pv_reg(6))
1061 .with(pv_reg(7))
1062 .with(pv_reg(16))
1063 .with(pv_reg(17))
1064 .with(pv_reg(18))
1065 .with(pv_reg(19))
1066 .with(pv_reg(20))
1067 .with(pv_reg(21))
1068 .with(pv_reg(22))
1069 .with(pv_reg(23))
1070 .with(pv_reg(24))
1071 .with(pv_reg(25))
1072 .with(pv_reg(26))
1073 .with(pv_reg(27))
1074 .with(pv_reg(28))
1075 .with(pv_reg(29))
1076 .with(pv_reg(30))
1077 .with(pv_reg(31)),
1078 ];
1079
1080 MachineEnv {
1081 preferred_regs_by_class,
1082 non_preferred_regs_by_class,
1083 fixed_stack_slots: vec![],
1084 scratch_by_class: [None, None, None],
1085 }
1086}
1087
1088impl Riscv64MachineDeps {
1089 fn gen_probestack_unroll(
1090 insts: &mut SmallInstVec<Inst>,
1091 tmp: Writable<Reg>,
1092 guard_size: u32,
1093 probe_count: u32,
1094 ) {
1095 insts.extend(Inst::load_constant_u64(tmp, (-(guard_size as i64)) as u64));
1107
1108 for _ in 0..probe_count {
1109 insts.push(Inst::AluRRR {
1110 alu_op: AluOPRRR::Add,
1111 rd: writable_stack_reg(),
1112 rs1: stack_reg(),
1113 rs2: tmp.to_reg(),
1114 });
1115
1116 insts.push(Inst::gen_store(
1117 AMode::SPOffset(0),
1118 zero_reg(),
1119 I32,
1120 MemFlagsData::trusted(),
1121 ));
1122 }
1123
1124 insts.extend(Self::gen_sp_reg_adjust((guard_size * probe_count) as i32));
1126 }
1127}