[ir][glsl] Basic function emitting
Create the basis for function emission for the GLSL IR printer.
Bug: tint:1993
Change-Id: Ief2acaf12b9f08554f3921d5748591c9a7f0f516
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/156600
Kokoro: Kokoro <noreply+kokoro@google.com>
Commit-Queue: dan sinclair <dsinclair@chromium.org>
Reviewed-by: Ben Clayton <bclayton@google.com>
diff --git a/src/tint/lang/glsl/writer/printer/BUILD.bazel b/src/tint/lang/glsl/writer/printer/BUILD.bazel
index 525314d..f54faec 100644
--- a/src/tint/lang/glsl/writer/printer/BUILD.bazel
+++ b/src/tint/lang/glsl/writer/printer/BUILD.bazel
@@ -64,7 +64,12 @@
"//src/tint/utils/symbol",
"//src/tint/utils/text",
"//src/tint/utils/traits",
- ],
+ ] + select({
+ ":tint_build_glsl_writer": [
+ "//src/tint/lang/glsl/writer/common",
+ ],
+ "//conditions:default": [],
+ }),
copts = COPTS,
visibility = ["//visibility:public"],
)
@@ -73,6 +78,7 @@
alwayslink = True,
srcs = [
"constant_test.cc",
+ "function_test.cc",
"helper_test.h",
],
deps = [
@@ -100,6 +106,7 @@
"@gtest",
] + select({
":tint_build_glsl_writer": [
+ "//src/tint/lang/glsl/writer/common",
"//src/tint/lang/glsl/writer/printer",
],
"//conditions:default": [],
diff --git a/src/tint/lang/glsl/writer/printer/BUILD.cmake b/src/tint/lang/glsl/writer/printer/BUILD.cmake
index 7f291bcb..73f0081 100644
--- a/src/tint/lang/glsl/writer/printer/BUILD.cmake
+++ b/src/tint/lang/glsl/writer/printer/BUILD.cmake
@@ -67,6 +67,12 @@
tint_utils_traits
)
+if(TINT_BUILD_GLSL_WRITER)
+ tint_target_add_dependencies(tint_lang_glsl_writer_printer lib
+ tint_lang_glsl_writer_common
+ )
+endif(TINT_BUILD_GLSL_WRITER)
+
endif(TINT_BUILD_GLSL_WRITER)
if(TINT_BUILD_GLSL_WRITER)
################################################################################
@@ -76,6 +82,7 @@
################################################################################
tint_add_target(tint_lang_glsl_writer_printer_test test
lang/glsl/writer/printer/constant_test.cc
+ lang/glsl/writer/printer/function_test.cc
lang/glsl/writer/printer/helper_test.h
)
@@ -109,6 +116,7 @@
if(TINT_BUILD_GLSL_WRITER)
tint_target_add_dependencies(tint_lang_glsl_writer_printer_test test
+ tint_lang_glsl_writer_common
tint_lang_glsl_writer_printer
)
endif(TINT_BUILD_GLSL_WRITER)
diff --git a/src/tint/lang/glsl/writer/printer/BUILD.gn b/src/tint/lang/glsl/writer/printer/BUILD.gn
index 3c9aca8..20efd60 100644
--- a/src/tint/lang/glsl/writer/printer/BUILD.gn
+++ b/src/tint/lang/glsl/writer/printer/BUILD.gn
@@ -68,6 +68,10 @@
"${tint_src_dir}/utils/text",
"${tint_src_dir}/utils/traits",
]
+
+ if (tint_build_glsl_writer) {
+ deps += [ "${tint_src_dir}/lang/glsl/writer/common" ]
+ }
}
}
if (tint_build_unittests) {
@@ -75,6 +79,7 @@
tint_unittests_source_set("unittests") {
sources = [
"constant_test.cc",
+ "function_test.cc",
"helper_test.h",
]
deps = [
@@ -103,7 +108,10 @@
]
if (tint_build_glsl_writer) {
- deps += [ "${tint_src_dir}/lang/glsl/writer/printer" ]
+ deps += [
+ "${tint_src_dir}/lang/glsl/writer/common",
+ "${tint_src_dir}/lang/glsl/writer/printer",
+ ]
}
}
}
diff --git a/src/tint/lang/glsl/writer/printer/function_test.cc b/src/tint/lang/glsl/writer/printer/function_test.cc
new file mode 100644
index 0000000..763a051
--- /dev/null
+++ b/src/tint/lang/glsl/writer/printer/function_test.cc
@@ -0,0 +1,45 @@
+// Copyright 2023 The Dawn & Tint Authors
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this
+// list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "src/tint/lang/glsl/writer/printer/helper_test.h"
+
+namespace tint::glsl::writer {
+namespace {
+
+TEST_F(GlslPrinterTest, Function_Empty) {
+ auto* func = b.Function("foo", ty.void_());
+ func->Block()->Append(b.Return(func));
+
+ ASSERT_TRUE(Generate()) << err_ << output_;
+ EXPECT_EQ(output_, GlslHeader() + R"(
+void foo() {
+}
+)");
+}
+
+} // namespace
+} // namespace tint::glsl::writer
diff --git a/src/tint/lang/glsl/writer/printer/helper_test.h b/src/tint/lang/glsl/writer/printer/helper_test.h
index 8aa5b0c..709fb17 100644
--- a/src/tint/lang/glsl/writer/printer/helper_test.h
+++ b/src/tint/lang/glsl/writer/printer/helper_test.h
@@ -50,6 +50,8 @@
core::ir::Builder b{mod};
/// The type manager.
core::type::Manager& ty{mod.Types()};
+ /// The GLSL version
+ Version version{};
protected:
/// The GLSL writer.
@@ -70,7 +72,7 @@
return false;
}
- auto result = writer_.Generate();
+ auto result = writer_.Generate(version);
if (!result) {
err_ = result.Failure().reason.str();
return false;
@@ -79,6 +81,17 @@
return true;
}
+
+ /// @returns the metal header string
+ std::string GlslHeader() const {
+ std::stringstream ver;
+ ver << "#version " << version.major_version << version.minor_version << "0";
+ if (version.IsES()) {
+ ver << " es";
+ }
+ ver << "\n";
+ return ver.str();
+ }
};
using GlslPrinterTest = GlslPrinterTestHelperBase<testing::Test>;
diff --git a/src/tint/lang/glsl/writer/printer/printer.cc b/src/tint/lang/glsl/writer/printer/printer.cc
index e2f47d1..6351b29 100644
--- a/src/tint/lang/glsl/writer/printer/printer.cc
+++ b/src/tint/lang/glsl/writer/printer/printer.cc
@@ -29,22 +29,49 @@
#include <utility>
+#include "src/tint/lang/core/ir/return.h"
+#include "src/tint/lang/core/ir/unreachable.h"
#include "src/tint/lang/core/ir/validator.h"
+#include "src/tint/utils/macros/scoped_assignment.h"
+#include "src/tint/utils/rtti/switch.h"
using namespace tint::core::fluent_types; // NOLINT
namespace tint::glsl::writer {
+// Helper for calling TINT_UNIMPLEMENTED() from a Switch(object_ptr) default case.
+#define UNHANDLED_CASE(object_ptr) \
+ TINT_UNIMPLEMENTED() << "unhandled case in Switch(): " \
+ << (object_ptr ? object_ptr->TypeInfo().name : "<null>")
+
Printer::Printer(core::ir::Module& module) : ir_(module) {}
Printer::~Printer() = default;
-tint::Result<SuccessType> Printer::Generate() {
+tint::Result<SuccessType> Printer::Generate(Version version) {
auto valid = core::ir::ValidateAndDumpIfNeeded(ir_, "GLSL writer");
if (!valid) {
return std::move(valid.Failure());
}
+ {
+ TINT_SCOPED_ASSIGNMENT(current_buffer_, &preamble_buffer_);
+
+ auto out = Line();
+ out << "#version " << version.major_version << version.minor_version << "0";
+ if (version.IsES()) {
+ out << " es";
+ }
+ }
+
+ // Emit module-scope declarations.
+ EmitBlockInstructions(ir_.root_block);
+
+ // Emit functions.
+ for (auto* func : ir_.functions) {
+ EmitFunction(func);
+ }
+
return Success;
}
@@ -54,4 +81,69 @@
return ss.str();
}
+void Printer::EmitFunction(core::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(core::ir::Block* block) {
+ // TODO(dsinclair): Handle marking inline
+ // MarkInlinable(block);
+
+ EmitBlockInstructions(block);
+}
+
+void Printer::EmitBlockInstructions(core::ir::Block* block) {
+ TINT_SCOPED_ASSIGNMENT(current_block_, block);
+
+ for (auto* inst : *block) {
+ Switch(
+ inst, //
+ [&](core::ir::Return* r) { EmitReturn(r); }, //
+ [&](core::ir::Unreachable*) { EmitUnreachable(); }, //
+ [&](Default) { UNHANDLED_CASE(inst); });
+ }
+}
+
+void Printer::EmitType(StringStream& out, [[maybe_unused]] const core::type::Type* ty) {
+ out << "void";
+}
+
+void Printer::EmitReturn(core::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";
+ // TODO(dsinclair): Handle return args
+ // if (!r->Args().IsEmpty()) {
+ // out << " " << Expr(r->Args().Front());
+ // }
+ out << ";";
+}
+
+void Printer::EmitUnreachable() {
+ Line() << "/* unreachable */";
+}
+
} // namespace tint::glsl::writer
diff --git a/src/tint/lang/glsl/writer/printer/printer.h b/src/tint/lang/glsl/writer/printer/printer.h
index b04908d..5df46df 100644
--- a/src/tint/lang/glsl/writer/printer/printer.h
+++ b/src/tint/lang/glsl/writer/printer/printer.h
@@ -31,6 +31,7 @@
#include <string>
#include "src/tint/lang/core/ir/module.h"
+#include "src/tint/lang/glsl/writer/common/version.h"
#include "src/tint/utils/generator/text_generator.h"
// Forward declarations
@@ -55,17 +56,45 @@
explicit Printer(core::ir::Module& module);
~Printer() override;
+ /// @param version the GLSL version information
/// @returns success or failure
- tint::Result<SuccessType> Generate();
+ tint::Result<SuccessType> Generate(Version version);
/// @copydoc tint::TextGenerator::Result
std::string Result() const override;
private:
+ /// Emit the function
+ /// @param func the function to emit
+ void EmitFunction(core::ir::Function* func);
+
+ /// Emit a block
+ /// @param block the block to emit
+ void EmitBlock(core::ir::Block* block);
+ /// Emit the instructions in a block
+ /// @param block the block with the instructions to emit
+ void EmitBlockInstructions(core::ir::Block* block);
+
+ /// Emit a return instruction
+ /// @param r the return instruction
+ void EmitReturn(core::ir::Return* r);
+ /// Emit an unreachable instruction
+ void EmitUnreachable();
+
+ /// Emit a type
+ /// @param out the stream to emit too
+ /// @param ty the type to emit
+ void EmitType(StringStream& out, const core::type::Type* ty);
+
core::ir::Module& ir_;
/// The buffer holding preamble text
TextBuffer preamble_buffer_;
+
+ /// The current function being emitted
+ core::ir::Function* current_function_ = nullptr;
+ /// The current block being emitted
+ core::ir::Block* current_block_ = nullptr;
};
} // namespace tint::glsl::writer
diff --git a/src/tint/lang/glsl/writer/writer.cc b/src/tint/lang/glsl/writer/writer.cc
index f5743d5..bc0f045 100644
--- a/src/tint/lang/glsl/writer/writer.cc
+++ b/src/tint/lang/glsl/writer/writer.cc
@@ -72,7 +72,7 @@
// Generate the GLSL code.
auto impl = std::make_unique<Printer>(ir);
- auto result = impl->Generate();
+ auto result = impl->Generate(options.version);
if (!result) {
return result.Failure();
}