1 //! Riscv64 ISA definitions: instruction arguments.
2 
3 use super::*;
4 use crate::ir::condcodes::CondCode;
5 
6 use crate::isa::riscv64::lower::isle::generated_code::{
7     COpcodeSpace, CaOp, CbOp, CiOp, CiwOp, ClOp, CrOp, CsOp, CssOp, CsznOp, FpuOPWidth, ZcbMemOp,
8 };
9 use crate::machinst::isle::WritableReg;
10 
11 use core::fmt::Result;
12 
13 /// A macro for defining a newtype of `Reg` that enforces some invariant about
14 /// the wrapped `Reg` (such as that it is of a particular register class).
15 macro_rules! newtype_of_reg {
16     (
17         $newtype_reg:ident,
18         $newtype_writable_reg:ident,
19         |$check_reg:ident| $check:expr
20     ) => {
21         /// A newtype wrapper around `Reg`.
22         #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
23         pub struct $newtype_reg(Reg);
24 
25         impl PartialEq<Reg> for $newtype_reg {
26             fn eq(&self, other: &Reg) -> bool {
27                 self.0 == *other
28             }
29         }
30 
31         impl From<$newtype_reg> for Reg {
32             fn from(r: $newtype_reg) -> Self {
33                 r.0
34             }
35         }
36 
37         impl $newtype_reg {
38             /// Create this newtype from the given register, or return `None` if the register
39             /// is not a valid instance of this newtype.
40             pub fn new($check_reg: Reg) -> Option<Self> {
41                 if $check { Some(Self($check_reg)) } else { None }
42             }
43 
44             /// Get this newtype's underlying `Reg`.
45             pub fn to_reg(self) -> Reg {
46                 self.0
47             }
48         }
49 
50         // Convenience impl so that people working with this newtype can use it
51         // "just like" a plain `Reg`.
52         //
53         // NB: We cannot implement `DerefMut` because that would let people do
54         // nasty stuff like `*my_xreg.deref_mut() = some_freg`, breaking the
55         // invariants that `XReg` provides.
56         impl core::ops::Deref for $newtype_reg {
57             type Target = Reg;
58 
59             fn deref(&self) -> &Reg {
60                 &self.0
61             }
62         }
63 
64         /// Writable Reg.
65         pub type $newtype_writable_reg = Writable<$newtype_reg>;
66     };
67 }
68 
69 // Newtypes for registers classes.
70 newtype_of_reg!(XReg, WritableXReg, |reg| reg.class() == RegClass::Int);
71 newtype_of_reg!(FReg, WritableFReg, |reg| reg.class() == RegClass::Float);
72 newtype_of_reg!(VReg, WritableVReg, |reg| reg.class() == RegClass::Vector);
73 
74 /// An addressing mode specified for a load/store operation.
75 #[derive(Clone, Debug, Copy)]
76 pub enum AMode {
77     /// Arbitrary offset from a register. Converted to generation of large
78     /// offsets with multiple instructions as necessary during code emission.
79     RegOffset(Reg, i64),
80     /// Offset from the stack pointer.
81     SPOffset(i64),
82 
83     /// Offset from the frame pointer.
84     FPOffset(i64),
85 
86     /// Offset into the slot area of the stack, which lies just above the
87     /// outgoing argument area that's setup by the function prologue.
88     /// At emission time, this is converted to `SPOffset` with a fixup added to
89     /// the offset constant. The fixup is a running value that is tracked as
90     /// emission iterates through instructions in linear order, and can be
91     /// adjusted up and down with [Inst::VirtualSPOffsetAdj].
92     ///
93     /// The standard ABI is in charge of handling this (by emitting the
94     /// adjustment meta-instructions). See the diagram in the documentation
95     /// for [crate::isa::aarch64::abi](the ABI module) for more details.
96     SlotOffset(i64),
97 
98     /// Offset into the argument area.
99     IncomingArg(i64),
100 
101     /// A reference to a constant which is placed outside of the function's
102     /// body, typically at the end.
103     Const(VCodeConstant),
104 
105     /// A reference to a label.
106     Label(MachLabel),
107 }
108 
109 impl AMode {
110     /// Add the registers referenced by this AMode to `collector`.
get_operands(&mut self, collector: &mut impl OperandVisitor)111     pub(crate) fn get_operands(&mut self, collector: &mut impl OperandVisitor) {
112         match self {
113             AMode::RegOffset(reg, ..) => collector.reg_use(reg),
114             // Registers used in these modes aren't allocatable.
115             AMode::SPOffset(..)
116             | AMode::FPOffset(..)
117             | AMode::SlotOffset(..)
118             | AMode::IncomingArg(..)
119             | AMode::Const(..)
120             | AMode::Label(..) => {}
121         }
122     }
123 
get_base_register(&self) -> Option<Reg>124     pub(crate) fn get_base_register(&self) -> Option<Reg> {
125         match self {
126             &AMode::RegOffset(reg, ..) => Some(reg),
127             &AMode::SPOffset(..) => Some(stack_reg()),
128             &AMode::FPOffset(..) => Some(fp_reg()),
129             &AMode::SlotOffset(..) => Some(stack_reg()),
130             &AMode::IncomingArg(..) => Some(stack_reg()),
131             &AMode::Const(..) | AMode::Label(..) => None,
132         }
133     }
134 
get_offset_with_state(&self, state: &EmitState) -> i64135     pub(crate) fn get_offset_with_state(&self, state: &EmitState) -> i64 {
136         match self {
137             &AMode::SlotOffset(offset) => {
138                 offset + i64::from(state.frame_layout().outgoing_args_size)
139             }
140 
141             // Compute the offset into the incoming argument area relative to SP
142             &AMode::IncomingArg(offset) => {
143                 let frame_layout = state.frame_layout();
144                 let sp_offset = frame_layout.tail_args_size
145                     + frame_layout.setup_area_size
146                     + frame_layout.clobber_size
147                     + frame_layout.fixed_frame_storage_size
148                     + frame_layout.outgoing_args_size;
149                 i64::from(sp_offset) - offset
150             }
151 
152             &AMode::RegOffset(_, offset) => offset,
153             &AMode::SPOffset(offset) => offset,
154             &AMode::FPOffset(offset) => offset,
155             &AMode::Const(_) | &AMode::Label(_) => 0,
156         }
157     }
158 
159     /// Retrieve a MachLabel that corresponds to this addressing mode, if it exists.
get_label_with_sink(&self, sink: &mut MachBuffer<Inst>) -> Option<MachLabel>160     pub(crate) fn get_label_with_sink(&self, sink: &mut MachBuffer<Inst>) -> Option<MachLabel> {
161         match self {
162             &AMode::Const(addr) => Some(sink.get_label_for_constant(addr)),
163             &AMode::Label(label) => Some(label),
164             &AMode::RegOffset(..)
165             | &AMode::SPOffset(..)
166             | &AMode::FPOffset(..)
167             | &AMode::IncomingArg(..)
168             | &AMode::SlotOffset(..) => None,
169         }
170     }
171 }
172 
173 impl Display for AMode {
fmt(&self, f: &mut Formatter<'_>) -> Result174     fn fmt(&self, f: &mut Formatter<'_>) -> Result {
175         match self {
176             &AMode::RegOffset(r, offset, ..) => {
177                 write!(f, "{}({})", offset, reg_name(r))
178             }
179             &AMode::SPOffset(offset, ..) => {
180                 write!(f, "{offset}(sp)")
181             }
182             &AMode::SlotOffset(offset, ..) => {
183                 write!(f, "{offset}(slot)")
184             }
185             &AMode::IncomingArg(offset) => {
186                 write!(f, "-{offset}(incoming_arg)")
187             }
188             &AMode::FPOffset(offset, ..) => {
189                 write!(f, "{offset}(fp)")
190             }
191             &AMode::Const(addr, ..) => {
192                 write!(f, "[const({})]", addr.as_u32())
193             }
194             &AMode::Label(label) => {
195                 write!(f, "[label{}]", label.as_u32())
196             }
197         }
198     }
199 }
200 
201 impl From<StackAMode> for AMode {
from(stack: StackAMode) -> AMode202     fn from(stack: StackAMode) -> AMode {
203         match stack {
204             StackAMode::IncomingArg(offset, stack_args_size) => {
205                 AMode::IncomingArg(i64::from(stack_args_size) - offset)
206             }
207             StackAMode::OutgoingArg(offset) => AMode::SPOffset(offset),
208             StackAMode::Slot(offset) => AMode::SlotOffset(offset),
209         }
210     }
211 }
212 
213 /// risc-v always take two register to compare
214 #[derive(Clone, Copy, Debug)]
215 pub struct IntegerCompare {
216     pub(crate) kind: IntCC,
217     pub(crate) rs1: Reg,
218     pub(crate) rs2: Reg,
219 }
220 
221 pub(crate) enum BranchFunct3 {
222     // ==
223     Eq,
224     // !=
225     Ne,
226     // signed <
227     Lt,
228     // signed >=
229     Ge,
230     // unsigned <
231     Ltu,
232     // unsigned >=
233     Geu,
234 }
235 
236 impl BranchFunct3 {
funct3(self) -> u32237     pub(crate) fn funct3(self) -> u32 {
238         match self {
239             BranchFunct3::Eq => 0b000,
240             BranchFunct3::Ne => 0b001,
241             BranchFunct3::Lt => 0b100,
242             BranchFunct3::Ge => 0b101,
243             BranchFunct3::Ltu => 0b110,
244             BranchFunct3::Geu => 0b111,
245         }
246     }
247 }
248 
249 impl IntegerCompare {
op_code(self) -> u32250     pub(crate) fn op_code(self) -> u32 {
251         0b1100011
252     }
253 
254     // funct3 and if need inverse the register
funct3(&self) -> (BranchFunct3, bool)255     pub(crate) fn funct3(&self) -> (BranchFunct3, bool) {
256         match self.kind {
257             IntCC::Equal => (BranchFunct3::Eq, false),
258             IntCC::NotEqual => (BranchFunct3::Ne, false),
259             IntCC::SignedLessThan => (BranchFunct3::Lt, false),
260             IntCC::SignedGreaterThanOrEqual => (BranchFunct3::Ge, false),
261 
262             IntCC::SignedGreaterThan => (BranchFunct3::Lt, true),
263             IntCC::SignedLessThanOrEqual => (BranchFunct3::Ge, true),
264 
265             IntCC::UnsignedLessThan => (BranchFunct3::Ltu, false),
266             IntCC::UnsignedGreaterThanOrEqual => (BranchFunct3::Geu, false),
267 
268             IntCC::UnsignedGreaterThan => (BranchFunct3::Ltu, true),
269             IntCC::UnsignedLessThanOrEqual => (BranchFunct3::Geu, true),
270         }
271     }
272 
273     #[inline]
op_name(&self) -> &'static str274     pub(crate) fn op_name(&self) -> &'static str {
275         match self.kind {
276             IntCC::Equal => "beq",
277             IntCC::NotEqual => "bne",
278             IntCC::SignedLessThan => "blt",
279             IntCC::SignedGreaterThanOrEqual => "bge",
280             IntCC::SignedGreaterThan => "bgt",
281             IntCC::SignedLessThanOrEqual => "ble",
282             IntCC::UnsignedLessThan => "bltu",
283             IntCC::UnsignedGreaterThanOrEqual => "bgeu",
284             IntCC::UnsignedGreaterThan => "bgtu",
285             IntCC::UnsignedLessThanOrEqual => "bleu",
286         }
287     }
288 
emit(self) -> u32289     pub(crate) fn emit(self) -> u32 {
290         let (funct3, reverse) = self.funct3();
291         let (rs1, rs2) = if reverse {
292             (self.rs2, self.rs1)
293         } else {
294             (self.rs1, self.rs2)
295         };
296 
297         self.op_code()
298             | funct3.funct3() << 12
299             | reg_to_gpr_num(rs1) << 15
300             | reg_to_gpr_num(rs2) << 20
301     }
302 
inverse(self) -> Self303     pub(crate) fn inverse(self) -> Self {
304         Self {
305             kind: self.kind.complement(),
306             ..self
307         }
308     }
309 
regs(&self) -> [Reg; 2]310     pub(crate) fn regs(&self) -> [Reg; 2] {
311         [self.rs1, self.rs2]
312     }
313 }
314 
315 #[derive(Debug, Clone, Copy, PartialEq)]
316 pub struct FliConstant(u8);
317 
318 impl FliConstant {
new(value: u8) -> Self319     pub(crate) fn new(value: u8) -> Self {
320         debug_assert!(value <= 31, "Invalid FliConstant: {value}");
321         Self(value)
322     }
323 
maybe_from_u64(ty: Type, imm: u64) -> Option<Self>324     pub(crate) fn maybe_from_u64(ty: Type, imm: u64) -> Option<Self> {
325         // Convert the value into an F64, this allows us to represent
326         // values from both f32 and f64 in the same value.
327         let value = match ty {
328             F16 => {
329                 // FIXME(#8312): Use `f16` once it has been stabilised.
330                 // Handle special/non-normal values first.
331                 match imm {
332                     // `f16::MIN_POSITIVE`
333                     0x0400 => return Some(Self::new(1)),
334                     // 2 pow -16
335                     0x0100 => return Some(Self::new(2)),
336                     // 2 pow -15
337                     0x0200 => return Some(Self::new(3)),
338                     // `f16::INFINITY`
339                     0x7c00 => return Some(Self::new(30)),
340                     // Canonical NaN
341                     0x7e00 => return Some(Self::new(31)),
342                     _ => {
343                         let exponent_bits = imm & 0x7c00;
344                         if exponent_bits == 0 || exponent_bits == 0x7c00 {
345                             // All non-normal values are handled above.
346                             return None;
347                         }
348                         let sign = (imm & 0x8000) << 48;
349                         // Adjust the exponent for the difference between the `f16` exponent bias
350                         // and the `f64` exponent bias.
351                         let exponent = (exponent_bits + ((1023 - 15) << 10)) << 42;
352                         let significand = (imm & 0x3ff) << 42;
353                         f64::from_bits(sign | exponent | significand)
354                     }
355                 }
356             }
357             F32 => f32::from_bits(imm as u32) as f64,
358             F64 => f64::from_bits(imm),
359             _ => unimplemented!(),
360         };
361 
362         Some(match (ty, value) {
363             (_, f) if f == -1.0 => Self::new(0),
364 
365             // Since f64 can represent all f32 values, f32::min_positive won't be
366             // the same as f64::min_positive, so we need to check for both indepenendtly
367             (F32, f) if f == (f32::MIN_POSITIVE as f64) => Self::new(1),
368             (F64, f) if f == f64::MIN_POSITIVE => Self::new(1),
369 
370             (_, f) if f == 2.0f64.powi(-16) => Self::new(2),
371             (_, f) if f == 2.0f64.powi(-15) => Self::new(3),
372             (_, f) if f == 2.0f64.powi(-8) => Self::new(4),
373             (_, f) if f == 2.0f64.powi(-7) => Self::new(5),
374             (_, f) if f == 0.0625 => Self::new(6),
375             (_, f) if f == 0.125 => Self::new(7),
376             (_, f) if f == 0.25 => Self::new(8),
377             (_, f) if f == 0.3125 => Self::new(9),
378             (_, f) if f == 0.375 => Self::new(10),
379             (_, f) if f == 0.4375 => Self::new(11),
380             (_, f) if f == 0.5 => Self::new(12),
381             (_, f) if f == 0.625 => Self::new(13),
382             (_, f) if f == 0.75 => Self::new(14),
383             (_, f) if f == 0.875 => Self::new(15),
384             (_, f) if f == 1.0 => Self::new(16),
385             (_, f) if f == 1.25 => Self::new(17),
386             (_, f) if f == 1.5 => Self::new(18),
387             (_, f) if f == 1.75 => Self::new(19),
388             (_, f) if f == 2.0 => Self::new(20),
389             (_, f) if f == 2.5 => Self::new(21),
390             (_, f) if f == 3.0 => Self::new(22),
391             (_, f) if f == 4.0 => Self::new(23),
392             (_, f) if f == 8.0 => Self::new(24),
393             (_, f) if f == 16.0 => Self::new(25),
394             (_, f) if f == 128.0 => Self::new(26),
395             (_, f) if f == 256.0 => Self::new(27),
396             (_, f) if f == 32768.0 => Self::new(28),
397             (_, f) if f == 65536.0 => Self::new(29),
398             (_, f) if f == f64::INFINITY => Self::new(30),
399 
400             // NaN's are not guaranteed to preserve the sign / payload bits, so we need to check
401             // the original bits directly.
402             (F32, f) if f.is_nan() && imm == 0x7fc0_0000 => Self::new(31), // Canonical NaN
403             (F64, f) if f.is_nan() && imm == 0x7ff8_0000_0000_0000 => Self::new(31), // Canonical NaN
404             _ => return None,
405         })
406     }
407 
format(self) -> &'static str408     pub(crate) fn format(self) -> &'static str {
409         // The preferred assembly syntax for entries 1, 30, and 31 is min, inf, and nan, respectively.
410         // For entries 0 through 29 (including entry 1), the assembler will accept decimal constants
411         // in C-like syntax.
412         match self.0 {
413             0 => "-1.0",
414             1 => "min",
415             2 => "2^-16",
416             3 => "2^-15",
417             4 => "2^-8",
418             5 => "2^-7",
419             6 => "0.0625",
420             7 => "0.125",
421             8 => "0.25",
422             9 => "0.3125",
423             10 => "0.375",
424             11 => "0.4375",
425             12 => "0.5",
426             13 => "0.625",
427             14 => "0.75",
428             15 => "0.875",
429             16 => "1.0",
430             17 => "1.25",
431             18 => "1.5",
432             19 => "1.75",
433             20 => "2.0",
434             21 => "2.5",
435             22 => "3.0",
436             23 => "4.0",
437             24 => "8.0",
438             25 => "16.0",
439             26 => "128.0",
440             27 => "256.0",
441             28 => "32768.0",
442             29 => "65536.0",
443             30 => "inf",
444             31 => "nan",
445             _ => panic!("Invalid FliConstant"),
446         }
447     }
448 
bits(self) -> u8449     pub(crate) fn bits(self) -> u8 {
450         self.0
451     }
452 }
453 
454 impl FpuOPRRRR {
op_name(self, width: FpuOPWidth) -> String455     pub(crate) fn op_name(self, width: FpuOPWidth) -> String {
456         match self {
457             Self::Fmadd => format!("fmadd.{width}"),
458             Self::Fmsub => format!("fmsub.{width}"),
459             Self::Fnmsub => format!("fnmsub.{width}"),
460             Self::Fnmadd => format!("fnmadd.{width}"),
461         }
462     }
463 
opcode(self) -> u32464     pub(crate) fn opcode(self) -> u32 {
465         match self {
466             Self::Fmadd => 0b1000011,
467             Self::Fmsub => 0b1000111,
468             Self::Fnmsub => 0b1001011,
469             Self::Fnmadd => 0b1001111,
470         }
471     }
472 }
473 
474 impl FpuOPRR {
op_name(self, width: FpuOPWidth) -> String475     pub(crate) fn op_name(self, width: FpuOPWidth) -> String {
476         let fmv_width = match width {
477             FpuOPWidth::H => "h",
478             FpuOPWidth::S => "w",
479             FpuOPWidth::D => "d",
480             FpuOPWidth::Q => "q",
481         };
482         match self {
483             Self::Fsqrt => format!("fsqrt.{width}"),
484             Self::Fround => format!("fround.{width}"),
485             Self::Fclass => format!("fclass.{width}"),
486             Self::FcvtWFmt => format!("fcvt.w.{width}"),
487             Self::FcvtWuFmt => format!("fcvt.wu.{width}"),
488             Self::FcvtLFmt => format!("fcvt.l.{width}"),
489             Self::FcvtLuFmt => format!("fcvt.lu.{width}"),
490             Self::FcvtFmtW => format!("fcvt.{width}.w"),
491             Self::FcvtFmtWu => format!("fcvt.{width}.wu"),
492             Self::FcvtFmtL => format!("fcvt.{width}.l"),
493             Self::FcvtFmtLu => format!("fcvt.{width}.lu"),
494 
495             // fmv instructions deviate from the normal encoding and instead
496             // encode the width as "w" instead of "s". The ISA manual gives this rationale:
497             //
498             // Instructions FMV.S.X and FMV.X.S were renamed to FMV.W.X and FMV.X.W respectively
499             // to be more consistent with their semantics, which did not change. The old names will continue
500             // to be supported in the tools.
501             Self::FmvXFmt => format!("fmv.x.{fmv_width}"),
502             Self::FmvFmtX => format!("fmv.{fmv_width}.x"),
503 
504             Self::FcvtSD => "fcvt.s.d".to_string(),
505             Self::FcvtDS => "fcvt.d.s".to_string(),
506         }
507     }
508 
is_convert_to_int(self) -> bool509     pub(crate) fn is_convert_to_int(self) -> bool {
510         match self {
511             Self::FcvtWFmt | Self::FcvtWuFmt | Self::FcvtLFmt | Self::FcvtLuFmt => true,
512             _ => false,
513         }
514     }
515 
has_frm(self) -> bool516     pub(crate) fn has_frm(self) -> bool {
517         match self {
518             FpuOPRR::FmvXFmt | FpuOPRR::FmvFmtX | FpuOPRR::Fclass => false,
519             _ => true,
520         }
521     }
522 
opcode(self) -> u32523     pub(crate) fn opcode(self) -> u32 {
524         // OP-FP Major opcode
525         0b1010011
526     }
527 
rs2(self) -> u32528     pub(crate) fn rs2(self) -> u32 {
529         match self {
530             Self::Fsqrt => 0b00000,
531             Self::Fround => 0b00100,
532             Self::Fclass => 0b00000,
533             Self::FcvtWFmt => 0b00000,
534             Self::FcvtWuFmt => 0b00001,
535             Self::FcvtLFmt => 0b00010,
536             Self::FcvtLuFmt => 0b00011,
537             Self::FcvtFmtW => 0b00000,
538             Self::FcvtFmtWu => 0b00001,
539             Self::FcvtFmtL => 0b00010,
540             Self::FcvtFmtLu => 0b00011,
541             Self::FmvXFmt => 0b00000,
542             Self::FmvFmtX => 0b00000,
543             Self::FcvtSD => 0b00001,
544             Self::FcvtDS => 0b00000,
545         }
546     }
547 
funct5(self) -> u32548     pub(crate) fn funct5(self) -> u32 {
549         match self {
550             Self::Fsqrt => 0b01011,
551             Self::Fround => 0b01000,
552             Self::Fclass => 0b11100,
553             Self::FcvtWFmt => 0b11000,
554             Self::FcvtWuFmt => 0b11000,
555             Self::FcvtLFmt => 0b11000,
556             Self::FcvtLuFmt => 0b11000,
557             Self::FcvtFmtW => 0b11010,
558             Self::FcvtFmtWu => 0b11010,
559             Self::FcvtFmtL => 0b11010,
560             Self::FcvtFmtLu => 0b11010,
561             Self::FmvXFmt => 0b11100,
562             Self::FmvFmtX => 0b11110,
563             Self::FcvtSD => 0b01000,
564             Self::FcvtDS => 0b01000,
565         }
566     }
567 
funct7(self, width: FpuOPWidth) -> u32568     pub(crate) fn funct7(self, width: FpuOPWidth) -> u32 {
569         (self.funct5() << 2) | width.as_u32()
570     }
571 }
572 
573 impl FpuOPRRR {
op_name(self, width: FpuOPWidth) -> String574     pub(crate) fn op_name(self, width: FpuOPWidth) -> String {
575         match self {
576             Self::Fadd => format!("fadd.{width}"),
577             Self::Fsub => format!("fsub.{width}"),
578             Self::Fmul => format!("fmul.{width}"),
579             Self::Fdiv => format!("fdiv.{width}"),
580             Self::Fsgnj => format!("fsgnj.{width}"),
581             Self::Fsgnjn => format!("fsgnjn.{width}"),
582             Self::Fsgnjx => format!("fsgnjx.{width}"),
583             Self::Fmin => format!("fmin.{width}"),
584             Self::Fmax => format!("fmax.{width}"),
585             Self::Feq => format!("feq.{width}"),
586             Self::Flt => format!("flt.{width}"),
587             Self::Fle => format!("fle.{width}"),
588             Self::Fminm => format!("fminm.{width}"),
589             Self::Fmaxm => format!("fmaxm.{width}"),
590         }
591     }
592 
opcode(self) -> u32593     pub(crate) fn opcode(self) -> u32 {
594         // OP-FP Major opcode
595         0b1010011
596     }
597 
funct5(self) -> u32598     pub(crate) const fn funct5(self) -> u32 {
599         match self {
600             Self::Fadd => 0b00000,
601             Self::Fsub => 0b00001,
602             Self::Fmul => 0b00010,
603             Self::Fdiv => 0b00011,
604             Self::Fsgnj => 0b00100,
605             Self::Fsgnjn => 0b00100,
606             Self::Fsgnjx => 0b00100,
607             Self::Fmin => 0b00101,
608             Self::Fmax => 0b00101,
609             Self::Feq => 0b10100,
610             Self::Flt => 0b10100,
611             Self::Fle => 0b10100,
612             Self::Fminm => 0b00101,
613             Self::Fmaxm => 0b00101,
614         }
615     }
616 
funct7(self, width: FpuOPWidth) -> u32617     pub(crate) fn funct7(self, width: FpuOPWidth) -> u32 {
618         (self.funct5() << 2) | width.as_u32()
619     }
620 
has_frm(self) -> bool621     pub(crate) fn has_frm(self) -> bool {
622         match self {
623             FpuOPRRR::Fsgnj
624             | FpuOPRRR::Fsgnjn
625             | FpuOPRRR::Fsgnjx
626             | FpuOPRRR::Fmin
627             | FpuOPRRR::Fmax
628             | FpuOPRRR::Feq
629             | FpuOPRRR::Flt
630             | FpuOPRRR::Fle => false,
631             _ => true,
632         }
633     }
634 }
635 
636 impl Display for FpuOPWidth {
fmt(&self, f: &mut Formatter<'_>) -> Result637     fn fmt(&self, f: &mut Formatter<'_>) -> Result {
638         write!(
639             f,
640             "{}",
641             match self {
642                 FpuOPWidth::H => "h",
643                 FpuOPWidth::S => "s",
644                 FpuOPWidth::D => "d",
645                 FpuOPWidth::Q => "q",
646             }
647         )
648     }
649 }
650 
651 impl TryFrom<Type> for FpuOPWidth {
652     type Error = &'static str;
653 
try_from(value: Type) -> core::result::Result<Self, Self::Error>654     fn try_from(value: Type) -> core::result::Result<Self, Self::Error> {
655         match value {
656             F16 => Ok(FpuOPWidth::H),
657             F32 => Ok(FpuOPWidth::S),
658             F64 => Ok(FpuOPWidth::D),
659             F128 => Ok(FpuOPWidth::Q),
660             _ => Err("Invalid type for FpuOPWidth"),
661         }
662     }
663 }
664 
665 impl FpuOPWidth {
as_u32(&self) -> u32666     pub(crate) fn as_u32(&self) -> u32 {
667         match self {
668             FpuOPWidth::S => 0b00,
669             FpuOPWidth::D => 0b01,
670             FpuOPWidth::H => 0b10,
671             FpuOPWidth::Q => 0b11,
672         }
673     }
674 }
675 
676 impl AluOPRRR {
op_name(self) -> &'static str677     pub(crate) const fn op_name(self) -> &'static str {
678         match self {
679             Self::Add => "add",
680             Self::Sub => "sub",
681             Self::Sll => "sll",
682             Self::Slt => "slt",
683             Self::Sgt => "sgt",
684             Self::SltU => "sltu",
685             Self::Sgtu => "sgtu",
686             Self::Xor => "xor",
687             Self::Srl => "srl",
688             Self::Sra => "sra",
689             Self::Or => "or",
690             Self::And => "and",
691             Self::Addw => "addw",
692             Self::Subw => "subw",
693             Self::Sllw => "sllw",
694             Self::Srlw => "srlw",
695             Self::Sraw => "sraw",
696             Self::Mul => "mul",
697             Self::Mulh => "mulh",
698             Self::Mulhsu => "mulhsu",
699             Self::Mulhu => "mulhu",
700             Self::Div => "div",
701             Self::DivU => "divu",
702             Self::Rem => "rem",
703             Self::RemU => "remu",
704             Self::Mulw => "mulw",
705             Self::Divw => "divw",
706             Self::Divuw => "divuw",
707             Self::Remw => "remw",
708             Self::Remuw => "remuw",
709             Self::Adduw => "add.uw",
710             Self::Andn => "andn",
711             Self::Bclr => "bclr",
712             Self::Bext => "bext",
713             Self::Binv => "binv",
714             Self::Bset => "bset",
715             Self::Clmul => "clmul",
716             Self::Clmulh => "clmulh",
717             Self::Clmulr => "clmulr",
718             Self::Max => "max",
719             Self::Maxu => "maxu",
720             Self::Min => "min",
721             Self::Minu => "minu",
722             Self::Orn => "orn",
723             Self::Rol => "rol",
724             Self::Rolw => "rolw",
725             Self::Ror => "ror",
726             Self::Rorw => "rorw",
727             Self::Sh1add => "sh1add",
728             Self::Sh1adduw => "sh1add.uw",
729             Self::Sh2add => "sh2add",
730             Self::Sh2adduw => "sh2add.uw",
731             Self::Sh3add => "sh3add",
732             Self::Sh3adduw => "sh3add.uw",
733             Self::Xnor => "xnor",
734             Self::Pack => "pack",
735             Self::Packw => "packw",
736             Self::Packh => "packh",
737             Self::CzeroEqz => "czero.eqz",
738             Self::CzeroNez => "czero.nez",
739         }
740     }
741 
funct3(self) -> u32742     pub fn funct3(self) -> u32 {
743         match self {
744             AluOPRRR::Add => 0b000,
745             AluOPRRR::Sll => 0b001,
746             AluOPRRR::Slt => 0b010,
747             AluOPRRR::Sgt => 0b010,
748             AluOPRRR::SltU => 0b011,
749             AluOPRRR::Sgtu => 0b011,
750             AluOPRRR::Xor => 0b100,
751             AluOPRRR::Srl => 0b101,
752             AluOPRRR::Sra => 0b101,
753             AluOPRRR::Or => 0b110,
754             AluOPRRR::And => 0b111,
755             AluOPRRR::Sub => 0b000,
756 
757             AluOPRRR::Addw => 0b000,
758             AluOPRRR::Subw => 0b000,
759             AluOPRRR::Sllw => 0b001,
760             AluOPRRR::Srlw => 0b101,
761             AluOPRRR::Sraw => 0b101,
762 
763             AluOPRRR::Mul => 0b000,
764             AluOPRRR::Mulh => 0b001,
765             AluOPRRR::Mulhsu => 0b010,
766             AluOPRRR::Mulhu => 0b011,
767             AluOPRRR::Div => 0b100,
768             AluOPRRR::DivU => 0b101,
769             AluOPRRR::Rem => 0b110,
770             AluOPRRR::RemU => 0b111,
771 
772             AluOPRRR::Mulw => 0b000,
773             AluOPRRR::Divw => 0b100,
774             AluOPRRR::Divuw => 0b101,
775             AluOPRRR::Remw => 0b110,
776             AluOPRRR::Remuw => 0b111,
777 
778             // Zbb
779             AluOPRRR::Adduw => 0b000,
780             AluOPRRR::Andn => 0b111,
781             AluOPRRR::Bclr => 0b001,
782             AluOPRRR::Bext => 0b101,
783             AluOPRRR::Binv => 0b001,
784             AluOPRRR::Bset => 0b001,
785             AluOPRRR::Clmul => 0b001,
786             AluOPRRR::Clmulh => 0b011,
787             AluOPRRR::Clmulr => 0b010,
788             AluOPRRR::Max => 0b110,
789             AluOPRRR::Maxu => 0b111,
790             AluOPRRR::Min => 0b100,
791             AluOPRRR::Minu => 0b101,
792             AluOPRRR::Orn => 0b110,
793             AluOPRRR::Rol => 0b001,
794             AluOPRRR::Rolw => 0b001,
795             AluOPRRR::Ror => 0b101,
796             AluOPRRR::Rorw => 0b101,
797             AluOPRRR::Sh1add => 0b010,
798             AluOPRRR::Sh1adduw => 0b010,
799             AluOPRRR::Sh2add => 0b100,
800             AluOPRRR::Sh2adduw => 0b100,
801             AluOPRRR::Sh3add => 0b110,
802             AluOPRRR::Sh3adduw => 0b110,
803             AluOPRRR::Xnor => 0b100,
804 
805             // Zbkb
806             AluOPRRR::Pack => 0b100,
807             AluOPRRR::Packw => 0b100,
808             AluOPRRR::Packh => 0b111,
809 
810             // ZiCond
811             AluOPRRR::CzeroEqz => 0b101,
812             AluOPRRR::CzeroNez => 0b111,
813         }
814     }
815 
op_code(self) -> u32816     pub fn op_code(self) -> u32 {
817         match self {
818             AluOPRRR::Add
819             | AluOPRRR::Sub
820             | AluOPRRR::Sll
821             | AluOPRRR::Slt
822             | AluOPRRR::Sgt
823             | AluOPRRR::SltU
824             | AluOPRRR::Sgtu
825             | AluOPRRR::Xor
826             | AluOPRRR::Srl
827             | AluOPRRR::Sra
828             | AluOPRRR::Or
829             | AluOPRRR::And
830             | AluOPRRR::Pack
831             | AluOPRRR::Packh => 0b0110011,
832 
833             AluOPRRR::Addw
834             | AluOPRRR::Subw
835             | AluOPRRR::Sllw
836             | AluOPRRR::Srlw
837             | AluOPRRR::Sraw
838             | AluOPRRR::Packw => 0b0111011,
839 
840             AluOPRRR::Mul
841             | AluOPRRR::Mulh
842             | AluOPRRR::Mulhsu
843             | AluOPRRR::Mulhu
844             | AluOPRRR::Div
845             | AluOPRRR::DivU
846             | AluOPRRR::Rem
847             | AluOPRRR::RemU => 0b0110011,
848 
849             AluOPRRR::Mulw
850             | AluOPRRR::Divw
851             | AluOPRRR::Divuw
852             | AluOPRRR::Remw
853             | AluOPRRR::Remuw => 0b0111011,
854 
855             AluOPRRR::Adduw => 0b0111011,
856             AluOPRRR::Andn
857             | AluOPRRR::Bclr
858             | AluOPRRR::Bext
859             | AluOPRRR::Binv
860             | AluOPRRR::Bset
861             | AluOPRRR::Clmul
862             | AluOPRRR::Clmulh
863             | AluOPRRR::Clmulr
864             | AluOPRRR::Max
865             | AluOPRRR::Maxu
866             | AluOPRRR::Min
867             | AluOPRRR::Minu
868             | AluOPRRR::Orn
869             | AluOPRRR::Rol
870             | AluOPRRR::Ror
871             | AluOPRRR::Sh1add
872             | AluOPRRR::Sh2add
873             | AluOPRRR::Sh3add
874             | AluOPRRR::Xnor
875             | AluOPRRR::CzeroEqz
876             | AluOPRRR::CzeroNez => 0b0110011,
877 
878             AluOPRRR::Rolw
879             | AluOPRRR::Rorw
880             | AluOPRRR::Sh2adduw
881             | AluOPRRR::Sh3adduw
882             | AluOPRRR::Sh1adduw => 0b0111011,
883         }
884     }
885 
funct7(self) -> u32886     pub const fn funct7(self) -> u32 {
887         match self {
888             AluOPRRR::Add => 0b0000000,
889             AluOPRRR::Sub => 0b0100000,
890             AluOPRRR::Sll => 0b0000000,
891             AluOPRRR::Slt => 0b0000000,
892             AluOPRRR::Sgt => 0b0000000,
893             AluOPRRR::SltU => 0b0000000,
894             AluOPRRR::Sgtu => 0b0000000,
895 
896             AluOPRRR::Xor => 0b0000000,
897             AluOPRRR::Srl => 0b0000000,
898             AluOPRRR::Sra => 0b0100000,
899             AluOPRRR::Or => 0b0000000,
900             AluOPRRR::And => 0b0000000,
901 
902             AluOPRRR::Addw => 0b0000000,
903             AluOPRRR::Subw => 0b0100000,
904             AluOPRRR::Sllw => 0b0000000,
905             AluOPRRR::Srlw => 0b0000000,
906             AluOPRRR::Sraw => 0b0100000,
907 
908             AluOPRRR::Mul => 0b0000001,
909             AluOPRRR::Mulh => 0b0000001,
910             AluOPRRR::Mulhsu => 0b0000001,
911             AluOPRRR::Mulhu => 0b0000001,
912             AluOPRRR::Div => 0b0000001,
913             AluOPRRR::DivU => 0b0000001,
914             AluOPRRR::Rem => 0b0000001,
915             AluOPRRR::RemU => 0b0000001,
916 
917             AluOPRRR::Mulw => 0b0000001,
918             AluOPRRR::Divw => 0b0000001,
919             AluOPRRR::Divuw => 0b0000001,
920             AluOPRRR::Remw => 0b0000001,
921             AluOPRRR::Remuw => 0b0000001,
922             AluOPRRR::Adduw => 0b0000100,
923             AluOPRRR::Andn => 0b0100000,
924             AluOPRRR::Bclr => 0b0100100,
925             AluOPRRR::Bext => 0b0100100,
926             AluOPRRR::Binv => 0b0110100,
927             AluOPRRR::Bset => 0b0010100,
928             AluOPRRR::Clmul => 0b0000101,
929             AluOPRRR::Clmulh => 0b0000101,
930             AluOPRRR::Clmulr => 0b0000101,
931             AluOPRRR::Max => 0b0000101,
932             AluOPRRR::Maxu => 0b0000101,
933             AluOPRRR::Min => 0b0000101,
934             AluOPRRR::Minu => 0b0000101,
935             AluOPRRR::Orn => 0b0100000,
936             AluOPRRR::Rol => 0b0110000,
937             AluOPRRR::Rolw => 0b0110000,
938             AluOPRRR::Ror => 0b0110000,
939             AluOPRRR::Rorw => 0b0110000,
940             AluOPRRR::Sh1add => 0b0010000,
941             AluOPRRR::Sh1adduw => 0b0010000,
942             AluOPRRR::Sh2add => 0b0010000,
943             AluOPRRR::Sh2adduw => 0b0010000,
944             AluOPRRR::Sh3add => 0b0010000,
945             AluOPRRR::Sh3adduw => 0b0010000,
946             AluOPRRR::Xnor => 0b0100000,
947 
948             // Zbkb
949             AluOPRRR::Pack => 0b0000100,
950             AluOPRRR::Packw => 0b0000100,
951             AluOPRRR::Packh => 0b0000100,
952 
953             // ZiCond
954             AluOPRRR::CzeroEqz => 0b0000111,
955             AluOPRRR::CzeroNez => 0b0000111,
956         }
957     }
958 
reverse_rs(self) -> bool959     pub(crate) fn reverse_rs(self) -> bool {
960         // special case.
961         // sgt and sgtu is not defined in isa.
962         // emit should reverse rs1 and rs2.
963         self == AluOPRRR::Sgt || self == AluOPRRR::Sgtu
964     }
965 }
966 
967 impl AluOPRRI {
option_funct6(self) -> Option<u32>968     pub(crate) fn option_funct6(self) -> Option<u32> {
969         let x: Option<u32> = match self {
970             Self::Slli => Some(0b00_0000),
971             Self::Srli => Some(0b00_0000),
972             Self::Srai => Some(0b01_0000),
973             Self::Bclri => Some(0b010010),
974             Self::Bexti => Some(0b010010),
975             Self::Binvi => Some(0b011010),
976             Self::Bseti => Some(0b001010),
977             Self::Rori => Some(0b011000),
978             Self::SlliUw => Some(0b000010),
979             _ => None,
980         };
981         x
982     }
983 
option_funct7(self) -> Option<u32>984     pub(crate) fn option_funct7(self) -> Option<u32> {
985         let x = match self {
986             Self::Slliw => Some(0b000_0000),
987             Self::SrliW => Some(0b000_0000),
988             Self::Sraiw => Some(0b010_0000),
989             Self::Roriw => Some(0b0110000),
990             _ => None,
991         };
992         x
993     }
994 
imm12(self, imm12: Imm12) -> u32995     pub(crate) fn imm12(self, imm12: Imm12) -> u32 {
996         let x = imm12.bits();
997         if let Some(func) = self.option_funct6() {
998             func << 6 | (x & 0b11_1111)
999         } else if let Some(func) = self.option_funct7() {
1000             func << 5 | (x & 0b1_1111)
1001         } else if let Some(func) = self.option_funct12() {
1002             func
1003         } else {
1004             x
1005         }
1006     }
1007 
option_funct12(self) -> Option<u32>1008     pub(crate) fn option_funct12(self) -> Option<u32> {
1009         match self {
1010             Self::Clz => Some(0b011000000000),
1011             Self::Clzw => Some(0b011000000000),
1012             Self::Cpop => Some(0b011000000010),
1013             Self::Cpopw => Some(0b011000000010),
1014             Self::Ctz => Some(0b011000000001),
1015             Self::Ctzw => Some(0b011000000001),
1016             Self::Rev8 => Some(0b011010111000),
1017             Self::Sextb => Some(0b011000000100),
1018             Self::Sexth => Some(0b011000000101),
1019             Self::Zexth => Some(0b000010000000),
1020             Self::Orcb => Some(0b001010000111),
1021             Self::Brev8 => Some(0b0110_1000_0111),
1022             _ => None,
1023         }
1024     }
1025 
op_name(self) -> &'static str1026     pub(crate) fn op_name(self) -> &'static str {
1027         match self {
1028             Self::Addi => "addi",
1029             Self::Slti => "slti",
1030             Self::SltiU => "sltiu",
1031             Self::Xori => "xori",
1032             Self::Ori => "ori",
1033             Self::Andi => "andi",
1034             Self::Slli => "slli",
1035             Self::Srli => "srli",
1036             Self::Srai => "srai",
1037             Self::Addiw => "addiw",
1038             Self::Slliw => "slliw",
1039             Self::SrliW => "srliw",
1040             Self::Sraiw => "sraiw",
1041             Self::Bclri => "bclri",
1042             Self::Bexti => "bexti",
1043             Self::Binvi => "binvi",
1044             Self::Bseti => "bseti",
1045             Self::Rori => "rori",
1046             Self::Roriw => "roriw",
1047             Self::SlliUw => "slli.uw",
1048             Self::Clz => "clz",
1049             Self::Clzw => "clzw",
1050             Self::Cpop => "cpop",
1051             Self::Cpopw => "cpopw",
1052             Self::Ctz => "ctz",
1053             Self::Ctzw => "ctzw",
1054             Self::Rev8 => "rev8",
1055             Self::Sextb => "sext.b",
1056             Self::Sexth => "sext.h",
1057             Self::Zexth => "zext.h",
1058             Self::Orcb => "orc.b",
1059             Self::Brev8 => "brev8",
1060         }
1061     }
1062 
funct3(self) -> u321063     pub fn funct3(self) -> u32 {
1064         match self {
1065             AluOPRRI::Addi => 0b000,
1066             AluOPRRI::Slti => 0b010,
1067             AluOPRRI::SltiU => 0b011,
1068             AluOPRRI::Xori => 0b100,
1069             AluOPRRI::Ori => 0b110,
1070             AluOPRRI::Andi => 0b111,
1071             AluOPRRI::Slli => 0b001,
1072             AluOPRRI::Srli => 0b101,
1073             AluOPRRI::Srai => 0b101,
1074             AluOPRRI::Addiw => 0b000,
1075             AluOPRRI::Slliw => 0b001,
1076             AluOPRRI::SrliW => 0b101,
1077             AluOPRRI::Sraiw => 0b101,
1078             AluOPRRI::Bclri => 0b001,
1079             AluOPRRI::Bexti => 0b101,
1080             AluOPRRI::Binvi => 0b001,
1081             AluOPRRI::Bseti => 0b001,
1082             AluOPRRI::Rori => 0b101,
1083             AluOPRRI::Roriw => 0b101,
1084             AluOPRRI::SlliUw => 0b001,
1085             AluOPRRI::Clz => 0b001,
1086             AluOPRRI::Clzw => 0b001,
1087             AluOPRRI::Cpop => 0b001,
1088             AluOPRRI::Cpopw => 0b001,
1089             AluOPRRI::Ctz => 0b001,
1090             AluOPRRI::Ctzw => 0b001,
1091             AluOPRRI::Rev8 => 0b101,
1092             AluOPRRI::Sextb => 0b001,
1093             AluOPRRI::Sexth => 0b001,
1094             AluOPRRI::Zexth => 0b100,
1095             AluOPRRI::Orcb => 0b101,
1096             AluOPRRI::Brev8 => 0b101,
1097         }
1098     }
1099 
op_code(self) -> u321100     pub fn op_code(self) -> u32 {
1101         match self {
1102             AluOPRRI::Addi
1103             | AluOPRRI::Slti
1104             | AluOPRRI::SltiU
1105             | AluOPRRI::Xori
1106             | AluOPRRI::Ori
1107             | AluOPRRI::Andi
1108             | AluOPRRI::Slli
1109             | AluOPRRI::Srli
1110             | AluOPRRI::Srai
1111             | AluOPRRI::Bclri
1112             | AluOPRRI::Bexti
1113             | AluOPRRI::Binvi
1114             | AluOPRRI::Bseti
1115             | AluOPRRI::Rori
1116             | AluOPRRI::Clz
1117             | AluOPRRI::Cpop
1118             | AluOPRRI::Ctz
1119             | AluOPRRI::Rev8
1120             | AluOPRRI::Sextb
1121             | AluOPRRI::Sexth
1122             | AluOPRRI::Orcb
1123             | AluOPRRI::Brev8 => 0b0010011,
1124 
1125             AluOPRRI::Addiw
1126             | AluOPRRI::Slliw
1127             | AluOPRRI::SrliW
1128             | AluOPRRI::Sraiw
1129             | AluOPRRI::Roriw
1130             | AluOPRRI::SlliUw
1131             | AluOPRRI::Clzw
1132             | AluOPRRI::Cpopw
1133             | AluOPRRI::Ctzw => 0b0011011,
1134             AluOPRRI::Zexth => 0b0111011,
1135         }
1136     }
1137 }
1138 
1139 impl Default for FRM {
default() -> Self1140     fn default() -> Self {
1141         Self::Fcsr
1142     }
1143 }
1144 
1145 /// float rounding mode.
1146 impl FRM {
to_static_str(self) -> &'static str1147     pub(crate) fn to_static_str(self) -> &'static str {
1148         match self {
1149             FRM::RNE => "rne",
1150             FRM::RTZ => "rtz",
1151             FRM::RDN => "rdn",
1152             FRM::RUP => "rup",
1153             FRM::RMM => "rmm",
1154             FRM::Fcsr => "fcsr",
1155         }
1156     }
1157 
1158     #[inline]
bits(self) -> u81159     pub(crate) fn bits(self) -> u8 {
1160         match self {
1161             FRM::RNE => 0b000,
1162             FRM::RTZ => 0b001,
1163             FRM::RDN => 0b010,
1164             FRM::RUP => 0b011,
1165             FRM::RMM => 0b100,
1166             FRM::Fcsr => 0b111,
1167         }
1168     }
as_u32(self) -> u321169     pub(crate) fn as_u32(self) -> u32 {
1170         self.bits() as u32
1171     }
1172 }
1173 
1174 impl FFlagsException {
1175     #[inline]
1176     #[expect(dead_code, reason = "here for future use")]
mask(self) -> u321177     pub(crate) fn mask(self) -> u32 {
1178         match self {
1179             FFlagsException::NV => 1 << 4,
1180             FFlagsException::DZ => 1 << 3,
1181             FFlagsException::OF => 1 << 2,
1182             FFlagsException::UF => 1 << 1,
1183             FFlagsException::NX => 1 << 0,
1184         }
1185     }
1186 }
1187 
1188 impl LoadOP {
op_name(self) -> &'static str1189     pub(crate) fn op_name(self) -> &'static str {
1190         match self {
1191             Self::Lb => "lb",
1192             Self::Lh => "lh",
1193             Self::Lw => "lw",
1194             Self::Lbu => "lbu",
1195             Self::Lhu => "lhu",
1196             Self::Lwu => "lwu",
1197             Self::Ld => "ld",
1198             Self::Flh => "flh",
1199             Self::Flw => "flw",
1200             Self::Fld => "fld",
1201         }
1202     }
1203 
from_type(ty: Type) -> Self1204     pub(crate) fn from_type(ty: Type) -> Self {
1205         match ty {
1206             F16 => Self::Flh,
1207             F32 => Self::Flw,
1208             F64 => Self::Fld,
1209             I8 => Self::Lb,
1210             I16 => Self::Lh,
1211             I32 => Self::Lw,
1212             I64 => Self::Ld,
1213             _ => unreachable!(),
1214         }
1215     }
1216 
size(&self) -> i641217     pub(crate) fn size(&self) -> i64 {
1218         match self {
1219             Self::Lb | Self::Lbu => 1,
1220             Self::Lh | Self::Lhu | Self::Flh => 2,
1221             Self::Lw | Self::Lwu | Self::Flw => 4,
1222             Self::Ld | Self::Fld => 8,
1223         }
1224     }
1225 
op_code(self) -> u321226     pub(crate) fn op_code(self) -> u32 {
1227         match self {
1228             Self::Lb | Self::Lh | Self::Lw | Self::Lbu | Self::Lhu | Self::Lwu | Self::Ld => {
1229                 0b0000011
1230             }
1231             Self::Flh | Self::Flw | Self::Fld => 0b0000111,
1232         }
1233     }
funct3(self) -> u321234     pub(crate) fn funct3(self) -> u32 {
1235         match self {
1236             Self::Lb => 0b000,
1237             Self::Lh => 0b001,
1238             Self::Lw => 0b010,
1239             Self::Lwu => 0b110,
1240             Self::Lbu => 0b100,
1241             Self::Lhu => 0b101,
1242             Self::Ld => 0b011,
1243             Self::Flh => 0b001,
1244             Self::Flw => 0b010,
1245             Self::Fld => 0b011,
1246         }
1247     }
1248 }
1249 
1250 impl StoreOP {
op_name(self) -> &'static str1251     pub(crate) fn op_name(self) -> &'static str {
1252         match self {
1253             Self::Sb => "sb",
1254             Self::Sh => "sh",
1255             Self::Sw => "sw",
1256             Self::Sd => "sd",
1257             Self::Fsh => "fsh",
1258             Self::Fsw => "fsw",
1259             Self::Fsd => "fsd",
1260         }
1261     }
from_type(ty: Type) -> Self1262     pub(crate) fn from_type(ty: Type) -> Self {
1263         match ty {
1264             F16 => Self::Fsh,
1265             F32 => Self::Fsw,
1266             F64 => Self::Fsd,
1267             I8 => Self::Sb,
1268             I16 => Self::Sh,
1269             I32 => Self::Sw,
1270             I64 => Self::Sd,
1271             _ => unreachable!(),
1272         }
1273     }
1274 
size(&self) -> i641275     pub(crate) fn size(&self) -> i64 {
1276         match self {
1277             Self::Sb => 1,
1278             Self::Sh | Self::Fsh => 2,
1279             Self::Sw | Self::Fsw => 4,
1280             Self::Sd | Self::Fsd => 8,
1281         }
1282     }
1283 
op_code(self) -> u321284     pub(crate) fn op_code(self) -> u32 {
1285         match self {
1286             Self::Sb | Self::Sh | Self::Sw | Self::Sd => 0b0100011,
1287             Self::Fsh | Self::Fsw | Self::Fsd => 0b0100111,
1288         }
1289     }
funct3(self) -> u321290     pub(crate) fn funct3(self) -> u32 {
1291         match self {
1292             Self::Sb => 0b000,
1293             Self::Sh => 0b001,
1294             Self::Sw => 0b010,
1295             Self::Sd => 0b011,
1296             Self::Fsh => 0b001,
1297             Self::Fsw => 0b010,
1298             Self::Fsd => 0b011,
1299         }
1300     }
1301 }
1302 
1303 impl FClassResult {
bit(self) -> u321304     pub(crate) const fn bit(self) -> u32 {
1305         match self {
1306             FClassResult::NegInfinite => 1 << 0,
1307             FClassResult::NegNormal => 1 << 1,
1308             FClassResult::NegSubNormal => 1 << 2,
1309             FClassResult::NegZero => 1 << 3,
1310             FClassResult::PosZero => 1 << 4,
1311             FClassResult::PosSubNormal => 1 << 5,
1312             FClassResult::PosNormal => 1 << 6,
1313             FClassResult::PosInfinite => 1 << 7,
1314             FClassResult::SNaN => 1 << 8,
1315             FClassResult::QNaN => 1 << 9,
1316         }
1317     }
1318 
1319     #[inline]
1320     #[expect(dead_code, reason = "here for future use")]
is_nan_bits() -> u321321     pub(crate) const fn is_nan_bits() -> u32 {
1322         Self::SNaN.bit() | Self::QNaN.bit()
1323     }
1324     #[inline]
1325     #[expect(dead_code, reason = "here for future use")]
is_zero_bits() -> u321326     pub(crate) fn is_zero_bits() -> u32 {
1327         Self::NegZero.bit() | Self::PosZero.bit()
1328     }
1329 
1330     #[inline]
1331     #[expect(dead_code, reason = "here for future use")]
is_infinite_bits() -> u321332     pub(crate) fn is_infinite_bits() -> u32 {
1333         Self::PosInfinite.bit() | Self::NegInfinite.bit()
1334     }
1335 }
1336 
1337 impl AtomicOP {
1338     #[inline]
is_load(self) -> bool1339     pub(crate) fn is_load(self) -> bool {
1340         match self {
1341             Self::LrW | Self::LrD => true,
1342             _ => false,
1343         }
1344     }
1345 
1346     #[inline]
op_name(self, amo: AMO) -> String1347     pub(crate) fn op_name(self, amo: AMO) -> String {
1348         let s = match self {
1349             Self::LrW => "lr.w",
1350             Self::ScW => "sc.w",
1351 
1352             Self::AmoswapW => "amoswap.w",
1353             Self::AmoaddW => "amoadd.w",
1354             Self::AmoxorW => "amoxor.w",
1355             Self::AmoandW => "amoand.w",
1356             Self::AmoorW => "amoor.w",
1357             Self::AmominW => "amomin.w",
1358             Self::AmomaxW => "amomax.w",
1359             Self::AmominuW => "amominu.w",
1360             Self::AmomaxuW => "amomaxu.w",
1361             Self::LrD => "lr.d",
1362             Self::ScD => "sc.d",
1363             Self::AmoswapD => "amoswap.d",
1364             Self::AmoaddD => "amoadd.d",
1365             Self::AmoxorD => "amoxor.d",
1366             Self::AmoandD => "amoand.d",
1367             Self::AmoorD => "amoor.d",
1368             Self::AmominD => "amomin.d",
1369             Self::AmomaxD => "amomax.d",
1370             Self::AmominuD => "amominu.d",
1371             Self::AmomaxuD => "amomaxu.d",
1372         };
1373         format!("{}{}", s, amo.to_static_str())
1374     }
1375     #[inline]
op_code(self) -> u321376     pub(crate) fn op_code(self) -> u32 {
1377         0b0101111
1378     }
1379 
1380     #[inline]
funct7(self, amo: AMO) -> u321381     pub(crate) fn funct7(self, amo: AMO) -> u32 {
1382         self.funct5() << 2 | amo.as_u32() & 0b11
1383     }
1384 
funct3(self) -> u321385     pub(crate) fn funct3(self) -> u32 {
1386         match self {
1387             AtomicOP::LrW
1388             | AtomicOP::ScW
1389             | AtomicOP::AmoswapW
1390             | AtomicOP::AmoaddW
1391             | AtomicOP::AmoxorW
1392             | AtomicOP::AmoandW
1393             | AtomicOP::AmoorW
1394             | AtomicOP::AmominW
1395             | AtomicOP::AmomaxW
1396             | AtomicOP::AmominuW
1397             | AtomicOP::AmomaxuW => 0b010,
1398             AtomicOP::LrD
1399             | AtomicOP::ScD
1400             | AtomicOP::AmoswapD
1401             | AtomicOP::AmoaddD
1402             | AtomicOP::AmoxorD
1403             | AtomicOP::AmoandD
1404             | AtomicOP::AmoorD
1405             | AtomicOP::AmominD
1406             | AtomicOP::AmomaxD
1407             | AtomicOP::AmominuD
1408             | AtomicOP::AmomaxuD => 0b011,
1409         }
1410     }
funct5(self) -> u321411     pub(crate) fn funct5(self) -> u32 {
1412         match self {
1413             AtomicOP::LrW => 0b00010,
1414             AtomicOP::ScW => 0b00011,
1415             AtomicOP::AmoswapW => 0b00001,
1416             AtomicOP::AmoaddW => 0b00000,
1417             AtomicOP::AmoxorW => 0b00100,
1418             AtomicOP::AmoandW => 0b01100,
1419             AtomicOP::AmoorW => 0b01000,
1420             AtomicOP::AmominW => 0b10000,
1421             AtomicOP::AmomaxW => 0b10100,
1422             AtomicOP::AmominuW => 0b11000,
1423             AtomicOP::AmomaxuW => 0b11100,
1424             AtomicOP::LrD => 0b00010,
1425             AtomicOP::ScD => 0b00011,
1426             AtomicOP::AmoswapD => 0b00001,
1427             AtomicOP::AmoaddD => 0b00000,
1428             AtomicOP::AmoxorD => 0b00100,
1429             AtomicOP::AmoandD => 0b01100,
1430             AtomicOP::AmoorD => 0b01000,
1431             AtomicOP::AmominD => 0b10000,
1432             AtomicOP::AmomaxD => 0b10100,
1433             AtomicOP::AmominuD => 0b11000,
1434             AtomicOP::AmomaxuD => 0b11100,
1435         }
1436     }
1437 
load_op(t: Type) -> Self1438     pub(crate) fn load_op(t: Type) -> Self {
1439         if t.bits() <= 32 { Self::LrW } else { Self::LrD }
1440     }
store_op(t: Type) -> Self1441     pub(crate) fn store_op(t: Type) -> Self {
1442         if t.bits() <= 32 { Self::ScW } else { Self::ScD }
1443     }
1444 
1445     /// extract
extract(rd: WritableReg, offset: Reg, rs: Reg, ty: Type) -> SmallInstVec<Inst>1446     pub(crate) fn extract(rd: WritableReg, offset: Reg, rs: Reg, ty: Type) -> SmallInstVec<Inst> {
1447         let mut insts = SmallInstVec::new();
1448         insts.push(Inst::AluRRR {
1449             alu_op: AluOPRRR::Srl,
1450             rd,
1451             rs1: rs,
1452             rs2: offset,
1453         });
1454         //
1455         insts.push(Inst::Extend {
1456             rd,
1457             rn: rd.to_reg(),
1458             signed: false,
1459             from_bits: ty.bits() as u8,
1460             to_bits: 64,
1461         });
1462         insts
1463     }
1464 
1465     /// like extract but sign extend the value.
1466     /// suitable for smax,etc.
extract_sext( rd: WritableReg, offset: Reg, rs: Reg, ty: Type, ) -> SmallInstVec<Inst>1467     pub(crate) fn extract_sext(
1468         rd: WritableReg,
1469         offset: Reg,
1470         rs: Reg,
1471         ty: Type,
1472     ) -> SmallInstVec<Inst> {
1473         let mut insts = SmallInstVec::new();
1474         insts.push(Inst::AluRRR {
1475             alu_op: AluOPRRR::Srl,
1476             rd,
1477             rs1: rs,
1478             rs2: offset,
1479         });
1480         //
1481         insts.push(Inst::Extend {
1482             rd,
1483             rn: rd.to_reg(),
1484             signed: true,
1485             from_bits: ty.bits() as u8,
1486             to_bits: 64,
1487         });
1488         insts
1489     }
1490 
unset( rd: WritableReg, tmp: WritableReg, offset: Reg, ty: Type, ) -> SmallInstVec<Inst>1491     pub(crate) fn unset(
1492         rd: WritableReg,
1493         tmp: WritableReg,
1494         offset: Reg,
1495         ty: Type,
1496     ) -> SmallInstVec<Inst> {
1497         assert!(rd != tmp);
1498         let mut insts = SmallInstVec::new();
1499         insts.extend(Inst::load_int_mask(tmp, ty));
1500         insts.push(Inst::AluRRR {
1501             alu_op: AluOPRRR::Sll,
1502             rd: tmp,
1503             rs1: tmp.to_reg(),
1504             rs2: offset,
1505         });
1506         insts.push(Inst::construct_bit_not(tmp, tmp.to_reg()));
1507         insts.push(Inst::AluRRR {
1508             alu_op: AluOPRRR::And,
1509             rd,
1510             rs1: rd.to_reg(),
1511             rs2: tmp.to_reg(),
1512         });
1513         insts
1514     }
1515 
set( rd: WritableReg, tmp: WritableReg, offset: Reg, rs: Reg, ty: Type, ) -> SmallInstVec<Inst>1516     pub(crate) fn set(
1517         rd: WritableReg,
1518         tmp: WritableReg,
1519         offset: Reg,
1520         rs: Reg,
1521         ty: Type,
1522     ) -> SmallInstVec<Inst> {
1523         assert!(rd != tmp);
1524         let mut insts = SmallInstVec::new();
1525         // make rs into tmp.
1526         insts.push(Inst::Extend {
1527             rd: tmp,
1528             rn: rs,
1529             signed: false,
1530             from_bits: ty.bits() as u8,
1531             to_bits: 64,
1532         });
1533         insts.push(Inst::AluRRR {
1534             alu_op: AluOPRRR::Sll,
1535             rd: tmp,
1536             rs1: tmp.to_reg(),
1537             rs2: offset,
1538         });
1539         insts.push(Inst::AluRRR {
1540             alu_op: AluOPRRR::Or,
1541             rd,
1542             rs1: rd.to_reg(),
1543             rs2: tmp.to_reg(),
1544         });
1545         insts
1546     }
1547 
1548     /// Merge reset part of rs into rd.
1549     /// Call this function must make sure that other part of value is already in rd.
merge( rd: WritableReg, tmp: WritableReg, offset: Reg, rs: Reg, ty: Type, ) -> SmallInstVec<Inst>1550     pub(crate) fn merge(
1551         rd: WritableReg,
1552         tmp: WritableReg,
1553         offset: Reg,
1554         rs: Reg,
1555         ty: Type,
1556     ) -> SmallInstVec<Inst> {
1557         let mut insts = Self::unset(rd, tmp, offset, ty);
1558         insts.extend(Self::set(rd, tmp, offset, rs, ty));
1559         insts
1560     }
1561 }
1562 
1563 ///Atomic Memory ordering.
1564 #[derive(Copy, Clone, Debug)]
1565 pub enum AMO {
1566     #[allow(dead_code, reason = "used only in emit tests for now")]
1567     Relax = 0b00,
1568     #[allow(dead_code, reason = "used only in emit tests for now")]
1569     Release = 0b01,
1570     #[allow(dead_code, reason = "used only in emit tests for now")]
1571     Acquire = 0b10,
1572     SeqCst = 0b11,
1573 }
1574 
1575 impl AMO {
to_static_str(self) -> &'static str1576     pub(crate) fn to_static_str(self) -> &'static str {
1577         match self {
1578             AMO::Relax => "",
1579             AMO::Release => ".rl",
1580             AMO::Acquire => ".aq",
1581             AMO::SeqCst => ".aqrl",
1582         }
1583     }
as_u32(self) -> u321584     pub(crate) fn as_u32(self) -> u32 {
1585         self as u32
1586     }
1587 }
1588 
1589 impl Inst {
1590     /// fence request bits.
1591     pub(crate) const FENCE_REQ_I: u8 = 1 << 3;
1592     pub(crate) const FENCE_REQ_O: u8 = 1 << 2;
1593     pub(crate) const FENCE_REQ_R: u8 = 1 << 1;
1594     pub(crate) const FENCE_REQ_W: u8 = 1 << 0;
fence_req_to_string(x: u8) -> String1595     pub(crate) fn fence_req_to_string(x: u8) -> String {
1596         let mut s = String::default();
1597         if x & Self::FENCE_REQ_I != 0 {
1598             s.push_str("i");
1599         }
1600         if x & Self::FENCE_REQ_O != 0 {
1601             s.push_str("o");
1602         }
1603         if x & Self::FENCE_REQ_R != 0 {
1604             s.push_str("r");
1605         }
1606         if x & Self::FENCE_REQ_W != 0 {
1607             s.push_str("w");
1608         }
1609         s
1610     }
1611 }
1612 
1613 impl CsrRegOP {
funct3(self) -> u321614     pub(crate) fn funct3(self) -> u32 {
1615         match self {
1616             CsrRegOP::CsrRW => 0b001,
1617             CsrRegOP::CsrRS => 0b010,
1618             CsrRegOP::CsrRC => 0b011,
1619         }
1620     }
1621 
opcode(self) -> u321622     pub(crate) fn opcode(self) -> u32 {
1623         0b1110011
1624     }
1625 
name(self) -> &'static str1626     pub(crate) fn name(self) -> &'static str {
1627         match self {
1628             CsrRegOP::CsrRW => "csrrw",
1629             CsrRegOP::CsrRS => "csrrs",
1630             CsrRegOP::CsrRC => "csrrc",
1631         }
1632     }
1633 }
1634 
1635 impl Display for CsrRegOP {
fmt(&self, f: &mut Formatter<'_>) -> Result1636     fn fmt(&self, f: &mut Formatter<'_>) -> Result {
1637         write!(f, "{}", self.name())
1638     }
1639 }
1640 
1641 impl CsrImmOP {
funct3(self) -> u321642     pub(crate) fn funct3(self) -> u32 {
1643         match self {
1644             CsrImmOP::CsrRWI => 0b101,
1645             CsrImmOP::CsrRSI => 0b110,
1646             CsrImmOP::CsrRCI => 0b111,
1647         }
1648     }
1649 
opcode(self) -> u321650     pub(crate) fn opcode(self) -> u32 {
1651         0b1110011
1652     }
1653 
name(self) -> &'static str1654     pub(crate) fn name(self) -> &'static str {
1655         match self {
1656             CsrImmOP::CsrRWI => "csrrwi",
1657             CsrImmOP::CsrRSI => "csrrsi",
1658             CsrImmOP::CsrRCI => "csrrci",
1659         }
1660     }
1661 }
1662 
1663 impl Display for CsrImmOP {
fmt(&self, f: &mut Formatter<'_>) -> Result1664     fn fmt(&self, f: &mut Formatter<'_>) -> Result {
1665         write!(f, "{}", self.name())
1666     }
1667 }
1668 
1669 impl CSR {
bits(self) -> Imm121670     pub(crate) fn bits(self) -> Imm12 {
1671         Imm12::from_i16(match self {
1672             CSR::Frm => 0x0002,
1673         })
1674     }
1675 
name(self) -> &'static str1676     pub(crate) fn name(self) -> &'static str {
1677         match self {
1678             CSR::Frm => "frm",
1679         }
1680     }
1681 }
1682 
1683 impl Display for CSR {
fmt(&self, f: &mut Formatter<'_>) -> Result1684     fn fmt(&self, f: &mut Formatter<'_>) -> Result {
1685         write!(f, "{}", self.name())
1686     }
1687 }
1688 
1689 impl COpcodeSpace {
bits(&self) -> u321690     pub fn bits(&self) -> u32 {
1691         match self {
1692             COpcodeSpace::C0 => 0b00,
1693             COpcodeSpace::C1 => 0b01,
1694             COpcodeSpace::C2 => 0b10,
1695         }
1696     }
1697 }
1698 
1699 impl CrOp {
funct4(&self) -> u321700     pub fn funct4(&self) -> u32 {
1701         // https://five-embeddev.com/riscv-isa-manual/latest/rvc-opcode-map.html#rvcopcodemap
1702         match self {
1703             // `c.jr` has the same op/funct4 as C.MV, but RS2 is 0, which is illegal for mv.
1704             CrOp::CMv | CrOp::CJr => 0b1000,
1705             CrOp::CAdd | CrOp::CJalr | CrOp::CEbreak => 0b1001,
1706         }
1707     }
1708 
op(&self) -> COpcodeSpace1709     pub fn op(&self) -> COpcodeSpace {
1710         // https://five-embeddev.com/riscv-isa-manual/latest/rvc-opcode-map.html#rvcopcodemap
1711         match self {
1712             CrOp::CMv | CrOp::CAdd | CrOp::CJr | CrOp::CJalr | CrOp::CEbreak => COpcodeSpace::C2,
1713         }
1714     }
1715 }
1716 
1717 impl CaOp {
funct2(&self) -> u321718     pub fn funct2(&self) -> u32 {
1719         // https://github.com/michaeljclark/riscv-meta/blob/master/opcodes
1720         match self {
1721             CaOp::CAnd => 0b11,
1722             CaOp::COr => 0b10,
1723             CaOp::CXor => 0b01,
1724             CaOp::CSub => 0b00,
1725             CaOp::CAddw => 0b01,
1726             CaOp::CSubw => 0b00,
1727             CaOp::CMul => 0b10,
1728         }
1729     }
1730 
funct6(&self) -> u321731     pub fn funct6(&self) -> u32 {
1732         // https://github.com/michaeljclark/riscv-meta/blob/master/opcodes
1733         match self {
1734             CaOp::CAnd | CaOp::COr | CaOp::CXor | CaOp::CSub => 0b100_011,
1735             CaOp::CSubw | CaOp::CAddw | CaOp::CMul => 0b100_111,
1736         }
1737     }
1738 
op(&self) -> COpcodeSpace1739     pub fn op(&self) -> COpcodeSpace {
1740         // https://five-embeddev.com/riscv-isa-manual/latest/rvc-opcode-map.html#rvcopcodemap
1741         match self {
1742             CaOp::CAnd
1743             | CaOp::COr
1744             | CaOp::CXor
1745             | CaOp::CSub
1746             | CaOp::CAddw
1747             | CaOp::CSubw
1748             | CaOp::CMul => COpcodeSpace::C1,
1749         }
1750     }
1751 }
1752 
1753 impl CjOp {
funct3(&self) -> u321754     pub fn funct3(&self) -> u32 {
1755         // https://github.com/michaeljclark/riscv-meta/blob/master/opcodes
1756         match self {
1757             CjOp::CJ => 0b101,
1758         }
1759     }
1760 
op(&self) -> COpcodeSpace1761     pub fn op(&self) -> COpcodeSpace {
1762         // https://five-embeddev.com/riscv-isa-manual/latest/rvc-opcode-map.html#rvcopcodemap
1763         match self {
1764             CjOp::CJ => COpcodeSpace::C1,
1765         }
1766     }
1767 }
1768 
1769 impl CiOp {
funct3(&self) -> u321770     pub fn funct3(&self) -> u32 {
1771         // https://github.com/michaeljclark/riscv-meta/blob/master/opcodes
1772         match self {
1773             CiOp::CAddi | CiOp::CSlli => 0b000,
1774             CiOp::CAddiw | CiOp::CFldsp => 0b001,
1775             CiOp::CLi | CiOp::CLwsp => 0b010,
1776             CiOp::CAddi16sp | CiOp::CLui | CiOp::CLdsp => 0b011,
1777         }
1778     }
1779 
op(&self) -> COpcodeSpace1780     pub fn op(&self) -> COpcodeSpace {
1781         // https://five-embeddev.com/riscv-isa-manual/latest/rvc-opcode-map.html#rvcopcodemap
1782         match self {
1783             CiOp::CAddi | CiOp::CAddiw | CiOp::CAddi16sp | CiOp::CLi | CiOp::CLui => {
1784                 COpcodeSpace::C1
1785             }
1786             CiOp::CSlli | CiOp::CLwsp | CiOp::CLdsp | CiOp::CFldsp => COpcodeSpace::C2,
1787         }
1788     }
1789 }
1790 
1791 impl CiwOp {
funct3(&self) -> u321792     pub fn funct3(&self) -> u32 {
1793         // https://github.com/michaeljclark/riscv-meta/blob/master/opcodes
1794         match self {
1795             CiwOp::CAddi4spn => 0b000,
1796         }
1797     }
1798 
op(&self) -> COpcodeSpace1799     pub fn op(&self) -> COpcodeSpace {
1800         // https://five-embeddev.com/riscv-isa-manual/latest/rvc-opcode-map.html#rvcopcodemap
1801         match self {
1802             CiwOp::CAddi4spn => COpcodeSpace::C0,
1803         }
1804     }
1805 }
1806 
1807 impl CbOp {
funct3(&self) -> u321808     pub fn funct3(&self) -> u32 {
1809         // https://github.com/michaeljclark/riscv-meta/blob/master/opcodes
1810         match self {
1811             CbOp::CSrli | CbOp::CSrai | CbOp::CAndi => 0b100,
1812         }
1813     }
1814 
funct2(&self) -> u321815     pub fn funct2(&self) -> u32 {
1816         // https://github.com/michaeljclark/riscv-meta/blob/master/opcodes
1817         match self {
1818             CbOp::CSrli => 0b00,
1819             CbOp::CSrai => 0b01,
1820             CbOp::CAndi => 0b10,
1821         }
1822     }
1823 
op(&self) -> COpcodeSpace1824     pub fn op(&self) -> COpcodeSpace {
1825         // https://five-embeddev.com/riscv-isa-manual/latest/rvc-opcode-map.html#rvcopcodemap
1826         match self {
1827             CbOp::CSrli | CbOp::CSrai | CbOp::CAndi => COpcodeSpace::C1,
1828         }
1829     }
1830 }
1831 
1832 impl CssOp {
funct3(&self) -> u321833     pub fn funct3(&self) -> u32 {
1834         // https://github.com/michaeljclark/riscv-meta/blob/master/opcodes
1835         match self {
1836             CssOp::CFsdsp => 0b101,
1837             CssOp::CSwsp => 0b110,
1838             CssOp::CSdsp => 0b111,
1839         }
1840     }
1841 
op(&self) -> COpcodeSpace1842     pub fn op(&self) -> COpcodeSpace {
1843         // https://five-embeddev.com/riscv-isa-manual/latest/rvc-opcode-map.html#rvcopcodemap
1844         match self {
1845             CssOp::CSwsp | CssOp::CSdsp | CssOp::CFsdsp => COpcodeSpace::C2,
1846         }
1847     }
1848 }
1849 
1850 impl CsOp {
funct3(&self) -> u321851     pub fn funct3(&self) -> u32 {
1852         // https://github.com/michaeljclark/riscv-meta/blob/master/opcodes
1853         match self {
1854             CsOp::CFsd => 0b101,
1855             CsOp::CSw => 0b110,
1856             CsOp::CSd => 0b111,
1857         }
1858     }
1859 
op(&self) -> COpcodeSpace1860     pub fn op(&self) -> COpcodeSpace {
1861         // https://five-embeddev.com/riscv-isa-manual/latest/rvc-opcode-map.html#rvcopcodemap
1862         match self {
1863             CsOp::CSw | CsOp::CSd | CsOp::CFsd => COpcodeSpace::C0,
1864         }
1865     }
1866 }
1867 
1868 impl ClOp {
funct3(&self) -> u321869     pub fn funct3(&self) -> u32 {
1870         // https://github.com/michaeljclark/riscv-meta/blob/master/opcodes
1871         match self {
1872             ClOp::CFld => 0b001,
1873             ClOp::CLw => 0b010,
1874             ClOp::CLd => 0b011,
1875         }
1876     }
1877 
op(&self) -> COpcodeSpace1878     pub fn op(&self) -> COpcodeSpace {
1879         // https://five-embeddev.com/riscv-isa-manual/latest/rvc-opcode-map.html#rvcopcodemap
1880         match self {
1881             ClOp::CLw | ClOp::CLd | ClOp::CFld => COpcodeSpace::C0,
1882         }
1883     }
1884 }
1885 
1886 impl CsznOp {
funct6(&self) -> u321887     pub fn funct6(&self) -> u32 {
1888         // https://github.com/michaeljclark/riscv-meta/blob/master/opcodes
1889         match self {
1890             CsznOp::CNot
1891             | CsznOp::CZextw
1892             | CsznOp::CZextb
1893             | CsznOp::CZexth
1894             | CsznOp::CSextb
1895             | CsznOp::CSexth => 0b100_111,
1896         }
1897     }
1898 
funct5(&self) -> u321899     pub fn funct5(&self) -> u32 {
1900         // https://github.com/michaeljclark/riscv-meta/blob/master/opcodes
1901         match self {
1902             CsznOp::CNot => 0b11_101,
1903             CsznOp::CZextb => 0b11_000,
1904             CsznOp::CZexth => 0b11_010,
1905             CsznOp::CZextw => 0b11_100,
1906             CsznOp::CSextb => 0b11_001,
1907             CsznOp::CSexth => 0b11_011,
1908         }
1909     }
1910 
op(&self) -> COpcodeSpace1911     pub fn op(&self) -> COpcodeSpace {
1912         // https://five-embeddev.com/riscv-isa-manual/latest/rvc-opcode-map.html#rvcopcodemap
1913         match self {
1914             CsznOp::CNot
1915             | CsznOp::CZextb
1916             | CsznOp::CZexth
1917             | CsznOp::CZextw
1918             | CsznOp::CSextb
1919             | CsznOp::CSexth => COpcodeSpace::C1,
1920         }
1921     }
1922 }
1923 
1924 impl ZcbMemOp {
funct6(&self) -> u321925     pub fn funct6(&self) -> u32 {
1926         // https://github.com/michaeljclark/riscv-meta/blob/master/opcodes
1927         match self {
1928             ZcbMemOp::CLbu => 0b100_000,
1929             // These two opcodes are differentiated in the imm field of the instruction.
1930             ZcbMemOp::CLhu | ZcbMemOp::CLh => 0b100_001,
1931             ZcbMemOp::CSb => 0b100_010,
1932             ZcbMemOp::CSh => 0b100_011,
1933         }
1934     }
1935 
imm_bits(&self) -> u81936     pub fn imm_bits(&self) -> u8 {
1937         match self {
1938             ZcbMemOp::CLhu | ZcbMemOp::CLh | ZcbMemOp::CSh => 1,
1939             ZcbMemOp::CLbu | ZcbMemOp::CSb => 2,
1940         }
1941     }
1942 
op(&self) -> COpcodeSpace1943     pub fn op(&self) -> COpcodeSpace {
1944         // https://five-embeddev.com/riscv-isa-manual/latest/rvc-opcode-map.html#rvcopcodemap
1945         match self {
1946             ZcbMemOp::CLbu | ZcbMemOp::CLhu | ZcbMemOp::CLh | ZcbMemOp::CSb | ZcbMemOp::CSh => {
1947                 COpcodeSpace::C0
1948             }
1949         }
1950     }
1951 }
1952