Skip to content

Commit fad761e

Browse files
eddybLegNeato
authored andcommitted
linker: centralize dumping SPIR-V and SPIR-T together.
1 parent 9be942e commit fad761e

File tree

1 file changed

+106
-68
lines changed
  • crates/rustc_codegen_spirv/src/linker

1 file changed

+106
-68
lines changed

crates/rustc_codegen_spirv/src/linker/mod.rs

Lines changed: 106 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -150,13 +150,98 @@ fn get_name<'a>(names: &FxHashMap<Word, &'a str>, id: Word) -> Cow<'a, str> {
150150
)
151151
}
152152

153+
impl Options {
154+
// FIXME(eddyb) using a method on this type seems a bit sketchy.
155+
fn spirt_cleanup_for_dumping(&self, module: &mut spirt::Module) {
156+
if self.spirt_strip_custom_debuginfo_from_dumps {
157+
spirt_passes::debuginfo::convert_custom_debuginfo_to_spv(module);
158+
}
159+
if !self.spirt_keep_debug_sources_in_dumps {
160+
const DOTS: &str = "⋯";
161+
let dots_interned_str = module.cx().intern(DOTS);
162+
let spirt::ModuleDebugInfo::Spv(debuginfo) = &mut module.debug_info;
163+
for sources in debuginfo.source_languages.values_mut() {
164+
for file in sources.file_contents.values_mut() {
165+
*file = DOTS.into();
166+
}
167+
sources.file_contents.insert(
168+
dots_interned_str,
169+
"sources hidden, to show them use \
170+
`RUSTGPU_CODEGEN_ARGS=--spirt-keep-debug-sources-in-dumps`"
171+
.into(),
172+
);
173+
}
174+
}
175+
}
176+
}
177+
153178
pub fn link(
154179
sess: &Session,
155180
mut inputs: Vec<Module>,
156181
opts: &Options,
157182
outputs: &OutputFilenames,
158183
disambiguated_crate_name_for_dumps: &OsStr,
159184
) -> Result<LinkResult> {
185+
// HACK(eddyb) this is defined here to allow SPIR-T pretty-printing to apply
186+
// to SPIR-V being dumped, outside of e.g. `--dump-spirt-passes`.
187+
// FIXME(eddyb) this isn't used everywhere, sadly - to find those, search
188+
// elsewhere for `.assemble()` and/or `spirv_tools::binary::from_binary`.
189+
let spv_module_to_spv_words_and_spirt_module = |spv_module: &Module| {
190+
let spv_words;
191+
let spv_bytes = {
192+
let _timer = sess.timer("assemble-to-spv_bytes-for-spirt");
193+
spv_words = spv_module.assemble();
194+
// FIXME(eddyb) this is wastefully cloning all the bytes, but also
195+
// `spirt::Module` should have a method that takes `Vec<u32>`.
196+
spirv_tools::binary::from_binary(&spv_words).to_vec()
197+
};
198+
199+
// FIXME(eddyb) should've really been "spirt::Module::lower_from_spv_bytes".
200+
let _timer = sess.timer("spirt::Module::lower_from_spv_file");
201+
let cx = std::rc::Rc::new(spirt::Context::new());
202+
crate::custom_insts::register_to_spirt_context(&cx);
203+
(
204+
spv_words,
205+
spirt::Module::lower_from_spv_bytes(cx, spv_bytes),
206+
)
207+
};
208+
209+
let dump_spv_and_spirt = |spv_module: &Module, dump_file_path_stem: PathBuf| {
210+
let (spv_words, spirt_module_or_err) = spv_module_to_spv_words_and_spirt_module(spv_module);
211+
std::fs::write(
212+
dump_file_path_stem.with_extension("spv"),
213+
spirv_tools::binary::from_binary(&spv_words),
214+
)
215+
.unwrap();
216+
217+
// FIXME(eddyb) reify SPIR-V -> SPIR-T errors so they're easier to debug.
218+
if let Ok(mut module) = spirt_module_or_err {
219+
// HACK(eddyb) avoid pretty-printing massive amounts of unused SPIR-T.
220+
spirt::passes::link::minimize_exports(&mut module, |export_key| {
221+
matches!(export_key, spirt::ExportKey::SpvEntryPoint { .. })
222+
});
223+
224+
opts.spirt_cleanup_for_dumping(&mut module);
225+
226+
let pretty = spirt::print::Plan::for_module(&module).pretty_print();
227+
228+
// FIXME(eddyb) don't allocate whole `String`s here.
229+
std::fs::write(
230+
dump_file_path_stem.with_extension("spirt"),
231+
pretty.to_string(),
232+
)
233+
.unwrap();
234+
std::fs::write(
235+
dump_file_path_stem.with_extension("spirt.html"),
236+
pretty
237+
.render_to_html()
238+
.with_dark_mode_support()
239+
.to_html_doc(),
240+
)
241+
.unwrap();
242+
}
243+
};
244+
160245
let mut output = {
161246
let _timer = sess.timer("link_merge");
162247
// shift all the ids
@@ -193,12 +278,7 @@ pub fn link(
193278
};
194279

195280
if let Some(dir) = &opts.dump_post_merge {
196-
std::fs::write(
197-
dir.join(disambiguated_crate_name_for_dumps)
198-
.with_extension("spv"),
199-
spirv_tools::binary::from_binary(&output.assemble()),
200-
)
201-
.unwrap();
281+
dump_spv_and_spirt(&output, dir.join(disambiguated_crate_name_for_dumps));
202282
}
203283

204284
// remove duplicates (https://github.com/KhronosGroup/SPIRV-Tools/blob/e7866de4b1dc2a7e8672867caeb0bdca49f458d3/source/opt/remove_duplicates_pass.cpp)
@@ -401,40 +481,22 @@ pub fn link(
401481
}
402482
};
403483

404-
let spv_words;
405-
let spv_bytes = {
406-
let _timer = sess.timer("assemble-to-spv_bytes-for-spirt");
407-
spv_words = output.assemble();
408-
// FIXME(eddyb) this is wastefully cloning all the bytes, but also
409-
// `spirt::Module` should have a method that takes `Vec<u32>`.
410-
spirv_tools::binary::from_binary(&spv_words).to_vec()
411-
};
412-
let cx = std::rc::Rc::new(spirt::Context::new());
413-
crate::custom_insts::register_to_spirt_context(&cx);
414-
let mut module = {
415-
let _timer = sess.timer("spirt::Module::lower_from_spv_file");
416-
match spirt::Module::lower_from_spv_bytes(cx.clone(), spv_bytes) {
417-
Ok(module) => module,
418-
Err(e) => {
419-
let spv_path = outputs.temp_path_ext("spirt-lower-from-spv-input.spv", None);
420-
421-
let was_saved_msg = match std::fs::write(
422-
&spv_path,
423-
spirv_tools::binary::from_binary(&spv_words),
424-
) {
425-
Ok(()) => format!("was saved to {}", spv_path.display()),
426-
Err(e) => format!("could not be saved: {e}"),
427-
};
428-
429-
return Err(sess
430-
.dcx()
431-
.struct_err(format!("{e}"))
432-
.with_note("while lowering SPIR-V module to SPIR-T (spirt::spv::lower)")
433-
.with_note(format!("input SPIR-V module {was_saved_msg}"))
434-
.emit());
435-
}
436-
}
437-
};
484+
let (spv_words, module_or_err) = spv_module_to_spv_words_and_spirt_module(&output);
485+
let mut module = module_or_err.map_err(|e| {
486+
let spv_path = outputs.temp_path_ext("spirt-lower-from-spv-input.spv", None);
487+
488+
let was_saved_msg =
489+
match std::fs::write(&spv_path, spirv_tools::binary::from_binary(&spv_words)) {
490+
Ok(()) => format!("was saved to {}", spv_path.display()),
491+
Err(e) => format!("could not be saved: {e}"),
492+
};
493+
494+
sess.dcx()
495+
.struct_err(format!("{e}"))
496+
.with_note("while lowering SPIR-V module to SPIR-T (spirt::spv::lower)")
497+
.with_note(format!("input SPIR-V module {was_saved_msg}"))
498+
.emit()
499+
})?;
438500
// HACK(eddyb) don't dump the unstructured state if not requested, as
439501
// after SPIR-T 0.4.0 it's extremely verbose (due to def-use hermeticity).
440502
if opts.spirt_keep_unstructured_cfg_in_dumps || !opts.structurize {
@@ -499,31 +561,12 @@ pub fn link(
499561
// NOTE(eddyb) this should be *before* `lift_to_spv` below,
500562
// so if that fails, the dump could be used to debug it.
501563
if let Some(dump_spirt_file_path) = &dump_spirt_file_path {
502-
if opts.spirt_strip_custom_debuginfo_from_dumps {
503-
for (_, module) in &mut per_pass_module_for_dumping {
504-
spirt_passes::debuginfo::convert_custom_debuginfo_to_spv(module);
505-
}
506-
}
507-
if !opts.spirt_keep_debug_sources_in_dumps {
508-
for (_, module) in &mut per_pass_module_for_dumping {
509-
let spirt::ModuleDebugInfo::Spv(debuginfo) = &mut module.debug_info;
510-
for sources in debuginfo.source_languages.values_mut() {
511-
const DOTS: &str = "⋯";
512-
for file in sources.file_contents.values_mut() {
513-
*file = DOTS.into();
514-
}
515-
sources.file_contents.insert(
516-
cx.intern(DOTS),
517-
"sources hidden, to show them use \
518-
`RUSTGPU_CODEGEN_ARGS=--spirt-keep-debug-sources-in-dumps`"
519-
.into(),
520-
);
521-
}
522-
}
564+
for (_, module) in &mut per_pass_module_for_dumping {
565+
opts.spirt_cleanup_for_dumping(module);
523566
}
524567

525568
let plan = spirt::print::Plan::for_versions(
526-
&cx,
569+
module.cx_ref(),
527570
per_pass_module_for_dumping
528571
.iter()
529572
.map(|(pass, module)| (format!("after {pass}"), module)),
@@ -695,13 +738,8 @@ pub fn link(
695738
file_name.push(".");
696739
file_name.push(file_stem);
697740
}
698-
file_name.push(".spv");
699741

700-
std::fs::write(
701-
dir.join(file_name),
702-
spirv_tools::binary::from_binary(&output.assemble()),
703-
)
704-
.unwrap();
742+
dump_spv_and_spirt(output, dir.join(file_name));
705743
}
706744
// Run DCE again, even if module_output_type == ModuleOutputType::Multiple - the first DCE ran before
707745
// structurization and mem2reg (for perf reasons), and mem2reg may remove references to

0 commit comments

Comments
 (0)