1use crate::{
4 codegen_error,
5 common_decl::Size,
6 location::{Location as AbstractLocation, Reg},
7 machine::MaybeImmediate,
8 machine_riscv::{ImmType, RISCV_RETURN_VALUE_REGISTERS},
9 riscv_decl::{ArgumentRegisterAllocator, RiscvRegister},
10};
11pub use crate::{
12 machine::{Label, Offset},
13 riscv_decl::{FPR, GPR},
14};
15use dynasmrt::{DynasmApi, DynasmLabelApi, VecAssembler, riscv::RiscvRelocation};
16use wasmer_compiler::types::{
17 function::FunctionBody,
18 section::{CustomSection, CustomSectionProtection, SectionBody},
19};
20use wasmer_types::{
21 CompileError, FunctionIndex, FunctionType, Type, VMOffsets,
22 target::{CallingConvention, CpuFeature},
23};
24
25type Assembler = VecAssembler<RiscvRelocation>;
26
27macro_rules! dynasm {
29 ($a:expr ; $($tt:tt)*) => {
30 dynasm::dynasm!(
31 $a
32 ; .arch riscv64
33 ; .feature g
34 ; $($tt)*
35 )
36 };
37}
38
39pub type Location = AbstractLocation<GPR, FPR>;
41
42#[derive(Copy, Clone, Debug, Eq, PartialEq)]
44pub enum Condition {
45 Lt,
47 Le,
49 Gt,
51 Ge,
53 Eq,
55 Ne,
57
58 Ltu,
60 Leu,
62 Gtu,
64 Geu,
66}
67
68#[derive(Copy, Clone, Debug, Eq, PartialEq)]
70pub enum RoundingMode {
71 Rne,
73 Rtz,
75 Rdn,
77 Rup,
79}
80
81#[derive(Copy, Clone, Debug, Eq, PartialEq)]
83pub enum AtomicBinaryOp {
84 Add,
85 Sub,
86 Or,
87 And,
88 Xor,
89 Exchange,
90}
91
92const SCRATCH_REG: GPR = GPR::X28;
94
95#[allow(unused)]
97pub trait EmitterRiscv {
98 fn emit_jmp_on_condition(
99 &mut self,
100 cond: Condition,
101 loc_a: Location,
102 loc_b: Location,
103 label: Label,
104 tmp: GPR,
105 ) -> Result<(), CompileError>;
106 fn emit_reserved_sd(
107 &mut self,
108 size: Size,
109 dest: GPR,
110 addr: GPR,
111 source: GPR,
112 ) -> Result<(), CompileError>;
113 fn get_simd_arch(&self) -> Option<&CpuFeature>;
115 fn get_label(&mut self) -> Label;
117 fn get_offset(&self) -> Offset;
119 fn get_jmp_instr_size(&self) -> u8;
121
122 fn finalize_function(&mut self) -> Result<(), CompileError>;
124
125 fn emit_label(&mut self, label: Label) -> Result<(), CompileError>;
126 fn emit_brk(&mut self) -> Result<(), CompileError>;
127 fn emit_ld(
128 &mut self,
129 sz: Size,
130 signed: bool,
131 reg: Location,
132 addr: Location,
133 ) -> Result<(), CompileError>;
134
135 fn emit_sd(&mut self, sz: Size, reg: Location, addr: Location) -> Result<(), CompileError>;
136 fn emit_push(&mut self, size: Size, src: Location) -> Result<(), CompileError>;
137 fn emit_pop(&mut self, size: Size, dst: Location) -> Result<(), CompileError>;
138
139 fn emit_add(
140 &mut self,
141 sz: Size,
142 src1: Location,
143 src2: Location,
144 dst: Location,
145 ) -> Result<(), CompileError>;
146 fn emit_sub(
147 &mut self,
148 sz: Size,
149 src1: Location,
150 src2: Location,
151 dst: Location,
152 ) -> Result<(), CompileError>;
153 fn emit_mul(
154 &mut self,
155 sz: Size,
156 src1: Location,
157 src2: Location,
158 dst: Location,
159 ) -> Result<(), CompileError>;
160 fn emit_sdiv(
161 &mut self,
162 sz: Size,
163 src1: Location,
164 src2: Location,
165 dst: Location,
166 ) -> Result<(), CompileError>;
167 fn emit_udiv(
168 &mut self,
169 sz: Size,
170 src1: Location,
171 src2: Location,
172 dst: Location,
173 ) -> Result<(), CompileError>;
174 fn emit_srem(
175 &mut self,
176 sz: Size,
177 src1: Location,
178 src2: Location,
179 dst: Location,
180 ) -> Result<(), CompileError>;
181 fn emit_urem(
182 &mut self,
183 sz: Size,
184 src1: Location,
185 src2: Location,
186 dst: Location,
187 ) -> Result<(), CompileError>;
188 fn emit_and(
189 &mut self,
190 sz: Size,
191 src1: Location,
192 src2: Location,
193 dst: Location,
194 ) -> Result<(), CompileError>;
195 fn emit_or(
196 &mut self,
197 sz: Size,
198 src1: Location,
199 src2: Location,
200 dst: Location,
201 ) -> Result<(), CompileError>;
202 fn emit_xor(
203 &mut self,
204 sz: Size,
205 src1: Location,
206 src2: Location,
207 dst: Location,
208 ) -> Result<(), CompileError>;
209 fn emit_sll(
210 &mut self,
211 sz: Size,
212 src1: Location,
213 src2: Location,
214 dst: Location,
215 ) -> Result<(), CompileError>;
216 fn emit_srl(
217 &mut self,
218 sz: Size,
219 src1: Location,
220 src2: Location,
221 dst: Location,
222 ) -> Result<(), CompileError>;
223 fn emit_sra(
224 &mut self,
225 sz: Size,
226 src1: Location,
227 src2: Location,
228 dst: Location,
229 ) -> Result<(), CompileError>;
230 fn emit_extend(
231 &mut self,
232 sz: Size,
233 signed: bool,
234 src: Location,
235 dst: Location,
236 ) -> Result<(), CompileError>;
237 fn emit_not(&mut self, sz: Size, src: Location, dst: Location) -> Result<(), CompileError>;
238 fn emit_neg(&mut self, sz: Size, src: Location, dst: Location) -> Result<(), CompileError>;
239
240 fn emit_mov(&mut self, sz: Size, src: Location, dst: Location) -> Result<(), CompileError>;
241
242 fn emit_ret(&mut self) -> Result<(), CompileError>;
243
244 fn emit_udf(&mut self, payload: u8) -> Result<(), CompileError>;
245
246 fn emit_mov_imm(&mut self, dst: Location, val: i64) -> Result<(), CompileError>;
247
248 fn emit_fneg(&mut self, sz: Size, src: Location, dst: Location) -> Result<(), CompileError>;
250 fn emit_fmin(
251 &mut self,
252 sz: Size,
253 src1: Location,
254 src2: Location,
255 dst: Location,
256 ) -> Result<(), CompileError>;
257 fn emit_fmax(
258 &mut self,
259 sz: Size,
260 src1: Location,
261 src2: Location,
262 dst: Location,
263 ) -> Result<(), CompileError>;
264 fn emit_fdiv(
265 &mut self,
266 sz: Size,
267 src1: Location,
268 src2: Location,
269 dst: Location,
270 ) -> Result<(), CompileError>;
271 fn emit_fsqrt(&mut self, sz: Size, src: Location, dst: Location) -> Result<(), CompileError>;
272 fn emit_fcvt(
273 &mut self,
274 signed: bool,
275 sz_in: Size,
276 src: Location,
277 sz_out: Size,
278 dst: Location,
279 ) -> Result<(), CompileError>;
280 fn emit_fcvt_with_rounding(
281 &mut self,
282 rounding: RoundingMode,
283 size: Size,
284 src: Location,
285 dst: Location,
286 tmp: GPR,
287 ) -> Result<(), CompileError>;
288 fn emit_swap_fscr(&mut self, reg: GPR) -> Result<(), CompileError>;
289
290 fn emit_cmp(
292 &mut self,
293 c: Condition,
294 loc_a: Location,
295 loc_b: Location,
296 ret: Location,
297 ) -> Result<(), CompileError>;
298 fn emit_fcmp(
299 &mut self,
300 c: Condition,
301 size: Size,
302 loc_a: Location,
303 loc_b: Location,
304 ret: Location,
305 ) -> Result<(), CompileError>;
306
307 fn emit_on_false_label(
308 &mut self,
309 cond: Location,
310 label: Label,
311 tmp: GPR,
312 ) -> Result<(), CompileError>;
313 fn emit_on_false_label_far(
314 &mut self,
315 cond: Location,
316 label: Label,
317 tmp: GPR,
318 ) -> Result<(), CompileError>;
319 fn emit_on_true_label_far(
320 &mut self,
321 cond: Location,
322 label: Label,
323 tmp: GPR,
324 ) -> Result<(), CompileError>;
325 fn emit_on_true_label(
326 &mut self,
327 cond: Location,
328 label: Label,
329 tmp: GPR,
330 ) -> Result<(), CompileError>;
331
332 fn emit_j_label(&mut self, label: Label, reg: Option<GPR>) -> Result<(), CompileError>;
333 fn emit_j_register(&mut self, reg: GPR) -> Result<(), CompileError>;
334 fn emit_load_label(&mut self, reg: GPR, label: Label) -> Result<(), CompileError>;
335 fn emit_call_label(&mut self, label: Label) -> Result<(), CompileError>;
336 fn emit_call_register(&mut self, reg: GPR) -> Result<(), CompileError>;
337
338 fn emit_rwfence(&mut self) -> Result<(), CompileError>;
339 fn emit_atomic_binop(
340 &mut self,
341 op: AtomicBinaryOp,
342 size: Size,
343 dest: GPR,
344 addr: GPR,
345 source: GPR,
346 ) -> Result<(), CompileError>;
347 fn emit_reserved_ld(&mut self, size: Size, reg: GPR, addr: GPR) -> Result<(), CompileError>;
348}
349
350impl EmitterRiscv for Assembler {
351 fn get_simd_arch(&self) -> Option<&CpuFeature> {
352 todo!()
353 }
354
355 fn get_label(&mut self) -> Label {
356 self.new_dynamic_label()
357 }
358
359 fn get_offset(&self) -> Offset {
360 self.offset()
361 }
362
363 fn get_jmp_instr_size(&self) -> u8 {
364 todo!()
365 }
366
367 fn finalize_function(&mut self) -> Result<(), CompileError> {
368 Ok(())
369 }
370
371 fn emit_label(&mut self, label: Label) -> Result<(), CompileError> {
372 dynasm!(self ; => label);
373 Ok(())
374 }
375
376 fn emit_brk(&mut self) -> Result<(), CompileError> {
377 dynasm!(self ; ebreak);
378 Ok(())
379 }
380
381 fn emit_udf(&mut self, payload: u8) -> Result<(), CompileError> {
382 dynasm!(self
383 ; li.12 a0, payload as _
384 ; unimp);
385 Ok(())
386 }
387
388 fn emit_ld(
389 &mut self,
390 sz: Size,
391 signed: bool,
392 reg: Location,
393 addr: Location,
394 ) -> Result<(), CompileError> {
395 let Location::Memory(addr, disp) = addr else {
396 codegen_error!("singlepass can't emit LD {:?}, {:?}, {:?}", sz, reg, addr);
397 };
398 assert!(ImmType::Bits12.compatible_imm(disp as i64));
399
400 match (sz, signed, reg) {
401 (Size::S64, _, Location::GPR(reg)) => {
402 dynasm!(self ; ld X(reg), [X(addr), disp]);
403 }
404 (Size::S32, false, Location::GPR(reg)) => {
405 dynasm!(self ; lwu X(reg), [X(addr), disp]);
406 }
407 (Size::S32, true, Location::GPR(reg)) => {
408 dynasm!(self ; lw X(reg), [X(addr), disp]);
409 }
410 (Size::S16, false, Location::GPR(reg)) => {
411 dynasm!(self ; lhu X(reg), [X(addr), disp]);
412 }
413 (Size::S16, true, Location::GPR(reg)) => {
414 dynasm!(self ; lh X(reg), [X(addr), disp]);
415 }
416 (Size::S8, false, Location::GPR(reg)) => {
417 dynasm!(self ; lbu X(reg), [X(addr), disp]);
418 }
419 (Size::S8, true, Location::GPR(reg)) => {
420 dynasm!(self ; lb X(reg), [X(addr), disp]);
421 }
422 (Size::S64, _, Location::SIMD(reg)) => {
423 dynasm!(self ; fld F(reg), [X(addr), disp]);
424 }
425 (Size::S32, _, Location::SIMD(reg)) => {
426 dynasm!(self ; flw F(reg), [X(addr), disp]);
427 }
428 _ => codegen_error!("singlepass can't emit LD {:?}, {:?}, {:?}", sz, reg, addr),
429 }
430 Ok(())
431 }
432
433 fn emit_sd(&mut self, sz: Size, reg: Location, addr: Location) -> Result<(), CompileError> {
434 let Location::Memory(addr, disp) = addr else {
435 codegen_error!("singlepass can't emit SD {:?}, {:?}, {:?}", sz, reg, addr);
436 };
437 assert!(ImmType::Bits12.compatible_imm(disp as i64));
438
439 match (sz, reg) {
440 (Size::S64, Location::GPR(reg)) => {
441 dynasm!(self ; sd X(reg), [X(addr), disp]);
442 }
443 (Size::S32, Location::GPR(reg)) => {
444 dynasm!(self ; sw X(reg), [X(addr), disp]);
445 }
446 (Size::S16, Location::GPR(reg)) => {
447 dynasm!(self ; sh X(reg), [X(addr), disp]);
448 }
449 (Size::S8, Location::GPR(reg)) => {
450 dynasm!(self ; sb X(reg), [X(addr), disp]);
451 }
452 (Size::S64, Location::SIMD(reg)) => {
453 dynasm!(self ; fsd F(reg), [X(addr), disp]);
454 }
455 (Size::S32, Location::SIMD(reg)) => {
456 dynasm!(self ; fsw F(reg), [X(addr), disp]);
457 }
458 _ => codegen_error!("singlepass can't emit SD {:?}, {:?}, {:?}", sz, reg, addr),
459 }
460 Ok(())
461 }
462
463 fn emit_push(&mut self, size: Size, src: Location) -> Result<(), CompileError> {
464 match (size, src) {
465 (Size::S64, Location::GPR(_)) => {
466 self.emit_sub(
467 Size::S64,
468 Location::GPR(GPR::Sp),
469 Location::Imm64(8),
470 Location::GPR(GPR::Sp),
471 )?;
472 self.emit_sd(Size::S64, src, Location::Memory(GPR::Sp, 0))?;
473 }
474 _ => codegen_error!("singlepass can't emit PUSH {:?} {:?}", size, src),
475 }
476 Ok(())
477 }
478
479 fn emit_pop(&mut self, size: Size, dst: Location) -> Result<(), CompileError> {
480 match (size, dst) {
481 (Size::S64, Location::GPR(_)) => {
482 self.emit_ld(Size::S64, false, dst, Location::Memory(GPR::Sp, 0))?;
483 self.emit_add(
484 Size::S64,
485 Location::GPR(GPR::Sp),
486 Location::Imm64(8),
487 Location::GPR(GPR::Sp),
488 )?;
489 }
490 _ => codegen_error!("singlepass can't emit POP {:?} {:?}", size, dst),
491 }
492 Ok(())
493 }
494
495 fn emit_add(
496 &mut self,
497 sz: Size,
498 src1: Location,
499 src2: Location,
500 dst: Location,
501 ) -> Result<(), CompileError> {
502 match (sz, src1, src2, dst) {
503 (Size::S64, Location::GPR(src1), Location::GPR(src2), Location::GPR(dst)) => {
504 dynasm!(self ; add X(dst), X(src1), X(src2));
505 }
506 (Size::S64, Location::GPR(src1), Location::Imm64(imm), Location::GPR(dst))
507 | (Size::S64, Location::Imm64(imm), Location::GPR(src1), Location::GPR(dst)) => {
508 assert!(ImmType::Bits12.compatible_imm(imm as i64));
509 dynasm!(self ; addi X(dst), X(src1), imm as _);
510 }
511 (Size::S32, Location::GPR(src1), Location::GPR(src2), Location::GPR(dst)) => {
512 dynasm!(self ; addw X(dst), X(src1), X(src2));
513 }
514 (Size::S32, Location::GPR(src1), Location::Imm32(imm), Location::GPR(dst))
515 | (Size::S32, Location::Imm32(imm), Location::GPR(src1), Location::GPR(dst)) => {
516 assert!(ImmType::Bits12.compatible_imm(imm as i64));
517 dynasm!(self ; addiw X(dst), X(src1), imm as _);
518 }
519
520 (Size::S32, Location::SIMD(src1), Location::SIMD(src2), Location::SIMD(dst)) => {
521 dynasm!(self ; fadd.s F(dst), F(src1), F(src2));
522 }
523 (Size::S64, Location::SIMD(src1), Location::SIMD(src2), Location::SIMD(dst)) => {
524 dynasm!(self ; fadd.d F(dst), F(src1), F(src2));
525 }
526 _ => codegen_error!(
527 "singlepass can't emit ADD {:?} {:?} {:?} {:?}",
528 sz,
529 src1,
530 src2,
531 dst
532 ),
533 }
534 Ok(())
535 }
536
537 fn emit_sub(
538 &mut self,
539 sz: Size,
540 src1: Location,
541 src2: Location,
542 dst: Location,
543 ) -> Result<(), CompileError> {
544 match (sz, src1, src2, dst) {
545 (Size::S64, Location::GPR(src1), Location::GPR(src2), Location::GPR(dst)) => {
546 dynasm!(self ; sub X(dst), X(src1), X(src2));
547 }
548 (Size::S64, Location::GPR(src1), Location::Imm64(imm), Location::GPR(dst)) => {
549 assert!(ImmType::Bits12Subtraction.compatible_imm(imm as i64));
550 dynasm!(self ; addi X(dst), X(src1), -(imm as i32) as _);
551 }
552 (Size::S64, Location::GPR(src1), Location::Imm32(imm), Location::GPR(dst)) => {
553 assert!(ImmType::Bits12Subtraction.compatible_imm(imm as i64));
554 dynasm!(self ; addi X(dst), X(src1), -(imm as i32) as _);
555 }
556 (Size::S32, Location::GPR(src1), Location::GPR(src2), Location::GPR(dst)) => {
557 dynasm!(self ; subw X(dst), X(src1), X(src2));
558 }
559 (Size::S32, Location::GPR(src1), Location::Imm32(imm), Location::GPR(dst)) => {
560 assert!(ImmType::Bits12Subtraction.compatible_imm(imm as i64));
561 dynasm!(self ; addiw X(dst), X(src1), -(imm as i32) as _);
562 }
563 (Size::S32, Location::GPR(src1), Location::Imm64(imm), Location::GPR(dst)) => {
564 assert!(ImmType::Bits12Subtraction.compatible_imm(imm as i64));
565 dynasm!(self ; addiw X(dst), X(src1), -(imm as i32) as _);
566 }
567 (Size::S32, Location::SIMD(src1), Location::SIMD(src2), Location::SIMD(dst)) => {
568 dynasm!(self ; fsub.s F(dst), F(src1), F(src2));
569 }
570 (Size::S64, Location::SIMD(src1), Location::SIMD(src2), Location::SIMD(dst)) => {
571 dynasm!(self ; fsub.d F(dst), F(src1), F(src2));
572 }
573 _ => codegen_error!(
574 "singlepass can't emit SUB {:?} {:?} {:?} {:?}",
575 sz,
576 src1,
577 src2,
578 dst
579 ),
580 }
581 Ok(())
582 }
583
584 fn emit_mul(
585 &mut self,
586 sz: Size,
587 src1: Location,
588 src2: Location,
589 dst: Location,
590 ) -> Result<(), CompileError> {
591 match (sz, src1, src2, dst) {
592 (Size::S64, Location::GPR(src1), Location::GPR(src2), Location::GPR(dst)) => {
593 dynasm!(self ; mul X(dst), X(src1), X(src2));
594 }
595 (Size::S32, Location::GPR(src1), Location::GPR(src2), Location::GPR(dst)) => {
596 dynasm!(self ; mulw X(dst), X(src1), X(src2));
597 }
598
599 (Size::S32, Location::SIMD(src1), Location::SIMD(src2), Location::SIMD(dst)) => {
600 dynasm!(self ; fmul.s F(dst), F(src1), F(src2));
601 }
602 (Size::S64, Location::SIMD(src1), Location::SIMD(src2), Location::SIMD(dst)) => {
603 dynasm!(self ; fmul.d F(dst), F(src1), F(src2));
604 }
605
606 _ => codegen_error!(
607 "singlepass can't emit MUL {:?} {:?} {:?} {:?}",
608 sz,
609 src1,
610 src2,
611 dst
612 ),
613 }
614 Ok(())
615 }
616
617 fn emit_udiv(
618 &mut self,
619 sz: Size,
620 src1: Location,
621 src2: Location,
622 dst: Location,
623 ) -> Result<(), CompileError> {
624 match (sz, src1, src2, dst) {
625 (Size::S32, Location::GPR(src1), Location::GPR(src2), Location::GPR(dst)) => {
626 dynasm!(self ; divuw X(dst), X(src1), X(src2));
627 }
628 (Size::S64, Location::GPR(src1), Location::GPR(src2), Location::GPR(dst)) => {
629 dynasm!(self ; divu X(dst), X(src1), X(src2));
630 }
631 _ => codegen_error!(
632 "singlepass can't emit UDIV {:?} {:?} {:?} {:?}",
633 sz,
634 src1,
635 src2,
636 dst
637 ),
638 }
639 Ok(())
640 }
641 fn emit_sdiv(
642 &mut self,
643 sz: Size,
644 src1: Location,
645 src2: Location,
646 dst: Location,
647 ) -> Result<(), CompileError> {
648 match (sz, src1, src2, dst) {
649 (Size::S32, Location::GPR(src1), Location::GPR(src2), Location::GPR(dst)) => {
650 dynasm!(self ; divw X(dst), X(src1), X(src2));
651 }
652 (Size::S64, Location::GPR(src1), Location::GPR(src2), Location::GPR(dst)) => {
653 dynasm!(self ; div X(dst), X(src1), X(src2));
654 }
655 _ => codegen_error!(
656 "singlepass can't emit SDIV {:?} {:?} {:?} {:?}",
657 sz,
658 src1,
659 src2,
660 dst
661 ),
662 }
663 Ok(())
664 }
665
666 fn emit_urem(
667 &mut self,
668 sz: Size,
669 src1: Location,
670 src2: Location,
671 dst: Location,
672 ) -> Result<(), CompileError> {
673 match (sz, src1, src2, dst) {
674 (Size::S32, Location::GPR(src1), Location::GPR(src2), Location::GPR(dst)) => {
675 dynasm!(self ; remuw X(dst), X(src1), X(src2));
676 }
677 (Size::S64, Location::GPR(src1), Location::GPR(src2), Location::GPR(dst)) => {
678 dynasm!(self ; remu X(dst), X(src1), X(src2));
679 }
680 _ => codegen_error!(
681 "singlepass can't emit UREM {:?} {:?} {:?} {:?}",
682 sz,
683 src1,
684 src2,
685 dst
686 ),
687 }
688 Ok(())
689 }
690 fn emit_srem(
691 &mut self,
692 sz: Size,
693 src1: Location,
694 src2: Location,
695 dst: Location,
696 ) -> Result<(), CompileError> {
697 match (sz, src1, src2, dst) {
698 (Size::S32, Location::GPR(src1), Location::GPR(src2), Location::GPR(dst)) => {
699 dynasm!(self ; remw X(dst), X(src1), X(src2));
700 }
701 (Size::S64, Location::GPR(src1), Location::GPR(src2), Location::GPR(dst)) => {
702 dynasm!(self ; rem X(dst), X(src1), X(src2));
703 }
704 _ => codegen_error!(
705 "singlepass can't emit REM {:?} {:?} {:?} {:?}",
706 sz,
707 src1,
708 src2,
709 dst
710 ),
711 }
712 Ok(())
713 }
714
715 fn emit_and(
716 &mut self,
717 sz: Size,
718 src1: Location,
719 src2: Location,
720 dst: Location,
721 ) -> Result<(), CompileError> {
722 match (sz, src1, src2, dst) {
723 (
724 Size::S32 | Size::S64,
725 Location::GPR(src1),
726 Location::GPR(src2),
727 Location::GPR(dst),
728 ) => {
729 dynasm!(self ; and X(dst), X(src1), X(src2));
730 }
731 (Size::S64, Location::GPR(src1), Location::Imm64(imm), Location::GPR(dst)) => {
732 assert!(ImmType::Bits12Subtraction.compatible_imm(imm as i64));
733 dynasm!(self ; andi X(dst), X(src1), imm as _);
734 }
735 (Size::S32, Location::GPR(src1), Location::Imm32(imm), Location::GPR(dst)) => {
736 assert!(ImmType::Bits12Subtraction.compatible_imm(imm as i64));
737 dynasm!(self ; andi X(dst), X(src1), imm as _);
738 }
739 _ => codegen_error!(
740 "singlepass can't emit AND {:?} {:?} {:?} {:?}",
741 sz,
742 src1,
743 src2,
744 dst
745 ),
746 }
747 Ok(())
748 }
749
750 fn emit_or(
751 &mut self,
752 sz: Size,
753 src1: Location,
754 src2: Location,
755 dst: Location,
756 ) -> Result<(), CompileError> {
757 match (sz, src1, src2, dst) {
758 (
759 Size::S32 | Size::S64,
760 Location::GPR(src1),
761 Location::GPR(src2),
762 Location::GPR(dst),
763 ) => {
764 dynasm!(self ; or X(dst), X(src1), X(src2));
765 }
766 (Size::S64, Location::GPR(src1), Location::Imm64(imm), Location::GPR(dst)) => {
767 assert!(ImmType::Bits12Subtraction.compatible_imm(imm as i64));
768 dynasm!(self ; ori X(dst), X(src1), imm as _);
769 }
770 (Size::S32, Location::GPR(src1), Location::Imm32(imm), Location::GPR(dst)) => {
771 assert!(ImmType::Bits12Subtraction.compatible_imm(imm as i64));
772 dynasm!(self ; ori X(dst), X(src1), imm as _);
773 }
774 _ => codegen_error!(
775 "singlepass can't emit OR {:?} {:?} {:?} {:?}",
776 sz,
777 src1,
778 src2,
779 dst
780 ),
781 }
782 Ok(())
783 }
784
785 fn emit_xor(
786 &mut self,
787 sz: Size,
788 src1: Location,
789 src2: Location,
790 dst: Location,
791 ) -> Result<(), CompileError> {
792 match (sz, src1, src2, dst) {
793 (
794 Size::S32 | Size::S64,
795 Location::GPR(src1),
796 Location::GPR(src2),
797 Location::GPR(dst),
798 ) => {
799 dynasm!(self ; xor X(dst), X(src1), X(src2));
800 }
801 (Size::S64, Location::GPR(src1), Location::Imm64(imm), Location::GPR(dst)) => {
802 assert!(ImmType::Bits12Subtraction.compatible_imm(imm as i64));
803 dynasm!(self ; xori X(dst), X(src1), imm as _);
804 }
805 (Size::S32, Location::GPR(src1), Location::Imm32(imm), Location::GPR(dst)) => {
806 assert!(ImmType::Bits12Subtraction.compatible_imm(imm as i64));
807 dynasm!(self ; xori X(dst), X(src1), imm as _);
808 }
809 _ => codegen_error!(
810 "singlepass can't emit XOR {:?} {:?} {:?} {:?}",
811 sz,
812 src1,
813 src2,
814 dst
815 ),
816 }
817 Ok(())
818 }
819
820 fn emit_sll(
821 &mut self,
822 sz: Size,
823 src1: Location,
824 src2: Location,
825 dst: Location,
826 ) -> Result<(), CompileError> {
827 match (sz, src1, src2, dst) {
828 (Size::S64, Location::GPR(src1), Location::GPR(src2), Location::GPR(dst)) => {
829 dynasm!(self ; sll X(dst), X(src1), X(src2));
830 }
831 (Size::S64, Location::GPR(src1), Location::Imm64(imm), Location::GPR(dst)) => {
832 if imm >= u64::BITS as _ {
833 codegen_error!("singlepass SLL with incompatible imm {}", imm);
834 }
835 dynasm!(self ; slli X(dst), X(src1), imm as _);
836 }
837 (Size::S64, Location::GPR(src1), Location::Imm32(imm), Location::GPR(dst)) => {
838 if imm >= u64::BITS as _ {
839 codegen_error!("singlepass SLL with incompatible imm {}", imm);
840 }
841 dynasm!(self ; slli X(dst), X(src1), imm as _);
842 }
843 (Size::S32, Location::GPR(src1), Location::GPR(src2), Location::GPR(dst)) => {
844 dynasm!(self ; sllw X(dst), X(src1), X(src2));
845 }
846 (Size::S32, Location::GPR(src1), Location::Imm32(imm), Location::GPR(dst)) => {
847 if imm >= u32::BITS {
848 codegen_error!("singlepass SLL with incompatible imm {}", imm);
849 }
850 dynasm!(self ; slliw X(dst), X(src1), imm as _);
851 }
852 _ => codegen_error!(
853 "singlepass can't emit SLL {:?} {:?} {:?} {:?}",
854 sz,
855 src1,
856 src2,
857 dst
858 ),
859 }
860 Ok(())
861 }
862
863 fn emit_srl(
864 &mut self,
865 sz: Size,
866 src1: Location,
867 src2: Location,
868 dst: Location,
869 ) -> Result<(), CompileError> {
870 match (sz, src1, src2, dst) {
871 (Size::S64, Location::GPR(src1), Location::GPR(src2), Location::GPR(dst)) => {
872 dynasm!(self ; srl X(dst), X(src1), X(src2));
873 }
874 (Size::S64, Location::GPR(src1), Location::Imm64(imm), Location::GPR(dst)) => {
875 if imm >= u64::BITS as _ {
876 codegen_error!("singlepass SRL with incompatible imm {}", imm);
877 }
878 dynasm!(self ; srli X(dst), X(src1), imm as _);
879 }
880 (Size::S64, Location::GPR(src1), Location::Imm32(imm), Location::GPR(dst)) => {
881 if imm >= u64::BITS as _ {
882 codegen_error!("singlepass SRL with incompatible imm {}", imm);
883 }
884 dynasm!(self ; srli X(dst), X(src1), imm as _);
885 }
886 (Size::S32, Location::GPR(src1), Location::GPR(src2), Location::GPR(dst)) => {
887 dynasm!(self ; srlw X(dst), X(src1), X(src2));
888 }
889 (Size::S32, Location::GPR(src1), Location::Imm32(imm), Location::GPR(dst)) => {
890 if imm >= u32::BITS {
891 codegen_error!("singlepass SRL with incompatible imm {}", imm);
892 }
893 dynasm!(self ; srliw X(dst), X(src1), imm as _);
894 }
895 (Size::S32, Location::GPR(src1), Location::Imm64(imm), Location::GPR(dst)) => {
896 if imm >= u32::BITS as _ {
897 codegen_error!("singlepass SRL with incompatible imm {}", imm);
898 }
899 dynasm!(self ; srliw X(dst), X(src1), imm as _);
900 }
901 (Size::S32, Location::Imm32(imm), Location::GPR(src2), Location::GPR(dst)) => {
902 self.emit_mov_imm(Location::GPR(dst), imm as i64)?;
903 dynasm!(self ; srlw X(dst), X(dst), X(src2));
904 }
905 _ => codegen_error!(
906 "singlepass can't emit SRL {:?} {:?} {:?} {:?}",
907 sz,
908 src1,
909 src2,
910 dst
911 ),
912 }
913 Ok(())
914 }
915
916 fn emit_sra(
917 &mut self,
918 sz: Size,
919 src1: Location,
920 src2: Location,
921 dst: Location,
922 ) -> Result<(), CompileError> {
923 match (sz, src1, src2, dst) {
924 (Size::S64, Location::GPR(src1), Location::GPR(src2), Location::GPR(dst)) => {
925 dynasm!(self ; sra X(dst), X(src1), X(src2));
926 }
927 (Size::S64, Location::GPR(src1), Location::Imm64(imm), Location::GPR(dst)) => {
928 if imm >= u64::BITS as _ {
929 codegen_error!("singlepass SRA with incompatible imm {}", imm);
930 }
931 dynasm!(self ; srai X(dst), X(src1), imm as _);
932 }
933 (Size::S64, Location::GPR(src1), Location::Imm32(imm), Location::GPR(dst)) => {
934 if imm >= u64::BITS as _ {
935 codegen_error!("singlepass SRA with incompatible imm {}", imm);
936 }
937 dynasm!(self ; srai X(dst), X(src1), imm as _);
938 }
939 (Size::S32, Location::GPR(src1), Location::GPR(src2), Location::GPR(dst)) => {
940 dynasm!(self ; sraw X(dst), X(src1), X(src2));
941 }
942 (Size::S32, Location::GPR(src1), Location::Imm32(imm), Location::GPR(dst)) => {
943 if imm >= u32::BITS {
944 codegen_error!("singlepass SRA with incompatible imm {}", imm);
945 }
946 dynasm!(self ; sraiw X(dst), X(src1), imm as _);
947 }
948 _ => codegen_error!(
949 "singlepass can't emit SRA {:?} {:?} {:?} {:?}",
950 sz,
951 src1,
952 src2,
953 dst
954 ),
955 }
956 Ok(())
957 }
958
959 fn emit_extend(
960 &mut self,
961 sz: Size,
962 signed: bool,
963 src: Location,
964 dst: Location,
965 ) -> Result<(), CompileError> {
966 let bit_shift = match sz {
967 Size::S8 => 56,
968 Size::S16 => 48,
969 Size::S32 => 32,
970 _ => codegen_error!("singlepass can't emit SEXT {:?} {:?} {:?}", sz, src, dst),
971 };
972
973 match (signed, src, dst) {
974 (true, Location::GPR(src), Location::GPR(dst)) => {
975 dynasm!(self
976 ; slli X(dst), X(src), bit_shift
977 ; srai X(dst), X(dst), bit_shift
978 );
979 }
980 (false, Location::GPR(src), Location::GPR(dst)) => {
981 dynasm!(self
982 ; slli X(dst), X(src), bit_shift
983 ; srli X(dst), X(dst), bit_shift
984 );
985 }
986 _ => codegen_error!("singlepass can't emit SEXT {:?} {:?} {:?}", sz, src, dst),
987 };
988 Ok(())
989 }
990
991 fn emit_not(&mut self, sz: Size, src: Location, dst: Location) -> Result<(), CompileError> {
992 match (sz, src, dst) {
993 (Size::S64, Location::GPR(src), Location::GPR(dst)) => {
994 dynasm!(self ; not X(dst), X(src));
995 }
996 _ => codegen_error!("singlepass can't emit NOT {:?} {:?} {:?}", sz, src, dst),
997 }
998
999 Ok(())
1000 }
1001
1002 fn emit_neg(&mut self, sz: Size, src: Location, dst: Location) -> Result<(), CompileError> {
1003 match (sz, src, dst) {
1004 (Size::S64, Location::GPR(src), Location::GPR(dst)) => {
1005 dynasm!(self ; neg X(dst), X(src));
1006 }
1007 _ => codegen_error!("singlepass can't emit NEG {:?} {:?} {:?}", sz, src, dst),
1008 }
1009
1010 Ok(())
1011 }
1012
1013 fn emit_mov(&mut self, sz: Size, src: Location, dst: Location) -> Result<(), CompileError> {
1014 match (sz, src, dst) {
1015 (Size::S64, Location::GPR(src), Location::GPR(dst)) => {
1016 dynasm!(self ; mv X(dst), X(src));
1017 }
1018 (Size::S32, Location::GPR(src), Location::GPR(dst)) => {
1019 dynasm!(self
1020 ; slli X(dst), X(src), 32
1021 ; srli X(dst), X(dst), 32
1022 );
1023 }
1024 (Size::S64, Location::GPR(src), Location::SIMD(dst)) => {
1025 dynasm!(self ; fmv.d.x F(dst), X(src));
1026 }
1027 (Size::S64, Location::SIMD(src), Location::GPR(dst)) => {
1028 dynasm!(self ; fmv.x.d X(dst), F(src));
1029 }
1030 (Size::S32, Location::GPR(src), Location::SIMD(dst)) => {
1031 dynasm!(self ; fmv.s.x F(dst), X(src));
1032 }
1033 (Size::S32, Location::SIMD(src), Location::GPR(dst)) => {
1034 dynasm!(self ; fmv.x.s X(dst), F(src));
1035 }
1036 (Size::S64, Location::SIMD(src), Location::SIMD(dst)) => {
1037 dynasm!(self ; fmv.d F(dst), F(src));
1038 }
1039 (Size::S32, Location::SIMD(src), Location::SIMD(dst)) => {
1040 dynasm!(self ; fmv.s F(dst), F(src));
1041 }
1042 _ => codegen_error!("singlepass can't emit MOV {:?} {:?} {:?}", sz, src, dst),
1043 }
1044
1045 Ok(())
1046 }
1047
1048 fn emit_ret(&mut self) -> Result<(), CompileError> {
1049 dynasm!(self ; ret);
1050 Ok(())
1051 }
1052
1053 fn emit_mov_imm(&mut self, dst: Location, val: i64) -> Result<(), CompileError> {
1054 let used_bits = if val == i64::MIN {
1057 i64::BITS
1058 } else {
1059 i64::BITS - val.abs().leading_zeros() + 1
1060 };
1061
1062 match dst {
1063 Location::GPR(dst) => match used_bits {
1064 0..=12 => dynasm!(self ; li.12 X(dst), val as _),
1065 13..=32 => dynasm!(self ; li.32 X(dst), val as _),
1066 33..=43 => dynasm!(self ; li.43 X(dst), val),
1067 44..=54 => dynasm!(self ; li.54 X(dst), val),
1068 55..=64 => dynasm!(self ; li X(dst), val),
1069 _ => unreachable!(),
1070 },
1071 _ => codegen_error!("singlepass can't emit MOVIMM {:?}", dst),
1072 }
1073 Ok(())
1074 }
1075
1076 fn emit_fneg(&mut self, sz: Size, src: Location, dst: Location) -> Result<(), CompileError> {
1077 match (sz, src, dst) {
1078 (Size::S64, Location::SIMD(src), Location::SIMD(dst)) => {
1079 dynasm!(self ; fneg.d F(dst), F(src));
1080 }
1081 (Size::S32, Location::SIMD(src), Location::SIMD(dst)) => {
1082 dynasm!(self ; fneg.s F(dst), F(src));
1083 }
1084 _ => codegen_error!("singlepass can't emit FNEG {:?} {:?} {:?}", sz, src, dst),
1085 }
1086
1087 Ok(())
1088 }
1089
1090 fn emit_fmin(
1091 &mut self,
1092 sz: Size,
1093 src1: Location,
1094 src2: Location,
1095 dst: Location,
1096 ) -> Result<(), CompileError> {
1097 match (sz, src1, src2, dst) {
1098 (Size::S32, Location::SIMD(src1), Location::SIMD(src2), Location::SIMD(dst)) => {
1099 dynasm!(self ; fmin.s F(dst), F(src1), F(src2));
1100 }
1101 (Size::S64, Location::SIMD(src1), Location::SIMD(src2), Location::SIMD(dst)) => {
1102 dynasm!(self ; fmin.d F(dst), F(src1), F(src2));
1103 }
1104 _ => codegen_error!(
1105 "singlepass can't emit FMIN {:?} {:?} {:?} {:?}",
1106 sz,
1107 src1,
1108 src2,
1109 dst
1110 ),
1111 }
1112 Ok(())
1113 }
1114
1115 fn emit_fmax(
1116 &mut self,
1117 sz: Size,
1118 src1: Location,
1119 src2: Location,
1120 dst: Location,
1121 ) -> Result<(), CompileError> {
1122 match (sz, src1, src2, dst) {
1123 (Size::S32, Location::SIMD(src1), Location::SIMD(src2), Location::SIMD(dst)) => {
1124 dynasm!(self ; fmax.s F(dst), F(src1), F(src2));
1125 }
1126 (Size::S64, Location::SIMD(src1), Location::SIMD(src2), Location::SIMD(dst)) => {
1127 dynasm!(self ; fmax.d F(dst), F(src1), F(src2));
1128 }
1129 _ => codegen_error!(
1130 "singlepass can't emit FMAX {:?} {:?} {:?} {:?}",
1131 sz,
1132 src1,
1133 src2,
1134 dst
1135 ),
1136 }
1137 Ok(())
1138 }
1139
1140 fn emit_fdiv(
1141 &mut self,
1142 sz: Size,
1143 src1: Location,
1144 src2: Location,
1145 dst: Location,
1146 ) -> Result<(), CompileError> {
1147 match (sz, src1, src2, dst) {
1148 (Size::S32, Location::SIMD(src1), Location::SIMD(src2), Location::SIMD(dst)) => {
1149 dynasm!(self ; fdiv.s F(dst), F(src1), F(src2));
1150 }
1151 (Size::S64, Location::SIMD(src1), Location::SIMD(src2), Location::SIMD(dst)) => {
1152 dynasm!(self ; fdiv.d F(dst), F(src1), F(src2));
1153 }
1154 _ => codegen_error!(
1155 "singlepass can't emit FDIV {:?} {:?} {:?} {:?}",
1156 sz,
1157 src1,
1158 src2,
1159 dst
1160 ),
1161 }
1162 Ok(())
1163 }
1164
1165 fn emit_fsqrt(&mut self, sz: Size, src: Location, dst: Location) -> Result<(), CompileError> {
1166 match (sz, src, dst) {
1167 (Size::S32, Location::SIMD(src), Location::SIMD(dst)) => {
1168 dynasm!(self ; fsqrt.s F(dst), F(src));
1169 }
1170 (Size::S64, Location::SIMD(src), Location::SIMD(dst)) => {
1171 dynasm!(self ; fsqrt.d F(dst), F(src));
1172 }
1173 _ => codegen_error!("singlepass can't emit FSQRT {:?} {:?} {:?}", sz, src, dst),
1174 }
1175 Ok(())
1176 }
1177
1178 fn emit_fcvt(
1179 &mut self,
1180 signed: bool,
1181 sz_in: Size,
1182 src: Location,
1183 sz_out: Size,
1184 dst: Location,
1185 ) -> Result<(), CompileError> {
1186 match (signed, sz_in, src, sz_out, dst) {
1187 (_, Size::S32, Location::SIMD(src), Size::S64, Location::SIMD(dst)) => {
1189 dynasm!(self ; fcvt.d.s F(dst), F(src));
1190 }
1191 (_, Size::S64, Location::SIMD(src), Size::S32, Location::SIMD(dst)) => {
1192 dynasm!(self ; fcvt.s.d F(dst), F(src));
1193 }
1194 (true, Size::S32, Location::SIMD(src), Size::S32, Location::GPR(dst)) => {
1196 dynasm!(self ; fcvt.w.s X(dst), F(src), rtz);
1197 }
1198 (true, Size::S64, Location::SIMD(src), Size::S32, Location::GPR(dst)) => {
1199 dynasm!(self ; fcvt.w.d X(dst), F(src), rtz);
1200 }
1201 (true, Size::S32, Location::SIMD(src), Size::S64, Location::GPR(dst)) => {
1202 dynasm!(self ; fcvt.l.s X(dst), F(src), rtz);
1203 }
1204 (true, Size::S64, Location::SIMD(src), Size::S64, Location::GPR(dst)) => {
1205 dynasm!(self ; fcvt.l.d X(dst), F(src), rtz);
1206 }
1207 (false, Size::S32, Location::SIMD(src), Size::S32, Location::GPR(dst)) => {
1208 dynasm!(self ; fcvt.wu.s X(dst), F(src), rtz);
1209 }
1210 (false, Size::S64, Location::SIMD(src), Size::S32, Location::GPR(dst)) => {
1211 dynasm!(self ; fcvt.wu.d X(dst), F(src), rtz);
1212 }
1213 (false, Size::S32, Location::SIMD(src), Size::S64, Location::GPR(dst)) => {
1214 dynasm!(self ; fcvt.lu.s X(dst), F(src), rtz);
1215 }
1216 (false, Size::S64, Location::SIMD(src), Size::S64, Location::GPR(dst)) => {
1217 dynasm!(self ; fcvt.lu.d X(dst), F(src), rtz);
1218 }
1219 (true, Size::S32, Location::GPR(src), Size::S32, Location::SIMD(dst)) => {
1221 dynasm!(self ; fcvt.s.w F(dst), X(src));
1222 }
1223 (true, Size::S64, Location::GPR(src), Size::S32, Location::SIMD(dst)) => {
1224 dynasm!(self ; fcvt.s.l F(dst), X(src));
1225 }
1226 (true, Size::S32, Location::GPR(src), Size::S64, Location::SIMD(dst)) => {
1227 dynasm!(self ; fcvt.d.w F(dst), X(src));
1228 }
1229 (true, Size::S64, Location::GPR(src), Size::S64, Location::SIMD(dst)) => {
1230 dynasm!(self ; fcvt.d.l F(dst), X(src));
1231 }
1232
1233 (false, Size::S32, Location::GPR(src), Size::S32, Location::SIMD(dst)) => {
1234 dynasm!(self ; fcvt.s.wu F(dst), X(src));
1235 }
1236 (false, Size::S64, Location::GPR(src), Size::S32, Location::SIMD(dst)) => {
1237 dynasm!(self ; fcvt.s.lu F(dst), X(src));
1238 }
1239 (false, Size::S32, Location::GPR(src), Size::S64, Location::SIMD(dst)) => {
1240 dynasm!(self ; fcvt.d.wu F(dst), X(src));
1241 }
1242 (false, Size::S64, Location::GPR(src), Size::S64, Location::SIMD(dst)) => {
1243 dynasm!(self ; fcvt.d.lu F(dst), X(src));
1244 }
1245 _ => codegen_error!(
1246 "singlepass can't emit FCVT {:?} {:?} {:?} {:?}",
1247 sz_in,
1248 src,
1249 sz_out,
1250 dst
1251 ),
1252 }
1253 Ok(())
1254 }
1255
1256 fn emit_fcvt_with_rounding(
1257 &mut self,
1258 rounding: RoundingMode,
1259 size: Size,
1260 src: Location,
1261 dst: Location,
1262 tmp: GPR,
1263 ) -> Result<(), CompileError> {
1264 let (Location::SIMD(src), Location::SIMD(dst)) = (src, dst) else {
1265 codegen_error!(
1266 "singlepass can't emit FCVT with rounding for non-register operands: {:?} {:?} {:?} {:?}",
1267 src,
1268 dst,
1269 size,
1270 rounding
1271 )
1272 };
1273
1274 match (size, rounding) {
1275 (Size::S32, RoundingMode::Rne) => {
1276 dynasm!(self
1277 ; fcvt.w.s X(tmp), F(src), rne
1278 ; fcvt.s.w F(dst), X(tmp), rne
1279 ; fsgnj.s F(dst), F(dst), F(src));
1280 }
1281 (Size::S32, RoundingMode::Rtz) => {
1282 dynasm!(self
1283 ; fcvt.w.s X(tmp), F(src), rtz
1284 ; fcvt.s.w F(dst), X(tmp), rtz
1285 ; fsgnj.s F(dst), F(dst), F(src));
1286 }
1287 (Size::S32, RoundingMode::Rdn) => {
1288 dynasm!(self
1289 ; fcvt.w.s X(tmp), F(src), rdn
1290 ; fcvt.s.w F(dst), X(tmp), rdn
1291 ; fsgnj.s F(dst), F(dst), F(src));
1292 }
1293 (Size::S32, RoundingMode::Rup) => {
1294 dynasm!(self
1295 ; fcvt.w.s X(tmp), F(src), rup
1296 ; fcvt.s.w F(dst), X(tmp), rup
1297 ; fsgnj.s F(dst), F(dst), F(src));
1298 }
1299
1300 (Size::S64, RoundingMode::Rne) => {
1301 dynasm!(self
1302 ; fcvt.l.d X(tmp), F(src), rne
1303 ; fcvt.d.l F(dst), X(tmp), rne
1304 ; fsgnj.d F(dst), F(dst), F(src));
1305 }
1306 (Size::S64, RoundingMode::Rtz) => {
1307 dynasm!(self
1308 ; fcvt.l.d X(tmp), F(src), rtz
1309 ; fcvt.d.l F(dst), X(tmp), rtz
1310 ; fsgnj.d F(dst), F(dst), F(src));
1311 }
1312 (Size::S64, RoundingMode::Rdn) => {
1313 dynasm!(self
1314 ; fcvt.l.d X(tmp), F(src), rdn
1315 ; fcvt.d.l F(dst), X(tmp), rdn
1316 ; fsgnj.d F(dst), F(dst), F(src));
1317 }
1318 (Size::S64, RoundingMode::Rup) => {
1319 dynasm!(self
1320 ; fcvt.l.d X(tmp), F(src), rup
1321 ; fcvt.d.l F(dst), X(tmp), rup
1322 ; fsgnj.d F(dst), F(dst), F(src));
1323 }
1324 _ => codegen_error!(
1325 "singlepass can't emit FCVT with rounding {:?} {:?}",
1326 size,
1327 rounding
1328 ),
1329 }
1330
1331 Ok(())
1332 }
1333
1334 fn emit_swap_fscr(&mut self, reg: GPR) -> Result<(), CompileError> {
1336 dynasm!(self ; fscsr X(reg), X(reg));
1337 Ok(())
1338 }
1339
1340 fn emit_cmp(
1341 &mut self,
1342 c: Condition,
1343 loc_a: Location,
1344 loc_b: Location,
1345 ret: Location,
1346 ) -> Result<(), CompileError> {
1347 let (Location::GPR(loc_a), Location::GPR(loc_b), Location::GPR(ret)) = (loc_a, loc_b, ret)
1348 else {
1349 codegen_error!(
1350 "singlepass can't emit CMP {:?} {:?} {:?}",
1351 loc_a,
1352 loc_b,
1353 ret
1354 );
1355 };
1356
1357 match c {
1358 Condition::Lt => {
1360 dynasm!(self; slt X(ret), X(loc_a), X(loc_b));
1361 }
1362 Condition::Le => {
1363 dynasm!(self
1364 ; slt X(ret), X(loc_b), X(loc_a)
1365 ; xori X(ret), X(ret), 1);
1366 }
1367 Condition::Gt => {
1368 dynasm!(self; slt X(ret), X(loc_b), X(loc_a));
1369 }
1370 Condition::Ge => {
1371 dynasm!(self
1372 ; slt X(ret), X(loc_a), X(loc_b)
1373 ; xori X(ret), X(ret), 1);
1374 }
1375 Condition::Eq => {
1376 dynasm!(self
1377 ; xor X(ret), X(loc_a), X(loc_b)
1378 ; seqz X(ret), X(ret));
1379 }
1380 Condition::Ne => {
1381 dynasm!(self
1382 ; xor X(ret), X(loc_a), X(loc_b)
1383 ; snez X(ret), X(ret));
1384 }
1385 Condition::Ltu => {
1387 dynasm!(self; sltu X(ret), X(loc_a), X(loc_b));
1388 }
1389 Condition::Leu => {
1390 dynasm!(self
1391 ; sltu X(ret), X(loc_b), X(loc_a)
1392 ; xori X(ret), X(ret), 1);
1393 }
1394 Condition::Gtu => {
1395 dynasm!(self; sltu X(ret), X(loc_b), X(loc_a));
1396 }
1397 Condition::Geu => {
1398 dynasm!(self
1399 ; sltu X(ret), X(loc_a), X(loc_b)
1400 ; xori X(ret), X(ret), 1);
1401 }
1402 }
1403
1404 Ok(())
1405 }
1406
1407 fn emit_fcmp(
1408 &mut self,
1409 c: Condition,
1410 size: Size,
1411 loc_a: Location,
1412 loc_b: Location,
1413 ret: Location,
1414 ) -> Result<(), CompileError> {
1415 let (Location::SIMD(loc_a), Location::SIMD(loc_b), Location::GPR(ret)) =
1416 (loc_a, loc_b, ret)
1417 else {
1418 codegen_error!(
1419 "singlepass can't emit FCMP {:?} {:?} {:?}",
1420 loc_a,
1421 loc_b,
1422 ret
1423 );
1424 };
1425
1426 match (size, c) {
1427 (Size::S32, Condition::Lt) => {
1428 dynasm!(self ; flt.s X(ret), F(loc_a), F(loc_b));
1429 }
1430 (Size::S32, Condition::Le) => {
1431 dynasm!(self ; fle.s X(ret), F(loc_a), F(loc_b));
1432 }
1433 (Size::S32, Condition::Gt) => {
1434 dynasm!(self ; flt.s X(ret), F(loc_b), F(loc_a));
1435 }
1436 (Size::S32, Condition::Ge) => {
1437 dynasm!(self ; fle.s X(ret), F(loc_b), F(loc_a));
1438 }
1439 (Size::S32, Condition::Eq) => {
1440 dynasm!(self ; feq.s X(ret), F(loc_a), F(loc_b));
1441 }
1442 (Size::S32, Condition::Ne) => {
1443 dynasm!(self
1444 ; feq.s X(ret), F(loc_a), F(loc_b)
1445 ; xori X(ret), X(ret), 1);
1446 }
1447
1448 (Size::S64, Condition::Lt) => {
1449 dynasm!(self ; flt.d X(ret), F(loc_a), F(loc_b));
1450 }
1451 (Size::S64, Condition::Le) => {
1452 dynasm!(self ; fle.d X(ret), F(loc_a), F(loc_b));
1453 }
1454 (Size::S64, Condition::Gt) => {
1455 dynasm!(self ; flt.d X(ret), F(loc_b), F(loc_a));
1456 }
1457 (Size::S64, Condition::Ge) => {
1458 dynasm!(self; fle.d X(ret), F(loc_b), F(loc_a));
1459 }
1460 (Size::S64, Condition::Eq) => {
1461 dynasm!(self ; feq.d X(ret), F(loc_a), F(loc_b));
1462 }
1463 (Size::S64, Condition::Ne) => {
1464 dynasm!(self
1465 ; feq.d X(ret), F(loc_a), F(loc_b)
1466 ; xori X(ret), X(ret), 1);
1467 }
1468 _ => codegen_error!(
1469 "singlepass can't emit FCMP {:?} {:?} {:?}",
1470 loc_a,
1471 loc_b,
1472 ret
1473 ),
1474 }
1475
1476 Ok(())
1477 }
1478
1479 fn emit_jmp_on_condition(
1480 &mut self,
1481 cond: Condition,
1482 loc_a: Location,
1483 loc_b: Location,
1484 label: Label,
1485 tmp: GPR,
1486 ) -> Result<(), CompileError> {
1487 let (Location::GPR(loc_a), Location::GPR(loc_b)) = (loc_a, loc_b) else {
1488 codegen_error!("singlepass can't emit JMP_ON_COND {:?} {:?} ", loc_a, loc_b,);
1489 };
1490
1491 let jump: Label = self.get_label();
1492 let cont: Label = self.get_label();
1493
1494 match cond {
1495 Condition::Eq => {
1496 dynasm!(self; beq X(loc_a), X(loc_b), => jump);
1497 }
1498 Condition::Ne => {
1499 dynasm!(self; bne X(loc_a), X(loc_b), => jump);
1500 }
1501 Condition::Ltu => {
1502 dynasm!(self; bltu X(loc_a), X(loc_b), => jump);
1503 }
1504 Condition::Leu => {
1505 dynasm!(self; bleu X(loc_a), X(loc_b), => jump);
1506 }
1507 Condition::Gtu => {
1508 dynasm!(self; bgtu X(loc_a), X(loc_b), => jump);
1509 }
1510 Condition::Geu => {
1511 dynasm!(self; bgeu X(loc_a), X(loc_b), => jump);
1512 }
1513 _ => codegen_error!(
1514 "singlepass can't emit jump on conditional branch {:?}",
1515 cond
1516 ),
1517 }
1518
1519 self.emit_j_label(cont, Some(tmp))?;
1520 self.emit_label(jump)?;
1521 self.emit_j_label(label, Some(tmp))?;
1522
1523 self.emit_label(cont)?;
1524
1525 Ok(())
1526 }
1527
1528 fn emit_on_false_label(
1529 &mut self,
1530 cond: Location,
1531 label: Label,
1532 tmp: GPR,
1533 ) -> Result<(), CompileError> {
1534 match cond {
1535 Location::GPR(cond) => {
1536 dynasm!(self; beqz X(cond), => label);
1537 }
1538 _ if cond.is_imm() => {
1539 let imm = cond.imm_value_scalar().unwrap();
1540 if imm == 0 {
1541 return self.emit_j_label(label, Some(tmp));
1542 }
1543 }
1544 _ => codegen_error!("singlepass can't emit jump to false branch {:?}", cond),
1545 }
1546 Ok(())
1547 }
1548 fn emit_on_false_label_far(
1549 &mut self,
1550 cond: Location,
1551 label: Label,
1552 tmp: GPR,
1553 ) -> Result<(), CompileError> {
1554 let cont: Label = self.get_label();
1555 match cond {
1556 Location::GPR(cond) => {
1557 dynasm!(self; bnez X(cond), => cont);
1560 }
1561 _ if cond.is_imm() => {
1562 let imm = cond.imm_value_scalar().unwrap();
1563 if imm == 0 {
1564 return self.emit_j_label(label, Some(tmp));
1565 } else {
1566 self.emit_j_label(cont, Some(tmp))?;
1567 }
1568 }
1569 _ => codegen_error!("singlepass can't emit jump to false branch {:?}", cond),
1570 }
1571
1572 self.emit_j_label(label, Some(tmp))?;
1573 self.emit_label(cont)?;
1574 Ok(())
1575 }
1576 fn emit_on_true_label(
1577 &mut self,
1578 cond: Location,
1579 label: Label,
1580 tmp: GPR,
1581 ) -> Result<(), CompileError> {
1582 match cond {
1583 Location::GPR(cond) => {
1584 dynasm!(self; bnez X(cond), => label);
1585 }
1586 _ if cond.is_imm() => {
1587 let imm = cond.imm_value_scalar().unwrap();
1588 if imm != 0 {
1589 return self.emit_j_label(label, Some(tmp));
1590 }
1591 }
1592 _ => codegen_error!("singlepass can't emit jump to true branch {:?}", cond),
1593 }
1594 Ok(())
1595 }
1596 fn emit_on_true_label_far(
1597 &mut self,
1598 cond: Location,
1599 label: Label,
1600 tmp: GPR,
1601 ) -> Result<(), CompileError> {
1602 let cont: Label = self.get_label();
1603 let jump_label: Label = self.get_label();
1604 match cond {
1605 Location::GPR(cond) => {
1606 dynasm!(self; bnez X(cond), => jump_label);
1607 }
1608 _ if cond.is_imm() => {
1609 let imm = cond.imm_value_scalar().unwrap();
1610 if imm == 1 {
1611 return self.emit_j_label(jump_label, Some(tmp));
1612 }
1613 }
1614 _ => codegen_error!("singlepass can't emit jump to false branch {:?}", cond),
1615 }
1616
1617 self.emit_j_label(cont, Some(tmp))?;
1619
1620 self.emit_label(jump_label)?;
1621 self.emit_j_label(label, Some(tmp))?;
1622
1623 self.emit_label(cont)?;
1624
1625 Ok(())
1626 }
1627
1628 fn emit_j_label(&mut self, label: Label, reg: Option<GPR>) -> Result<(), CompileError> {
1629 if let Some(reg) = reg {
1630 dynasm!(self ; jump => label, X(reg));
1631 } else {
1632 dynasm!(self ; j => label);
1633 }
1634 Ok(())
1635 }
1636
1637 fn emit_j_register(&mut self, reg: GPR) -> Result<(), CompileError> {
1638 dynasm!(self ; jalr zero, X(reg), 0);
1639 Ok(())
1640 }
1641
1642 fn emit_call_label(&mut self, label: Label) -> Result<(), CompileError> {
1643 dynasm!(self ; call =>label);
1644 Ok(())
1645 }
1646
1647 fn emit_call_register(&mut self, reg: GPR) -> Result<(), CompileError> {
1648 dynasm!(self ; jalr ra, X(reg), 0);
1649 Ok(())
1650 }
1651
1652 fn emit_load_label(&mut self, reg: GPR, label: Label) -> Result<(), CompileError> {
1653 dynasm!(self ; la X(reg), => label);
1654 Ok(())
1655 }
1656
1657 fn emit_rwfence(&mut self) -> Result<(), CompileError> {
1658 dynasm!(self ; fence rw, rw);
1659 Ok(())
1660 }
1661
1662 fn emit_atomic_binop(
1663 &mut self,
1664 op: AtomicBinaryOp,
1665 size: Size,
1666 dest: GPR,
1667 addr: GPR,
1668 source: GPR,
1669 ) -> Result<(), CompileError> {
1670 match (size, op) {
1671 (Size::S64, AtomicBinaryOp::Add) => {
1672 dynasm!(self ; amoadd.d.aqrl X(dest), X(source), [X(addr)])
1673 }
1674 (Size::S64, AtomicBinaryOp::Or) => {
1675 dynasm!(self ; amoor.d.aqrl X(dest), X(source), [X(addr)])
1676 }
1677 (Size::S64, AtomicBinaryOp::Xor) => {
1678 dynasm!(self ; amoxor.d.aqrl X(dest), X(source), [X(addr)])
1679 }
1680 (Size::S64, AtomicBinaryOp::And) => {
1681 dynasm!(self ; amoand.d.aqrl X(dest), X(source), [X(addr)])
1682 }
1683 (Size::S64, AtomicBinaryOp::Exchange) => {
1684 dynasm!(self ; amoswap.d.aqrl X(dest), X(source), [X(addr)])
1685 }
1686
1687 (Size::S32, AtomicBinaryOp::Add) => {
1688 dynasm!(self ; amoadd.w.aqrl X(dest), X(source), [X(addr)])
1689 }
1690 (Size::S32, AtomicBinaryOp::Or) => {
1691 dynasm!(self ; amoor.w.aqrl X(dest), X(source), [X(addr)])
1692 }
1693 (Size::S32, AtomicBinaryOp::Xor) => {
1694 dynasm!(self ; amoxor.w.aqrl X(dest), X(source), [X(addr)])
1695 }
1696 (Size::S32, AtomicBinaryOp::And) => {
1697 dynasm!(self ; amoand.w.aqrl X(dest), X(source), [X(addr)])
1698 }
1699 (Size::S32, AtomicBinaryOp::Exchange) => {
1700 dynasm!(self ; amoswap.w.aqrl X(dest), X(source), [X(addr)])
1701 }
1702 _ => codegen_error!("singlepass can't emit atomic binop {:?} {:?}", size, op),
1703 }
1704
1705 Ok(())
1706 }
1707
1708 fn emit_reserved_ld(&mut self, size: Size, reg: GPR, addr: GPR) -> Result<(), CompileError> {
1709 match size {
1710 Size::S32 => {
1711 dynasm!(self ; lr.w.aqrl X(reg), [X(addr)])
1712 }
1713 Size::S64 => {
1714 dynasm!(self ; lr.d.aqrl X(reg), [X(addr)])
1715 }
1716 _ => codegen_error!("singlepass can't emit atomic reserved ld {:?}", size),
1717 }
1718
1719 Ok(())
1720 }
1721
1722 fn emit_reserved_sd(
1723 &mut self,
1724 size: Size,
1725 dest: GPR,
1726 addr: GPR,
1727 source: GPR,
1728 ) -> Result<(), CompileError> {
1729 match size {
1730 Size::S32 => {
1731 dynasm!(self ; sc.w.rl X(dest), X(source), [X(addr)])
1732 }
1733 Size::S64 => {
1734 dynasm!(self ; sc.d.rl X(dest), X(source), [X(addr)])
1735 }
1736 _ => codegen_error!("singlepass can't emit atomic reserved sd {:?}", size),
1737 }
1738
1739 Ok(())
1740 }
1741}
1742
1743pub fn gen_std_trampoline_riscv(
1744 sig: &FunctionType,
1745 _calling_convention: CallingConvention,
1746) -> Result<FunctionBody, CompileError> {
1747 let mut a = Assembler::new(0);
1748
1749 let fptr = GPR::X26;
1751 let args = GPR::X27;
1752
1753 dynasm!(a
1754 ; addi sp, sp, -32
1755 ; sd s0, [sp,24]
1756 ; sd ra, [sp,16]
1757 ; sd X(fptr), [sp, 8]
1758 ; sd X(args), [sp, 0]
1759 ; mv s0, sp ; mv X(fptr), a1
1761 ; mv X(args), a2
1762 );
1763
1764 let stack_args = sig.params().len().saturating_sub(7); let stack_return_slots = sig
1766 .results()
1767 .len()
1768 .saturating_sub(RISCV_RETURN_VALUE_REGISTERS.len());
1769 let mut stack_offset = (stack_args + stack_return_slots) as u32 * 8;
1770 if stack_offset > 0 {
1771 stack_offset = stack_offset.next_multiple_of(16);
1772 if ImmType::Bits12Subtraction.compatible_imm(stack_offset as _) {
1773 dynasm!(a ; addi sp, sp, -(stack_offset as i32));
1774 } else {
1775 a.emit_mov_imm(Location::GPR(SCRATCH_REG), stack_offset as _)?;
1776 dynasm!(a ; sub sp, sp, X(SCRATCH_REG));
1777 }
1778 }
1779
1780 let mut caller_stack_offset: i32 = stack_return_slots as i32 * 8;
1783 for (i, param) in sig.params().iter().enumerate() {
1784 let sz = match *param {
1785 Type::I32 | Type::F32 => Size::S32,
1786 Type::I64 | Type::F64 => Size::S64,
1787 Type::ExternRef => Size::S64,
1788 Type::FuncRef => Size::S64,
1789 _ => codegen_error!(
1790 "singlepass unsupported param type for trampoline {:?}",
1791 *param
1792 ),
1793 };
1794 match i {
1795 0..=6 => {
1796 a.emit_ld(
1797 sz,
1798 false,
1799 Location::GPR(GPR::from_index(i + 10 + 1).unwrap()),
1800 Location::Memory(args, (i * 16) as i32),
1801 )?;
1802 }
1803 _ => {
1804 let args_offset = (i * 16) as i32;
1805 let arg_location = if ImmType::Bits12.compatible_imm(args_offset as i64) {
1806 Location::Memory(args, args_offset)
1807 } else {
1808 a.emit_mov_imm(Location::GPR(SCRATCH_REG), args_offset as i64)?;
1809 a.emit_add(
1810 Size::S64,
1811 Location::GPR(args),
1812 Location::GPR(SCRATCH_REG),
1813 Location::GPR(SCRATCH_REG),
1814 )?;
1815 Location::Memory(SCRATCH_REG, 0)
1816 };
1817 a.emit_ld(sz, false, Location::GPR(SCRATCH_REG), arg_location)?;
1818
1819 let arg_dest_location =
1820 if ImmType::Bits12.compatible_imm(caller_stack_offset as i64) {
1821 Location::Memory(GPR::Sp, caller_stack_offset)
1822 } else {
1823 a.emit_mov_imm(Location::GPR(GPR::X29), caller_stack_offset as i64)?;
1824 a.emit_add(
1825 Size::S64,
1826 Location::GPR(GPR::X29),
1827 Location::GPR(GPR::Sp),
1828 Location::GPR(GPR::X29),
1829 )?;
1830 Location::Memory(GPR::X29, 0)
1831 };
1832 a.emit_sd(sz, Location::GPR(SCRATCH_REG), arg_dest_location)?;
1833 caller_stack_offset += 8;
1834 }
1835 }
1836 }
1837
1838 dynasm!(a
1839 ; jalr ra, X(fptr), 0);
1840
1841 let mut n_stack_return_slots: usize = 0;
1843 for i in 0..sig.results().len() {
1844 let src = if let Some(®) = RISCV_RETURN_VALUE_REGISTERS.get(i) {
1845 reg
1846 } else {
1847 a.emit_ld(
1848 Size::S64,
1849 false,
1850 Location::GPR(SCRATCH_REG),
1851 Location::Memory(GPR::Sp, (n_stack_return_slots as u32 * 8) as _),
1852 )?;
1853 n_stack_return_slots += 1;
1854 SCRATCH_REG
1855 };
1856 a.emit_sd(
1857 Size::S64,
1858 Location::GPR(src),
1859 Location::Memory(args, (i * 16) as _),
1860 )?;
1861 }
1862
1863 dynasm!(a
1865 ; ld X(args), [s0,0]
1866 ; ld X(fptr), [s0,8]
1867 ; ld ra, [s0,16]
1868 ; ld s0, [s0,24]
1869 );
1870 let restored_stack_offset = 32 + stack_offset;
1871 if ImmType::Bits12.compatible_imm(restored_stack_offset as _) {
1872 dynasm!(a; addi sp, sp, restored_stack_offset as _);
1873 } else {
1874 a.emit_mov_imm(Location::GPR(SCRATCH_REG), restored_stack_offset as _)?;
1875 dynasm!(a; add sp, sp, X(SCRATCH_REG));
1876 }
1877 dynasm!(a; ret);
1878
1879 let mut body = a.finalize().unwrap();
1880
1881 body.shrink_to_fit();
1882 Ok(FunctionBody {
1883 body,
1884 unwind_info: None,
1885 })
1886}
1887
1888pub fn gen_std_dynamic_import_trampoline_riscv(
1890 vmoffsets: &VMOffsets,
1891 sig: &FunctionType,
1892) -> Result<FunctionBody, CompileError> {
1893 let mut a = Assembler::new(0);
1894 let stack_offset: usize = 16 * std::cmp::max(sig.params().len(), sig.results().len());
1896
1897 a.emit_push(Size::S64, Location::GPR(GPR::X1))?;
1899 a.emit_push(Size::S64, Location::GPR(SCRATCH_REG))?;
1900
1901 if stack_offset != 0 {
1902 if ImmType::Bits12Subtraction.compatible_imm(stack_offset as _) {
1903 a.emit_sub(
1904 Size::S64,
1905 Location::GPR(GPR::Sp),
1906 Location::Imm64(stack_offset as _),
1907 Location::GPR(GPR::Sp),
1908 )?;
1909 } else {
1910 a.emit_mov_imm(Location::GPR(SCRATCH_REG), stack_offset as _)?;
1911 a.emit_sub(
1912 Size::S64,
1913 Location::GPR(GPR::Sp),
1914 Location::GPR(SCRATCH_REG),
1915 Location::GPR(GPR::Sp),
1916 )?;
1917 }
1918 }
1919
1920 if !sig.params().is_empty() {
1922 let mut argalloc = ArgumentRegisterAllocator::default();
1923 argalloc.next(Type::I64).unwrap(); let mut stack_param_count: usize = 0;
1926
1927 for (i, ty) in sig.params().iter().enumerate() {
1928 let source_loc = match argalloc.next(*ty)? {
1929 Some(RiscvRegister::GPR(gpr)) => Location::GPR(gpr),
1930 Some(RiscvRegister::FPR(fpr)) => Location::SIMD(fpr),
1931 None => {
1932 a.emit_ld(
1933 Size::S64,
1934 false,
1935 Location::GPR(SCRATCH_REG),
1936 Location::Memory(GPR::Sp, (stack_offset + 16 + stack_param_count) as _),
1937 )?;
1938 stack_param_count += 8;
1939 Location::GPR(SCRATCH_REG)
1940 }
1941 };
1942 a.emit_sd(
1943 Size::S64,
1944 source_loc,
1945 Location::Memory(GPR::Sp, (i * 16) as _),
1946 )?;
1947 a.emit_sd(
1949 Size::S64,
1950 Location::GPR(GPR::XZero),
1951 Location::Memory(GPR::Sp, (i * 16 + 8) as _),
1952 )?;
1953 }
1954 }
1955
1956 let offset = vmoffsets.vmdynamicfunction_import_context_address();
1958 a.emit_ld(
1959 Size::S64,
1960 false,
1961 Location::GPR(SCRATCH_REG),
1962 Location::Memory(GPR::X10, offset as i32),
1963 )?;
1964 a.emit_add(
1966 Size::S64,
1967 Location::GPR(GPR::Sp),
1968 Location::Imm64(0),
1969 Location::GPR(GPR::X11),
1970 )?;
1971
1972 a.emit_call_register(SCRATCH_REG)?;
1974
1975 if !sig.results().is_empty() {
1977 assert_eq!(sig.results().len(), 1);
1978 a.emit_ld(
1979 Size::S64,
1980 false,
1981 Location::GPR(GPR::X10),
1982 Location::Memory(GPR::Sp, 0),
1983 )?;
1984 }
1985
1986 if stack_offset != 0 {
1988 if ImmType::Bits12.compatible_imm(stack_offset as _) {
1989 a.emit_add(
1990 Size::S64,
1991 Location::GPR(GPR::Sp),
1992 Location::Imm64(stack_offset as _),
1993 Location::GPR(GPR::Sp),
1994 )?;
1995 } else {
1996 a.emit_mov_imm(Location::GPR(SCRATCH_REG), stack_offset as _)?;
1997 a.emit_add(
1998 Size::S64,
1999 Location::GPR(GPR::Sp),
2000 Location::GPR(SCRATCH_REG),
2001 Location::GPR(GPR::Sp),
2002 )?;
2003 }
2004 }
2005 a.emit_pop(Size::S64, Location::GPR(SCRATCH_REG))?;
2006 a.emit_pop(Size::S64, Location::GPR(GPR::X1))?;
2007
2008 a.emit_ret()?;
2010
2011 let mut body = a.finalize().unwrap();
2012 body.shrink_to_fit();
2013 Ok(FunctionBody {
2014 body,
2015 unwind_info: None,
2016 })
2017}
2018
2019pub fn gen_import_call_trampoline_riscv(
2021 vmoffsets: &VMOffsets,
2022 index: FunctionIndex,
2023 sig: &FunctionType,
2024 _calling_convention: CallingConvention,
2025) -> Result<CustomSection, CompileError> {
2026 let mut a = Assembler::new(0);
2027
2028 if sig
2033 .params()
2034 .iter()
2035 .any(|&x| x == Type::F32 || x == Type::F64)
2036 {
2037 const PARAM_REGS: &[GPR] = &[
2038 GPR::X11,
2040 GPR::X12,
2041 GPR::X13,
2042 GPR::X14,
2043 GPR::X15,
2044 GPR::X16,
2045 GPR::X17,
2046 ];
2047 const PARAM_REGS_COUNT: usize = PARAM_REGS.len();
2048
2049 let stack_offset: i32 = if sig.params().len() > PARAM_REGS_COUNT {
2051 (PARAM_REGS_COUNT * 8) as i32
2052 } else {
2053 (sig.params().len() as i32) * 8
2054 };
2055 if stack_offset > 0 {
2056 if ImmType::Bits12Subtraction.compatible_imm(stack_offset as _) {
2057 a.emit_sub(
2058 Size::S64,
2059 Location::GPR(GPR::Sp),
2060 Location::Imm64(stack_offset as _),
2061 Location::GPR(GPR::Sp),
2062 )?;
2063 } else {
2064 a.emit_mov_imm(Location::GPR(SCRATCH_REG), stack_offset as _)?;
2065 a.emit_sub(
2066 Size::S64,
2067 Location::GPR(GPR::Sp),
2068 Location::GPR(SCRATCH_REG),
2069 Location::GPR(GPR::Sp),
2070 )?;
2071 }
2072 }
2073
2074 let mut param_locations = vec![];
2077 #[allow(clippy::needless_range_loop)]
2079 for i in 0..sig.params().len() {
2080 let loc = match i {
2081 0..PARAM_REGS_COUNT => {
2082 let loc = Location::Memory(GPR::Sp, (i * 8) as i32);
2083 a.emit_sd(Size::S64, Location::GPR(PARAM_REGS[i]), loc)?;
2084 loc
2085 }
2086 _ => Location::Memory(GPR::Sp, stack_offset + ((i - PARAM_REGS_COUNT) * 8) as i32),
2087 };
2088 param_locations.push(loc);
2089 }
2090
2091 let mut caller_stack_offset: i32 = 0;
2093 let mut argalloc = ArgumentRegisterAllocator::default();
2094 argalloc.next(Type::I64).unwrap(); for (i, ty) in sig.params().iter().enumerate() {
2096 let prev_loc = param_locations[i];
2097 let targ = match argalloc.next(*ty)? {
2098 Some(RiscvRegister::GPR(gpr)) => Location::GPR(gpr),
2099 Some(RiscvRegister::FPR(neon)) => Location::SIMD(neon),
2100 None => {
2101 a.emit_ld(Size::S64, false, Location::GPR(SCRATCH_REG), prev_loc)?;
2103 a.emit_sd(
2104 Size::S64,
2105 Location::GPR(SCRATCH_REG),
2106 Location::Memory(GPR::Sp, stack_offset + caller_stack_offset),
2107 )?;
2108 caller_stack_offset += 8;
2109 continue;
2110 }
2111 };
2112 a.emit_ld(Size::S64, false, targ, prev_loc)?;
2113 }
2114
2115 if stack_offset > 0 {
2117 if ImmType::Bits12.compatible_imm(stack_offset as _) {
2118 a.emit_add(
2119 Size::S64,
2120 Location::GPR(GPR::Sp),
2121 Location::Imm64(stack_offset as _),
2122 Location::GPR(GPR::Sp),
2123 )?;
2124 } else {
2125 a.emit_mov_imm(Location::GPR(SCRATCH_REG), stack_offset as _)?;
2126 a.emit_add(
2127 Size::S64,
2128 Location::GPR(GPR::Sp),
2129 Location::GPR(SCRATCH_REG),
2130 Location::GPR(GPR::Sp),
2131 )?;
2132 }
2133 }
2134 }
2135
2136 let offset = vmoffsets.vmctx_vmfunction_import(index);
2140
2141 a.emit_ld(
2142 Size::S64,
2143 false,
2144 Location::GPR(SCRATCH_REG),
2145 Location::Memory(GPR::X10, offset as i32), )?;
2147 a.emit_ld(
2148 Size::S64,
2149 false,
2150 Location::GPR(GPR::X10),
2151 Location::Memory(GPR::X10, offset as i32 + 8), )?;
2153
2154 a.emit_j_register(SCRATCH_REG)?;
2155
2156 let mut contents = a.finalize().unwrap();
2157 contents.shrink_to_fit();
2158 let section_body = SectionBody::new_with_vec(contents);
2159
2160 Ok(CustomSection {
2161 protection: CustomSectionProtection::ReadExecute,
2162 alignment: None,
2163 bytes: section_body,
2164 relocations: vec![],
2165 })
2166}