1use super::opcodes::Opcode;
2use crate::AsmError;
3use crate::core::arch_traits::Arch;
4use crate::core::buffer::{CodeBuffer, CodeOffset, ConstantData, LabelUse, Reloc, RelocTarget};
5use crate::core::operand::*;
6use crate::core::operand::{Imm, Sym};
7use crate::core::patch::{PatchableBlock, PatchableSite};
8use crate::core::target::Environment;
9use crate::riscv::instdb::{ANY, OPCODE_FEATURE_CONTEXT, OPCODE_FEATURE_MASKS, SIGNATURE_TABLE};
10use crate::riscv::opcodes::Inst;
11use crate::riscv::opcodes::{ALL_OPCODES, Encoding, OPCODE_XLEN, SHORT_OPCODE};
12use crate::riscv::{Gp, RA, ZERO};
13pub struct Assembler<'a> {
14 pub(crate) buffer: &'a mut CodeBuffer,
15 last_error: Option<AsmError>,
17}
18
19fn validate_raw_operand(op: &Operand) -> bool {
20 let Some(op_type) = op.signature.try_op_type() else {
21 return false;
22 };
23
24 match op_type {
25 OperandType::None => op.signature.bits() == 0,
26 OperandType::Reg => {
27 let Some(reg_type) = op.signature.try_reg_type() else {
28 return false;
29 };
30 let Some(_) = op.signature.try_reg_group() else {
31 return false;
32 };
33 let expected = crate::riscv::Reg::signature_of(reg_type);
34 let mask = OperandSignature::OP_TYPE_MASK
35 | OperandSignature::REG_TYPE_MASK
36 | OperandSignature::REG_GROUP_MASK
37 | OperandSignature::SIZE_MASK;
38 expected.bits() != 0
39 && op.signature.subset(mask) == expected.subset(mask)
40 && op.id() <= 31
41 }
42 OperandType::Mem => {
43 op.signature.try_mem_base_type().is_some()
44 && op.signature.try_mem_index_type().is_some()
45 }
46 OperandType::Imm | OperandType::Label | OperandType::Sym => true,
47 OperandType::RegList => false,
48 }
49}
50
51impl<'a> Assembler<'a> {
52 pub fn new(buffer: &'a mut CodeBuffer) -> Self {
53 if !matches!(buffer.env().arch(), Arch::RISCV32 | Arch::RISCV64) {
54 return Self::poisoned(buffer, AsmError::InvalidArch);
55 }
56 Self::unchecked(buffer)
57 }
58
59 pub fn try_new(buffer: &'a mut CodeBuffer) -> Result<Self, AsmError> {
60 if !matches!(buffer.env().arch(), Arch::RISCV32 | Arch::RISCV64) {
61 return Err(AsmError::InvalidArch);
62 }
63 Ok(Self::unchecked(buffer))
64 }
65
66 fn unchecked(buffer: &'a mut CodeBuffer) -> Self {
67 Self {
68 buffer,
69 last_error: None,
70 }
71 }
72
73 fn poisoned(buffer: &'a mut CodeBuffer, error: AsmError) -> Self {
74 buffer.record_error(error);
75 Self::unchecked(buffer)
76 }
77
78 pub fn environment(&self) -> &Environment {
80 self.buffer.env()
81 }
82
83 pub fn is_32bit(&self) -> bool {
85 self.buffer.env().is_32bit()
86 }
87
88 pub fn is_64bit(&self) -> bool {
90 self.buffer.env().is_64bit()
91 }
92
93 #[cfg(test)]
94 fn last_error(&self) -> Option<AsmError> {
95 self.buffer.error().cloned()
96 }
97
98 pub fn get_label(&mut self) -> Label {
99 self.buffer.get_label()
100 }
101
102 pub fn bind_label(&mut self, label: Label) {
103 if let Err(error) = self.try_bind_label(label) {
104 self.buffer.record_error(error);
105 }
106 }
107
108 pub fn try_bind_label(&mut self, label: Label) -> Result<(), AsmError> {
109 self.buffer.try_bind_label(label)
110 }
111
112 pub fn add_constant(&mut self, c: impl Into<ConstantData>) -> Label {
113 let c = self.buffer.add_constant(c);
114 self.buffer.get_label_for_constant(c)
115 }
116
117 pub fn label_offset(&self, label: Label) -> CodeOffset {
118 self.buffer.label_offset(label)
119 }
120
121 pub fn data(&self) -> &[u8] {
122 self.buffer.data()
123 }
124
125 pub fn error(&self) -> Option<&AsmError> {
126 self.buffer.error()
127 }
128
129 pub fn reserve_patch_block(
131 &mut self,
132 size: CodeOffset,
133 align: CodeOffset,
134 ) -> Result<PatchableBlock, AsmError> {
135 self.buffer.reserve_patch_block(size, align)
136 }
137
138 pub fn patchable_j(&mut self, label: Label) -> PatchableSite {
139 if self.buffer.error().is_some() {
140 return unsafe { PatchableSite::new(u32::MAX, LabelUse::RVJal20, 0) };
143 }
144 let checkpoint = self.buffer.checkpoint();
145 let offset = self.buffer.cur_offset();
146 self.j(label);
147 let _ = self
148 .buffer
149 .record_label_patch_site(offset, label, LabelUse::RVJal20);
150 if self.buffer.error().is_some() {
151 self.buffer.rollback(checkpoint);
152 return unsafe { PatchableSite::new(u32::MAX, LabelUse::RVJal20, 0) };
155 }
156 unsafe { PatchableSite::new(offset, LabelUse::RVJal20, 0) }
158 }
159
160 pub fn patchable_call(&mut self, label: Label) -> PatchableSite {
161 if self.buffer.error().is_some() {
162 return unsafe { PatchableSite::new(u32::MAX, LabelUse::RVJal20, 0) };
165 }
166 let checkpoint = self.buffer.checkpoint();
167 let offset = self.buffer.cur_offset();
168 self.jal(RA, label);
169 let _ = self
170 .buffer
171 .record_label_patch_site(offset, label, LabelUse::RVJal20);
172 if self.buffer.error().is_some() {
173 self.buffer.rollback(checkpoint);
174 return unsafe { PatchableSite::new(u32::MAX, LabelUse::RVJal20, 0) };
177 }
178 unsafe { PatchableSite::new(offset, LabelUse::RVJal20, 0) }
180 }
181
182 pub fn patchable_li(&mut self, rd: Gp, imm: impl Into<i64>) -> PatchableBlock {
189 let arch = self.buffer.env().arch();
190 let value = imm.into();
191 if self.buffer.error().is_some() {
192 return unsafe { PatchableBlock::new(u32::MAX, 4, arch) };
195 }
196 let checkpoint = self.buffer.checkpoint();
197
198 if self.is_32bit() {
199 self.auipc(rd, crate::core::operand::imm(0));
200 self.lw(rd, rd, crate::core::operand::imm(12));
201 self.jal(ZERO, crate::core::operand::imm(8));
202 let lit = self.buffer.cur_offset();
203 self.buffer.write_u32(value as u32);
204 let _ = self.buffer.record_patch_block(lit, 4, 4);
205 if self.buffer.error().is_some() {
206 self.buffer.rollback(checkpoint);
207 return unsafe { PatchableBlock::new(u32::MAX, 4, arch) };
210 }
211 unsafe { PatchableBlock::new(lit, 4, arch) }
213 } else {
214 self.auipc(rd, crate::core::operand::imm(0));
215 self.ld(rd, rd, crate::core::operand::imm(12));
216 self.jal(ZERO, crate::core::operand::imm(12));
217 let lit = self.buffer.cur_offset();
218 self.buffer.write_u64(value as u64);
219 let _ = self.buffer.record_patch_block(lit, 8, 4);
220 if self.buffer.error().is_some() {
221 self.buffer.rollback(checkpoint);
222 return unsafe { PatchableBlock::new(u32::MAX, 8, arch) };
225 }
226 unsafe { PatchableBlock::new(lit, 8, arch) }
228 }
229 }
230
231 pub fn la(&mut self, rd: Gp, target: impl OperandCast) {
232 if self.buffer.error().is_some() {
233 return;
234 }
235 let checkpoint = self.buffer.checkpoint();
236 let target = target.as_operand();
237
238 if target.is_label() {
239 let off = self.buffer.cur_offset();
240 self.buffer
241 .use_label_at_offset(off, target.as_::<Label>(), LabelUse::RVPCRelHi20);
242 self.auipc(rd, imm(0));
243 let off = self.buffer.cur_offset();
244 self.buffer
245 .use_label_at_offset(off, target.as_::<Label>(), LabelUse::RVPCRelLo12I);
246 self.addi(rd, rd, imm(0));
247 } else if target.is_sym() {
248 if self.buffer.env().pic() {
249 let sym = target.as_::<Sym>();
261
262 let auipc_label = self.get_label();
264 self.bind_label(auipc_label);
265 self.buffer
266 .add_reloc(Reloc::RiscvGotHi20, RelocTarget::Sym(sym), 0);
267
268 self.auipc(rd, imm(0));
269 self.buffer
271 .add_reloc(Reloc::RiscvPCRelLo12I, RelocTarget::Label(auipc_label), 0);
272 if self.is_32bit() {
273 self.lw(rd, rd, imm(0));
274 } else {
275 self.ld(rd, rd, imm(0));
276 }
277 } else {
278 let label_data = self.get_label();
288 let label_end = self.get_label();
289
290 if self.is_32bit() {
291 self.emit_n(
292 Opcode::LW as i64,
293 &[rd.as_operand(), rd.as_operand(), label_data.as_operand()],
294 );
295 } else {
296 self.emit_n(
297 Opcode::LD as i64,
298 &[rd.as_operand(), rd.as_operand(), label_data.as_operand()],
299 );
300 }
301 self.j(label_end);
302 self.bind_label(label_data);
303 if self.is_32bit() {
304 self.buffer
305 .add_reloc(Reloc::Abs4, RelocTarget::Sym(target.as_::<Sym>()), 0);
306 self.buffer.put4(0);
307 } else {
308 self.buffer
309 .add_reloc(Reloc::Abs8, RelocTarget::Sym(target.as_::<Sym>()), 0);
310 self.buffer.put8(0);
311 }
312 self.bind_label(label_end);
313 }
314 } else {
315 self.buffer.record_error(AsmError::InvalidOperand);
316 }
317 if self.buffer.error().is_some() {
318 self.buffer.rollback(checkpoint);
319 }
320 }
321
322 pub fn call(&mut self, target: impl OperandCast) {
323 if self.buffer.error().is_some() {
324 return;
325 }
326 let checkpoint = self.buffer.checkpoint();
327 let target = target.as_operand();
328
329 if target.is_label() {
330 let off = self.buffer.cur_offset();
331 self.buffer
332 .use_label_at_offset(off, target.as_::<Label>(), LabelUse::RVPCRelHi20);
333 self.auipc(RA, imm(0));
334 let off = self.buffer.cur_offset();
335 self.buffer
336 .use_label_at_offset(off, target.as_::<Label>(), LabelUse::RVPCRelLo12I);
337 self.jalr(RA, RA, imm(0));
338 } else if target.is_sym() {
339 let sym = target.as_::<Sym>();
340
341 let reloc = Reloc::RiscvCallPlt;
342
343 self.buffer.add_reloc(reloc, RelocTarget::Sym(sym), 0);
344 self.auipc(RA, imm(0));
345 self.jalr(RA, RA, imm(0));
346 } else if target.is_imm() {
347 self.jalr(RA, RA, target.as_::<Imm>());
348 } else if target.is_reg() {
349 self.jalr(RA, target.as_::<Gp>(), imm(0));
350 } else {
351 self.buffer.record_error(AsmError::InvalidOperand);
352 }
353 if self.buffer.error().is_some() {
354 self.buffer.rollback(checkpoint);
355 }
356 }
357}
358macro_rules! enc_ops1 {
359 ($op0:ident) => {
360 OperandType::$op0 as u32
361 };
362}
363
364macro_rules! enc_ops2 {
365 ($op0:ident, $op1:ident) => {
366 (OperandType::$op0 as u32) | ((OperandType::$op1 as u32) << 3)
367 };
368}
369
370macro_rules! enc_ops3 {
371 ($op0:ident, $op1:ident, $op2:ident) => {
372 (OperandType::$op0 as u32)
373 | ((OperandType::$op1 as u32) << 3)
374 | ((OperandType::$op2 as u32) << 6)
375 };
376}
377
378macro_rules! enc_ops4 {
379 ($op0:ident, $op1:ident, $op2:ident, $op3:ident) => {
380 (OperandType::$op0 as u32)
381 | ((OperandType::$op1 as u32) << 3)
382 | ((OperandType::$op2 as u32) << 6)
383 | ((OperandType::$op3 as u32) << 9)
384 };
385}
386
387impl<'a> Assembler<'a> {
388 pub fn emit_n(&mut self, opcode: i64, ops: &[&Operand]) {
389 if let Err(error) = self.try_emit_n(opcode, ops) {
390 self.buffer.record_error(error);
391 }
392 }
393
394 pub fn try_emit_n(&mut self, opcode: i64, ops: &[&Operand]) -> Result<(), AsmError> {
395 if let Some(error) = self.buffer.error().cloned() {
396 return Err(error);
397 }
398 if ops.len() > 5 || ops.iter().any(|op| !validate_raw_operand(op)) {
399 return Err(AsmError::InvalidOperand);
400 }
401 let checkpoint = self.buffer.checkpoint();
402 self.last_error = None;
403 self.emit_n_inner(opcode, ops);
404 if let Some(error) = self.last_error.take() {
405 self.buffer.rollback(checkpoint);
406 return Err(error);
407 }
408 if let Some(error) = self.buffer.error().cloned() {
409 self.buffer.rollback(checkpoint);
410 return Err(error);
411 }
412 Ok(())
413 }
414
415 #[allow(unused_assignments)]
416 fn emit_n_inner(&mut self, opcode: i64, ops: &[&crate::core::operand::Operand]) {
417 let Ok(opcode) = usize::try_from(opcode) else {
418 self.last_error = Some(AsmError::InvalidInstruction);
419 return;
420 };
421 let Some(opcode) = ALL_OPCODES.get(opcode).copied() else {
422 self.last_error = Some(AsmError::InvalidInstruction);
423 return;
424 };
425 if !self
426 .environment()
427 .supports_any_riscv_feature(&OPCODE_FEATURE_MASKS[opcode as usize])
428 {
429 self.last_error = Some(AsmError::MissingCpuFeature {
430 feature: OPCODE_FEATURE_CONTEXT[opcode as usize],
431 });
432 return;
433 }
434 let signature = &SIGNATURE_TABLE[opcode.inst_info().signature_index as usize];
435 let expected_operands = signature
436 .iter()
437 .position(|operand_class| *operand_class == ANY)
438 .unwrap_or(signature.len());
439 if ops.len() != expected_operands {
440 self.last_error = Some(AsmError::InvalidOperand);
441 return;
442 }
443
444 let xlen_bit = if self.is_32bit() { 1 } else { 2 };
447 if OPCODE_XLEN[opcode as usize] & xlen_bit == 0 {
448 self.last_error = Some(AsmError::InvalidInstruction);
449 return;
450 }
451
452 let encoding = opcode.encoding();
453 let is_prime_register = |id| (8..=15).contains(&id);
454
455 let mut inst = Inst::new(opcode).encode();
456 let mut label_use = None;
457
458 let isign3 = match ops {
459 [] => 0,
460 [op0] => op0.op_type() as u32,
461 [op0, op1] => op0.op_type() as u32 + ((op1.op_type() as u32) << 3),
462 [op0, op1, op2, ..] => {
463 op0.op_type() as u32 + ((op1.op_type() as u32) << 3) + ((op2.op_type() as u32) << 6)
464 }
465 };
466
467 let isign4 = match ops {
468 [] => 0,
469 [op0] => op0.op_type() as u32,
470 [op0, op1] => op0.op_type() as u32 + ((op1.op_type() as u32) << 3),
471 [op0, op1, op2] => {
472 op0.op_type() as u32 + ((op1.op_type() as u32) << 3) + ((op2.op_type() as u32) << 6)
473 }
474 [op0, op1, op2, op3, ..] => {
475 op0.op_type() as u32
476 + ((op1.op_type() as u32) << 3)
477 + ((op2.op_type() as u32) << 6)
478 + ((op3.op_type() as u32) << 9)
479 }
480 };
481 let mut short = SHORT_OPCODE[opcode as usize];
482 match encoding {
483 Encoding::Bimm12HiRs1Bimm12lo => {
484 let rs1 = ops[0].id();
485 let imm = if ops[1].is_imm() {
486 ops[1].as_::<Imm>().value() as i32
487 } else if ops[1].is_label() {
488 label_use = Some((ops[1], LabelUse::RVB12));
489 0
490 } else {
491 self.last_error = Some(AsmError::InvalidOperand);
492 return;
493 };
494
495 inst = inst.set_rs1(rs1).set_bimm12lohi(imm);
496 }
497
498 Encoding::Bimm12HiRs1Rs2Bimm12lo => {
499 let rs1 = ops[0].id();
500 let rs2 = ops[1].id();
501
502 let imm = if ops[2].is_imm() {
503 ops[2].as_::<Imm>().value() as i32
504 } else if ops[2].is_label() {
505 label_use = Some((ops[2], LabelUse::RVB12));
506 0
507 } else {
508 self.last_error = Some(AsmError::InvalidOperand);
509 return;
510 };
511
512 inst = inst.set_rs1(rs1).set_rs2(rs2).set_bimm12lohi(imm);
513 }
514
515 Encoding::Bimm12HiRs2Rs1Bimm12lo => {
516 let rs1 = ops[0].id();
517 let rs2 = ops[1].id();
518 let imm = if ops[2].is_imm() {
519 ops[2].as_::<Imm>().value() as i32
520 } else if ops[2].is_label() {
521 label_use = Some((ops[2], LabelUse::RVB12));
522 0
523 } else {
524 self.last_error = Some(AsmError::InvalidOperand);
525 return;
526 };
527
528 inst = inst.set_rs2(rs2).set_rs1(rs1).set_bimm12lohi(imm);
529 }
530
531 Encoding::Bimm12HiRs2Bimm12lo => {
532 let rs2 = ops[0].id();
533 let imm = if ops[1].is_imm() {
534 ops[1].as_::<Imm>().value() as i32
535 } else if ops[1].is_label() {
536 label_use = Some((ops[1], LabelUse::RVB12));
537 0
538 } else {
539 self.last_error = Some(AsmError::InvalidOperand);
540 return;
541 };
542
543 inst = inst.set_rs2(rs2).set_bimm12lohi(imm);
544 }
545
546 Encoding::CImm12 => {
547 short = true;
548 let imm = if ops[0].is_imm() {
549 ops[0].as_::<Imm>().value() as i32
550 } else if ops[0].is_label() {
551 label_use = Some((ops[0], LabelUse::RVCJump));
552 0
553 } else {
554 self.last_error = Some(AsmError::InvalidOperand);
555 return;
556 };
557
558 inst = inst.set_c_imm12(imm)
559 }
560
561 Encoding::CIndex => {
562 short = true;
563 let imm = if ops[0].is_imm() {
564 ops[0].as_::<Imm>().value() as i32
565 } else {
566 self.last_error = Some(AsmError::InvalidOperand);
567 return;
568 };
569 inst = inst.set_c_index(imm as _);
570 }
571
572 Encoding::CMopT => {
573 short = true;
574 let imm = if ops[0].is_imm() {
575 ops[0].as_::<Imm>().value() as i32
576 } else {
577 self.last_error = Some(AsmError::InvalidOperand);
578 return;
579 };
580
581 inst = inst.set_c_mop_t(imm as _);
582 }
583
584 Encoding::CNzimm10hiCNzimm10lo => {
585 short = true;
586 let imm = if ops[0].is_imm() {
587 ops[0].as_::<Imm>().value() as i32
588 } else {
589 self.last_error = Some(AsmError::InvalidOperand);
590 return;
591 };
592
593 if imm == 0 || !(-1024..=1024).contains(&imm) {
594 self.last_error = Some(AsmError::InvalidOperand);
595 return;
596 }
597
598 inst = inst.set_c_nzimm10lohi(imm);
599 }
600
601 Encoding::CNzimm6hiCNzimm6lo => {
602 short = true;
603 let imm = if ops[0].is_imm() {
604 ops[0].as_::<Imm>().value() as i32
605 } else {
606 self.last_error = Some(AsmError::InvalidOperand);
607 return;
608 };
609
610 if imm == 0 || imm > 64 {
611 self.last_error = Some(AsmError::InvalidOperand);
612 return;
613 }
614
615 inst = inst.set_c_nzimm6lohi(imm)
616 }
617
618 Encoding::CRlistCSpimm => {
619 self.last_error = Some(AsmError::UnsupportedInstruction {
620 reason: "RISC-V compressed register-list instructions are not implemented",
621 });
622 return;
623 }
624
625 Encoding::CRs1N0 => {
626 short = true;
627 let rs1 = ops[0].id();
628 inst = inst.set_rs1_n0(rs1);
629 }
630
631 Encoding::CRs2CUimm8spS => {
632 short = true;
633 let rs2 = ops[0].id();
634 let imm = if ops[1].is_imm() {
635 ops[1].as_::<Imm>().value() as i32
636 } else {
637 self.last_error = Some(AsmError::InvalidOperand);
638 return;
639 };
640 if !(0..=256).contains(&imm) {
641 self.last_error = Some(AsmError::InvalidOperand);
642 return;
643 }
644 inst = inst.set_c_uimm8lohi(imm as _).set_c_rs2(rs2);
645 }
646
647 Encoding::CRs2CUimm9spS => {
648 short = true;
649 let rs2 = ops[0].id();
650 let imm = if ops[1].is_imm() {
651 ops[1].as_::<Imm>().value() as i32
652 } else {
653 self.last_error = Some(AsmError::InvalidOperand);
654 return;
655 };
656 if !(0..=511).contains(&imm) {
657 self.last_error = Some(AsmError::InvalidOperand);
658 return;
659 }
660 inst = inst.set_c_rs2(rs2).set_c_uimm9sp_s(imm as _);
661 }
662
663 Encoding::CSreg1CSreg2 => {
664 self.last_error = Some(AsmError::UnsupportedInstruction {
665 reason: "RISC-V compressed saved-register moves are not implemented",
666 });
667 return;
668 }
669
670 Encoding::CsrZimm5 => {
671 let csr_imm = if ops[0].is_imm() {
672 ops[0].as_::<Imm>().value() as i32
673 } else {
674 self.last_error = Some(AsmError::InvalidOperand);
675 return;
676 };
677
678 let zimm = if ops[1].is_imm() {
679 ops[1].as_::<Imm>().value()
680 } else {
681 self.last_error = Some(AsmError::InvalidOperand);
682 return;
683 };
684
685 inst = inst.set_csr(csr_imm as _).set_zimm5(zimm as _);
686 }
687
688 Encoding::Empty => {}
689 Encoding::FmPredSuccRs1Rd => {
690 let fm = if ops[0].is_imm() {
691 ops[0].as_::<Imm>().value() as u8
692 } else {
693 self.last_error = Some(AsmError::InvalidOperand);
694 return;
695 };
696
697 let pred = if ops[1].is_imm() {
698 ops[1].as_::<Imm>().value() as u8
699 } else {
700 self.last_error = Some(AsmError::InvalidOperand);
701 return;
702 };
703
704 let succ = if ops[2].is_imm() {
705 ops[2].as_::<Imm>().value() as u8
706 } else {
707 self.last_error = Some(AsmError::InvalidOperand);
708 return;
709 };
710
711 let rs1 = ops[3].id();
712 let rd = ops[4].id();
713
714 inst = inst
715 .set_fm(fm as _)
716 .set_pred(pred as _)
717 .set_succ(succ as _)
718 .set_rs1(rs1)
719 .set_rd(rd);
720 }
721
722 Encoding::Imm12HiRs1Rs2Imm12lo => {
723 if isign3 == enc_ops3!(Reg, Reg, Imm) {
724 let rs1 = ops[0].id();
725 let rs2 = ops[1].id();
726 let imm = ops[2].as_::<Imm>().value() as i32;
727
728 inst = inst.set_rs1(rs1).set_rs2(rs2).set_imm12lohi(imm);
729 } else {
730 self.last_error = Some(AsmError::InvalidOperand);
731 return;
732 };
733 }
734
735 Encoding::Imm12Rs1Rd => {
736 if opcode == Opcode::FENCEI {
737 } else if isign3 == enc_ops3!(Reg, Reg, Imm) {
739 let rs1 = ops[0].id();
740 let rd = ops[1].id();
741 let imm = ops[2].as_::<Imm>().value() as i32;
742
743 inst = inst.set_rs1(rs1).set_rd(rd).set_imm12(imm);
744 } else {
745 self.last_error = Some(AsmError::InvalidOperand);
746 return;
747 }
748 }
749
750 Encoding::Imm20 => {
751 if isign3 == enc_ops1!(Imm) {
752 let imm = ops[0].as_::<Imm>().value() as i32;
753 inst = inst.set_imm20(imm);
754 } else {
755 self.last_error = Some(AsmError::InvalidOperand);
756 return;
757 }
758 }
759
760 Encoding::Jimm20 => {
761 if isign3 == enc_ops1!(Imm) {
762 let imm = ops[0].as_::<Imm>().value() as i32;
763 inst = inst.set_jimm20(imm);
764 } else if isign3 == enc_ops1!(Label) {
765 label_use = Some((ops[0], LabelUse::RVJal20));
766 inst = inst.set_jimm20(0);
767 } else {
768 self.last_error = Some(AsmError::InvalidOperand);
769 return;
770 }
771 }
772
773 Encoding::MopRT30MopRT2726MopRT2120RdRs1 => {
774 self.last_error = Some(AsmError::UnsupportedInstruction {
775 reason: "RISC-V MOP.RN instructions are not implemented",
776 });
777 return;
778 }
779 Encoding::MopRrT30MopRrT2726RdRs1Rs2 => {
780 self.last_error = Some(AsmError::UnsupportedInstruction {
781 reason: "RISC-V MOP.RR.N instructions are not implemented",
782 });
783 return;
784 }
785
786 Encoding::NfVmRs1Vd => {
787 if isign4 == enc_ops4!(Reg, Reg, Imm, Imm) {
788 let vd = ops[0].id();
789 let rs1 = ops[1].id();
790 let vm = ops[2].as_::<Imm>().value();
791 let nf = ops[3].as_::<Imm>().value();
792 if !(0..=1).contains(&vm) || !(0..=7).contains(&nf) {
793 self.last_error = Some(AsmError::InvalidOperand);
794 return;
795 }
796
797 inst = inst.set_vd(vd).set_rs1(rs1).set_vm(vm as _).set_nf(nf as _);
798 } else {
799 self.last_error = Some(AsmError::InvalidOperand);
800 return;
801 }
802 }
803
804 Encoding::NfVmRs1Vs3 => {
805 if isign4 == enc_ops4!(Reg, Reg, Imm, Imm) {
806 let vs3 = ops[0].id();
807 let rs1 = ops[1].id();
808 let vm = ops[2].as_::<Imm>().value();
809 let nf = ops[3].as_::<Imm>().value();
810 if !(0..=1).contains(&vm) || !(0..=7).contains(&nf) {
811 self.last_error = Some(AsmError::InvalidOperand);
812 return;
813 }
814
815 inst = inst
816 .set_vs3(vs3)
817 .set_rs1(rs1)
818 .set_vm(vm as _)
819 .set_nf(nf as _);
820 } else {
821 self.last_error = Some(AsmError::InvalidOperand);
822 return;
823 }
824 }
825
826 Encoding::NfVmRs2Rs1Vd => {
827 if isign4 == enc_ops4!(Reg, Reg, Reg, Imm)
828 && ops.get(4).is_some_and(|op| op.is_imm())
829 {
830 let vd = ops[0].id();
831 let rs1 = ops[1].id();
832 let vm = ops[3].as_::<Imm>().value();
833 let nf = ops[4].as_::<Imm>().value();
834 if !(0..=1).contains(&vm) || !(0..=7).contains(&nf) {
835 self.last_error = Some(AsmError::InvalidOperand);
836 return;
837 }
838 let rs2 = ops[2].id();
839 inst = inst
840 .set_rs1(rs1)
841 .set_rs2(rs2)
842 .set_vd(vd)
843 .set_vm(vm as _)
844 .set_nf(nf as _);
845 } else {
846 self.last_error = Some(AsmError::InvalidOperand);
847 return;
848 }
849 }
850
851 Encoding::NfVmRs2Rs1Vs3 => {
852 if isign4 == enc_ops4!(Reg, Reg, Reg, Imm)
853 && ops.get(4).is_some_and(|op| op.is_imm())
854 {
855 let vs3 = ops[0].id();
856 let rs1 = ops[1].id();
857 let vm = ops[3].as_::<Imm>().value();
858 let nf = ops[4].as_::<Imm>().value();
859 if !(0..=1).contains(&vm) || !(0..=7).contains(&nf) {
860 self.last_error = Some(AsmError::InvalidOperand);
861 return;
862 }
863 let rs2 = ops[2].id();
864 inst = inst
865 .set_rs1(rs1)
866 .set_rs2(rs2)
867 .set_vs3(vs3)
868 .set_vm(vm as _)
869 .set_nf(nf as _);
870 } else {
871 self.last_error = Some(AsmError::InvalidOperand);
872 return;
873 }
874 }
875
876 Encoding::NfVmVs2Rs1Vd => {
877 if isign4 == enc_ops4!(Reg, Reg, Reg, Imm)
878 && ops.get(4).is_some_and(|op| op.is_imm())
879 {
880 let vd = ops[0].id();
881 let rs1 = ops[1].id();
882 let vs2 = ops[2].id();
883 let vm = ops[3].as_::<Imm>().value();
884 let nf = ops[4].as_::<Imm>().value();
885 if !(0..=1).contains(&vm) || !(0..=7).contains(&nf) {
886 self.last_error = Some(AsmError::InvalidOperand);
887 return;
888 }
889
890 inst = inst
891 .set_rs1(rs1)
892 .set_vd(vd)
893 .set_vs2(vs2)
894 .set_vm(vm as _)
895 .set_nf(nf as _);
896 } else {
897 self.last_error = Some(AsmError::InvalidOperand);
898 return;
899 }
900 }
901
902 Encoding::NfVmVs2Rs1Vs3 => {
903 if isign4 == enc_ops4!(Reg, Reg, Reg, Imm)
904 && ops.get(4).is_some_and(|op| op.is_imm())
905 {
906 let vs3 = ops[0].id();
907 let rs1 = ops[1].id();
908 let vs2 = ops[2].id();
909 let vm = ops[3].as_::<Imm>().value();
910 let nf = ops[4].as_::<Imm>().value();
911 if !(0..=1).contains(&vm) || !(0..=7).contains(&nf) {
912 self.last_error = Some(AsmError::InvalidOperand);
913 return;
914 }
915
916 inst = inst
917 .set_vs3(vs3)
918 .set_rs1(rs1)
919 .set_vs2(vs2)
920 .set_vm(vm as _)
921 .set_nf(nf as _);
922 } else {
923 self.last_error = Some(AsmError::InvalidOperand);
924 return;
925 }
926 }
927
928 Encoding::Rd => {
929 if isign3 == enc_ops1!(Reg) {
930 let rd = ops[0].id();
931 inst = inst.set_rd(rd);
932 } else {
933 self.last_error = Some(AsmError::InvalidOperand);
934 return;
935 }
936 }
937
938 Encoding::RdCUimm8sphiCUimm8splo => {
939 if isign3 == enc_ops2!(Reg, Imm) {
940 let rd = ops[0].id();
941 let imm = ops[1].as_::<Imm>().value() as u32;
942
943 inst = inst.set_rd(rd).set_c_uimm8splohi(imm);
944 } else {
945 self.last_error = Some(AsmError::InvalidOperand);
946 return;
947 }
948 }
949
950 Encoding::RdCUimm9sphiCUimm9splo => {
951 if isign3 == enc_ops2!(Reg, Imm) {
952 let rd = ops[0].id();
953 let imm = ops[1].as_::<Imm>().value() as u32;
954
955 inst = inst.set_rd(rd).set_c_uimm9splohi(imm);
956 } else {
957 self.last_error = Some(AsmError::InvalidOperand);
958 return;
959 }
960 }
961
962 Encoding::RdCsr => {
963 if isign3 == enc_ops2!(Reg, Imm) {
964 let rd = ops[0].id();
965 let csr = ops[1].as_::<Imm>().value() as u32;
966 inst = inst.set_rd(rd).set_csr(csr);
967 } else {
968 self.last_error = Some(AsmError::InvalidOperand);
969 return;
970 }
971 }
972
973 Encoding::RdCsrZimm5 => {
974 if isign3 == enc_ops3!(Reg, Imm, Imm) {
975 let rd = ops[0].id();
976 let csr = ops[1].as_::<Imm>().value() as u32;
977 let zimm = ops[2].as_::<Imm>().value() as i32;
978 inst = inst.set_rd(rd).set_csr(csr).set_zimm5(zimm);
979 } else {
980 self.last_error = Some(AsmError::InvalidOperand);
981 return;
982 }
983 }
984 Encoding::RdImm20 => {
985 if isign3 == enc_ops2!(Reg, Imm) {
986 let rd = ops[0].id();
987 let imm = ops[1].as_::<Imm>().value() as i32;
988 inst = inst.set_rd(rd).set_imm20(imm);
989 } else if isign3 == enc_ops2!(Reg, Label) {
990 let rd = ops[0].id();
991 label_use = Some((ops[1], LabelUse::RVPCRelHi20));
992 inst = inst.set_rd(rd).set_imm20(0);
993 } else {
994 self.last_error = Some(AsmError::InvalidOperand);
995 return;
996 };
997 }
998
999 Encoding::RdJimm20 => {
1000 if isign3 == enc_ops2!(Reg, Imm) {
1001 let rd = ops[0].id();
1002 let imm = ops[1].as_::<Imm>().value() as i32;
1003 inst = inst.set_rd(rd).set_jimm20(imm);
1004 } else if isign3 == enc_ops2!(Reg, Label) {
1005 let rd = ops[0].id();
1006 label_use = Some((ops[1], LabelUse::RVJal20));
1007 inst = inst.set_rd(rd).set_jimm20(0);
1008 } else {
1009 self.last_error = Some(AsmError::InvalidOperand);
1010 return;
1011 };
1012 }
1013
1014 Encoding::RdN0 => {
1015 if isign3 == enc_ops1!(Reg) {
1016 let rd = ops[0].id();
1017 inst = inst.set_rd_n0(rd);
1018 } else {
1019 self.last_error = Some(AsmError::InvalidOperand);
1020 return;
1021 }
1022 }
1023
1024 Encoding::RdN0CImm6loCImm6hi => {
1025 short = true;
1026 if isign3 == enc_ops2!(Reg, Imm) {
1027 let rd = ops[0].id();
1028 let imm = ops[1].as_::<Imm>().value() as i32;
1029 inst = inst.set_rd_n0(rd).set_c_imm6lohi(imm);
1030 } else {
1031 self.last_error = Some(AsmError::InvalidOperand);
1032 return;
1033 }
1034 }
1035
1036 Encoding::RdN0CRs2N0 => {
1037 short = true;
1038 if isign3 == enc_ops2!(Reg, Reg) {
1039 let rd = ops[0].id();
1040 let rs1 = ops[1].id();
1041 inst = inst.set_rd_n0(rd).set_c_rs2(rs1);
1042 } else {
1043 self.last_error = Some(AsmError::InvalidOperand);
1044 return;
1045 }
1046 }
1047
1048 Encoding::RdN0CUimm8sphiCUimm8splo => {
1049 short = true;
1050 if isign3 == enc_ops2!(Reg, Imm) {
1051 let rd = ops[0].id();
1052 let imm = ops[1].as_::<Imm>().value() as i32;
1053 inst = inst.set_rd_n0(rd).set_c_uimm8splohi(imm as _);
1054 } else {
1055 self.last_error = Some(AsmError::InvalidOperand);
1056 return;
1057 }
1058 }
1059
1060 Encoding::RdN0CUimm9sphiCUimm9splo => {
1061 short = true;
1062 if isign3 == enc_ops2!(Reg, Imm) {
1063 let rd = ops[0].id();
1064 let imm = ops[1].as_::<Imm>().value() as i32;
1065 inst = inst.set_rd_n0(rd).set_c_uimm9splohi(imm as _);
1066 } else {
1067 self.last_error = Some(AsmError::InvalidOperand);
1068 return;
1069 }
1070 }
1071
1072 Encoding::RdN2CNzimm18hiCNzimm18lo => {
1073 short = true;
1074 if isign3 == enc_ops2!(Reg, Imm) {
1075 let rd = ops[0].id();
1076 let imm = ops[1].as_::<Imm>().value() as i32;
1077 if imm == 0 {
1078 self.last_error = Some(AsmError::InvalidOperand);
1079 return;
1080 } else {
1081 inst = inst.set_rd_n2(rd).set_c_nzimm18lohi(imm);
1082 }
1083 } else {
1084 self.last_error = Some(AsmError::InvalidOperand);
1085 return;
1086 }
1087 }
1088
1089 Encoding::RdPCNzuimm10 => {
1090 if isign3 == enc_ops2!(Reg, Imm) {
1091 let rd = ops[0].id();
1092 if !is_prime_register(rd) {
1093 self.last_error = Some(AsmError::InvalidOperand);
1094 return;
1095 }
1096 let imm = ops[1].as_::<Imm>().value() as i32;
1097 inst = inst.set_rd_p(rd).set_c_nzimm10lohi(imm);
1098 } else {
1099 self.last_error = Some(AsmError::InvalidOperand);
1100 return;
1101 }
1102 }
1103
1104 Encoding::RdPRs1PCUimm1 => {
1105 if isign3 == enc_ops3!(Reg, Reg, Imm) {
1106 let rd = ops[0].id();
1107 let rs1 = ops[1].id();
1108 if !is_prime_register(rd) || !is_prime_register(rs1) {
1109 self.last_error = Some(AsmError::InvalidOperand);
1110 return;
1111 }
1112 let imm = ops[2].as_::<Imm>().value() as i32;
1113
1114 inst = inst.set_rd_p(rd).set_rs1_p(rs1).set_c_uimm1(imm as _);
1115 } else {
1116 self.last_error = Some(AsmError::InvalidOperand);
1117 return;
1118 }
1119 }
1120
1121 Encoding::RdPRs1PCUimm2 => {
1122 if isign3 == enc_ops3!(Reg, Reg, Imm) {
1123 let rd = ops[0].id();
1124 let rs1 = ops[1].id();
1125 if !is_prime_register(rd) || !is_prime_register(rs1) {
1126 self.last_error = Some(AsmError::InvalidOperand);
1127 return;
1128 }
1129 let imm = ops[2].as_::<Imm>().value() as i32;
1130
1131 inst = inst.set_rd_p(rd).set_rs1_p(rs1).set_c_uimm2(imm as _);
1132 } else {
1133 self.last_error = Some(AsmError::InvalidOperand);
1134 return;
1135 }
1136 }
1137
1138 Encoding::RdPRs1PCUimm7loCUimm7hi => {
1139 short = true;
1140 if isign3 == enc_ops3!(Reg, Reg, Imm) {
1141 let rd = ops[0].id();
1142 let rs1 = ops[1].id();
1143 if !is_prime_register(rd) || !is_prime_register(rs1) {
1144 self.last_error = Some(AsmError::InvalidOperand);
1145 return;
1146 }
1147 let imm = ops[2].as_::<Imm>().value() as i32;
1148 inst = inst.set_rd_p(rd).set_rs1_p(rs1).set_c_uimm7lohi(imm as _);
1149 } else {
1150 self.last_error = Some(AsmError::InvalidOperand);
1151 return;
1152 }
1153 }
1154
1155 Encoding::RdPRs1PCUimm8loCUimm8hi => {
1156 short = true;
1157 if isign3 == enc_ops3!(Reg, Reg, Imm) {
1158 let rd = ops[0].id();
1159 let rs1 = ops[1].id();
1160 if !is_prime_register(rd) || !is_prime_register(rs1) {
1161 self.last_error = Some(AsmError::InvalidOperand);
1162 return;
1163 }
1164 let imm = ops[2].as_::<Imm>().value() as i32;
1165 inst = inst.set_rd_p(rd).set_rs1_p(rs1).set_c_uimm8lohi(imm as _);
1166 } else {
1167 self.last_error = Some(AsmError::InvalidOperand);
1168 return;
1169 }
1170 }
1171
1172 Encoding::RdRs1 => {
1173 if isign3 == enc_ops2!(Reg, Reg) {
1174 let rd = ops[0].id();
1175 let rs1 = ops[1].id();
1176 inst = inst.set_rd(rd).set_rs1(rs1);
1177 } else {
1178 self.last_error = Some(AsmError::InvalidOperand);
1179 return;
1180 }
1181 }
1182
1183 Encoding::RdRs1AqRl => {
1184 if isign4 == enc_ops4!(Reg, Reg, Imm, Imm) {
1185 let rd = ops[0].id();
1186 let rs1 = ops[1].id();
1187 let aq = ops[2].as_::<Imm>().value();
1188 let rl = ops[3].as_::<Imm>().value();
1189 if !(0..=1).contains(&aq) || !(0..=1).contains(&rl) {
1190 self.last_error = Some(AsmError::InvalidOperand);
1191 return;
1192 }
1193 inst = inst.set_rd(rd).set_rs1(rs1).set_aq(aq as _).set_rl(rl as _);
1194 } else {
1195 self.last_error = Some(AsmError::InvalidOperand);
1196 return;
1197 }
1198 }
1199
1200 Encoding::RdRs1Csr => {
1201 if isign3 == enc_ops3!(Reg, Reg, Imm) {
1202 let rd = ops[0].id();
1203 let rs1 = ops[1].id();
1204 let imm = ops[2].as_::<Imm>().value() as i32;
1205 inst = inst.set_rd(rd).set_rs1(rs1).set_csr(imm as _);
1206 } else {
1207 self.last_error = Some(AsmError::InvalidOperand);
1208 return;
1209 }
1210 }
1211
1212 Encoding::RdRs1Imm12 => {
1213 if isign3 == enc_ops3!(Reg, Reg, Imm) {
1214 let rd = ops[0].id();
1215 let rs1 = ops[1].id();
1216 let imm = ops[2].as_::<Imm>().value() as i32;
1217 inst = inst.set_rd(rd).set_rs1(rs1).set_imm12(imm);
1218 } else if isign3 == enc_ops3!(Reg, Reg, Label) {
1219 let rd = ops[0].id();
1220 let rs1 = ops[1].id();
1221 if rd != rs1 {
1222 self.last_error = Some(AsmError::InvalidOperand);
1223 return;
1224 }
1225 let off = self.buffer.cur_offset();
1226 self.buffer
1227 .use_label_at_offset(off, ops[2].as_(), LabelUse::RVPCRelHi20);
1228 self.auipc(ops[0].as_::<Gp>(), imm(0));
1229 label_use = Some((ops[2], LabelUse::RVPCRelLo12I));
1230 inst = inst.set_rd(rd).set_rs1(rs1).set_imm12(0);
1231 } else {
1232 self.last_error = Some(AsmError::InvalidOperand);
1233 return;
1234 }
1235 }
1236
1237 Encoding::RdRs1N0 => {
1238 self.last_error = Some(AsmError::UnsupportedInstruction {
1239 reason: "RISC-V RdRs1N0 instructions are not implemented",
1240 });
1241 return;
1242 }
1243
1244 Encoding::RdRs1Rm => {
1245 if isign3 == enc_ops3!(Reg, Reg, Imm) {
1246 let rd = ops[0].id();
1247 let rs1 = ops[1].id();
1248 let rm = ops[2].as_::<Imm>().value() as i32;
1249 if !matches!(rm, 0..=4 | 7) {
1250 self.last_error = Some(AsmError::InvalidOperand);
1251 return;
1252 }
1253 inst = inst.set_rd(rd).set_rs1(rs1).set_rm(rm as _);
1254 } else {
1255 self.last_error = Some(AsmError::InvalidOperand);
1256 return;
1257 }
1258 }
1259 Encoding::RdRs1Rnum => {
1260 if isign3 == enc_ops3!(Reg, Reg, Imm) {
1261 let rd = ops[0].id();
1262 let rs1 = ops[1].id();
1263 let rm = ops[2].as_::<Imm>().value() as i32;
1264 inst = inst.set_rd(rd).set_rs1(rs1).set_rnum(rm as _);
1265 } else {
1266 self.last_error = Some(AsmError::InvalidOperand);
1267 return;
1268 }
1269 }
1270
1271 Encoding::RdRs1Rs2 => {
1272 if isign3 == enc_ops3!(Reg, Reg, Reg) {
1273 let rd = ops[0].id();
1274 let rs1 = ops[1].id();
1275 let rs2 = ops[2].id();
1276 inst = inst.set_rd(rd).set_rs1(rs1).set_rs2(rs2);
1277 } else {
1278 self.last_error = Some(AsmError::InvalidOperand);
1279 return;
1280 }
1281 }
1282
1283 Encoding::RdRs1Rs2AqRl => {
1284 if isign4 == enc_ops4!(Reg, Reg, Reg, Imm)
1285 && ops.get(4).is_some_and(|op| op.is_imm())
1286 {
1287 let rd = ops[0].id();
1288 let rs1 = ops[1].id();
1289 let rs2 = ops[2].id();
1290 let aq = ops[3].as_::<Imm>().value();
1291 let rl = ops[4].as_::<Imm>().value();
1292 if !(0..=1).contains(&aq) || !(0..=1).contains(&rl) {
1293 self.last_error = Some(AsmError::InvalidOperand);
1294 return;
1295 }
1296 inst = inst
1297 .set_rd(rd)
1298 .set_rs1(rs1)
1299 .set_rs2(rs2)
1300 .set_aq(aq as _)
1301 .set_rl(rl as _);
1302 } else {
1303 self.last_error = Some(AsmError::InvalidOperand);
1304 return;
1305 }
1306 }
1307
1308 Encoding::RdRs1Rs2Bs => {
1309 if isign4 == enc_ops4!(Reg, Reg, Reg, Imm) {
1310 let rd = ops[0].id();
1311 let rs1 = ops[1].id();
1312 let rs2 = ops[2].id();
1313 let imm = ops[3].as_::<Imm>().value() as i32;
1314 inst = inst.set_rd(rd).set_rs1(rs1).set_rs2(rs2).set_bs(imm as _);
1315 } else {
1316 self.last_error = Some(AsmError::InvalidOperand);
1317 return;
1318 }
1319 }
1320
1321 Encoding::RdRs1Rs2EqRs1 => {
1322 if isign3 == enc_ops3!(Reg, Reg, Reg) {
1323 let rd = ops[0].id();
1324 let rs1 = ops[1].id();
1325 let rs2 = ops[2].id();
1326 inst = inst.set_rd(rd).set_rs1(rs1).set_rs2_eq_rs1(rs2);
1327 } else {
1328 self.last_error = Some(AsmError::InvalidOperand);
1329 return;
1330 }
1331 }
1332
1333 Encoding::RdRs1Rs2Rm => {
1334 if isign4 == enc_ops4!(Reg, Reg, Reg, Imm) {
1335 let rd = ops[0].id();
1336 let rs1 = ops[1].id();
1337 let rs2 = ops[2].id();
1338 let rm = ops[3].as_::<Imm>().value() as i32;
1339 if !matches!(rm, 0..=4 | 7) {
1340 self.last_error = Some(AsmError::InvalidOperand);
1341 return;
1342 }
1343 inst = inst.set_rd(rd).set_rs1(rs1).set_rs2(rs2).set_rm(rm as _);
1344 } else {
1345 self.last_error = Some(AsmError::InvalidOperand);
1346 return;
1347 }
1348 }
1349
1350 Encoding::RdRs1Rs2Rs3Rm => {
1351 if isign4 == enc_ops4!(Reg, Reg, Reg, Reg) && ops[4].op_type() == OperandType::Imm {
1352 let rd = ops[0].id();
1353 let rs1 = ops[1].id();
1354 let rs2 = ops[2].id();
1355 let rs3 = ops[3].id();
1356 let rm = ops[4].as_::<Imm>().value() as i32;
1357 if !matches!(rm, 0..=4 | 7) {
1358 self.last_error = Some(AsmError::InvalidOperand);
1359 return;
1360 }
1361
1362 inst = inst
1363 .set_rd(rd)
1364 .set_rs1(rs1)
1365 .set_rs2(rs2)
1366 .set_rs3(rs3)
1367 .set_rm(rm as _);
1368 } else {
1369 self.last_error = Some(AsmError::InvalidOperand);
1370 return;
1371 }
1372 }
1373
1374 Encoding::RdRs1Shamtw => {
1375 if isign3 == enc_ops3!(Reg, Reg, Imm) {
1376 let rd = ops[0].id();
1377 let rs1 = ops[1].id();
1378 let shamt = ops[2].as_::<Imm>().value() as i32;
1379 inst = inst.set_rd(rd).set_rs1(rs1).set_shamtw(shamt as _);
1380 } else {
1381 self.last_error = Some(AsmError::InvalidOperand);
1382 return;
1383 }
1384 }
1385 Encoding::RdRs2 => {
1386 if isign3 == enc_ops2!(Reg, Reg) {
1387 let rd = ops[0].id();
1388 let rs2 = ops[1].id();
1389 inst = inst.set_rd(rd).set_rs2(rs2);
1390 } else {
1391 self.last_error = Some(AsmError::InvalidOperand);
1392 return;
1393 }
1394 }
1395
1396 Encoding::RdZimm5 => {
1397 if isign3 == enc_ops2!(Reg, Imm) {
1398 let rd = ops[0].id();
1399 let imm = ops[1].as_::<Imm>().value() as i32;
1400 inst = inst.set_rd(rd).set_zimm5(imm);
1401 } else {
1402 self.last_error = Some(AsmError::InvalidOperand);
1403 return;
1404 }
1405 }
1406
1407 Encoding::Rs1 => {
1408 if isign3 == enc_ops1!(Reg) {
1409 let rs1 = ops[0].id();
1410 inst = inst.set_rs1(rs1);
1411 } else {
1412 self.last_error = Some(AsmError::InvalidOperand);
1413 return;
1414 }
1415 }
1416
1417 Encoding::Rs1Csr => {
1418 if isign3 == enc_ops2!(Reg, Imm) {
1419 let rs1 = ops[0].id();
1420 let csr = ops[1].as_::<Imm>().value() as i32;
1421 inst = inst.set_rs1(rs1).set_csr(csr as _);
1422 } else {
1423 self.last_error = Some(AsmError::InvalidOperand);
1424 return;
1425 }
1426 }
1427
1428 Encoding::Rs1Imm12hi => {
1429 if isign3 == enc_ops2!(Reg, Imm) {
1430 let rs1 = ops[0].id();
1431 let imm = ops[1].as_::<Imm>().value() as i32;
1432 inst = inst.set_rs1(rs1).set_imm12hi_raw(imm as _);
1433 } else {
1434 self.last_error = Some(AsmError::InvalidOperand);
1435 return;
1436 }
1437 }
1438
1439 Encoding::Rs1N0 => {
1440 short = true;
1441 if isign3 == enc_ops1!(Reg) {
1442 let rs1 = ops[0].id();
1443 inst = inst.set_rs1_n0(rs1);
1444 } else {
1445 self.last_error = Some(AsmError::InvalidOperand);
1446 return;
1447 }
1448 }
1449
1450 Encoding::Rs1PCBimm9loCBimm9hi => {
1451 short = true;
1452 if isign3 == enc_ops2!(Reg, Imm) {
1453 let rs1 = ops[0].id();
1454 let imm = ops[1].as_::<Imm>().value();
1455
1456 inst = inst.set_rs1(rs1).set_c_bimm9lohi(imm as _);
1457 } else if isign3 == enc_ops2!(Reg, Label) {
1458 let rs1 = ops[0].id();
1459 label_use = Some((ops[1], LabelUse::RVCB9));
1460 inst = inst.set_rs1(rs1).set_c_bimm9lohi(0);
1461 } else {
1462 self.last_error = Some(AsmError::InvalidOperand);
1463 return;
1464 }
1465 }
1466
1467 Encoding::Rs1PRs2PCUimm7loCUimm7hi => {
1468 short = true;
1469 if isign3 == enc_ops3!(Reg, Reg, Imm) {
1470 let rs1 = ops[0].id();
1471 let rs2 = ops[1].id();
1472 if !is_prime_register(rs1) || !is_prime_register(rs2) {
1473 self.last_error = Some(AsmError::InvalidOperand);
1474 return;
1475 }
1476 let imm = ops[2].as_::<Imm>().value() as i32;
1477 inst = inst.set_rs1_p(rs1).set_rs2_p(rs2).set_c_uimm7lohi(imm as _);
1478 } else {
1479 self.last_error = Some(AsmError::InvalidOperand);
1480 return;
1481 }
1482 }
1483
1484 Encoding::Rs1PRs2PCUimm8loCUimm8hi => {
1485 short = true;
1486 if isign3 == enc_ops3!(Reg, Reg, Imm) {
1487 let rs1 = ops[0].id();
1488 let rs2 = ops[1].id();
1489 if !is_prime_register(rs1) || !is_prime_register(rs2) {
1490 self.last_error = Some(AsmError::InvalidOperand);
1491 return;
1492 }
1493 let imm = ops[2].as_::<Imm>().value() as i32;
1494 inst = inst.set_rs1_p(rs1).set_rs2_p(rs2).set_c_uimm8lohi(imm as _);
1495 } else {
1496 self.last_error = Some(AsmError::InvalidOperand);
1497 return;
1498 }
1499 }
1500
1501 Encoding::Rs1PRs2PCUimm8hiCUimm8lo => {
1502 short = true;
1503 if isign3 == enc_ops3!(Reg, Reg, Imm) {
1504 let rs1 = ops[0].id();
1505 let rs2 = ops[1].id();
1506 if !is_prime_register(rs1) || !is_prime_register(rs2) {
1507 self.last_error = Some(AsmError::InvalidOperand);
1508 return;
1509 }
1510 let imm = ops[2].as_::<Imm>().value() as i32;
1511 inst = inst.set_rs1_p(rs1).set_rs2_p(rs2).set_c_uimm8lohi(imm as _);
1512 } else {
1513 self.last_error = Some(AsmError::InvalidOperand);
1514 return;
1515 }
1516 }
1517
1518 Encoding::Rs1Rd => {
1519 if opcode == Opcode::FENCETSO {
1520 } else if isign3 == enc_ops2!(Reg, Reg) {
1522 let rd = ops[0].id();
1523 let rs1 = ops[1].id();
1524
1525 inst = inst.set_rd(rd).set_rs1(rs1);
1526 } else {
1527 self.last_error = Some(AsmError::InvalidOperand);
1528 return;
1529 }
1530 }
1531
1532 Encoding::Rs1Rs2 => {
1533 if isign3 == enc_ops2!(Reg, Reg) {
1534 let rs1 = ops[0].id();
1535 let rs2 = ops[1].id();
1536 inst = inst.set_rs1(rs1).set_rs2(rs2);
1537 } else {
1538 self.last_error = Some(AsmError::InvalidOperand);
1539 return;
1540 }
1541 }
1542
1543 Encoding::Rs1Vd => {
1544 if isign3 == enc_ops2!(Reg, Reg) {
1545 let rs1 = ops[1].id();
1546 let vd = ops[0].id();
1547 inst = inst.set_vd(vd).set_rs1(rs1);
1548 } else {
1549 self.last_error = Some(AsmError::InvalidOperand);
1550 return;
1551 }
1552 }
1553 Encoding::Rs1Vs3 => {
1554 if isign3 == enc_ops2!(Reg, Reg) {
1555 let rs1 = ops[1].id();
1556 let vs3 = ops[0].id();
1557 inst = inst.set_rs1(rs1).set_vs3(vs3);
1558 } else {
1559 self.last_error = Some(AsmError::InvalidOperand);
1560 return;
1561 }
1562 }
1563
1564 Encoding::Rs2PRs1PCUimm1 => {
1565 short = true;
1566 if isign3 == enc_ops3!(Reg, Reg, Imm) {
1567 let rs1 = ops[0].id();
1568 let rs2 = ops[1].id();
1569 if !is_prime_register(rs1) || !is_prime_register(rs2) {
1570 self.last_error = Some(AsmError::InvalidOperand);
1571 return;
1572 }
1573 let imm = ops[2].as_::<Imm>().value() as i32;
1574 inst = inst.set_rs1_p(rs1).set_rs2_p(rs2).set_c_uimm1(imm as _);
1575 } else {
1576 self.last_error = Some(AsmError::InvalidOperand);
1577 return;
1578 }
1579 }
1580
1581 Encoding::Rs2PRs1PCUimm2 => {
1582 short = true;
1583 if isign3 == enc_ops3!(Reg, Reg, Imm) {
1584 let rs1 = ops[0].id();
1585 let rs2 = ops[1].id();
1586 if !is_prime_register(rs1) || !is_prime_register(rs2) {
1587 self.last_error = Some(AsmError::InvalidOperand);
1588 return;
1589 }
1590 let imm = ops[2].as_::<Imm>().value() as i32;
1591 inst = inst.set_rs1_p(rs1).set_rs2_p(rs2).set_c_uimm2(imm as _);
1592 } else {
1593 self.last_error = Some(AsmError::InvalidOperand);
1594 return;
1595 }
1596 }
1597 Encoding::Rs2Rs1Rd => {
1598 if isign3 == enc_ops3!(Reg, Reg, Reg) {
1599 let rd = ops[0].id();
1600 let rs1 = ops[1].id();
1601 let rs2 = ops[2].id();
1602
1603 inst = inst.set_rd(rd).set_rs1(rs1).set_rs2(rs2);
1604 } else {
1605 self.last_error = Some(AsmError::InvalidOperand);
1606 return;
1607 }
1608 }
1609
1610 Encoding::Simm5Vd => {
1611 if isign3 == enc_ops2!(Reg, Imm) {
1612 let vd = ops[0].id();
1613 let imm = ops[1].as_::<Imm>().value() as i8;
1614 inst = inst.set_vd(vd).set_simm5(imm as _);
1615 } else {
1616 self.last_error = Some(AsmError::InvalidOperand);
1617 return;
1618 }
1619 }
1620
1621 Encoding::VmVs2Rd => {
1622 if isign3 == enc_ops3!(Reg, Reg, Imm) {
1623 let rd = ops[0].id();
1624 let vs2 = ops[1].id();
1625 let vm = ops[2].as_::<Imm>().value();
1626 if !(0..=1).contains(&vm) {
1627 self.last_error = Some(AsmError::InvalidOperand);
1628 return;
1629 }
1630 inst = inst.set_rd(rd).set_vs2(vs2).set_vm(vm as _);
1631 } else {
1632 self.last_error = Some(AsmError::InvalidOperand);
1633 return;
1634 }
1635 }
1636
1637 Encoding::VmVd => {
1638 if isign3 == enc_ops2!(Reg, Imm) {
1639 let vd = ops[0].id();
1640 let vm = ops[1].as_::<Imm>().value();
1641 if !(0..=1).contains(&vm) {
1642 self.last_error = Some(AsmError::InvalidOperand);
1643 return;
1644 }
1645 inst = inst.set_vd(vd).set_vm(vm as _);
1646 } else {
1647 self.last_error = Some(AsmError::InvalidOperand);
1648 return;
1649 }
1650 }
1651
1652 Encoding::VmVs2Rs1Vd => {
1653 if isign4 == enc_ops4!(Reg, Reg, Reg, Imm) {
1654 let rs1 = ops[2].id();
1655 let vs2 = ops[1].id();
1656 let vm = ops[3].as_::<Imm>().value();
1657 if !(0..=1).contains(&vm) {
1658 self.last_error = Some(AsmError::InvalidOperand);
1659 return;
1660 }
1661 let vd = ops[0].id();
1662 inst = inst.set_vd(vd).set_vm(vm as _).set_rs1(rs1).set_vs2(vs2);
1663 } else {
1664 self.last_error = Some(AsmError::InvalidOperand);
1665 return;
1666 }
1667 }
1668
1669 Encoding::VmVs2Simm5Vd => {
1670 if isign4 == enc_ops4!(Reg, Reg, Imm, Imm) {
1671 let simm5 = ops[2].as_::<Imm>().value() as i32;
1672 let vs2 = ops[1].id();
1673 let vm = ops[3].as_::<Imm>().value();
1674 if !(0..=1).contains(&vm) {
1675 self.last_error = Some(AsmError::InvalidOperand);
1676 return;
1677 }
1678 let vd = ops[0].id();
1679 inst = inst
1680 .set_vd(vd)
1681 .set_vm(vm as _)
1682 .set_simm5(simm5)
1683 .set_vs2(vs2);
1684 } else {
1685 self.last_error = Some(AsmError::InvalidOperand);
1686 return;
1687 }
1688 }
1689
1690 Encoding::VmVs2Vd => {
1691 if isign3 == enc_ops3!(Reg, Reg, Imm) {
1692 let vd = ops[0].id();
1693 let vs2 = ops[1].id();
1694 let vm = ops[2].as_::<Imm>().value();
1695 if !(0..=1).contains(&vm) {
1696 self.last_error = Some(AsmError::InvalidOperand);
1697 return;
1698 }
1699
1700 inst = inst.set_vd(vd).set_vs2(vs2).set_vm(vm as _);
1701 } else {
1702 self.last_error = Some(AsmError::InvalidOperand);
1703 return;
1704 }
1705 }
1706
1707 Encoding::VmVs2Vs1Vd => {
1708 if isign4 == enc_ops4!(Reg, Reg, Reg, Imm) {
1709 let vd = ops[0].id();
1710 let vs1 = ops[1].id();
1711 let vs2 = ops[2].id();
1712 let vm = ops[3].as_::<Imm>().value();
1713 if !(0..=1).contains(&vm) {
1714 self.last_error = Some(AsmError::InvalidOperand);
1715 return;
1716 }
1717 inst = inst.set_vd(vd).set_vs1(vs1).set_vs2(vs2).set_vm(vm as _);
1718 } else {
1719 self.last_error = Some(AsmError::InvalidOperand);
1720 return;
1721 }
1722 }
1723
1724 Encoding::VmVs2Zimm5Vd => {
1725 if isign4 == enc_ops4!(Reg, Reg, Imm, Imm) {
1726 let vd = ops[0].id();
1727 let vs2 = ops[1].id();
1728 let vm = ops[3].as_::<Imm>().value();
1729 if !(0..=1).contains(&vm) {
1730 self.last_error = Some(AsmError::InvalidOperand);
1731 return;
1732 }
1733 let zimm5 = ops[2].as_::<Imm>().value() as i8;
1734 inst = inst
1735 .set_vd(vd)
1736 .set_vs2(vs2)
1737 .set_vm(vm as _)
1738 .set_zimm5(zimm5 as _);
1739 } else {
1740 self.last_error = Some(AsmError::InvalidOperand);
1741 return;
1742 }
1743 }
1744
1745 Encoding::Vs1Vd => {
1746 if isign3 == enc_ops2!(Reg, Reg) {
1747 let vd = ops[0].id();
1748 let vs1 = ops[1].id();
1749 inst = inst.set_vd(vd).set_vs1(vs1);
1750 } else {
1751 self.last_error = Some(AsmError::InvalidOperand);
1752 return;
1753 }
1754 }
1755
1756 Encoding::Vs2Rd => {
1757 if isign3 == enc_ops2!(Reg, Reg) {
1758 let rd = ops[0].id();
1759 let vs2 = ops[1].id();
1760 inst = inst.set_rd(rd).set_vs2(vs2);
1761 } else {
1762 self.last_error = Some(AsmError::InvalidOperand);
1763 return;
1764 }
1765 }
1766
1767 Encoding::Vs2Rs1Vd => {
1768 if isign4 == enc_ops3!(Reg, Reg, Reg) {
1769 let rs1 = ops[1].id();
1770 let vs2 = ops[2].id();
1771 let vd = ops[0].id();
1772 inst = inst.set_vd(vd).set_vs2(vs2).set_rs1(rs1);
1773 } else {
1774 self.last_error = Some(AsmError::InvalidOperand);
1775 return;
1776 }
1777 }
1778
1779 Encoding::Vs2Simm5Vd => {
1780 if isign3 == enc_ops3!(Reg, Reg, Imm) {
1781 let vd = ops[0].id();
1782 let vs2 = ops[1].id();
1783 let imm = ops[2].as_::<Imm>().value();
1784
1785 inst = inst.set_vd(vd).set_vs2(vs2).set_simm5(imm as _);
1786 } else {
1787 self.last_error = Some(AsmError::InvalidOperand);
1788 return;
1789 }
1790 }
1791
1792 Encoding::Vs2Vd => {
1793 if isign3 == enc_ops2!(Reg, Reg) {
1794 let vd = ops[0].id();
1795 let vs2 = ops[1].id();
1796 inst = inst.set_vd(vd).set_vs2(vs2);
1797 } else {
1798 self.last_error = Some(AsmError::InvalidOperand);
1799 return;
1800 }
1801 }
1802
1803 Encoding::Vs2Vs1Vd => {
1804 if isign4 == enc_ops3!(Reg, Reg, Reg) {
1805 let vd = ops[0].id();
1806 let vs1 = ops[1].id();
1807 let vs2 = ops[2].id();
1808
1809 inst = inst.set_vd(vd).set_vs1(vs1).set_vs2(vs2);
1810 } else {
1811 self.last_error = Some(AsmError::InvalidOperand);
1812 return;
1813 }
1814 }
1815
1816 Encoding::Vs2Zimm5Vd => {
1817 if isign3 == enc_ops3!(Reg, Reg, Imm) {
1818 let vd = ops[0].id();
1819 let vs2 = ops[1].id();
1820 let zimm5 = ops[2].as_::<Imm>().value() as i8;
1821 inst = inst.set_vd(vd).set_vs2(vs2).set_zimm5(zimm5 as _);
1822 } else {
1823 self.last_error = Some(AsmError::InvalidOperand);
1824 return;
1825 }
1826 }
1827
1828 Encoding::Zimm10Zimm5Rd => {
1829 if isign3 == enc_ops3!(Reg, Imm, Imm) {
1830 let rd = ops[0].id();
1831 let uimm = ops[1].as_::<Imm>().value() as i8;
1832 let vtypei = ops[2].as_::<Imm>().value() as i8;
1833 inst = inst.set_rd(rd).set_zimm10(vtypei as _).set_zimm5(uimm as _);
1834 } else {
1835 self.last_error = Some(AsmError::InvalidOperand);
1836 return;
1837 }
1838 }
1839
1840 Encoding::Zimm11Rs1Rd => {
1841 if isign3 == enc_ops3!(Reg, Reg, Imm) {
1842 let rd = ops[0].id();
1843 let rs1 = ops[1].id();
1844 let imm = ops[2].as_::<Imm>().value() as i32;
1845 inst = inst.set_rd(rd).set_rs1(rs1).set_zimm11(imm);
1846 } else {
1847 self.last_error = Some(AsmError::InvalidOperand);
1848 return;
1849 }
1850 }
1851
1852 Encoding::Zimm6HiVmVs2Zimm6loVd => {
1853 if isign4 == enc_ops4!(Reg, Reg, Imm, Imm) {
1854 let vd = ops[0].id();
1855 let vs2 = ops[1].id();
1856 let imm = ops[2].as_::<Imm>().value();
1857 let vm = ops[3].as_::<Imm>().value();
1858 if !(0..=1).contains(&vm) {
1859 self.last_error = Some(AsmError::InvalidOperand);
1860 return;
1861 }
1862
1863 inst = inst
1864 .set_vd(vd)
1865 .set_vs2(vs2)
1866 .set_zimm6lohi(imm as _)
1867 .set_vm(vm as _);
1868 } else {
1869 self.last_error = Some(AsmError::InvalidOperand);
1870 return;
1871 }
1872 }
1873 Encoding::RdRs1N0CNzimm6loCNzimm6hi => {
1874 short = true;
1875 if isign3 == enc_ops2!(Reg, Imm) {
1876 let rd = ops[0].id();
1877 let imm = ops[1].as_::<Imm>().value() as i32;
1878 if imm == 0 {
1879 self.last_error = Some(AsmError::InvalidOperand);
1880 return;
1881 } else {
1882 inst = inst.set_rd_rs1_n0(rd).set_c_nzimm6lohi(imm);
1883 }
1884 } else {
1885 self.last_error = Some(AsmError::InvalidOperand);
1886 return;
1887 }
1888 }
1889
1890 Encoding::RdRs1N0CImm6loCImm6hi => {
1891 short = true;
1892 if isign3 == enc_ops2!(Reg, Imm) {
1893 let rd = ops[0].id();
1894 let imm = ops[1].as_::<Imm>().value() as i32;
1895 inst = inst.set_rd_rs1_n0(rd).set_c_imm6lohi(imm);
1896 } else {
1897 self.last_error = Some(AsmError::InvalidOperand);
1898 return;
1899 }
1900 }
1901
1902 Encoding::RdRs1N0CNzuimm6hiCNzuimm6lo => {
1903 short = true;
1904 if isign3 == enc_ops2!(Reg, Imm) {
1905 let rd = ops[0].id();
1906 let imm = ops[1].as_::<Imm>().value() as i32;
1907 if imm == 0 {
1908 self.last_error = Some(AsmError::InvalidOperand);
1909 return;
1910 } else {
1911 inst = inst.set_rd_rs1_n0(rd).set_c_nzuimm6lohi(imm as u32);
1912 }
1913 } else {
1914 self.last_error = Some(AsmError::InvalidOperand);
1915 return;
1916 }
1917 }
1918
1919 Encoding::RdRs1N0CNzuimm6lo => {
1920 short = true;
1921 if isign3 == enc_ops2!(Reg, Imm) {
1922 let rd = ops[0].id();
1923 let imm = ops[1].as_::<Imm>().value() as i32;
1924 if imm == 0 {
1925 self.last_error = Some(AsmError::InvalidOperand);
1926 return;
1927 } else {
1928 inst = inst.set_rd_rs1_n0(rd).set_c_nzuimm6lo_raw(imm as u32);
1929 }
1930 } else {
1931 self.last_error = Some(AsmError::InvalidOperand);
1932 return;
1933 }
1934 }
1935
1936 Encoding::RdRs1N0CRs2N0 => {
1937 short = true;
1938 if isign3 == enc_ops2!(Reg, Reg) {
1939 let rd = ops[0].id();
1940 let rs1 = ops[1].id();
1941 inst = inst.set_rd_rs1_n0(rd).set_c_rs2_n0(rs1);
1942 } else {
1943 self.last_error = Some(AsmError::InvalidOperand);
1944 return;
1945 }
1946 }
1947
1948 Encoding::RdRs1P => {
1949 short = true;
1950 if isign3 == enc_ops1!(Reg) {
1951 let rd = ops[0].id();
1952 if !is_prime_register(rd) {
1953 self.last_error = Some(AsmError::InvalidOperand);
1954 return;
1955 }
1956
1957 inst = inst.set_rd_rs1_p(rd);
1958 } else {
1959 self.last_error = Some(AsmError::InvalidOperand);
1960 return;
1961 }
1962 }
1963
1964 Encoding::RdRs1PCImm6hiCImm6lo => {
1965 short = true;
1966 if isign3 == enc_ops2!(Reg, Imm) {
1967 let rd = ops[0].id();
1968 if !is_prime_register(rd) {
1969 self.last_error = Some(AsmError::InvalidOperand);
1970 return;
1971 }
1972 let imm = ops[1].as_::<Imm>().value() as i32;
1973 inst = inst.set_rd_rs1_p(rd).set_c_imm6lohi(imm);
1974 } else {
1975 self.last_error = Some(AsmError::InvalidOperand);
1976 return;
1977 }
1978 }
1979
1980 Encoding::RdRs1PCNzuimm5 => {
1981 short = true;
1982 if isign3 == enc_ops2!(Reg, Imm) {
1983 let rd = ops[0].id();
1984 let imm = ops[1].as_::<Imm>().value() as i32;
1985 if imm == 0 {
1986 self.last_error = Some(AsmError::InvalidOperand);
1987 return;
1988 } else {
1989 inst = inst.set_rd(rd).set_rs1(0).set_c_nzuimm5(imm as u32);
1990 }
1991 } else {
1992 self.last_error = Some(AsmError::InvalidOperand);
1993 return;
1994 }
1995 }
1996
1997 Encoding::RdRs1PCNzuimm6loCNzuimm6hi => {
1998 short = true;
1999 if isign3 == enc_ops2!(Reg, Imm) {
2000 let rd = ops[0].id();
2001 if !is_prime_register(rd) {
2002 self.last_error = Some(AsmError::InvalidOperand);
2003 return;
2004 }
2005 let imm = ops[1].as_::<Imm>().value() as i32;
2006 if imm == 0 {
2007 self.last_error = Some(AsmError::InvalidOperand);
2008 return;
2009 } else {
2010 inst = inst.set_rd_rs1_p(rd).set_c_nzuimm6lohi(imm as u32);
2011 }
2012 } else {
2013 self.last_error = Some(AsmError::InvalidOperand);
2014 return;
2015 }
2016 }
2017
2018 Encoding::RdRs1PRs2P => {
2019 short = true;
2020 if isign3 == enc_ops2!(Reg, Reg) {
2021 let rd = ops[0].id();
2022 let rs2 = ops[1].id();
2023 if !is_prime_register(rd) || !is_prime_register(rs2) {
2024 self.last_error = Some(AsmError::InvalidOperand);
2025 return;
2026 }
2027 inst = inst.set_rd_rs1_p(rd).set_rs2_p(rs2);
2028 } else {
2029 self.last_error = Some(AsmError::InvalidOperand);
2030 return;
2031 }
2032 }
2033
2034 Encoding::RdRs1Shamtd => {
2035 if isign3 == enc_ops3!(Reg, Reg, Imm) {
2036 let rd = ops[0].id();
2037 let rs1 = ops[1].id();
2038 let shamt = ops[2].as_::<Imm>().value() as i32;
2039 inst = inst.set_rd(rd).set_rs1(rs1).set_shamtd(shamt as _);
2040 } else {
2041 self.last_error = Some(AsmError::InvalidOperand);
2042 return;
2043 }
2044 }
2045 }
2046 let offset = self.buffer.cur_offset();
2047 if let Some((label, kind)) = label_use {
2048 self.buffer
2049 .use_label_at_offset(offset, label.as_::<Label>(), kind);
2050 }
2051
2052 if short {
2053 self.buffer.put2(inst.value as u16);
2054 } else {
2055 self.buffer.put4(inst.value);
2056 }
2057 }
2058}
2059
2060impl crate::core::builder::InstSink for Assembler<'_> {
2061 fn arch(&self) -> Arch {
2062 self.environment().arch()
2063 }
2064
2065 fn emit_inst(&mut self, inst: &crate::core::inst::Inst) -> Result<(), AsmError> {
2066 let ops = inst.operands();
2067 let mut refs: smallvec::SmallVec<[&Operand; 6]> = smallvec::SmallVec::new();
2068 refs.extend(ops.iter());
2069 self.try_emit_n(inst.id as i64, &refs)
2070 }
2071
2072 fn bind_label(&mut self, label: Label) -> Result<(), AsmError> {
2073 self.try_bind_label(label)
2074 }
2075}
2076
2077#[cfg(test)]
2078mod tests {
2079 use super::*;
2080 use crate::core::target::Environment;
2081 use crate::riscv::opcodes::{
2082 MATCH_C_LW, MATCH_C_NOT, MATCH_FADD_S, MATCH_FMADD_S, MATCH_FMV_W_X, MATCH_FMV_X_W,
2083 MATCH_LR_W, MATCH_SSAMOSWAP_W, MATCH_SSRDP, MATCH_VAESKF1_VI, MATCH_VFADD_VF, MATCH_VLE8_V,
2084 };
2085 use crate::riscv::operands::regs::*;
2086 use std::vec::Vec;
2087
2088 fn rv32(buf: &mut CodeBuffer) -> Assembler<'_> {
2089 Assembler::new(buf)
2090 }
2091
2092 fn data(buf: &mut CodeBuffer) -> Vec<u8> {
2093 buf.finish().unwrap().data().to_vec()
2094 }
2095
2096 #[test]
2097 fn default_environment_is_rv64() {
2098 let mut buf = CodeBuffer::new(Environment::new(Arch::RISCV64));
2099 let asm = Assembler::new(&mut buf);
2100 assert!(!asm.is_32bit());
2101 assert_eq!(asm.environment().arch(), Arch::RISCV64);
2102 }
2103
2104 #[test]
2105 fn fixed_fences_have_no_artificial_operands() {
2106 for arch in [Arch::RISCV32, Arch::RISCV64] {
2107 let mut buf = CodeBuffer::new(Environment::new(arch));
2108 {
2109 let mut asm = Assembler::new(&mut buf);
2110 asm.fence_i();
2111 asm.fence_tso();
2112 assert_eq!(asm.last_error(), None);
2113 }
2114 assert_eq!(
2115 data(&mut buf),
2116 [0x0000_100fu32.to_le_bytes(), 0x8330_000fu32.to_le_bytes()].concat()
2117 );
2118 }
2119 }
2120
2121 #[test]
2122 fn baseline_rejects_optional_extensions_before_writing() {
2123 let mut buf = CodeBuffer::new(Environment::baseline(Arch::RISCV64));
2124 let mut asm = Assembler::new(&mut buf);
2125 let vm = imm(1);
2126
2127 let error = asm
2128 .try_emit_n(
2129 Opcode::VADDVV as i64,
2130 &[
2131 V0.as_operand(),
2132 V1.as_operand(),
2133 V2.as_operand(),
2134 vm.as_operand(),
2135 ],
2136 )
2137 .unwrap_err();
2138
2139 assert!(
2140 matches!(error, AsmError::MissingCpuFeature { feature } if feature.contains("vadd.vv") && feature.contains("rv_v"))
2141 );
2142 assert!(asm.buffer.data().is_empty());
2143 }
2144
2145 #[test]
2146 fn optional_extensions_are_enabled_by_default() {
2147 let mut buf = CodeBuffer::new(Environment::new(Arch::RISCV64));
2148 let mut asm = Assembler::new(&mut buf);
2149 let vm = imm(1);
2150
2151 asm.try_emit_n(
2152 Opcode::VADDVV as i64,
2153 &[
2154 V0.as_operand(),
2155 V1.as_operand(),
2156 V2.as_operand(),
2157 vm.as_operand(),
2158 ],
2159 )
2160 .unwrap();
2161
2162 assert_eq!(asm.buffer.data().len(), 4);
2163 }
2164
2165 #[test]
2166 fn invalid_raw_opcode_is_rejected_without_writing() {
2167 let mut buf = CodeBuffer::new(Environment::new(Arch::RISCV64));
2168 let mut asm = Assembler::new(&mut buf);
2169
2170 asm.emit_n(-1, &[]);
2171 assert_eq!(asm.last_error(), Some(AsmError::InvalidInstruction));
2172 assert!(asm.buffer.data().is_empty());
2173
2174 asm.buffer.clear();
2175 asm.emit_n(i64::MAX, &[]);
2176 assert_eq!(asm.last_error(), Some(AsmError::InvalidInstruction));
2177 assert!(asm.buffer.data().is_empty());
2178 }
2179
2180 #[test]
2181 fn raw_emission_rejects_malformed_or_extra_operands_without_mutation() {
2182 let mut buf = CodeBuffer::new(Environment::new(Arch::RISCV64));
2183 let mut asm = Assembler::new(&mut buf);
2184 let malformed = Operand {
2185 signature: OperandSignature::from(7),
2186 base_id: 0,
2187 data: [0; 2],
2188 };
2189 let invalid_register = Operand {
2190 signature: OperandSignature::from(
2191 OperandType::Reg as u32 | (31 << OperandSignature::REG_TYPE_SHIFT),
2192 ),
2193 base_id: 0,
2194 data: [0; 2],
2195 };
2196 let none = Operand::new();
2197
2198 assert_eq!(
2199 asm.try_emit_n(Opcode::ADD as i64, &[&malformed]),
2200 Err(AsmError::InvalidOperand)
2201 );
2202 assert_eq!(
2203 asm.try_emit_n(Opcode::ADD as i64, &[&invalid_register]),
2204 Err(AsmError::InvalidOperand)
2205 );
2206 assert_eq!(
2207 asm.try_emit_n(Opcode::ADD as i64, &[RA.as_operand()]),
2208 Err(AsmError::InvalidOperand)
2209 );
2210 assert_eq!(
2211 asm.try_emit_n(
2212 Opcode::ADD as i64,
2213 &[&none, &none, &none, &none, &none, &none],
2214 ),
2215 Err(AsmError::InvalidOperand)
2216 );
2217 assert!(asm.buffer.error().is_none());
2218 assert!(asm.buffer.data().is_empty());
2219 }
2220
2221 #[test]
2222 fn macro_helpers_reject_wrong_operand_kinds_without_panicking() {
2223 let mut buf = CodeBuffer::new(Environment::new(Arch::RISCV64));
2224 let mut asm = Assembler::new(&mut buf);
2225
2226 asm.la(RA, imm(0));
2227 assert_eq!(asm.buffer.error(), Some(&AsmError::InvalidOperand));
2228 assert!(asm.buffer.data().is_empty());
2229
2230 asm.buffer.clear();
2231 asm.call(Operand::new());
2232 assert_eq!(asm.buffer.error(), Some(&AsmError::InvalidOperand));
2233 assert!(asm.buffer.data().is_empty());
2234 }
2235
2236 #[test]
2237 fn raw_label_registration_error_rolls_back_emission() {
2238 let mut buf = CodeBuffer::new(Environment::new(Arch::RISCV64));
2239 let mut asm = Assembler::new(&mut buf);
2240 let invalid_label = Label::from_id(0);
2241
2242 assert_eq!(
2243 asm.try_emit_n(
2244 Opcode::JAL as i64,
2245 &[RA.as_operand(), invalid_label.as_operand()]
2246 ),
2247 Err(AsmError::InvalidArgument)
2248 );
2249 assert_eq!(asm.buffer.error(), Some(&AsmError::InvalidArgument));
2250 assert!(asm.buffer.data().is_empty());
2251 }
2252
2253 #[test]
2254 fn failed_call_rolls_back_the_whole_sequence() {
2255 let mut buf = CodeBuffer::new(Environment::new(Arch::RISCV64));
2256 let mut asm = Assembler::new(&mut buf);
2257
2258 asm.call(Label::from_id(0));
2259
2260 assert_eq!(asm.buffer.error(), Some(&AsmError::InvalidArgument));
2261 assert!(asm.buffer.data().is_empty());
2262 }
2263
2264 #[test]
2265 fn unimplemented_encodings_return_typed_errors() {
2266 let mut buf = CodeBuffer::new(Environment::new(Arch::RISCV64));
2267 let mut asm = Assembler::new(&mut buf);
2268 let one = imm(1);
2269 let sixteen = imm(16);
2270 let zero = imm(0);
2271
2272 asm.emit_n(
2273 Opcode::CMPOP as i64,
2274 &[one.as_operand(), sixteen.as_operand()],
2275 );
2276 assert!(matches!(
2277 asm.last_error(),
2278 Some(AsmError::UnsupportedInstruction { .. })
2279 ));
2280 assert!(asm.buffer.data().is_empty());
2281
2282 asm.buffer.clear();
2283 asm.emit_n(Opcode::CMMVA01S as i64, &[A0.as_operand(), A1.as_operand()]);
2284 assert!(matches!(
2285 asm.last_error(),
2286 Some(AsmError::UnsupportedInstruction { .. })
2287 ));
2288 assert!(asm.buffer.data().is_empty());
2289
2290 asm.buffer.clear();
2291 asm.emit_n(
2292 Opcode::MOPRN as i64,
2293 &[
2294 zero.as_operand(),
2295 zero.as_operand(),
2296 zero.as_operand(),
2297 A0.as_operand(),
2298 A1.as_operand(),
2299 ],
2300 );
2301 assert!(matches!(
2302 asm.last_error(),
2303 Some(AsmError::UnsupportedInstruction { .. })
2304 ));
2305 assert!(asm.buffer.data().is_empty());
2306
2307 asm.buffer.clear();
2308 asm.emit_n(
2309 Opcode::MOPRRN as i64,
2310 &[
2311 zero.as_operand(),
2312 zero.as_operand(),
2313 A0.as_operand(),
2314 A1.as_operand(),
2315 A2.as_operand(),
2316 ],
2317 );
2318 assert!(matches!(
2319 asm.last_error(),
2320 Some(AsmError::UnsupportedInstruction { .. })
2321 ));
2322 assert!(asm.buffer.data().is_empty());
2323
2324 asm.buffer.clear();
2325 asm.emit_n(Opcode::CSEXTW as i64, &[A0.as_operand()]);
2326 assert!(matches!(
2327 asm.last_error(),
2328 Some(AsmError::UnsupportedInstruction { .. })
2329 ));
2330 assert!(asm.buffer.data().is_empty());
2331 }
2332
2333 #[test]
2334 fn rv32_encodes_base_and_rv32_only_instructions() {
2335 let mut buf = CodeBuffer::new(Environment::new(Arch::RISCV32));
2336 {
2337 let mut asm = rv32(&mut buf);
2338 asm.add(A0, A1, A2);
2339 asm.slli_rv32(A0, A1, 5);
2341 assert_eq!(asm.last_error(), None);
2342 }
2343 let expected = [0x00C58533u32.to_le_bytes(), 0x00559513u32.to_le_bytes()].concat();
2344 assert_eq!(data(&mut buf), expected);
2345 }
2346
2347 #[test]
2348 fn rv32_rejects_rv64_only_instructions() {
2349 let mut buf = CodeBuffer::new(Environment::new(Arch::RISCV32));
2350 {
2351 let mut asm = rv32(&mut buf);
2352 asm.ld(A0, A1, imm(0));
2353 asm.addw(A0, A1, A2);
2354 assert_eq!(asm.last_error(), Some(AsmError::InvalidInstruction));
2355 }
2356 assert_eq!(buf.finish().err(), Some(AsmError::InvalidInstruction));
2357 }
2358
2359 #[test]
2360 fn rv64_rejects_rv32_only_instructions() {
2361 let mut buf = CodeBuffer::new(Environment::new(Arch::RISCV64));
2362 {
2363 let mut asm = Assembler::new(&mut buf);
2364 asm.slli_rv32(A0, A1, imm(5));
2365 assert_eq!(asm.last_error(), Some(AsmError::InvalidInstruction));
2366 }
2367 assert_eq!(buf.finish().err(), Some(AsmError::InvalidInstruction));
2368 }
2369
2370 #[test]
2371 fn rv64_encodes_rv64_only_instructions() {
2372 let mut buf = CodeBuffer::new(Environment::new(Arch::RISCV64));
2373 {
2374 let mut asm = Assembler::new(&mut buf);
2375 asm.ld(A0, A1, imm(0));
2376 asm.addw(A0, A1, A2);
2377 assert_eq!(asm.last_error(), None);
2378 }
2379 let expected = [0x0005B503u32.to_le_bytes(), 0x00C5853Bu32.to_le_bytes()].concat();
2380 assert_eq!(data(&mut buf), expected);
2381 }
2382
2383 #[test]
2384 fn lpad_encodes_on_both_xlen() {
2385 let mut buf = CodeBuffer::new(Environment::new(Arch::RISCV32));
2388 {
2389 let mut asm = rv32(&mut buf);
2390 asm.lpad(imm(0x12345 << 12));
2391 assert_eq!(asm.last_error(), None);
2392 }
2393 assert_eq!(data(&mut buf), 0x12345017u32.to_le_bytes());
2394
2395 let mut buf = CodeBuffer::new(Environment::new(Arch::RISCV64));
2396 {
2397 let mut asm = Assembler::new(&mut buf);
2398 asm.lpad(imm(0x12345 << 12));
2399 assert_eq!(asm.last_error(), None);
2400 }
2401 assert_eq!(data(&mut buf), 0x12345017u32.to_le_bytes());
2402 }
2403
2404 #[test]
2405 fn zicfiss_shadow_stack_instructions_encode() {
2406 let mut buf = CodeBuffer::new(Environment::new(Arch::RISCV32));
2407 {
2408 let mut asm = rv32(&mut buf);
2409 asm.sspush_x1();
2410 asm.ssrdp(A0);
2411 asm.ssamoswap_w(A0, A1, A2, imm(0), imm(0));
2412 assert_eq!(asm.last_error(), None);
2413 }
2414 let sspush_x1 = 0xCE104073u32; let ssrdp_a0 = MATCH_SSRDP | (10 << 7);
2416 let ssamoswap_w = MATCH_SSAMOSWAP_W | (10 << 7) | (11 << 15) | (12 << 20);
2417 let expected = [
2418 sspush_x1.to_le_bytes(),
2419 ssrdp_a0.to_le_bytes(),
2420 ssamoswap_w.to_le_bytes(),
2421 ]
2422 .concat();
2423 assert_eq!(data(&mut buf), expected);
2424 }
2425
2426 #[test]
2427 fn rv32_accepts_zclsd_compressed_load_store_pair() {
2428 let mut buf = CodeBuffer::new(Environment::new(Arch::RISCV32));
2431 {
2432 let mut asm = rv32(&mut buf);
2433 asm.c_ld(A0, A1, imm(0));
2434 asm.c_sd(A1, A0, imm(0));
2436 assert_eq!(asm.last_error(), None);
2437 }
2438 assert_eq!(data(&mut buf), [0x88, 0x61, 0x88, 0xE1]);
2440 }
2441
2442 #[test]
2443 fn compressed_loads_use_prime_register_fields() {
2444 let mut buf = CodeBuffer::new(Environment::new(Arch::RISCV64));
2446 {
2447 let mut asm = Assembler::new(&mut buf);
2448 asm.c_lw(S0, A5, imm(0));
2449 assert_eq!(asm.last_error(), None);
2450 }
2451 assert_eq!(
2452 data(&mut buf),
2453 ((MATCH_C_LW | (7 << 7)) as u16).to_le_bytes()
2454 );
2455 }
2456
2457 #[test]
2458 fn typed_vector_fields_encode_and_validate() {
2459 let mut buf = CodeBuffer::new(Environment::new(Arch::RISCV64));
2460 {
2461 let mut asm = Assembler::new(&mut buf);
2462 asm.vle8_v(V1, A0, imm(1), imm(3));
2463 assert_eq!(asm.last_error(), None);
2464 }
2465 let expected = MATCH_VLE8_V | (1 << 7) | (10 << 15) | (1 << 25) | (3 << 29);
2466 assert_eq!(data(&mut buf), expected.to_le_bytes());
2467
2468 let mut buf = CodeBuffer::new(Environment::new(Arch::RISCV64));
2469 let mut asm = Assembler::new(&mut buf);
2470 asm.vle8_v(V1, A0, imm(2), imm(0));
2471 assert_eq!(asm.last_error(), Some(AsmError::InvalidOperand));
2472 asm.buffer.clear();
2473 asm.vle8_v(V1, A0, imm(1), imm(8));
2474 assert_eq!(asm.last_error(), Some(AsmError::InvalidOperand));
2475
2476 let mut buf = CodeBuffer::new(Environment::new(Arch::RISCV64));
2477 let mut asm = Assembler::new(&mut buf);
2478 asm.vaeskf1_vi(V1, V2, 3);
2479 assert_eq!(asm.last_error(), None);
2480 let expected = MATCH_VAESKF1_VI | (1 << 7) | (3 << 15) | (2 << 20);
2481 assert_eq!(asm.buffer.data(), expected.to_le_bytes());
2482
2483 let mut buf = CodeBuffer::new(Environment::new(Arch::RISCV64));
2484 let mut asm = Assembler::new(&mut buf);
2485 asm.vfadd_vf(V1, V2, F0, 1);
2486 asm.fmv_w_x(F1, A0);
2487 asm.fmv_x_w(A1, F2);
2488 assert_eq!(asm.last_error(), None);
2489 let expected = [
2490 (MATCH_VFADD_VF | (1 << 7) | (2 << 20) | (1 << 25)).to_le_bytes(),
2491 (MATCH_FMV_W_X | (1 << 7) | (10 << 15)).to_le_bytes(),
2492 (MATCH_FMV_X_W | (11 << 7) | (2 << 15)).to_le_bytes(),
2493 ]
2494 .concat();
2495 assert_eq!(asm.buffer.data(), expected);
2496 }
2497
2498 #[test]
2499 fn pc_relative_label_register_coupling_is_transactional() {
2500 let mut buf = CodeBuffer::new(Environment::new(Arch::RISCV64));
2501 let mut asm = Assembler::new(&mut buf);
2502 let label = asm.get_label();
2503 asm.emit_n(
2504 Opcode::JALR as i64,
2505 &[A0.as_operand(), A1.as_operand(), label.as_operand()],
2506 );
2507 assert_eq!(asm.last_error(), Some(AsmError::InvalidOperand));
2508 assert!(asm.buffer.data().is_empty());
2509
2510 let mut buf = CodeBuffer::new(Environment::new(Arch::RISCV64));
2511 let mut asm = Assembler::new(&mut buf);
2512 let label = asm.get_label();
2513 asm.emit_n(
2514 Opcode::LW as i64,
2515 &[A0.as_operand(), A1.as_operand(), label.as_operand()],
2516 );
2517 assert_eq!(asm.last_error(), Some(AsmError::InvalidOperand));
2518 assert!(asm.buffer.data().is_empty());
2519
2520 let mut buf = CodeBuffer::new(Environment::new(Arch::RISCV64));
2521 let mut asm = Assembler::new(&mut buf);
2522 let label = asm.get_label();
2523 asm.emit_n(
2524 Opcode::JALR as i64,
2525 &[A0.as_operand(), A0.as_operand(), label.as_operand()],
2526 );
2527 assert_eq!(asm.last_error(), None);
2528 assert_eq!(asm.buffer.data().len(), 8);
2529
2530 let mut buf = CodeBuffer::new(Environment::new(Arch::RISCV64));
2531 let mut asm = Assembler::new(&mut buf);
2532 let label = asm.get_label();
2533 asm.emit_n(
2534 Opcode::LW as i64,
2535 &[A0.as_operand(), A0.as_operand(), label.as_operand()],
2536 );
2537 assert_eq!(asm.last_error(), None);
2538 assert_eq!(asm.buffer.data().len(), 8);
2539 }
2540
2541 #[test]
2542 fn typed_atomic_and_rounding_fields_validate() {
2543 let mut buf = CodeBuffer::new(Environment::new(Arch::RISCV64));
2544 {
2545 let mut asm = Assembler::new(&mut buf);
2546 asm.lr_w(A0, A1, 0, 0);
2547 asm.lr_w(A0, A1, 0, 1);
2548 asm.lr_w(A0, A1, 1, 0);
2549 asm.lr_w(A0, A1, 1, 1);
2550 assert_eq!(asm.last_error(), None);
2551 }
2552 let base = MATCH_LR_W | (10 << 7) | (11 << 15);
2553 let expected = [
2554 base.to_le_bytes(),
2555 (base | (1 << 25)).to_le_bytes(),
2556 (base | (1 << 26)).to_le_bytes(),
2557 (base | (3 << 25)).to_le_bytes(),
2558 ]
2559 .concat();
2560 assert_eq!(data(&mut buf), expected);
2561
2562 let mut buf = CodeBuffer::new(Environment::new(Arch::RISCV64));
2563 let mut asm = Assembler::new(&mut buf);
2564 asm.fadd_s(F0, F1, F2, imm(5));
2565 assert_eq!(asm.last_error(), Some(AsmError::InvalidOperand));
2566 asm.buffer.clear();
2567 asm.fadd_s(F0, F1, F2, imm(7));
2568 assert_eq!(asm.last_error(), None);
2569 let expected = MATCH_FADD_S | (1 << 15) | (2 << 20) | (7 << 12);
2570 assert_eq!(asm.buffer.data(), expected.to_le_bytes());
2571
2572 let mut buf = CodeBuffer::new(Environment::new(Arch::RISCV64));
2573 let mut asm = Assembler::new(&mut buf);
2574 asm.fmadd_s(F0, F1, F2, F3, 0);
2575 assert_eq!(asm.last_error(), None);
2576 let expected = MATCH_FMADD_S | (1 << 15) | (2 << 20) | (3 << 27);
2577 assert_eq!(asm.buffer.data(), expected.to_le_bytes());
2578 }
2579
2580 #[test]
2581 fn compressed_prime_registers_reject_non_prime_ids() {
2582 let mut buf = CodeBuffer::new(Environment::new(Arch::RISCV64));
2583 let mut asm = Assembler::new(&mut buf);
2584 asm.c_lw(T2, A1, imm(0));
2585 assert_eq!(asm.last_error(), Some(AsmError::InvalidOperand));
2586 assert!(asm.buffer.data().is_empty());
2587
2588 let mut buf = CodeBuffer::new(Environment::new(Arch::RISCV64));
2589 {
2590 let mut asm = Assembler::new(&mut buf);
2591 asm.c_not(S0);
2592 assert_eq!(asm.last_error(), None);
2593 }
2594 assert_eq!(
2595 data(&mut buf),
2596 ((MATCH_C_NOT & !(0x7 << 7)) as u16).to_le_bytes()
2597 );
2598
2599 let mut buf = CodeBuffer::new(Environment::new(Arch::RISCV64));
2600 let mut asm = Assembler::new(&mut buf);
2601 asm.c_not(T2);
2602 assert_eq!(asm.last_error(), Some(AsmError::InvalidOperand));
2603 assert!(asm.buffer.data().is_empty());
2604
2605 asm.buffer.clear();
2606 asm.c_lw(A0, T2, imm(0));
2607 assert_eq!(asm.last_error(), Some(AsmError::InvalidOperand));
2608 assert!(asm.buffer.data().is_empty());
2609
2610 asm.buffer.clear();
2611 asm.c_lw(A6, A1, imm(0));
2612 assert_eq!(asm.last_error(), Some(AsmError::InvalidOperand));
2613 assert!(asm.buffer.data().is_empty());
2614 }
2615
2616 #[test]
2617 fn register_label_encodings_use_the_label_operand() {
2618 for arch in [Arch::RISCV32, Arch::RISCV64] {
2619 let mut buf = CodeBuffer::new(Environment::new(arch));
2620 let target = buf.get_label();
2621 {
2622 let mut asm = Assembler::new(&mut buf);
2623 asm.auipc(A0, target);
2624 asm.jal(A1, target);
2625 asm.bind_label(target);
2626 assert_eq!(asm.last_error(), None);
2627 }
2628 assert_eq!(buf.label_offset(target), 8);
2629 assert_eq!(
2630 data(&mut buf),
2631 [0x0000_0517u32.to_le_bytes(), 0x0040_05EFu32.to_le_bytes()].concat()
2632 );
2633
2634 let mut buf = CodeBuffer::new(Environment::new(arch));
2635 let target = buf.get_label();
2636 {
2637 let mut asm = Assembler::new(&mut buf);
2638 asm.bind_label(target);
2639 asm.auipc(A0, target);
2640 asm.jal(A1, target);
2641 assert_eq!(asm.last_error(), None);
2642 }
2643 assert_eq!(buf.label_offset(target), 0);
2644 assert_eq!(
2645 data(&mut buf),
2646 [0x0000_0517u32.to_le_bytes(), 0xFFDFF5EFu32.to_le_bytes()].concat()
2647 );
2648 }
2649 }
2650
2651 #[test]
2652 fn patchable_li_literal_can_be_rewritten() {
2653 let mut buf = CodeBuffer::new(Environment::new(Arch::RISCV64));
2654 let block = {
2655 let mut asm = Assembler::new(&mut buf);
2656 asm.patchable_li(A0, 0x1122_3344_5566_7788u64 as i64)
2657 };
2658 let code = buf.finish_patched().unwrap();
2659 assert_eq!(block.size(), 8);
2660 assert_eq!(
2661 &code.data()[block.offset() as usize..][..8],
2662 &0x1122_3344_5566_7788u64.to_le_bytes()
2663 );
2664 let ld = u32::from_le_bytes([
2667 code.data()[4],
2668 code.data()[5],
2669 code.data()[6],
2670 code.data()[7],
2671 ]);
2672 assert_eq!(((ld as i32) >> 20) & 0xFFF, 12);
2673
2674 let mut bytes = code.data().to_vec();
2675 unsafe {
2676 block
2677 .repatch_u64(&mut bytes, 0xAABB_CCDD_EEFF_0011)
2678 .unwrap();
2679 }
2680 assert_eq!(
2681 &bytes[block.offset() as usize..][..8],
2682 &0xAABB_CCDD_EEFF_0011u64.to_le_bytes()
2683 );
2684 }
2685
2686 #[test]
2687 fn patchable_j_can_be_retargeted_offline() {
2688 let mut buf = CodeBuffer::new(Environment::new(Arch::RISCV64));
2689 let (site, alt) = {
2690 let mut asm = Assembler::new(&mut buf);
2691 let target = asm.get_label();
2692 let alt = asm.get_label();
2693 let site = asm.patchable_j(target);
2694 asm.bind_label(target);
2695 asm.addi(A0, A0, imm(1));
2696 asm.bind_label(alt);
2697 asm.addi(A0, A0, imm(2));
2698 (site, asm.label_offset(alt))
2699 };
2700 let code = buf.finish_patched().unwrap();
2701 let mut bytes = code.data().to_vec();
2702 unsafe {
2703 site.retarget(&mut bytes, alt).unwrap();
2704 }
2705 assert_ne!(bytes, code.data());
2707 }
2708}