Migrate rustc_codegen_spirv env vars to codegen args.

This commit is contained in:
Eduard-Mihai Burtescu 2022-12-02 19:06:11 +02:00 committed by Eduard-Mihai Burtescu
parent 47d5577a93
commit b3c280424c
12 changed files with 380 additions and 183 deletions

View File

@ -151,6 +151,27 @@ jobs:
run: RUSTDOCFLAGS=-Dwarnings cargo doc --no-deps
- name: Clippy
run: .github/workflows/clippy.sh
# HACK(eddyb) see `docs/src/codegen-args.md` for more context around this,
# but basically we're implementing a custom "lint" to ban `std::env` usage,
# which could be disastrous because env vars access can't be tracked by
# `rustc`, unlike its CLI flags (which are integrated with incremental).
- name: Disallow `std::env` (mis)use from `rustc_codegen_spirv``
run: |
if (
egrep -r '::\s*env|env\s*::' crates/rustc_codegen_spirv/src/ |
# HACK(eddyb) exclude the one place in `rustc_codegen_spirv`
# needing access to an env var (only for codegen args `--help`).
egrep -v '^crates/rustc_codegen_spirv/src/codegen_cx/mod.rs: let help_flag_comes_from_spirv_builder_env_var = std::env::var\(spirv_builder_env_var\)$'
); then
echo '^^^'
echo '!!! Found disallowed `std::env` usage in `rustc_codegen_spirv` !!!'
echo ' ("codegen args" should be used instead of environment variables)'
echo
echo 'For more details on "codegen args", see: docs/src/codegen-args.md'
echo ' (and/or https://github.com/EmbarkStudios/rust-gpu/pull/959)'
echo
exit 1
fi
cargo-deny:
runs-on: ubuntu-20.04

View File

@ -33,13 +33,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Added two `spirv-builder` environment variables to customize *only* the `rustc` invocations for shader crates and their dependencies:
- `RUSTGPU_RUSTFLAGS="..."` for shader `RUSTFLAGS="..."`
- `RUSTGPU_CODEGEN_ARGS="..."` for shader `RUSTFLAGS=-Cllvm-args="..."`
(run with `RUSTGPU_CODEGEN_ARGS=--help` to see a list of options)
- `RUSTGPU_CODEGEN_ARGS="..."` for shader "codegen args" (i.e. `RUSTFLAGS=-Cllvm-args="..."`)
(check out ["codegen args" docs](docs/src/codegen-args.md), or run with `RUSTGPU_CODEGEN_ARGS=--help` to see the full list of options)
### Changed 🛠️
- Updated toolchain to `nightly-2022-10-29`
- Applied workspace inheritance to Cargo.toml files
- Applied workspace inheritance to `Cargo.toml` files
- Moved `rustc_codegen_spirv` debugging functionality from environment variables to "codegen args" options/flags (see [the updated docs](docs/src/codegen-args.md) for more details)
### Removed 🔥
@ -58,7 +59,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added ⭐
- Added check for env var `RUSTGPU_SKIP_TOOLCHAIN_CHECK` to prevent toolchain check
- Added check for environment variable `RUSTGPU_SKIP_TOOLCHAIN_CHECK` to prevent toolchain check
### Changed 🛠️

View File

@ -33,7 +33,7 @@ use rustc_target::spec::{HasTargetSpec, Target};
use std::cell::{Cell, RefCell};
use std::collections::BTreeSet;
use std::iter::once;
use std::path::Path;
use std::path::{Path, PathBuf};
use std::rc::Rc;
use std::str::FromStr;
@ -232,8 +232,9 @@ impl<'tcx> CodegenCx<'tcx> {
}
}
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
#[derive(Debug, Default, PartialEq, Eq, Clone, Copy)]
pub enum SpirvMetadata {
#[default]
None,
NameVariables,
Full,
@ -248,6 +249,8 @@ pub struct CodegenArgs {
pub spirv_metadata: SpirvMetadata,
pub run_spirv_val: bool,
// spirv-val flags
pub relax_struct_store: bool,
pub relax_logical_pointer: bool,
@ -256,8 +259,22 @@ pub struct CodegenArgs {
pub scalar_block_layout: bool,
pub skip_block_layout: bool,
pub run_spirv_opt: bool,
// spirv-opt flags
pub preserve_bindings: bool,
/// All options pertinent to `rustc_codegen_spirv::linker` specifically.
//
// FIXME(eddyb) should these be handled as `-C linker-args="..."` instead?
pub linker_opts: crate::linker::Options,
// NOTE(eddyb) these are debugging options that used to be env vars
// (for more information see `docs/src/codegen-args.md`).
pub dump_mir: Option<PathBuf>,
pub dump_module_on_panic: Option<PathBuf>,
pub dump_pre_link: Option<PathBuf>,
pub dump_post_link: Option<PathBuf>,
}
impl CodegenArgs {
@ -268,6 +285,7 @@ impl CodegenArgs {
}
}
// FIXME(eddyb) `structopt` would come a long way to making this nicer.
pub fn parse(args: &[String]) -> Result<Self, rustc_session::getopts::Fail> {
use rustc_session::getopts;
@ -294,6 +312,13 @@ impl CodegenArgs {
opts.optopt("", "spirv-metadata", "how much metadata to include", "");
// FIXME(eddyb) clean up this `no-` "negation prefix" situation.
opts.optflag(
"",
"no-spirv-val",
"disables running spirv-val on the final output",
);
opts.optflag("", "relax-struct-store", "Allow store from one struct type to a different type with compatible layout and members.");
opts.optflag("", "relax-logical-pointer", "Allow allocating an object of a pointer type and returning a pointer value from a function in logical addressing mode");
opts.optflag("", "relax-block-layout", "Enable VK_KHR_relaxed_block_layout when checking standard uniform, storage buffer, and push constant layouts. This is the default when targeting Vulkan 1.1 or later.");
@ -301,12 +326,91 @@ impl CodegenArgs {
opts.optflag("", "scalar-block-layout", "Enable VK_EXT_scalar_block_layout when checking standard uniform, storage buffer, and push constant layouts. Scalar layout rules are more permissive than relaxed block layout so in effect this will override the --relax-block-layout option.");
opts.optflag("", "skip-block-layout", "Skip checking standard uniform/storage buffer layout. Overrides any --relax-block-layout or --scalar-block-layout option.");
// FIXME(eddyb) clean up this `no-` "negation prefix" situation.
opts.optflag(
"",
"no-spirv-opt",
"disables running spirv-opt on the final output",
);
opts.optflag(
"",
"preserve-bindings",
"Preserve unused descriptor bindings. Useful for reflection.",
);
// Linker options.
// FIXME(eddyb) should these be handled as `-C linker-args="..."` instead?
{
// FIXME(eddyb) clean up this `no-` "negation prefix" situation.
opts.optflag("", "no-dce", "disables running dead code elimination");
opts.optflag(
"",
"no-compact-ids",
"disables compaction of SPIR-V IDs at the end of linking",
);
opts.optflag("", "no-structurize", "disables CFG structurization");
// NOTE(eddyb) these are debugging options that used to be env vars
// (for more information see `docs/src/codegen-args.md`).
opts.optopt(
"",
"dump-post-merge",
"dump the merged module immediately after merging, to FILE",
"FILE",
);
opts.optopt(
"",
"dump-post-split",
"dump modules immediately after multimodule splitting, to files in DIR",
"DIR",
);
opts.optflag(
"",
"specializer-debug",
"enable debug logging for the specializer",
);
opts.optopt(
"",
"specializer-dump-instances",
"dump all instances inferred by the specializer, to FILE",
"FILE",
);
opts.optflag("", "print-all-zombie", "prints all removed zombies");
opts.optflag(
"",
"print-zombie",
"prints everything removed (even transitively) due to zombies",
);
}
// NOTE(eddyb) these are debugging options that used to be env vars
// (for more information see `docs/src/codegen-args.md`).
opts.optopt(
"",
"dump-mir",
"dump every MIR body codegen sees, to files in DIR",
"DIR",
);
opts.optopt(
"",
"dump-module-on-panic",
"if codegen panics, dump the (partially) emitted module, to FILE",
"FILE",
);
opts.optopt(
"",
"dump-pre-link",
"dump all input modules to the linker, to files in DIR",
"DIR",
);
opts.optopt(
"",
"dump-post-link",
"dump all output modules from the linker, to files in DIR",
"DIR",
);
let matches = opts.parse(args)?;
let help_flag_positions: BTreeSet<_> = ["h", "help"]
@ -363,6 +467,9 @@ impl CodegenArgs {
let spirv_metadata = matches.opt_str("spirv-metadata");
// FIXME(eddyb) clean up this `no-` "negation prefix" situation.
let run_spirv_val = !matches.opt_present("no-spirv-val");
let relax_struct_store = matches.opt_present("relax-struct-store");
let relax_logical_pointer = matches.opt_present("relax-logical-pointer");
let relax_block_layout = matches.opt_present("relax-block-layout");
@ -370,6 +477,9 @@ impl CodegenArgs {
let scalar_block_layout = matches.opt_present("scalar-block-layout");
let skip_block_layout = matches.opt_present("skip-block-layout");
// FIXME(eddyb) clean up this `no-` "negation prefix" situation.
let run_spirv_opt = !matches.opt_present("no-spirv-opt");
let preserve_bindings = matches.opt_present("preserve-bindings");
let relax_block_layout = if relax_block_layout { Some(true) } else { None };
@ -385,6 +495,37 @@ impl CodegenArgs {
}
};
let matches_opt_path = |name| matches.opt_str(name).map(PathBuf::from);
let matches_opt_dump_dir_path = |name| {
matches_opt_path(name).map(|path| {
if path.is_file() {
std::fs::remove_file(&path).unwrap();
}
std::fs::create_dir_all(&path).unwrap();
path
})
};
// FIXME(eddyb) should these be handled as `-C linker-args="..."` instead?
let linker_opts = crate::linker::Options {
// FIXME(eddyb) clean up this `no-` "negation prefix" situation.
dce: !matches.opt_present("no-dce"),
compact_ids: !matches.opt_present("no-compact-ids"),
structurize: !matches.opt_present("no-structurize"),
// FIXME(eddyb) deduplicate between `CodegenArgs` and `linker::Options`.
emit_multiple_modules: module_output_type == ModuleOutputType::Multiple,
spirv_metadata,
// NOTE(eddyb) these are debugging options that used to be env vars
// (for more information see `docs/src/codegen-args.md`).
dump_post_merge: matches_opt_path("dump-post-merge"),
dump_post_split: matches_opt_dump_dir_path("dump-post-split"),
specializer_debug: matches.opt_present("specializer-debug"),
specializer_dump_instances: matches_opt_path("specializer-dump-instances"),
print_all_zombie: matches.opt_present("print-all-zombie"),
print_zombie: matches.opt_present("print-zombie"),
};
Ok(Self {
module_output_type,
disassemble,
@ -394,6 +535,8 @@ impl CodegenArgs {
spirv_metadata,
run_spirv_val,
relax_struct_store,
relax_logical_pointer,
relax_block_layout,
@ -401,7 +544,18 @@ impl CodegenArgs {
scalar_block_layout,
skip_block_layout,
run_spirv_opt,
preserve_bindings,
linker_opts,
// NOTE(eddyb) these are debugging options that used to be env vars
// (for more information see `docs/src/codegen-args.md`).
dump_mir: matches_opt_dump_dir_path("dump-mir"),
dump_module_on_panic: matches_opt_path("dump-module-on-panic"),
dump_pre_link: matches_opt_dump_dir_path("dump-pre-link"),
dump_post_link: matches_opt_dump_dir_path("dump-post-link"),
})
}

View File

@ -107,11 +107,10 @@ use rustc_session::Session;
use rustc_span::symbol::{sym, Symbol};
use rustc_target::spec::{Target, 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::path::Path;
use std::sync::Arc;
fn dump_mir<'tcx>(
@ -410,9 +409,8 @@ impl ExtraBackendMethods for SpirvCodegenBackend {
let do_codegen = || {
let mono_items = cx.codegen_unit.items_in_deterministic_order(cx.tcx);
if let Some(mut path) = get_env_dump_dir("DUMP_MIR") {
path.push(cgu_name.to_string());
dump_mir(tcx, &mono_items, &path);
if let Some(dir) = &cx.codegen_args.dump_mir {
dump_mir(tcx, &mono_items, &dir.join(cgu_name.to_string()));
}
for &(mono_item, (linkage, visibility)) in mono_items.iter() {
@ -438,7 +436,7 @@ impl ExtraBackendMethods for SpirvCodegenBackend {
// attributes::sanitize(&cx, SanitizerSet::empty(), entry);
}
};
if let Ok(ref path) = env::var("DUMP_MODULE_ON_PANIC") {
if let Some(path) = &cx.codegen_args.dump_module_on_panic {
let module_dumper = DumpModuleOnPanic { cx: &cx, path };
with_no_trimmed_paths!(do_codegen());
drop(module_dumper);
@ -470,15 +468,14 @@ impl ExtraBackendMethods for SpirvCodegenBackend {
struct DumpModuleOnPanic<'a, 'cx, 'tcx> {
cx: &'cx CodegenCx<'tcx>,
path: &'a str,
path: &'a Path,
}
impl Drop for DumpModuleOnPanic<'_, '_, '_> {
fn drop(&mut self) {
if std::thread::panicking() {
let path: &Path = self.path.as_ref();
if path.has_root() {
self.cx.builder.dump_module(path);
if self.path.has_root() {
self.cx.builder.dump_module(self.path);
} else {
println!("{}", self.cx.builder.dump_module_str());
}
@ -486,19 +483,6 @@ impl Drop for DumpModuleOnPanic<'_, '_, '_> {
}
}
fn get_env_dump_dir(env_var: &str) -> Option<PathBuf> {
if let Some(path) = std::env::var_os(env_var) {
let path = PathBuf::from(path);
if path.is_file() {
std::fs::remove_file(&path).unwrap();
}
std::fs::create_dir_all(&path).unwrap();
Some(path)
} else {
None
}
}
/// This is the entrypoint for a hot plugged `rustc_codegen_spirv`
#[no_mangle]
pub fn __rustc_codegen_backend() -> Box<dyn CodegenBackend> {

View File

@ -1,4 +1,4 @@
use crate::codegen_cx::{CodegenArgs, ModuleOutputType, SpirvMetadata};
use crate::codegen_cx::{CodegenArgs, SpirvMetadata};
use crate::{linker, SpirvCodegenBackend, SpirvModuleBuffer, SpirvThinBuffer};
use ar::{Archive, GnuBuilder, Header};
use rspirv::binary::Assemble;
@ -17,7 +17,6 @@ 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::env;
use std::ffi::CString;
use std::fs::File;
use std::io::{BufWriter, Read};
@ -202,9 +201,12 @@ fn post_link_single_module(
spv_binary: Vec<u32>,
out_filename: &Path,
) {
if let Some(mut path) = crate::get_env_dump_dir("DUMP_POST_LINK") {
path.push(out_filename.file_name().unwrap());
std::fs::write(path, spirv_tools::binary::from_binary(&spv_binary)).unwrap();
if let Some(dir) = &cg_args.dump_post_link {
std::fs::write(
dir.join(out_filename.file_name().unwrap()),
spirv_tools::binary::from_binary(&spv_binary),
)
.unwrap();
}
let val_options = spirv_tools::val::ValidatorOptions {
@ -227,7 +229,7 @@ fn post_link_single_module(
let spv_binary = if sess.opts.optimize != OptLevel::No
|| (sess.opts.debuginfo == DebugInfo::None && cg_args.spirv_metadata == SpirvMetadata::None)
{
if env::var("NO_SPIRV_OPT").is_err() {
if cg_args.run_spirv_opt {
let _timer = sess.timer("link_spirv_opt");
do_spirv_opt(sess, cg_args, spv_binary, out_filename, opt_options)
} else {
@ -237,7 +239,7 @@ fn post_link_single_module(
(optlevel, true) => format!("optlevel={:?}, debuginfo=None", optlevel),
};
sess.warn(format!(
"spirv-opt should have ran ({}) but was disabled by NO_SPIRV_OPT",
"`spirv-opt` should have ran ({}) but was disabled by `--no-spirv-opt`",
reason
));
spv_binary
@ -246,7 +248,7 @@ fn post_link_single_module(
spv_binary
};
if env::var("NO_SPIRV_VAL").is_err() {
if cg_args.run_spirv_val {
do_spirv_val(sess, &spv_binary, out_filename, val_options);
}
@ -548,7 +550,7 @@ fn do_link(
}
}
if let Some(dir) = crate::get_env_dump_dir("DUMP_PRE_LINK") {
if let Some(dir) = &cg_args.dump_pre_link {
for (num, module) in modules.iter().enumerate() {
std::fs::write(
dir.join(format!("mod_{}.spv", num)),
@ -560,15 +562,7 @@ fn do_link(
drop(load_modules_timer);
// Do the link...
let options = linker::Options {
dce: env::var("NO_DCE").is_err(),
compact_ids: env::var("NO_COMPACT_IDS").is_err(),
structurize: env::var("NO_STRUCTURIZE").is_err(),
emit_multiple_modules: cg_args.module_output_type == ModuleOutputType::Multiple,
spirv_metadata: cg_args.spirv_metadata,
};
let link_result = linker::link(sess, modules, &options);
let link_result = linker::link(sess, modules, &cg_args.linker_opts);
match link_result {
Ok(v) => v,

View File

@ -25,15 +25,27 @@ use rspirv::spirv::{Op, StorageClass, Word};
use rustc_data_structures::fx::FxHashMap;
use rustc_errors::ErrorGuaranteed;
use rustc_session::Session;
use std::path::PathBuf;
pub type Result<T> = std::result::Result<T, ErrorGuaranteed>;
#[derive(Default)]
pub struct Options {
pub compact_ids: bool,
pub dce: bool,
pub structurize: bool,
pub emit_multiple_modules: bool,
pub spirv_metadata: SpirvMetadata,
// NOTE(eddyb) these are debugging options that used to be env vars
// (for more information see `docs/src/codegen-args.md`).
pub dump_post_merge: Option<PathBuf>,
pub dump_post_split: Option<PathBuf>,
pub specializer_debug: bool,
pub specializer_dump_instances: Option<PathBuf>,
pub print_all_zombie: bool,
pub print_zombie: bool,
}
pub enum LinkResult {
@ -147,7 +159,7 @@ pub fn link(sess: &Session, mut inputs: Vec<Module>, opts: &Options) -> Result<L
output
};
if let Ok(ref path) = std::env::var("DUMP_POST_MERGE") {
if let Some(path) = &opts.dump_post_merge {
std::fs::write(path, spirv_tools::binary::from_binary(&output.assemble())).unwrap();
}
@ -182,7 +194,7 @@ pub fn link(sess: &Session, mut inputs: Vec<Module>, opts: &Options) -> Result<L
{
let _timer = sess.timer("link_remove_zombies");
zombies::remove_zombies(sess, &mut output)?;
zombies::remove_zombies(sess, opts, &mut output)?;
}
{
@ -194,6 +206,7 @@ pub fn link(sess: &Session, mut inputs: Vec<Module>, opts: &Options) -> Result<L
simple_passes::block_ordering_pass(func);
}
output = specializer::specialize(
opts,
output,
specializer::SimpleSpecialization {
specialize_operand: |operand| {
@ -318,9 +331,12 @@ pub fn link(sess: &Session, mut inputs: Vec<Module>, opts: &Options) -> Result<L
LinkResult::MultipleModules(ref mut m) => Box::new(m.values_mut()),
};
for (i, output) in output_module_iter.enumerate() {
if let Some(mut path) = crate::get_env_dump_dir("DUMP_POST_SPLIT") {
path.push(format!("mod_{}.spv", i));
std::fs::write(path, spirv_tools::binary::from_binary(&output.assemble())).unwrap();
if let Some(dir) = &opts.dump_post_split {
std::fs::write(
dir.join(format!("mod_{}.spv", i)),
spirv_tools::binary::from_binary(&output.assemble()),
)
.unwrap();
}
// Run DCE again, even if emit_multiple_modules==false - the first DCE ran before
// structurization and mem2reg (for perf reasons), and mem2reg may remove references to

View File

@ -106,10 +106,14 @@ impl<SO: Fn(&Operand) -> bool> Specialization for SimpleSpecialization<SO> {
}
}
pub fn specialize(module: Module, specialization: impl Specialization) -> Module {
pub fn specialize(
opts: &super::Options,
module: Module,
specialization: impl Specialization,
) -> Module {
// FIXME(eddyb) use `log`/`tracing` instead.
let debug = std::env::var("SPECIALIZER_DEBUG").is_ok();
let dump_instances = std::env::var("SPECIALIZER_DUMP_INSTANCES").ok();
let debug = opts.specializer_debug;
let dump_instances = &opts.specializer_dump_instances;
let mut debug_names = FxHashMap::default();
if debug || dump_instances.is_some() {

View File

@ -1,5 +1,4 @@
use super::{link, LinkResult, Options};
use crate::codegen_cx::SpirvMetadata;
use pipe::pipe;
use rspirv::dr::{Loader, Module};
use rustc_errors::registry::Registry;
@ -124,10 +123,7 @@ fn assemble_and_link(binaries: &[&[u8]]) -> Result<Module, PrettyString> {
modules,
&Options {
compact_ids: true,
dce: false,
structurize: false,
emit_multiple_modules: false,
spirv_metadata: SpirvMetadata::None,
..Default::default()
},
);
assert_eq!(sess.has_errors(), res.as_ref().err().copied());

View File

@ -7,7 +7,6 @@ use rspirv::spirv::Word;
use rustc_data_structures::fx::FxHashMap;
use rustc_session::Session;
use rustc_span::{Span, DUMMY_SP};
use std::env;
use std::iter::once;
#[derive(Clone)]
@ -134,7 +133,11 @@ fn report_error_zombies(
result
}
pub fn remove_zombies(sess: &Session, module: &mut Module) -> super::Result<()> {
pub fn remove_zombies(
sess: &Session,
opts: &super::Options,
module: &mut Module,
) -> super::Result<()> {
let zombies_owned = ZombieDecoration::decode_all(module)
.map(|(id, zombie)| {
let ZombieDecoration { reason, span } = zombie.deserialize();
@ -154,7 +157,8 @@ pub fn remove_zombies(sess: &Session, module: &mut Module) -> super::Result<()>
let result = report_error_zombies(sess, module, &zombies);
if env::var("PRINT_ALL_ZOMBIE").is_ok() {
// FIXME(eddyb) use `log`/`tracing` instead.
if opts.print_all_zombie {
for (&zomb, reason) in &zombies {
let orig = if zombies_owned.iter().any(|&(z, _)| z == zomb) {
"original"
@ -165,7 +169,7 @@ pub fn remove_zombies(sess: &Session, module: &mut Module) -> super::Result<()>
}
}
if env::var("PRINT_ZOMBIE").is_ok() {
if opts.print_zombie {
let names = get_names(module);
for f in &module.functions {
if let Some(reason) = is_zombie(f.def.as_ref().unwrap(), &zombies) {

View File

@ -4,9 +4,9 @@
- [Contributing to Rust-GPU]()
- [Building](./building-rust-gpu.md)
- [Testing](./testing.md)
- [Environment variables Rust-GPU reads](./compiler-env-vars.md)
- ["Codegen args" (flags/options) supported by the Rust-GPU codegen backend](./codegen-args.md)
- [Minimizing bugs in SPIR-V](./spirv-minimization.md)
- [Publishing rust-gpu on crates.io](./publishing-rust-gpu.md)
- [Publishing Rust-GPU on crates.io](./publishing-rust-gpu.md)
- [Platform Support](./platform-support.md)
- [Writing Shader Crates](./writing-shader-crates.md)
- [Features]()

140
docs/src/codegen-args.md Normal file
View File

@ -0,0 +1,140 @@
# "Codegen args" (flags/options) supported by the Rust-GPU codegen backend
Please keep in mind that many of these flags/options are for internal development, and may break output
unexpectedly and generally muck things up. Please only use these if you know what you're doing.
Help is also appreciated keeping this document up to date, "codegen args" flags/options may be
added/removed on an ad-hoc basis without much thought, as they're internal development tools, not a
public API - this documentation is only here because these flags/options may be helpful diagnosing
problems for others.
It's recommended that "codegen args" options that take paths to files or directories are set to full
paths, as the working directory of the compiler might be something wonky and unexpected, and it's
easier to set the full path.
---
## How to set "codegen args" flags/options
The most convenient method is relying on `spirv-builder` reading the `RUSTGPU_CODEGEN_ARGS` environment variable, e.g.:
```console
$ RUSTGPU_CODEGEN_ARGS="--no-spirv-val --dump-post-link=$PWD/postlink" cargo run -p example-runner-wgpu
...
Finished release [optimized] target(s) in 15.15s
$ file postlink/*
postlink/module: Khronos SPIR-V binary, little-endian, version 0x010300, generator 0x1b0000
```
Notable, `RUSTGPU_CODEGEN_ARGS="--help"` can be used to see an "usage" message (which lists all the flags/options, including onesn not listed in this document), via e.g. running a Cargo build that relies on `spirv-builder`.
However, it's only a convenient alias for for `RUSTGPU_RUSTFLAGS=-Cllvm-args="..."` (without having to expose the fact that LLVM's name is still attached to `rustc`'s interface for this functionality), and if in direct control of `rustc`, you can still pass such "codegen args" flags/options wrapped in `-C llvm-args="..."`.
---
## Historical note about past "environment variables"
Many of these flags/options were at one point, individual environment variable (e.g. the `--dump-pre-link` option used to be the environment variable `DUMP_PRE_LINK`).
However, that approach is prone to various failure modes, because the environment variables would not get registered as a "dependency" (without extra work that never happened), and the idea of "codegen args" fits better with existing practices (e.g. `rustc -C llvm-args="..."` for the LLVM codegen backend of `rustc`).
For more context see also [PR #959](https://github.com/EmbarkStudios/rust-gpu/pull/959), which made the transition to this system.
## Where are all the rest of the flags/options documented?
If you do run a build with `RUSTGPU_CODEGEN_ARGS="--help"` (or `-C llvm-args="--help"`), you will notice more flags/options than are listed in this documented.
This is a historical artifact: as mentioned above, these used to be environment variables, and this document only described those, without talking about the older "codegen args" at all.
While most of those flags are usually only exposed through higher-level `spirv-builder` APIs, it would be nice to have all of them documented in one place (eventually?).
---
## Debugging "codegen args" flags/options
As mentioned above, these form the bulk of "codegen args", but keep in mind the list is not exhaustive and you will want to cehck the full list with e.g. `RUSTGPU_CODEGEN_ARGS="--help"`.
### `--dump-mir DIR`
Dumps the MIR of every function rust-gpu encounters, to files in `DIR`. Yes, rustc does have options to do
this by default, but I always forget the syntax, and plumbing through the option to `spirv-builder`
is annoying, so this is handy to just hack an output.
_**FIXME(@eddyb)** this may be irrelevant now given `RUSTGPU_RUSTFLAGS`_
### `--dump-module-on-panic FILE`
If codegen panics, then write the (partially) emitted module to `FILE`. Note that this only exists
for codegen, if the linker panics, this option does nothing, sadly.
### `--dump-pre-link DIR`
Dumps all input modules to the linker, to files in `DIR`, before the linker touches them at all.
### `--dump-post-merge FILE`
Dumps the merged module, to `FILE`, immediately after merging, but before the linker has done anything else
(including, well, linking the methods - `LinkageAttributes` will still exist, etc.). This is very
similar to `--dump-pre-link`, except it outputs only a single file, which might make grepping through
for stuff easier.
### `--dump-post-split DIR`
Dumps the modules, to files in `DIR`, immediately after multimodule splitting, but before final cleanup passes (e.g.
DCE to remove the other entry points).
### `--dump-post-link DIR`
Takes: path to directory
Dumps all output modules from the linker, to files in `DIR`. This may be multiple files due to the multimodule/module
splitting option, hence it takes a directory instead of a file path. This is the final output
binary before `spirv-opt` is executed, so it may be useful to output this to check if an issue is in
Rust-GPU, or in `spirv-opt`.
### `--specializer-debug`
Enables debug logging for the specializer.
_**FIXME(@eddyb)** use `log`/`tracing` instead for this purpose_
### `--specializer-dump-instances FILE`
Dumps to `FILE` all instances inferred by the specializer.
### `--print-zombie`
Prints to rustc stdout which functions were removed due to being zombies, and why.
_**FIXME(@eddyb)** use `log`/`tracing` instead for this purpose_
### `--print-all-zombie`
Prints to rustc stdout *everything* that was removed due to being zombies, why, and if it was an
original zombie or if it was infected. (prints a lot!)
_**FIXME(@eddyb)** use `log`/`tracing` instead for this purpose_
### `--no-spirv-val`
Disables running `spirv-val` on the final output. Spooky scary option, can cause invalid modules!
### `--no-spirv-opt`
Forcibly disables running `spirv-opt` on the final output, even if optimizations are enabled.
### `--no-dce`
Disables running dead code elimination. Can and probably will generate invalid modules or crash the
linker, hasn't been tested for a while.
### `--no-compact-ids`
Disables compaction of SPIR-V IDs at the end of linking. Causes absolutely ginormous IDs to be
emitted. Useful if you're println debugging IDs in the linker (although spirv-opt will compact them
anyway, be careful).
### `--no-structurize`
Disables CFG structurization. Probably results in invalid modules.

View File

@ -1,117 +0,0 @@
# Debug environment variables that the Rust-GPU compiler reads
Please keep in mind that all of these variables are for internal development, and may break output
unexpectedly and generally muck things up. Please only use these if you know what you're doing.
Help is also appreciated keeping this document up to date, environment variables may be
added/removed on an ad-hoc basis without much thought, as they're internal development tools, not a
public API - this documentation is only here because these variables may be helpful diagnosing
problems for others.
It's recommended that environment variables that take paths to files or directories are set to full
paths, as the working directory of the compiler might be something wonky and unexpected, and it's
easier to set the full path.
## DUMP_MIR
Takes: path to file
Dumps the MIR of every function rust-gpu encounters to a file. Yes, rustc does have options to do
this by default, but I always forget the syntax, and plumbing through the option to spirv-builder
is annoying, so this is handy to just hack an output.
## DUMP_MODULE_ON_PANIC
Takes: path to file
If codegen panics, then write the (partially) emitted module to a file. Note that this only exists
for codegen, if the linker panics, this option does nothing, sadly.
## DUMP_PRE_LINK
Takes: path to directory
Dumps all input modules to the linker, before the linker touches them at all.
## DUMP_POST_MERGE
Takes: path to file
Dumps the merged module immediately after merging, but before the linker has done anything else
(including, well, linking the methods - LinkageAttributes will still exist, etc.). This is very
similar to DUMP_PRE_LINK, except it outputs only a single file, which might make grepping through
for stuff easier.
## DUMP_POST_SPLIT
Takes: path to directory
Dumps the modules immediately after multimodule splitting, but before final cleanup passes (e.g.
DCE to remove the other entry points).
## DUMP_POST_LINK
Takes: path to directory
Dumps all output modules from the linker. This may be multiple files due to the multimodule/module
splitting option, hence it takes a directory instead of a file path. This is the final output
binary before spirv-opt is executed, so it may be useful to output this to check if an issue is in
rust-gpu, or in spirv-opt.
## SPECIALIZER_DEBUG
Takes: presence or absence (e.g. set to `1`)
Prints to rustc stdout some debug information about the specializer.
## SPECIALIZER_DUMP_INSTANCES
Takes: path to file
Prints to file some... stuff, idk, ask eddyb (useful for debugging specializer)
## PRINT_ZOMBIE
Takes: presence or absence (e.g. set to `1`)
Prints to rustc stdout which functions were removed due to being zombies, and why.
## PRINT_ALL_ZOMBIE
Takes: presence or absence (e.g. set to `1`)
Prints to rustc stdout *everything* that was removed due to being zombies, why, and if it was an
original zombie or if it was infected. (prints a lot!)
## NO_SPIRV_VAL
Takes: presence or absence (e.g. set to `1`)
Disables running spirv-val on the final output. Spooky scary option, can cause invalid modules!
## NO_SPIRV_OPT
Takes: presence or absence (e.g. set to `1`)
Forcibly disables running spirv-opt on the final output, even if optimizations are enabled.
## NO_DCE
Takes: presence or absence (e.g. set to `1`)
Disables running dead code elimination. Can and probably will generate invalid modules or crash the
linker, hasn't been tested for a while.
## NO_COMPACT_IDS
Takes: presence or absence (e.g. set to `1`)
Disables compaction of SPIR-V IDs at the end of linking. Causes absolutely ginormous IDs to be
emitted. Useful if you're println debugging IDs in the linker (although spirv-opt will compact them
anyway, be careful).
## NO_STRUCTURIZE
Takes: presence or absence (e.g. set to `1`)
Disables structurization. Probably results in invalid modules.