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}