ckb_vm/instructions/
tagged.rs

1use crate::{
2    error::Error,
3    instructions::{
4        extract_opcode, insts, Instruction, Itype, R4type, R5type, Rtype, Stype, Utype,
5    },
6};
7use core::convert::TryFrom;
8use core::fmt;
9
10// This is used for generating human readable texts from RISC-V instructions.
11// For performance reason, ckb-vm will not use this representation internally.
12#[derive(Debug, Clone, PartialEq)]
13pub enum TaggedInstruction {
14    Rtype(Rtype),
15    Itype(Itype),
16    Stype(Stype),
17    Utype(Utype),
18    R4type(R4type),
19    R5type(R5type),
20}
21
22impl fmt::Display for TaggedInstruction {
23    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
24        match self {
25            TaggedInstruction::Rtype(i) => i.fmt(f),
26            TaggedInstruction::Itype(i) => i.fmt(f),
27            TaggedInstruction::Stype(i) => i.fmt(f),
28            TaggedInstruction::Utype(i) => i.fmt(f),
29            TaggedInstruction::R4type(i) => i.fmt(f),
30            TaggedInstruction::R5type(i) => i.fmt(f),
31        }
32    }
33}
34
35impl From<Rtype> for TaggedInstruction {
36    fn from(i: Rtype) -> Self {
37        TaggedInstruction::Rtype(i)
38    }
39}
40
41impl From<Itype> for TaggedInstruction {
42    fn from(i: Itype) -> Self {
43        TaggedInstruction::Itype(i)
44    }
45}
46
47impl From<Stype> for TaggedInstruction {
48    fn from(i: Stype) -> Self {
49        TaggedInstruction::Stype(i)
50    }
51}
52
53impl From<Utype> for TaggedInstruction {
54    fn from(i: Utype) -> Self {
55        TaggedInstruction::Utype(i)
56    }
57}
58
59impl From<R4type> for TaggedInstruction {
60    fn from(i: R4type) -> Self {
61        TaggedInstruction::R4type(i)
62    }
63}
64
65impl From<R5type> for TaggedInstruction {
66    fn from(i: R5type) -> Self {
67        TaggedInstruction::R5type(i)
68    }
69}
70
71impl From<TaggedInstruction> for Instruction {
72    fn from(t: TaggedInstruction) -> Self {
73        match t {
74            TaggedInstruction::Rtype(i) => i.0,
75            TaggedInstruction::Itype(i) => i.0,
76            TaggedInstruction::Stype(i) => i.0,
77            TaggedInstruction::Utype(i) => i.0,
78            TaggedInstruction::R4type(i) => i.0,
79            TaggedInstruction::R5type(i) => i.0,
80        }
81    }
82}
83
84impl TryFrom<Instruction> for TaggedInstruction {
85    type Error = Error;
86
87    fn try_from(i: Instruction) -> Result<Self, Self::Error> {
88        let op = extract_opcode(i);
89        let tagged_inst = match op {
90            insts::OP_UNLOADED => Rtype(i).into(),
91            insts::OP_ECALL => Rtype(i).into(),
92            insts::OP_EBREAK => Rtype(i).into(),
93            insts::OP_FENCEI => Rtype(i).into(),
94            insts::OP_FENCE => Rtype(i).into(),
95            insts::OP_CUSTOM_TRACE_END => Rtype(i).into(),
96            insts::OP_SUB => Rtype(i).into(),
97            insts::OP_SUBW => Rtype(i).into(),
98            insts::OP_ADD => Rtype(i).into(),
99            insts::OP_ADDW => Rtype(i).into(),
100            insts::OP_XOR => Rtype(i).into(),
101            insts::OP_OR => Rtype(i).into(),
102            insts::OP_AND => Rtype(i).into(),
103            insts::OP_SLL => Rtype(i).into(),
104            insts::OP_SLLW => Rtype(i).into(),
105            insts::OP_SRL => Rtype(i).into(),
106            insts::OP_SRLW => Rtype(i).into(),
107            insts::OP_SRA => Rtype(i).into(),
108            insts::OP_SRAW => Rtype(i).into(),
109            insts::OP_SLT => Rtype(i).into(),
110            insts::OP_SLTU => Rtype(i).into(),
111            insts::OP_LB_VERSION0 => Itype(i).into(),
112            insts::OP_LB_VERSION1 => Itype(i).into(),
113            insts::OP_LH_VERSION0 => Itype(i).into(),
114            insts::OP_LH_VERSION1 => Itype(i).into(),
115            insts::OP_LW_VERSION0 => Itype(i).into(),
116            insts::OP_LW_VERSION1 => Itype(i).into(),
117            insts::OP_LD_VERSION0 => Itype(i).into(),
118            insts::OP_LD_VERSION1 => Itype(i).into(),
119            insts::OP_LBU_VERSION0 => Itype(i).into(),
120            insts::OP_LBU_VERSION1 => Itype(i).into(),
121            insts::OP_LHU_VERSION0 => Itype(i).into(),
122            insts::OP_LHU_VERSION1 => Itype(i).into(),
123            insts::OP_LWU_VERSION0 => Itype(i).into(),
124            insts::OP_LWU_VERSION1 => Itype(i).into(),
125            insts::OP_ADDI => Itype(i).into(),
126            insts::OP_ADDIW => Itype(i).into(),
127            insts::OP_XORI => Itype(i).into(),
128            insts::OP_ORI => Itype(i).into(),
129            insts::OP_ANDI => Itype(i).into(),
130            insts::OP_SLTI => Itype(i).into(),
131            insts::OP_SLTIU => Itype(i).into(),
132            insts::OP_JALR_VERSION0 => Itype(i).into(),
133            insts::OP_JALR_VERSION1 => Itype(i).into(),
134            insts::OP_SLLI => Itype(i).into(),
135            insts::OP_SRLI => Itype(i).into(),
136            insts::OP_SRAI => Itype(i).into(),
137            insts::OP_SLLIW => Itype(i).into(),
138            insts::OP_SRLIW => Itype(i).into(),
139            insts::OP_SRAIW => Itype(i).into(),
140            insts::OP_SB => Stype(i).into(),
141            insts::OP_SH => Stype(i).into(),
142            insts::OP_SW => Stype(i).into(),
143            insts::OP_SD => Stype(i).into(),
144            insts::OP_BEQ => Stype(i).into(),
145            insts::OP_BNE => Stype(i).into(),
146            insts::OP_BLT => Stype(i).into(),
147            insts::OP_BGE => Stype(i).into(),
148            insts::OP_BLTU => Stype(i).into(),
149            insts::OP_BGEU => Stype(i).into(),
150            insts::OP_LUI => Utype(i).into(),
151            insts::OP_AUIPC => Utype(i).into(),
152            insts::OP_JAL => Utype(i).into(),
153            insts::OP_MUL => Rtype(i).into(),
154            insts::OP_MULW => Rtype(i).into(),
155            insts::OP_MULH => Rtype(i).into(),
156            insts::OP_MULHSU => Rtype(i).into(),
157            insts::OP_MULHU => Rtype(i).into(),
158            insts::OP_DIV => Rtype(i).into(),
159            insts::OP_DIVW => Rtype(i).into(),
160            insts::OP_DIVU => Rtype(i).into(),
161            insts::OP_DIVUW => Rtype(i).into(),
162            insts::OP_REM => Rtype(i).into(),
163            insts::OP_REMW => Rtype(i).into(),
164            insts::OP_REMU => Rtype(i).into(),
165            insts::OP_REMUW => Rtype(i).into(),
166            insts::OP_LR_W => Rtype(i).into(),
167            insts::OP_SC_W => Rtype(i).into(),
168            insts::OP_AMOSWAP_W => Rtype(i).into(),
169            insts::OP_AMOADD_W => Rtype(i).into(),
170            insts::OP_AMOXOR_W => Rtype(i).into(),
171            insts::OP_AMOAND_W => Rtype(i).into(),
172            insts::OP_AMOOR_W => Rtype(i).into(),
173            insts::OP_AMOMIN_W => Rtype(i).into(),
174            insts::OP_AMOMAX_W => Rtype(i).into(),
175            insts::OP_AMOMINU_W => Rtype(i).into(),
176            insts::OP_AMOMAXU_W => Rtype(i).into(),
177            insts::OP_LR_D => Rtype(i).into(),
178            insts::OP_SC_D => Rtype(i).into(),
179            insts::OP_AMOSWAP_D => Rtype(i).into(),
180            insts::OP_AMOADD_D => Rtype(i).into(),
181            insts::OP_AMOXOR_D => Rtype(i).into(),
182            insts::OP_AMOAND_D => Rtype(i).into(),
183            insts::OP_AMOOR_D => Rtype(i).into(),
184            insts::OP_AMOMIN_D => Rtype(i).into(),
185            insts::OP_AMOMAX_D => Rtype(i).into(),
186            insts::OP_AMOMINU_D => Rtype(i).into(),
187            insts::OP_AMOMAXU_D => Rtype(i).into(),
188            insts::OP_ADDUW => Rtype(i).into(),
189            insts::OP_ANDN => Rtype(i).into(),
190            insts::OP_BCLR => Rtype(i).into(),
191            insts::OP_BCLRI => Itype(i).into(),
192            insts::OP_BEXT => Rtype(i).into(),
193            insts::OP_BEXTI => Itype(i).into(),
194            insts::OP_BINV => Rtype(i).into(),
195            insts::OP_BINVI => Itype(i).into(),
196            insts::OP_BSET => Rtype(i).into(),
197            insts::OP_BSETI => Itype(i).into(),
198            insts::OP_CLMUL => Rtype(i).into(),
199            insts::OP_CLMULH => Rtype(i).into(),
200            insts::OP_CLMULR => Rtype(i).into(),
201            insts::OP_CLZ => Rtype(i).into(),
202            insts::OP_CLZW => Rtype(i).into(),
203            insts::OP_CPOP => Rtype(i).into(),
204            insts::OP_CPOPW => Rtype(i).into(),
205            insts::OP_CTZ => Rtype(i).into(),
206            insts::OP_CTZW => Rtype(i).into(),
207            insts::OP_MAX => Rtype(i).into(),
208            insts::OP_MAXU => Rtype(i).into(),
209            insts::OP_MIN => Rtype(i).into(),
210            insts::OP_MINU => Rtype(i).into(),
211            insts::OP_ORCB => Rtype(i).into(),
212            insts::OP_ORN => Rtype(i).into(),
213            insts::OP_REV8 => Rtype(i).into(),
214            insts::OP_ROL => Rtype(i).into(),
215            insts::OP_ROLW => Rtype(i).into(),
216            insts::OP_ROR => Rtype(i).into(),
217            insts::OP_RORI => Itype(i).into(),
218            insts::OP_RORIW => Itype(i).into(),
219            insts::OP_RORW => Rtype(i).into(),
220            insts::OP_SEXTB => Rtype(i).into(),
221            insts::OP_SEXTH => Rtype(i).into(),
222            insts::OP_SH1ADD => Rtype(i).into(),
223            insts::OP_SH1ADDUW => Rtype(i).into(),
224            insts::OP_SH2ADD => Rtype(i).into(),
225            insts::OP_SH2ADDUW => Rtype(i).into(),
226            insts::OP_SH3ADD => Rtype(i).into(),
227            insts::OP_SH3ADDUW => Rtype(i).into(),
228            insts::OP_SLLIUW => Itype(i).into(),
229            insts::OP_XNOR => Rtype(i).into(),
230            insts::OP_ZEXTH => Rtype(i).into(),
231            insts::OP_WIDE_MUL => R4type(i).into(),
232            insts::OP_WIDE_MULU => R4type(i).into(),
233            insts::OP_WIDE_MULSU => R4type(i).into(),
234            insts::OP_WIDE_DIV => R4type(i).into(),
235            insts::OP_WIDE_DIVU => R4type(i).into(),
236            insts::OP_FAR_JUMP_REL => Utype(i).into(),
237            insts::OP_FAR_JUMP_ABS => Utype(i).into(),
238            insts::OP_ADC => Rtype(i).into(),
239            insts::OP_SBB => R4type(i).into(),
240            insts::OP_ADCS => R4type(i).into(),
241            insts::OP_SBBS => R4type(i).into(),
242            insts::OP_ADD3A => R5type(i).into(),
243            insts::OP_ADD3B => R5type(i).into(),
244            insts::OP_ADD3C => R5type(i).into(),
245            insts::OP_CUSTOM_LOAD_UIMM => Utype(i).into(),
246            insts::OP_CUSTOM_LOAD_IMM => Utype(i).into(),
247            _ => return Err(Error::InvalidOp(op)),
248        };
249        Ok(tagged_inst)
250    }
251}
252
253#[cfg(test)]
254mod tests {
255    use super::*;
256    use crate::instructions::{blank_instruction, instruction_opcode_name};
257
258    #[test]
259    fn test_all_valid_opcodes_convert_to_tagged_instruction() {
260        for i in insts::OP_UNLOADED..=insts::OP_CUSTOM_TRACE_END {
261            let inst = blank_instruction(i);
262            let result = TaggedInstruction::try_from(inst);
263            assert!(
264                result.is_ok(),
265                "TaggedInstruction does not handle opcode {}({})!",
266                i,
267                instruction_opcode_name(i)
268            );
269        }
270    }
271}