From 23819c7a2cd1701161946b057d2a11e1e02dcc3d Mon Sep 17 00:00:00 2001 From: Ashley Hauck Date: Wed, 28 Oct 2020 10:08:01 +0100 Subject: [PATCH] Add support for spir-v 1.0 (#165) --- examples/wgpu-example-runner/build.rs | 4 +++- rustc_codegen_spirv/src/builder_spirv.rs | 10 +++++--- rustc_codegen_spirv/src/codegen_cx/mod.rs | 22 +++++++++++++++-- rustc_codegen_spirv/src/linker/mod.rs | 9 ------- rustc_codegen_spirv/src/linker/test.rs | 14 ++++------- rustc_codegen_spirv/src/symbols.rs | 12 ++++++++++ spirv-builder/src/lib.rs | 29 ++++++++++++++++++++--- 7 files changed, 72 insertions(+), 28 deletions(-) diff --git a/examples/wgpu-example-runner/build.rs b/examples/wgpu-example-runner/build.rs index c06af3be83..0243f6c665 100644 --- a/examples/wgpu-example-runner/build.rs +++ b/examples/wgpu-example-runner/build.rs @@ -3,6 +3,8 @@ use std::error::Error; fn main() -> Result<(), Box> { // This will set the env var `wgpu-example-shader.spv` to a spir-v file that can be include!()'d - SpirvBuilder::new("../wgpu-example-shader").build()?; + SpirvBuilder::new("../wgpu-example-shader") + .spirv_version(1, 0) + .build()?; Ok(()) } diff --git a/rustc_codegen_spirv/src/builder_spirv.rs b/rustc_codegen_spirv/src/builder_spirv.rs index 28baabcb04..f96194c944 100644 --- a/rustc_codegen_spirv/src/builder_spirv.rs +++ b/rustc_codegen_spirv/src/builder_spirv.rs @@ -71,10 +71,11 @@ pub struct BuilderSpirv { } impl BuilderSpirv { - pub fn new(kernel_mode: bool) -> Self { + pub fn new(version: Option<(u8, u8)>, kernel_mode: bool) -> Self { let mut builder = Builder::new(); - // intel-compute-runtime only supports v1.3 - builder.set_version(1, 3); + // Default to spir-v 1.3 + let version = version.unwrap_or((1, 3)); + builder.set_version(version.0, version.1); if kernel_mode { builder.capability(Capability::Kernel); } else { @@ -82,6 +83,9 @@ impl BuilderSpirv { builder.capability(Capability::Shader); builder.capability(Capability::VulkanMemoryModel); builder.capability(Capability::VariablePointers); + if version < (1, 3) { + builder.extension("SPV_KHR_variable_pointers"); + } } // The linker will always be ran on this module builder.capability(Capability::Linkage); diff --git a/rustc_codegen_spirv/src/codegen_cx/mod.rs b/rustc_codegen_spirv/src/codegen_cx/mod.rs index 903dc54d1b..9d3ee8009f 100644 --- a/rustc_codegen_spirv/src/codegen_cx/mod.rs +++ b/rustc_codegen_spirv/src/codegen_cx/mod.rs @@ -63,11 +63,29 @@ pub struct CodegenCx<'tcx> { impl<'tcx> CodegenCx<'tcx> { pub fn new(tcx: TyCtxt<'tcx>, codegen_unit: &'tcx CodegenUnit<'tcx>) -> Self { let sym = Box::new(Symbols::new()); - let kernel_mode = tcx.sess.target_features.contains(&sym.kernel); + let mut kernel_mode = false; + let mut spirv_version = None; + for &feature in &tcx.sess.target_features { + if feature == sym.kernel { + kernel_mode = true; + } else if feature == sym.spirv10 { + spirv_version = Some((1, 0)); + } else if feature == sym.spirv11 { + spirv_version = Some((1, 1)); + } else if feature == sym.spirv12 { + spirv_version = Some((1, 2)); + } else if feature == sym.spirv13 { + spirv_version = Some((1, 3)); + } else if feature == sym.spirv14 { + spirv_version = Some((1, 4)); + } else if feature == sym.spirv15 { + spirv_version = Some((1, 5)); + } + } Self { tcx, codegen_unit, - builder: BuilderSpirv::new(kernel_mode), + builder: BuilderSpirv::new(spirv_version, kernel_mode), instances: Default::default(), function_parameter_values: Default::default(), type_cache: Default::default(), diff --git a/rustc_codegen_spirv/src/linker/mod.rs b/rustc_codegen_spirv/src/linker/mod.rs index 3b78ec5158..1f057372da 100644 --- a/rustc_codegen_spirv/src/linker/mod.rs +++ b/rustc_codegen_spirv/src/linker/mod.rs @@ -223,15 +223,6 @@ pub fn link(sess: Option<&Session>, inputs: &mut [&mut Module], opts: &Options) output.header.as_mut().unwrap().bound = simple_passes::compact_ids(&mut output); }; - output.debugs.push(Instruction::new( - Op::ModuleProcessed, - None, - None, - vec![Operand::LiteralString( - "Linked by rspirv-linker".to_string(), - )], - )); - // output the module Ok(output) } diff --git a/rustc_codegen_spirv/src/linker/test.rs b/rustc_codegen_spirv/src/linker/test.rs index 7bc9c32a13..a504460135 100644 --- a/rustc_codegen_spirv/src/linker/test.rs +++ b/rustc_codegen_spirv/src/linker/test.rs @@ -138,8 +138,7 @@ fn standard() -> Result<()> { ); let result = assemble_and_link(&[&a, &b])?; - let expect = r#"OpModuleProcessed "Linked by rspirv-linker" - %1 = OpTypeFloat 32 + let expect = r#"%1 = OpTypeFloat 32 %2 = OpVariable %1 Input %3 = OpConstant %1 42.0 %4 = OpVariable %1 Uniform %3"#; @@ -158,8 +157,7 @@ fn not_a_lib_extra_exports() -> Result<()> { ); let result = assemble_and_link(&[&a])?; - let expect = r#"OpModuleProcessed "Linked by rspirv-linker" - %1 = OpTypeFloat 32 + let expect = r#"%1 = OpTypeFloat 32 %2 = OpVariable %1 Uniform"#; without_header_eq(result, expect); Ok(()) @@ -178,8 +176,7 @@ fn lib_extra_exports() -> Result<()> { let result = assemble_and_link(&[&a])?; - let expect = r#"OpModuleProcessed "Linked by rspirv-linker" - OpDecorate %1 LinkageAttributes "foo" Export + let expect = r#"OpDecorate %1 LinkageAttributes "foo" Export %2 = OpTypeFloat 32 %1 = OpVariable %2 Uniform"#; without_header_eq(result, expect); @@ -363,8 +360,7 @@ fn func_ctrl() -> Result<()> { let result = assemble_and_link(&[&a, &b])?; - let expect = r#"OpModuleProcessed "Linked by rspirv-linker" - %1 = OpTypeVoid + let expect = r#"%1 = OpTypeVoid %2 = OpTypeFunction %1 %3 = OpTypeFloat 32 %4 = OpVariable %3 Uniform @@ -417,7 +413,6 @@ fn use_exported_func_param_attr() -> Result<()> { let result = assemble_and_link(&[&a, &b])?; let expect = r#"OpCapability Kernel - OpModuleProcessed "Linked by rspirv-linker" OpDecorate %1 FuncParamAttr Zext %1 = OpDecorationGroup OpGroupDecorate %1 %2 @@ -487,7 +482,6 @@ fn names_and_decorations() -> Result<()> { let expect = r#"OpCapability Kernel OpName %1 "foo" OpName %2 "param" - OpModuleProcessed "Linked by rspirv-linker" OpDecorate %3 Restrict OpDecorate %4 NonWritable %3 = OpDecorationGroup diff --git a/rustc_codegen_spirv/src/symbols.rs b/rustc_codegen_spirv/src/symbols.rs index beb8494418..2753aa6cb2 100644 --- a/rustc_codegen_spirv/src/symbols.rs +++ b/rustc_codegen_spirv/src/symbols.rs @@ -13,6 +13,12 @@ pub struct Symbols { pub spirv: Symbol, pub spirv_std: Symbol, pub kernel: Symbol, + pub spirv10: Symbol, + pub spirv11: Symbol, + pub spirv12: Symbol, + pub spirv13: Symbol, + pub spirv14: Symbol, + pub spirv15: Symbol, descriptor_set: Symbol, binding: Symbol, attributes: HashMap, @@ -211,6 +217,12 @@ impl Symbols { spirv: Symbol::intern("spirv"), spirv_std: Symbol::intern("spirv_std"), kernel: Symbol::intern("kernel"), + spirv10: Symbol::intern("spirv1.0"), + spirv11: Symbol::intern("spirv1.1"), + spirv12: Symbol::intern("spirv1.2"), + spirv13: Symbol::intern("spirv1.3"), + spirv14: Symbol::intern("spirv1.4"), + spirv15: Symbol::intern("spirv1.5"), descriptor_set: Symbol::intern("descriptor_set"), binding: Symbol::intern("binding"), attributes, diff --git a/spirv-builder/src/lib.rs b/spirv-builder/src/lib.rs index 43f29154c7..1e373793d7 100644 --- a/spirv-builder/src/lib.rs +++ b/spirv-builder/src/lib.rs @@ -30,12 +30,14 @@ impl Error for SpirvBuilderError {} pub struct SpirvBuilder { path_to_crate: PathBuf, print_metadata: bool, + spirv_version: Option<(u8, u8)>, } impl SpirvBuilder { pub fn new(path_to_crate: impl AsRef) -> Self { Self { path_to_crate: path_to_crate.as_ref().to_owned(), print_metadata: true, + spirv_version: None, } } @@ -45,11 +47,20 @@ impl SpirvBuilder { self } + pub fn spirv_version(mut self, major: u8, minor: u8) -> Self { + self.spirv_version = Some((major, minor)); + self + } + /// Builds the module. Returns the path to the built spir-v file. If print_metadata is true, /// you usually don't have to inspect the path, as the environment variable will already be /// set. pub fn build(self) -> Result { - let spirv_module = invoke_rustc(self.path_to_crate.as_ref(), self.print_metadata)?; + let spirv_module = invoke_rustc( + self.path_to_crate.as_ref(), + self.print_metadata, + self.spirv_version, + )?; let env_var = spirv_module.file_name().unwrap().to_str().unwrap(); if self.print_metadata { println!("cargo:rustc-env={}={}", env_var, spirv_module.display()); @@ -90,7 +101,11 @@ fn find_rustc_codegen_spirv() -> PathBuf { panic!("Could not find {} in library path", filename); } -fn invoke_rustc(path_to_crate: &Path, print_metadata: bool) -> Result { +fn invoke_rustc( + path_to_crate: &Path, + print_metadata: bool, + spirv_version: Option<(u8, u8)>, +) -> Result { // Okay, this is a little bonkers: in a normal world, we'd have the user clone // rustc_codegen_spirv and pass in the path to it, and then we'd invoke cargo to build it, grab // the resulting .so, and pass it into -Z codegen-backend. But that's really gross: the user @@ -100,7 +115,15 @@ fn invoke_rustc(path_to_crate: &Path, print_metadata: bool) -> Result "".to_string(), + Some((major, minor)) => format!(" -C target-feature=+spirv{}.{}", major, minor), + }; + let rustflags = format!( + "-Z codegen-backend={}{}", + rustc_codegen_spirv.display(), + spirv_version_feture + ); let build = Command::new("cargo") .args(&[ "build",