spv_lower_link_qptr_lift/
spv-lower-link-qptr-lift.rs

1
2
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
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
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);
        }
    }
}