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