diff --git a/Cargo.lock b/Cargo.lock index c2a5a9f1f6..e071a2f4bd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -393,6 +393,16 @@ dependencies = [ "objc", ] +[[package]] +name = "crossbeam-channel" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b153fe7cbef478c567df0f972e02e6d736db11affe43dfc9c56a9374d1adfb87" +dependencies = [ + "crossbeam-utils 0.7.2", + "maybe-uninit", +] + [[package]] name = "crossbeam-channel" version = "0.5.0" @@ -400,7 +410,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dca26ee1f8d361640700bde38b2c37d8c22b3ce2d360e1fc1c74ea4b0aa7d775" dependencies = [ "cfg-if 1.0.0", - "crossbeam-utils", + "crossbeam-utils 0.8.0", ] [[package]] @@ -411,7 +421,7 @@ checksum = "94af6efb46fef72616855b036a624cf27ba656ffc9be1b9a3c931cfc7749a9a9" dependencies = [ "cfg-if 1.0.0", "crossbeam-epoch", - "crossbeam-utils", + "crossbeam-utils 0.8.0", ] [[package]] @@ -422,12 +432,23 @@ checksum = "ec0f606a85340376eef0d6d8fec399e6d4a544d648386c6645eb6d0653b27d9f" dependencies = [ "cfg-if 1.0.0", "const_fn", - "crossbeam-utils", + "crossbeam-utils 0.8.0", "lazy_static", "memoffset", "scopeguard", ] +[[package]] +name = "crossbeam-utils" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8" +dependencies = [ + "autocfg 1.0.1", + "cfg-if 0.1.10", + "lazy_static", +] + [[package]] name = "crossbeam-utils" version = "0.8.0" @@ -1510,6 +1531,15 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +[[package]] +name = "pipe" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bcd11e042e056991b5df9c0c5ae6bd0cce219b74294c40f65b89f40f7030106c" +dependencies = [ + "crossbeam-channel 0.4.4", +] + [[package]] name = "pkg-config" version = "0.3.19" @@ -1813,9 +1843,9 @@ version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ab346ac5921dc62ffa9f89b7a773907511cdfa5490c572ae9be1be33e8afa4a" dependencies = [ - "crossbeam-channel", + "crossbeam-channel 0.5.0", "crossbeam-deque", - "crossbeam-utils", + "crossbeam-utils 0.8.0", "lazy_static", "num_cpus", ] @@ -1900,12 +1930,12 @@ name = "rustc_codegen_spirv" version = "0.1.0" dependencies = [ "bimap", + "pipe", "pretty_assertions", "rspirv 0.7.0 (git+https://github.com/gfx-rs/rspirv.git?rev=f11f8797bd4df2d1d22cf10767b39a5119c57551)", "spirv-tools", "tar", "tempfile", - "thiserror", "topological-sort", ] diff --git a/crates/rustc_codegen_spirv/Cargo.toml b/crates/rustc_codegen_spirv/Cargo.toml index 13fa72f1bf..5d9aace6f9 100644 --- a/crates/rustc_codegen_spirv/Cargo.toml +++ b/crates/rustc_codegen_spirv/Cargo.toml @@ -30,7 +30,6 @@ use-compiled-tools = ["spirv-tools/use-compiled-tools"] bimap = "0.5" rspirv = { git = "https://github.com/gfx-rs/rspirv.git", rev = "f11f8797bd4df2d1d22cf10767b39a5119c57551" } tar = "0.4.30" -thiserror = "1.0.20" topological-sort = "0.1" [dependencies.spirv-tools] @@ -39,5 +38,6 @@ path = "../spirv-tools" default-features = false [dev-dependencies] +pipe = "0.3" pretty_assertions = "0.6" tempfile = "3.1" diff --git a/crates/rustc_codegen_spirv/src/lib.rs b/crates/rustc_codegen_spirv/src/lib.rs index f431a80dc8..dc527e40a1 100644 --- a/crates/rustc_codegen_spirv/src/lib.rs +++ b/crates/rustc_codegen_spirv/src/lib.rs @@ -113,6 +113,7 @@ use rustc_middle::mir::mono::{Linkage, MonoItem, Visibility}; use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::query::Providers; use rustc_middle::ty::{InstanceDef, TyCtxt}; +use rustc_mir::util::write_mir_pretty; use rustc_session::config::{self, OptLevel, OutputFilenames, OutputType}; use rustc_session::Session; use rustc_span::Symbol; @@ -120,22 +121,24 @@ use rustc_target::spec::abi::Abi; use rustc_target::spec::{LinkerFlavor, PanicStrategy, Target, TargetOptions, TargetTriple}; use std::any::Any; use std::env; +use std::fs::{create_dir_all, File}; +use std::io::Cursor; +use std::io::Write; use std::path::{Path, PathBuf}; -use std::{fs::File, io::Write, sync::Arc}; +use std::sync::Arc; fn dump_mir<'tcx>( tcx: TyCtxt<'tcx>, mono_items: &[(MonoItem<'_>, (Linkage, Visibility))], path: &Path, ) { - std::fs::create_dir_all(path.parent().unwrap()).unwrap(); + create_dir_all(path.parent().unwrap()).unwrap(); let mut file = File::create(path).unwrap(); for &(mono_item, (_, _)) in mono_items { if let MonoItem::Fn(instance) = mono_item { if matches!(instance.def, InstanceDef::Item(_)) { - let mut mir = ::std::io::Cursor::new(Vec::new()); - if rustc_mir::util::write_mir_pretty(tcx, Some(instance.def_id()), &mut mir).is_ok() - { + let mut mir = Cursor::new(Vec::new()); + if write_mir_pretty(tcx, Some(instance.def_id()), &mut mir).is_ok() { writeln!(file, "{}", String::from_utf8(mir.into_inner()).unwrap()).unwrap() } } @@ -270,8 +273,8 @@ impl CodegenBackend for SpirvCodegenBackend { fn codegen_crate( &self, - tcx: rustc_middle::ty::TyCtxt<'_>, - metadata: rustc_middle::middle::cstore::EncodedMetadata, + tcx: TyCtxt<'_>, + metadata: EncodedMetadata, need_metadata_module: bool, ) -> Box { Box::new(rustc_codegen_ssa::base::codegen_crate( @@ -550,7 +553,7 @@ struct DumpModuleOnPanic<'a, 'cx, 'tcx> { impl Drop for DumpModuleOnPanic<'_, '_, '_> { fn drop(&mut self) { if std::thread::panicking() { - let path: &std::path::Path = self.path.as_ref(); + let path: &Path = self.path.as_ref(); if path.has_root() { self.cx.builder.dump_module(path); } else { diff --git a/crates/rustc_codegen_spirv/src/link.rs b/crates/rustc_codegen_spirv/src/link.rs index e5a5913987..bf4a608e57 100644 --- a/crates/rustc_codegen_spirv/src/link.rs +++ b/crates/rustc_codegen_spirv/src/link.rs @@ -386,15 +386,13 @@ fn do_link(sess: &Session, objects: &[PathBuf], rlibs: &[PathBuf], legalize: boo } } - let mut module_refs = modules.iter_mut().collect::>(); - if let Ok(ref path) = env::var("DUMP_PRE_LINK") { let path = Path::new(path); if path.is_file() { std::fs::remove_file(path).unwrap(); } std::fs::create_dir_all(path).unwrap(); - for (num, module) in module_refs.iter().enumerate() { + for (num, module) in modules.iter().enumerate() { File::create(path.join(format!("mod_{}.spv", num))) .unwrap() .write_all(crate::slice_u32_to_u8(&module.assemble())) @@ -412,25 +410,13 @@ fn do_link(sess: &Session, objects: &[PathBuf], rlibs: &[PathBuf], legalize: boo structurize: env::var("NO_STRUCTURIZE").is_err(), }; - let link_result = linker::link(Some(sess), &mut module_refs, &options); + let link_result = linker::link(sess, modules, &options); let assembled = match link_result { Ok(v) => v, - Err(err) => { - if let Ok(ref path) = env::var("DUMP_MODULE_ON_PANIC") { - let path = Path::new(path); - if path.is_file() { - std::fs::remove_file(path).unwrap(); - } - std::fs::create_dir_all(path).unwrap(); - for (num, module) in modules.iter().enumerate() { - File::create(path.join(format!("mod_{}.spv", num))) - .unwrap() - .write_all(crate::slice_u32_to_u8(&module.assemble())) - .unwrap(); - } - } - sess.fatal(&format!("Linker error: {}", err)) + Err(rustc_errors::ErrorReported) => { + sess.abort_if_errors(); + bug!("Linker errored, but no error reported") } }; diff --git a/crates/rustc_codegen_spirv/src/linker/import_export_link.rs b/crates/rustc_codegen_spirv/src/linker/import_export_link.rs index 2f1f16d2f9..aaa3ebc81c 100644 --- a/crates/rustc_codegen_spirv/src/linker/import_export_link.rs +++ b/crates/rustc_codegen_spirv/src/linker/import_export_link.rs @@ -1,10 +1,13 @@ -use super::{LinkerError, Result}; +use super::Result; use rspirv::dr::{Instruction, Module}; use rspirv::spirv::{Capability, Decoration, LinkageType, Op, Word}; +use rustc_errors::ErrorReported; +use rustc_session::Session; use std::collections::{HashMap, HashSet}; -pub fn run(module: &mut Module) -> Result<()> { - let (rewrite_rules, killed_parameters) = find_import_export_pairs_and_killed_params(module)?; +pub fn run(sess: &Session, module: &mut Module) -> Result<()> { + let (rewrite_rules, killed_parameters) = + find_import_export_pairs_and_killed_params(sess, module)?; kill_linkage_instructions(module, &rewrite_rules); import_kill_annotations_and_debug(module, &rewrite_rules, &killed_parameters); replace_all_uses_with(module, &rewrite_rules); @@ -12,6 +15,7 @@ pub fn run(module: &mut Module) -> Result<()> { } fn find_import_export_pairs_and_killed_params( + sess: &Session, module: &Module, ) -> Result<(HashMap, HashSet)> { let type_map = get_type_map(module); @@ -31,7 +35,8 @@ fn find_import_export_pairs_and_killed_params( }; let type_id = *type_map.get(&id).expect("Unexpected op"); if exports.insert(name, (id, type_id)).is_some() { - return Err(LinkerError::MultipleExports(name.to_string())); + sess.err(&format!("Multiple exports found for {:?}", name)); + return Err(ErrorReported); } } // Then, collect all the imports, and create the rewrite rules. @@ -42,13 +47,14 @@ fn find_import_export_pairs_and_killed_params( }; let (export_id, export_type) = match exports.get(name) { None => { - return Err(LinkerError::UnresolvedSymbol(name.to_string())); + sess.err(&format!("Unresolved symbol {:?}", name)); + return Err(ErrorReported); } Some(&x) => x, }; let import_type = *type_map.get(&import_id).expect("Unexpected op"); // Make sure the import/export pair has the same type. - check_tys_equal(name, import_type, export_type)?; + check_tys_equal(sess, name, import_type, export_type)?; rewrite_rules.insert(import_id, export_id); if let Some(params) = fn_parameters.get(&import_id) { for ¶m in params { @@ -97,13 +103,12 @@ fn fn_parameters(module: &Module) -> HashMap> { .collect() } -fn check_tys_equal(name: &str, import_type: Word, export_type: Word) -> Result<()> { +fn check_tys_equal(sess: &Session, name: &str, import_type: Word, export_type: Word) -> Result<()> { if import_type == export_type { Ok(()) } else { - Err(LinkerError::TypeMismatch { - name: name.to_string(), - }) + sess.err(&format!("Types mismatch for {:?}", name)); + Err(ErrorReported) } } diff --git a/crates/rustc_codegen_spirv/src/linker/mod.rs b/crates/rustc_codegen_spirv/src/linker/mod.rs index 5bb5f82c37..8645ac0bcb 100644 --- a/crates/rustc_codegen_spirv/src/linker/mod.rs +++ b/crates/rustc_codegen_spirv/src/linker/mod.rs @@ -14,31 +14,11 @@ mod zombies; use rspirv::binary::Consumer; use rspirv::dr::{Block, Instruction, Loader, Module, ModuleHeader}; use rspirv::spirv::{Op, Word}; +use rustc_errors::ErrorReported; use rustc_session::Session; use std::collections::HashMap; -use thiserror::Error; -#[derive(Error, Debug, PartialEq)] -pub enum LinkerError { - #[error("Unresolved symbol {:?}", .0)] - UnresolvedSymbol(String), - #[error("Multiple exports found for {:?}", .0)] - MultipleExports(String), - #[error("Types mismatch for {:?}", .name)] - TypeMismatch { name: String }, - #[error("spirv-tools error {:#}", .0)] - #[cfg(test)] - SpirvTool(spirv_tools::Error), -} - -#[cfg(test)] -impl From for LinkerError { - fn from(err: spirv_tools::Error) -> Self { - Self::SpirvTool(err) - } -} - -pub type Result = std::result::Result; +pub type Result = std::result::Result; pub struct Options { pub compact_ids: bool, @@ -88,10 +68,9 @@ fn apply_rewrite_rules(rewrite_rules: &HashMap, blocks: &mut [Block] // Sess needs to be Option because linker tests call this method, and linker tests can't synthesize // a test Session (not sure how to do that). -pub fn link(sess: Option<&Session>, inputs: &mut [&mut Module], opts: &Options) -> Result { - let timer = |n| sess.map(|s| s.timer(n)); +pub fn link(sess: &Session, mut inputs: Vec, opts: &Options) -> Result { let mut output = { - let _timer = timer("link_merge"); + let _timer = sess.timer("link_merge"); // shift all the ids let mut bound = inputs[0].header.as_ref().unwrap().bound - 1; let version = inputs[0].header.as_ref().unwrap().version(); @@ -101,20 +80,17 @@ pub fn link(sess: Option<&Session>, inputs: &mut [&mut Module], opts: &Options) bound += module.header.as_ref().unwrap().bound - 1; let this_version = module.header.as_ref().unwrap().version(); if version != this_version { - match sess { - Some(sess) => sess.fatal(&format!( - "cannot link two modules with different SPIR-V versions: v{}.{} and v{}.{}", - version.0, version.1, this_version.0, this_version.1 - )), - None => panic!("spir-v version mismatch: {:?} {:?}", version, this_version), - } + sess.fatal(&format!( + "cannot link two modules with different SPIR-V versions: v{}.{} and v{}.{}", + version.0, version.1, this_version.0, this_version.1 + )) } } // merge the binaries let mut loader = Loader::new(); - for module in inputs.iter() { + for module in inputs { module.all_inst_iter().for_each(|inst| { loader.consume_instruction(inst.clone()); }); @@ -129,7 +105,7 @@ pub fn link(sess: Option<&Session>, inputs: &mut [&mut Module], opts: &Options) // remove duplicates (https://github.com/KhronosGroup/SPIRV-Tools/blob/e7866de4b1dc2a7e8672867caeb0bdca49f458d3/source/opt/remove_duplicates_pass.cpp) { - let _timer = timer("link_remove_duplicates"); + let _timer = sess.timer("link_remove_duplicates"); duplicates::remove_duplicate_extensions(&mut output); duplicates::remove_duplicate_capablities(&mut output); duplicates::remove_duplicate_ext_inst_imports(&mut output); @@ -139,32 +115,32 @@ pub fn link(sess: Option<&Session>, inputs: &mut [&mut Module], opts: &Options) // find import / export pairs { - let _timer = timer("link_find_pairs"); - import_export_link::run(&mut output)?; + let _timer = sess.timer("link_find_pairs"); + import_export_link::run(sess, &mut output)?; } { - let _timer = timer("link_remove_zombies"); + let _timer = sess.timer("link_remove_zombies"); zombies::remove_zombies(sess, &mut output); } if opts.inline { - let _timer = timer("link_inline"); + let _timer = sess.timer("link_inline"); inline::inline(&mut output); } if opts.dce { - let _timer = timer("link_dce"); + let _timer = sess.timer("link_dce"); dce::dce(&mut output); } if opts.structurize { - let _timer = timer("link_structurize"); + let _timer = sess.timer("link_structurize"); structurizer::structurize(sess, &mut output); } { - let _timer = timer("link_block_ordering_pass_and_mem2reg"); + let _timer = sess.timer("link_block_ordering_pass_and_mem2reg"); let mut pointer_to_pointee = HashMap::new(); let mut constants = HashMap::new(); if opts.mem2reg { @@ -205,18 +181,18 @@ pub fn link(sess: Option<&Session>, inputs: &mut [&mut Module], opts: &Options) } } { - let _timer = timer("link_sort_globals"); + let _timer = sess.timer("link_sort_globals"); simple_passes::sort_globals(&mut output); } { - let _timer = timer("link_remove_extra_capabilities"); + let _timer = sess.timer("link_remove_extra_capabilities"); capability_computation::remove_extra_capabilities(&mut output); capability_computation::remove_extra_extensions(&mut output); } if opts.compact_ids { - let _timer = timer("link_compact_ids"); + let _timer = sess.timer("link_compact_ids"); // compact the ids https://github.com/KhronosGroup/SPIRV-Tools/blob/e02f178a716b0c3c803ce31b9df4088596537872/source/opt/compact_ids_pass.cpp#L43 output.header.as_mut().unwrap().bound = simple_passes::compact_ids(&mut output); }; diff --git a/crates/rustc_codegen_spirv/src/linker/structurizer.rs b/crates/rustc_codegen_spirv/src/linker/structurizer.rs index d3ece57adb..6be752cd6f 100644 --- a/crates/rustc_codegen_spirv/src/linker/structurizer.rs +++ b/crates/rustc_codegen_spirv/src/linker/structurizer.rs @@ -132,15 +132,7 @@ impl ControlFlowInfo { } } -fn emit_compiler_error(sess: Option<&Session>, msg: &'static str) -> ! { - if let Some(sess) = sess { - sess.fatal(msg); - } else { - panic!(msg); - } -} - -pub fn structurize(sess: Option<&Session>, module: &mut Module) { +pub fn structurize(sess: &Session, module: &mut Module) { let mut debug_names = Vec::new(); for func in &mut module.functions { @@ -508,7 +500,7 @@ fn make_unreachable_block(header: &mut ModuleHeader, blocks: &mut Vec) -> } pub fn insert_selection_merge_on_conditional_branch( - sess: Option<&Session>, + sess: &Session, header: &mut ModuleHeader, blocks: &mut Vec, cf_info: &mut ControlFlowInfo, @@ -580,19 +572,13 @@ pub fn insert_selection_merge_on_conditional_branch( blocks[a_first_idx].label_id().unwrap() } else if branch_a_returns { // (partially unreachable) merge block becomes end/start of b. - emit_compiler_error( - sess, - "UNIMPLEMENTED, A partially unreachable case was detected on a.", - ); + sess.fatal("UNIMPLEMENTED, A partially unreachable case was detected on a."); } else if branch_b_returns { // (partially unreachable) merge block becomes end/start of a. - emit_compiler_error( - sess, - "UNIMPLEMENTED, A partially unreachable case was detected on b.", - ); + sess.fatal("UNIMPLEMENTED, A partially unreachable case was detected on b."); } else { // In theory this should never happen. - emit_compiler_error(sess, "UNEXPECTED, Unknown exit detected."); + sess.fatal("UNEXPECTED, Unknown exit detected."); } }; diff --git a/crates/rustc_codegen_spirv/src/linker/test.rs b/crates/rustc_codegen_spirv/src/linker/test.rs index e875b34c0e..bdc64f2e87 100644 --- a/crates/rustc_codegen_spirv/src/linker/test.rs +++ b/crates/rustc_codegen_spirv/src/linker/test.rs @@ -1,5 +1,13 @@ -use super::{link, LinkerError, Options, Result}; +use super::{link, Options}; +use pipe::pipe; use rspirv::dr::{Loader, Module}; +use rustc_driver::handle_options; +use rustc_errors::registry::Registry; +use rustc_session::config::build_session_options; +use rustc_session::config::Input; +use rustc_session::DiagnosticOutput; +use std::io::Read; +use std::path::PathBuf; // https://github.com/colin-kiegel/rust-pretty-assertions/issues/24 #[derive(PartialEq, Eq)] @@ -12,15 +20,17 @@ impl<'a> std::fmt::Debug for PrettyString<'a> { } } -fn assemble_spirv(spirv: &str) -> Result> { +fn assemble_spirv(spirv: &str) -> Vec { use spirv_tools::assembler::{self, Assembler}; let assembler = assembler::create(None); - let spv_binary = assembler.assemble(spirv, assembler::AssemblerOptions::default())?; + let spv_binary = assembler + .assemble(spirv, assembler::AssemblerOptions::default()) + .expect("Failed to assemble test spir-v"); let contents: &[u8] = spv_binary.as_ref(); - Ok(contents.to_vec()) + contents.to_vec() } #[allow(unused)] @@ -40,21 +50,56 @@ fn load(bytes: &[u8]) -> Module { loader.module() } -fn assemble_and_link(binaries: &[&[u8]]) -> super::Result { - let mut modules = binaries.iter().cloned().map(load).collect::>(); - let mut modules = modules.iter_mut().collect::>(); +fn assemble_and_link(binaries: &[&[u8]]) -> Result { + let modules = binaries.iter().cloned().map(load).collect::>(); - link( - None, - &mut modules, - &Options { - compact_ids: true, - dce: false, - inline: false, - mem2reg: false, - structurize: false, - }, - ) + // need pipe here because Config takes ownership of the writer, and the writer must be 'static. + let (mut read_diags, write_diags) = pipe(); + let thread = std::thread::spawn(move || { + // must spawn thread because pipe crate is synchronous + let mut diags = String::new(); + read_diags.read_to_string(&mut diags).unwrap(); + let suffix = "\n\nerror: aborting due to previous error\n\n"; + if diags.ends_with(suffix) { + diags.truncate(diags.len() - suffix.len()); + } + diags + }); + let matches = handle_options(&["".to_string(), "x.rs".to_string()]).unwrap(); + let sopts = build_session_options(&matches); + let config = rustc_interface::Config { + opts: sopts, + crate_cfg: Default::default(), + input: Input::File(PathBuf::new()), + input_path: None, + output_file: None, + output_dir: None, + file_loader: None, + diagnostic_output: DiagnosticOutput::Raw(Box::new(write_diags)), + stderr: None, + crate_name: None, + lint_caps: Default::default(), + register_lints: None, + override_queries: None, + make_codegen_backend: None, + registry: Registry::new(&[]), + }; + let res = rustc_interface::interface::run_compiler(config, |compiler| { + let res = link( + compiler.session(), + modules, + &Options { + compact_ids: true, + dce: false, + inline: false, + mem2reg: false, + structurize: false, + }, + ); + assert_eq!(compiler.session().has_errors(), res.is_err()); + res + }); + res.map_err(|_| thread.join().unwrap()) } fn without_header_eq(mut result: Module, expected: &str) { @@ -91,14 +136,14 @@ fn without_header_eq(mut result: Module, expected: &str) { } #[test] -fn standard() -> Result<()> { +fn standard() { let a = assemble_spirv( r#"OpCapability Linkage OpDecorate %1 LinkageAttributes "foo" Import %2 = OpTypeFloat 32 %1 = OpVariable %2 Uniform %3 = OpVariable %2 Input"#, - )?; + ); let b = assemble_spirv( r#"OpCapability Linkage @@ -107,38 +152,19 @@ fn standard() -> Result<()> { %3 = OpConstant %2 42 %1 = OpVariable %2 Uniform %3 "#, - )?; + ); - let result = assemble_and_link(&[&a, &b])?; + let result = assemble_and_link(&[&a, &b]).unwrap(); let expect = r#"%1 = OpTypeFloat 32 %2 = OpVariable %1 Input %3 = OpConstant %1 42.0 %4 = OpVariable %1 Uniform %3"#; without_header_eq(result, expect); - Ok(()) } #[test] -fn not_a_lib_extra_exports() -> Result<()> { - let a = assemble_spirv( - r#"OpCapability Linkage - OpDecorate %1 LinkageAttributes "foo" Export - %2 = OpTypeFloat 32 - %1 = OpVariable %2 Uniform"#, - )?; - - let result = assemble_and_link(&[&a])?; - let expect = r#"%1 = OpTypeFloat 32 - %2 = OpVariable %1 Uniform"#; - without_header_eq(result, expect); - Ok(()) -} - -// TODO: Lib mode is not supported yet. Double-TODO: Will it *ever* be supported? (probably not) -/* -#[test] -fn lib_extra_exports() -> Result<()> { +fn not_a_lib_extra_exports() { let a = assemble_spirv( r#"OpCapability Linkage OpDecorate %1 LinkageAttributes "foo" Export @@ -146,46 +172,40 @@ fn lib_extra_exports() -> Result<()> { %1 = OpVariable %2 Uniform"#, ); - let result = assemble_and_link(&[&a])?; - - let expect = r#"OpDecorate %1 LinkageAttributes "foo" Export - %2 = OpTypeFloat 32 - %1 = OpVariable %2 Uniform"#; + let result = assemble_and_link(&[&a]).unwrap(); + let expect = r#"%1 = OpTypeFloat 32 + %2 = OpVariable %1 Uniform"#; without_header_eq(result, expect); - Ok(()) } -*/ #[test] -fn unresolved_symbol() -> Result<()> { +fn unresolved_symbol() { let a = assemble_spirv( r#"OpCapability Linkage OpDecorate %1 LinkageAttributes "foo" Import %2 = OpTypeFloat 32 %1 = OpVariable %2 Uniform"#, - )?; + ); - let b = assemble_spirv("OpCapability Linkage")?; + let b = assemble_spirv("OpCapability Linkage"); let result = assemble_and_link(&[&a, &b]); assert_eq!( - result.err(), - Some(LinkerError::UnresolvedSymbol("foo".to_string())) + result.err().as_deref(), + Some("error: Unresolved symbol \"foo\"") ); - - Ok(()) } #[test] -fn type_mismatch() -> Result<()> { +fn type_mismatch() { let a = assemble_spirv( r#"OpCapability Linkage OpDecorate %1 LinkageAttributes "foo" Import %2 = OpTypeFloat 32 %1 = OpVariable %2 Uniform %3 = OpVariable %2 Input"#, - )?; + ); let b = assemble_spirv( r#"OpCapability Linkage @@ -194,27 +214,24 @@ fn type_mismatch() -> Result<()> { %3 = OpConstant %2 42 %1 = OpVariable %2 Uniform %3 "#, - )?; + ); let result = assemble_and_link(&[&a, &b]); assert_eq!( - result.err(), - Some(LinkerError::TypeMismatch { - name: "foo".to_string(), - }) + result.err().as_deref(), + Some("error: Types mismatch for \"foo\"") ); - Ok(()) } #[test] -fn multiple_definitions() -> Result<()> { +fn multiple_definitions() { let a = assemble_spirv( r#"OpCapability Linkage OpDecorate %1 LinkageAttributes "foo" Import %2 = OpTypeFloat 32 %1 = OpVariable %2 Uniform %3 = OpVariable %2 Input"#, - )?; + ); let b = assemble_spirv( r#"OpCapability Linkage @@ -223,7 +240,7 @@ fn multiple_definitions() -> Result<()> { %2 = OpTypeFloat 32 %3 = OpConstant %2 42 %1 = OpVariable %2 Uniform %3"#, - )?; + ); let c = assemble_spirv( r#"OpCapability Linkage @@ -231,25 +248,24 @@ fn multiple_definitions() -> Result<()> { %2 = OpTypeFloat 32 %3 = OpConstant %2 -1 %1 = OpVariable %2 Uniform %3"#, - )?; + ); let result = assemble_and_link(&[&a, &b, &c]); assert_eq!( - result.err(), - Some(LinkerError::MultipleExports("foo".to_string())) + result.err().as_deref(), + Some("error: Multiple exports found for \"foo\"") ); - Ok(()) } #[test] -fn multiple_definitions_different_types() -> Result<()> { +fn multiple_definitions_different_types() { let a = assemble_spirv( r#"OpCapability Linkage OpDecorate %1 LinkageAttributes "foo" Import %2 = OpTypeFloat 32 %1 = OpVariable %2 Uniform %3 = OpVariable %2 Input"#, - )?; + ); let b = assemble_spirv( r#"OpCapability Linkage @@ -258,7 +274,7 @@ fn multiple_definitions_different_types() -> Result<()> { %2 = OpTypeInt 32 0 %3 = OpConstant %2 42 %1 = OpVariable %2 Uniform %3"#, - )?; + ); let c = assemble_spirv( r#"OpCapability Linkage @@ -266,19 +282,18 @@ fn multiple_definitions_different_types() -> Result<()> { %2 = OpTypeFloat 32 %3 = OpConstant %2 12 %1 = OpVariable %2 Uniform %3"#, - )?; + ); let result = assemble_and_link(&[&a, &b, &c]); assert_eq!( - result.err(), - Some(LinkerError::MultipleExports("foo".to_string())) + result.err().as_deref(), + Some("error: Multiple exports found for \"foo\"") ); - Ok(()) } //jb-todo: this isn't validated yet in the linker (see ensure_matching_import_export_pairs) /*#[test] -fn decoration_mismatch() -> Result<()> { +fn decoration_mismatch() { let a = assemble_spirv( r#"OpCapability Linkage OpDecorate %1 LinkageAttributes "foo" Import @@ -305,7 +320,7 @@ fn decoration_mismatch() -> Result<()> { }*/ #[test] -fn func_ctrl() -> Result<()> { +fn func_ctrl() { let a = assemble_spirv( r#"OpCapability Linkage OpDecorate %1 LinkageAttributes "foo" Import @@ -315,7 +330,7 @@ fn func_ctrl() -> Result<()> { %5 = OpVariable %4 Uniform %1 = OpFunction %2 None %3 OpFunctionEnd"#, - )?; + ); let b = assemble_spirv( r#"OpCapability Linkage @@ -326,9 +341,9 @@ fn func_ctrl() -> Result<()> { %4 = OpLabel OpReturn OpFunctionEnd"#, - )?; + ); - let result = assemble_and_link(&[&a, &b])?; + let result = assemble_and_link(&[&a, &b]).unwrap(); let expect = r#"%1 = OpTypeVoid %2 = OpTypeFunction %1 @@ -340,11 +355,10 @@ fn func_ctrl() -> Result<()> { OpFunctionEnd"#; without_header_eq(result, expect); - Ok(()) } #[test] -fn use_exported_func_param_attr() -> Result<()> { +fn use_exported_func_param_attr() { let a = assemble_spirv( r#"OpCapability Kernel OpCapability Linkage @@ -362,7 +376,7 @@ fn use_exported_func_param_attr() -> Result<()> { %4 = OpFunctionParameter %6 OpFunctionEnd "#, - )?; + ); let b = assemble_spirv( r#"OpCapability Kernel @@ -378,9 +392,9 @@ fn use_exported_func_param_attr() -> Result<()> { OpReturn OpFunctionEnd "#, - )?; + ); - let result = assemble_and_link(&[&a, &b])?; + let result = assemble_and_link(&[&a, &b]).unwrap(); let expect = r#"OpCapability Kernel OpDecorate %1 FuncParamAttr Zext @@ -400,11 +414,10 @@ fn use_exported_func_param_attr() -> Result<()> { OpFunctionEnd"#; without_header_eq(result, expect); - Ok(()) } #[test] -fn names_and_decorations() -> Result<()> { +fn names_and_decorations() { let a = assemble_spirv( r#"OpCapability Kernel OpCapability Linkage @@ -426,7 +439,7 @@ fn names_and_decorations() -> Result<()> { %4 = OpFunctionParameter %9 OpFunctionEnd "#, - )?; + ); let b = assemble_spirv( r#"OpCapability Kernel @@ -445,9 +458,9 @@ fn names_and_decorations() -> Result<()> { OpReturn OpFunctionEnd "#, - )?; + ); - let result = assemble_and_link(&[&a, &b])?; + let result = assemble_and_link(&[&a, &b]).unwrap(); let expect = r#"OpCapability Kernel OpName %1 "foo" @@ -471,5 +484,4 @@ fn names_and_decorations() -> Result<()> { OpFunctionEnd"#; without_header_eq(result, expect); - Ok(()) } diff --git a/crates/rustc_codegen_spirv/src/linker/zombies.rs b/crates/rustc_codegen_spirv/src/linker/zombies.rs index d27b93a667..cb86a3c631 100644 --- a/crates/rustc_codegen_spirv/src/linker/zombies.rs +++ b/crates/rustc_codegen_spirv/src/linker/zombies.rs @@ -160,7 +160,7 @@ fn report_error_zombies(sess: &Session, module: &Module, zombie: &HashMap, module: &mut Module) { +pub fn remove_zombies(sess: &Session, module: &mut Module) { let zombies_owned = collect_zombies(module); let mut zombies = zombies_owned .iter() @@ -170,9 +170,7 @@ pub fn remove_zombies(sess: Option<&Session>, module: &mut Module) { // Note: This is O(n^2). while spread_zombie(module, &mut zombies) {} - if let Some(sess) = sess { - report_error_zombies(sess, module, &zombies); - } + report_error_zombies(sess, module, &zombies); if env::var("PRINT_ALL_ZOMBIE").is_ok() { for (&zomb, reason) in &zombies {