spirt::context

Struct Context

source
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 some EntityDefs collection somewhere in a Module (or further nested), with only the entity indices being allocated by the Context
  • 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

source

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.

source

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

source

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
Hide additional 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);
        }
    }
}
source

pub fn intern<T: InternInCx<I>, I>(&self, x: T) -> I

Trait Implementations§

source§

impl Default for Context

source§

fn default() -> Context

Returns the “default value” for a type. Read more
source§

impl<I: Interned> Index<I> for Context

source§

type Output = <I as Interned>::Def

The returned type after indexing.
source§

fn index(&self, interned: I) -> &Self::Output

Performs the indexing (container[index]) operation. Read more

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> Any for T
where T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Borrow<T> for T
where T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

source§

impl<T, U> Into<U> for T
where U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

source§

impl<T> IntoEither for T

source§

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 more
source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

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
source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

source§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.