-
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.
Introduce
qptr
("quasi-pointer") type and associated lower->analyze…
…->lift passes.
- Loading branch information
Showing
17 changed files
with
5,240 additions
and
49 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
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,138 @@ | ||
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)?; | ||
|
||
// HACK(eddyb) this is roughly what Rust-GPU would need. | ||
let layout_config = &spirt::qptr::LayoutConfig { | ||
abstract_bool_size_align: (1, 1), | ||
logical_ptr_size_align: (4, 4), | ||
..spirt::qptr::LayoutConfig::VULKAN_SCALAR_LAYOUT | ||
}; | ||
|
||
eprint_duration(|| { | ||
spirt::passes::qptr::lower_from_spv_ptrs(&mut module, layout_config) | ||
}); | ||
eprintln!("qptr::lower_from_spv_ptrs"); | ||
after_pass("qptr::lower_from_spv_ptrs", &module)?; | ||
|
||
eprint_duration(|| spirt::passes::qptr::analyze_uses(&mut module, layout_config)); | ||
eprintln!("qptr::analyze_uses"); | ||
after_pass("qptr::analyze_uses", &module)?; | ||
|
||
eprint_duration(|| spirt::passes::qptr::lift_to_spv_ptrs(&mut module, layout_config)); | ||
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
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,104 @@ | ||
//! [`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, layout_config: &qptr::LayoutConfig) { | ||
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 (export_key, &exportee) in &module.exports { | ||
export_key.inner_visit_with(&mut collector); | ||
exportee.inner_visit_with(&mut collector); | ||
} | ||
(collector.seen_global_vars, collector.seen_funcs) | ||
}; | ||
|
||
let lowerer = qptr::lower::LowerFromSpvPtrs::new(cx.clone(), layout_config); | ||
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, layout_config: &qptr::LayoutConfig) { | ||
qptr::analyze::InferUsage::new(module.cx(), layout_config).infer_usage_in_module(module); | ||
} | ||
|
||
pub fn lift_to_spv_ptrs(module: &mut Module, layout_config: &qptr::LayoutConfig) { | ||
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 (export_key, &exportee) in &module.exports { | ||
export_key.inner_visit_with(&mut collector); | ||
exportee.inner_visit_with(&mut collector); | ||
} | ||
(collector.seen_global_vars, collector.seen_funcs) | ||
}; | ||
|
||
let lifter = qptr::lift::LiftToSpvPtrs::new(cx.clone(), layout_config); | ||
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.