pub struct Context {
interners: Interners,
entity_allocs: EntityAllocs,
custom_spv_ext_inst_set_descs: FrozenBTreeMap<String, Box<ExtInstSetDesc>>,
}
Expand description
Context object with global resources for SPIR-T.
Those resources currently are:
- interners, for anything without an identity, and which can be deduplicated
- “entity” allocators, for everything else - i.e. anything with an identity
that needs to remain unique across an entire
Context
- the definition of an entity isn’t kept in the
Context
, but rather in someEntityDefs
collection somewhere in aModule
(or further nested), with only the entity indices being allocated by theContext
- the definition of an entity isn’t kept in the
- custom SPIR-V “extended instruction set” descriptions, which can be
dynamically registered, to account for any such “extended instruction set”
not covered by
spv::spec::Spec
’s built-in list (e.g. non-standard tool-specific sets), and only used for pretty-printing
Fields§
§interners: Interners
§entity_allocs: EntityAllocs
§custom_spv_ext_inst_set_descs: FrozenBTreeMap<String, Box<ExtInstSetDesc>>
Implementations§
source§impl Context
impl Context
sourcepub fn register_custom_ext_inst_set(
&self,
ext_inst_set_name: &str,
ext_inst_set_desc: ExtInstSetDesc,
)
pub fn register_custom_ext_inst_set( &self, ext_inst_set_name: &str, ext_inst_set_desc: ExtInstSetDesc, )
Register a custom ExtInstSetDesc
with name ext_inst_set_name
,
to be used by pretty-printing when using this Context
.
sourcepub fn get_custom_ext_inst_set_by_lowercase_name(
&self,
lowercase_ext_inst_set_name: &str,
) -> Option<&ExtInstSetDesc>
pub fn get_custom_ext_inst_set_by_lowercase_name( &self, lowercase_ext_inst_set_name: &str, ) -> Option<&ExtInstSetDesc>
Return a custom ExtInstSetDesc
, if one was registered on this Context
,
for this OpExtInstImport
name (required to be lowercase, due to Khronos’
choice of case insensitivity, but not checked by this function).
source§impl Context
impl Context
sourcepub fn new() -> Self
pub fn new() -> Self
Examples found in repository?
examples/spv-lower-print.rs (line 25)
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
fn main() -> std::io::Result<()> {
match &std::env::args().collect::<Vec<_>>()[..] {
[_, in_files @ ..] => {
for in_file in in_files {
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 =
if suffix.is_empty() { "spirt".into() } else { 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(),
)
};
let mut module = spirt::Module::lower_from_spv_file(
Rc::new(spirt::Context::new()),
in_file_path,
)?;
save_print_plan("", spirt::print::Plan::for_module(&module))?;
spirt::passes::legalize::structurize_func_cfgs(&mut module);
save_print_plan("structured", spirt::print::Plan::for_module(&module))?;
}
Ok(())
}
args => {
eprintln!("Usage: {} FILES", args[0]);
std::process::exit(1);
}
}
}
More examples
examples/spv-lower-lift-roundtrip.rs (line 7)
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
fn main() -> std::io::Result<()> {
match &std::env::args().collect::<Vec<_>>()[..] {
[_, in_file, out_file] => {
let module =
spirt::Module::lower_from_spv_file(Rc::new(spirt::Context::new()), in_file)?;
module.lift_to_spv_file(out_file)?;
// FIXME(eddyb) dump the module without reading the just-written file.
let parser = spirt::spv::read::ModuleParser::read_from_spv_file(out_file)?;
// FIXME(eddyb) deduplicate the rest of this function between this
// example and `spv-read-write-roundtrip`.
{
// FIXME(eddyb) show more of the header.
let [_, v, ..] = parser.header;
eprintln!("SPIR-V {}.{} module:", v >> 16, (v >> 8) & 0xff);
}
for inst in parser {
let inst = inst.unwrap();
eprint!(" ");
if let Some(id) = inst.result_id {
eprint!("%{id}");
if let Some(type_id) = inst.result_type_id {
eprint!(": %{type_id}");
}
eprint!(" = ");
}
eprint!("{}", inst.opcode.name());
spirt::spv::print::inst_operands(
inst.opcode,
inst.imms.iter().copied(),
inst.ids.iter().map(|id| format!("%{id}")),
)
.for_each(|operand_parts| eprint!(" {}", operand_parts.concat_to_plain_text()));
eprintln!();
}
Ok(())
}
args => {
eprintln!("Usage: {} IN OUT", args[0]);
std::process::exit(1);
}
}
}
examples/spv-lower-link-lift.rs (line 36)
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103
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)?;
if multi_version_printing {
// FIXME(eddyb) use a better suffix than `link` (or none).
save_print_plan(
"link",
spirt::print::Plan::for_versions(
&cx,
per_pass_module
.iter()
.map(|(pass, module)| (format!("after {pass}"), module)),
),
)?;
}
let out_file_path = in_file_path.with_extension("link.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);
}
}
}
examples/spv-lower-link-qptr-lift.rs (line 36)
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135
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);
}
}
}
pub fn intern<T: InternInCx<I>, I>(&self, x: T) -> I
Trait Implementations§
Auto Trait Implementations§
impl !Freeze for Context
impl !RefUnwindSafe for Context
impl !Send for Context
impl !Sync for Context
impl Unpin for Context
impl UnwindSafe for Context
Blanket Implementations§
source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Mutably borrows from an owned value. Read more
source§impl<T> IntoEither for T
impl<T> IntoEither for T
source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
Converts
self
into a Left
variant of Either<Self, Self>
if into_left
is true
.
Converts self
into a Right
variant of Either<Self, Self>
otherwise. Read moresource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
Converts
self
into a Left
variant of Either<Self, Self>
if into_left(&self)
returns true
.
Converts self
into a Right
variant of Either<Self, Self>
otherwise. Read more