Skip to content

Commit fb1c777

Browse files
nazar-pcjimblandy
authored andcommitted
naga: fix panic parsing SPIR-V subgroup reduce/scan/ballot ops
1 parent 2eddc8c commit fb1c777

5 files changed

Lines changed: 94 additions & 4 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ Bottom level categories:
8484
#### naga
8585

8686
- Fix panics when shader `var<immediate>` size is larger than 256 bytes. By @beicause in [#9725](https://github.com/gfx-rs/wgpu/pull/9725).
87+
- Fix a panic in the SPIR-V frontend when a subgroup collective operation (e.g. `OpGroupNonUniformUMin`) or `OpGroupNonUniformBallot` used an argument whose value needed to be spilled to a temporary variable, such as when the argument was computed inside a loop. By @nazar-pc in [#9957](https://github.com/gfx-rs/wgpu/issues/9957).
8788

8889
#### Validation
8990

naga/src/front/spv/next_block.rs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2533,7 +2533,6 @@ impl<I: Iterator<Item = u32>> Frontend<I> {
25332533
}
25342534
Op::GroupNonUniformBallot => {
25352535
inst.expect(5)?;
2536-
block.extend(emitter.finish(ctx.expressions));
25372536
let result_type_id = self.next()?;
25382537
let result_id = self.next()?;
25392538
let exec_scope_id = self.next()?;
@@ -2564,6 +2563,7 @@ impl<I: Iterator<Item = u32>> Frontend<I> {
25642563
Some(predicate_handle)
25652564
};
25662565

2566+
block.extend(emitter.finish(ctx.expressions));
25672567
let result_handle = ctx
25682568
.expressions
25692569
.append(crate::Expression::SubgroupBallotResult, span);
@@ -2603,7 +2603,6 @@ impl<I: Iterator<Item = u32>> Frontend<I> {
26032603
| Op::GroupNonUniformLogicalAnd
26042604
| Op::GroupNonUniformLogicalOr
26052605
| Op::GroupNonUniformLogicalXor => {
2606-
block.extend(emitter.finish(ctx.expressions));
26072606
inst.expect(
26082607
if matches!(inst.op, Op::GroupNonUniformAll | Op::GroupNonUniformAny) {
26092608
5
@@ -2639,6 +2638,8 @@ impl<I: Iterator<Item = u32>> Frontend<I> {
26392638
let argument_lookup = self.lookup_expression.lookup(argument_id)?;
26402639
let argument_handle = get_expr_handle!(argument_id, argument_lookup);
26412640

2641+
block.extend(emitter.finish(ctx.expressions));
2642+
26422643
let exec_scope_const = self.lookup_constant.lookup(exec_scope_id)?;
26432644
let _exec_scope = resolve_constant(ctx.gctx(), &exec_scope_const.inner)
26442645
.filter(|exec_scope| *exec_scope == spirv::Scope::Subgroup as u32)
@@ -2711,7 +2712,6 @@ impl<I: Iterator<Item = u32>> Frontend<I> {
27112712
} else {
27122713
6
27132714
})?;
2714-
block.extend(emitter.finish(ctx.expressions));
27152715
let result_type_id = self.next()?;
27162716
let result_id = self.next()?;
27172717
let exec_scope_id = self.next()?;
@@ -2752,6 +2752,7 @@ impl<I: Iterator<Item = u32>> Frontend<I> {
27522752
}
27532753
};
27542754

2755+
block.extend(emitter.finish(ctx.expressions));
27552756
let result_type = self.lookup_type.lookup(result_type_id)?;
27562757

27572758
let result_handle = ctx.expressions.append(
@@ -2781,7 +2782,6 @@ impl<I: Iterator<Item = u32>> Frontend<I> {
27812782
}
27822783
Op::GroupNonUniformQuadSwap => {
27832784
inst.expect(6)?;
2784-
block.extend(emitter.finish(ctx.expressions));
27852785
let result_type_id = self.next()?;
27862786
let result_id = self.next()?;
27872787
let exec_scope_id = self.next()?;
@@ -2791,6 +2791,8 @@ impl<I: Iterator<Item = u32>> Frontend<I> {
27912791
let argument_lookup = self.lookup_expression.lookup(argument_id)?;
27922792
let argument_handle = get_expr_handle!(argument_id, argument_lookup);
27932793

2794+
block.extend(emitter.finish(ctx.expressions));
2795+
27942796
let exec_scope_const = self.lookup_constant.lookup(exec_scope_id)?;
27952797
let _exec_scope = resolve_constant(ctx.gctx(), &exec_scope_const.inner)
27962798
.filter(|exec_scope| *exec_scope == spirv::Scope::Subgroup as u32)
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
; SPIR-V
2+
; Version: 1.3
3+
;
4+
; Regression test for https://github.com/gfx-rs/wgpu/issues/8389
5+
;
6+
; The `naga` SPIR-V frontend panicked with
7+
; `called Option::unwrap() on a None value` at `naga::proc::emitter::Emitter::finish`
8+
; when a `OpGroupNonUniform*` reduction/scan instruction (e.g. `OpGroupNonUniformUMin`)
9+
; used an argument whose defining expression came from an already-closed control-flow
10+
; body (here, a value computed inside a loop and used after the loop merges), which
11+
; requires spilling the value through a temporary local variable.
12+
OpCapability Shader
13+
OpCapability GroupNonUniform
14+
OpCapability GroupNonUniformArithmetic
15+
%ext = OpExtInstImport "GLSL.std.450"
16+
OpMemoryModel Logical GLSL450
17+
OpEntryPoint GLCompute %main "main" %local_id
18+
OpExecutionMode %main LocalSize 1 1 1
19+
OpDecorate %local_id BuiltIn LocalInvocationIndex
20+
21+
%void = OpTypeVoid
22+
%voidfn = OpTypeFunction %void
23+
%uint = OpTypeInt 32 0
24+
%bool = OpTypeBool
25+
%_ptr_Input_uint = OpTypePointer Input %uint
26+
%local_id = OpVariable %_ptr_Input_uint Input
27+
%uint_0 = OpConstant %uint 0
28+
%uint_1 = OpConstant %uint 1
29+
%uint_4 = OpConstant %uint 4
30+
%subgroup_scope = OpConstant %uint 3
31+
32+
%main = OpFunction %void None %voidfn
33+
%entry = OpLabel
34+
%id = OpLoad %uint %local_id
35+
OpBranch %loop_header
36+
37+
%loop_header = OpLabel
38+
%i = OpPhi %uint %uint_0 %entry %i_next %continue
39+
OpLoopMerge %merge %continue None
40+
OpBranch %body
41+
42+
%body = OpLabel
43+
%acc = OpIAdd %uint %id %i
44+
OpBranch %continue
45+
46+
%continue = OpLabel
47+
%i_next = OpIAdd %uint %i %uint_1
48+
%cond = OpULessThan %bool %i_next %uint_4
49+
OpBranchConditional %cond %loop_header %merge
50+
51+
%merge = OpLabel
52+
%min = OpGroupNonUniformUMin %uint %subgroup_scope Reduce %acc
53+
OpReturn
54+
OpFunctionEnd
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
capabilities = "SUBGROUP"
2+
targets = "WGSL"
3+
4+
[spv]
5+
version = [1, 3]
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
var<private> global: u32;
2+
3+
fn function_() {
4+
var phi_16_: u32;
5+
var local: u32;
6+
7+
let _e4 = global;
8+
phi_16_ = 0u;
9+
loop {
10+
let _e6 = phi_16_;
11+
local = (_e4 + _e6);
12+
continue;
13+
continuing {
14+
let _e8 = (_e6 + 1u);
15+
phi_16_ = _e8;
16+
break if !((_e8 < 4u));
17+
}
18+
}
19+
let _e12 = local;
20+
let _e13 = subgroupMin(_e12);
21+
return;
22+
}
23+
24+
@compute @workgroup_size(1, 1, 1)
25+
fn main(@builtin(local_invocation_index) param: u32) {
26+
global = param;
27+
function_();
28+
}

0 commit comments

Comments
 (0)