ckb_vm_contrib/
decoder.rs

1use ckb_vm::{
2    ckb_vm_definitions::instructions as insts,
3    decoder::Decoder,
4    instructions::{
5        extract_opcode, instruction_length, set_instruction_length_n, Instruction, Itype, Utype,
6    },
7    Error, Memory,
8};
9
10/// This wraps on top of ckb-vm's decoder, providing more mops & opcode
11/// rewriting that can further optimize the VM.
12pub struct AuxDecoder {
13    inner: Decoder,
14}
15
16impl AuxDecoder {
17    pub fn new(inner: Decoder) -> Self {
18        Self { inner }
19    }
20
21    pub fn decode<M: Memory>(&mut self, memory: &mut M, pc: u64) -> Result<Instruction, Error> {
22        let head_inst = self.inner.decode(memory, pc)?;
23        match extract_opcode(head_inst) {
24            insts::OP_AUIPC => {
25                let i = Utype(head_inst);
26                let head_len = instruction_length(head_inst);
27                let mut rule_auipc = || -> Result<Option<Instruction>, Error> {
28                    let next_instruction = self.inner.decode(memory, pc + head_len as u64)?;
29                    let next_opcode = extract_opcode(next_instruction);
30                    match next_opcode {
31                        insts::OP_ADDI => {
32                            let ni = Itype(next_instruction);
33                            if i.rd() == ni.rd() && ni.rd() == ni.rs1() {
34                                let value = pc
35                                    .wrapping_add(i64::from(i.immediate_s()) as u64)
36                                    .wrapping_add(i64::from(ni.immediate_s()) as u64);
37                                if let Ok(value) = value.try_into() {
38                                    return Ok(Some(set_instruction_length_n(
39                                        Utype::new(insts::OP_CUSTOM_LOAD_IMM, i.rd(), value).0,
40                                        head_len + instruction_length(next_instruction),
41                                    )));
42                                }
43                            }
44                        }
45                        _ => (),
46                    };
47                    Ok(None)
48                };
49                if let Ok(Some(i)) = rule_auipc() {
50                    return Ok(i);
51                } else {
52                    let value = pc.wrapping_add(i64::from(i.immediate_s()) as u64);
53                    if let Ok(value) = value.try_into() {
54                        return Ok(set_instruction_length_n(
55                            Utype::new(insts::OP_CUSTOM_LOAD_UIMM, i.rd(), value).0,
56                            head_len,
57                        ));
58                    }
59                }
60            }
61            _ => (),
62        };
63
64        Ok(head_inst)
65    }
66}