[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());