mirror of
https://github.com/HigherOrderCO/Bend.git
synced 2024-11-05 04:51:40 +03:00
Add manual toggle for optimizations
This commit is contained in:
parent
68bd80709d
commit
69380a3471
86
src/lib.rs
86
src/lib.rs
@ -22,22 +22,26 @@ pub use term::load_book::load_file_to_book;
|
||||
|
||||
pub fn check_book(mut book: Book) -> Result<(), String> {
|
||||
// TODO: Do the checks without having to do full compilation
|
||||
compile_book(&mut book, OptimizationLevel::Light)?;
|
||||
compile_book(&mut book, Opts::light())?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn compile_book(book: &mut Book, opt_level: OptimizationLevel) -> Result<CompileResult, String> {
|
||||
let (main, warnings) = desugar_book(book, opt_level)?;
|
||||
pub fn compile_book(book: &mut Book, opts: Opts) -> Result<CompileResult, String> {
|
||||
let (main, warnings) = desugar_book(book, opts)?;
|
||||
let (nets, hvmc_names, labels) = book_to_nets(book, main);
|
||||
let mut core_book = nets_to_hvmc(nets, &hvmc_names)?;
|
||||
pre_reduce_book(&mut core_book, opt_level >= OptimizationLevel::Heavy)?;
|
||||
if opt_level >= OptimizationLevel::Heavy {
|
||||
pre_reduce_book(&mut core_book, opts.pre_reduce)?;
|
||||
if opts.prune {
|
||||
prune_defs(&mut core_book);
|
||||
}
|
||||
Ok(CompileResult { core_book, hvmc_names, labels, warnings })
|
||||
}
|
||||
|
||||
pub fn desugar_book(book: &mut Book, opt_level: OptimizationLevel) -> Result<(DefId, Vec<Warning>), String> {
|
||||
|
||||
pub fn desugar_book(
|
||||
book: &mut Book,
|
||||
Opts { eta, ref_to_ref, prune, supercombinators, .. }: Opts,
|
||||
) -> Result<(DefId, Vec<Warning>), String> {
|
||||
let mut warnings = Vec::new();
|
||||
let main = book.check_has_main()?;
|
||||
book.check_shared_names()?;
|
||||
@ -50,13 +54,15 @@ pub fn desugar_book(book: &mut Book, opt_level: OptimizationLevel) -> Result<(De
|
||||
book.check_unbound_vars()?;
|
||||
book.make_var_names_unique();
|
||||
book.linearize_vars();
|
||||
book.eta_reduction(opt_level >= OptimizationLevel::Heavy);
|
||||
book.detach_supercombinators(main);
|
||||
if opt_level >= OptimizationLevel::Heavy {
|
||||
book.eta_reduction(eta);
|
||||
if supercombinators {
|
||||
book.detach_supercombinators(main);
|
||||
}
|
||||
if ref_to_ref {
|
||||
book.simplify_ref_to_ref()?;
|
||||
}
|
||||
book.simplify_main_ref(main);
|
||||
if opt_level >= OptimizationLevel::Heavy {
|
||||
if prune {
|
||||
book.prune(main);
|
||||
}
|
||||
Ok((main, warnings))
|
||||
@ -82,9 +88,9 @@ pub fn run_book(
|
||||
debug: bool,
|
||||
linear: bool,
|
||||
skip_warnings: bool,
|
||||
opt_level: OptimizationLevel,
|
||||
opts: Opts,
|
||||
) -> Result<(Term, DefNames, RunInfo), String> {
|
||||
let CompileResult { core_book, hvmc_names, labels, warnings } = compile_book(&mut book, opt_level)?;
|
||||
let CompileResult { core_book, hvmc_names, labels, warnings } = compile_book(&mut book, opts)?;
|
||||
|
||||
if !warnings.is_empty() {
|
||||
let warnings = warnings.iter().join("\n");
|
||||
@ -152,17 +158,55 @@ pub fn total_rewrites(rwrts: &Rewrites) -> usize {
|
||||
rwrts.anni + rwrts.comm + rwrts.eras + rwrts.dref + rwrts.oper
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)]
|
||||
pub enum OptimizationLevel {
|
||||
/// The minimum amount of transformations to produce valid hvmc outputs.
|
||||
Light,
|
||||
/// More aggressive optimizations.
|
||||
Heavy,
|
||||
#[derive(Clone, Copy, Debug, Default)]
|
||||
pub struct Opts {
|
||||
/// Enables [term::transform::eta_reduction].
|
||||
pub eta: bool,
|
||||
|
||||
/// Enables [term::transform::simplify_ref_to_ref].
|
||||
pub ref_to_ref: bool,
|
||||
|
||||
/// Enables [term::transform::definition_pruning] and [hvmc_net::prune].
|
||||
pub prune: bool,
|
||||
|
||||
/// Enables [hvmc_net::pre_reduce].
|
||||
pub pre_reduce: bool,
|
||||
|
||||
/// Enables [term::transform::detach_supercombinators].
|
||||
pub supercombinators: bool,
|
||||
}
|
||||
|
||||
impl From<usize> for OptimizationLevel {
|
||||
fn from(value: usize) -> Self {
|
||||
if value == 0 { OptimizationLevel::Light } else { OptimizationLevel::Heavy }
|
||||
impl Opts {
|
||||
/// All optimizations enabled.
|
||||
pub fn heavy() -> Self {
|
||||
Self { eta: true, ref_to_ref: true, prune: true, pre_reduce: true, supercombinators: true }
|
||||
}
|
||||
|
||||
/// All optimizations disabled, except detach supercombinators.
|
||||
pub fn light() -> Self {
|
||||
let mut this = Self::default();
|
||||
this.supercombinators = true;
|
||||
this
|
||||
}
|
||||
}
|
||||
|
||||
impl Opts {
|
||||
pub fn from_vec(&mut self, values: Vec<String>) -> Result<(), String> {
|
||||
for value in values {
|
||||
match value.as_ref() {
|
||||
"all" => *self = Opts::heavy(),
|
||||
"eta" => self.eta = true,
|
||||
"no-eta" => self.eta = false,
|
||||
"prune" => self.prune = true,
|
||||
"no-prune" => self.prune = false,
|
||||
"ref-to-ref" => self.ref_to_ref = true,
|
||||
"no-ref-to-ref" => self.ref_to_ref = false,
|
||||
"supercombinators" => self.supercombinators = true,
|
||||
"no-supercombinators" => self.supercombinators = false,
|
||||
other => return Err(format!("Unknown option '{other}'.")),
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
|
29
src/main.rs
29
src/main.rs
@ -1,8 +1,7 @@
|
||||
use clap::{Parser, ValueEnum};
|
||||
use hvmc::ast::{show_book, show_net};
|
||||
use hvml::{
|
||||
check_book, compile_book, desugar_book, load_file_to_book, run_book, total_rewrites, OptimizationLevel,
|
||||
RunInfo,
|
||||
check_book, compile_book, desugar_book, load_file_to_book, run_book, total_rewrites, Opts, RunInfo,
|
||||
};
|
||||
use std::path::PathBuf;
|
||||
|
||||
@ -32,8 +31,17 @@ struct Args {
|
||||
|
||||
#[arg(short = 'l', help = "Linear readback (show explicit dups)")]
|
||||
pub linear: bool,
|
||||
#[arg(short = 'O', default_value = "1", help = "Optimization level (0 or 1)", value_parser = opt_level_parser)]
|
||||
pub opt_level: OptimizationLevel,
|
||||
|
||||
#[arg(
|
||||
short = 'O',
|
||||
value_delimiter = ' ',
|
||||
action = clap::ArgAction::Append,
|
||||
long_help = r#"Enables or disables the given optimizations
|
||||
all, eta, no-eta, prune, no-prune, ref-to-ref, no-ref-to-ref,
|
||||
supercombinators (enabled by default), no-supercombinators
|
||||
"#,
|
||||
)]
|
||||
pub opts: Vec<String>,
|
||||
|
||||
#[arg(help = "Path to the input file")]
|
||||
pub path: PathBuf,
|
||||
@ -63,17 +71,14 @@ fn mem_parser(arg: &str) -> Result<usize, String> {
|
||||
Ok(base * mult)
|
||||
}
|
||||
|
||||
fn opt_level_parser(arg: &str) -> Result<OptimizationLevel, String> {
|
||||
let num = arg.parse::<usize>().map_err(|e| e.to_string())?;
|
||||
Ok(OptimizationLevel::from(num))
|
||||
}
|
||||
|
||||
fn main() {
|
||||
fn run() -> Result<(), String> {
|
||||
#[cfg(not(feature = "cli"))]
|
||||
compile_error!("The 'cli' feature is needed for the hvm-lang cli");
|
||||
|
||||
let args = Args::parse();
|
||||
let mut opts = Opts::light();
|
||||
Opts::from_vec(&mut opts, args.opts)?;
|
||||
|
||||
let mut book = load_file_to_book(&args.path)?;
|
||||
if args.verbose {
|
||||
@ -85,7 +90,7 @@ fn main() {
|
||||
check_book(book)?;
|
||||
}
|
||||
Mode::Compile => {
|
||||
let compiled = compile_book(&mut book, args.opt_level)?;
|
||||
let compiled = compile_book(&mut book, opts)?;
|
||||
|
||||
for warn in &compiled.warnings {
|
||||
eprintln!("WARNING: {warn}");
|
||||
@ -94,13 +99,13 @@ fn main() {
|
||||
print!("{}", show_book(&compiled.core_book));
|
||||
}
|
||||
Mode::Desugar => {
|
||||
desugar_book(&mut book, args.opt_level)?;
|
||||
desugar_book(&mut book, opts)?;
|
||||
println!("{book}");
|
||||
}
|
||||
Mode::Run => {
|
||||
let mem_size = args.mem / std::mem::size_of::<(hvmc::run::APtr, hvmc::run::APtr)>();
|
||||
let (res_term, def_names, info) =
|
||||
run_book(book, mem_size, !args.single_core, args.debug, args.linear, args.skip_warnings, args.opt_level)?;
|
||||
run_book(book, mem_size, !args.single_core, args.debug, args.linear, args.skip_warnings,opts)?;
|
||||
let RunInfo { stats, readback_errors, net: lnet } = info;
|
||||
let total_rewrites = total_rewrites(&stats.rewrites) as f64;
|
||||
let rps = total_rewrites / stats.run_time / 1_000_000.0;
|
||||
|
@ -8,7 +8,7 @@ use hvml::{
|
||||
parser::{parse_definition_book, parse_term},
|
||||
term_to_compat_net, Book, DefId, Term,
|
||||
},
|
||||
OptimizationLevel,
|
||||
Opts,
|
||||
};
|
||||
use insta::assert_snapshot;
|
||||
use itertools::Itertools;
|
||||
@ -95,7 +95,7 @@ fn compile_term() {
|
||||
fn compile_file() {
|
||||
run_golden_test_dir(function_name!(), &|code| {
|
||||
let mut book = do_parse_book(code)?;
|
||||
let compiled = compile_book(&mut book, OptimizationLevel::Heavy)?;
|
||||
let compiled = compile_book(&mut book, Opts::heavy())?;
|
||||
Ok(format!("{:?}", compiled))
|
||||
})
|
||||
}
|
||||
@ -103,7 +103,7 @@ fn compile_file() {
|
||||
fn compile_file_o0() {
|
||||
run_golden_test_dir(function_name!(), &|code| {
|
||||
let mut book = do_parse_book(code)?;
|
||||
let compiled = compile_book(&mut book, OptimizationLevel::Light)?;
|
||||
let compiled = compile_book(&mut book, Opts::light())?;
|
||||
Ok(format!("{:?}", compiled))
|
||||
})
|
||||
}
|
||||
@ -113,7 +113,7 @@ fn run_file() {
|
||||
run_golden_test_dir(function_name!(), &|code| {
|
||||
let book = do_parse_book(code)?;
|
||||
// 1 million nodes for the test runtime. Smaller doesn't seem to make it any faster
|
||||
let (res, def_names, info) = run_book(book, 1 << 20, true, false, false, false, OptimizationLevel::Heavy)?;
|
||||
let (res, def_names, info) = run_book(book, 1 << 20, true, false, false, false, Opts::heavy())?;
|
||||
let res = if info.readback_errors.is_empty() {
|
||||
res.display(&def_names).to_string()
|
||||
} else {
|
||||
|
Loading…
Reference in New Issue
Block a user