[spirv] Do not add exit phi for loop initializer
When a loop with an empty initializer block has results, we were
treating the initializer as an implicit exit block and adding OpPhi
operands for it. The only implicit exit blocks we have are on `if`
instructions, so restrict the implicit exit block logic to those.
Change-Id: If0beaba4816f683fd58ec82d832a12c59f07e347
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/190462
Reviewed-by: dan sinclair <dsinclair@chromium.org>
Reviewed-by: Ben Clayton <bclayton@google.com>
diff --git a/src/tint/lang/spirv/writer/common/helper_test.h b/src/tint/lang/spirv/writer/common/helper_test.h
index 553b173..bedc457 100644
--- a/src/tint/lang/spirv/writer/common/helper_test.h
+++ b/src/tint/lang/spirv/writer/common/helper_test.h
@@ -36,6 +36,7 @@
#include "gtest/gtest.h"
#include "spirv-tools/libspirv.hpp"
#include "src/tint/lang/core/ir/builder.h"
+#include "src/tint/lang/core/ir/disassembly.h"
#include "src/tint/lang/core/ir/validator.h"
#include "src/tint/lang/core/type/array.h"
#include "src/tint/lang/core/type/depth_texture.h"
@@ -241,6 +242,10 @@
}
return nullptr;
}
+
+ /// Helper to dump the disassembly of the Tint IR module.
+ /// @returns the disassembly (with a leading newline)
+ std::string IR() { return "\n" + core::ir::Disassemble(mod).Plain(); }
};
using SpirvWriterTest = SpirvWriterTestHelperBase<testing::Test>;
diff --git a/src/tint/lang/spirv/writer/loop_test.cc b/src/tint/lang/spirv/writer/loop_test.cc
index f8ccb38..a5640fa 100644
--- a/src/tint/lang/spirv/writer/loop_test.cc
+++ b/src/tint/lang/spirv/writer/loop_test.cc
@@ -621,5 +621,48 @@
)");
}
+TEST_F(SpirvWriterTest, Loop_ExitValue) {
+ auto* func = b.Function("foo", ty.i32());
+ b.Append(func->Block(), [&] {
+ auto* result = b.InstructionResult(ty.i32());
+ auto* loop = b.Loop();
+ loop->SetResults(Vector{result});
+ b.Append(loop->Body(), [&] { //
+ b.ExitLoop(loop, 42_i);
+ });
+ b.Return(func, result);
+ });
+
+ EXPECT_EQ(IR(), R"(
+%foo = func():i32 {
+ $B1: {
+ %2:i32 = loop [b: $B2] { # loop_1
+ $B2: { # body
+ exit_loop 42i # loop_1
+ }
+ }
+ ret %2
+ }
+}
+)");
+
+ ASSERT_TRUE(Generate()) << Error() << output_;
+ EXPECT_INST(R"(
+ %4 = OpLabel
+ OpBranch %7
+ %7 = OpLabel
+ OpLoopMerge %8 %6 None
+ OpBranch %5
+ %5 = OpLabel
+ OpBranch %8
+ %6 = OpLabel
+ OpBranch %7
+ %8 = OpLabel
+ %9 = OpPhi %int %int_42 %5
+ OpReturnValue %9
+ OpFunctionEnd
+)");
+}
+
} // namespace
} // namespace tint::spirv::writer
diff --git a/src/tint/lang/spirv/writer/printer/printer.cc b/src/tint/lang/spirv/writer/printer/printer.cc
index 3a3fa00..8a7ccc1 100644
--- a/src/tint/lang/spirv/writer/printer/printer.cc
+++ b/src/tint/lang/spirv/writer/printer/printer.cc
@@ -2191,11 +2191,13 @@
branches.Sort(); // Sort the branches by label to ensure deterministic output
// Also add phi nodes from implicit exit blocks.
- inst->ForeachBlock([&](core::ir::Block* block) {
- if (block->IsEmpty()) {
- branches.Push(Branch{Label(block), nullptr});
- }
- });
+ if (inst->Is<core::ir::If>()) {
+ inst->ForeachBlock([&](core::ir::Block* block) {
+ if (block->IsEmpty()) {
+ branches.Push(Branch{Label(block), nullptr});
+ }
+ });
+ }
OperandList ops{Type(ty), Value(result)};
for (auto& branch : branches) {