Skip to content

Commit bcde3f8

Browse files
shuklaayushjonathanpwang
authored andcommitted
feat(new-execution): rv32im tracegen and e1 execution (#1607)
1 parent b85bfc2 commit bcde3f8

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

79 files changed

+8150
-5695
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,3 +37,6 @@ guest.syms
3737

3838
# openvm generated files
3939
crates/cli/openvm/
40+
41+
# samply profile
42+
profile.json.gz

benchmarks/execute/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,11 +31,11 @@ criterion = { version = "0.5", features = ["html_reports"] }
3131

3232
[features]
3333
default = ["jemalloc"]
34-
profiling = ["openvm-sdk/profiling"]
3534
mimalloc = ["openvm-circuit/mimalloc"]
3635
jemalloc = ["openvm-circuit/jemalloc"]
3736
jemalloc-prof = ["openvm-circuit/jemalloc-prof"]
3837
nightly-features = ["openvm-circuit/nightly-features"]
38+
profiling = ["openvm-circuit/function-span", "openvm-transpiler/function-span"]
3939

4040
[[bench]]
4141
name = "fibonacci_execute"

benchmarks/execute/src/main.rs

Lines changed: 31 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,34 @@
1-
use cargo_openvm::{default::DEFAULT_APP_CONFIG_PATH, util::read_config_toml_or_default};
21
use clap::{Parser, ValueEnum};
32
use eyre::Result;
43
use openvm_benchmarks_utils::{get_elf_path, get_programs_dir, read_elf_file};
54
use openvm_circuit::arch::{instructions::exe::VmExe, VmExecutor};
6-
use openvm_sdk::StdIn;
7-
use openvm_stark_sdk::bench::run_with_metric_collection;
8-
use openvm_transpiler::FromElf;
5+
use openvm_rv32im_circuit::Rv32ImConfig;
6+
use openvm_rv32im_transpiler::{
7+
Rv32ITranspilerExtension, Rv32IoTranspilerExtension, Rv32MTranspilerExtension,
8+
};
9+
use openvm_stark_sdk::{bench::run_with_metric_collection, p3_baby_bear::BabyBear};
10+
use openvm_transpiler::{transpiler::Transpiler, FromElf};
911

1012
#[derive(Debug, Clone, ValueEnum)]
1113
enum BuildProfile {
1214
Debug,
1315
Release,
1416
}
1517

18+
// const DEFAULT_APP_CONFIG_PATH: &str = "./openvm.toml";
19+
1620
static AVAILABLE_PROGRAMS: &[&str] = &[
17-
"fibonacci_recursive",
18-
"fibonacci_iterative",
21+
// "fibonacci_recursive",
22+
// "fibonacci_iterative",
1923
"quicksort",
20-
"bubblesort",
21-
"pairing",
22-
"keccak256",
23-
"keccak256_iter",
24-
"sha256",
25-
"sha256_iter",
26-
"revm_transfer",
27-
"revm_snailtracer",
24+
// "bubblesort",
25+
// "pairing",
26+
// "keccak256",
27+
// "keccak256_iter",
28+
// "sha256",
29+
// "sha256_iter",
30+
// "revm_transfer",
31+
// "revm_snailtracer",
2832
];
2933

3034
#[derive(Parser)]
@@ -106,13 +110,22 @@ fn main() -> Result<()> {
106110
let elf_path = get_elf_path(&program_dir);
107111
let elf = read_elf_file(&elf_path)?;
108112

109-
let config_path = program_dir.join(DEFAULT_APP_CONFIG_PATH);
110-
let vm_config = read_config_toml_or_default(&config_path)?.app_vm_config;
113+
// let config_path = program_dir.join(DEFAULT_APP_CONFIG_PATH);
114+
// let vm_config = read_config_toml_or_default(&config_path)?.app_vm_config;
115+
// let transpiler = vm_config.transpiler;
116+
let vm_config = Rv32ImConfig::default();
117+
118+
let transpiler = Transpiler::<BabyBear>::default()
119+
.with_extension(Rv32ITranspilerExtension)
120+
.with_extension(Rv32IoTranspilerExtension)
121+
.with_extension(Rv32MTranspilerExtension);
111122

112-
let exe = VmExe::from_elf(elf, vm_config.transpiler())?;
123+
let exe = VmExe::from_elf(elf, transpiler)?;
113124

114125
let executor = VmExecutor::new(vm_config);
115-
executor.execute(exe, StdIn::default())?;
126+
executor
127+
.execute_e1(exe, vec![])
128+
.expect("Failed to execute program");
116129
tracing::info!("Completed program: {}", program);
117130
}
118131
tracing::info!("All programs executed successfully");

crates/circuits/mod-builder/src/core_chip.rs

Lines changed: 3 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,9 @@
11
use itertools::Itertools;
22
use num_bigint::BigUint;
33
use num_traits::Zero;
4-
use openvm_circuit::{
5-
arch::{
6-
AdapterAirContext, AdapterRuntimeContext, DynAdapterInterface, DynArray, InsExecutorE1,
7-
MinimalInstruction, Result, VmAdapterInterface, VmCoreAir, VmCoreChip, VmExecutionState,
8-
},
9-
system::memory::online::GuestMemory,
4+
use openvm_circuit::arch::{
5+
AdapterAirContext, AdapterRuntimeContext, DynAdapterInterface, DynArray, MinimalInstruction,
6+
Result, VmAdapterInterface, VmCoreAir, VmCoreChip,
107
};
118
use openvm_circuit_primitives::{
129
var_range::SharedVariableRangeCheckerChip, SubAir, TraceSubRowGenerator,
@@ -314,20 +311,6 @@ where
314311
}
315312
}
316313

317-
impl<Mem, Ctx, F> InsExecutorE1<Mem, Ctx, F> for FieldExpressionCoreChip
318-
where
319-
Mem: GuestMemory,
320-
F: PrimeField32,
321-
{
322-
fn execute_e1(
323-
&mut self,
324-
_state: &mut VmExecutionState<Mem, Ctx>,
325-
_instruction: &Instruction<F>,
326-
) -> Result<()> {
327-
todo!("Implement execute_e1")
328-
}
329-
}
330-
331314
impl FieldExpressionCoreChip {
332315
// We will be setting is_valid = 0. That forces all flags be 0 (otherwise setup will be -1).
333316
// We generate a dummy row with all flags set to 0, then we set is_valid = 0.

crates/vm/derive/src/lib.rs

Lines changed: 99 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,104 @@ pub fn instruction_executor_derive(input: TokenStream) -> TokenStream {
113113
}
114114
}
115115

116+
#[proc_macro_derive(InsExecutorE1)]
117+
pub fn ins_executor_e1_executor_derive(input: TokenStream) -> TokenStream {
118+
let ast: syn::DeriveInput = syn::parse(input).unwrap();
119+
120+
let name = &ast.ident;
121+
let generics = &ast.generics;
122+
let (impl_generics, ty_generics, _) = generics.split_for_impl();
123+
124+
match &ast.data {
125+
Data::Struct(inner) => {
126+
// Check if the struct has only one unnamed field
127+
let inner_ty = match &inner.fields {
128+
Fields::Unnamed(fields) => {
129+
if fields.unnamed.len() != 1 {
130+
panic!("Only one unnamed field is supported");
131+
}
132+
fields.unnamed.first().unwrap().ty.clone()
133+
}
134+
_ => panic!("Only unnamed fields are supported"),
135+
};
136+
// Use full path ::openvm_circuit... so it can be used either within or outside the vm
137+
// crate. Assume F is already generic of the field.
138+
let mut new_generics = generics.clone();
139+
let where_clause = new_generics.make_where_clause();
140+
where_clause
141+
.predicates
142+
.push(syn::parse_quote! { #inner_ty: ::openvm_circuit::arch::InsExecutorE1<F> });
143+
quote! {
144+
impl #impl_generics ::openvm_circuit::arch::InsExecutorE1<F> for #name #ty_generics #where_clause {
145+
fn execute_e1<Mem, Ctx>(
146+
&mut self,
147+
state: ::openvm_circuit::arch::execution::VmStateMut<Mem, Ctx>,
148+
instruction: &::openvm_circuit::arch::instructions::instruction::Instruction<F>,
149+
) -> ::openvm_circuit::arch::Result<()>
150+
where
151+
Mem: ::openvm_circuit::system::memory::online::GuestMemory,
152+
F: ::openvm_stark_backend::p3_field::PrimeField32
153+
{
154+
self.0.execute_e1(state, instruction)
155+
}
156+
}
157+
}
158+
.into()
159+
}
160+
Data::Enum(e) => {
161+
let variants = e
162+
.variants
163+
.iter()
164+
.map(|variant| {
165+
let variant_name = &variant.ident;
166+
167+
let mut fields = variant.fields.iter();
168+
let field = fields.next().unwrap();
169+
assert!(fields.next().is_none(), "Only one field is supported");
170+
(variant_name, field)
171+
})
172+
.collect::<Vec<_>>();
173+
let first_ty_generic = ast
174+
.generics
175+
.params
176+
.first()
177+
.and_then(|param| match param {
178+
GenericParam::Type(type_param) => Some(&type_param.ident),
179+
_ => None,
180+
})
181+
.expect("First generic must be type for Field");
182+
// Use full path ::openvm_circuit... so it can be used either within or outside the vm
183+
// crate. Assume F is already generic of the field.
184+
let execute_arms = variants.iter().map(|(variant_name, field)| {
185+
let field_ty = &field.ty;
186+
quote! {
187+
#name::#variant_name(x) => <#field_ty as ::openvm_circuit::arch::InsExecutorE1<#first_ty_generic>>::execute_e1(x, state, instruction)
188+
}
189+
}).collect::<Vec<_>>();
190+
191+
quote! {
192+
impl #impl_generics ::openvm_circuit::arch::InsExecutorE1<#first_ty_generic> for #name #ty_generics {
193+
fn execute_e1<Mem, Ctx>(
194+
&mut self,
195+
state: ::openvm_circuit::arch::execution::VmStateMut<Mem, Ctx>,
196+
instruction: &::openvm_circuit::arch::instructions::instruction::Instruction<#first_ty_generic>,
197+
) -> ::openvm_circuit::arch::Result<()>
198+
where
199+
Mem: ::openvm_circuit::system::memory::online::GuestMemory,
200+
#first_ty_generic: ::openvm_stark_backend::p3_field::PrimeField32
201+
{
202+
match self {
203+
#(#execute_arms,)*
204+
}
205+
}
206+
}
207+
}
208+
.into()
209+
}
210+
Data::Union(_) => unimplemented!("Unions are not supported"),
211+
}
212+
}
213+
116214
/// Derives `AnyEnum` trait on an enum type.
117215
/// By default an enum arm will just return `self` as `&dyn Any`.
118216
///
@@ -347,7 +445,7 @@ pub fn vm_generic_config_derive(input: proc_macro::TokenStream) -> proc_macro::T
347445
let periphery_type = Ident::new(&format!("{}Periphery", name), name.span());
348446

349447
TokenStream::from(quote! {
350-
#[derive(::openvm_circuit::circuit_derive::ChipUsageGetter, ::openvm_circuit::circuit_derive::Chip, ::openvm_circuit::derive::InstructionExecutor, ::derive_more::derive::From, ::openvm_circuit::derive::AnyEnum)]
448+
#[derive(::openvm_circuit::circuit_derive::ChipUsageGetter, ::openvm_circuit::circuit_derive::Chip, ::openvm_circuit::derive::InstructionExecutor, ::openvm_circuit::derive::InsExecutorE1, ::derive_more::derive::From, ::openvm_circuit::derive::AnyEnum)]
351449
pub enum #executor_type<F: PrimeField32> {
352450
#[any_enum]
353451
#source_name_upper(#source_executor_type<F>),

crates/vm/src/arch/execution.rs

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use openvm_stark_backend::{
1111
use serde::{Deserialize, Serialize};
1212
use thiserror::Error;
1313

14-
use super::{Streams, VmExecutionState};
14+
use super::Streams;
1515
use crate::system::{
1616
memory::{
1717
online::{GuestMemory, TracingMemory},
@@ -79,6 +79,7 @@ pub enum ExecutionError {
7979
/// Global VM state accessible during instruction execution.
8080
/// The state is generic in guest memory `MEM` and additional host state `CTX`.
8181
/// The host state is execution context specific.
82+
#[derive(derive_new::new)]
8283
pub struct VmStateMut<'a, MEM, CTX> {
8384
pub pc: &'a mut u32,
8485
pub memory: &'a mut MEM,
@@ -111,16 +112,32 @@ pub trait InstructionExecutor<F> {
111112
}
112113

113114
/// New trait for instruction execution
114-
pub trait InsExecutorE1<Mem, Ctx, F>
115+
pub trait InsExecutorE1<F> {
116+
fn execute_e1<Mem, Ctx>(
117+
&mut self,
118+
state: VmStateMut<Mem, Ctx>,
119+
instruction: &Instruction<F>,
120+
) -> Result<()>
121+
where
122+
Mem: GuestMemory,
123+
F: PrimeField32;
124+
}
125+
126+
impl<F, C> InsExecutorE1<F> for RefCell<C>
115127
where
116-
Mem: GuestMemory,
117-
F: PrimeField32,
128+
C: InsExecutorE1<F>,
118129
{
119-
fn execute_e1(
130+
fn execute_e1<Mem, Ctx>(
120131
&mut self,
121-
state: &mut VmExecutionState<Mem, Ctx>,
132+
state: VmStateMut<Mem, Ctx>,
122133
instruction: &Instruction<F>,
123-
) -> Result<()>;
134+
) -> Result<()>
135+
where
136+
Mem: GuestMemory,
137+
F: PrimeField32,
138+
{
139+
self.borrow_mut().execute_e1(state, instruction)
140+
}
124141
}
125142

126143
impl<F, C: InstructionExecutor<F>> InstructionExecutor<F> for RefCell<C> {

0 commit comments

Comments
 (0)