openvm_transpiler/
extension.rs

1use eyre::Result;
2use openvm_instructions::{exe::SparseMemoryImage, instruction::Instruction};
3
4/// Trait to add custom RISC-V instruction transpilation to OpenVM instruction format.
5/// RISC-V instructions always come in 32-bit chunks.
6/// An important feature is that multiple 32-bit RISC-V instructions can be transpiled into a single
7/// OpenVM instruction. See [process_custom](Self::process_custom) for details.
8pub trait TranspilerExtension<F> {
9    /// The `instruction_stream` provides a view of the remaining RISC-V instructions to be
10    /// processed, presented as 32-bit chunks. The [process_custom](Self::process_custom) should
11    /// determine if it knows how to transpile the next contiguous section of RISC-V
12    /// instructions into an [`Instruction`]. It returns `None` if it cannot transpile.
13    /// Otherwise it returns `TranspilerOutput { instructions, used_u32s }` to indicate that
14    /// `instruction_stream[..used_u32s]` should be transpiled into `instructions`.
15    fn process_custom(&self, instruction_stream: &[u32]) -> Option<TranspilerOutput<F>>;
16
17    /// Each transpiler extension is given the opportunity to modify the initial memory state.
18    /// By default, nothing is done.
19    fn modify_initial_memory(&self, _init_memory: &mut SparseMemoryImage) -> Result<()> {
20        Ok(())
21    }
22}
23
24pub struct TranspilerOutput<F> {
25    pub instructions: Vec<Option<Instruction<F>>>,
26    pub used_u32s: usize,
27}
28
29impl<F> TranspilerOutput<F> {
30    pub fn one_to_one(instruction: Instruction<F>) -> Self {
31        Self {
32            instructions: vec![Some(instruction)],
33            used_u32s: 1,
34        }
35    }
36
37    pub fn many_to_one(instruction: Instruction<F>, used_u32s: usize) -> Self {
38        Self {
39            instructions: vec![Some(instruction)],
40            used_u32s,
41        }
42    }
43
44    pub fn gap(gap_length: usize, used_u32s: usize) -> Self {
45        Self {
46            instructions: (0..gap_length).map(|_| None).collect(),
47            used_u32s,
48        }
49    }
50}