[spirv-reader][ir] Ignore continuing blocks without inbound branches. If there are no branches into the continuing block, we can skip emitting it. This works around an issue in SPIR-V where the continuing with no in-bound branches can reference IDs from any of the blocks above it. This makes it really hard to propagate the value up to the continuing block. Bug: 42250952 Change-Id: If855dbb4a743a93ea0adc3b72dd87bbc1cef8481 Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/246274 Commit-Queue: dan sinclair <dsinclair@chromium.org> Reviewed-by: James Price <jrprice@google.com>
diff --git a/src/tint/lang/spirv/reader/parser/branch_test.cc b/src/tint/lang/spirv/reader/parser/branch_test.cc index f1d14c9..b7a97fd 100644 --- a/src/tint/lang/spirv/reader/parser/branch_test.cc +++ b/src/tint/lang/spirv/reader/parser/branch_test.cc
@@ -3872,11 +3872,10 @@ unreachable } $B3: { # continuing - %4:i32 = spirv.add<i32> 2i, 2i next_iteration # -> $B2 } } - %5:i32 = spirv.add<i32> 3i, 3i + %4:i32 = spirv.add<i32> 3i, 3i ret } } @@ -4109,7 +4108,6 @@ exit_loop # loop_1 } $B3: { # continuing - %3:i32 = spirv.add<i32> 2i, 2i next_iteration # -> $B2 } } @@ -4602,7 +4600,6 @@ exit_loop # loop_1 } $B3: { # continuing - %3:i32 = spirv.add<i32> 2i, 2i next_iteration # -> $B2 } } @@ -5649,11 +5646,10 @@ unreachable } $B3: { # continuing - %5:i32 = spirv.add<i32> 3i, 3i next_iteration # -> $B2 } } - %6:i32 = spirv.add<i32> 1i, 3i + %5:i32 = spirv.add<i32> 1i, 3i ret } } @@ -5713,11 +5709,10 @@ unreachable } $B3: { # continuing - %6:i32 = spirv.add<i32> 1i, 2i next_iteration # -> $B2 } } - %7:i32 = spirv.add<i32> 1i, 3i + %6:i32 = spirv.add<i32> 1i, 3i ret } } @@ -7133,6 +7128,73 @@ } )"); } +TEST_F(SpirvParserTest, ConvertHoisted) { + EXPECT_IR(R"( + OpCapability Shader + OpMemoryModel Logical Simple + OpEntryPoint Fragment %100 "main" + OpExecutionMode %100 OriginUpperLeft + %void = OpTypeVoid + %2 = OpTypeFunction %void + %bool = OpTypeBool + %uint = OpTypeInt 32 0 + %float = OpTypeFloat 32 + %true = OpConstantTrue %bool + %float_50 = OpConstant %float 50 + %100 = OpFunction %void None %2 + %10 = OpLabel + OpBranch %30 + %30 = OpLabel + OpLoopMerge %90 %80 None + OpBranchConditional %true %90 %40 + %40 = OpLabel + OpSelectionMerge %50 None + OpBranchConditional %true %45 %50 + %45 = OpLabel + %600 = OpCopyObject %float %float_50 + OpBranch %50 + %50 = OpLabel + OpBranch %90 + %80 = OpLabel + %82 = OpConvertFToU %uint %600 + OpBranch %30 + %90 = OpLabel + OpReturn + OpFunctionEnd +)", + R"( +%main = @fragment func():void { + $B1: { + loop [b: $B2, c: $B3] { # loop_1 + $B2: { # body + if true [t: $B4, f: $B5] { # if_1 + $B4: { # true + exit_loop # loop_1 + } + $B5: { # false + if true [t: $B6, f: $B7] { # if_2 + $B6: { # true + %2:f32 = let 50.0f + exit_if # if_2 + } + $B7: { # false + exit_if # if_2 + } + } + exit_loop # loop_1 + } + } + unreachable + } + $B3: { # continuing + next_iteration # -> $B2 + } + } + ret + } +} +)"); +} } // namespace } // namespace tint::spirv::reader
diff --git a/src/tint/lang/spirv/reader/parser/parser.cc b/src/tint/lang/spirv/reader/parser/parser.cc index a725e62..45482cf 100644 --- a/src/tint/lang/spirv/reader/parser/parser.cc +++ b/src/tint/lang/spirv/reader/parser/parser.cc
@@ -1300,7 +1300,7 @@ } } - bool InBlock(core::ir::Block* blk) { return current_blocks_.count(blk) > 0; } + bool InBlock(core::ir::Block* blk) { return current_blocks_.contains(blk); } // A block parent is a container for a scope, like a `{}`d section in code. It controls the // block addition to the current blocks and the ID stack entry for the block. @@ -1774,7 +1774,14 @@ id_stack_.emplace_back(); auto continue_id = loop_merge_inst->GetSingleWordInOperand(1); - if (continue_id != src.id()) { + + // We only need to emit the continuing block if: + // a) It is not the loop header + // b) It has inbound branches. This works around a case where you can have a continuing + // where uses values which are very difficult to propagate, but the continuing is + // never reached anyway, so the propagation is useless. + if (continue_id != src.id() && + !loop->Continuing()->InboundSiblingBranches().IsEmpty()) { const auto& bb_continue = current_spirv_function_->FindBlock(continue_id); current_blocks_.insert(loop->Continuing());