[ir][msl] Add `return` support
Add support for `return` in the MSL IR generator.
Bug: tint:1967
Change-Id: Ib38994ef97119a1b39b35ae3d157d91b3a741a1d
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/144201
Kokoro: Kokoro <noreply+kokoro@google.com>
Reviewed-by: James Price <jrprice@google.com>
Commit-Queue: Dan Sinclair <dsinclair@chromium.org>
diff --git a/src/tint/BUILD.gn b/src/tint/BUILD.gn
index e570fe8..371d351 100644
--- a/src/tint/BUILD.gn
+++ b/src/tint/BUILD.gn
@@ -2329,6 +2329,7 @@
"lang/msl/writer/printer/constant_test.cc",
"lang/msl/writer/printer/function_test.cc",
"lang/msl/writer/printer/helper_test.h",
+ "lang/msl/writer/printer/return_test.cc",
"lang/msl/writer/printer/type_test.cc",
]
deps += [
diff --git a/src/tint/CMakeLists.txt b/src/tint/CMakeLists.txt
index d9e69b7..f1dbdaf 100644
--- a/src/tint/CMakeLists.txt
+++ b/src/tint/CMakeLists.txt
@@ -1556,6 +1556,7 @@
lang/msl/writer/printer/constant_test.cc
lang/msl/writer/printer/function_test.cc
lang/msl/writer/printer/helper_test.h
+ lang/msl/writer/printer/return_test.cc
lang/msl/writer/printer/type_test.cc
)
endif()
diff --git a/src/tint/lang/msl/writer/printer/helper_test.h b/src/tint/lang/msl/writer/printer/helper_test.h
index aaf7e15..d6c9f8b 100644
--- a/src/tint/lang/msl/writer/printer/helper_test.h
+++ b/src/tint/lang/msl/writer/printer/helper_test.h
@@ -18,13 +18,17 @@
#include <iostream>
#include <string>
-#include "gtest/gtest.h"
+#include "gmock/gmock.h"
#include "src/tint/lang/core/ir/builder.h"
#include "src/tint/lang/core/ir/validator.h"
#include "src/tint/lang/msl/writer/printer/printer.h"
namespace tint::msl::writer {
+constexpr auto kMetalHeader = R"(#include <metal_stdlib>
+using namespace metal;
+)";
+
/// Base helper class for testing the MSL generator implementation.
template <typename BASE>
class MslPrinterTestHelperBase : public BASE {
@@ -38,6 +42,9 @@
/// The type manager.
type::Manager& ty{mod.Types()};
+ /// @returns the metal header string
+ std::string MetalHeader() const { return kMetalHeader; }
+
protected:
/// The MSL generator.
Printer generator_;
diff --git a/src/tint/lang/msl/writer/printer/printer.cc b/src/tint/lang/msl/writer/printer/printer.cc
index f29bc65..5294f89 100644
--- a/src/tint/lang/msl/writer/printer/printer.cc
+++ b/src/tint/lang/msl/writer/printer/printer.cc
@@ -17,6 +17,8 @@
#include "src/tint/lang/core/constant/composite.h"
#include "src/tint/lang/core/constant/splat.h"
#include "src/tint/lang/core/ir/constant.h"
+#include "src/tint/lang/core/ir/multi_in_block.h"
+#include "src/tint/lang/core/ir/return.h"
#include "src/tint/lang/core/ir/validator.h"
#include "src/tint/lang/core/type/array.h"
#include "src/tint/lang/core/type/atomic.h"
@@ -71,7 +73,6 @@
{
TINT_SCOPED_ASSIGNMENT(current_buffer_, &preamble_buffer_);
Line() << "#include <metal_stdlib>";
- Line();
Line() << "using namespace metal;";
}
@@ -98,15 +99,6 @@
return ss.str();
}
-void Printer::EmitFunction(ir::Function* func) {
- {
- auto out = Line();
- EmitType(out, func->ReturnType());
- out << " " << ir_->NameOf(func).Name() << "() {";
- }
- Line() << "}";
-}
-
const std::string& Printer::ArrayTemplateName() {
if (!array_template_name_.empty()) {
return array_template_name_;
@@ -134,6 +126,74 @@
return array_template_name_;
}
+void Printer::EmitFunction(ir::Function* func) {
+ TINT_SCOPED_ASSIGNMENT(current_function_, func);
+
+ {
+ auto out = Line();
+
+ // TODO(dsinclair): Emit function stage if any
+ // TODO(dsinclair): Handle return type attributes
+
+ EmitType(out, func->ReturnType());
+ out << " " << ir_->NameOf(func).Name() << "() {";
+
+ // TODO(dsinclair): Emit Function parameters
+ }
+ {
+ ScopedIndent si(current_buffer_);
+ EmitBlock(func->Block());
+ }
+
+ Line() << "}";
+}
+
+void Printer::EmitBlock(ir::Block* block) {
+ if (block->As<ir::MultiInBlock>()) {
+ // TODO(dsinclair): Emit variables to used by the PHIs.
+ }
+
+ // TODO(dsinclair): Handle inline things
+ // MarkInlinable(block);
+
+ EmitBlockInstructions(block);
+}
+
+void Printer::EmitBlockInstructions(ir::Block* block) {
+ TINT_SCOPED_ASSIGNMENT(current_block_, block);
+
+ for (auto* inst : *block) {
+ Switch(
+ inst, //
+ [&](ir::Return* r) { EmitReturn(r); }, //
+ [&](Default) { TINT_ICE() << "unimplemented instruction: " << inst->TypeInfo().name; });
+ }
+}
+
+void Printer::EmitReturn(ir::Return* r) {
+ // If this return has no arguments and the current block is for the function which is being
+ // returned, skip the return.
+ if (current_block_ == current_function_->Block() && r->Args().IsEmpty()) {
+ return;
+ }
+
+ auto out = Line();
+
+ out << "return";
+ if (!r->Args().IsEmpty()) {
+ // TODO(dsinclair): This should emit the expression instead of just assuming it's a constant
+ // value
+ if (!r->Args().Front()->Is<ir::Constant>()) {
+ TINT_ICE() << "return only handles constants";
+ return;
+ }
+
+ out << " "; // << Expr(out, r->Args().Front());
+ EmitConstant(out, r->Args().Front()->As<ir::Constant>());
+ }
+ out << ";";
+}
+
void Printer::EmitAddressSpace(StringStream& out, builtin::AddressSpace sc) {
switch (sc) {
case builtin::AddressSpace::kFunction:
diff --git a/src/tint/lang/msl/writer/printer/printer.h b/src/tint/lang/msl/writer/printer/printer.h
index 92f7ffd..59c87ac 100644
--- a/src/tint/lang/msl/writer/printer/printer.h
+++ b/src/tint/lang/msl/writer/printer/printer.h
@@ -25,6 +25,11 @@
#include "src/tint/utils/generator/text_generator.h"
#include "src/tint/utils/text/string_stream.h"
+// Forward declarations
+namespace tint::ir {
+class Return;
+} // namespace tint::ir
+
namespace tint::msl::writer {
/// Implementation class for the MSL generator
@@ -45,6 +50,17 @@
/// @param func the function to emit
void EmitFunction(ir::Function* func);
+ /// Emit a block
+ /// @param block the block to emit
+ void EmitBlock(ir::Block* block);
+ /// Emit the instructions in a block
+ /// @param block the block with the instructions to emit
+ void EmitBlockInstructions(ir::Block* block);
+
+ /// Emit a return instruction
+ /// @param r the return instruction
+ void EmitReturn(ir::Return* r);
+
/// Emit a type
/// @param out the stream to emit too
/// @param ty the type to emit
@@ -125,6 +141,11 @@
std::string invariant_define_name_;
std::unordered_set<const type::Struct*> emitted_structs_;
+
+ /// The current function being emitted
+ ir::Function* current_function_ = nullptr;
+ /// The current block being emitted
+ ir::Block* current_block_ = nullptr;
};
} // namespace tint::msl::writer
diff --git a/src/tint/lang/msl/writer/printer/return_test.cc b/src/tint/lang/msl/writer/printer/return_test.cc
new file mode 100644
index 0000000..ae8fdab
--- /dev/null
+++ b/src/tint/lang/msl/writer/printer/return_test.cc
@@ -0,0 +1,64 @@
+// Copyright 2023 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "src/tint/lang/msl/writer/printer/helper_test.h"
+
+using namespace tint::number_suffixes; // NOLINT
+
+namespace tint::msl::writer {
+namespace {
+
+// TODO(dsinclair): Requires if emission in MSL generator
+TEST_F(MslPrinterTest, DISABLED_Return) {
+ auto* func = b.Function("foo", ty.void_());
+ b.Append(func->Block(), [&] {
+ auto* if_ = b.If(true);
+ b.Append(if_->True(), [&] { b.Return(func); });
+ });
+
+ ASSERT_TRUE(generator_.Generate()) << generator_.Diagnostics().str();
+ EXPECT_EQ(generator_.Result(), MetalHeader() + R"(
+void foo() {
+ if (true) {
+ return;
+ }
+}
+)");
+}
+
+TEST_F(MslPrinterTest, ReturnAtEndOfVoidDropped) {
+ auto* func = b.Function("foo", ty.void_());
+ func->Block()->Append(b.Return(func));
+
+ ASSERT_TRUE(generator_.Generate()) << generator_.Diagnostics().str();
+ EXPECT_EQ(generator_.Result(), MetalHeader() + R"(
+void foo() {
+}
+)");
+}
+
+TEST_F(MslPrinterTest, ReturnWithValue) {
+ auto* func = b.Function("foo", ty.i32());
+ func->Block()->Append(b.Return(func, 123_i));
+
+ ASSERT_TRUE(generator_.Generate()) << generator_.Diagnostics().str();
+ EXPECT_EQ(generator_.Result(), MetalHeader() + R"(
+int foo() {
+ return 123;
+}
+)");
+}
+
+} // namespace
+} // namespace tint::msl::writer