Merge pull request #293 from powdr-org/combine_pil_and_asm

Combine CLI for pil and asm compilation.
This commit is contained in:
Leo
2023-05-23 12:15:55 +02:00
committed by GitHub
2 changed files with 73 additions and 70 deletions

View File

@@ -18,6 +18,25 @@ pub fn no_callback<T>() -> Option<fn(&str) -> Option<T>> {
None
}
/// Compiles a .pil or .asm file and runs witness generation.
/// If the file ends in .asm, converts it to .pil first.
pub fn compile_pil_or_asm<T: FieldElement>(
file_name: &str,
inputs: Vec<T>,
output_dir: &Path,
force_overwrite: bool,
) {
if file_name.ends_with(".asm") {
compile_asm(file_name, inputs, output_dir, force_overwrite)
} else {
compile_pil(
Path::new(file_name),
output_dir,
Some(inputs_to_query_callback(inputs)),
);
}
}
/// Compiles a .pil file to its json form and also tries to generate
/// constants and committed polynomials.
/// @returns true if all committed/witness and constant/fixed polynomials
@@ -90,31 +109,11 @@ pub fn compile_asm_string<T: FieldElement>(
}
fs::write(pil_file_name.clone(), format!("{pil}")).unwrap();
let query_callback = |query: &str| -> Option<T> {
let items = query.split(',').map(|s| s.trim()).collect::<Vec<_>>();
match items[0] {
"\"input\"" => {
assert_eq!(items.len(), 2);
let index = items[1].parse::<usize>().unwrap();
let value = inputs.get(index).cloned();
if let Some(value) = value {
log::trace!("Input query: Index {index} -> {value}");
}
value
}
"\"print_char\"" => {
assert_eq!(items.len(), 2);
print!("{}", items[1].parse::<u8>().unwrap() as char);
Some(0.into())
}
_ => None,
}
};
compile_pil_ast(
&pil,
pil_file_name.file_name().unwrap(),
output_dir,
Some(query_callback),
Some(inputs_to_query_callback(inputs)),
);
}
@@ -174,3 +173,26 @@ fn write_polys_file<T: FieldElement>(
}
}
}
fn inputs_to_query_callback<T: FieldElement>(inputs: Vec<T>) -> impl Fn(&str) -> Option<T> {
move |query: &str| -> Option<T> {
let items = query.split(',').map(|s| s.trim()).collect::<Vec<_>>();
match items[0] {
"\"input\"" => {
assert_eq!(items.len(), 2);
let index = items[1].parse::<usize>().unwrap();
let value = inputs.get(index).cloned();
if let Some(value) = value {
log::trace!("Input query: Index {index} -> {value}");
}
value
}
"\"print_char\"" => {
assert_eq!(items.len(), 2);
print!("{}", items[1].parse::<u8>().unwrap() as char);
Some(0.into())
}
_ => None,
}
}
}

View File

@@ -1,7 +1,6 @@
//! The powdr CLI tool
use clap::{Parser, Subcommand};
use compiler::no_callback;
use env_logger::{Builder, Target};
use log::LevelFilter;
use number::{FieldElement, GoldilocksField};
@@ -16,6 +15,29 @@ struct Cli {
#[derive(Subcommand)]
enum Commands {
/// Runs compilation and witness generation for .pil and .asm files.
/// First converts .asm files to .pil, if needed.
/// Then converts the .pil file to json and generates fixed and witness column data files.
Pil {
/// Input file
file: String,
/// Output directory for the PIL file, json file and fixed and witness column data.
#[arg(short, long)]
#[arg(default_value_t = String::from("."))]
output_directory: String,
/// Comma-separated list of free inputs (numbers). Assumes queries to have the form
/// ("input", <index>).
#[arg(short, long)]
#[arg(default_value_t = String::new())]
inputs: String,
/// Force overwriting of PIL output file.
#[arg(short, long)]
#[arg(default_value_t = false)]
force: bool,
},
/// Compiles (no-std) rust code to riscv assembly, then to powdr assembly
/// and finally to PIL and generates fixed and witness columns.
/// Needs `rustup target add riscv32imc-unknown-none-elf`.
@@ -61,42 +83,11 @@ enum Commands {
force: bool,
},
/// Compiles assembly to PIL and generates fixed and witness columns.
Asm {
/// Input file
file: String,
/// Comma-separated list of free inputs (numbers).
#[arg(short, long)]
#[arg(default_value_t = String::new())]
inputs: String,
/// Output directory for PIL file, json file and fixed and witness column data.
#[arg(short, long)]
#[arg(default_value_t = String::from("."))]
output_directory: String,
/// Force overwriting of PIL output file.
#[arg(short, long)]
#[arg(default_value_t = false)]
force: bool,
},
/// Parses and prints the PIL file on stdout.
Reformat {
/// Input file
file: String,
},
/// Compiles the PIL file to json and generates fixed and witness columns.
Compile {
/// Input file
file: String,
/// Output directory for json file and fixed and witness column data.
#[arg(short, long)]
#[arg(default_value_t = String::from("."))]
output_directory: String,
},
}
fn split_inputs<T: FieldElement>(inputs: &str) -> Vec<T> {
@@ -146,19 +137,6 @@ fn main() {
force,
);
}
Commands::Asm {
file,
inputs,
output_directory,
force,
} => {
compiler::compile_asm::<GoldilocksField>(
&file,
split_inputs(&inputs),
Path::new(&output_directory),
force,
);
}
Commands::Reformat { file } => {
let contents = fs::read_to_string(&file).unwrap();
match parser::parse::<GoldilocksField>(Some(&file), &contents) {
@@ -166,14 +144,17 @@ fn main() {
Err(err) => err.output_to_stderr(),
}
}
Commands::Compile {
Commands::Pil {
file,
output_directory,
inputs,
force,
} => {
compiler::compile_pil::<GoldilocksField>(
Path::new(&file),
compiler::compile_pil_or_asm::<GoldilocksField>(
&file,
split_inputs(&inputs),
Path::new(&output_directory),
no_callback(),
force,
);
}
}