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::S64, Location::GPR(src1), Location::Imm32(imm), Location::GPR(dst))
512 | (Size::S64, Location::Imm32(imm), Location::GPR(src1), Location::GPR(dst)) => {
513 assert!(ImmType::Bits12.compatible_imm(imm as i64));
514 dynasm!(self ; addi X(dst), X(src1), imm as _);
515 }
516 (Size::S32, Location::GPR(src1), Location::GPR(src2), Location::GPR(dst)) => {
517 dynasm!(self ; addw X(dst), X(src1), X(src2));
518 }
519 (Size::S32, Location::GPR(src1), Location::Imm32(imm), Location::GPR(dst))
520 | (Size::S32, Location::Imm32(imm), Location::GPR(src1), Location::GPR(dst)) => {
521 assert!(ImmType::Bits12.compatible_imm(imm as i64));
522 dynasm!(self ; addiw X(dst), X(src1), imm as _);
523 }
524
525 (Size::S32, Location::SIMD(src1), Location::SIMD(src2), Location::SIMD(dst)) => {
526 dynasm!(self ; fadd.s F(dst), F(src1), F(src2));
527 }
528 (Size::S64, Location::SIMD(src1), Location::SIMD(src2), Location::SIMD(dst)) => {
529 dynasm!(self ; fadd.d F(dst), F(src1), F(src2));
530 }
531 _ => codegen_error!(
532 "singlepass can't emit ADD {:?} {:?} {:?} {:?}",
533 sz,
534 src1,
535 src2,
536 dst
537 ),
538 }
539 Ok(())
540 }
541
542 fn emit_sub(
543 &mut self,
544 sz: Size,
545 src1: Location,
546 src2: Location,
547 dst: Location,
548 ) -> Result<(), CompileError> {
549 match (sz, src1, src2, dst) {
550 (Size::S64, Location::GPR(src1), Location::GPR(src2), Location::GPR(dst)) => {
551 dynasm!(self ; sub X(dst), X(src1), X(src2));
552 }
553 (Size::S64, Location::GPR(src1), Location::Imm64(imm), Location::GPR(dst)) => {
554 assert!(ImmType::Bits12Subtraction.compatible_imm(imm as i64));
555 dynasm!(self ; addi X(dst), X(src1), -(imm as i32) as _);
556 }
557 (Size::S64, Location::GPR(src1), Location::Imm32(imm), Location::GPR(dst)) => {
558 assert!(ImmType::Bits12Subtraction.compatible_imm(imm as i64));
559 dynasm!(self ; addi X(dst), X(src1), -(imm as i32) as _);
560 }
561 (Size::S32, Location::GPR(src1), Location::GPR(src2), Location::GPR(dst)) => {
562 dynasm!(self ; subw X(dst), X(src1), X(src2));
563 }
564 (Size::S32, Location::GPR(src1), Location::Imm32(imm), Location::GPR(dst)) => {
565 assert!(ImmType::Bits12Subtraction.compatible_imm(imm as i64));
566 dynasm!(self ; addiw X(dst), X(src1), -(imm as i32) as _);
567 }
568 (Size::S32, Location::GPR(src1), Location::Imm64(imm), Location::GPR(dst)) => {
569 assert!(ImmType::Bits12Subtraction.compatible_imm(imm as i64));
570 dynasm!(self ; addiw X(dst), X(src1), -(imm as i32) as _);
571 }
572 (Size::S32, Location::SIMD(src1), Location::SIMD(src2), Location::SIMD(dst)) => {
573 dynasm!(self ; fsub.s F(dst), F(src1), F(src2));
574 }
575 (Size::S64, Location::SIMD(src1), Location::SIMD(src2), Location::SIMD(dst)) => {
576 dynasm!(self ; fsub.d F(dst), F(src1), F(src2));
577 }
578 _ => codegen_error!(
579 "singlepass can't emit SUB {:?} {:?} {:?} {:?}",
580 sz,
581 src1,
582 src2,
583 dst
584 ),
585 }
586 Ok(())
587 }
588
589 fn emit_mul(
590 &mut self,
591 sz: Size,
592 src1: Location,
593 src2: Location,
594 dst: Location,
595 ) -> Result<(), CompileError> {
596 match (sz, src1, src2, dst) {
597 (Size::S64, Location::GPR(src1), Location::GPR(src2), Location::GPR(dst)) => {
598 dynasm!(self ; mul X(dst), X(src1), X(src2));
599 }
600 (Size::S32, Location::GPR(src1), Location::GPR(src2), Location::GPR(dst)) => {
601 dynasm!(self ; mulw X(dst), X(src1), X(src2));
602 }
603
604 (Size::S32, Location::SIMD(src1), Location::SIMD(src2), Location::SIMD(dst)) => {
605 dynasm!(self ; fmul.s F(dst), F(src1), F(src2));
606 }
607 (Size::S64, Location::SIMD(src1), Location::SIMD(src2), Location::SIMD(dst)) => {
608 dynasm!(self ; fmul.d F(dst), F(src1), F(src2));
609 }
610
611 _ => codegen_error!(
612 "singlepass can't emit MUL {:?} {:?} {:?} {:?}",
613 sz,
614 src1,
615 src2,
616 dst
617 ),
618 }
619 Ok(())
620 }
621
622 fn emit_udiv(
623 &mut self,
624 sz: Size,
625 src1: Location,
626 src2: Location,
627 dst: Location,
628 ) -> Result<(), CompileError> {
629 match (sz, src1, src2, dst) {
630 (Size::S32, Location::GPR(src1), Location::GPR(src2), Location::GPR(dst)) => {
631 dynasm!(self ; divuw X(dst), X(src1), X(src2));
632 }
633 (Size::S64, Location::GPR(src1), Location::GPR(src2), Location::GPR(dst)) => {
634 dynasm!(self ; divu X(dst), X(src1), X(src2));
635 }
636 _ => codegen_error!(
637 "singlepass can't emit UDIV {:?} {:?} {:?} {:?}",
638 sz,
639 src1,
640 src2,
641 dst
642 ),
643 }
644 Ok(())
645 }
646 fn emit_sdiv(
647 &mut self,
648 sz: Size,
649 src1: Location,
650 src2: Location,
651 dst: Location,
652 ) -> Result<(), CompileError> {
653 match (sz, src1, src2, dst) {
654 (Size::S32, Location::GPR(src1), Location::GPR(src2), Location::GPR(dst)) => {
655 dynasm!(self ; divw X(dst), X(src1), X(src2));
656 }
657 (Size::S64, Location::GPR(src1), Location::GPR(src2), Location::GPR(dst)) => {
658 dynasm!(self ; div X(dst), X(src1), X(src2));
659 }
660 _ => codegen_error!(
661 "singlepass can't emit SDIV {:?} {:?} {:?} {:?}",
662 sz,
663 src1,
664 src2,
665 dst
666 ),
667 }
668 Ok(())
669 }
670
671 fn emit_urem(
672 &mut self,
673 sz: Size,
674 src1: Location,
675 src2: Location,
676 dst: Location,
677 ) -> Result<(), CompileError> {
678 match (sz, src1, src2, dst) {
679 (Size::S32, Location::GPR(src1), Location::GPR(src2), Location::GPR(dst)) => {
680 dynasm!(self ; remuw X(dst), X(src1), X(src2));
681 }
682 (Size::S64, Location::GPR(src1), Location::GPR(src2), Location::GPR(dst)) => {
683 dynasm!(self ; remu X(dst), X(src1), X(src2));
684 }
685 _ => codegen_error!(
686 "singlepass can't emit UREM {:?} {:?} {:?} {:?}",
687 sz,
688 src1,
689 src2,
690 dst
691 ),
692 }
693 Ok(())
694 }
695 fn emit_srem(
696 &mut self,
697 sz: Size,
698 src1: Location,
699 src2: Location,
700 dst: Location,
701 ) -> Result<(), CompileError> {
702 match (sz, src1, src2, dst) {
703 (Size::S32, Location::GPR(src1), Location::GPR(src2), Location::GPR(dst)) => {
704 dynasm!(self ; remw X(dst), X(src1), X(src2));
705 }
706 (Size::S64, Location::GPR(src1), Location::GPR(src2), Location::GPR(dst)) => {
707 dynasm!(self ; rem X(dst), X(src1), X(src2));
708 }
709 _ => codegen_error!(
710 "singlepass can't emit REM {:?} {:?} {:?} {:?}",
711 sz,
712 src1,
713 src2,
714 dst
715 ),
716 }
717 Ok(())
718 }
719
720 fn emit_and(
721 &mut self,
722 sz: Size,
723 src1: Location,
724 src2: Location,
725 dst: Location,
726 ) -> Result<(), CompileError> {
727 match (sz, src1, src2, dst) {
728 (
729 Size::S32 | Size::S64,
730 Location::GPR(src1),
731 Location::GPR(src2),
732 Location::GPR(dst),
733 ) => {
734 dynasm!(self ; and X(dst), X(src1), X(src2));
735 }
736 (Size::S64, Location::GPR(src1), Location::Imm64(imm), Location::GPR(dst)) => {
737 assert!(ImmType::Bits12Subtraction.compatible_imm(imm as i64));
738 dynasm!(self ; andi X(dst), X(src1), imm as _);
739 }
740 (Size::S32, Location::GPR(src1), Location::Imm32(imm), Location::GPR(dst)) => {
741 assert!(ImmType::Bits12Subtraction.compatible_imm(imm as i64));
742 dynasm!(self ; andi X(dst), X(src1), imm as _);
743 }
744 _ => codegen_error!(
745 "singlepass can't emit AND {:?} {:?} {:?} {:?}",
746 sz,
747 src1,
748 src2,
749 dst
750 ),
751 }
752 Ok(())
753 }
754
755 fn emit_or(
756 &mut self,
757 sz: Size,
758 src1: Location,
759 src2: Location,
760 dst: Location,
761 ) -> Result<(), CompileError> {
762 match (sz, src1, src2, dst) {
763 (
764 Size::S32 | Size::S64,
765 Location::GPR(src1),
766 Location::GPR(src2),
767 Location::GPR(dst),
768 ) => {
769 dynasm!(self ; or X(dst), X(src1), X(src2));
770 }
771 (Size::S64, Location::GPR(src1), Location::Imm64(imm), Location::GPR(dst)) => {
772 assert!(ImmType::Bits12Subtraction.compatible_imm(imm as i64));
773 dynasm!(self ; ori X(dst), X(src1), imm as _);
774 }
775 (Size::S32, Location::GPR(src1), Location::Imm32(imm), Location::GPR(dst)) => {
776 assert!(ImmType::Bits12Subtraction.compatible_imm(imm as i64));
777 dynasm!(self ; ori X(dst), X(src1), imm as _);
778 }
779 _ => codegen_error!(
780 "singlepass can't emit OR {:?} {:?} {:?} {:?}",
781 sz,
782 src1,
783 src2,
784 dst
785 ),
786 }
787 Ok(())
788 }
789
790 fn emit_xor(
791 &mut self,
792 sz: Size,
793 src1: Location,
794 src2: Location,
795 dst: Location,
796 ) -> Result<(), CompileError> {
797 match (sz, src1, src2, dst) {
798 (
799 Size::S32 | Size::S64,
800 Location::GPR(src1),
801 Location::GPR(src2),
802 Location::GPR(dst),
803 ) => {
804 dynasm!(self ; xor X(dst), X(src1), X(src2));
805 }
806 (Size::S64, Location::GPR(src1), Location::Imm64(imm), Location::GPR(dst)) => {
807 assert!(ImmType::Bits12Subtraction.compatible_imm(imm as i64));
808 dynasm!(self ; xori X(dst), X(src1), imm as _);
809 }
810 (Size::S32, Location::GPR(src1), Location::Imm32(imm), Location::GPR(dst)) => {
811 assert!(ImmType::Bits12Subtraction.compatible_imm(imm as i64));
812 dynasm!(self ; xori X(dst), X(src1), imm as _);
813 }
814 _ => codegen_error!(
815 "singlepass can't emit XOR {:?} {:?} {:?} {:?}",
816 sz,
817 src1,
818 src2,
819 dst
820 ),
821 }
822 Ok(())
823 }
824
825 fn emit_sll(
826 &mut self,
827 sz: Size,
828 src1: Location,
829 src2: Location,
830 dst: Location,
831 ) -> Result<(), CompileError> {
832 match (sz, src1, src2, dst) {
833 (Size::S64, Location::GPR(src1), Location::GPR(src2), Location::GPR(dst)) => {
834 dynasm!(self ; sll X(dst), X(src1), X(src2));
835 }
836 (Size::S64, Location::GPR(src1), Location::Imm64(imm), Location::GPR(dst)) => {
837 if imm >= u64::BITS as _ {
838 codegen_error!("singlepass SLL with incompatible imm {}", imm);
839 }
840 dynasm!(self ; slli X(dst), X(src1), imm as _);
841 }
842 (Size::S64, Location::GPR(src1), Location::Imm32(imm), Location::GPR(dst)) => {
843 if imm >= u64::BITS as _ {
844 codegen_error!("singlepass SLL with incompatible imm {}", imm);
845 }
846 dynasm!(self ; slli X(dst), X(src1), imm as _);
847 }
848 (Size::S32, Location::GPR(src1), Location::GPR(src2), Location::GPR(dst)) => {
849 dynasm!(self ; sllw X(dst), X(src1), X(src2));
850 }
851 (Size::S32, Location::GPR(src1), Location::Imm32(imm), Location::GPR(dst)) => {
852 if imm >= u32::BITS {
853 codegen_error!("singlepass SLL with incompatible imm {}", imm);
854 }
855 dynasm!(self ; slliw X(dst), X(src1), imm as _);
856 }
857 _ => codegen_error!(
858 "singlepass can't emit SLL {:?} {:?} {:?} {:?}",
859 sz,
860 src1,
861 src2,
862 dst
863 ),
864 }
865 Ok(())
866 }
867
868 fn emit_srl(
869 &mut self,
870 sz: Size,
871 src1: Location,
872 src2: Location,
873 dst: Location,
874 ) -> Result<(), CompileError> {
875 match (sz, src1, src2, dst) {
876 (Size::S64, Location::GPR(src1), Location::GPR(src2), Location::GPR(dst)) => {
877 dynasm!(self ; srl X(dst), X(src1), X(src2));
878 }
879 (Size::S64, Location::GPR(src1), Location::Imm64(imm), Location::GPR(dst)) => {
880 if imm >= u64::BITS as _ {
881 codegen_error!("singlepass SRL with incompatible imm {}", imm);
882 }
883 dynasm!(self ; srli X(dst), X(src1), imm as _);
884 }
885 (Size::S64, Location::GPR(src1), Location::Imm32(imm), Location::GPR(dst)) => {
886 if imm >= u64::BITS as _ {
887 codegen_error!("singlepass SRL with incompatible imm {}", imm);
888 }
889 dynasm!(self ; srli X(dst), X(src1), imm as _);
890 }
891 (Size::S32, Location::GPR(src1), Location::GPR(src2), Location::GPR(dst)) => {
892 dynasm!(self ; srlw X(dst), X(src1), X(src2));
893 }
894 (Size::S32, Location::GPR(src1), Location::Imm32(imm), Location::GPR(dst)) => {
895 if imm >= u32::BITS {
896 codegen_error!("singlepass SRL with incompatible imm {}", imm);
897 }
898 dynasm!(self ; srliw X(dst), X(src1), imm as _);
899 }
900 (Size::S32, Location::GPR(src1), Location::Imm64(imm), Location::GPR(dst)) => {
901 if imm >= u32::BITS as _ {
902 codegen_error!("singlepass SRL with incompatible imm {}", imm);
903 }
904 dynasm!(self ; srliw X(dst), X(src1), imm as _);
905 }
906 (Size::S32, Location::Imm32(imm), Location::GPR(src2), Location::GPR(dst)) => {
907 self.emit_mov_imm(Location::GPR(dst), imm as i64)?;
908 dynasm!(self ; srlw X(dst), X(dst), X(src2));
909 }
910 _ => codegen_error!(
911 "singlepass can't emit SRL {:?} {:?} {:?} {:?}",
912 sz,
913 src1,
914 src2,
915 dst
916 ),
917 }
918 Ok(())
919 }
920
921 fn emit_sra(
922 &mut self,
923 sz: Size,
924 src1: Location,
925 src2: Location,
926 dst: Location,
927 ) -> Result<(), CompileError> {
928 match (sz, src1, src2, dst) {
929 (Size::S64, Location::GPR(src1), Location::GPR(src2), Location::GPR(dst)) => {
930 dynasm!(self ; sra X(dst), X(src1), X(src2));
931 }
932 (Size::S64, Location::GPR(src1), Location::Imm64(imm), Location::GPR(dst)) => {
933 if imm >= u64::BITS as _ {
934 codegen_error!("singlepass SRA with incompatible imm {}", imm);
935 }
936 dynasm!(self ; srai X(dst), X(src1), imm as _);
937 }
938 (Size::S64, Location::GPR(src1), Location::Imm32(imm), Location::GPR(dst)) => {
939 if imm >= u64::BITS as _ {
940 codegen_error!("singlepass SRA with incompatible imm {}", imm);
941 }
942 dynasm!(self ; srai X(dst), X(src1), imm as _);
943 }
944 (Size::S32, Location::GPR(src1), Location::GPR(src2), Location::GPR(dst)) => {
945 dynasm!(self ; sraw X(dst), X(src1), X(src2));
946 }
947 (Size::S32, Location::GPR(src1), Location::Imm32(imm), Location::GPR(dst)) => {
948 if imm >= u32::BITS {
949 codegen_error!("singlepass SRA with incompatible imm {}", imm);
950 }
951 dynasm!(self ; sraiw X(dst), X(src1), imm as _);
952 }
953 _ => codegen_error!(
954 "singlepass can't emit SRA {:?} {:?} {:?} {:?}",
955 sz,
956 src1,
957 src2,
958 dst
959 ),
960 }
961 Ok(())
962 }
963
964 fn emit_extend(
965 &mut self,
966 sz: Size,
967 signed: bool,
968 src: Location,
969 dst: Location,
970 ) -> Result<(), CompileError> {
971 let bit_shift = match sz {
972 Size::S8 => 56,
973 Size::S16 => 48,
974 Size::S32 => 32,
975 _ => codegen_error!("singlepass can't emit SEXT {:?} {:?} {:?}", sz, src, dst),
976 };
977
978 match (signed, src, dst) {
979 (true, Location::GPR(src), Location::GPR(dst)) => {
980 dynasm!(self
981 ; slli X(dst), X(src), bit_shift
982 ; srai X(dst), X(dst), bit_shift
983 );
984 }
985 (false, Location::GPR(src), Location::GPR(dst)) => {
986 dynasm!(self
987 ; slli X(dst), X(src), bit_shift
988 ; srli X(dst), X(dst), bit_shift
989 );
990 }
991 _ => codegen_error!("singlepass can't emit SEXT {:?} {:?} {:?}", sz, src, dst),
992 };
993 Ok(())
994 }
995
996 fn emit_not(&mut self, sz: Size, src: Location, dst: Location) -> Result<(), CompileError> {
997 match (sz, src, dst) {
998 (Size::S64, Location::GPR(src), Location::GPR(dst)) => {
999 dynasm!(self ; not X(dst), X(src));
1000 }
1001 _ => codegen_error!("singlepass can't emit NOT {:?} {:?} {:?}", sz, src, dst),
1002 }
1003
1004 Ok(())
1005 }
1006
1007 fn emit_neg(&mut self, sz: Size, src: Location, dst: Location) -> Result<(), CompileError> {
1008 match (sz, src, dst) {
1009 (Size::S64, Location::GPR(src), Location::GPR(dst)) => {
1010 dynasm!(self ; neg X(dst), X(src));
1011 }
1012 _ => codegen_error!("singlepass can't emit NEG {:?} {:?} {:?}", sz, src, dst),
1013 }
1014
1015 Ok(())
1016 }
1017
1018 fn emit_mov(&mut self, sz: Size, src: Location, dst: Location) -> Result<(), CompileError> {
1019 match (sz, src, dst) {
1020 (Size::S64, Location::GPR(src), Location::GPR(dst)) => {
1021 dynasm!(self ; mv X(dst), X(src));
1022 }
1023 (Size::S32, Location::GPR(src), Location::GPR(dst)) => {
1024 dynasm!(self
1025 ; slli X(dst), X(src), 32
1026 ; srli X(dst), X(dst), 32
1027 );
1028 }
1029 (Size::S64, Location::GPR(src), Location::SIMD(dst)) => {
1030 dynasm!(self ; fmv.d.x F(dst), X(src));
1031 }
1032 (Size::S64, Location::SIMD(src), Location::GPR(dst)) => {
1033 dynasm!(self ; fmv.x.d X(dst), F(src));
1034 }
1035 (Size::S32, Location::GPR(src), Location::SIMD(dst)) => {
1036 dynasm!(self ; fmv.s.x F(dst), X(src));
1037 }
1038 (Size::S32, Location::SIMD(src), Location::GPR(dst)) => {
1039 dynasm!(self ; fmv.x.s X(dst), F(src));
1040 }
1041 (Size::S64, Location::SIMD(src), Location::SIMD(dst)) => {
1042 dynasm!(self ; fmv.d F(dst), F(src));
1043 }
1044 (Size::S32, Location::SIMD(src), Location::SIMD(dst)) => {
1045 dynasm!(self ; fmv.s F(dst), F(src));
1046 }
1047 _ => codegen_error!("singlepass can't emit MOV {:?} {:?} {:?}", sz, src, dst),
1048 }
1049
1050 Ok(())
1051 }
1052
1053 fn emit_ret(&mut self) -> Result<(), CompileError> {
1054 dynasm!(self ; ret);
1055 Ok(())
1056 }
1057
1058 fn emit_mov_imm(&mut self, dst: Location, val: i64) -> Result<(), CompileError> {
1059 let used_bits = if val == i64::MIN {
1062 i64::BITS
1063 } else {
1064 i64::BITS - val.abs().leading_zeros() + 1
1065 };
1066
1067 match dst {
1068 Location::GPR(dst) => match used_bits {
1069 0..=12 => dynasm!(self ; li.12 X(dst), val as _),
1070 13..=32 => dynasm!(self ; li.32 X(dst), val as _),
1071 33..=43 => dynasm!(self ; li.43 X(dst), val),
1072 44..=54 => dynasm!(self ; li.54 X(dst), val),
1073 55..=64 => dynasm!(self ; li X(dst), val),
1074 _ => unreachable!(),
1075 },
1076 _ => codegen_error!("singlepass can't emit MOVIMM {:?}", dst),
1077 }
1078 Ok(())
1079 }
1080
1081 fn emit_fneg(&mut self, sz: Size, src: Location, dst: Location) -> Result<(), CompileError> {
1082 match (sz, src, dst) {
1083 (Size::S64, Location::SIMD(src), Location::SIMD(dst)) => {
1084 dynasm!(self ; fneg.d F(dst), F(src));
1085 }
1086 (Size::S32, Location::SIMD(src), Location::SIMD(dst)) => {
1087 dynasm!(self ; fneg.s F(dst), F(src));
1088 }
1089 _ => codegen_error!("singlepass can't emit FNEG {:?} {:?} {:?}", sz, src, dst),
1090 }
1091
1092 Ok(())
1093 }
1094
1095 fn emit_fmin(
1096 &mut self,
1097 sz: Size,
1098 src1: Location,
1099 src2: Location,
1100 dst: Location,
1101 ) -> Result<(), CompileError> {
1102 match (sz, src1, src2, dst) {
1103 (Size::S32, Location::SIMD(src1), Location::SIMD(src2), Location::SIMD(dst)) => {
1104 dynasm!(self ; fmin.s F(dst), F(src1), F(src2));
1105 }
1106 (Size::S64, Location::SIMD(src1), Location::SIMD(src2), Location::SIMD(dst)) => {
1107 dynasm!(self ; fmin.d F(dst), F(src1), F(src2));
1108 }
1109 _ => codegen_error!(
1110 "singlepass can't emit FMIN {:?} {:?} {:?} {:?}",
1111 sz,
1112 src1,
1113 src2,
1114 dst
1115 ),
1116 }
1117 Ok(())
1118 }
1119
1120 fn emit_fmax(
1121 &mut self,
1122 sz: Size,
1123 src1: Location,
1124 src2: Location,
1125 dst: Location,
1126 ) -> Result<(), CompileError> {
1127 match (sz, src1, src2, dst) {
1128 (Size::S32, Location::SIMD(src1), Location::SIMD(src2), Location::SIMD(dst)) => {
1129 dynasm!(self ; fmax.s F(dst), F(src1), F(src2));
1130 }
1131 (Size::S64, Location::SIMD(src1), Location::SIMD(src2), Location::SIMD(dst)) => {
1132 dynasm!(self ; fmax.d F(dst), F(src1), F(src2));
1133 }
1134 _ => codegen_error!(
1135 "singlepass can't emit FMAX {:?} {:?} {:?} {:?}",
1136 sz,
1137 src1,
1138 src2,
1139 dst
1140 ),
1141 }
1142 Ok(())
1143 }
1144
1145 fn emit_fdiv(
1146 &mut self,
1147 sz: Size,
1148 src1: Location,
1149 src2: Location,
1150 dst: Location,
1151 ) -> Result<(), CompileError> {
1152 match (sz, src1, src2, dst) {
1153 (Size::S32, Location::SIMD(src1), Location::SIMD(src2), Location::SIMD(dst)) => {
1154 dynasm!(self ; fdiv.s F(dst), F(src1), F(src2));
1155 }
1156 (Size::S64, Location::SIMD(src1), Location::SIMD(src2), Location::SIMD(dst)) => {
1157 dynasm!(self ; fdiv.d F(dst), F(src1), F(src2));
1158 }
1159 _ => codegen_error!(
1160 "singlepass can't emit FDIV {:?} {:?} {:?} {:?}",
1161 sz,
1162 src1,
1163 src2,
1164 dst
1165 ),
1166 }
1167 Ok(())
1168 }
1169
1170 fn emit_fsqrt(&mut self, sz: Size, src: Location, dst: Location) -> Result<(), CompileError> {
1171 match (sz, src, dst) {
1172 (Size::S32, Location::SIMD(src), Location::SIMD(dst)) => {
1173 dynasm!(self ; fsqrt.s F(dst), F(src));
1174 }
1175 (Size::S64, Location::SIMD(src), Location::SIMD(dst)) => {
1176 dynasm!(self ; fsqrt.d F(dst), F(src));
1177 }
1178 _ => codegen_error!("singlepass can't emit FSQRT {:?} {:?} {:?}", sz, src, dst),
1179 }
1180 Ok(())
1181 }
1182
1183 fn emit_fcvt(
1184 &mut self,
1185 signed: bool,
1186 sz_in: Size,
1187 src: Location,
1188 sz_out: Size,
1189 dst: Location,
1190 ) -> Result<(), CompileError> {
1191 match (signed, sz_in, src, sz_out, dst) {
1192 (_, Size::S32, Location::SIMD(src), Size::S64, Location::SIMD(dst)) => {
1194 dynasm!(self ; fcvt.d.s F(dst), F(src));
1195 }
1196 (_, Size::S64, Location::SIMD(src), Size::S32, Location::SIMD(dst)) => {
1197 dynasm!(self ; fcvt.s.d F(dst), F(src));
1198 }
1199 (true, Size::S32, Location::SIMD(src), Size::S32, Location::GPR(dst)) => {
1201 dynasm!(self ; fcvt.w.s X(dst), F(src), rtz);
1202 }
1203 (true, Size::S64, Location::SIMD(src), Size::S32, Location::GPR(dst)) => {
1204 dynasm!(self ; fcvt.w.d X(dst), F(src), rtz);
1205 }
1206 (true, Size::S32, Location::SIMD(src), Size::S64, Location::GPR(dst)) => {
1207 dynasm!(self ; fcvt.l.s X(dst), F(src), rtz);
1208 }
1209 (true, Size::S64, Location::SIMD(src), Size::S64, Location::GPR(dst)) => {
1210 dynasm!(self ; fcvt.l.d X(dst), F(src), rtz);
1211 }
1212 (false, Size::S32, Location::SIMD(src), Size::S32, Location::GPR(dst)) => {
1213 dynasm!(self ; fcvt.wu.s X(dst), F(src), rtz);
1214 }
1215 (false, Size::S64, Location::SIMD(src), Size::S32, Location::GPR(dst)) => {
1216 dynasm!(self ; fcvt.wu.d X(dst), F(src), rtz);
1217 }
1218 (false, Size::S32, Location::SIMD(src), Size::S64, Location::GPR(dst)) => {
1219 dynasm!(self ; fcvt.lu.s X(dst), F(src), rtz);
1220 }
1221 (false, Size::S64, Location::SIMD(src), Size::S64, Location::GPR(dst)) => {
1222 dynasm!(self ; fcvt.lu.d X(dst), F(src), rtz);
1223 }
1224 (true, Size::S32, Location::GPR(src), Size::S32, Location::SIMD(dst)) => {
1226 dynasm!(self ; fcvt.s.w F(dst), X(src));
1227 }
1228 (true, Size::S64, Location::GPR(src), Size::S32, Location::SIMD(dst)) => {
1229 dynasm!(self ; fcvt.s.l F(dst), X(src));
1230 }
1231 (true, Size::S32, Location::GPR(src), Size::S64, Location::SIMD(dst)) => {
1232 dynasm!(self ; fcvt.d.w F(dst), X(src));
1233 }
1234 (true, Size::S64, Location::GPR(src), Size::S64, Location::SIMD(dst)) => {
1235 dynasm!(self ; fcvt.d.l F(dst), X(src));
1236 }
1237
1238 (false, Size::S32, Location::GPR(src), Size::S32, Location::SIMD(dst)) => {
1239 dynasm!(self ; fcvt.s.wu F(dst), X(src));
1240 }
1241 (false, Size::S64, Location::GPR(src), Size::S32, Location::SIMD(dst)) => {
1242 dynasm!(self ; fcvt.s.lu F(dst), X(src));
1243 }
1244 (false, Size::S32, Location::GPR(src), Size::S64, Location::SIMD(dst)) => {
1245 dynasm!(self ; fcvt.d.wu F(dst), X(src));
1246 }
1247 (false, Size::S64, Location::GPR(src), Size::S64, Location::SIMD(dst)) => {
1248 dynasm!(self ; fcvt.d.lu F(dst), X(src));
1249 }
1250 _ => codegen_error!(
1251 "singlepass can't emit FCVT {:?} {:?} {:?} {:?}",
1252 sz_in,
1253 src,
1254 sz_out,
1255 dst
1256 ),
1257 }
1258 Ok(())
1259 }
1260
1261 fn emit_fcvt_with_rounding(
1262 &mut self,
1263 rounding: RoundingMode,
1264 size: Size,
1265 src: Location,
1266 dst: Location,
1267 tmp: GPR,
1268 ) -> Result<(), CompileError> {
1269 let (Location::SIMD(src), Location::SIMD(dst)) = (src, dst) else {
1270 codegen_error!(
1271 "singlepass can't emit FCVT with rounding for non-register operands: {:?} {:?} {:?} {:?}",
1272 src,
1273 dst,
1274 size,
1275 rounding
1276 )
1277 };
1278
1279 match (size, rounding) {
1280 (Size::S32, RoundingMode::Rne) => {
1281 dynasm!(self
1282 ; fcvt.w.s X(tmp), F(src), rne
1283 ; fcvt.s.w F(dst), X(tmp), rne
1284 ; fsgnj.s F(dst), F(dst), F(src));
1285 }
1286 (Size::S32, RoundingMode::Rtz) => {
1287 dynasm!(self
1288 ; fcvt.w.s X(tmp), F(src), rtz
1289 ; fcvt.s.w F(dst), X(tmp), rtz
1290 ; fsgnj.s F(dst), F(dst), F(src));
1291 }
1292 (Size::S32, RoundingMode::Rdn) => {
1293 dynasm!(self
1294 ; fcvt.w.s X(tmp), F(src), rdn
1295 ; fcvt.s.w F(dst), X(tmp), rdn
1296 ; fsgnj.s F(dst), F(dst), F(src));
1297 }
1298 (Size::S32, RoundingMode::Rup) => {
1299 dynasm!(self
1300 ; fcvt.w.s X(tmp), F(src), rup
1301 ; fcvt.s.w F(dst), X(tmp), rup
1302 ; fsgnj.s F(dst), F(dst), F(src));
1303 }
1304
1305 (Size::S64, RoundingMode::Rne) => {
1306 dynasm!(self
1307 ; fcvt.l.d X(tmp), F(src), rne
1308 ; fcvt.d.l F(dst), X(tmp), rne
1309 ; fsgnj.d F(dst), F(dst), F(src));
1310 }
1311 (Size::S64, RoundingMode::Rtz) => {
1312 dynasm!(self
1313 ; fcvt.l.d X(tmp), F(src), rtz
1314 ; fcvt.d.l F(dst), X(tmp), rtz
1315 ; fsgnj.d F(dst), F(dst), F(src));
1316 }
1317 (Size::S64, RoundingMode::Rdn) => {
1318 dynasm!(self
1319 ; fcvt.l.d X(tmp), F(src), rdn
1320 ; fcvt.d.l F(dst), X(tmp), rdn
1321 ; fsgnj.d F(dst), F(dst), F(src));
1322 }
1323 (Size::S64, RoundingMode::Rup) => {
1324 dynasm!(self
1325 ; fcvt.l.d X(tmp), F(src), rup
1326 ; fcvt.d.l F(dst), X(tmp), rup
1327 ; fsgnj.d F(dst), F(dst), F(src));
1328 }
1329 _ => codegen_error!(
1330 "singlepass can't emit FCVT with rounding {:?} {:?}",
1331 size,
1332 rounding
1333 ),
1334 }
1335
1336 Ok(())
1337 }
1338
1339 fn emit_swap_fscr(&mut self, reg: GPR) -> Result<(), CompileError> {
1341 dynasm!(self ; fscsr X(reg), X(reg));
1342 Ok(())
1343 }
1344
1345 fn emit_cmp(
1346 &mut self,
1347 c: Condition,
1348 loc_a: Location,
1349 loc_b: Location,
1350 ret: Location,
1351 ) -> Result<(), CompileError> {
1352 let (Location::GPR(loc_a), Location::GPR(loc_b), Location::GPR(ret)) = (loc_a, loc_b, ret)
1353 else {
1354 codegen_error!(
1355 "singlepass can't emit CMP {:?} {:?} {:?}",
1356 loc_a,
1357 loc_b,
1358 ret
1359 );
1360 };
1361
1362 match c {
1363 Condition::Lt => {
1365 dynasm!(self; slt X(ret), X(loc_a), X(loc_b));
1366 }
1367 Condition::Le => {
1368 dynasm!(self
1369 ; slt X(ret), X(loc_b), X(loc_a)
1370 ; xori X(ret), X(ret), 1);
1371 }
1372 Condition::Gt => {
1373 dynasm!(self; slt X(ret), X(loc_b), X(loc_a));
1374 }
1375 Condition::Ge => {
1376 dynasm!(self
1377 ; slt X(ret), X(loc_a), X(loc_b)
1378 ; xori X(ret), X(ret), 1);
1379 }
1380 Condition::Eq => {
1381 dynasm!(self
1382 ; xor X(ret), X(loc_a), X(loc_b)
1383 ; seqz X(ret), X(ret));
1384 }
1385 Condition::Ne => {
1386 dynasm!(self
1387 ; xor X(ret), X(loc_a), X(loc_b)
1388 ; snez X(ret), X(ret));
1389 }
1390 Condition::Ltu => {
1392 dynasm!(self; sltu X(ret), X(loc_a), X(loc_b));
1393 }
1394 Condition::Leu => {
1395 dynasm!(self
1396 ; sltu X(ret), X(loc_b), X(loc_a)
1397 ; xori X(ret), X(ret), 1);
1398 }
1399 Condition::Gtu => {
1400 dynasm!(self; sltu X(ret), X(loc_b), X(loc_a));
1401 }
1402 Condition::Geu => {
1403 dynasm!(self
1404 ; sltu X(ret), X(loc_a), X(loc_b)
1405 ; xori X(ret), X(ret), 1);
1406 }
1407 }
1408
1409 Ok(())
1410 }
1411
1412 fn emit_fcmp(
1413 &mut self,
1414 c: Condition,
1415 size: Size,
1416 loc_a: Location,
1417 loc_b: Location,
1418 ret: Location,
1419 ) -> Result<(), CompileError> {
1420 let (Location::SIMD(loc_a), Location::SIMD(loc_b), Location::GPR(ret)) =
1421 (loc_a, loc_b, ret)
1422 else {
1423 codegen_error!(
1424 "singlepass can't emit FCMP {:?} {:?} {:?}",
1425 loc_a,
1426 loc_b,
1427 ret
1428 );
1429 };
1430
1431 match (size, c) {
1432 (Size::S32, Condition::Lt) => {
1433 dynasm!(self ; flt.s X(ret), F(loc_a), F(loc_b));
1434 }
1435 (Size::S32, Condition::Le) => {
1436 dynasm!(self ; fle.s X(ret), F(loc_a), F(loc_b));
1437 }
1438 (Size::S32, Condition::Gt) => {
1439 dynasm!(self ; flt.s X(ret), F(loc_b), F(loc_a));
1440 }
1441 (Size::S32, Condition::Ge) => {
1442 dynasm!(self ; fle.s X(ret), F(loc_b), F(loc_a));
1443 }
1444 (Size::S32, Condition::Eq) => {
1445 dynasm!(self ; feq.s X(ret), F(loc_a), F(loc_b));
1446 }
1447 (Size::S32, Condition::Ne) => {
1448 dynasm!(self
1449 ; feq.s X(ret), F(loc_a), F(loc_b)
1450 ; xori X(ret), X(ret), 1);
1451 }
1452
1453 (Size::S64, Condition::Lt) => {
1454 dynasm!(self ; flt.d X(ret), F(loc_a), F(loc_b));
1455 }
1456 (Size::S64, Condition::Le) => {
1457 dynasm!(self ; fle.d X(ret), F(loc_a), F(loc_b));
1458 }
1459 (Size::S64, Condition::Gt) => {
1460 dynasm!(self ; flt.d X(ret), F(loc_b), F(loc_a));
1461 }
1462 (Size::S64, Condition::Ge) => {
1463 dynasm!(self; fle.d X(ret), F(loc_b), F(loc_a));
1464 }
1465 (Size::S64, Condition::Eq) => {
1466 dynasm!(self ; feq.d X(ret), F(loc_a), F(loc_b));
1467 }
1468 (Size::S64, Condition::Ne) => {
1469 dynasm!(self
1470 ; feq.d X(ret), F(loc_a), F(loc_b)
1471 ; xori X(ret), X(ret), 1);
1472 }
1473 _ => codegen_error!(
1474 "singlepass can't emit FCMP {:?} {:?} {:?}",
1475 loc_a,
1476 loc_b,
1477 ret
1478 ),
1479 }
1480
1481 Ok(())
1482 }
1483
1484 fn emit_jmp_on_condition(
1485 &mut self,
1486 cond: Condition,
1487 loc_a: Location,
1488 loc_b: Location,
1489 label: Label,
1490 tmp: GPR,
1491 ) -> Result<(), CompileError> {
1492 let (Location::GPR(loc_a), Location::GPR(loc_b)) = (loc_a, loc_b) else {
1493 codegen_error!("singlepass can't emit JMP_ON_COND {:?} {:?} ", loc_a, loc_b,);
1494 };
1495
1496 let jump: Label = self.get_label();
1497 let cont: Label = self.get_label();
1498
1499 match cond {
1500 Condition::Eq => {
1501 dynasm!(self; beq X(loc_a), X(loc_b), => jump);
1502 }
1503 Condition::Ne => {
1504 dynasm!(self; bne X(loc_a), X(loc_b), => jump);
1505 }
1506 Condition::Ltu => {
1507 dynasm!(self; bltu X(loc_a), X(loc_b), => jump);
1508 }
1509 Condition::Leu => {
1510 dynasm!(self; bleu X(loc_a), X(loc_b), => jump);
1511 }
1512 Condition::Gtu => {
1513 dynasm!(self; bgtu X(loc_a), X(loc_b), => jump);
1514 }
1515 Condition::Geu => {
1516 dynasm!(self; bgeu X(loc_a), X(loc_b), => jump);
1517 }
1518 _ => codegen_error!(
1519 "singlepass can't emit jump on conditional branch {:?}",
1520 cond
1521 ),
1522 }
1523
1524 self.emit_j_label(cont, Some(tmp))?;
1525 self.emit_label(jump)?;
1526 self.emit_j_label(label, Some(tmp))?;
1527
1528 self.emit_label(cont)?;
1529
1530 Ok(())
1531 }
1532
1533 fn emit_on_false_label(
1534 &mut self,
1535 cond: Location,
1536 label: Label,
1537 tmp: GPR,
1538 ) -> Result<(), CompileError> {
1539 match cond {
1540 Location::GPR(cond) => {
1541 dynasm!(self; beqz X(cond), => label);
1542 }
1543 _ if cond.is_imm() => {
1544 let imm = cond.imm_value_scalar().unwrap();
1545 if imm == 0 {
1546 return self.emit_j_label(label, Some(tmp));
1547 }
1548 }
1549 _ => codegen_error!("singlepass can't emit jump to false branch {:?}", cond),
1550 }
1551 Ok(())
1552 }
1553 fn emit_on_false_label_far(
1554 &mut self,
1555 cond: Location,
1556 label: Label,
1557 tmp: GPR,
1558 ) -> Result<(), CompileError> {
1559 let cont: Label = self.get_label();
1560 match cond {
1561 Location::GPR(cond) => {
1562 dynasm!(self; bnez X(cond), => cont);
1565 }
1566 _ if cond.is_imm() => {
1567 let imm = cond.imm_value_scalar().unwrap();
1568 if imm == 0 {
1569 return self.emit_j_label(label, Some(tmp));
1570 } else {
1571 self.emit_j_label(cont, Some(tmp))?;
1572 }
1573 }
1574 _ => codegen_error!("singlepass can't emit jump to false branch {:?}", cond),
1575 }
1576
1577 self.emit_j_label(label, Some(tmp))?;
1578 self.emit_label(cont)?;
1579 Ok(())
1580 }
1581 fn emit_on_true_label(
1582 &mut self,
1583 cond: Location,
1584 label: Label,
1585 tmp: GPR,
1586 ) -> Result<(), CompileError> {
1587 match cond {
1588 Location::GPR(cond) => {
1589 dynasm!(self; bnez X(cond), => label);
1590 }
1591 _ if cond.is_imm() => {
1592 let imm = cond.imm_value_scalar().unwrap();
1593 if imm != 0 {
1594 return self.emit_j_label(label, Some(tmp));
1595 }
1596 }
1597 _ => codegen_error!("singlepass can't emit jump to true branch {:?}", cond),
1598 }
1599 Ok(())
1600 }
1601 fn emit_on_true_label_far(
1602 &mut self,
1603 cond: Location,
1604 label: Label,
1605 tmp: GPR,
1606 ) -> Result<(), CompileError> {
1607 let cont: Label = self.get_label();
1608 let jump_label: Label = self.get_label();
1609 match cond {
1610 Location::GPR(cond) => {
1611 dynasm!(self; bnez X(cond), => jump_label);
1612 }
1613 _ if cond.is_imm() => {
1614 let imm = cond.imm_value_scalar().unwrap();
1615 if imm == 1 {
1616 return self.emit_j_label(jump_label, Some(tmp));
1617 }
1618 }
1619 _ => codegen_error!("singlepass can't emit jump to false branch {:?}", cond),
1620 }
1621
1622 self.emit_j_label(cont, Some(tmp))?;
1624
1625 self.emit_label(jump_label)?;
1626 self.emit_j_label(label, Some(tmp))?;
1627
1628 self.emit_label(cont)?;
1629
1630 Ok(())
1631 }
1632
1633 fn emit_j_label(&mut self, label: Label, reg: Option<GPR>) -> Result<(), CompileError> {
1634 if let Some(reg) = reg {
1635 dynasm!(self ; jump => label, X(reg));
1636 } else {
1637 dynasm!(self ; j => label);
1638 }
1639 Ok(())
1640 }
1641
1642 fn emit_j_register(&mut self, reg: GPR) -> Result<(), CompileError> {
1643 dynasm!(self ; jalr zero, X(reg), 0);
1644 Ok(())
1645 }
1646
1647 fn emit_call_label(&mut self, label: Label) -> Result<(), CompileError> {
1648 dynasm!(self ; call =>label);
1649 Ok(())
1650 }
1651
1652 fn emit_call_register(&mut self, reg: GPR) -> Result<(), CompileError> {
1653 dynasm!(self ; jalr ra, X(reg), 0);
1654 Ok(())
1655 }
1656
1657 fn emit_load_label(&mut self, reg: GPR, label: Label) -> Result<(), CompileError> {
1658 dynasm!(self ; la X(reg), => label);
1659 Ok(())
1660 }
1661
1662 fn emit_rwfence(&mut self) -> Result<(), CompileError> {
1663 dynasm!(self ; fence rw, rw);
1664 Ok(())
1665 }
1666
1667 fn emit_atomic_binop(
1668 &mut self,
1669 op: AtomicBinaryOp,
1670 size: Size,
1671 dest: GPR,
1672 addr: GPR,
1673 source: GPR,
1674 ) -> Result<(), CompileError> {
1675 match (size, op) {
1676 (Size::S64, AtomicBinaryOp::Add) => {
1677 dynasm!(self ; amoadd.d.aqrl X(dest), X(source), [X(addr)])
1678 }
1679 (Size::S64, AtomicBinaryOp::Or) => {
1680 dynasm!(self ; amoor.d.aqrl X(dest), X(source), [X(addr)])
1681 }
1682 (Size::S64, AtomicBinaryOp::Xor) => {
1683 dynasm!(self ; amoxor.d.aqrl X(dest), X(source), [X(addr)])
1684 }
1685 (Size::S64, AtomicBinaryOp::And) => {
1686 dynasm!(self ; amoand.d.aqrl X(dest), X(source), [X(addr)])
1687 }
1688 (Size::S64, AtomicBinaryOp::Exchange) => {
1689 dynasm!(self ; amoswap.d.aqrl X(dest), X(source), [X(addr)])
1690 }
1691
1692 (Size::S32, AtomicBinaryOp::Add) => {
1693 dynasm!(self ; amoadd.w.aqrl X(dest), X(source), [X(addr)])
1694 }
1695 (Size::S32, AtomicBinaryOp::Or) => {
1696 dynasm!(self ; amoor.w.aqrl X(dest), X(source), [X(addr)])
1697 }
1698 (Size::S32, AtomicBinaryOp::Xor) => {
1699 dynasm!(self ; amoxor.w.aqrl X(dest), X(source), [X(addr)])
1700 }
1701 (Size::S32, AtomicBinaryOp::And) => {
1702 dynasm!(self ; amoand.w.aqrl X(dest), X(source), [X(addr)])
1703 }
1704 (Size::S32, AtomicBinaryOp::Exchange) => {
1705 dynasm!(self ; amoswap.w.aqrl X(dest), X(source), [X(addr)])
1706 }
1707 _ => codegen_error!("singlepass can't emit atomic binop {:?} {:?}", size, op),
1708 }
1709
1710 Ok(())
1711 }
1712
1713 fn emit_reserved_ld(&mut self, size: Size, reg: GPR, addr: GPR) -> Result<(), CompileError> {
1714 match size {
1715 Size::S32 => {
1716 dynasm!(self ; lr.w.aqrl X(reg), [X(addr)])
1717 }
1718 Size::S64 => {
1719 dynasm!(self ; lr.d.aqrl X(reg), [X(addr)])
1720 }
1721 _ => codegen_error!("singlepass can't emit atomic reserved ld {:?}", size),
1722 }
1723
1724 Ok(())
1725 }
1726
1727 fn emit_reserved_sd(
1728 &mut self,
1729 size: Size,
1730 dest: GPR,
1731 addr: GPR,
1732 source: GPR,
1733 ) -> Result<(), CompileError> {
1734 match size {
1735 Size::S32 => {
1736 dynasm!(self ; sc.w.rl X(dest), X(source), [X(addr)])
1737 }
1738 Size::S64 => {
1739 dynasm!(self ; sc.d.rl X(dest), X(source), [X(addr)])
1740 }
1741 _ => codegen_error!("singlepass can't emit atomic reserved sd {:?}", size),
1742 }
1743
1744 Ok(())
1745 }
1746}
1747
1748pub fn gen_std_trampoline_riscv(
1749 sig: &FunctionType,
1750 _calling_convention: CallingConvention,
1751) -> Result<FunctionBody, CompileError> {
1752 let mut a = Assembler::new(0);
1753
1754 let fptr = GPR::X26;
1756 let args = GPR::X27;
1757
1758 dynasm!(a
1759 ; addi sp, sp, -32
1760 ; sd s0, [sp,24]
1761 ; sd ra, [sp,16]
1762 ; sd X(fptr), [sp, 8]
1763 ; sd X(args), [sp, 0]
1764 ; mv s0, sp ; mv X(fptr), a1
1766 ; mv X(args), a2
1767 );
1768
1769 let stack_args = sig.params().len().saturating_sub(7); let stack_return_slots = sig
1771 .results()
1772 .len()
1773 .saturating_sub(RISCV_RETURN_VALUE_REGISTERS.len());
1774 let mut stack_offset = (stack_args + stack_return_slots) as u32 * 8;
1775 if stack_offset > 0 {
1776 stack_offset = stack_offset.next_multiple_of(16);
1777 if ImmType::Bits12Subtraction.compatible_imm(stack_offset as _) {
1778 dynasm!(a ; addi sp, sp, -(stack_offset as i32));
1779 } else {
1780 a.emit_mov_imm(Location::GPR(SCRATCH_REG), stack_offset as _)?;
1781 dynasm!(a ; sub sp, sp, X(SCRATCH_REG));
1782 }
1783 }
1784
1785 let mut caller_stack_offset: i32 = stack_return_slots as i32 * 8;
1788 for (i, param) in sig.params().iter().enumerate() {
1789 let sz = match *param {
1790 Type::I32 | Type::F32 => Size::S32,
1791 Type::I64 | Type::F64 => Size::S64,
1792 Type::ExternRef => Size::S64,
1793 Type::FuncRef => Size::S64,
1794 _ => codegen_error!(
1795 "singlepass unsupported param type for trampoline {:?}",
1796 *param
1797 ),
1798 };
1799 match i {
1800 0..=6 => {
1801 a.emit_ld(
1802 sz,
1803 false,
1804 Location::GPR(GPR::from_index(i + 10 + 1).unwrap()),
1805 Location::Memory(args, (i * 16) as i32),
1806 )?;
1807 }
1808 _ => {
1809 let args_offset = (i * 16) as i32;
1810 let arg_location = if ImmType::Bits12.compatible_imm(args_offset as i64) {
1811 Location::Memory(args, args_offset)
1812 } else {
1813 a.emit_mov_imm(Location::GPR(SCRATCH_REG), args_offset as i64)?;
1814 a.emit_add(
1815 Size::S64,
1816 Location::GPR(args),
1817 Location::GPR(SCRATCH_REG),
1818 Location::GPR(SCRATCH_REG),
1819 )?;
1820 Location::Memory(SCRATCH_REG, 0)
1821 };
1822 a.emit_ld(sz, false, Location::GPR(SCRATCH_REG), arg_location)?;
1823
1824 let arg_dest_location =
1825 if ImmType::Bits12.compatible_imm(caller_stack_offset as i64) {
1826 Location::Memory(GPR::Sp, caller_stack_offset)
1827 } else {
1828 a.emit_mov_imm(Location::GPR(GPR::X29), caller_stack_offset as i64)?;
1829 a.emit_add(
1830 Size::S64,
1831 Location::GPR(GPR::X29),
1832 Location::GPR(GPR::Sp),
1833 Location::GPR(GPR::X29),
1834 )?;
1835 Location::Memory(GPR::X29, 0)
1836 };
1837 a.emit_sd(sz, Location::GPR(SCRATCH_REG), arg_dest_location)?;
1838 caller_stack_offset += 8;
1839 }
1840 }
1841 }
1842
1843 dynasm!(a
1844 ; jalr ra, X(fptr), 0);
1845
1846 let mut n_stack_return_slots: usize = 0;
1848 for i in 0..sig.results().len() {
1849 let src = if let Some(®) = RISCV_RETURN_VALUE_REGISTERS.get(i) {
1850 reg
1851 } else {
1852 a.emit_ld(
1853 Size::S64,
1854 false,
1855 Location::GPR(SCRATCH_REG),
1856 Location::Memory(GPR::Sp, (n_stack_return_slots as u32 * 8) as _),
1857 )?;
1858 n_stack_return_slots += 1;
1859 SCRATCH_REG
1860 };
1861 a.emit_sd(
1862 Size::S64,
1863 Location::GPR(src),
1864 Location::Memory(args, (i * 16) as _),
1865 )?;
1866 }
1867
1868 dynasm!(a
1870 ; ld X(args), [s0,0]
1871 ; ld X(fptr), [s0,8]
1872 ; ld ra, [s0,16]
1873 ; ld s0, [s0,24]
1874 );
1875 let restored_stack_offset = 32 + stack_offset;
1876 if ImmType::Bits12.compatible_imm(restored_stack_offset as _) {
1877 dynasm!(a; addi sp, sp, restored_stack_offset as _);
1878 } else {
1879 a.emit_mov_imm(Location::GPR(SCRATCH_REG), restored_stack_offset as _)?;
1880 dynasm!(a; add sp, sp, X(SCRATCH_REG));
1881 }
1882 dynasm!(a; ret);
1883
1884 let mut body = a.finalize().unwrap();
1885
1886 body.shrink_to_fit();
1887 Ok(FunctionBody {
1888 body,
1889 unwind_info: None,
1890 })
1891}
1892
1893pub fn gen_std_dynamic_import_trampoline_riscv(
1895 vmoffsets: &VMOffsets,
1896 sig: &FunctionType,
1897) -> Result<FunctionBody, CompileError> {
1898 let mut a = Assembler::new(0);
1899 let stack_offset: usize = 16 * std::cmp::max(sig.params().len(), sig.results().len());
1901
1902 a.emit_push(Size::S64, Location::GPR(GPR::X1))?;
1904 a.emit_push(Size::S64, Location::GPR(SCRATCH_REG))?;
1905
1906 if stack_offset != 0 {
1907 if ImmType::Bits12Subtraction.compatible_imm(stack_offset as _) {
1908 a.emit_sub(
1909 Size::S64,
1910 Location::GPR(GPR::Sp),
1911 Location::Imm64(stack_offset as _),
1912 Location::GPR(GPR::Sp),
1913 )?;
1914 } else {
1915 a.emit_mov_imm(Location::GPR(SCRATCH_REG), stack_offset as _)?;
1916 a.emit_sub(
1917 Size::S64,
1918 Location::GPR(GPR::Sp),
1919 Location::GPR(SCRATCH_REG),
1920 Location::GPR(GPR::Sp),
1921 )?;
1922 }
1923 }
1924
1925 if !sig.params().is_empty() {
1927 let mut argalloc = ArgumentRegisterAllocator::default();
1928 argalloc.next(Type::I64).unwrap(); let mut stack_param_count: usize = 0;
1931
1932 for (i, ty) in sig.params().iter().enumerate() {
1933 let source_loc = match argalloc.next(*ty)? {
1934 Some(RiscvRegister::GPR(gpr)) => Location::GPR(gpr),
1935 Some(RiscvRegister::FPR(fpr)) => Location::SIMD(fpr),
1936 None => {
1937 a.emit_ld(
1938 Size::S64,
1939 false,
1940 Location::GPR(SCRATCH_REG),
1941 Location::Memory(GPR::Sp, (stack_offset + 16 + stack_param_count) as _),
1942 )?;
1943 stack_param_count += 8;
1944 Location::GPR(SCRATCH_REG)
1945 }
1946 };
1947 a.emit_sd(
1948 Size::S64,
1949 source_loc,
1950 Location::Memory(GPR::Sp, (i * 16) as _),
1951 )?;
1952 a.emit_sd(
1954 Size::S64,
1955 Location::GPR(GPR::XZero),
1956 Location::Memory(GPR::Sp, (i * 16 + 8) as _),
1957 )?;
1958 }
1959 }
1960
1961 let offset = vmoffsets.vmdynamicfunction_import_context_address();
1963 a.emit_ld(
1964 Size::S64,
1965 false,
1966 Location::GPR(SCRATCH_REG),
1967 Location::Memory(GPR::X10, offset as i32),
1968 )?;
1969 a.emit_add(
1971 Size::S64,
1972 Location::GPR(GPR::Sp),
1973 Location::Imm64(0),
1974 Location::GPR(GPR::X11),
1975 )?;
1976
1977 a.emit_call_register(SCRATCH_REG)?;
1979
1980 if !sig.results().is_empty() {
1982 assert_eq!(sig.results().len(), 1);
1983 a.emit_ld(
1984 Size::S64,
1985 false,
1986 Location::GPR(GPR::X10),
1987 Location::Memory(GPR::Sp, 0),
1988 )?;
1989 }
1990
1991 if stack_offset != 0 {
1993 if ImmType::Bits12.compatible_imm(stack_offset as _) {
1994 a.emit_add(
1995 Size::S64,
1996 Location::GPR(GPR::Sp),
1997 Location::Imm64(stack_offset as _),
1998 Location::GPR(GPR::Sp),
1999 )?;
2000 } else {
2001 a.emit_mov_imm(Location::GPR(SCRATCH_REG), stack_offset as _)?;
2002 a.emit_add(
2003 Size::S64,
2004 Location::GPR(GPR::Sp),
2005 Location::GPR(SCRATCH_REG),
2006 Location::GPR(GPR::Sp),
2007 )?;
2008 }
2009 }
2010 a.emit_pop(Size::S64, Location::GPR(SCRATCH_REG))?;
2011 a.emit_pop(Size::S64, Location::GPR(GPR::X1))?;
2012
2013 a.emit_ret()?;
2015
2016 let mut body = a.finalize().unwrap();
2017 body.shrink_to_fit();
2018 Ok(FunctionBody {
2019 body,
2020 unwind_info: None,
2021 })
2022}
2023
2024pub fn gen_import_call_trampoline_riscv(
2026 vmoffsets: &VMOffsets,
2027 index: FunctionIndex,
2028 sig: &FunctionType,
2029 _calling_convention: CallingConvention,
2030) -> Result<CustomSection, CompileError> {
2031 let mut a = Assembler::new(0);
2032
2033 if sig
2038 .params()
2039 .iter()
2040 .any(|&x| x == Type::F32 || x == Type::F64)
2041 {
2042 const PARAM_REGS: &[GPR] = &[
2043 GPR::X11,
2045 GPR::X12,
2046 GPR::X13,
2047 GPR::X14,
2048 GPR::X15,
2049 GPR::X16,
2050 GPR::X17,
2051 ];
2052 const PARAM_REGS_COUNT: usize = PARAM_REGS.len();
2053
2054 let stack_offset: i32 = if sig.params().len() > PARAM_REGS_COUNT {
2056 (PARAM_REGS_COUNT * 8) as i32
2057 } else {
2058 (sig.params().len() as i32) * 8
2059 };
2060 if stack_offset > 0 {
2061 if ImmType::Bits12Subtraction.compatible_imm(stack_offset as _) {
2062 a.emit_sub(
2063 Size::S64,
2064 Location::GPR(GPR::Sp),
2065 Location::Imm64(stack_offset as _),
2066 Location::GPR(GPR::Sp),
2067 )?;
2068 } else {
2069 a.emit_mov_imm(Location::GPR(SCRATCH_REG), stack_offset as _)?;
2070 a.emit_sub(
2071 Size::S64,
2072 Location::GPR(GPR::Sp),
2073 Location::GPR(SCRATCH_REG),
2074 Location::GPR(GPR::Sp),
2075 )?;
2076 }
2077 }
2078
2079 let mut param_locations = vec![];
2082 #[allow(clippy::needless_range_loop)]
2084 for i in 0..sig.params().len() {
2085 let loc = match i {
2086 0..PARAM_REGS_COUNT => {
2087 let loc = Location::Memory(GPR::Sp, (i * 8) as i32);
2088 a.emit_sd(Size::S64, Location::GPR(PARAM_REGS[i]), loc)?;
2089 loc
2090 }
2091 _ => Location::Memory(GPR::Sp, stack_offset + ((i - PARAM_REGS_COUNT) * 8) as i32),
2092 };
2093 param_locations.push(loc);
2094 }
2095
2096 let mut caller_stack_offset: i32 = 0;
2098 let mut argalloc = ArgumentRegisterAllocator::default();
2099 argalloc.next(Type::I64).unwrap(); for (i, ty) in sig.params().iter().enumerate() {
2101 let prev_loc = param_locations[i];
2102 let targ = match argalloc.next(*ty)? {
2103 Some(RiscvRegister::GPR(gpr)) => Location::GPR(gpr),
2104 Some(RiscvRegister::FPR(neon)) => Location::SIMD(neon),
2105 None => {
2106 a.emit_ld(Size::S64, false, Location::GPR(SCRATCH_REG), prev_loc)?;
2108 a.emit_sd(
2109 Size::S64,
2110 Location::GPR(SCRATCH_REG),
2111 Location::Memory(GPR::Sp, stack_offset + caller_stack_offset),
2112 )?;
2113 caller_stack_offset += 8;
2114 continue;
2115 }
2116 };
2117 a.emit_ld(Size::S64, false, targ, prev_loc)?;
2118 }
2119
2120 if stack_offset > 0 {
2122 if ImmType::Bits12.compatible_imm(stack_offset as _) {
2123 a.emit_add(
2124 Size::S64,
2125 Location::GPR(GPR::Sp),
2126 Location::Imm64(stack_offset as _),
2127 Location::GPR(GPR::Sp),
2128 )?;
2129 } else {
2130 a.emit_mov_imm(Location::GPR(SCRATCH_REG), stack_offset as _)?;
2131 a.emit_add(
2132 Size::S64,
2133 Location::GPR(GPR::Sp),
2134 Location::GPR(SCRATCH_REG),
2135 Location::GPR(GPR::Sp),
2136 )?;
2137 }
2138 }
2139 }
2140
2141 let offset = vmoffsets.vmctx_vmfunction_import(index);
2145
2146 a.emit_ld(
2147 Size::S64,
2148 false,
2149 Location::GPR(SCRATCH_REG),
2150 Location::Memory(GPR::X10, offset as i32), )?;
2152 a.emit_ld(
2153 Size::S64,
2154 false,
2155 Location::GPR(GPR::X10),
2156 Location::Memory(GPR::X10, offset as i32 + 8), )?;
2158
2159 a.emit_j_register(SCRATCH_REG)?;
2160
2161 let mut contents = a.finalize().unwrap();
2162 contents.shrink_to_fit();
2163 let section_body = SectionBody::new_with_vec(contents);
2164
2165 Ok(CustomSection {
2166 protection: CustomSectionProtection::ReadExecute,
2167 alignment: None,
2168 bytes: section_body,
2169 relocations: vec![],
2170 })
2171}