[glsl] Emit user call statements
Add emitting of user call statements.
Bug: 42251044
Change-Id: Ic30d588472f47d9412ff8c90f5808c85448cbc41
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/200244
Reviewed-by: James Price <jrprice@google.com>
Commit-Queue: dan sinclair <dsinclair@chromium.org>
diff --git a/src/tint/lang/glsl/writer/BUILD.bazel b/src/tint/lang/glsl/writer/BUILD.bazel
index 111f1a9..9ea3151 100644
--- a/src/tint/lang/glsl/writer/BUILD.bazel
+++ b/src/tint/lang/glsl/writer/BUILD.bazel
@@ -87,6 +87,7 @@
name = "test",
alwayslink = True,
srcs = [
+ "call_test.cc",
"constant_test.cc",
"function_test.cc",
] + select({
diff --git a/src/tint/lang/glsl/writer/BUILD.cmake b/src/tint/lang/glsl/writer/BUILD.cmake
index 8e0850b..f105f30 100644
--- a/src/tint/lang/glsl/writer/BUILD.cmake
+++ b/src/tint/lang/glsl/writer/BUILD.cmake
@@ -98,6 +98,7 @@
# Condition: TINT_BUILD_GLSL_WRITER AND TINT_BUILD_GLSL_VALIDATOR
################################################################################
tint_add_target(tint_lang_glsl_writer_test test
+ lang/glsl/writer/call_test.cc
lang/glsl/writer/constant_test.cc
lang/glsl/writer/function_test.cc
)
diff --git a/src/tint/lang/glsl/writer/BUILD.gn b/src/tint/lang/glsl/writer/BUILD.gn
index 966c7b0..1d2047c 100644
--- a/src/tint/lang/glsl/writer/BUILD.gn
+++ b/src/tint/lang/glsl/writer/BUILD.gn
@@ -90,6 +90,7 @@
if (tint_build_glsl_writer && tint_build_glsl_validator) {
tint_unittests_source_set("unittests") {
sources = [
+ "call_test.cc",
"constant_test.cc",
"function_test.cc",
]
diff --git a/src/tint/lang/glsl/writer/call_test.cc b/src/tint/lang/glsl/writer/call_test.cc
new file mode 100644
index 0000000..b7148f1
--- /dev/null
+++ b/src/tint/lang/glsl/writer/call_test.cc
@@ -0,0 +1,116 @@
+// Copyright 2024 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/helper_test.h"
+
+using namespace tint::core::number_suffixes; // NOLINT
+using namespace tint::core::fluent_types; // NOLINT
+
+namespace tint::glsl::writer {
+namespace {
+
+// TODO(dsinclair): Enable when `let` is supported
+TEST_F(GlslWriterTest, DISABLED_CallWithoutParams) {
+ auto* f = b.Function("a", ty.bool_());
+ f->Block()->Append(b.Return(f, false));
+
+ auto* ep = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kCompute);
+ ep->SetWorkgroupSize(1, 1, 1);
+ b.Append(ep->Block(), [&] {
+ b.Let("x", b.Call(f));
+ b.Return(ep);
+ });
+
+ ASSERT_TRUE(Generate()) << err_ << output_.glsl;
+ EXPECT_EQ(output_.glsl, GlslHeader() + R"(
+bool a() {
+ return false;
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+ bool x = a();
+}
+
+)");
+}
+
+// TODO(dsinclair): Enable when FunctionParam is supported
+TEST_F(GlslWriterTest, DISABLED_CallWithParams) {
+ auto* p1 = b.FunctionParam("p1", ty.f32());
+ auto* p2 = b.FunctionParam("p2", ty.bool_());
+
+ auto* f = b.Function("a", ty.bool_());
+ f->SetParams({p1, p2});
+ f->Block()->Append(b.Return(f, p2));
+
+ auto* ep = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kCompute);
+ ep->SetWorkgroupSize(1, 1, 1);
+ b.Append(ep->Block(), [&] {
+ b.Let("x", b.Call(f, 1.2_f, false));
+ b.Return(ep);
+ });
+
+ ASSERT_TRUE(Generate()) << err_ << output_.glsl;
+ EXPECT_EQ(output_.glsl, GlslHeader() + R"(
+bool a(float p1, bool p2) {
+ return p2;
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+ bool x = a(1.2f, false);
+}
+
+)");
+}
+
+TEST_F(GlslWriterTest, CallStatement) {
+ auto* f = b.Function("a", ty.bool_());
+ f->Block()->Append(b.Return(f, false));
+
+ auto* ep = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kCompute);
+ ep->SetWorkgroupSize(1, 1, 1);
+ b.Append(ep->Block(), [&] {
+ b.Call(f);
+ b.Return(ep);
+ });
+
+ ASSERT_TRUE(Generate()) << err_ << output_.glsl;
+ EXPECT_EQ(output_.glsl, GlslHeader() + R"(
+bool a() {
+ return false;
+}
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+ a();
+}
+)");
+}
+
+} // namespace
+} // namespace tint::glsl::writer
diff --git a/src/tint/lang/glsl/writer/printer/printer.cc b/src/tint/lang/glsl/writer/printer/printer.cc
index 02012a4..8ce53bd 100644
--- a/src/tint/lang/glsl/writer/printer/printer.cc
+++ b/src/tint/lang/glsl/writer/printer/printer.cc
@@ -30,10 +30,21 @@
#include <string>
#include <utility>
+#include "src/tint/lang/core/ir/access.h"
+#include "src/tint/lang/core/ir/bitcast.h"
+#include "src/tint/lang/core/ir/construct.h"
+#include "src/tint/lang/core/ir/core_binary.h"
+#include "src/tint/lang/core/ir/core_unary.h"
+#include "src/tint/lang/core/ir/exit_if.h"
#include "src/tint/lang/core/ir/function.h"
+#include "src/tint/lang/core/ir/load.h"
+#include "src/tint/lang/core/ir/load_vector_element.h"
#include "src/tint/lang/core/ir/module.h"
+#include "src/tint/lang/core/ir/next_iteration.h"
#include "src/tint/lang/core/ir/return.h"
+#include "src/tint/lang/core/ir/swizzle.h"
#include "src/tint/lang/core/ir/unreachable.h"
+#include "src/tint/lang/core/ir/user_call.h"
#include "src/tint/lang/core/ir/validator.h"
#include "src/tint/lang/core/type/bool.h"
#include "src/tint/lang/core/type/f16.h"
@@ -59,7 +70,7 @@
public:
/// Constructor
/// @param module the Tint IR module to generate
- explicit Printer(const core::ir::Module& module) : ir_(module) {}
+ explicit Printer(core::ir::Module& module) : ir_(module) {}
/// @param version the GLSL version information
/// @returns the generated GLSL shader
@@ -80,7 +91,7 @@
}
// Emit module-scope declarations.
- EmitBlockInstructions(ir_.root_block);
+ EmitBlock(ir_.root_block);
// Emit functions.
for (auto& func : ir_.functions) {
@@ -93,7 +104,7 @@
}
private:
- const core::ir::Module& ir_;
+ core::ir::Module& ir_;
/// The buffer holding preamble text
TextBuffer preamble_buffer_;
@@ -105,6 +116,25 @@
Hashset<std::string, 4> emitted_extensions_;
+ /// A hashmap of value to name
+ Hashmap<const core::ir::Value*, std::string, 32> names_;
+
+ /// @returns the name of the given value, creating a new unique name if the value is unnamed in
+ /// the module.
+ std::string NameOf(const core::ir::Value* value) {
+ return names_.GetOrAdd(value, [&] {
+ auto sym = ir_.NameOf(value);
+ return sym.IsValid() ? sym.Name() : UniqueIdentifier("v");
+ });
+ }
+
+ /// @return a new, unique identifier with the given prefix.
+ /// @param prefix optional prefix to apply to the generated identifier. If empty
+ /// "tint_symbol" will be used.
+ std::string UniqueIdentifier(const std::string& prefix /* = "" */) {
+ return ir_.symbols.New(prefix).Name();
+ }
+
/// Emit the function
/// @param func the function to emit
void EmitFunction(const core::ir::Function* func) {
@@ -140,26 +170,38 @@
/// Emit a block
/// @param block the block to emit
void EmitBlock(const core::ir::Block* block) {
- // TODO(dsinclair): Handle marking inline
- // MarkInlinable(block);
-
- EmitBlockInstructions(block);
- }
-
- /// Emit the instructions in a block
- /// @param block the block with the instructions to emit
- void EmitBlockInstructions(const core::ir::Block* block) {
TINT_SCOPED_ASSIGNMENT(current_block_, block);
for (auto* inst : *block) {
tint::Switch(
inst, //
+ [&](const core::ir::Call* i) { EmitCallStmt(i); }, //
[&](const core::ir::Return* r) { EmitReturn(r); }, //
[&](const core::ir::Unreachable*) { EmitUnreachable(); }, //
+
+ [&](const core::ir::NextIteration*) { /* do nothing */ }, //
+ [&](const core::ir::ExitIf*) { /* do nothing handled by transform */ }, //
+ //
+ [&](const core::ir::Access*) { /* inlined */ }, //
+ [&](const core::ir::Bitcast*) { /* inlined */ }, //
+ [&](const core::ir::Construct*) { /* inlined */ }, //
+ [&](const core::ir::CoreBinary*) { /* inlined */ }, //
+ [&](const core::ir::CoreUnary*) { /* inlined */ }, //
+ [&](const core::ir::Load*) { /* inlined */ }, //
+ [&](const core::ir::LoadVectorElement*) { /* inlined */ }, //
+ [&](const core::ir::Swizzle*) { /* inlined */ }, //
TINT_ICE_ON_NO_MATCH);
}
}
+ void EmitCallStmt(const core::ir::Call* c) {
+ if (!c->Result(0)->IsUsed()) {
+ auto out = Line();
+ EmitValue(out, c->Result(0));
+ out << ";";
+ }
+ }
+
void EmitExtension(std::string name) {
if (emitted_extensions_.Contains(name)) {
return;
@@ -213,11 +255,31 @@
tint::Switch(
v, //
[&](const core::ir::Constant* c) { EmitConstant(out, c); }, //
-
+ [&](const core::ir::InstructionResult* r) {
+ tint::Switch(
+ r->Instruction(), //
+ [&](const core::ir::UserCall* c) { EmitUserCall(out, c); }, //
+ TINT_ICE_ON_NO_MATCH);
+ },
// TODO(dsinclair): Handle remaining value types
TINT_ICE_ON_NO_MATCH);
}
+ /// Emits a user call instruction
+ void EmitUserCall(StringStream& out, const core::ir::UserCall* c) {
+ out << NameOf(c->Target()) << "(";
+ size_t i = 0;
+ for (const auto* arg : c->Args()) {
+ if (i > 0) {
+ out << ", ";
+ }
+ ++i;
+
+ EmitValue(out, arg);
+ }
+ out << ")";
+ }
+
void EmitConstant(StringStream& out, const core::ir::Constant* c) {
EmitConstant(out, c->Value());
}
@@ -240,7 +302,7 @@
};
} // namespace
-Result<std::string> Print(const core::ir::Module& module, const Version& version) {
+Result<std::string> Print(core::ir::Module& module, const Version& version) {
return Printer{module}.Generate(version);
}
diff --git a/src/tint/lang/glsl/writer/printer/printer.h b/src/tint/lang/glsl/writer/printer/printer.h
index 6f75b39..49c6301 100644
--- a/src/tint/lang/glsl/writer/printer/printer.h
+++ b/src/tint/lang/glsl/writer/printer/printer.h
@@ -45,7 +45,7 @@
/// @returns the generated GLSL shader on success, or failure
/// @param module the Tint IR module to generate
/// @param version the GLSL version information
-Result<std::string> Print(const core::ir::Module& module, const Version& version);
+Result<std::string> Print(core::ir::Module& module, const Version& version);
} // namespace tint::glsl::writer