From 6ff2089cfaacd267a8e45161d950754cdac86eaf Mon Sep 17 00:00:00 2001 From: calebmkim <55243755+calebmkim@users.noreply.github.com> Date: Tue, 4 Jun 2024 12:17:38 -0400 Subject: [PATCH] Pass Reorder Option (#2075) * reorder pass options * interp bug * clippy * clippy again * some more erros * redo this --- calyx-opt/src/pass_manager.rs | 53 ++++++++++++++++++++++++++++++++--- interp/src/debugger/cidr.rs | 2 +- interp/src/main.rs | 2 +- src/cmdline.rs | 4 +++ src/main.rs | 8 +++++- web/rust/src/lib.rs | 2 +- 6 files changed, 63 insertions(+), 8 deletions(-) diff --git a/calyx-opt/src/pass_manager.rs b/calyx-opt/src/pass_manager.rs index ccfa2f2a72..709d38ee5b 100644 --- a/calyx-opt/src/pass_manager.rs +++ b/calyx-opt/src/pass_manager.rs @@ -150,9 +150,22 @@ impl PassManager { &self, incls: &[String], excls: &[String], + insns: &[String], ) -> CalyxResult<(Vec, HashSet)> { - // Incls and excls can both have aliases in them. Resolve them. - let passes = incls + let mut insertions = insns + .iter() + .filter_map(|str| match str.split_once(':') { + Some((before, after)) => { + Some((before.to_string(), after.to_string())) + } + None => { + log::warn!("No ':' in {str}. Ignoring this option."); + None + } + }) + .collect::>(); + // Incls and excls can have aliases in them. Resolve them. + let mut passes = incls .iter() .flat_map(|maybe_alias| self.resolve_alias(maybe_alias)) .collect::>(); @@ -163,7 +176,7 @@ impl PassManager { .collect::>(); // Validate that names of passes in incl and excl sets are known - passes.iter().chain(excl_set.iter()).try_for_each(|pass| { + passes.iter().chain(excl_set.iter().chain(insertions.iter().flat_map(|(pass1, pass2)| vec![pass1, pass2]))).try_for_each(|pass| { if !self.passes.contains_key(pass) { Err(Error::misc(format!( "Unknown pass: {pass}. Run compiler with pass-help subcommand to view registered passes." @@ -173,18 +186,50 @@ impl PassManager { } })?; + // Remove passes from `insertions` that are not slated to run. + insertions.retain(|(pass1, pass2)| + if !passes.contains(pass1) || excl_set.contains(pass1) { + log::warn!("Pass {pass1} is not slated to run. Reordering will have no effect."); + false + } + else if !passes.contains(pass2) || excl_set.contains(pass2) { + log::warn!("Pass {pass2} is not slated to run. Reordering will have no effect."); + false + } + else { + true + } + ); + + // Perform re-insertion. + // Insert `after` right after `before`. If `after` already appears after + // before, do nothing. + for (before, after) in insertions { + let before_idx = + passes.iter().position(|pass| *pass == before).unwrap(); + let after_idx = + passes.iter().position(|pass| *pass == after).unwrap(); + // Only need to perform re-insertion if it is actually out of order. + if before_idx > after_idx { + passes.insert(before_idx + 1, after); + passes.remove(after_idx); + } + } + Ok((passes, excl_set)) } /// Executes a given "plan" constructed using the incl and excl lists. + /// ord is a relative ordering that should be enforced. pub fn execute_plan( &self, ctx: &mut ir::Context, incl: &[String], excl: &[String], + insn: &[String], dump_ir: bool, ) -> CalyxResult<()> { - let (passes, excl_set) = self.create_plan(incl, excl)?; + let (passes, excl_set) = self.create_plan(incl, excl, insn)?; for name in passes { // Pass is known to exist because create_plan validates the diff --git a/interp/src/debugger/cidr.rs b/interp/src/debugger/cidr.rs index b8409fca63..37fcfb7c8d 100644 --- a/interp/src/debugger/cidr.rs +++ b/interp/src/debugger/cidr.rs @@ -102,7 +102,7 @@ impl Debugger { let pm = PassManager::default_passes()?; // if !opts.skip_verification - pm.execute_plan(&mut ctx, &["validate".to_string()], &[], false)?; + pm.execute_plan(&mut ctx, &["validate".to_string()], &[], &[], false)?; let entry_point = ctx.entrypoint; diff --git a/interp/src/main.rs b/interp/src/main.rs index c19ae5b322..f3e9a19b38 100644 --- a/interp/src/main.rs +++ b/interp/src/main.rs @@ -147,7 +147,7 @@ fn main() -> InterpreterResult<()> { let pm = PassManager::default_passes()?; if !opts.skip_verification { - pm.execute_plan(&mut ctx, &["validate".to_string()], &[], false)?; + pm.execute_plan(&mut ctx, &["validate".to_string()], &[], &[], false)?; } let command = opts.comm.unwrap_or(Command::Interpret(CommandInterpret {})); diff --git a/src/cmdline.rs b/src/cmdline.rs index 3520becdc4..0461823de1 100644 --- a/src/cmdline.rs +++ b/src/cmdline.rs @@ -91,6 +91,10 @@ pub struct Opts { #[argh(option, short = 'x', long = "extra-opt")] pub extra_opts: Vec, + /// establish a relative ordering of passes + #[argh(option, short = 'i', long = "insert")] + pub insertions: Vec, + /// enable verbose printing #[argh(option, long = "log", default = "log::LevelFilter::Warn")] pub log_level: log::LevelFilter, diff --git a/src/main.rs b/src/main.rs index f0e4eb41d4..4317f9222e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -74,7 +74,13 @@ fn main() -> CalyxResult<()> { ctx.extra_opts = opts.extra_opts.drain(..).collect(); // Run all passes specified by the command line - pm.execute_plan(&mut ctx, &opts.pass, &opts.disable_pass, opts.dump_ir)?; + pm.execute_plan( + &mut ctx, + &opts.pass, + &opts.disable_pass, + &opts.insertions, + opts.dump_ir, + )?; // Print out the Calyx program after transformation. if opts.backend == BackendOpt::Calyx { diff --git a/web/rust/src/lib.rs b/web/rust/src/lib.rs index 714ca3f1f3..bf43e76bf9 100644 --- a/web/rust/src/lib.rs +++ b/web/rust/src/lib.rs @@ -40,7 +40,7 @@ fn compile( // Build the IR representation let mut rep = ir::from_ast::ast_to_ir(ws)?; - pm.execute_plan(&mut rep, passes, &[], false)?; + pm.execute_plan(&mut rep, passes, &[], &[], false)?; let mut buffer: Vec = vec![]; for comp in &rep.components {