mirror of
https://github.com/EmbarkStudios/rust-gpu.git
synced 2024-11-25 00:04:11 +00:00
linker: use OutputFilenames::temp_path_ext
for critical dumping, even without --dump-*
.
This commit is contained in:
parent
1abd1cf43b
commit
7f508ba86c
@ -78,6 +78,7 @@ pub fn link(
|
|||||||
crate_type,
|
crate_type,
|
||||||
&out_filename,
|
&out_filename,
|
||||||
codegen_results,
|
codegen_results,
|
||||||
|
outputs,
|
||||||
&disambiguated_crate_name_for_dumps,
|
&disambiguated_crate_name_for_dumps,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -123,6 +124,7 @@ fn link_exe(
|
|||||||
crate_type: CrateType,
|
crate_type: CrateType,
|
||||||
out_filename: &Path,
|
out_filename: &Path,
|
||||||
codegen_results: &CodegenResults,
|
codegen_results: &CodegenResults,
|
||||||
|
outputs: &OutputFilenames,
|
||||||
disambiguated_crate_name_for_dumps: &OsStr,
|
disambiguated_crate_name_for_dumps: &OsStr,
|
||||||
) {
|
) {
|
||||||
let mut objects = Vec::new();
|
let mut objects = Vec::new();
|
||||||
@ -152,6 +154,7 @@ fn link_exe(
|
|||||||
&cg_args,
|
&cg_args,
|
||||||
&objects,
|
&objects,
|
||||||
&rlibs,
|
&rlibs,
|
||||||
|
outputs,
|
||||||
disambiguated_crate_name_for_dumps,
|
disambiguated_crate_name_for_dumps,
|
||||||
);
|
);
|
||||||
let compile_result = match link_result {
|
let compile_result = match link_result {
|
||||||
@ -517,6 +520,7 @@ fn do_link(
|
|||||||
cg_args: &CodegenArgs,
|
cg_args: &CodegenArgs,
|
||||||
objects: &[PathBuf],
|
objects: &[PathBuf],
|
||||||
rlibs: &[PathBuf],
|
rlibs: &[PathBuf],
|
||||||
|
outputs: &OutputFilenames,
|
||||||
disambiguated_crate_name_for_dumps: &OsStr,
|
disambiguated_crate_name_for_dumps: &OsStr,
|
||||||
) -> linker::LinkResult {
|
) -> linker::LinkResult {
|
||||||
let load_modules_timer = sess.timer("link_load_modules");
|
let load_modules_timer = sess.timer("link_load_modules");
|
||||||
@ -570,6 +574,7 @@ fn do_link(
|
|||||||
sess,
|
sess,
|
||||||
modules,
|
modules,
|
||||||
&cg_args.linker_opts,
|
&cg_args.linker_opts,
|
||||||
|
outputs,
|
||||||
disambiguated_crate_name_for_dumps,
|
disambiguated_crate_name_for_dumps,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -27,6 +27,7 @@ use rspirv::dr::{Block, Instruction, Loader, Module, ModuleHeader, Operand};
|
|||||||
use rspirv::spirv::{Op, StorageClass, Word};
|
use rspirv::spirv::{Op, StorageClass, Word};
|
||||||
use rustc_data_structures::fx::FxHashMap;
|
use rustc_data_structures::fx::FxHashMap;
|
||||||
use rustc_errors::ErrorGuaranteed;
|
use rustc_errors::ErrorGuaranteed;
|
||||||
|
use rustc_session::config::OutputFilenames;
|
||||||
use rustc_session::Session;
|
use rustc_session::Session;
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
use std::ffi::{OsStr, OsString};
|
use std::ffi::{OsStr, OsString};
|
||||||
@ -151,6 +152,7 @@ pub fn link(
|
|||||||
sess: &Session,
|
sess: &Session,
|
||||||
mut inputs: Vec<Module>,
|
mut inputs: Vec<Module>,
|
||||||
opts: &Options,
|
opts: &Options,
|
||||||
|
outputs: &OutputFilenames,
|
||||||
disambiguated_crate_name_for_dumps: &OsStr,
|
disambiguated_crate_name_for_dumps: &OsStr,
|
||||||
) -> Result<LinkResult> {
|
) -> Result<LinkResult> {
|
||||||
let mut output = {
|
let mut output = {
|
||||||
@ -383,9 +385,13 @@ pub fn link(
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let spv_words;
|
||||||
let spv_bytes = {
|
let spv_bytes = {
|
||||||
let _timer = sess.timer("assemble-to-spv_bytes-for-spirt");
|
let _timer = sess.timer("assemble-to-spv_bytes-for-spirt");
|
||||||
spirv_tools::binary::from_binary(&output.assemble()).to_vec()
|
spv_words = output.assemble();
|
||||||
|
// FIXME(eddyb) this is wastefully cloning all the bytes, but also
|
||||||
|
// `spirt::Module` should have a method that takes `Vec<u32>`.
|
||||||
|
spirv_tools::binary::from_binary(&spv_words).to_vec()
|
||||||
};
|
};
|
||||||
let cx = std::rc::Rc::new(spirt::Context::new());
|
let cx = std::rc::Rc::new(spirt::Context::new());
|
||||||
let mut module = {
|
let mut module = {
|
||||||
@ -393,14 +399,20 @@ pub fn link(
|
|||||||
match spirt::Module::lower_from_spv_bytes(cx.clone(), spv_bytes) {
|
match spirt::Module::lower_from_spv_bytes(cx.clone(), spv_bytes) {
|
||||||
Ok(module) => module,
|
Ok(module) => module,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
use rspirv::binary::Disassemble;
|
let spv_path = outputs.temp_path_ext("spirt-lower-from-spv-input.spv", None);
|
||||||
|
|
||||||
|
let was_saved_msg = match std::fs::write(
|
||||||
|
&spv_path,
|
||||||
|
spirv_tools::binary::from_binary(&spv_words),
|
||||||
|
) {
|
||||||
|
Ok(()) => format!("was saved to {}", spv_path.display()),
|
||||||
|
Err(e) => format!("could not be saved: {e}"),
|
||||||
|
};
|
||||||
|
|
||||||
return Err(sess
|
return Err(sess
|
||||||
.struct_err(format!("{e}"))
|
.struct_err(format!("{e}"))
|
||||||
.note(format!(
|
.note("while lowering SPIR-V module to SPIR-T (spirt::spv::lower)")
|
||||||
"while lowering this SPIR-V module to SPIR-T:\n{}",
|
.note(format!("input SPIR-V module {was_saved_msg}"))
|
||||||
output.disassemble()
|
|
||||||
))
|
|
||||||
.emit());
|
.emit());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -438,14 +450,30 @@ pub fn link(
|
|||||||
let _timer = sess.timer("spirt_passes::diagnostics::report_diagnostics");
|
let _timer = sess.timer("spirt_passes::diagnostics::report_diagnostics");
|
||||||
spirt_passes::diagnostics::report_diagnostics(sess, opts, &module)
|
spirt_passes::diagnostics::report_diagnostics(sess, opts, &module)
|
||||||
};
|
};
|
||||||
|
let any_spirt_bugs = report_diagnostics_result
|
||||||
|
.as_ref()
|
||||||
|
.err()
|
||||||
|
.map_or(false, |e| e.any_errors_were_spirt_bugs);
|
||||||
|
|
||||||
|
let mut dump_spirt_file_path = opts.dump_spirt_passes.as_ref().map(|dump_dir| {
|
||||||
|
dump_dir
|
||||||
|
.join(disambiguated_crate_name_for_dumps)
|
||||||
|
.with_extension("spirt")
|
||||||
|
});
|
||||||
|
|
||||||
|
// FIXME(eddyb) this won't allow seeing the individual passes, but it's
|
||||||
|
// better than nothing (we could theoretically put this whole block in
|
||||||
|
// a loop so that we redo everything but keeping `Module` clones?).
|
||||||
|
if any_spirt_bugs && dump_spirt_file_path.is_none() {
|
||||||
|
if per_pass_module_for_dumping.is_empty() {
|
||||||
|
per_pass_module_for_dumping.push(("", module.clone()));
|
||||||
|
}
|
||||||
|
dump_spirt_file_path = Some(outputs.temp_path_ext("spirt", None));
|
||||||
|
}
|
||||||
|
|
||||||
// NOTE(eddyb) this should be *before* `lift_to_spv` below,
|
// NOTE(eddyb) this should be *before* `lift_to_spv` below,
|
||||||
// so if that fails, the dump could be used to debug it.
|
// so if that fails, the dump could be used to debug it.
|
||||||
if let Some(dump_dir) = &opts.dump_spirt_passes {
|
if let Some(dump_spirt_file_path) = &dump_spirt_file_path {
|
||||||
let dump_spirt_file_path = dump_dir
|
|
||||||
.join(disambiguated_crate_name_for_dumps)
|
|
||||||
.with_extension("spirt");
|
|
||||||
|
|
||||||
// HACK(eddyb) unless requested otherwise, clean up the pretty-printed
|
// HACK(eddyb) unless requested otherwise, clean up the pretty-printed
|
||||||
// SPIR-T output by converting our custom extended instructions, to
|
// SPIR-T output by converting our custom extended instructions, to
|
||||||
// standard SPIR-V debuginfo (which SPIR-T knows how to pretty-print).
|
// standard SPIR-V debuginfo (which SPIR-T knows how to pretty-print).
|
||||||
@ -464,7 +492,7 @@ pub fn link(
|
|||||||
let pretty = plan.pretty_print();
|
let pretty = plan.pretty_print();
|
||||||
|
|
||||||
// FIXME(eddyb) don't allocate whole `String`s here.
|
// FIXME(eddyb) don't allocate whole `String`s here.
|
||||||
std::fs::write(&dump_spirt_file_path, pretty.to_string()).unwrap();
|
std::fs::write(dump_spirt_file_path, pretty.to_string()).unwrap();
|
||||||
std::fs::write(
|
std::fs::write(
|
||||||
dump_spirt_file_path.with_extension("spirt.html"),
|
dump_spirt_file_path.with_extension("spirt.html"),
|
||||||
pretty
|
pretty
|
||||||
@ -475,6 +503,19 @@ pub fn link(
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if any_spirt_bugs {
|
||||||
|
let mut note = sess.struct_note_without_error("SPIR-T bugs were reported");
|
||||||
|
note.help(format!(
|
||||||
|
"pretty-printed SPIR-T was saved to {}.html",
|
||||||
|
dump_spirt_file_path.as_ref().unwrap().display()
|
||||||
|
));
|
||||||
|
if opts.dump_spirt_passes.is_none() {
|
||||||
|
note.help("re-run with `RUSTGPU_CODEGEN_ARGS=\"--dump-spirt-passes=$PWD\"` for more details");
|
||||||
|
}
|
||||||
|
note.note("pretty-printed SPIR-T is preferred when reporting Rust-GPU issues")
|
||||||
|
.emit();
|
||||||
|
}
|
||||||
|
|
||||||
// NOTE(eddyb) this is late so that `--dump-spirt-passes` is processed,
|
// NOTE(eddyb) this is late so that `--dump-spirt-passes` is processed,
|
||||||
// even/especially when errors were reported, but lifting to SPIR-V is
|
// even/especially when errors were reported, but lifting to SPIR-V is
|
||||||
// skipped (since it could very well fail due to reported errors).
|
// skipped (since it could very well fail due to reported errors).
|
||||||
|
@ -17,11 +17,22 @@ use spirt::{
|
|||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
use std::{mem, str};
|
use std::{mem, str};
|
||||||
|
|
||||||
|
pub(crate) struct ReportedDiagnostics {
|
||||||
|
pub rustc_errors_guarantee: rustc_errors::ErrorGuaranteed,
|
||||||
|
pub any_errors_were_spirt_bugs: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<ReportedDiagnostics> for rustc_errors::ErrorGuaranteed {
|
||||||
|
fn from(r: ReportedDiagnostics) -> Self {
|
||||||
|
r.rustc_errors_guarantee
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn report_diagnostics(
|
pub(crate) fn report_diagnostics(
|
||||||
sess: &Session,
|
sess: &Session,
|
||||||
linker_options: &crate::linker::Options,
|
linker_options: &crate::linker::Options,
|
||||||
module: &Module,
|
module: &Module,
|
||||||
) -> crate::linker::Result<()> {
|
) -> Result<(), ReportedDiagnostics> {
|
||||||
let cx = &module.cx();
|
let cx = &module.cx();
|
||||||
|
|
||||||
let mut reporter = DiagnosticReporter {
|
let mut reporter = DiagnosticReporter {
|
||||||
@ -68,28 +79,12 @@ pub(crate) fn report_diagnostics(
|
|||||||
exportee.inner_visit_with(&mut reporter);
|
exportee.inner_visit_with(&mut reporter);
|
||||||
}
|
}
|
||||||
|
|
||||||
if reporter.any_spirt_bugs {
|
reporter
|
||||||
let mut note = sess.struct_note_without_error("SPIR-T bugs were reported");
|
.overall_result
|
||||||
match &linker_options.dump_spirt_passes {
|
.map_err(|rustc_errors_guarantee| ReportedDiagnostics {
|
||||||
Some(dump_dir) => {
|
rustc_errors_guarantee,
|
||||||
note.help(format!(
|
any_errors_were_spirt_bugs: reporter.any_spirt_bugs,
|
||||||
"pretty-printed SPIR-T will be saved to `{}`, as `.spirt.html` files",
|
})
|
||||||
dump_dir.display()
|
|
||||||
));
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
// FIXME(eddyb) maybe just always generate the files in a tmpdir?
|
|
||||||
note.help(
|
|
||||||
"re-run with `RUSTGPU_CODEGEN_ARGS=\"--dump-spirt-passes=$PWD\"` to \
|
|
||||||
get pretty-printed SPIR-T (`.spirt.html`)",
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
note.note("pretty-printed SPIR-T is preferred when reporting Rust-GPU issues")
|
|
||||||
.emit();
|
|
||||||
}
|
|
||||||
|
|
||||||
reporter.overall_result
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// HACK(eddyb) version of `decorations::LazilyDecoded` that works for SPIR-T.
|
// HACK(eddyb) version of `decorations::LazilyDecoded` that works for SPIR-T.
|
||||||
|
@ -2,7 +2,8 @@ use super::{link, LinkResult};
|
|||||||
use pipe::pipe;
|
use pipe::pipe;
|
||||||
use rspirv::dr::{Loader, Module};
|
use rspirv::dr::{Loader, Module};
|
||||||
use rustc_errors::{registry::Registry, TerminalUrl};
|
use rustc_errors::{registry::Registry, TerminalUrl};
|
||||||
use rustc_session::{config::Input, CompilerIO};
|
use rustc_session::config::{Input, OutputFilenames, OutputTypes};
|
||||||
|
use rustc_session::CompilerIO;
|
||||||
use rustc_span::FileName;
|
use rustc_span::FileName;
|
||||||
use std::io::Read;
|
use std::io::Read;
|
||||||
|
|
||||||
@ -148,7 +149,20 @@ fn link_with_linker_opts(
|
|||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
let res = link(&sess, modules, opts, Default::default());
|
let res = link(
|
||||||
|
&sess,
|
||||||
|
modules,
|
||||||
|
opts,
|
||||||
|
&OutputFilenames::new(
|
||||||
|
std::env::current_dir().unwrap_or_default(),
|
||||||
|
"".into(),
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
"".into(),
|
||||||
|
OutputTypes::new(&[]),
|
||||||
|
),
|
||||||
|
Default::default(),
|
||||||
|
);
|
||||||
assert_eq!(sess.has_errors(), res.as_ref().err().copied());
|
assert_eq!(sess.has_errors(), res.as_ref().err().copied());
|
||||||
res.map(|res| match res {
|
res.map(|res| match res {
|
||||||
LinkResult::SingleModule(m) => *m,
|
LinkResult::SingleModule(m) => *m,
|
||||||
|
Loading…
Reference in New Issue
Block a user