mirror of
https://github.com/EmbarkStudios/rust-gpu.git
synced 2024-11-21 22:34:34 +00:00
Add support for outputting multiple modules, one per entry point (#551)
* Add multimodule feature * Use -Cllvm-args instead of -Ctarget-feature for multimodule * Fix cargo.toml
This commit is contained in:
parent
30c9b1fdc0
commit
c3a3b20e3c
149
Cargo.lock
generated
149
Cargo.lock
generated
@ -1402,9 +1402,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "memoffset"
|
||||
version = "0.6.1"
|
||||
version = "0.6.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "157b4208e3059a8f9e78d559edc658e13df41410cb3ae03979c83130067fdd87"
|
||||
checksum = "cc14fc54a812b4472b4113facc3e44d099fbc0ea2ce0551fa5c703f8edfbfd38"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
@ -1425,17 +1425,17 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "minifb"
|
||||
version = "0.19.2"
|
||||
version = "0.19.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "87b4b6a6da61c3003a41e84ee1f6b56e079f835f4d4fce424fc84092b57ad804"
|
||||
checksum = "7b6e41119d1667465608d36488fa5dcd228057a26c156e25f17f492f38435124"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"orbclient",
|
||||
"raw-window-handle",
|
||||
"tempfile",
|
||||
"wayland-client 0.27.0",
|
||||
"wayland-cursor 0.27.0",
|
||||
"wayland-protocols 0.27.0",
|
||||
"wayland-client",
|
||||
"wayland-cursor",
|
||||
"wayland-protocols",
|
||||
"winapi 0.3.9",
|
||||
"x11-dl",
|
||||
"xkb",
|
||||
@ -1513,6 +1513,13 @@ dependencies = [
|
||||
"spirv-std",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "multibuilder"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"spirv-builder",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "naga"
|
||||
version = "0.3.2"
|
||||
@ -1585,19 +1592,6 @@ dependencies = [
|
||||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nix"
|
||||
version = "0.17.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "50e4785f2c3b7589a0d0c1dd60285e1188adac4006e8abd6dd578e1567027363"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"cc",
|
||||
"cfg-if 0.1.10",
|
||||
"libc",
|
||||
"void",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nix"
|
||||
version = "0.18.0"
|
||||
@ -2110,6 +2104,7 @@ dependencies = [
|
||||
"pretty_assertions",
|
||||
"rspirv",
|
||||
"rustc-demangle",
|
||||
"sanitize-filename",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"smallvec",
|
||||
@ -2169,6 +2164,16 @@ dependencies = [
|
||||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sanitize-filename"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bf18934a12018228c5b55a6dae9df5d0641e3566b3630cb46cc55564068e7c2f"
|
||||
dependencies = [
|
||||
"lazy_static",
|
||||
"regex",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "scoped-tls"
|
||||
version = "1.0.0"
|
||||
@ -2314,9 +2319,9 @@ dependencies = [
|
||||
"log",
|
||||
"memmap2",
|
||||
"nix 0.18.0",
|
||||
"wayland-client 0.28.5",
|
||||
"wayland-cursor 0.28.5",
|
||||
"wayland-protocols 0.28.5",
|
||||
"wayland-client",
|
||||
"wayland-cursor",
|
||||
"wayland-protocols",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -2758,17 +2763,11 @@ version = "0.9.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe"
|
||||
|
||||
[[package]]
|
||||
name = "void"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
|
||||
|
||||
[[package]]
|
||||
name = "walkdir"
|
||||
version = "2.3.1"
|
||||
version = "2.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "777182bc735b6424e1a57516d35ed72cb8019d85c8c9bf536dccb3445c1a2f7d"
|
||||
checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56"
|
||||
dependencies = [
|
||||
"same-file",
|
||||
"winapi 0.3.9",
|
||||
@ -2847,21 +2846,6 @@ version = "0.2.69"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7e7811dd7f9398f14cc76efd356f98f03aa30419dea46aa810d71e819fc97158"
|
||||
|
||||
[[package]]
|
||||
name = "wayland-client"
|
||||
version = "0.27.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ab702fefbcd6d6f67fb5816e3a89a3b5a42a94290abbc015311c9a30d1068ae4"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"downcast-rs",
|
||||
"libc",
|
||||
"nix 0.17.0",
|
||||
"wayland-commons 0.27.0",
|
||||
"wayland-scanner 0.27.0",
|
||||
"wayland-sys 0.27.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wayland-client"
|
||||
version = "0.28.5"
|
||||
@ -2873,21 +2857,9 @@ dependencies = [
|
||||
"libc",
|
||||
"nix 0.20.0",
|
||||
"scoped-tls",
|
||||
"wayland-commons 0.28.5",
|
||||
"wayland-scanner 0.28.5",
|
||||
"wayland-sys 0.28.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wayland-commons"
|
||||
version = "0.27.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e972e9336ad5a9dd861b4e21ff35ad71d3e5c6b4803d65c39913612f851b95f1"
|
||||
dependencies = [
|
||||
"nix 0.17.0",
|
||||
"once_cell",
|
||||
"smallvec",
|
||||
"wayland-sys 0.27.0",
|
||||
"wayland-commons",
|
||||
"wayland-scanner",
|
||||
"wayland-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -2899,18 +2871,7 @@ dependencies = [
|
||||
"nix 0.20.0",
|
||||
"once_cell",
|
||||
"smallvec",
|
||||
"wayland-sys 0.28.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wayland-cursor"
|
||||
version = "0.27.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "539f346e1a3f706f38c8ccbe1196001e2fb1c9b3e6b605c27d665db2f5b60d41"
|
||||
dependencies = [
|
||||
"nix 0.17.0",
|
||||
"wayland-client 0.27.0",
|
||||
"xcursor",
|
||||
"wayland-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -2920,22 +2881,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b37e5455ec72f5de555ec39b5c3704036ac07c2ecd50d0bffe02d5fe2d4e65ab"
|
||||
dependencies = [
|
||||
"nix 0.20.0",
|
||||
"wayland-client 0.28.5",
|
||||
"wayland-client",
|
||||
"xcursor",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wayland-protocols"
|
||||
version = "0.27.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f3d6fc54b17b98b5083bc21ae3a30e6d75cb4b01647360e4c3a04648bcf8781d"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"wayland-client 0.27.0",
|
||||
"wayland-commons 0.27.0",
|
||||
"wayland-scanner 0.27.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wayland-protocols"
|
||||
version = "0.28.5"
|
||||
@ -2943,20 +2892,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "95df3317872bcf9eec096c864b69aa4769a1d5d6291a5b513f8ba0af0efbd52c"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"wayland-client 0.28.5",
|
||||
"wayland-commons 0.28.5",
|
||||
"wayland-scanner 0.28.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wayland-scanner"
|
||||
version = "0.27.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "030f56009d932bd9400bb472764fea8109be1b0fc482d9cd75496c943ac30328"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"xml-rs",
|
||||
"wayland-client",
|
||||
"wayland-commons",
|
||||
"wayland-scanner",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -2970,15 +2908,6 @@ dependencies = [
|
||||
"xml-rs",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wayland-sys"
|
||||
version = "0.27.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8bdeffbbb474477dfa2acb45ac7479e5fe8f741c64ab032c5d11b94d07edc269"
|
||||
dependencies = [
|
||||
"pkg-config",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wayland-sys"
|
||||
version = "0.28.5"
|
||||
@ -3150,7 +3079,7 @@ dependencies = [
|
||||
"raw-window-handle",
|
||||
"smithay-client-toolkit",
|
||||
"wasm-bindgen",
|
||||
"wayland-client 0.28.5",
|
||||
"wayland-client",
|
||||
"web-sys",
|
||||
"winapi 0.3.9",
|
||||
"x11-dl",
|
||||
|
@ -7,6 +7,7 @@ members = [
|
||||
"examples/shaders/simplest-shader",
|
||||
"examples/shaders/compute-shader",
|
||||
"examples/shaders/mouse-shader",
|
||||
"examples/multibuilder",
|
||||
|
||||
"crates/rustc_codegen_spirv",
|
||||
"crates/spirv-builder",
|
||||
|
@ -39,6 +39,7 @@ bimap = "0.6"
|
||||
indexmap = "1.6.0"
|
||||
rspirv = { git = "https://github.com/gfx-rs/rspirv.git", rev = "ee1e913" }
|
||||
rustc-demangle = "0.1.18"
|
||||
sanitize-filename = "0.3"
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_json = "1.0"
|
||||
smallvec = "1.6.1"
|
||||
|
@ -33,6 +33,7 @@ use std::cell::{Cell, RefCell};
|
||||
use std::collections::HashMap;
|
||||
use std::iter::once;
|
||||
use std::rc::Rc;
|
||||
use std::str::FromStr;
|
||||
|
||||
pub struct CodegenCx<'tcx> {
|
||||
pub tcx: TyCtxt<'tcx>,
|
||||
@ -69,6 +70,8 @@ pub struct CodegenCx<'tcx> {
|
||||
/// Some runtimes (e.g. intel-compute-runtime) disallow atomics on i8 and i16, even though it's allowed by the spec.
|
||||
/// This enables/disables them.
|
||||
pub i8_i16_atomics_allowed: bool,
|
||||
|
||||
pub codegen_args: CodegenArgs,
|
||||
}
|
||||
|
||||
impl<'tcx> CodegenCx<'tcx> {
|
||||
@ -102,6 +105,7 @@ impl<'tcx> CodegenCx<'tcx> {
|
||||
tcx.sess.err(&format!("Unknown feature {}", feature));
|
||||
}
|
||||
}
|
||||
let codegen_args = CodegenArgs::from_session(tcx.sess);
|
||||
Self {
|
||||
tcx,
|
||||
codegen_unit,
|
||||
@ -120,6 +124,7 @@ impl<'tcx> CodegenCx<'tcx> {
|
||||
panic_fn_id: Default::default(),
|
||||
panic_bounds_check_fn_id: Default::default(),
|
||||
i8_i16_atomics_allowed: false,
|
||||
codegen_args,
|
||||
}
|
||||
}
|
||||
|
||||
@ -256,6 +261,51 @@ impl<'tcx> CodegenCx<'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
pub struct CodegenArgs {
|
||||
pub module_output_type: ModuleOutputType,
|
||||
}
|
||||
|
||||
impl CodegenArgs {
|
||||
pub fn from_session(sess: &Session) -> Self {
|
||||
match CodegenArgs::parse(&sess.opts.cg.llvm_args) {
|
||||
Ok(ok) => ok,
|
||||
Err(err) => sess.fatal(&format!("Unable to parse llvm-args: {}", err)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parse(args: &[String]) -> Result<Self, rustc_session::getopts::Fail> {
|
||||
use rustc_session::getopts;
|
||||
let mut opts = getopts::Options::new();
|
||||
opts.optopt(
|
||||
"",
|
||||
"module-output",
|
||||
"single output or multiple output",
|
||||
"[single|multiple]",
|
||||
);
|
||||
let matches = opts.parse(args)?;
|
||||
let module_output_type =
|
||||
matches.opt_get_default("module-output", ModuleOutputType::Single)?;
|
||||
Ok(Self { module_output_type })
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
pub enum ModuleOutputType {
|
||||
Single,
|
||||
Multiple,
|
||||
}
|
||||
|
||||
impl FromStr for ModuleOutputType {
|
||||
type Err = rustc_session::getopts::Fail;
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
match s {
|
||||
"single" => Ok(Self::Single),
|
||||
"multiple" => Ok(Self::Multiple),
|
||||
v => Err(Self::Err::UnrecognizedOption(v.to_string())),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> BackendTypes for CodegenCx<'tcx> {
|
||||
type Value = SpirvValue;
|
||||
type Function = SpirvValue;
|
||||
|
@ -118,7 +118,7 @@ mod spirv_type_constraints;
|
||||
mod symbols;
|
||||
|
||||
use builder::Builder;
|
||||
use codegen_cx::CodegenCx;
|
||||
use codegen_cx::{CodegenArgs, CodegenCx, ModuleOutputType};
|
||||
pub use rspirv;
|
||||
use rspirv::binary::Assemble;
|
||||
use rustc_ast::expand::allocator::AllocatorKind;
|
||||
@ -380,6 +380,8 @@ impl CodegenBackend for SpirvCodegenBackend {
|
||||
) -> Result<(), ErrorReported> {
|
||||
// TODO: Can we merge this sym with the one in symbols.rs?
|
||||
let legalize = !sess.target_features.contains(&Symbol::intern("kernel"));
|
||||
let codegen_args = CodegenArgs::from_session(sess);
|
||||
let emit_multiple_modules = codegen_args.module_output_type == ModuleOutputType::Multiple;
|
||||
|
||||
let timer = sess.timer("link_crate");
|
||||
link::link(
|
||||
@ -388,6 +390,7 @@ impl CodegenBackend for SpirvCodegenBackend {
|
||||
outputs,
|
||||
&codegen_results.crate_name.as_str(),
|
||||
legalize,
|
||||
emit_multiple_modules,
|
||||
);
|
||||
drop(timer);
|
||||
|
||||
|
@ -13,11 +13,11 @@ use rustc_session::config::{CrateType, DebugInfo, Lto, OptLevel, OutputFilenames
|
||||
use rustc_session::output::{check_file_is_writeable, invalid_output_for_target, out_filename};
|
||||
use rustc_session::utils::NativeLibKind;
|
||||
use rustc_session::Session;
|
||||
use std::collections::HashSet;
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::env;
|
||||
use std::ffi::{CString, OsStr};
|
||||
use std::fs::File;
|
||||
use std::io::{Read, Write};
|
||||
use std::io::{BufWriter, Read, Write};
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::sync::Arc;
|
||||
use tar::{Archive, Builder, Header};
|
||||
@ -28,6 +28,7 @@ pub fn link<'a>(
|
||||
outputs: &OutputFilenames,
|
||||
crate_name: &str,
|
||||
legalize: bool,
|
||||
emit_multiple_modules: bool,
|
||||
) {
|
||||
let output_metadata = sess.opts.output_types.contains_key(&OutputType::Metadata);
|
||||
for &crate_type in sess.crate_types().iter() {
|
||||
@ -60,9 +61,14 @@ pub fn link<'a>(
|
||||
CrateType::Rlib => {
|
||||
link_rlib(sess, codegen_results, &out_filename);
|
||||
}
|
||||
CrateType::Executable | CrateType::Cdylib | CrateType::Dylib => {
|
||||
link_exe(sess, crate_type, &out_filename, codegen_results, legalize)
|
||||
}
|
||||
CrateType::Executable | CrateType::Cdylib | CrateType::Dylib => link_exe(
|
||||
sess,
|
||||
crate_type,
|
||||
&out_filename,
|
||||
codegen_results,
|
||||
legalize,
|
||||
emit_multiple_modules,
|
||||
),
|
||||
other => sess.err(&format!("CrateType {:?} not supported yet", other)),
|
||||
}
|
||||
}
|
||||
@ -104,6 +110,7 @@ fn link_exe(
|
||||
out_filename: &Path,
|
||||
codegen_results: &CodegenResults,
|
||||
legalize: bool,
|
||||
emit_multiple_modules: bool,
|
||||
) {
|
||||
let mut objects = Vec::new();
|
||||
let mut rlibs = Vec::new();
|
||||
@ -122,8 +129,34 @@ fn link_exe(
|
||||
codegen_results,
|
||||
);
|
||||
|
||||
let spv_binary = do_link(sess, &objects, &rlibs, legalize);
|
||||
let spv_binary = do_link(sess, &objects, &rlibs, legalize, emit_multiple_modules);
|
||||
|
||||
use rspirv::binary::Assemble;
|
||||
match spv_binary {
|
||||
linker::LinkResult::SingleModule(spv_binary) => {
|
||||
post_link_single_module(sess, spv_binary.assemble(), out_filename);
|
||||
}
|
||||
linker::LinkResult::MultipleModules(map) => {
|
||||
let mut root_file_name = out_filename.file_name().unwrap().to_owned();
|
||||
root_file_name.push(".dir");
|
||||
let out_dir = out_filename.with_file_name(root_file_name);
|
||||
if !out_dir.is_dir() {
|
||||
std::fs::create_dir_all(&out_dir).unwrap();
|
||||
}
|
||||
let mut hashmap = HashMap::new();
|
||||
for (name, spv_binary) in map {
|
||||
let mut module_filename = out_dir.clone();
|
||||
module_filename.push(sanitize_filename::sanitize(&name));
|
||||
post_link_single_module(sess, spv_binary.assemble(), &module_filename);
|
||||
hashmap.insert(name, module_filename);
|
||||
}
|
||||
let file = File::create(out_filename).unwrap();
|
||||
serde_json::to_writer(BufWriter::new(file), &hashmap).unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn post_link_single_module(sess: &Session, spv_binary: Vec<u32>, out_filename: &Path) {
|
||||
if let Ok(ref path) = std::env::var("DUMP_POST_LINK") {
|
||||
File::create(path)
|
||||
.unwrap()
|
||||
@ -378,7 +411,13 @@ pub fn read_metadata(rlib: &Path) -> Result<MetadataRef, String> {
|
||||
|
||||
/// This is the actual guts of linking: the rest of the link-related functions are just digging through rustc's
|
||||
/// shenanigans to collect all the object files we need to link.
|
||||
fn do_link(sess: &Session, objects: &[PathBuf], rlibs: &[PathBuf], legalize: bool) -> Vec<u32> {
|
||||
fn do_link(
|
||||
sess: &Session,
|
||||
objects: &[PathBuf],
|
||||
rlibs: &[PathBuf],
|
||||
legalize: bool,
|
||||
emit_multiple_modules: bool,
|
||||
) -> linker::LinkResult {
|
||||
fn load(bytes: &[u8]) -> rspirv::dr::Module {
|
||||
let mut loader = rspirv::dr::Loader::new();
|
||||
rspirv::binary::parse_bytes(&bytes, &mut loader).unwrap();
|
||||
@ -407,6 +446,7 @@ fn do_link(sess: &Session, objects: &[PathBuf], rlibs: &[PathBuf], legalize: boo
|
||||
}
|
||||
|
||||
if let Ok(ref path) = env::var("DUMP_PRE_LINK") {
|
||||
use rspirv::binary::Assemble;
|
||||
let path = Path::new(path);
|
||||
if path.is_file() {
|
||||
std::fs::remove_file(path).unwrap();
|
||||
@ -429,21 +469,18 @@ fn do_link(sess: &Session, objects: &[PathBuf], rlibs: &[PathBuf], legalize: boo
|
||||
mem2reg: legalize,
|
||||
structurize: env::var("NO_STRUCTURIZE").is_err(),
|
||||
use_new_structurizer: env::var("OLD_STRUCTURIZER").is_err(),
|
||||
emit_multiple_modules,
|
||||
};
|
||||
|
||||
let link_result = linker::link(sess, modules, &options);
|
||||
|
||||
let assembled = match link_result {
|
||||
match link_result {
|
||||
Ok(v) => v,
|
||||
Err(rustc_errors::ErrorReported) => {
|
||||
sess.abort_if_errors();
|
||||
bug!("Linker errored, but no error reported")
|
||||
}
|
||||
};
|
||||
|
||||
// And finally write out the linked binary.
|
||||
use rspirv::binary::Assemble;
|
||||
assembled.assemble()
|
||||
}
|
||||
}
|
||||
|
||||
/// As of right now, this is essentially a no-op, just plumbing through all the files.
|
||||
|
@ -73,6 +73,9 @@ fn kill_unrooted(module: &mut Module, rooted: &HashSet<Word>) {
|
||||
module
|
||||
.ext_inst_imports
|
||||
.retain(|inst| is_rooted(inst, rooted));
|
||||
module
|
||||
.execution_modes
|
||||
.retain(|inst| is_rooted(inst, rooted));
|
||||
module.debugs.retain(|inst| is_rooted(inst, rooted));
|
||||
module.annotations.retain(|inst| is_rooted(inst, rooted));
|
||||
module
|
||||
|
@ -30,6 +30,12 @@ pub struct Options {
|
||||
pub mem2reg: bool,
|
||||
pub structurize: bool,
|
||||
pub use_new_structurizer: bool,
|
||||
pub emit_multiple_modules: bool,
|
||||
}
|
||||
|
||||
pub enum LinkResult {
|
||||
SingleModule(Module),
|
||||
MultipleModules(HashMap<String, Module>),
|
||||
}
|
||||
|
||||
fn id(header: &mut ModuleHeader) -> Word {
|
||||
@ -70,9 +76,7 @@ fn apply_rewrite_rules(rewrite_rules: &HashMap<Word, Word>, 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: &Session, mut inputs: Vec<Module>, opts: &Options) -> Result<Module> {
|
||||
pub fn link(sess: &Session, mut inputs: Vec<Module>, opts: &Options) -> Result<LinkResult> {
|
||||
let mut output = {
|
||||
let _timer = sess.timer("link_merge");
|
||||
// shift all the ids
|
||||
@ -241,18 +245,54 @@ pub fn link(sess: &Session, mut inputs: Vec<Module>, opts: &Options) -> Result<M
|
||||
simple_passes::sort_globals(&mut output);
|
||||
}
|
||||
|
||||
{
|
||||
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 = 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);
|
||||
let mut output = if opts.emit_multiple_modules {
|
||||
let modules = output
|
||||
.entry_points
|
||||
.iter()
|
||||
.map(|entry| {
|
||||
let mut module = output.clone();
|
||||
module.entry_points.clear();
|
||||
module.entry_points.push(entry.clone());
|
||||
let name = entry.operands[2].unwrap_literal_string();
|
||||
(name.to_string(), module)
|
||||
})
|
||||
.collect();
|
||||
LinkResult::MultipleModules(modules)
|
||||
} else {
|
||||
LinkResult::SingleModule(output)
|
||||
};
|
||||
|
||||
// output the module
|
||||
let output_module_iter: Box<dyn Iterator<Item = &mut Module>> = match output {
|
||||
LinkResult::SingleModule(ref mut m) => Box::new(std::iter::once(m)),
|
||||
LinkResult::MultipleModules(ref mut m) => Box::new(m.values_mut()),
|
||||
};
|
||||
for output in output_module_iter {
|
||||
if let Ok(ref path) = std::env::var("DUMP_POST_SPLIT") {
|
||||
use rspirv::binary::Assemble;
|
||||
use std::fs::File;
|
||||
use std::io::Write;
|
||||
|
||||
File::create(path)
|
||||
.unwrap()
|
||||
.write_all(spirv_tools::binary::from_binary(&output.assemble()))
|
||||
.unwrap();
|
||||
}
|
||||
if opts.dce && opts.emit_multiple_modules {
|
||||
let _timer = sess.timer("link_dce_2");
|
||||
dce::dce(output);
|
||||
}
|
||||
{
|
||||
let _timer = sess.timer("link_remove_extra_capabilities");
|
||||
capability_computation::remove_extra_capabilities(output);
|
||||
capability_computation::remove_extra_extensions(output);
|
||||
}
|
||||
|
||||
if opts.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(output);
|
||||
};
|
||||
}
|
||||
|
||||
Ok(output)
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
use super::{link, Options};
|
||||
use super::{link, LinkResult, Options};
|
||||
use pipe::pipe;
|
||||
use rspirv::dr::{Loader, Module};
|
||||
use rustc_driver::handle_options;
|
||||
@ -95,10 +95,14 @@ fn assemble_and_link(binaries: &[&[u8]]) -> Result<Module, String> {
|
||||
mem2reg: false,
|
||||
structurize: false,
|
||||
use_new_structurizer: false,
|
||||
emit_multiple_modules: false,
|
||||
},
|
||||
);
|
||||
assert_eq!(compiler.session().has_errors(), res.is_err());
|
||||
res
|
||||
res.map(|res| match res {
|
||||
LinkResult::SingleModule(m) => m,
|
||||
LinkResult::MultipleModules(_) => unreachable!(),
|
||||
})
|
||||
})
|
||||
.map_err(|_e| thread.join().unwrap())
|
||||
}
|
||||
|
@ -64,18 +64,32 @@ use std::collections::HashMap;
|
||||
use std::env;
|
||||
use std::error::Error;
|
||||
use std::fmt;
|
||||
use std::fs::File;
|
||||
use std::io::BufReader;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::process::{Command, Stdio};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum SpirvBuilderError {
|
||||
BuildFailed,
|
||||
MultiModuleWithPrintMetadata,
|
||||
MetadataFileMissing(std::io::Error),
|
||||
MetadataFileMalformed(serde_json::Error),
|
||||
}
|
||||
|
||||
impl fmt::Display for SpirvBuilderError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
SpirvBuilderError::BuildFailed => f.write_str("Build failed"),
|
||||
SpirvBuilderError::MultiModuleWithPrintMetadata => {
|
||||
f.write_str("Multi-module build cannot be used with print_metadata = true")
|
||||
}
|
||||
SpirvBuilderError::MetadataFileMissing(_) => {
|
||||
f.write_str("Multi-module metadata file missing")
|
||||
}
|
||||
SpirvBuilderError::MetadataFileMalformed(_) => {
|
||||
f.write_str("Unable to parse multi-module metadata file")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -134,13 +148,25 @@ impl SpirvBuilder {
|
||||
/// 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)?;
|
||||
let spirv_module = invoke_rustc(&self, false)?;
|
||||
let env_var = spirv_module.file_name().unwrap().to_str().unwrap();
|
||||
if self.print_metadata {
|
||||
println!("cargo:rustc-env={}={}", env_var, spirv_module.display());
|
||||
}
|
||||
Ok(spirv_module)
|
||||
}
|
||||
|
||||
pub fn build_multimodule(self) -> Result<HashMap<String, PathBuf>, SpirvBuilderError> {
|
||||
if self.print_metadata {
|
||||
return Err(SpirvBuilderError::MultiModuleWithPrintMetadata);
|
||||
}
|
||||
let metadata_file = invoke_rustc(&self, true)?;
|
||||
let metadata_contents =
|
||||
File::open(metadata_file).map_err(SpirvBuilderError::MetadataFileMissing)?;
|
||||
let metadata = serde_json::from_reader(BufReader::new(metadata_contents))
|
||||
.map_err(SpirvBuilderError::MetadataFileMalformed)?;
|
||||
Ok(metadata)
|
||||
}
|
||||
}
|
||||
|
||||
// https://github.com/rust-lang/cargo/blob/1857880b5124580c4aeb4e8bc5f1198f491d61b1/src/cargo/util/paths.rs#L29-L52
|
||||
@ -175,7 +201,8 @@ fn find_rustc_codegen_spirv() -> PathBuf {
|
||||
panic!("Could not find {} in library path", filename);
|
||||
}
|
||||
|
||||
fn invoke_rustc(builder: &SpirvBuilder) -> Result<PathBuf, SpirvBuilderError> {
|
||||
// Note: in case of multimodule, returns path to the metadata json
|
||||
fn invoke_rustc(builder: &SpirvBuilder, multimodule: bool) -> 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
|
||||
@ -205,10 +232,16 @@ fn invoke_rustc(builder: &SpirvBuilder) -> Result<PathBuf, SpirvBuilderError> {
|
||||
} else {
|
||||
format!(" -C target-feature={}", target_features.join(","))
|
||||
};
|
||||
let llvm_args = if multimodule {
|
||||
" -C llvm-args=--module-output=multiple"
|
||||
} else {
|
||||
""
|
||||
};
|
||||
let rustflags = format!(
|
||||
"-Z codegen-backend={} -Z symbol-mangling-version=v0{}",
|
||||
"-Z codegen-backend={} -Z symbol-mangling-version=v0{}{}",
|
||||
rustc_codegen_spirv.display(),
|
||||
feature_flag,
|
||||
llvm_args,
|
||||
);
|
||||
let mut cargo = Command::new("cargo");
|
||||
cargo.args(&[
|
||||
|
16
examples/multibuilder/Cargo.toml
Normal file
16
examples/multibuilder/Cargo.toml
Normal file
@ -0,0 +1,16 @@
|
||||
[package]
|
||||
name = "multibuilder"
|
||||
version = "0.1.0"
|
||||
authors = ["Embark <opensource@embark-studios.com>"]
|
||||
edition = "2018"
|
||||
license = "MIT OR Apache-2.0"
|
||||
publish = false
|
||||
|
||||
# See rustc_codegen_spirv/Cargo.toml for details on these features
|
||||
[features]
|
||||
default = ["use-compiled-tools"]
|
||||
use-installed-tools = ["spirv-builder/use-installed-tools"]
|
||||
use-compiled-tools = ["spirv-builder/use-compiled-tools"]
|
||||
|
||||
[dependencies]
|
||||
spirv-builder = { path = "../../crates/spirv-builder", default-features = false }
|
10
examples/multibuilder/src/main.rs
Normal file
10
examples/multibuilder/src/main.rs
Normal file
@ -0,0 +1,10 @@
|
||||
use spirv_builder::SpirvBuilder;
|
||||
|
||||
fn main() {
|
||||
let result = SpirvBuilder::new("../shaders/sky-shader")
|
||||
.print_metadata(false)
|
||||
.spirv_version(1, 0)
|
||||
.build_multimodule()
|
||||
.unwrap();
|
||||
println!("{:#?}", result);
|
||||
}
|
@ -18,7 +18,10 @@ pub fn main_fs(output: &mut Vec4) {
|
||||
}
|
||||
|
||||
#[spirv(vertex)]
|
||||
pub fn main_vs(#[spirv(vertex_index)] vert_id: i32, #[spirv(position)] out_pos: &mut Vec4) {
|
||||
pub fn main_vs(
|
||||
#[spirv(vertex_index)] vert_id: i32,
|
||||
#[spirv(position, invariant)] out_pos: &mut Vec4,
|
||||
) {
|
||||
*out_pos = vec4(
|
||||
(vert_id - 1) as f32,
|
||||
((vert_id & 1) * 2 - 1) as f32,
|
||||
|
Loading…
Reference in New Issue
Block a user