Skip to content

Commit

Permalink
compiler options and codegen split
Browse files Browse the repository at this point in the history
  • Loading branch information
leonardoalt committed Oct 8, 2024
1 parent 01f90f1 commit 5f2bd16
Show file tree
Hide file tree
Showing 18 changed files with 3,281 additions and 2,988 deletions.
118 changes: 63 additions & 55 deletions cli-rs/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,9 @@ use env_logger::fmt::Color;
use env_logger::{Builder, Target};
use log::LevelFilter;

use powdr_number::{BigUint, Bn254Field, FieldElement, GoldilocksField};
use powdr_number::{BabyBearField, BigUint, Bn254Field, FieldElement, GoldilocksField, KnownField};
use powdr_pipeline::Pipeline;
use powdr_riscv::{CompilerOptions, RuntimeLibs};
use powdr_riscv_executor::ProfilerOptions;

use std::ffi::OsStr;
Expand All @@ -20,12 +21,24 @@ use strum::{Display, EnumString, EnumVariantNames};

#[derive(Clone, EnumString, EnumVariantNames, Display)]
pub enum FieldArgument {
#[strum(serialize = "bb")]
Bb,
#[strum(serialize = "gl")]
Gl,
#[strum(serialize = "bn254")]
Bn254,
}

impl FieldArgument {
pub fn as_known_field(&self) -> KnownField {
match self {
FieldArgument::Bb => KnownField::BabyBearField,
FieldArgument::Gl => KnownField::GoldilocksField,
FieldArgument::Bn254 => KnownField::Bn254Field,
}
}
}

