spv_lower_link_lift/
spv-lower-link-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
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)?;

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