Skip to content

Commit 54be6a2

Browse files
authored
Fix empty ifs causing errors on spirv 1.6 (#7883)
1 parent 2d835bf commit 54be6a2

File tree

11 files changed

+309
-206
lines changed

11 files changed

+309
-206
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,12 @@ By @Vecvec in [#7913](https://github.com/gfx-rs/wgpu/pull/7913).
109109

110110
- Fixed memory leak in vulkan backend. By @cwfitzgerald in [#8031](https://github.com/gfx-rs/wgpu/pull/8031).
111111

112+
### Bug Fixes
113+
114+
#### Naga
115+
116+
- Fix empty `if` statements causing errors on spirv 1.6+. By @Vecvec in [#7883](https://github.com/gfx-rs/wgpu/pull/7883).
117+
112118
## v26.0.2 (2025-07-23)
113119

114120
### Bug Fixes

naga/src/back/spv/block.rs

Lines changed: 58 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -2979,62 +2979,69 @@ impl BlockContext<'_> {
29792979
ref accept,
29802980
ref reject,
29812981
} => {
2982-
let condition_id = self.cached[condition];
2982+
// In spirv 1.6, in a conditional branch the two block ids
2983+
// of the branches can't have the same label. If `accept`
2984+
// and `reject` are both empty (e.g. in `if (condition) {}`)
2985+
// merge id will be both labels. Because both branches are
2986+
// empty, we can skip the if statement.
2987+
if !(accept.is_empty() && reject.is_empty()) {
2988+
let condition_id = self.cached[condition];
2989+
2990+
let merge_id = self.gen_id();
2991+
block.body.push(Instruction::selection_merge(
2992+
merge_id,
2993+
spirv::SelectionControl::NONE,
2994+
));
29832995

2984-
let merge_id = self.gen_id();
2985-
block.body.push(Instruction::selection_merge(
2986-
merge_id,
2987-
spirv::SelectionControl::NONE,
2988-
));
2996+
let accept_id = if accept.is_empty() {
2997+
None
2998+
} else {
2999+
Some(self.gen_id())
3000+
};
3001+
let reject_id = if reject.is_empty() {
3002+
None
3003+
} else {
3004+
Some(self.gen_id())
3005+
};
29893006

2990-
let accept_id = if accept.is_empty() {
2991-
None
2992-
} else {
2993-
Some(self.gen_id())
2994-
};
2995-
let reject_id = if reject.is_empty() {
2996-
None
2997-
} else {
2998-
Some(self.gen_id())
2999-
};
3007+
self.function.consume(
3008+
block,
3009+
Instruction::branch_conditional(
3010+
condition_id,
3011+
accept_id.unwrap_or(merge_id),
3012+
reject_id.unwrap_or(merge_id),
3013+
),
3014+
);
30003015

3001-
self.function.consume(
3002-
block,
3003-
Instruction::branch_conditional(
3004-
condition_id,
3005-
accept_id.unwrap_or(merge_id),
3006-
reject_id.unwrap_or(merge_id),
3007-
),
3008-
);
3016+
if let Some(block_id) = accept_id {
3017+
// We can ignore the `BlockExitDisposition` returned here because,
3018+
// even if `merge_id` is not actually reachable, it is always
3019+
// referred to by the `OpSelectionMerge` instruction we emitted
3020+
// earlier.
3021+
let _ = self.write_block(
3022+
block_id,
3023+
accept,
3024+
BlockExit::Branch { target: merge_id },
3025+
loop_context,
3026+
debug_info,
3027+
)?;
3028+
}
3029+
if let Some(block_id) = reject_id {
3030+
// We can ignore the `BlockExitDisposition` returned here because,
3031+
// even if `merge_id` is not actually reachable, it is always
3032+
// referred to by the `OpSelectionMerge` instruction we emitted
3033+
// earlier.
3034+
let _ = self.write_block(
3035+
block_id,
3036+
reject,
3037+
BlockExit::Branch { target: merge_id },
3038+
loop_context,
3039+
debug_info,
3040+
)?;
3041+
}
30093042

3010-
if let Some(block_id) = accept_id {
3011-
// We can ignore the `BlockExitDisposition` returned here because,
3012-
// even if `merge_id` is not actually reachable, it is always
3013-
// referred to by the `OpSelectionMerge` instruction we emitted
3014-
// earlier.
3015-
let _ = self.write_block(
3016-
block_id,
3017-
accept,
3018-
BlockExit::Branch { target: merge_id },
3019-
loop_context,
3020-
debug_info,
3021-
)?;
3022-
}
3023-
if let Some(block_id) = reject_id {
3024-
// We can ignore the `BlockExitDisposition` returned here because,
3025-
// even if `merge_id` is not actually reachable, it is always
3026-
// referred to by the `OpSelectionMerge` instruction we emitted
3027-
// earlier.
3028-
let _ = self.write_block(
3029-
block_id,
3030-
reject,
3031-
BlockExit::Branch { target: merge_id },
3032-
loop_context,
3033-
debug_info,
3034-
)?;
3043+
block = Block::new(merge_id);
30353044
}
3036-
3037-
block = Block::new(merge_id);
30383045
}
30393046
Statement::Switch {
30403047
selector,

naga/tests/in/wgsl/empty-if.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
[spv]
2+
version = [1, 6]

naga/tests/in/wgsl/empty-if.wgsl

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
@workgroup_size(1)
2+
@compute
3+
fn comp(@builtin(global_invocation_id) id: vec3<u32>) {
4+
if (id.x == 0) {
5+
6+
}
7+
_ = 1+1; // otherwise, naga generates returns in the if statement.
8+
return;
9+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
#version 310 es
2+
3+
precision highp float;
4+
precision highp int;
5+
6+
layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
7+
8+
9+
void main() {
10+
uvec3 id = gl_GlobalInvocationID;
11+
if ((id.x == 0u)) {
12+
}
13+
return;
14+
}
15+
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
[numthreads(1, 1, 1)]
2+
void comp(uint3 id : SV_DispatchThreadID)
3+
{
4+
if ((id.x == 0u)) {
5+
}
6+
return;
7+
}

naga/tests/out/hlsl/wgsl-empty-if.ron

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
(
2+
vertex:[
3+
],
4+
fragment:[
5+
],
6+
compute:[
7+
(
8+
entry_point:"comp",
9+
target_profile:"cs_5_1",
10+
),
11+
],
12+
)

naga/tests/out/msl/wgsl-empty-if.msl

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// language: metal1.0
2+
#include <metal_stdlib>
3+
#include <simd/simd.h>
4+
5+
using metal::uint;
6+
7+
8+
struct compInput {
9+
};
10+
kernel void comp(
11+
metal::uint3 id [[thread_position_in_grid]]
12+
) {
13+
if (id.x == 0u) {
14+
}
15+
return;
16+
}

0 commit comments

Comments
 (0)