#[derive(Parser)]
#[command(name = "powdr-rs", author, version, about, long_about = None)]
struct Cli {
Expand Down Expand Up @@ -196,28 +209,26 @@ fn run_command(command: Commands) {
output_directory,
coprocessors,
continuations,
} => {
call_with_field!(compile_rust::<field>(
&file,
Path::new(&output_directory),
coprocessors,
continuations
))
}
} => compile_rust(
&file,
field.as_known_field(),
Path::new(&output_directory),
coprocessors,
continuations,
),
Commands::RiscvElf {
file,
field,
output_directory,
coprocessors,
continuations,
} => {
call_with_field!(compile_riscv_elf::<field>(
&file,
Path::new(&output_directory),
coprocessors,
continuations
))
}
} => compile_riscv_elf(
&file,
field.as_known_field(),
Path::new(&output_directory),
coprocessors,
continuations,
),
Commands::Execute {
file,
field,
Expand All @@ -243,6 +254,7 @@ fn run_command(command: Commands) {
};
call_with_field!(execute::<field>(
Path::new(&file),
field.as_known_field(),
split_inputs(&inputs),
Path::new(&output_directory),
continuations,
Expand All @@ -260,63 +272,40 @@ fn run_command(command: Commands) {
}

#[allow(clippy::too_many_arguments)]
fn compile_rust<F: FieldElement>(
fn compile_rust(
file_name: &str,
field: KnownField,
output_dir: &Path,
coprocessors: Option<String>,
continuations: bool,
) -> Result<(), Vec<String>> {
let mut runtime = match coprocessors {
Some(list) => {
powdr_riscv::Runtime::try_from(list.split(',').collect::<Vec<_>>().as_ref()).unwrap()
}
None => powdr_riscv::Runtime::base(),
};

if continuations {
if runtime.has_submachine("poseidon_gl") {
return Err(vec![
"Poseidon continuations mode is chosen automatically and incompatible with the chosen standard Poseidon coprocessor".to_string(),
]);
}
runtime = runtime.with_poseidon_for_continuations();
}

powdr_riscv::compile_rust::<F>(file_name, output_dir, true, &runtime, continuations, None)
let libs = coprocessors_to_options(coprocessors)?;
let options = CompilerOptions::new(field, libs, continuations);
powdr_riscv::compile_rust(file_name, options, output_dir, true, None)
.ok_or_else(|| vec!["could not compile rust".to_string()])?;

Ok(())
}

fn compile_riscv_elf<F: FieldElement>(
fn compile_riscv_elf(
input_file: &str,
field: KnownField,
output_dir: &Path,
coprocessors: Option<String>,
continuations: bool,
) -> Result<(), Vec<String>> {
let runtime = match coprocessors {
Some(list) => {
powdr_riscv::Runtime::try_from(list.split(',').collect::<Vec<_>>().as_ref()).unwrap()
}
None => powdr_riscv::Runtime::base(),
};

powdr_riscv::compile_riscv_elf::<F>(
input_file,
Path::new(input_file),
output_dir,
true,
&runtime,
continuations,
)
.ok_or_else(|| vec!["could not translate RISC-V executable".to_string()])?;
let libs = coprocessors_to_options(coprocessors)?;
let options = CompilerOptions::new(field, libs, continuations);
powdr_riscv::compile_riscv_elf(input_file, Path::new(input_file), options, output_dir, true)
.ok_or_else(|| vec!["could not translate RISC-V executable".to_string()])?;

Ok(())
}

#[allow(clippy::too_many_arguments)]
fn execute<F: FieldElement>(
file_name: &Path,
field: KnownField,
inputs: Vec<F>,
output_dir: &Path,
continuations: bool,
Expand All @@ -335,7 +324,7 @@ fn execute<F: FieldElement>(

match (witness, continuations) {
(false, true) => {
powdr_riscv::continuations::rust_continuations_dry_run(&mut pipeline, profiling);
powdr_riscv::continuations::rust_continuations_dry_run(&mut pipeline, field, profiling);
}
(false, false) => {
let program = pipeline.compute_asm_string().unwrap().clone();
Expand All @@ -350,8 +339,11 @@ fn execute<F: FieldElement>(
log::info!("Execution trace length: {}", trace.len);
}
(true, true) => {
let dry_run =
powdr_riscv::continuations::rust_continuations_dry_run(&mut pipeline, profiling);
let dry_run = powdr_riscv::continuations::rust_continuations_dry_run(
&mut pipeline,
field,
profiling,
);
powdr_riscv::continuations::rust_continuations(pipeline, generate_witness, dry_run)?;
}
(true, false) => {
Expand All @@ -361,3 +353,19 @@ fn execute<F: FieldElement>(

Ok(())
}

fn coprocessors_to_options(coprocessors: Option<String>) -> Result<RuntimeLibs, Vec<String>> {
let mut libs = RuntimeLibs::new();
if let Some(list) = coprocessors {
let names = list.split(',').collect::<Vec<_>>();
for name in names {
match name {
"poseidon_gl" => libs = libs.with_poseidon(),
"keccakf" => libs = libs.with_keccak(),
"arith" => libs = libs.with_arith(),
_ => return Err(vec![format!("Invalid co-processor specified: {name}")]),
}
}
}
Ok(libs)
}
1 change: 1 addition & 0 deletions cli-rs/src/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ macro_rules! clap_enum_variants {
macro_rules! call_with_field {
($function:ident::<$field:ident>($($args:expr),*) ) => {
match $field {
FieldArgument::Bb => $function::<BabyBearField>($($args),*),
FieldArgument::Gl => $function::<GoldilocksField>($($args),*),
FieldArgument::Bn254 => $function::<Bn254Field>($($args),*),
}
Expand Down
2 changes: 1 addition & 1 deletion number/src/traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ pub trait LargeInt:
fn from_hex(s: &str) -> Self;
}

#[derive(Debug, PartialEq, Serialize, Deserialize)]
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub enum KnownField {
BabyBearField,
Mersenne31Field,
Expand Down
49 changes: 44 additions & 5 deletions pipeline/src/test_util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,21 +57,21 @@ pub fn make_prepared_pipeline<T: FieldElement>(
pipeline
}

/// Tests witness generation, pilcom, halo2 and estark.
/// Does NOT test plonky3.
/// Tests witness generation, pilcom, halo2, estark and plonky3.
pub fn regular_test(file_name: &str, inputs: &[i32]) {
let inputs_gl = inputs.iter().map(|x| GoldilocksField::from(*x)).collect();
let pipeline_gl = make_prepared_pipeline(file_name, inputs_gl, vec![]);
test_pilcom(pipeline_gl.clone());
gen_estark_proof(pipeline_gl);
gen_estark_proof(pipeline_gl.clone());
test_plonky3_pipeline(pipeline_gl);

let inputs_bn = inputs.iter().map(|x| Bn254Field::from(*x)).collect();
let pipeline_bn = make_prepared_pipeline(file_name, inputs_bn, vec![]);
test_halo2(pipeline_bn);

let inputs_bb = inputs.iter().map(|x| BabyBearField::from(*x)).collect();
let mut pipeline_bb = make_prepared_pipeline(file_name, inputs_bb, vec![]);
pipeline_bb.compute_witness().unwrap();
let pipeline_bb = make_prepared_pipeline(file_name, inputs_bb, vec![]);
test_plonky3_pipeline(pipeline_bb);
}

pub fn regular_test_without_babybear(file_name: &str, inputs: &[i32]) {
Expand Down Expand Up @@ -331,6 +331,45 @@ pub fn test_plonky3_with_backend_variant<T: FieldElement>(
}
}

#[cfg(feature = "plonky3")]
pub fn test_plonky3_pipeline<T: FieldElement>(pipeline: Pipeline<T>) {
let mut pipeline = pipeline.with_backend(powdr_backend::BackendType::Plonky3Composite, None);

pipeline.compute_witness().unwrap();

if !should_generate_proofs() {
return;
}

// Generate a proof
let proof = pipeline.compute_proof().cloned().unwrap();

let publics: Vec<T> = pipeline
.publics()
.clone()
.unwrap()
.iter()
.map(|(_name, v)| *v)
.collect();

pipeline.verify(&proof, &[publics.clone()]).unwrap();

if pipeline.optimized_pil().unwrap().constant_count() > 0 {
// Export verification Key
let output_dir = pipeline.output_dir().as_ref().unwrap();
let vkey_file_path = output_dir.join("verification_key.bin");
buffered_write_file(&vkey_file_path, |writer| {
pipeline.export_verification_key(writer).unwrap()
})
.unwrap();

let mut pipeline = pipeline.with_vkey_file(Some(vkey_file_path));

// Verify the proof again
pipeline.verify(&proof, &[publics]).unwrap();
}
}

#[cfg(not(feature = "plonky3"))]
pub fn test_plonky3_with_backend_variant<T: FieldElement>(_: &str, _: Vec<T>, _: BackendVariant) {}

Expand Down
6 changes: 3 additions & 3 deletions pipeline/tests/asm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ fn mem_write_once_external_write() {
#[test]
fn block_machine_cache_miss() {
let f = "asm/block_machine_cache_miss.asm";
regular_test(f, Default::default());
regular_test_without_babybear(f, Default::default());
}

#[test]
Expand Down Expand Up @@ -259,13 +259,13 @@ fn mem_read_write_no_memory_accesses() {
#[test]
fn mem_read_write_with_bootloader() {
let f = "asm/mem_read_write_with_bootloader.asm";
regular_test(f, Default::default());
regular_test_without_babybear(f, Default::default());
}

#[test]
fn mem_read_write_large_diffs() {
let f = "asm/mem_read_write_large_diffs.asm";
regular_test(f, Default::default());
regular_test_without_babybear(f, Default::default());
}

#[test]
Expand Down
12 changes: 5 additions & 7 deletions riscv/benches/executor_benchmark.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use ::powdr_pipeline::Pipeline;
use powdr_number::GoldilocksField;

use powdr_riscv::{
compile_rust_crate_to_riscv, continuations::bootloader::default_input, elf, Runtime,
compile_rust_crate_to_riscv, continuations::bootloader::default_input, elf, CompilerOptions,
};

use criterion::{criterion_group, criterion_main, Criterion};
Expand All @@ -18,7 +18,8 @@ fn executor_benchmark(c: &mut Criterion) {
let tmp_dir = Temp::new_dir().unwrap();
let executable =
compile_rust_crate_to_riscv("./tests/riscv_data/keccak/Cargo.toml", &tmp_dir, None);
let contents = elf::translate::<T>(&executable, &Runtime::base(), false);
let options = CompilerOptions::new_32();
let contents = elf::translate(&executable, options.clone());
let mut pipeline = Pipeline::<T>::default().from_asm_string(contents, None);
pipeline.compute_optimized_pil().unwrap();
pipeline.compute_fixed_cols().unwrap();
Expand All @@ -30,11 +31,8 @@ fn executor_benchmark(c: &mut Criterion) {
// The first chunk of `many_chunks`, with Poseidon co-processor & bootloader
let executable =
compile_rust_crate_to_riscv("./tests/riscv_data/many_chunks/Cargo.toml", &tmp_dir, None);
let contents = elf::translate::<T>(
&executable,
&Runtime::base().with_poseidon_for_continuations(),
true,
);
let options = options.with_continuations().with_poseidon();
let contents = elf::translate(&executable, options);
let mut pipeline = Pipeline::<T>::default().from_asm_string(contents, None);
pipeline.compute_optimized_pil().unwrap();
pipeline.compute_fixed_cols().unwrap();
Expand Down
Loading

0 comments on commit 5f2bd16

Please sign in to comment.