[ir][msl] Stub out IR MSL Generator
Create the skeleton of an IR based MSL generator. This sets up the
various required generator files, test files and other needed helpers.
An IRTextGenerator is added which includes a `preamble_buffer` text
block to go along with the `main_buffer`. This allows emitting things
into the pre-amble out of order but have them appear before all
functions.
Bug: tint:1967
Change-Id: I4a8030ec0e18f4869c0ee98af4049ebf070f0de8
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/138740
Kokoro: Kokoro <noreply+kokoro@google.com>
Reviewed-by: Ben Clayton <bclayton@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 3901d5d..77d6165 100644
--- a/src/tint/BUILD.gn
+++ b/src/tint/BUILD.gn
@@ -1020,6 +1020,15 @@
":libtint_type_src",
":libtint_utils_src",
]
+
+ if (tint_build_ir) {
+ sources += [
+ "writer/ir_text_generator.cc",
+ "writer/ir_text_generator.h",
+ ]
+
+ deps += [ ":libtint_ir_src" ]
+ }
}
libtint_source_set("libtint_spv_writer_src") {
@@ -1136,6 +1145,18 @@
":libtint_utils_src",
":libtint_writer_src",
]
+
+ if (tint_build_ir) {
+ sources += [
+ "writer/msl/ir/generator_impl_ir.cc",
+ "writer/msl/ir/generator_impl_ir.h",
+ ]
+ deps += [
+ ":libtint_ir_builder_src",
+ ":libtint_ir_src",
+ ":libtint_ir_transform_src",
+ ]
+ }
}
libtint_source_set("libtint_hlsl_writer_src") {
@@ -2191,6 +2212,14 @@
":libtint_utils_src",
":tint_unittests_ast_src",
]
+
+ if (tint_build_ir) {
+ sources += [
+ "writer/msl/ir/generator_impl_ir_function_test.cc",
+ "writer/msl/ir/test_helper_ir.h",
+ ]
+ deps += [ ":libtint_ir_src" ]
+ }
}
tint_unittests_source_set("tint_unittests_hlsl_writer_src") {
@@ -2374,6 +2403,7 @@
]
deps = [
+ ":libtint_builtins_src",
":libtint_ir_builder_src",
":libtint_ir_src",
]
diff --git a/src/tint/CMakeLists.txt b/src/tint/CMakeLists.txt
index a9c5a8d..ee9d6b9 100644
--- a/src/tint/CMakeLists.txt
+++ b/src/tint/CMakeLists.txt
@@ -575,6 +575,8 @@
writer/flatten_bindings.h
writer/float_to_string.cc
writer/float_to_string.h
+ writer/ir_text_generator.cc
+ writer/ir_text_generator.h
writer/text_generator.cc
writer/text_generator.h
writer/text.cc
@@ -693,6 +695,13 @@
writer/msl/generator_impl.cc
writer/msl/generator_impl.h
)
+
+ if(${TINT_BUILD_IR})
+ list(APPEND TINT_LIB_SRCS
+ writer/msl/ir/generator_impl_ir.cc
+ writer/msl/ir/generator_impl_ir.h
+ )
+ endif()
endif()
if(${TINT_BUILD_GLSL_WRITER})
@@ -1442,6 +1451,13 @@
writer/msl/generator_impl_variable_decl_statement_test.cc
writer/msl/test_helper.h
)
+
+ if(${TINT_BUILD_IR})
+ list(APPEND TINT_TEST_SRCS
+ writer/msl/ir/generator_impl_ir_function_test.cc
+ writer/msl/ir/test_helper_ir.h
+ )
+ endif()
endif()
if (${TINT_BUILD_GLSL_WRITER})
diff --git a/src/tint/ir/disassembler.cc b/src/tint/ir/disassembler.cc
index 03c88ee..f8e301f 100644
--- a/src/tint/ir/disassembler.cc
+++ b/src/tint/ir/disassembler.cc
@@ -42,7 +42,6 @@
#include "src/tint/ir/store.h"
#include "src/tint/ir/switch.h"
#include "src/tint/ir/swizzle.h"
-#include "src/tint/ir/transform/block_decorated_structs.h"
#include "src/tint/ir/unreachable.h"
#include "src/tint/ir/user_call.h"
#include "src/tint/ir/var.h"
diff --git a/src/tint/writer/ast_text_generator.h b/src/tint/writer/ast_text_generator.h
index 243458c..74c42ae 100644
--- a/src/tint/writer/ast_text_generator.h
+++ b/src/tint/writer/ast_text_generator.h
@@ -31,7 +31,7 @@
/// Constructor
/// @param program the program used by the generator
explicit ASTTextGenerator(const Program* program);
- ~ASTTextGenerator();
+ ~ASTTextGenerator() override;
/// @return a new, unique identifier with the given prefix.
/// @param prefix optional prefix to apply to the generated identifier. If
diff --git a/src/tint/writer/glsl/generator_impl.h b/src/tint/writer/glsl/generator_impl.h
index 23633ae..8650647 100644
--- a/src/tint/writer/glsl/generator_impl.h
+++ b/src/tint/writer/glsl/generator_impl.h
@@ -81,7 +81,7 @@
/// @param program the program to generate
/// @param version the GLSL version to use
GeneratorImpl(const Program* program, const Version& version);
- ~GeneratorImpl();
+ ~GeneratorImpl() override;
/// Generates the GLSL shader
void Generate();
diff --git a/src/tint/writer/hlsl/generator_impl.h b/src/tint/writer/hlsl/generator_impl.h
index 3028853..1d8b59c 100644
--- a/src/tint/writer/hlsl/generator_impl.h
+++ b/src/tint/writer/hlsl/generator_impl.h
@@ -79,7 +79,7 @@
/// Constructor
/// @param program the program to generate
explicit GeneratorImpl(const Program* program);
- ~GeneratorImpl();
+ ~GeneratorImpl() override;
/// @returns true on successful generation; false otherwise
bool Generate();
diff --git a/src/tint/writer/ir_text_generator.cc b/src/tint/writer/ir_text_generator.cc
new file mode 100644
index 0000000..91ed689
--- /dev/null
+++ b/src/tint/writer/ir_text_generator.cc
@@ -0,0 +1,23 @@
+// 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/writer/ir_text_generator.h"
+
+namespace tint::writer {
+
+IRTextGenerator::IRTextGenerator(ir::Module* mod) : ir_(mod) {}
+
+IRTextGenerator::~IRTextGenerator() = default;
+
+} // namespace tint::writer
diff --git a/src/tint/writer/ir_text_generator.h b/src/tint/writer/ir_text_generator.h
new file mode 100644
index 0000000..5ae6003
--- /dev/null
+++ b/src/tint/writer/ir_text_generator.h
@@ -0,0 +1,50 @@
+// 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.
+
+#ifndef SRC_TINT_WRITER_IR_TEXT_GENERATOR_H_
+#define SRC_TINT_WRITER_IR_TEXT_GENERATOR_H_
+
+#include <string>
+
+#include "src/tint/ir/module.h"
+#include "src/tint/writer/text_generator.h"
+
+namespace tint::writer {
+
+/// Helper methods for generators which are creating text output
+class IRTextGenerator : public TextGenerator {
+ public:
+ /// Constructor
+ /// @param mod the IR module used by the generator
+ explicit IRTextGenerator(ir::Module* mod);
+ ~IRTextGenerator() override;
+
+ /// @returns the generated shader string
+ std::string result() const override {
+ utils::StringStream ss;
+ ss << preamble_buffer_.String() << std::endl << main_buffer_.String();
+ return ss.str();
+ }
+
+ protected:
+ /// The IR module
+ ir::Module* ir_ = nullptr;
+
+ /// The buffer holding preamble text
+ TextBuffer preamble_buffer_;
+};
+
+} // namespace tint::writer
+
+#endif // SRC_TINT_WRITER_IR_TEXT_GENERATOR_H_
diff --git a/src/tint/writer/msl/generator.cc b/src/tint/writer/msl/generator.cc
index f811a88..b562655 100644
--- a/src/tint/writer/msl/generator.cc
+++ b/src/tint/writer/msl/generator.cc
@@ -18,6 +18,11 @@
#include "src/tint/writer/msl/generator_impl.h"
+#if TINT_BUILD_IR
+#include "src/tint/ir/from_program.h" // nogncheck
+#include "src/tint/writer/msl/ir/generator_impl_ir.h" // nogncheck
+#endif // TINT_BUILD_IR
+
namespace tint::writer::msl {
Options::Options() = default;
@@ -36,24 +41,43 @@
return result;
}
- // Sanitize the program.
- auto sanitized_result = Sanitize(program, options);
- if (!sanitized_result.program.IsValid()) {
- result.success = false;
- result.error = sanitized_result.program.Diagnostics().str();
- return result;
- }
- result.needs_storage_buffer_sizes = sanitized_result.needs_storage_buffer_sizes;
- result.used_array_length_from_uniform_indices =
- std::move(sanitized_result.used_array_length_from_uniform_indices);
+#if TINT_BUILD_IR
+ if (options.use_tint_ir) {
+ // Convert the AST program to an IR module.
+ auto converted = ir::FromProgram(program);
+ if (!converted) {
+ result.error = "IR converter: " + converted.Failure();
+ return result;
+ }
- // Generate the MSL code.
- auto impl = std::make_unique<GeneratorImpl>(&sanitized_result.program);
- result.success = impl->Generate();
- result.error = impl->Diagnostics().str();
- result.msl = impl->result();
- result.has_invariant_attribute = impl->HasInvariant();
- result.workgroup_allocations = impl->DynamicWorkgroupAllocations();
+ // Generate the MSL code.
+ auto ir = converted.Move();
+ auto impl = std::make_unique<GeneratorImplIr>(&ir);
+ result.success = impl->Generate();
+ result.error = impl->Diagnostics().str();
+ result.msl = impl->result();
+ } else // NOLINT(readability/braces)
+#endif
+ {
+ // Sanitize the program.
+ auto sanitized_result = Sanitize(program, options);
+ if (!sanitized_result.program.IsValid()) {
+ result.success = false;
+ result.error = sanitized_result.program.Diagnostics().str();
+ return result;
+ }
+ result.needs_storage_buffer_sizes = sanitized_result.needs_storage_buffer_sizes;
+ result.used_array_length_from_uniform_indices =
+ std::move(sanitized_result.used_array_length_from_uniform_indices);
+
+ // Generate the MSL code.
+ auto impl = std::make_unique<GeneratorImpl>(&sanitized_result.program);
+ result.success = impl->Generate();
+ result.error = impl->Diagnostics().str();
+ result.msl = impl->result();
+ result.has_invariant_attribute = impl->HasInvariant();
+ result.workgroup_allocations = impl->DynamicWorkgroupAllocations();
+ }
return result;
}
diff --git a/src/tint/writer/msl/generator.h b/src/tint/writer/msl/generator.h
index 53805f1..886277c 100644
--- a/src/tint/writer/msl/generator.h
+++ b/src/tint/writer/msl/generator.h
@@ -74,6 +74,11 @@
/// Options used in the bindings remapper
BindingRemapperOptions binding_remapper_options = {};
+#if TINT_BUILD_IR
+ /// Set to `true` to generate MSL via the Tint IR instead of from the AST.
+ bool use_tint_ir = false;
+#endif
+
/// Reflect the fields of this class so that it can be used by tint::ForeachField()
TINT_REFLECT(disable_robustness,
buffer_size_ubo_index,
diff --git a/src/tint/writer/msl/generator_impl.h b/src/tint/writer/msl/generator_impl.h
index b9bd3501..a272187 100644
--- a/src/tint/writer/msl/generator_impl.h
+++ b/src/tint/writer/msl/generator_impl.h
@@ -85,7 +85,7 @@
/// Constructor
/// @param program the program to generate
explicit GeneratorImpl(const Program* program);
- ~GeneratorImpl();
+ ~GeneratorImpl() override;
/// @returns true on successful generation; false otherwise
bool Generate();
diff --git a/src/tint/writer/msl/ir/generator_impl_ir.cc b/src/tint/writer/msl/ir/generator_impl_ir.cc
new file mode 100644
index 0000000..1a4e5b7
--- /dev/null
+++ b/src/tint/writer/msl/ir/generator_impl_ir.cc
@@ -0,0 +1,77 @@
+// 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/writer/msl/ir/generator_impl_ir.h"
+
+#include "src/tint/ir/validate.h"
+#include "src/tint/transform/manager.h"
+#include "src/tint/utils/scoped_assignment.h"
+
+namespace tint::writer::msl {
+namespace {
+
+void Sanitize(ir::Module* module) {
+ transform::Manager manager;
+ transform::DataMap data;
+
+ transform::DataMap outputs;
+ manager.Run(module, data, outputs);
+}
+
+} // namespace
+
+GeneratorImplIr::GeneratorImplIr(ir::Module* module) : IRTextGenerator(module) {}
+
+GeneratorImplIr::~GeneratorImplIr() = default;
+
+bool GeneratorImplIr::Generate() {
+ auto valid = ir::Validate(*ir_);
+ if (!valid) {
+ diagnostics_ = valid.Failure();
+ return false;
+ }
+
+ // Run the IR transformations to prepare for MSL emission.
+ Sanitize(ir_);
+
+ {
+ TINT_SCOPED_ASSIGNMENT(current_buffer_, &preamble_buffer_);
+ line() << "#include <metal_stdlib>";
+ line();
+ line() << "using namespace metal;";
+ }
+
+ // Emit module-scope declarations.
+ if (ir_->root_block) {
+ // EmitRootBlock(ir_->root_block);
+ }
+
+ // Emit functions.
+ for (auto* func : ir_->functions) {
+ EmitFunction(func);
+ }
+
+ if (diagnostics_.contains_errors()) {
+ return false;
+ }
+
+ return true;
+}
+
+void GeneratorImplIr::EmitFunction(ir::Function* func) {
+ line() << "void " << ir_->NameOf(func).Name() << "() {";
+ line() << "}";
+}
+
+} // namespace tint::writer::msl
diff --git a/src/tint/writer/msl/ir/generator_impl_ir.h b/src/tint/writer/msl/ir/generator_impl_ir.h
new file mode 100644
index 0000000..584a88f
--- /dev/null
+++ b/src/tint/writer/msl/ir/generator_impl_ir.h
@@ -0,0 +1,42 @@
+// 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.
+
+#ifndef SRC_TINT_WRITER_MSL_IR_GENERATOR_IMPL_IR_H_
+#define SRC_TINT_WRITER_MSL_IR_GENERATOR_IMPL_IR_H_
+
+#include "src/tint/diagnostic/diagnostic.h"
+#include "src/tint/ir/module.h"
+#include "src/tint/writer/ir_text_generator.h"
+
+namespace tint::writer::msl {
+
+/// Implementation class for the MSL generator
+class GeneratorImplIr : public IRTextGenerator {
+ public:
+ /// Constructor
+ /// @param module the Tint IR module to generate
+ explicit GeneratorImplIr(ir::Module* module);
+ ~GeneratorImplIr() override;
+
+ /// @returns true on successful generation; false otherwise
+ bool Generate();
+
+ /// Emit the function
+ /// @param func the function to emit
+ void EmitFunction(ir::Function* func);
+};
+
+} // namespace tint::writer::msl
+
+#endif // SRC_TINT_WRITER_MSL_IR_GENERATOR_IMPL_IR_H_
diff --git a/src/tint/writer/msl/ir/generator_impl_ir_function_test.cc b/src/tint/writer/msl/ir/generator_impl_ir_function_test.cc
new file mode 100644
index 0000000..5789037
--- /dev/null
+++ b/src/tint/writer/msl/ir/generator_impl_ir_function_test.cc
@@ -0,0 +1,34 @@
+// 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/writer/msl/ir/test_helper_ir.h"
+
+namespace tint::writer::msl {
+namespace {
+
+TEST_F(MslGeneratorImplIrTest, Function_Empty) {
+ auto* func = b.Function("foo", ty.void_());
+ func->Block()->Append(b.Return(func));
+
+ ASSERT_TRUE(IRIsValid()) << Error();
+
+ generator_.EmitFunction(func);
+ EXPECT_EQ(generator_.result(), R"(
+void foo() {
+}
+)");
+}
+
+} // namespace
+} // namespace tint::writer::msl
diff --git a/src/tint/writer/msl/ir/test_helper_ir.h b/src/tint/writer/msl/ir/test_helper_ir.h
new file mode 100644
index 0000000..38bbf9b
--- /dev/null
+++ b/src/tint/writer/msl/ir/test_helper_ir.h
@@ -0,0 +1,68 @@
+// 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.
+
+#ifndef SRC_TINT_WRITER_MSL_IR_TEST_HELPER_IR_H_
+#define SRC_TINT_WRITER_MSL_IR_TEST_HELPER_IR_H_
+
+#include <string>
+
+#include "gtest/gtest.h"
+#include "src/tint/ir/builder.h"
+#include "src/tint/ir/validate.h"
+#include "src/tint/writer/msl/ir/generator_impl_ir.h"
+
+namespace tint::writer::msl {
+
+/// Base helper class for testing the MSL generator implementation.
+template <typename BASE>
+class MslGeneratorIrTestHelperBase : public BASE {
+ public:
+ MslGeneratorIrTestHelperBase() : generator_(&mod) {}
+
+ /// The test module.
+ ir::Module mod;
+ /// The test builder.
+ ir::Builder b{mod};
+ /// The type manager.
+ type::Manager& ty{mod.Types()};
+
+ protected:
+ /// The MSL generator.
+ GeneratorImplIr generator_;
+
+ /// Validation errors
+ std::string err_;
+
+ /// @returns the error string from the validation
+ std::string Error() const { return err_; }
+
+ /// @returns true if the IR module is valid
+ bool IRIsValid() {
+ auto res = ir::Validate(mod);
+ if (!res) {
+ err_ = res.Failure().str();
+ return false;
+ }
+ return true;
+ }
+};
+
+using MslGeneratorImplIrTest = MslGeneratorIrTestHelperBase<testing::Test>;
+
+template <typename T>
+using MslGeneratorImplIrTestWithParam = MslGeneratorIrTestHelperBase<testing::TestWithParam<T>>;
+
+} // namespace tint::writer::msl
+
+#endif // SRC_TINT_WRITER_MSL_IR_TEST_HELPER_IR_H_
diff --git a/src/tint/writer/syntax_tree/generator_impl.h b/src/tint/writer/syntax_tree/generator_impl.h
index 2473df2..4ffed4a 100644
--- a/src/tint/writer/syntax_tree/generator_impl.h
+++ b/src/tint/writer/syntax_tree/generator_impl.h
@@ -46,7 +46,7 @@
/// Constructor
/// @param program the program
explicit GeneratorImpl(const Program* program);
- ~GeneratorImpl();
+ ~GeneratorImpl() override;
/// Generates the result data
void Generate();
diff --git a/src/tint/writer/text_generator.h b/src/tint/writer/text_generator.h
index 8458db0..7d9113b 100644
--- a/src/tint/writer/text_generator.h
+++ b/src/tint/writer/text_generator.h
@@ -87,7 +87,7 @@
/// Constructor
TextGenerator();
- ~TextGenerator();
+ virtual ~TextGenerator();
/// Increment the emitter indent level
void increment_indent() { current_buffer_->IncrementIndent(); }
@@ -95,7 +95,7 @@
void decrement_indent() { current_buffer_->DecrementIndent(); }
/// @returns the result data
- std::string result() const { return main_buffer_.String(); }
+ virtual std::string result() const { return main_buffer_.String(); }
/// @returns the list of diagnostics raised by the generator.
const diag::List& Diagnostics() const { return diagnostics_; }
@@ -183,7 +183,6 @@
/// The buffer the TextGenerator is currently appending lines to
TextBuffer* current_buffer_ = &main_buffer_;
- private:
/// The primary text buffer that the generator will emit
TextBuffer main_buffer_;
};
diff --git a/src/tint/writer/wgsl/generator_impl.h b/src/tint/writer/wgsl/generator_impl.h
index 6c67d79..25df464 100644
--- a/src/tint/writer/wgsl/generator_impl.h
+++ b/src/tint/writer/wgsl/generator_impl.h
@@ -46,7 +46,7 @@
/// Constructor
/// @param program the program
explicit GeneratorImpl(const Program* program);
- ~GeneratorImpl();
+ ~GeneratorImpl() override;
/// Generates the result data
void Generate();