Skip to main content

asmkit/riscv/
assembler.rs

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