Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support GLSL450 and Simple memory models #168

Merged
merged 3 commits into from
Oct 28, 2020
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 10 additions & 3 deletions rustc_codegen_spirv/src/builder_spirv.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,17 +71,24 @@ pub struct BuilderSpirv {
}

impl BuilderSpirv {
pub fn new(version: Option<(u8, u8)>, kernel_mode: bool) -> Self {
pub fn new(
version: Option<(u8, u8)>,
memory_model: Option<MemoryModel>,
kernel_mode: bool,
) -> Self {
let mut builder = Builder::new();
// Default to spir-v 1.3
let version = version.unwrap_or((1, 3));
builder.set_version(version.0, version.1);
let memory_model = memory_model.unwrap_or(MemoryModel::Vulkan);
if kernel_mode {
builder.capability(Capability::Kernel);
} else {
builder.extension("SPV_KHR_vulkan_memory_model");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this extension actually needed?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, the vulkan memory model isn't present for spir-v versions less than 1.5. I'll fix this, though.

builder.capability(Capability::Shader);
builder.capability(Capability::VulkanMemoryModel);
if memory_model == MemoryModel::Vulkan {
builder.capability(Capability::VulkanMemoryModel);
}
builder.capability(Capability::VariablePointers);
if version < (1, 3) {
builder.extension("SPV_KHR_variable_pointers");
Expand All @@ -98,7 +105,7 @@ impl BuilderSpirv {
builder.capability(Capability::Addresses);
builder.memory_model(AddressingModel::Physical32, MemoryModel::OpenCL);
} else {
builder.memory_model(AddressingModel::Logical, MemoryModel::Vulkan);
builder.memory_model(AddressingModel::Logical, memory_model);
}
Self {
builder: RefCell::new(builder),
Expand Down
15 changes: 12 additions & 3 deletions rustc_codegen_spirv/src/codegen_cx/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use crate::spirv_type::{SpirvType, SpirvTypePrinter, TypeCache};
use crate::symbols::Symbols;
use bimap::BiHashMap;
use rspirv::dr::{Module, Operand};
use rspirv::spirv::{Decoration, LinkageType, StorageClass, Word};
use rspirv::spirv::{Decoration, LinkageType, MemoryModel, StorageClass, Word};
use rustc_codegen_ssa::mir::debuginfo::{FunctionDebugContext, VariableKind};
use rustc_codegen_ssa::traits::{
AsmMethods, BackendTypes, CoverageInfoMethods, DebugInfoMethods, MiscMethods,
Expand Down Expand Up @@ -63,8 +63,9 @@ 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 mut kernel_mode = false;
let mut spirv_version = None;
let mut memory_model = None;
let mut kernel_mode = false;
for &feature in &tcx.sess.target_features {
if feature == sym.kernel {
kernel_mode = true;
Expand All @@ -80,12 +81,20 @@ impl<'tcx> CodegenCx<'tcx> {
spirv_version = Some((1, 4));
} else if feature == sym.spirv15 {
spirv_version = Some((1, 5));
} else if feature == sym.simple {
memory_model = Some(MemoryModel::Simple);
} else if feature == sym.vulkan {
memory_model = Some(MemoryModel::Vulkan);
} else if feature == sym.glsl450 {
memory_model = Some(MemoryModel::GLSL450);
} else {
tcx.sess.err(&format!("Unknown feature {}", feature));
}
}
Self {
tcx,
codegen_unit,
builder: BuilderSpirv::new(spirv_version, kernel_mode),
builder: BuilderSpirv::new(spirv_version, memory_model, kernel_mode),
instances: Default::default(),
function_parameter_values: Default::default(),
type_cache: Default::default(),
Expand Down
6 changes: 6 additions & 0 deletions rustc_codegen_spirv/src/symbols.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ pub struct Symbols {
pub spirv: Symbol,
pub spirv_std: Symbol,
pub kernel: Symbol,
pub simple: Symbol,
pub vulkan: Symbol,
pub glsl450: Symbol,
pub spirv10: Symbol,
pub spirv11: Symbol,
pub spirv12: Symbol,
Expand Down Expand Up @@ -217,6 +220,9 @@ impl Symbols {
spirv: Symbol::intern("spirv"),
spirv_std: Symbol::intern("spirv_std"),
kernel: Symbol::intern("kernel"),
simple: Symbol::intern("simple"),
vulkan: Symbol::intern("vulkan"),
glsl450: Symbol::intern("glsl450"),
spirv10: Symbol::intern("spirv1.0"),
spirv11: Symbol::intern("spirv1.1"),
spirv12: Symbol::intern("spirv1.2"),
Expand Down
55 changes: 39 additions & 16 deletions spirv-builder/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,17 +27,25 @@ impl fmt::Display for SpirvBuilderError {

impl Error for SpirvBuilderError {}

pub enum MemoryModel {
Simple,
Vulkan,
GLSL450,
}

pub struct SpirvBuilder {
path_to_crate: PathBuf,
print_metadata: bool,
spirv_version: Option<(u8, u8)>,
memory_model: Option<MemoryModel>,
}
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,
memory_model: None,
}
}

Expand All @@ -47,20 +55,23 @@ impl SpirvBuilder {
self
}

/// Sets the SPIR-V binary version to use. Defaults to v1.3.
pub fn spirv_version(mut self, major: u8, minor: u8) -> Self {
self.spirv_version = Some((major, minor));
self
}

/// Sets the SPIR-V memory model. Defaults to Vulkan.
pub fn memory_model(mut self, memory_model: MemoryModel) -> Self {
self.memory_model = Some(memory_model);
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,
self.spirv_version,
)?;
let spirv_module = invoke_rustc(&self)?;
let env_var = spirv_module.file_name().unwrap().to_str().unwrap();
if self.print_metadata {
println!("cargo:rustc-env={}={}", env_var, spirv_module.display());
Expand Down Expand Up @@ -101,11 +112,7 @@ fn find_rustc_codegen_spirv() -> PathBuf {
panic!("Could not find {} in library path", filename);
}

fn invoke_rustc(
path_to_crate: &Path,
print_metadata: bool,
spirv_version: Option<(u8, u8)>,
) -> Result<PathBuf, SpirvBuilderError> {
fn invoke_rustc(builder: &SpirvBuilder) -> 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
Expand All @@ -115,14 +122,30 @@ fn invoke_rustc(
// 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 spirv_version_feture = match spirv_version {
None => "".to_string(),
Some((major, minor)) => format!(" -C target-feature=+spirv{}.{}", major, minor),
let mut target_features = Vec::new();
// these must match codegen_cx/mod.rs
if let Some((major, minor)) = builder.spirv_version {
target_features.push(format!("+spirv{}.{}", major, minor));
}
if let Some(memory_model) = &builder.memory_model {
target_features.push(
match memory_model {
MemoryModel::Simple => "+simple",
MemoryModel::Vulkan => "+vulkan",
MemoryModel::GLSL450 => "+glsl450",
}
.to_string(),
);
}
let feature_flag = if target_features.is_empty() {
String::new()
} else {
format!(" -C target-feature={}", target_features.join(","))
};
let rustflags = format!(
"-Z codegen-backend={}{}",
rustc_codegen_spirv.display(),
spirv_version_feture
feature_flag,
);
let build = Command::new("cargo")
.args(&[
Expand All @@ -135,14 +158,14 @@ fn invoke_rustc(
"--release",
])
.stderr(Stdio::inherit())
.current_dir(path_to_crate)
.current_dir(&builder.path_to_crate)
.env("RUSTFLAGS", rustflags)
.output()
.expect("failed to execute cargo build");
if build.status.success() {
let stdout = String::from_utf8(build.stdout).unwrap();
let artifact = get_last_artifact(&stdout);
if print_metadata {
if builder.print_metadata {
print_deps_of(&artifact);
}
Ok(artifact)
Expand Down