diff --git a/powdr/src/lib.rs b/powdr/src/lib.rs index fbb1cbf71..8473f5359 100644 --- a/powdr/src/lib.rs +++ b/powdr/src/lib.rs @@ -28,10 +28,37 @@ pub struct Session { const DEFAULT_PKEY: &str = "pkey.bin"; const DEFAULT_VKEY: &str = "vkey.bin"; +// Minimum and maximum log of number of rows for the RISCV machine. +const DEFAULT_MIN_DEGREE_LOG: u32 = 5; +const DEFAULT_MAX_DEGREE_LOG: u32 = 20; +// Minimum acceptable max degree. +const DEFAULT_MIN_MAX_DEGREE_LOG: u32 = 18; + impl Session { pub fn new(guest_path: &str, out_path: &str) -> Self { Session { - pipeline: pipeline_from_guest(guest_path, Path::new(out_path)), + pipeline: pipeline_from_guest( + guest_path, + Path::new(out_path), + DEFAULT_MIN_DEGREE_LOG, + DEFAULT_MAX_DEGREE_LOG, + ), + out_path: out_path.into(), + } + .with_backend(powdr_backend::BackendType::Plonky3) + } + + /// Create a new session with a specific chunk size, represented by its log2. + /// Example: for a chunk size of 2^20, set chunk_size_log to 20. + pub fn new_with_chunk_size(guest_path: &str, out_path: &str, chunk_size_log: u32) -> Self { + assert!(chunk_size_log >= DEFAULT_MIN_MAX_DEGREE_LOG); + Session { + pipeline: pipeline_from_guest( + guest_path, + Path::new(out_path), + DEFAULT_MIN_DEGREE_LOG, + chunk_size_log, + ), out_path: out_path.into(), } .with_backend(powdr_backend::BackendType::Plonky3) @@ -137,12 +164,19 @@ fn pil_file_path(asm_name: &Path) -> PathBuf { asm_name.with_file_name(opt_file_stem).with_extension("pil") } -pub fn build_guest(guest_path: &str, out_path: &Path) -> (PathBuf, String) { +pub fn build_guest( + guest_path: &str, + out_path: &Path, + min_degree_log: u32, + max_degree_log: u32, +) -> (PathBuf, String) { riscv::compile_rust( guest_path, CompilerOptions::new_gl() .with_poseidon() - .with_continuations(), + .with_continuations() + .with_min_degree_log(min_degree_log) + .with_max_degree_log(max_degree_log), out_path, true, None, @@ -151,10 +185,16 @@ pub fn build_guest(guest_path: &str, out_path: &Path) -> (PathBuf, String) { .unwrap() } -pub fn pipeline_from_guest(guest_path: &str, out_path: &Path) -> Pipeline { +pub fn pipeline_from_guest( + guest_path: &str, + out_path: &Path, + min_degree_log: u32, + max_degree_log: u32, +) -> Pipeline { log::info!("Compiling guest program..."); - let (asm_file_path, asm_contents) = build_guest(guest_path, out_path); + let (asm_file_path, asm_contents) = + build_guest(guest_path, out_path, min_degree_log, max_degree_log); // Create a pipeline from the asm program Pipeline::::default() diff --git a/riscv/benches/executor_benchmark.rs b/riscv/benches/executor_benchmark.rs index 9e5f4e451..c3421ed43 100644 --- a/riscv/benches/executor_benchmark.rs +++ b/riscv/benches/executor_benchmark.rs @@ -19,7 +19,7 @@ fn executor_benchmark(c: &mut Criterion) { let executable = compile_rust_crate_to_riscv("./tests/riscv_data/keccak/Cargo.toml", &tmp_dir, None); let options = CompilerOptions::new_gl(); - let contents = elf::translate(&executable, options.clone()); + let contents = elf::translate(&executable, options); let mut pipeline = Pipeline::::default().from_asm_string(contents, None); pipeline.compute_optimized_pil().unwrap(); pipeline.compute_fixed_cols().unwrap(); diff --git a/riscv/src/large_field/code_gen.rs b/riscv/src/large_field/code_gen.rs index 9f2a12731..692e20a48 100644 --- a/riscv/src/large_field/code_gen.rs +++ b/riscv/src/large_field/code_gen.rs @@ -25,6 +25,7 @@ pub fn translate_program(program: impl RiscVProgram, options: CompilerOptions) - translate_program_impl(program, options.field, &runtime, options.continuations); riscv_machine( + options, &runtime, &preamble(options.field, &runtime, options.continuations), initial_mem, @@ -184,6 +185,7 @@ fn translate_program_impl( } fn riscv_machine( + options: CompilerOptions, runtime: &Runtime, preamble: &str, initial_memory: Vec, @@ -207,11 +209,15 @@ let initial_memory: (fe, fe)[] = [ }} "#, runtime.submachines_import(), - 1 << powdr_linker::MIN_DEGREE_LOG, + 1 << (options + .min_degree_log + .unwrap_or(powdr_linker::MIN_DEGREE_LOG as u32)), // We expect some machines (e.g. register memory) to use up to 4x the number // of rows as main. By setting the max degree of main to be smaller by a factor // of 4, we ensure that we don't run out of rows in those machines. - 1 << (*powdr_linker::MAX_DEGREE_LOG - 2), + 1 << options + .max_degree_log + .unwrap_or(*powdr_linker::MAX_DEGREE_LOG as u32 - 2), runtime.submachines_declare(), preamble, initial_memory diff --git a/riscv/src/lib.rs b/riscv/src/lib.rs index 13d8147a1..0d44477f5 100644 --- a/riscv/src/lib.rs +++ b/riscv/src/lib.rs @@ -21,7 +21,7 @@ pub mod small_field; static TARGET_STD: &str = "riscv32im-risc0-zkvm-elf"; static TARGET_NO_STD: &str = "riscv32imac-unknown-none-elf"; -#[derive(Default, Clone)] +#[derive(Copy, Default, Clone)] pub struct RuntimeLibs { pub arith: bool, pub keccak: bool, @@ -58,11 +58,13 @@ impl RuntimeLibs { } } } -#[derive(Clone)] +#[derive(Copy, Clone)] pub struct CompilerOptions { pub field: KnownField, pub libs: RuntimeLibs, pub continuations: bool, + pub min_degree_log: Option, + pub max_degree_log: Option, } impl CompilerOptions { @@ -71,6 +73,8 @@ impl CompilerOptions { field, libs, continuations, + min_degree_log: None, + max_degree_log: None, } } @@ -79,6 +83,8 @@ impl CompilerOptions { field: KnownField::BabyBearField, libs: RuntimeLibs::new(), continuations: false, + min_degree_log: None, + max_degree_log: None, } } @@ -87,6 +93,22 @@ impl CompilerOptions { field: KnownField::GoldilocksField, libs: RuntimeLibs::new(), continuations: false, + min_degree_log: None, + max_degree_log: None, + } + } + + pub fn with_min_degree_log(self, log_min_degree: u32) -> Self { + Self { + min_degree_log: Some(log_min_degree), + ..self + } + } + + pub fn with_max_degree_log(self, log_max_degree: u32) -> Self { + Self { + max_degree_log: Some(log_max_degree), + ..self } } diff --git a/riscv/tests/common/mod.rs b/riscv/tests/common/mod.rs index 33cbc2bd8..dbbb4dbf8 100644 --- a/riscv/tests/common/mod.rs +++ b/riscv/tests/common/mod.rs @@ -95,7 +95,7 @@ pub fn verify_riscv_asm_file(asm_file: &Path, options: CompilerOptions, use_pie: let case_name = asm_file.file_stem().unwrap().to_str().unwrap(); - let powdr_asm = powdr_riscv::elf::translate(&executable, options.clone()); + let powdr_asm = powdr_riscv::elf::translate(&executable, options); match options.field { KnownField::BabyBearField => { diff --git a/riscv/tests/riscv.rs b/riscv/tests/riscv.rs index 5933ce071..fd7cba448 100644 --- a/riscv/tests/riscv.rs +++ b/riscv/tests/riscv.rs @@ -386,7 +386,7 @@ fn features_with_options(options: CompilerOptions) { ); log::info!("Verifying {case} converted from ELF file"); - let from_elf = powdr_riscv::elf::translate(&executable, options.clone()); + let from_elf = powdr_riscv::elf::translate(&executable, options); verify_riscv_asm_string::( &format!("{case}_from_elf.asm"), &from_elf, @@ -403,7 +403,7 @@ fn features_with_options(options: CompilerOptions) { ); log::info!("Verifying {case} converted from ELF file"); - let from_elf = powdr_riscv::elf::translate(&executable, options.clone()); + let from_elf = powdr_riscv::elf::translate(&executable, options); verify_riscv_asm_string::( &format!("{case}_from_elf.asm"), &from_elf,