Fix incorrect continue target.
A single-block loop inside the continuing of a parent loop may have the
continuing block as it's continuing target. Previously we'd set the
outer loop as the continue target in the IR which is invalid. Instead,
when we're emitting the continue block, remove the continuing
information so it can be re-added when we emit the inner loop.
Fixed: 42250521
Change-Id: I77c4fe115008eee6c68ed9c20131d89a573d85c4
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/265714
Commit-Queue: James Price <jrprice@google.com>
Auto-Submit: 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 8692e2a..91fb798 100644
--- a/src/tint/lang/spirv/reader/parser/branch_test.cc
+++ b/src/tint/lang/spirv/reader/parser/branch_test.cc
@@ -7249,5 +7249,77 @@
)");
}
+TEST_F(SpirvParserTest, LoopInContinuing) {
+ EXPECT_IR(R"(
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %fn "main"
+ OpExecutionMode %fn OriginUpperLeft
+ %void = OpTypeVoid
+ %bool = OpTypeBool
+ %false = OpConstantFalse %bool
+ %void_fn = OpTypeFunction %void
+
+ %fn = OpFunction %void None %void_fn
+ %entry = OpLabel
+ OpBranch %loop1
+ %loop1 = OpLabel
+
+ OpLoopMerge %loop1_merge %loop2 None
+ OpBranch %loop1_body
+ %loop1_body = OpLabel
+ OpBranchConditional %false %loop1_merge %loop2
+ %loop2 = OpLabel
+
+ OpLoopMerge %loop2_merge %loop2 None
+ OpBranchConditional %false %loop2_merge %loop2
+ %loop2_merge = OpLabel
+ OpBranch %loop1
+
+ %loop1_merge = OpLabel
+ OpReturn
+ OpFunctionEnd
+)",
+ R"(
+%main = @fragment func():void {
+ $B1: {
+ loop [b: $B2, c: $B3] { # loop_1
+ $B2: { # body
+ if false [t: $B4, f: $B5] { # if_1
+ $B4: { # true
+ exit_loop # loop_1
+ }
+ $B5: { # false
+ continue # -> $B3
+ }
+ }
+ unreachable
+ }
+ $B3: { # continuing
+ loop [b: $B6, c: $B7] { # loop_2
+ $B6: { # body
+ if false [t: $B8, f: $B9] { # if_2
+ $B8: { # true
+ exit_loop # loop_2
+ }
+ $B9: { # false
+ continue # -> $B7
+ }
+ }
+ unreachable
+ }
+ $B7: { # continuing
+ next_iteration # -> $B6
+ }
+ }
+ 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 429c041..6069d72 100644
--- a/src/tint/lang/spirv/reader/parser/parser.cc
+++ b/src/tint/lang/spirv/reader/parser/parser.cc
@@ -1791,6 +1791,12 @@
}
void EmitContinueBlock(uint32_t src_id, uint32_t continue_id, core::ir::Loop* loop) {
+ // We're emitting the continue block, so remove it from the continue targets as it can no
+ // longer be a target for this loop. This will allow it to be _reused_ as the continue
+ // target for a single block loop if needed (which may have this same block as the
+ // continue).
+ continue_targets_.erase(continue_id);
+
// Push id stack entry for the continuing block. We don't use EmitBlockParent to do this
// because we need the scope to exist until after we process any `continue_blk_phis_`.
id_stack_.emplace_back();