Skip to main content

cranelift_codegen/isa/riscv64/inst/
args.rs

1//! Riscv64 ISA definitions: instruction arguments.
2
3use super::*;
4use crate::ir::condcodes::CondCode;
5
6use crate::isa::riscv64::lower::isle::generated_code::{
7    COpcodeSpace, CaOp, CbOp, CiOp, CiwOp, ClOp, CrOp, CsOp, CssOp, CsznOp, FpuOPWidth, ZcbMemOp,
8};
9use crate::machinst::isle::WritableReg;
10
11use 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).
15macro_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.
70newtype_of_reg!(XReg, WritableXReg, |reg| reg.class() == RegClass::Int);
71newtype_of_reg!(FReg, WritableFReg, |reg| reg.class() == RegClass::Float);
72newtype_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)]
76pub 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
109impl AMode {
110    /// Add the registers referenced by this AMode to `collector`.
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
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
135    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.
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
173impl Display for AMode {
174    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
201impl From<StackAMode> for AMode {
202    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)]
215pub struct IntegerCompare {
216    pub(crate) kind: IntCC,
217    pub(crate) rs1: Reg,
218    pub(crate) rs2: Reg,
219}
220
221pub(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
236impl BranchFunct3 {
237    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
249impl IntegerCompare {
250    pub(crate) fn op_code(self) -> u32 {
251        0b1100011
252    }
253
254    // funct3 and if need inverse the register
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]
274    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
289    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
303    pub(crate) fn inverse(self) -> Self {
304        Self {
305            kind: self.kind.complement(),
306            ..self
307        }
308    }
309
310    pub(crate) fn regs(&self) -> [Reg; 2] {
311        [self.rs1, self.rs2]
312    }
313}
314
315#[derive(Debug, Clone, Copy, PartialEq)]
316pub struct FliConstant(u8);
317
318impl FliConstant {
319    pub(crate) fn new(value: u8) -> Self {
320        debug_assert!(value <= 31, "Invalid FliConstant: {value}");
321        Self(value)
322    }
323
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 == libm::pow(2.0, -16.0) => Self::new(2),
371            (_, f) if f == libm::pow(2.0, -15.0) => Self::new(3),
372            (_, f) if f == libm::pow(2.0, -8.0) => Self::new(4),
373            (_, f) if f == libm::pow(2.0, -7.0) => 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
408    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
449    pub(crate) fn bits(self) -> u8 {
450        self.0
451    }
452}
453
454impl FpuOPRRRR {
455    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
464    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
474impl FpuOPRR {
475    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::FcvtSH => "fcvt.s.h".to_string(),
505            Self::FcvtHS => "fcvt.h.s".to_string(),
506            Self::FcvtSD => "fcvt.s.d".to_string(),
507            Self::FcvtDS => "fcvt.d.s".to_string(),
508            Self::FcvtDH => "fcvt.d.h".to_string(),
509            Self::FcvtHD => "fcvt.h.d".to_string(),
510        }
511    }
512
513    pub(crate) fn is_convert_to_int(self) -> bool {
514        match self {
515            Self::FcvtWFmt | Self::FcvtWuFmt | Self::FcvtLFmt | Self::FcvtLuFmt => true,
516            _ => false,
517        }
518    }
519
520    pub(crate) fn has_frm(self) -> bool {
521        match self {
522            FpuOPRR::FmvXFmt | FpuOPRR::FmvFmtX | FpuOPRR::Fclass => false,
523            _ => true,
524        }
525    }
526
527    pub(crate) fn opcode(self) -> u32 {
528        // OP-FP Major opcode
529        0b1010011
530    }
531
532    pub(crate) fn rs2(self) -> u32 {
533        match self {
534            Self::Fsqrt => 0b00000,
535            Self::Fround => 0b00100,
536            Self::Fclass => 0b00000,
537            Self::FcvtWFmt => 0b00000,
538            Self::FcvtWuFmt => 0b00001,
539            Self::FcvtLFmt => 0b00010,
540            Self::FcvtLuFmt => 0b00011,
541            Self::FcvtFmtW => 0b00000,
542            Self::FcvtFmtWu => 0b00001,
543            Self::FcvtFmtL => 0b00010,
544            Self::FcvtFmtLu => 0b00011,
545            Self::FmvXFmt => 0b00000,
546            Self::FmvFmtX => 0b00000,
547            Self::FcvtSH => 0b00010,
548            Self::FcvtHS => 0b00000,
549            Self::FcvtSD => 0b00001,
550            Self::FcvtDS => 0b00000,
551            Self::FcvtDH => 0b00010,
552            Self::FcvtHD => 0b00001,
553        }
554    }
555
556    pub(crate) fn funct5(self) -> u32 {
557        match self {
558            Self::Fsqrt => 0b01011,
559            Self::Fround => 0b01000,
560            Self::Fclass => 0b11100,
561            Self::FcvtWFmt => 0b11000,
562            Self::FcvtWuFmt => 0b11000,
563            Self::FcvtLFmt => 0b11000,
564            Self::FcvtLuFmt => 0b11000,
565            Self::FcvtFmtW => 0b11010,
566            Self::FcvtFmtWu => 0b11010,
567            Self::FcvtFmtL => 0b11010,
568            Self::FcvtFmtLu => 0b11010,
569            Self::FmvXFmt => 0b11100,
570            Self::FmvFmtX => 0b11110,
571            Self::FcvtSH
572            | Self::FcvtHS
573            | Self::FcvtSD
574            | Self::FcvtDS
575            | Self::FcvtDH
576            | Self::FcvtHD => 0b01000,
577        }
578    }
579
580    pub(crate) fn funct7(self, width: FpuOPWidth) -> u32 {
581        (self.funct5() << 2) | width.as_u32()
582    }
583}
584
585impl FpuOPRRR {
586    pub(crate) fn op_name(self, width: FpuOPWidth) -> String {
587        match self {
588            Self::Fadd => format!("fadd.{width}"),
589            Self::Fsub => format!("fsub.{width}"),
590            Self::Fmul => format!("fmul.{width}"),
591            Self::Fdiv => format!("fdiv.{width}"),
592            Self::Fsgnj => format!("fsgnj.{width}"),
593            Self::Fsgnjn => format!("fsgnjn.{width}"),
594            Self::Fsgnjx => format!("fsgnjx.{width}"),
595            Self::Fmin => format!("fmin.{width}"),
596            Self::Fmax => format!("fmax.{width}"),
597            Self::Feq => format!("feq.{width}"),
598            Self::Flt => format!("flt.{width}"),
599            Self::Fle => format!("fle.{width}"),
600            Self::Fminm => format!("fminm.{width}"),
601            Self::Fmaxm => format!("fmaxm.{width}"),
602        }
603    }
604
605    pub(crate) fn opcode(self) -> u32 {
606        // OP-FP Major opcode
607        0b1010011
608    }
609
610    pub(crate) const fn funct5(self) -> u32 {
611        match self {
612            Self::Fadd => 0b00000,
613            Self::Fsub => 0b00001,
614            Self::Fmul => 0b00010,
615            Self::Fdiv => 0b00011,
616            Self::Fsgnj => 0b00100,
617            Self::Fsgnjn => 0b00100,
618            Self::Fsgnjx => 0b00100,
619            Self::Fmin => 0b00101,
620            Self::Fmax => 0b00101,
621            Self::Feq => 0b10100,
622            Self::Flt => 0b10100,
623            Self::Fle => 0b10100,
624            Self::Fminm => 0b00101,
625            Self::Fmaxm => 0b00101,
626        }
627    }
628
629    pub(crate) fn funct7(self, width: FpuOPWidth) -> u32 {
630        (self.funct5() << 2) | width.as_u32()
631    }
632
633    pub(crate) fn has_frm(self) -> bool {
634        match self {
635            FpuOPRRR::Fsgnj
636            | FpuOPRRR::Fsgnjn
637            | FpuOPRRR::Fsgnjx
638            | FpuOPRRR::Fmin
639            | FpuOPRRR::Fmax
640            | FpuOPRRR::Feq
641            | FpuOPRRR::Flt
642            | FpuOPRRR::Fle => false,
643            _ => true,
644        }
645    }
646}
647
648impl Display for FpuOPWidth {
649    fn fmt(&self, f: &mut Formatter<'_>) -> Result {
650        write!(
651            f,
652            "{}",
653            match self {
654                FpuOPWidth::H => "h",
655                FpuOPWidth::S => "s",
656                FpuOPWidth::D => "d",
657                FpuOPWidth::Q => "q",
658            }
659        )
660    }
661}
662
663impl TryFrom<Type> for FpuOPWidth {
664    type Error = &'static str;
665
666    fn try_from(value: Type) -> core::result::Result<Self, Self::Error> {
667        match value {
668            F16 => Ok(FpuOPWidth::H),
669            F32 => Ok(FpuOPWidth::S),
670            F64 => Ok(FpuOPWidth::D),
671            F128 => Ok(FpuOPWidth::Q),
672            _ => Err("Invalid type for FpuOPWidth"),
673        }
674    }
675}
676
677impl FpuOPWidth {
678    pub(crate) fn as_u32(&self) -> u32 {
679        match self {
680            FpuOPWidth::S => 0b00,
681            FpuOPWidth::D => 0b01,
682            FpuOPWidth::H => 0b10,
683            FpuOPWidth::Q => 0b11,
684        }
685    }
686}
687
688impl AluOPRRR {
689    pub(crate) const fn op_name(self) -> &'static str {
690        match self {
691            Self::Add => "add",
692            Self::Sub => "sub",
693            Self::Sll => "sll",
694            Self::Slt => "slt",
695            Self::Sgt => "sgt",
696            Self::SltU => "sltu",
697            Self::Sgtu => "sgtu",
698            Self::Xor => "xor",
699            Self::Srl => "srl",
700            Self::Sra => "sra",
701            Self::Or => "or",
702            Self::And => "and",
703            Self::Addw => "addw",
704            Self::Subw => "subw",
705            Self::Sllw => "sllw",
706            Self::Srlw => "srlw",
707            Self::Sraw => "sraw",
708            Self::Mul => "mul",
709            Self::Mulh => "mulh",
710            Self::Mulhsu => "mulhsu",
711            Self::Mulhu => "mulhu",
712            Self::Div => "div",
713            Self::DivU => "divu",
714            Self::Rem => "rem",
715            Self::RemU => "remu",
716            Self::Mulw => "mulw",
717            Self::Divw => "divw",
718            Self::Divuw => "divuw",
719            Self::Remw => "remw",
720            Self::Remuw => "remuw",
721            Self::Adduw => "add.uw",
722            Self::Andn => "andn",
723            Self::Bclr => "bclr",
724            Self::Bext => "bext",
725            Self::Binv => "binv",
726            Self::Bset => "bset",
727            Self::Clmul => "clmul",
728            Self::Clmulh => "clmulh",
729            Self::Clmulr => "clmulr",
730            Self::Max => "max",
731            Self::Maxu => "maxu",
732            Self::Min => "min",
733            Self::Minu => "minu",
734            Self::Orn => "orn",
735            Self::Rol => "rol",
736            Self::Rolw => "rolw",
737            Self::Ror => "ror",
738            Self::Rorw => "rorw",
739            Self::Sh1add => "sh1add",
740            Self::Sh1adduw => "sh1add.uw",
741            Self::Sh2add => "sh2add",
742            Self::Sh2adduw => "sh2add.uw",
743            Self::Sh3add => "sh3add",
744            Self::Sh3adduw => "sh3add.uw",
745            Self::Xnor => "xnor",
746            Self::Pack => "pack",
747            Self::Packw => "packw",
748            Self::Packh => "packh",
749            Self::CzeroEqz => "czero.eqz",
750            Self::CzeroNez => "czero.nez",
751        }
752    }
753
754    pub fn funct3(self) -> u32 {
755        match self {
756            AluOPRRR::Add => 0b000,
757            AluOPRRR::Sll => 0b001,
758            AluOPRRR::Slt => 0b010,
759            AluOPRRR::Sgt => 0b010,
760            AluOPRRR::SltU => 0b011,
761            AluOPRRR::Sgtu => 0b011,
762            AluOPRRR::Xor => 0b100,
763            AluOPRRR::Srl => 0b101,
764            AluOPRRR::Sra => 0b101,
765            AluOPRRR::Or => 0b110,
766            AluOPRRR::And => 0b111,
767            AluOPRRR::Sub => 0b000,
768
769            AluOPRRR::Addw => 0b000,
770            AluOPRRR::Subw => 0b000,
771            AluOPRRR::Sllw => 0b001,
772            AluOPRRR::Srlw => 0b101,
773            AluOPRRR::Sraw => 0b101,
774
775            AluOPRRR::Mul => 0b000,
776            AluOPRRR::Mulh => 0b001,
777            AluOPRRR::Mulhsu => 0b010,
778            AluOPRRR::Mulhu => 0b011,
779            AluOPRRR::Div => 0b100,
780            AluOPRRR::DivU => 0b101,
781            AluOPRRR::Rem => 0b110,
782            AluOPRRR::RemU => 0b111,
783
784            AluOPRRR::Mulw => 0b000,
785            AluOPRRR::Divw => 0b100,
786            AluOPRRR::Divuw => 0b101,
787            AluOPRRR::Remw => 0b110,
788            AluOPRRR::Remuw => 0b111,
789
790            // Zbb
791            AluOPRRR::Adduw => 0b000,
792            AluOPRRR::Andn => 0b111,
793            AluOPRRR::Bclr => 0b001,
794            AluOPRRR::Bext => 0b101,
795            AluOPRRR::Binv => 0b001,
796            AluOPRRR::Bset => 0b001,
797            AluOPRRR::Clmul => 0b001,
798            AluOPRRR::Clmulh => 0b011,
799            AluOPRRR::Clmulr => 0b010,
800            AluOPRRR::Max => 0b110,
801            AluOPRRR::Maxu => 0b111,
802            AluOPRRR::Min => 0b100,
803            AluOPRRR::Minu => 0b101,
804            AluOPRRR::Orn => 0b110,
805            AluOPRRR::Rol => 0b001,
806            AluOPRRR::Rolw => 0b001,
807            AluOPRRR::Ror => 0b101,
808            AluOPRRR::Rorw => 0b101,
809            AluOPRRR::Sh1add => 0b010,
810            AluOPRRR::Sh1adduw => 0b010,
811            AluOPRRR::Sh2add => 0b100,
812            AluOPRRR::Sh2adduw => 0b100,
813            AluOPRRR::Sh3add => 0b110,
814            AluOPRRR::Sh3adduw => 0b110,
815            AluOPRRR::Xnor => 0b100,
816
817            // Zbkb
818            AluOPRRR::Pack => 0b100,
819            AluOPRRR::Packw => 0b100,
820            AluOPRRR::Packh => 0b111,
821
822            // ZiCond
823            AluOPRRR::CzeroEqz => 0b101,
824            AluOPRRR::CzeroNez => 0b111,
825        }
826    }
827
828    pub fn op_code(self) -> u32 {
829        match self {
830            AluOPRRR::Add
831            | AluOPRRR::Sub
832            | AluOPRRR::Sll
833            | AluOPRRR::Slt
834            | AluOPRRR::Sgt
835            | AluOPRRR::SltU
836            | AluOPRRR::Sgtu
837            | AluOPRRR::Xor
838            | AluOPRRR::Srl
839            | AluOPRRR::Sra
840            | AluOPRRR::Or
841            | AluOPRRR::And
842            | AluOPRRR::Pack
843            | AluOPRRR::Packh => 0b0110011,
844
845            AluOPRRR::Addw
846            | AluOPRRR::Subw
847            | AluOPRRR::Sllw
848            | AluOPRRR::Srlw
849            | AluOPRRR::Sraw
850            | AluOPRRR::Packw => 0b0111011,
851
852            AluOPRRR::Mul
853            | AluOPRRR::Mulh
854            | AluOPRRR::Mulhsu
855            | AluOPRRR::Mulhu
856            | AluOPRRR::Div
857            | AluOPRRR::DivU
858            | AluOPRRR::Rem
859            | AluOPRRR::RemU => 0b0110011,
860
861            AluOPRRR::Mulw
862            | AluOPRRR::Divw
863            | AluOPRRR::Divuw
864            | AluOPRRR::Remw
865            | AluOPRRR::Remuw => 0b0111011,
866
867            AluOPRRR::Adduw => 0b0111011,
868            AluOPRRR::Andn
869            | AluOPRRR::Bclr
870            | AluOPRRR::Bext
871            | AluOPRRR::Binv
872            | AluOPRRR::Bset
873            | AluOPRRR::Clmul
874            | AluOPRRR::Clmulh
875            | AluOPRRR::Clmulr
876            | AluOPRRR::Max
877            | AluOPRRR::Maxu
878            | AluOPRRR::Min
879            | AluOPRRR::Minu
880            | AluOPRRR::Orn
881            | AluOPRRR::Rol
882            | AluOPRRR::Ror
883            | AluOPRRR::Sh1add
884            | AluOPRRR::Sh2add
885            | AluOPRRR::Sh3add
886            | AluOPRRR::Xnor
887            | AluOPRRR::CzeroEqz
888            | AluOPRRR::CzeroNez => 0b0110011,
889
890            AluOPRRR::Rolw
891            | AluOPRRR::Rorw
892            | AluOPRRR::Sh2adduw
893            | AluOPRRR::Sh3adduw
894            | AluOPRRR::Sh1adduw => 0b0111011,
895        }
896    }
897
898    pub const fn funct7(self) -> u32 {
899        match self {
900            AluOPRRR::Add => 0b0000000,
901            AluOPRRR::Sub => 0b0100000,
902            AluOPRRR::Sll => 0b0000000,
903            AluOPRRR::Slt => 0b0000000,
904            AluOPRRR::Sgt => 0b0000000,
905            AluOPRRR::SltU => 0b0000000,
906            AluOPRRR::Sgtu => 0b0000000,
907
908            AluOPRRR::Xor => 0b0000000,
909            AluOPRRR::Srl => 0b0000000,
910            AluOPRRR::Sra => 0b0100000,
911            AluOPRRR::Or => 0b0000000,
912            AluOPRRR::And => 0b0000000,
913
914            AluOPRRR::Addw => 0b0000000,
915            AluOPRRR::Subw => 0b0100000,
916            AluOPRRR::Sllw => 0b0000000,
917            AluOPRRR::Srlw => 0b0000000,
918            AluOPRRR::Sraw => 0b0100000,
919
920            AluOPRRR::Mul => 0b0000001,
921            AluOPRRR::Mulh => 0b0000001,
922            AluOPRRR::Mulhsu => 0b0000001,
923            AluOPRRR::Mulhu => 0b0000001,
924            AluOPRRR::Div => 0b0000001,
925            AluOPRRR::DivU => 0b0000001,
926            AluOPRRR::Rem => 0b0000001,
927            AluOPRRR::RemU => 0b0000001,
928
929            AluOPRRR::Mulw => 0b0000001,
930            AluOPRRR::Divw => 0b0000001,
931            AluOPRRR::Divuw => 0b0000001,
932            AluOPRRR::Remw => 0b0000001,
933            AluOPRRR::Remuw => 0b0000001,
934            AluOPRRR::Adduw => 0b0000100,
935            AluOPRRR::Andn => 0b0100000,
936            AluOPRRR::Bclr => 0b0100100,
937            AluOPRRR::Bext => 0b0100100,
938            AluOPRRR::Binv => 0b0110100,
939            AluOPRRR::Bset => 0b0010100,
940            AluOPRRR::Clmul => 0b0000101,
941            AluOPRRR::Clmulh => 0b0000101,
942            AluOPRRR::Clmulr => 0b0000101,
943            AluOPRRR::Max => 0b0000101,
944            AluOPRRR::Maxu => 0b0000101,
945            AluOPRRR::Min => 0b0000101,
946            AluOPRRR::Minu => 0b0000101,
947            AluOPRRR::Orn => 0b0100000,
948            AluOPRRR::Rol => 0b0110000,
949            AluOPRRR::Rolw => 0b0110000,
950            AluOPRRR::Ror => 0b0110000,
951            AluOPRRR::Rorw => 0b0110000,
952            AluOPRRR::Sh1add => 0b0010000,
953            AluOPRRR::Sh1adduw => 0b0010000,
954            AluOPRRR::Sh2add => 0b0010000,
955            AluOPRRR::Sh2adduw => 0b0010000,
956            AluOPRRR::Sh3add => 0b0010000,
957            AluOPRRR::Sh3adduw => 0b0010000,
958            AluOPRRR::Xnor => 0b0100000,
959
960            // Zbkb
961            AluOPRRR::Pack => 0b0000100,
962            AluOPRRR::Packw => 0b0000100,
963            AluOPRRR::Packh => 0b0000100,
964
965            // ZiCond
966            AluOPRRR::CzeroEqz => 0b0000111,
967            AluOPRRR::CzeroNez => 0b0000111,
968        }
969    }
970
971    pub(crate) fn reverse_rs(self) -> bool {
972        // special case.
973        // sgt and sgtu is not defined in isa.
974        // emit should reverse rs1 and rs2.
975        self == AluOPRRR::Sgt || self == AluOPRRR::Sgtu
976    }
977}
978
979impl AluOPRRI {
980    pub(crate) fn option_funct6(self) -> Option<u32> {
981        let x: Option<u32> = match self {
982            Self::Slli => Some(0b00_0000),
983            Self::Srli => Some(0b00_0000),
984            Self::Srai => Some(0b01_0000),
985            Self::Bclri => Some(0b010010),
986            Self::Bexti => Some(0b010010),
987            Self::Binvi => Some(0b011010),
988            Self::Bseti => Some(0b001010),
989            Self::Rori => Some(0b011000),
990            Self::SlliUw => Some(0b000010),
991            _ => None,
992        };
993        x
994    }
995
996    pub(crate) fn option_funct7(self) -> Option<u32> {
997        let x = match self {
998            Self::Slliw => Some(0b000_0000),
999            Self::SrliW => Some(0b000_0000),
1000            Self::Sraiw => Some(0b010_0000),
1001            Self::Roriw => Some(0b0110000),
1002            _ => None,
1003        };
1004        x
1005    }
1006
1007    pub(crate) fn imm12(self, imm12: Imm12) -> u32 {
1008        let x = imm12.bits();
1009        if let Some(func) = self.option_funct6() {
1010            func << 6 | (x & 0b11_1111)
1011        } else if let Some(func) = self.option_funct7() {
1012            func << 5 | (x & 0b1_1111)
1013        } else if let Some(func) = self.option_funct12() {
1014            func
1015        } else {
1016            x
1017        }
1018    }
1019
1020    pub(crate) fn option_funct12(self) -> Option<u32> {
1021        match self {
1022            Self::Clz => Some(0b011000000000),
1023            Self::Clzw => Some(0b011000000000),
1024            Self::Cpop => Some(0b011000000010),
1025            Self::Cpopw => Some(0b011000000010),
1026            Self::Ctz => Some(0b011000000001),
1027            Self::Ctzw => Some(0b011000000001),
1028            Self::Rev8 => Some(0b011010111000),
1029            Self::Sextb => Some(0b011000000100),
1030            Self::Sexth => Some(0b011000000101),
1031            Self::Zexth => Some(0b000010000000),
1032            Self::Orcb => Some(0b001010000111),
1033            Self::Brev8 => Some(0b0110_1000_0111),
1034            _ => None,
1035        }
1036    }
1037
1038    pub(crate) fn op_name(self) -> &'static str {
1039        match self {
1040            Self::Addi => "addi",
1041            Self::Slti => "slti",
1042            Self::SltiU => "sltiu",
1043            Self::Xori => "xori",
1044            Self::Ori => "ori",
1045            Self::Andi => "andi",
1046            Self::Slli => "slli",
1047            Self::Srli => "srli",
1048            Self::Srai => "srai",
1049            Self::Addiw => "addiw",
1050            Self::Slliw => "slliw",
1051            Self::SrliW => "srliw",
1052            Self::Sraiw => "sraiw",
1053            Self::Bclri => "bclri",
1054            Self::Bexti => "bexti",
1055            Self::Binvi => "binvi",
1056            Self::Bseti => "bseti",
1057            Self::Rori => "rori",
1058            Self::Roriw => "roriw",
1059            Self::SlliUw => "slli.uw",
1060            Self::Clz => "clz",
1061            Self::Clzw => "clzw",
1062            Self::Cpop => "cpop",
1063            Self::Cpopw => "cpopw",
1064            Self::Ctz => "ctz",
1065            Self::Ctzw => "ctzw",
1066            Self::Rev8 => "rev8",
1067            Self::Sextb => "sext.b",
1068            Self::Sexth => "sext.h",
1069            Self::Zexth => "zext.h",
1070            Self::Orcb => "orc.b",
1071            Self::Brev8 => "brev8",
1072        }
1073    }
1074
1075    pub fn funct3(self) -> u32 {
1076        match self {
1077            AluOPRRI::Addi => 0b000,
1078            AluOPRRI::Slti => 0b010,
1079            AluOPRRI::SltiU => 0b011,
1080            AluOPRRI::Xori => 0b100,
1081            AluOPRRI::Ori => 0b110,
1082            AluOPRRI::Andi => 0b111,
1083            AluOPRRI::Slli => 0b001,
1084            AluOPRRI::Srli => 0b101,
1085            AluOPRRI::Srai => 0b101,
1086            AluOPRRI::Addiw => 0b000,
1087            AluOPRRI::Slliw => 0b001,
1088            AluOPRRI::SrliW => 0b101,
1089            AluOPRRI::Sraiw => 0b101,
1090            AluOPRRI::Bclri => 0b001,
1091            AluOPRRI::Bexti => 0b101,
1092            AluOPRRI::Binvi => 0b001,
1093            AluOPRRI::Bseti => 0b001,
1094            AluOPRRI::Rori => 0b101,
1095            AluOPRRI::Roriw => 0b101,
1096            AluOPRRI::SlliUw => 0b001,
1097            AluOPRRI::Clz => 0b001,
1098            AluOPRRI::Clzw => 0b001,
1099            AluOPRRI::Cpop => 0b001,
1100            AluOPRRI::Cpopw => 0b001,
1101            AluOPRRI::Ctz => 0b001,
1102            AluOPRRI::Ctzw => 0b001,
1103            AluOPRRI::Rev8 => 0b101,
1104            AluOPRRI::Sextb => 0b001,
1105            AluOPRRI::Sexth => 0b001,
1106            AluOPRRI::Zexth => 0b100,
1107            AluOPRRI::Orcb => 0b101,
1108            AluOPRRI::Brev8 => 0b101,
1109        }
1110    }
1111
1112    pub fn op_code(self) -> u32 {
1113        match self {
1114            AluOPRRI::Addi
1115            | AluOPRRI::Slti
1116            | AluOPRRI::SltiU
1117            | AluOPRRI::Xori
1118            | AluOPRRI::Ori
1119            | AluOPRRI::Andi
1120            | AluOPRRI::Slli
1121            | AluOPRRI::Srli
1122            | AluOPRRI::Srai
1123            | AluOPRRI::Bclri
1124            | AluOPRRI::Bexti
1125            | AluOPRRI::Binvi
1126            | AluOPRRI::Bseti
1127            | AluOPRRI::Rori
1128            | AluOPRRI::Clz
1129            | AluOPRRI::Cpop
1130            | AluOPRRI::Ctz
1131            | AluOPRRI::Rev8
1132            | AluOPRRI::Sextb
1133            | AluOPRRI::Sexth
1134            | AluOPRRI::Orcb
1135            | AluOPRRI::Brev8 => 0b0010011,
1136
1137            AluOPRRI::Addiw
1138            | AluOPRRI::Slliw
1139            | AluOPRRI::SrliW
1140            | AluOPRRI::Sraiw
1141            | AluOPRRI::Roriw
1142            | AluOPRRI::SlliUw
1143            | AluOPRRI::Clzw
1144            | AluOPRRI::Cpopw
1145            | AluOPRRI::Ctzw => 0b0011011,
1146            AluOPRRI::Zexth => 0b0111011,
1147        }
1148    }
1149}
1150
1151impl Default for FRM {
1152    fn default() -> Self {
1153        Self::Fcsr
1154    }
1155}
1156
1157/// float rounding mode.
1158impl FRM {
1159    pub(crate) fn to_static_str(self) -> &'static str {
1160        match self {
1161            FRM::RNE => "rne",
1162            FRM::RTZ => "rtz",
1163            FRM::RDN => "rdn",
1164            FRM::RUP => "rup",
1165            FRM::RMM => "rmm",
1166            FRM::Fcsr => "fcsr",
1167        }
1168    }
1169
1170    #[inline]
1171    pub(crate) fn bits(self) -> u8 {
1172        match self {
1173            FRM::RNE => 0b000,
1174            FRM::RTZ => 0b001,
1175            FRM::RDN => 0b010,
1176            FRM::RUP => 0b011,
1177            FRM::RMM => 0b100,
1178            FRM::Fcsr => 0b111,
1179        }
1180    }
1181    pub(crate) fn as_u32(self) -> u32 {
1182        self.bits() as u32
1183    }
1184}
1185
1186impl FFlagsException {
1187    #[inline]
1188    #[expect(dead_code, reason = "here for future use")]
1189    pub(crate) fn mask(self) -> u32 {
1190        match self {
1191            FFlagsException::NV => 1 << 4,
1192            FFlagsException::DZ => 1 << 3,
1193            FFlagsException::OF => 1 << 2,
1194            FFlagsException::UF => 1 << 1,
1195            FFlagsException::NX => 1 << 0,
1196        }
1197    }
1198}
1199
1200impl LoadOP {
1201    pub(crate) fn op_name(self) -> &'static str {
1202        match self {
1203            Self::Lb => "lb",
1204            Self::Lh => "lh",
1205            Self::Lw => "lw",
1206            Self::Lbu => "lbu",
1207            Self::Lhu => "lhu",
1208            Self::Lwu => "lwu",
1209            Self::Ld => "ld",
1210            Self::Flh => "flh",
1211            Self::Flw => "flw",
1212            Self::Fld => "fld",
1213        }
1214    }
1215
1216    pub(crate) fn from_type(ty: Type) -> Self {
1217        match ty {
1218            F16 => Self::Flh,
1219            F32 => Self::Flw,
1220            F64 => Self::Fld,
1221            I8 => Self::Lb,
1222            I16 => Self::Lh,
1223            I32 => Self::Lw,
1224            I64 => Self::Ld,
1225            _ => unreachable!(),
1226        }
1227    }
1228
1229    pub(crate) fn size(&self) -> i64 {
1230        match self {
1231            Self::Lb | Self::Lbu => 1,
1232            Self::Lh | Self::Lhu | Self::Flh => 2,
1233            Self::Lw | Self::Lwu | Self::Flw => 4,
1234            Self::Ld | Self::Fld => 8,
1235        }
1236    }
1237
1238    pub(crate) fn op_code(self) -> u32 {
1239        match self {
1240            Self::Lb | Self::Lh | Self::Lw | Self::Lbu | Self::Lhu | Self::Lwu | Self::Ld => {
1241                0b0000011
1242            }
1243            Self::Flh | Self::Flw | Self::Fld => 0b0000111,
1244        }
1245    }
1246    pub(crate) fn funct3(self) -> u32 {
1247        match self {
1248            Self::Lb => 0b000,
1249            Self::Lh => 0b001,
1250            Self::Lw => 0b010,
1251            Self::Lwu => 0b110,
1252            Self::Lbu => 0b100,
1253            Self::Lhu => 0b101,
1254            Self::Ld => 0b011,
1255            Self::Flh => 0b001,
1256            Self::Flw => 0b010,
1257            Self::Fld => 0b011,
1258        }
1259    }
1260}
1261
1262impl StoreOP {
1263    pub(crate) fn op_name(self) -> &'static str {
1264        match self {
1265            Self::Sb => "sb",
1266            Self::Sh => "sh",
1267            Self::Sw => "sw",
1268            Self::Sd => "sd",
1269            Self::Fsh => "fsh",
1270            Self::Fsw => "fsw",
1271            Self::Fsd => "fsd",
1272        }
1273    }
1274    pub(crate) fn from_type(ty: Type) -> Self {
1275        match ty {
1276            F16 => Self::Fsh,
1277            F32 => Self::Fsw,
1278            F64 => Self::Fsd,
1279            I8 => Self::Sb,
1280            I16 => Self::Sh,
1281            I32 => Self::Sw,
1282            I64 => Self::Sd,
1283            _ => unreachable!(),
1284        }
1285    }
1286
1287    pub(crate) fn size(&self) -> i64 {
1288        match self {
1289            Self::Sb => 1,
1290            Self::Sh | Self::Fsh => 2,
1291            Self::Sw | Self::Fsw => 4,
1292            Self::Sd | Self::Fsd => 8,
1293        }
1294    }
1295
1296    pub(crate) fn op_code(self) -> u32 {
1297        match self {
1298            Self::Sb | Self::Sh | Self::Sw | Self::Sd => 0b0100011,
1299            Self::Fsh | Self::Fsw | Self::Fsd => 0b0100111,
1300        }
1301    }
1302    pub(crate) fn funct3(self) -> u32 {
1303        match self {
1304            Self::Sb => 0b000,
1305            Self::Sh => 0b001,
1306            Self::Sw => 0b010,
1307            Self::Sd => 0b011,
1308            Self::Fsh => 0b001,
1309            Self::Fsw => 0b010,
1310            Self::Fsd => 0b011,
1311        }
1312    }
1313}
1314
1315impl FClassResult {
1316    pub(crate) const fn bit(self) -> u32 {
1317        match self {
1318            FClassResult::NegInfinite => 1 << 0,
1319            FClassResult::NegNormal => 1 << 1,
1320            FClassResult::NegSubNormal => 1 << 2,
1321            FClassResult::NegZero => 1 << 3,
1322            FClassResult::PosZero => 1 << 4,
1323            FClassResult::PosSubNormal => 1 << 5,
1324            FClassResult::PosNormal => 1 << 6,
1325            FClassResult::PosInfinite => 1 << 7,
1326            FClassResult::SNaN => 1 << 8,
1327            FClassResult::QNaN => 1 << 9,
1328        }
1329    }
1330
1331    #[inline]
1332    #[expect(dead_code, reason = "here for future use")]
1333    pub(crate) const fn is_nan_bits() -> u32 {
1334        Self::SNaN.bit() | Self::QNaN.bit()
1335    }
1336    #[inline]
1337    #[expect(dead_code, reason = "here for future use")]
1338    pub(crate) fn is_zero_bits() -> u32 {
1339        Self::NegZero.bit() | Self::PosZero.bit()
1340    }
1341
1342    #[inline]
1343    #[expect(dead_code, reason = "here for future use")]
1344    pub(crate) fn is_infinite_bits() -> u32 {
1345        Self::PosInfinite.bit() | Self::NegInfinite.bit()
1346    }
1347}
1348
1349impl AtomicOP {
1350    #[inline]
1351    pub(crate) fn is_load(self) -> bool {
1352        match self {
1353            Self::LrW | Self::LrD => true,
1354            _ => false,
1355        }
1356    }
1357
1358    #[inline]
1359    pub(crate) fn op_name(self, amo: AMO) -> String {
1360        let s = match self {
1361            Self::LrW => "lr.w",
1362            Self::ScW => "sc.w",
1363
1364            Self::AmoswapW => "amoswap.w",
1365            Self::AmoaddW => "amoadd.w",
1366            Self::AmoxorW => "amoxor.w",
1367            Self::AmoandW => "amoand.w",
1368            Self::AmoorW => "amoor.w",
1369            Self::AmominW => "amomin.w",
1370            Self::AmomaxW => "amomax.w",
1371            Self::AmominuW => "amominu.w",
1372            Self::AmomaxuW => "amomaxu.w",
1373            Self::LrD => "lr.d",
1374            Self::ScD => "sc.d",
1375            Self::AmoswapD => "amoswap.d",
1376            Self::AmoaddD => "amoadd.d",
1377            Self::AmoxorD => "amoxor.d",
1378            Self::AmoandD => "amoand.d",
1379            Self::AmoorD => "amoor.d",
1380            Self::AmominD => "amomin.d",
1381            Self::AmomaxD => "amomax.d",
1382            Self::AmominuD => "amominu.d",
1383            Self::AmomaxuD => "amomaxu.d",
1384        };
1385        format!("{}{}", s, amo.to_static_str())
1386    }
1387    #[inline]
1388    pub(crate) fn op_code(self) -> u32 {
1389        0b0101111
1390    }
1391
1392    #[inline]
1393    pub(crate) fn funct7(self, amo: AMO) -> u32 {
1394        self.funct5() << 2 | amo.as_u32() & 0b11
1395    }
1396
1397    pub(crate) fn funct3(self) -> u32 {
1398        match self {
1399            AtomicOP::LrW
1400            | AtomicOP::ScW
1401            | AtomicOP::AmoswapW
1402            | AtomicOP::AmoaddW
1403            | AtomicOP::AmoxorW
1404            | AtomicOP::AmoandW
1405            | AtomicOP::AmoorW
1406            | AtomicOP::AmominW
1407            | AtomicOP::AmomaxW
1408            | AtomicOP::AmominuW
1409            | AtomicOP::AmomaxuW => 0b010,
1410            AtomicOP::LrD
1411            | AtomicOP::ScD
1412            | AtomicOP::AmoswapD
1413            | AtomicOP::AmoaddD
1414            | AtomicOP::AmoxorD
1415            | AtomicOP::AmoandD
1416            | AtomicOP::AmoorD
1417            | AtomicOP::AmominD
1418            | AtomicOP::AmomaxD
1419            | AtomicOP::AmominuD
1420            | AtomicOP::AmomaxuD => 0b011,
1421        }
1422    }
1423    pub(crate) fn funct5(self) -> u32 {
1424        match self {
1425            AtomicOP::LrW => 0b00010,
1426            AtomicOP::ScW => 0b00011,
1427            AtomicOP::AmoswapW => 0b00001,
1428            AtomicOP::AmoaddW => 0b00000,
1429            AtomicOP::AmoxorW => 0b00100,
1430            AtomicOP::AmoandW => 0b01100,
1431            AtomicOP::AmoorW => 0b01000,
1432            AtomicOP::AmominW => 0b10000,
1433            AtomicOP::AmomaxW => 0b10100,
1434            AtomicOP::AmominuW => 0b11000,
1435            AtomicOP::AmomaxuW => 0b11100,
1436            AtomicOP::LrD => 0b00010,
1437            AtomicOP::ScD => 0b00011,
1438            AtomicOP::AmoswapD => 0b00001,
1439            AtomicOP::AmoaddD => 0b00000,
1440            AtomicOP::AmoxorD => 0b00100,
1441            AtomicOP::AmoandD => 0b01100,
1442            AtomicOP::AmoorD => 0b01000,
1443            AtomicOP::AmominD => 0b10000,
1444            AtomicOP::AmomaxD => 0b10100,
1445            AtomicOP::AmominuD => 0b11000,
1446            AtomicOP::AmomaxuD => 0b11100,
1447        }
1448    }
1449
1450    pub(crate) fn load_op(t: Type) -> Self {
1451        if t.bits() <= 32 { Self::LrW } else { Self::LrD }
1452    }
1453    pub(crate) fn store_op(t: Type) -> Self {
1454        if t.bits() <= 32 { Self::ScW } else { Self::ScD }
1455    }
1456
1457    /// extract
1458    pub(crate) fn extract(rd: WritableReg, offset: Reg, rs: Reg, ty: Type) -> SmallInstVec<Inst> {
1459        let mut insts = SmallInstVec::new();
1460        insts.push(Inst::AluRRR {
1461            alu_op: AluOPRRR::Srl,
1462            rd,
1463            rs1: rs,
1464            rs2: offset,
1465        });
1466        //
1467        insts.push(Inst::Extend {
1468            rd,
1469            rn: rd.to_reg(),
1470            signed: false,
1471            from_bits: ty.bits() as u8,
1472            to_bits: 64,
1473        });
1474        insts
1475    }
1476
1477    /// like extract but sign extend the value.
1478    /// suitable for smax,etc.
1479    pub(crate) fn extract_sext(
1480        rd: WritableReg,
1481        offset: Reg,
1482        rs: Reg,
1483        ty: Type,
1484    ) -> SmallInstVec<Inst> {
1485        let mut insts = SmallInstVec::new();
1486        insts.push(Inst::AluRRR {
1487            alu_op: AluOPRRR::Srl,
1488            rd,
1489            rs1: rs,
1490            rs2: offset,
1491        });
1492        //
1493        insts.push(Inst::Extend {
1494            rd,
1495            rn: rd.to_reg(),
1496            signed: true,
1497            from_bits: ty.bits() as u8,
1498            to_bits: 64,
1499        });
1500        insts
1501    }
1502
1503    pub(crate) fn unset(
1504        rd: WritableReg,
1505        tmp: WritableReg,
1506        offset: Reg,
1507        ty: Type,
1508    ) -> SmallInstVec<Inst> {
1509        assert!(rd != tmp);
1510        let mut insts = SmallInstVec::new();
1511        insts.extend(Inst::load_int_mask(tmp, ty));
1512        insts.push(Inst::AluRRR {
1513            alu_op: AluOPRRR::Sll,
1514            rd: tmp,
1515            rs1: tmp.to_reg(),
1516            rs2: offset,
1517        });
1518        insts.push(Inst::construct_bit_not(tmp, tmp.to_reg()));
1519        insts.push(Inst::AluRRR {
1520            alu_op: AluOPRRR::And,
1521            rd,
1522            rs1: rd.to_reg(),
1523            rs2: tmp.to_reg(),
1524        });
1525        insts
1526    }
1527
1528    pub(crate) fn set(
1529        rd: WritableReg,
1530        tmp: WritableReg,
1531        offset: Reg,
1532        rs: Reg,
1533        ty: Type,
1534    ) -> SmallInstVec<Inst> {
1535        assert!(rd != tmp);
1536        let mut insts = SmallInstVec::new();
1537        // make rs into tmp.
1538        insts.push(Inst::Extend {
1539            rd: tmp,
1540            rn: rs,
1541            signed: false,
1542            from_bits: ty.bits() as u8,
1543            to_bits: 64,
1544        });
1545        insts.push(Inst::AluRRR {
1546            alu_op: AluOPRRR::Sll,
1547            rd: tmp,
1548            rs1: tmp.to_reg(),
1549            rs2: offset,
1550        });
1551        insts.push(Inst::AluRRR {
1552            alu_op: AluOPRRR::Or,
1553            rd,
1554            rs1: rd.to_reg(),
1555            rs2: tmp.to_reg(),
1556        });
1557        insts
1558    }
1559
1560    /// Merge reset part of rs into rd.
1561    /// Call this function must make sure that other part of value is already in rd.
1562    pub(crate) fn merge(
1563        rd: WritableReg,
1564        tmp: WritableReg,
1565        offset: Reg,
1566        rs: Reg,
1567        ty: Type,
1568    ) -> SmallInstVec<Inst> {
1569        let mut insts = Self::unset(rd, tmp, offset, ty);
1570        insts.extend(Self::set(rd, tmp, offset, rs, ty));
1571        insts
1572    }
1573}
1574
1575///Atomic Memory ordering.
1576#[derive(Copy, Clone, Debug)]
1577pub enum AMO {
1578    #[allow(dead_code, reason = "used only in emit tests for now")]
1579    Relax = 0b00,
1580    #[allow(dead_code, reason = "used only in emit tests for now")]
1581    Release = 0b01,
1582    #[allow(dead_code, reason = "used only in emit tests for now")]
1583    Acquire = 0b10,
1584    SeqCst = 0b11,
1585}
1586
1587impl AMO {
1588    pub(crate) fn to_static_str(self) -> &'static str {
1589        match self {
1590            AMO::Relax => "",
1591            AMO::Release => ".rl",
1592            AMO::Acquire => ".aq",
1593            AMO::SeqCst => ".aqrl",
1594        }
1595    }
1596    pub(crate) fn as_u32(self) -> u32 {
1597        self as u32
1598    }
1599}
1600
1601impl Inst {
1602    /// fence request bits.
1603    pub(crate) const FENCE_REQ_I: u8 = 1 << 3;
1604    pub(crate) const FENCE_REQ_O: u8 = 1 << 2;
1605    pub(crate) const FENCE_REQ_R: u8 = 1 << 1;
1606    pub(crate) const FENCE_REQ_W: u8 = 1 << 0;
1607    pub(crate) fn fence_req_to_string(x: u8) -> String {
1608        let mut s = String::default();
1609        if x & Self::FENCE_REQ_I != 0 {
1610            s.push_str("i");
1611        }
1612        if x & Self::FENCE_REQ_O != 0 {
1613            s.push_str("o");
1614        }
1615        if x & Self::FENCE_REQ_R != 0 {
1616            s.push_str("r");
1617        }
1618        if x & Self::FENCE_REQ_W != 0 {
1619            s.push_str("w");
1620        }
1621        s
1622    }
1623}
1624
1625impl CsrRegOP {
1626    pub(crate) fn funct3(self) -> u32 {
1627        match self {
1628            CsrRegOP::CsrRW => 0b001,
1629            CsrRegOP::CsrRS => 0b010,
1630            CsrRegOP::CsrRC => 0b011,
1631        }
1632    }
1633
1634    pub(crate) fn opcode(self) -> u32 {
1635        0b1110011
1636    }
1637
1638    pub(crate) fn name(self) -> &'static str {
1639        match self {
1640            CsrRegOP::CsrRW => "csrrw",
1641            CsrRegOP::CsrRS => "csrrs",
1642            CsrRegOP::CsrRC => "csrrc",
1643        }
1644    }
1645}
1646
1647impl Display for CsrRegOP {
1648    fn fmt(&self, f: &mut Formatter<'_>) -> Result {
1649        write!(f, "{}", self.name())
1650    }
1651}
1652
1653impl CsrImmOP {
1654    pub(crate) fn funct3(self) -> u32 {
1655        match self {
1656            CsrImmOP::CsrRWI => 0b101,
1657            CsrImmOP::CsrRSI => 0b110,
1658            CsrImmOP::CsrRCI => 0b111,
1659        }
1660    }
1661
1662    pub(crate) fn opcode(self) -> u32 {
1663        0b1110011
1664    }
1665
1666    pub(crate) fn name(self) -> &'static str {
1667        match self {
1668            CsrImmOP::CsrRWI => "csrrwi",
1669            CsrImmOP::CsrRSI => "csrrsi",
1670            CsrImmOP::CsrRCI => "csrrci",
1671        }
1672    }
1673}
1674
1675impl Display for CsrImmOP {
1676    fn fmt(&self, f: &mut Formatter<'_>) -> Result {
1677        write!(f, "{}", self.name())
1678    }
1679}
1680
1681impl CSR {
1682    pub(crate) fn bits(self) -> Imm12 {
1683        Imm12::from_i16(match self {
1684            CSR::Frm => 0x0002,
1685        })
1686    }
1687
1688    pub(crate) fn name(self) -> &'static str {
1689        match self {
1690            CSR::Frm => "frm",
1691        }
1692    }
1693}
1694
1695impl Display for CSR {
1696    fn fmt(&self, f: &mut Formatter<'_>) -> Result {
1697        write!(f, "{}", self.name())
1698    }
1699}
1700
1701impl COpcodeSpace {
1702    pub fn bits(&self) -> u32 {
1703        match self {
1704            COpcodeSpace::C0 => 0b00,
1705            COpcodeSpace::C1 => 0b01,
1706            COpcodeSpace::C2 => 0b10,
1707        }
1708    }
1709}
1710
1711impl CrOp {
1712    pub fn funct4(&self) -> u32 {
1713        // https://five-embeddev.com/riscv-isa-manual/latest/rvc-opcode-map.html#rvcopcodemap
1714        match self {
1715            // `c.jr` has the same op/funct4 as C.MV, but RS2 is 0, which is illegal for mv.
1716            CrOp::CMv | CrOp::CJr => 0b1000,
1717            CrOp::CAdd | CrOp::CJalr | CrOp::CEbreak => 0b1001,
1718        }
1719    }
1720
1721    pub fn op(&self) -> COpcodeSpace {
1722        // https://five-embeddev.com/riscv-isa-manual/latest/rvc-opcode-map.html#rvcopcodemap
1723        match self {
1724            CrOp::CMv | CrOp::CAdd | CrOp::CJr | CrOp::CJalr | CrOp::CEbreak => COpcodeSpace::C2,
1725        }
1726    }
1727}
1728
1729impl CaOp {
1730    pub fn funct2(&self) -> u32 {
1731        // https://github.com/michaeljclark/riscv-meta/blob/master/opcodes
1732        match self {
1733            CaOp::CAnd => 0b11,
1734            CaOp::COr => 0b10,
1735            CaOp::CXor => 0b01,
1736            CaOp::CSub => 0b00,
1737            CaOp::CAddw => 0b01,
1738            CaOp::CSubw => 0b00,
1739            CaOp::CMul => 0b10,
1740        }
1741    }
1742
1743    pub fn funct6(&self) -> u32 {
1744        // https://github.com/michaeljclark/riscv-meta/blob/master/opcodes
1745        match self {
1746            CaOp::CAnd | CaOp::COr | CaOp::CXor | CaOp::CSub => 0b100_011,
1747            CaOp::CSubw | CaOp::CAddw | CaOp::CMul => 0b100_111,
1748        }
1749    }
1750
1751    pub fn op(&self) -> COpcodeSpace {
1752        // https://five-embeddev.com/riscv-isa-manual/latest/rvc-opcode-map.html#rvcopcodemap
1753        match self {
1754            CaOp::CAnd
1755            | CaOp::COr
1756            | CaOp::CXor
1757            | CaOp::CSub
1758            | CaOp::CAddw
1759            | CaOp::CSubw
1760            | CaOp::CMul => COpcodeSpace::C1,
1761        }
1762    }
1763}
1764
1765impl CjOp {
1766    pub fn funct3(&self) -> u32 {
1767        // https://github.com/michaeljclark/riscv-meta/blob/master/opcodes
1768        match self {
1769            CjOp::CJ => 0b101,
1770        }
1771    }
1772
1773    pub fn op(&self) -> COpcodeSpace {
1774        // https://five-embeddev.com/riscv-isa-manual/latest/rvc-opcode-map.html#rvcopcodemap
1775        match self {
1776            CjOp::CJ => COpcodeSpace::C1,
1777        }
1778    }
1779}
1780
1781impl CiOp {
1782    pub fn funct3(&self) -> u32 {
1783        // https://github.com/michaeljclark/riscv-meta/blob/master/opcodes
1784        match self {
1785            CiOp::CAddi | CiOp::CSlli => 0b000,
1786            CiOp::CAddiw | CiOp::CFldsp => 0b001,
1787            CiOp::CLi | CiOp::CLwsp => 0b010,
1788            CiOp::CAddi16sp | CiOp::CLui | CiOp::CLdsp => 0b011,
1789        }
1790    }
1791
1792    pub fn op(&self) -> COpcodeSpace {
1793        // https://five-embeddev.com/riscv-isa-manual/latest/rvc-opcode-map.html#rvcopcodemap
1794        match self {
1795            CiOp::CAddi | CiOp::CAddiw | CiOp::CAddi16sp | CiOp::CLi | CiOp::CLui => {
1796                COpcodeSpace::C1
1797            }
1798            CiOp::CSlli | CiOp::CLwsp | CiOp::CLdsp | CiOp::CFldsp => COpcodeSpace::C2,
1799        }
1800    }
1801}
1802
1803impl CiwOp {
1804    pub fn funct3(&self) -> u32 {
1805        // https://github.com/michaeljclark/riscv-meta/blob/master/opcodes
1806        match self {
1807            CiwOp::CAddi4spn => 0b000,
1808        }
1809    }
1810
1811    pub fn op(&self) -> COpcodeSpace {
1812        // https://five-embeddev.com/riscv-isa-manual/latest/rvc-opcode-map.html#rvcopcodemap
1813        match self {
1814            CiwOp::CAddi4spn => COpcodeSpace::C0,
1815        }
1816    }
1817}
1818
1819impl CbOp {
1820    pub fn funct3(&self) -> u32 {
1821        // https://github.com/michaeljclark/riscv-meta/blob/master/opcodes
1822        match self {
1823            CbOp::CSrli | CbOp::CSrai | CbOp::CAndi => 0b100,
1824        }
1825    }
1826
1827    pub fn funct2(&self) -> u32 {
1828        // https://github.com/michaeljclark/riscv-meta/blob/master/opcodes
1829        match self {
1830            CbOp::CSrli => 0b00,
1831            CbOp::CSrai => 0b01,
1832            CbOp::CAndi => 0b10,
1833        }
1834    }
1835
1836    pub fn op(&self) -> COpcodeSpace {
1837        // https://five-embeddev.com/riscv-isa-manual/latest/rvc-opcode-map.html#rvcopcodemap
1838        match self {
1839            CbOp::CSrli | CbOp::CSrai | CbOp::CAndi => COpcodeSpace::C1,
1840        }
1841    }
1842}
1843
1844impl CssOp {
1845    pub fn funct3(&self) -> u32 {
1846        // https://github.com/michaeljclark/riscv-meta/blob/master/opcodes
1847        match self {
1848            CssOp::CFsdsp => 0b101,
1849            CssOp::CSwsp => 0b110,
1850            CssOp::CSdsp => 0b111,
1851        }
1852    }
1853
1854    pub fn op(&self) -> COpcodeSpace {
1855        // https://five-embeddev.com/riscv-isa-manual/latest/rvc-opcode-map.html#rvcopcodemap
1856        match self {
1857            CssOp::CSwsp | CssOp::CSdsp | CssOp::CFsdsp => COpcodeSpace::C2,
1858        }
1859    }
1860}
1861
1862impl CsOp {
1863    pub fn funct3(&self) -> u32 {
1864        // https://github.com/michaeljclark/riscv-meta/blob/master/opcodes
1865        match self {
1866            CsOp::CFsd => 0b101,
1867            CsOp::CSw => 0b110,
1868            CsOp::CSd => 0b111,
1869        }
1870    }
1871
1872    pub fn op(&self) -> COpcodeSpace {
1873        // https://five-embeddev.com/riscv-isa-manual/latest/rvc-opcode-map.html#rvcopcodemap
1874        match self {
1875            CsOp::CSw | CsOp::CSd | CsOp::CFsd => COpcodeSpace::C0,
1876        }
1877    }
1878}
1879
1880impl ClOp {
1881    pub fn funct3(&self) -> u32 {
1882        // https://github.com/michaeljclark/riscv-meta/blob/master/opcodes
1883        match self {
1884            ClOp::CFld => 0b001,
1885            ClOp::CLw => 0b010,
1886            ClOp::CLd => 0b011,
1887        }
1888    }
1889
1890    pub fn op(&self) -> COpcodeSpace {
1891        // https://five-embeddev.com/riscv-isa-manual/latest/rvc-opcode-map.html#rvcopcodemap
1892        match self {
1893            ClOp::CLw | ClOp::CLd | ClOp::CFld => COpcodeSpace::C0,
1894        }
1895    }
1896}
1897
1898impl CsznOp {
1899    pub fn funct6(&self) -> u32 {
1900        // https://github.com/michaeljclark/riscv-meta/blob/master/opcodes
1901        match self {
1902            CsznOp::CNot
1903            | CsznOp::CZextw
1904            | CsznOp::CZextb
1905            | CsznOp::CZexth
1906            | CsznOp::CSextb
1907            | CsznOp::CSexth => 0b100_111,
1908        }
1909    }
1910
1911    pub fn funct5(&self) -> u32 {
1912        // https://github.com/michaeljclark/riscv-meta/blob/master/opcodes
1913        match self {
1914            CsznOp::CNot => 0b11_101,
1915            CsznOp::CZextb => 0b11_000,
1916            CsznOp::CZexth => 0b11_010,
1917            CsznOp::CZextw => 0b11_100,
1918            CsznOp::CSextb => 0b11_001,
1919            CsznOp::CSexth => 0b11_011,
1920        }
1921    }
1922
1923    pub fn op(&self) -> COpcodeSpace {
1924        // https://five-embeddev.com/riscv-isa-manual/latest/rvc-opcode-map.html#rvcopcodemap
1925        match self {
1926            CsznOp::CNot
1927            | CsznOp::CZextb
1928            | CsznOp::CZexth
1929            | CsznOp::CZextw
1930            | CsznOp::CSextb
1931            | CsznOp::CSexth => COpcodeSpace::C1,
1932        }
1933    }
1934}
1935
1936impl ZcbMemOp {
1937    pub fn funct6(&self) -> u32 {
1938        // https://github.com/michaeljclark/riscv-meta/blob/master/opcodes
1939        match self {
1940            ZcbMemOp::CLbu => 0b100_000,
1941            // These two opcodes are differentiated in the imm field of the instruction.
1942            ZcbMemOp::CLhu | ZcbMemOp::CLh => 0b100_001,
1943            ZcbMemOp::CSb => 0b100_010,
1944            ZcbMemOp::CSh => 0b100_011,
1945        }
1946    }
1947
1948    pub fn imm_bits(&self) -> u8 {
1949        match self {
1950            ZcbMemOp::CLhu | ZcbMemOp::CLh | ZcbMemOp::CSh => 1,
1951            ZcbMemOp::CLbu | ZcbMemOp::CSb => 2,
1952        }
1953    }
1954
1955    pub fn op(&self) -> COpcodeSpace {
1956        // https://five-embeddev.com/riscv-isa-manual/latest/rvc-opcode-map.html#rvcopcodemap
1957        match self {
1958            ZcbMemOp::CLbu | ZcbMemOp::CLhu | ZcbMemOp::CLh | ZcbMemOp::CSb | ZcbMemOp::CSh => {
1959                COpcodeSpace::C0
1960            }
1961        }
1962    }
1963}