Skip to content

Commit 4252427

Browse files
committed
Add debugPrintf-based panic reporting, controlled via spirv_builder::ShaderPanicStrategy.
1 parent e830e60 commit 4252427

File tree

13 files changed

+628
-128
lines changed

13 files changed

+628
-128
lines changed

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
2929

3030
## [Unreleased]
3131

32+
### Added ⭐
33+
- [PR#1080](https://github.com/EmbarkStudios/rust-gpu/pull/1080) added `debugPrintf`-based
34+
panic reporting, with the desired behavior selected via `spirv_builder::ShaderPanicStrategy`
35+
(see its documentation for more details about each available panic handling strategy)
36+
3237
### Changed 🛠
3338
- [PR#1079](https://github.com/EmbarkStudios/rust-gpu/pull/1079) revised `spirv-builder`'s `README.md`,
3439
and added a way for `docs.rs` to be able to build it (via `cargo +stable doc --no-default-features`)

crates/rustc_codegen_spirv/src/builder/builder_methods.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ use rustc_codegen_ssa::common::{
1313
use rustc_codegen_ssa::mir::operand::{OperandRef, OperandValue};
1414
use rustc_codegen_ssa::mir::place::PlaceRef;
1515
use rustc_codegen_ssa::traits::{
16-
BackendTypes, BuilderMethods, ConstMethods, IntrinsicCallMethods, LayoutTypeMethods, OverflowOp,
16+
BackendTypes, BuilderMethods, ConstMethods, LayoutTypeMethods, OverflowOp,
1717
};
1818
use rustc_codegen_ssa::MemFlags;
1919
use rustc_data_structures::fx::FxHashSet;
@@ -2647,7 +2647,8 @@ impl<'a, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'tcx> {
26472647

26482648
// HACK(eddyb) redirect any possible panic call to an abort, to avoid
26492649
// needing to materialize `&core::panic::Location` or `format_args!`.
2650-
self.abort();
2650+
// FIXME(eddyb) find a way to extract the original message.
2651+
self.abort_with_message("panic!(...)".into());
26512652
self.undef(result_type)
26522653
} else if let Some(mode) = buffer_load_intrinsic {
26532654
self.codegen_buffer_load_intrinsic(result_type, args, mode)

crates/rustc_codegen_spirv/src/builder/intrinsics.rs

Lines changed: 25 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use crate::builder_spirv::{SpirvValue, SpirvValueExt};
44
use crate::codegen_cx::CodegenCx;
55
use crate::custom_insts::CustomInst;
66
use crate::spirv_type::SpirvType;
7+
use rspirv::dr::Operand;
78
use rspirv::spirv::GLOp;
89
use rustc_codegen_ssa::mir::operand::OperandRef;
910
use rustc_codegen_ssa::mir::place::PlaceRef;
@@ -338,18 +339,7 @@ impl<'a, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'a, 'tcx> {
338339
}
339340

340341
fn abort(&mut self) {
341-
// FIXME(eddyb) this should be cached more efficiently.
342-
let void_ty = SpirvType::Void.def(rustc_span::DUMMY_SP, self);
343-
344-
// HACK(eddyb) there is no `abort` or `trap` instruction in SPIR-V,
345-
// so the best thing we can do is use our own custom instruction.
346-
self.custom_inst(void_ty, CustomInst::Abort);
347-
self.unreachable();
348-
349-
// HACK(eddyb) we still need an active block in case the user of this
350-
// `Builder` will continue to emit instructions after the `.abort()`.
351-
let post_abort_dead_bb = self.append_sibling_block("post_abort_dead");
352-
self.switch_to_block(post_abort_dead_bb);
342+
self.abort_with_message("intrinsics::abort()".into());
353343
}
354344

355345
fn assume(&mut self, _val: Self::Value) {
@@ -382,3 +372,26 @@ impl<'a, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'a, 'tcx> {
382372
todo!()
383373
}
384374
}
375+
376+
impl Builder<'_, '_> {
377+
pub fn abort_with_message(&mut self, message: String) {
378+
// FIXME(eddyb) this should be cached more efficiently.
379+
let void_ty = SpirvType::Void.def(rustc_span::DUMMY_SP, self);
380+
381+
// HACK(eddyb) there is no `abort` or `trap` instruction in SPIR-V,
382+
// so the best thing we can do is use our own custom instruction.
383+
let message_id = self.emit().string(message);
384+
self.custom_inst(
385+
void_ty,
386+
CustomInst::Abort {
387+
message: Operand::IdRef(message_id),
388+
},
389+
);
390+
self.unreachable();
391+
392+
// HACK(eddyb) we still need an active block in case the user of this
393+
// `Builder` will continue to emit instructions after the `.abort()`.
394+
let post_abort_dead_bb = self.append_sibling_block("post_abort_dead");
395+
self.switch_to_block(post_abort_dead_bb);
396+
}
397+
}

crates/rustc_codegen_spirv/src/codegen_cx/mod.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -348,6 +348,12 @@ impl CodegenArgs {
348348
"enable additional SPIR-T passes (comma-separated)",
349349
"PASSES",
350350
);
351+
opts.optopt(
352+
"",
353+
"abort-strategy",
354+
"select a non-default abort (i.e. panic) strategy - see `spirv-builder` docs",
355+
"STRATEGY",
356+
);
351357

352358
// NOTE(eddyb) these are debugging options that used to be env vars
353359
// (for more information see `docs/src/codegen-args.md`).
@@ -529,6 +535,8 @@ impl CodegenArgs {
529535
.map(|s| s.to_string())
530536
.collect(),
531537

538+
abort_strategy: matches.opt_str("abort-strategy"),
539+
532540
// FIXME(eddyb) deduplicate between `CodegenArgs` and `linker::Options`.
533541
emit_multiple_modules: module_output_type == ModuleOutputType::Multiple,
534542
spirv_metadata,

crates/rustc_codegen_spirv/src/custom_insts.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -138,15 +138,15 @@ def_custom_insts! {
138138
// an additional returned `bool`, instead (i.e. a form of emulated unwinding).
139139
//
140140
// As this is a custom terminator, it must only appear before `OpUnreachable`,
141-
// *without* any instructions in between (not even debuginfo ones).
141+
// with at most debuginfo instructions (standard or custom), between the two.
142142
//
143143
// FIXME(eddyb) long-term this kind of custom control-flow could be generalized
144144
// to fully emulate unwinding (resulting in codegen similar to `?` in functions
145145
// returning `Option` or `Result`), to e.g. run destructors, or even allow
146146
// users to do `catch_unwind` at the top-level of their shader to handle
147147
// panics specially (e.g. by appending to a custom buffer, or using some
148148
// specific color in a fragment shader, to indicate a panic happened).
149-
4 => Abort,
149+
4 => Abort { message },
150150
}
151151

152152
impl CustomOp {
@@ -164,8 +164,8 @@ impl CustomOp {
164164
}
165165

166166
/// Returns `true` iff this `CustomOp` is a custom terminator instruction,
167-
/// i.e. semantic and must always appear just before an `OpUnreachable`
168-
/// standard terminator (without even debuginfo in between the two).
167+
/// i.e. semantic and must precede an `OpUnreachable` standard terminator,
168+
/// with at most debuginfo instructions (standard or custom), between the two.
169169
pub fn is_terminator(self) -> bool {
170170
match self {
171171
CustomOp::SetDebugSrcLoc

0 commit comments

Comments
 (0)