Add support for spir-v 1.0 (#165)

This commit is contained in:
Ashley Hauck 2020-10-28 10:08:01 +01:00 committed by GitHub
parent 706f4cc695
commit 23819c7a2c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 72 additions and 28 deletions

View File

@ -3,6 +3,8 @@ use std::error::Error;
fn main() -> Result<(), Box<dyn Error>> {
// 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(())
}

View File

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

View File

@ -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(),

View File

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

View File

@ -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

View File

@ -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<Symbol, SpirvAttribute>,
@ -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,

View File

@ -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<Path>) -> 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<PathBuf, SpirvBuilderError> {
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<PathBuf, SpirvBuilderError> {
fn invoke_rustc(
path_to_crate: &Path,
print_metadata: bool,
spirv_version: Option<(u8, u8)>,
) -> Result<PathBuf, SpirvBuilderError> {
// 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<PathBuf, S
// rustc expects a full path, instead of a filename looked up via LD_LIBRARY_PATH, so we need
// to copy cargo's understanding of library lookup and find the library and its full path.
let rustc_codegen_spirv = find_rustc_codegen_spirv();
let rustflags = format!("-Z codegen-backend={}", rustc_codegen_spirv.display());
let spirv_version_feture = match spirv_version {
None => "".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",