-
Notifications
You must be signed in to change notification settings - Fork 9
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
15 changed files
with
4,746 additions
and
50 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,129 @@ | ||
use std::fs; | ||
use std::path::Path; | ||
use std::rc::Rc; | ||
|
||
fn main() -> std::io::Result<()> { | ||
match &std::env::args().collect::<Vec<_>>()[..] { | ||
[_, in_file] => { | ||
let in_file_path = Path::new(in_file); | ||
|
||
let save_print_plan = |suffix: &str, plan: spirt::print::Plan| { | ||
let pretty = plan.pretty_print(); | ||
let ext = format!("{suffix}.spirt"); | ||
|
||
// FIXME(eddyb) don't allocate whole `String`s here. | ||
fs::write(in_file_path.with_extension(&ext), pretty.to_string())?; | ||
fs::write( | ||
in_file_path.with_extension(ext + ".html"), | ||
pretty | ||
.render_to_html() | ||
.with_dark_mode_support() | ||
.to_html_doc(), | ||
) | ||
}; | ||
|
||
// FIXME(eddyb) adapt the other examples to this style. | ||
|
||
fn eprint_duration<R>(f: impl FnOnce() -> R) -> R { | ||
let start = std::time::Instant::now(); | ||
let r = f(); | ||
eprint!("[{:8.3}ms] ", start.elapsed().as_secs_f64() * 1000.0); | ||
r | ||
} | ||
|
||
eprint_duration(|| { | ||
let _ = spirt::spv::spec::Spec::get(); | ||
}); | ||
eprintln!("spv::spec::Spec::get"); | ||
|
||
let cx = Rc::new(spirt::Context::new()); | ||
|
||
let multi_version_printing = true; | ||
let mut per_pass_module = vec![]; | ||
let mut after_pass = |pass, module: &spirt::Module| { | ||
if multi_version_printing { | ||
per_pass_module.push((pass, module.clone())); | ||
Ok(()) | ||
} else { | ||
save_print_plan( | ||
&format!("after.{pass}"), | ||
spirt::print::Plan::for_module(module), | ||
) | ||
} | ||
}; | ||
|
||
let mut module = | ||
eprint_duration(|| spirt::Module::lower_from_spv_file(cx.clone(), in_file_path))?; | ||
eprintln!("Module::lower_from_spv_file({})", in_file_path.display()); | ||
|
||
let original_export_count = module.exports.len(); | ||
eprint_duration(|| { | ||
spirt::passes::link::minimize_exports(&mut module, |export_key| { | ||
matches!(export_key, spirt::ExportKey::SpvEntryPoint { .. }) | ||
}) | ||
}); | ||
eprintln!( | ||
"link::minimize_exports: {} -> {} exports", | ||
original_export_count, | ||
module.exports.len() | ||
); | ||
//after_pass("minimize_exports", &module)?; | ||
|
||
// HACK(eddyb) do this late enough to avoid spending time on unused | ||
// functions, which `link::minimize_exports` makes unreachable. | ||
eprint_duration(|| spirt::passes::legalize::structurize_func_cfgs(&mut module)); | ||
eprintln!("legalize::structurize_func_cfgs"); | ||
//after_pass("structurize_func_cfgs", &module)?; | ||
|
||
eprint_duration(|| spirt::passes::link::resolve_imports(&mut module)); | ||
eprintln!("link::resolve_imports"); | ||
//after_pass("resolve_imports", &module)?; | ||
|
||
// HACK(eddyb) | ||
after_pass("", &module)?; | ||
|
||
eprint_duration(|| spirt::passes::qptr::lower_from_spv_ptrs(&mut module)); | ||
eprintln!("qptr::lower_from_spv_ptrs"); | ||
after_pass("qptr::lower_from_spv_ptrs", &module)?; | ||
|
||
eprint_duration(|| spirt::passes::qptr::analyze_uses(&mut module)); | ||
eprintln!("qptr::analyze_uses"); | ||
after_pass("qptr::analyze_uses", &module)?; | ||
|
||
eprint_duration(|| spirt::passes::qptr::lift_to_spv_ptrs(&mut module)); | ||
eprintln!("qptr::lift_to_spv_ptrs"); | ||
after_pass("qptr::lift_to_spv_ptrs", &module)?; | ||
|
||
if multi_version_printing { | ||
// FIXME(eddyb) use a better suffix than `qptr` (or none). | ||
save_print_plan( | ||
"qptr", | ||
spirt::print::Plan::for_versions( | ||
&cx, | ||
per_pass_module.iter().map(|(pass, module)| { | ||
( | ||
// HACK(eddyb) | ||
if pass.is_empty() { | ||
"initial".into() | ||
} else { | ||
format!("after {pass}") | ||
}, | ||
module, | ||
) | ||
}), | ||
), | ||
)?; | ||
} | ||
|
||
//let out_file_path = in_file_path.with_extension("qptr.spv"); | ||
//eprint_duration(|| module.lift_to_spv_file(&out_file_path))?; | ||
//eprintln!("Module::lift_to_spv_file({})", out_file_path.display()); | ||
|
||
Ok(()) | ||
} | ||
args => { | ||
eprintln!("Usage: {} IN", args[0]); | ||
std::process::exit(1); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,102 @@ | ||
//! [`QPtr`](crate::TypeCtor::QPtr) transforms. | ||
use crate::qptr; | ||
use crate::visit::{InnerVisit, Visitor}; | ||
use crate::{AttrSet, Const, Context, Func, FxIndexSet, GlobalVar, Module, Type}; | ||
|
||
pub fn lower_from_spv_ptrs(module: &mut Module) { | ||
let cx = &module.cx(); | ||
|
||
let (seen_global_vars, seen_funcs) = { | ||
// FIXME(eddyb) reuse this collection work in some kind of "pass manager". | ||
let mut collector = ReachableUseCollector { | ||
cx, | ||
module, | ||
|
||
seen_types: FxIndexSet::default(), | ||
seen_consts: FxIndexSet::default(), | ||
seen_global_vars: FxIndexSet::default(), | ||
seen_funcs: FxIndexSet::default(), | ||
}; | ||
for &exportee in module.exports.values() { | ||
exportee.inner_visit_with(&mut collector); | ||
} | ||
(collector.seen_global_vars, collector.seen_funcs) | ||
}; | ||
|
||
let lowerer = qptr::lower::LowerFromSpvPtrs::new(cx.clone()); | ||
for &global_var in &seen_global_vars { | ||
lowerer.lower_global_var(&mut module.global_vars[global_var]); | ||
} | ||
for &func in &seen_funcs { | ||
lowerer.lower_func(&mut module.funcs[func]); | ||
} | ||
} | ||
|
||
pub fn analyze_uses(module: &mut Module) { | ||
qptr::analyze::InferUsage::new(module.cx()).infer_usage_in_module(module); | ||
} | ||
|
||
pub fn lift_to_spv_ptrs(module: &mut Module) { | ||
let cx = &module.cx(); | ||
|
||
let (seen_global_vars, seen_funcs) = { | ||
// FIXME(eddyb) reuse this collection work in some kind of "pass manager". | ||
let mut collector = ReachableUseCollector { | ||
cx, | ||
module, | ||
|
||
seen_types: FxIndexSet::default(), | ||
seen_consts: FxIndexSet::default(), | ||
seen_global_vars: FxIndexSet::default(), | ||
seen_funcs: FxIndexSet::default(), | ||
}; | ||
for &exportee in module.exports.values() { | ||
exportee.inner_visit_with(&mut collector); | ||
} | ||
(collector.seen_global_vars, collector.seen_funcs) | ||
}; | ||
|
||
let lifter = qptr::lift::LiftToSpvPtrs::new(cx.clone()); | ||
for &global_var in &seen_global_vars { | ||
lifter.lift_global_var(&mut module.global_vars[global_var]); | ||
} | ||
lifter.lift_all_funcs(module, seen_funcs); | ||
} | ||
|
||
struct ReachableUseCollector<'a> { | ||
cx: &'a Context, | ||
module: &'a Module, | ||
|
||
// FIXME(eddyb) build some automation to avoid ever repeating these. | ||
seen_types: FxIndexSet<Type>, | ||
seen_consts: FxIndexSet<Const>, | ||
seen_global_vars: FxIndexSet<GlobalVar>, | ||
seen_funcs: FxIndexSet<Func>, | ||
} | ||
|
||
impl Visitor<'_> for ReachableUseCollector<'_> { | ||
// FIXME(eddyb) build some automation to avoid ever repeating these. | ||
fn visit_attr_set_use(&mut self, _attrs: AttrSet) {} | ||
fn visit_type_use(&mut self, ty: Type) { | ||
if self.seen_types.insert(ty) { | ||
self.visit_type_def(&self.cx[ty]); | ||
} | ||
} | ||
fn visit_const_use(&mut self, ct: Const) { | ||
if self.seen_consts.insert(ct) { | ||
self.visit_const_def(&self.cx[ct]); | ||
} | ||
} | ||
|
||
fn visit_global_var_use(&mut self, gv: GlobalVar) { | ||
if self.seen_global_vars.insert(gv) { | ||
self.visit_global_var_decl(&self.module.global_vars[gv]); | ||
} | ||
} | ||
fn visit_func_use(&mut self, func: Func) { | ||
if self.seen_funcs.insert(func) { | ||
self.visit_func_decl(&self.module.funcs[func]); | ||
} | ||
} | ||
} |
Oops, something went wrong.