[tint][ir] Begin building proto-based serializer
Change-Id: Idf01b213b642afb4614ee0b0dbc4d1a70979cc70
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/155702
Reviewed-by: James Price <jrprice@google.com>
Kokoro: Kokoro <noreply+kokoro@google.com>
Commit-Queue: Ben Clayton <bclayton@google.com>
diff --git a/src/tint/CMakeLists.txt b/src/tint/CMakeLists.txt
index 208a231..9a4eba5 100644
--- a/src/tint/CMakeLists.txt
+++ b/src/tint/CMakeLists.txt
@@ -41,6 +41,12 @@
endif()
endif()
+if (TARGET libprotobuf)
+ set(TINT_BUILD_IR_BINARY 1)
+else()
+ set(TINT_BUILD_IR_BINARY 0)
+endif()
+
################################################################################
# Helper functions
################################################################################
@@ -50,6 +56,7 @@
target_compile_definitions(${TARGET} PUBLIC -DTINT_BUILD_GLSL_VALIDATOR=$<BOOL:${TINT_BUILD_GLSL_VALIDATOR}>)
target_compile_definitions(${TARGET} PUBLIC -DTINT_BUILD_GLSL_WRITER=$<BOOL:${TINT_BUILD_GLSL_WRITER}>)
target_compile_definitions(${TARGET} PUBLIC -DTINT_BUILD_HLSL_WRITER=$<BOOL:${TINT_BUILD_HLSL_WRITER}>)
+ target_compile_definitions(${TARGET} PUBLIC -DTINT_BUILD_IR_BINARY=$<BOOL:${TINT_BUILD_IR_BINARY}>)
target_compile_definitions(${TARGET} PUBLIC -DTINT_BUILD_IS_LINUX=$<BOOL:${TINT_BUILD_IS_LINUX}>)
target_compile_definitions(${TARGET} PUBLIC -DTINT_BUILD_IS_MAC=$<BOOL:${TINT_BUILD_IS_MAC}>)
target_compile_definitions(${TARGET} PUBLIC -DTINT_BUILD_IS_WIN=$<BOOL:${TINT_BUILD_IS_WIN}>)
@@ -60,7 +67,6 @@
target_compile_definitions(${TARGET} PUBLIC -DTINT_BUILD_WGSL_READER=$<BOOL:${TINT_BUILD_WGSL_READER}>)
target_compile_definitions(${TARGET} PUBLIC -DTINT_BUILD_WGSL_WRITER=$<BOOL:${TINT_BUILD_WGSL_WRITER}>)
-
if(TINT_BUILD_FUZZERS)
target_compile_options(${TARGET} PRIVATE "-fsanitize=fuzzer")
endif()
diff --git a/src/tint/cmd/test/BUILD.bazel b/src/tint/cmd/test/BUILD.bazel
index 080bcb9..e0e9b73 100644
--- a/src/tint/cmd/test/BUILD.bazel
+++ b/src/tint/cmd/test/BUILD.bazel
@@ -103,6 +103,11 @@
],
"//conditions:default": [],
}) + select({
+ ":tint_build_ir_binary": [
+ "//src/tint/lang/core/ir/binary:test",
+ ],
+ "//conditions:default": [],
+ }) + select({
":tint_build_msl_writer": [
"//src/tint/lang/msl/writer/ast_printer:test",
"//src/tint/lang/msl/writer/common:test",
@@ -176,6 +181,11 @@
)
alias(
+ name = "tint_build_ir_binary",
+ actual = "//src/tint:tint_build_ir_binary_true",
+)
+
+alias(
name = "tint_build_msl_writer",
actual = "//src/tint:tint_build_msl_writer_true",
)
diff --git a/src/tint/cmd/test/BUILD.cmake b/src/tint/cmd/test/BUILD.cmake
index 3709145..909b3e8 100644
--- a/src/tint/cmd/test/BUILD.cmake
+++ b/src/tint/cmd/test/BUILD.cmake
@@ -112,6 +112,12 @@
)
endif(TINT_BUILD_HLSL_WRITER AND TINT_BUILD_WGSL_READER AND TINT_BUILD_WGSL_WRITER)
+if(TINT_BUILD_IR_BINARY)
+ tint_target_add_dependencies(tint_cmd_test_test_cmd test_cmd
+ tint_lang_core_ir_binary_test
+ )
+endif(TINT_BUILD_IR_BINARY)
+
if(TINT_BUILD_MSL_WRITER)
tint_target_add_dependencies(tint_cmd_test_test_cmd test_cmd
tint_lang_msl_writer_ast_printer_test
diff --git a/src/tint/cmd/test/BUILD.gn b/src/tint/cmd/test/BUILD.gn
index e307f93..622cf0f 100644
--- a/src/tint/cmd/test/BUILD.gn
+++ b/src/tint/cmd/test/BUILD.gn
@@ -109,6 +109,10 @@
deps += [ "${tint_src_dir}/lang/hlsl/writer/ast_raise:unittests" ]
}
+ if (tint_build_ir_binary) {
+ deps += [ "${tint_src_dir}/lang/core/ir/binary:unittests" ]
+ }
+
if (tint_build_msl_writer) {
deps += [
"${tint_src_dir}/lang/msl/writer/ast_printer:unittests",
diff --git a/src/tint/lang/core/ir/BUILD.cmake b/src/tint/lang/core/ir/BUILD.cmake
index 19c6a8a..c901636 100644
--- a/src/tint/lang/core/ir/BUILD.cmake
+++ b/src/tint/lang/core/ir/BUILD.cmake
@@ -34,6 +34,7 @@
# Do not modify this file directly
################################################################################
+include(lang/core/ir/binary/BUILD.cmake)
include(lang/core/ir/transform/BUILD.cmake)
################################################################################
diff --git a/src/tint/lang/core/ir/binary/BUILD.bazel b/src/tint/lang/core/ir/binary/BUILD.bazel
new file mode 100644
index 0000000..e781ef7
--- /dev/null
+++ b/src/tint/lang/core/ir/binary/BUILD.bazel
@@ -0,0 +1,120 @@
+# 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.
+
+################################################################################
+# File generated by 'tools/src/cmd/gen' using the template:
+# tools/src/cmd/gen/build/BUILD.bazel.tmpl
+#
+# To regenerate run: './tools/run gen'
+#
+# Do not modify this file directly
+################################################################################
+
+load("//src/tint:flags.bzl", "COPTS")
+load("@bazel_skylib//lib:selects.bzl", "selects")
+cc_library(
+ name = "binary",
+ srcs = [
+ "decode.cc",
+ "encode.cc",
+ ],
+ hdrs = [
+ "decode.h",
+ "encode.h",
+ ],
+ deps = [
+ "//src/tint/api/common",
+ "//src/tint/lang/core",
+ "//src/tint/lang/core/constant",
+ "//src/tint/lang/core/intrinsic",
+ "//src/tint/lang/core/ir",
+ "//src/tint/lang/core/type",
+ "//src/tint/utils/containers",
+ "//src/tint/utils/diagnostic",
+ "//src/tint/utils/ice",
+ "//src/tint/utils/id",
+ "//src/tint/utils/macros",
+ "//src/tint/utils/math",
+ "//src/tint/utils/memory",
+ "//src/tint/utils/reflection",
+ "//src/tint/utils/result",
+ "//src/tint/utils/rtti",
+ "//src/tint/utils/symbol",
+ "//src/tint/utils/text",
+ "//src/tint/utils/traits",
+ ] + select({
+ ":tint_build_ir_binary": [
+ "",
+ ],
+ "//conditions:default": [],
+ }),
+ copts = COPTS,
+ visibility = ["//visibility:public"],
+)
+cc_library(
+ name = "test",
+ alwayslink = True,
+ srcs = [
+ "roundtrip_test.cc",
+ ],
+ deps = [
+ "//src/tint/api/common",
+ "//src/tint/lang/core",
+ "//src/tint/lang/core/constant",
+ "//src/tint/lang/core/intrinsic",
+ "//src/tint/lang/core/ir",
+ "//src/tint/lang/core/ir:test",
+ "//src/tint/lang/core/type",
+ "//src/tint/utils/containers",
+ "//src/tint/utils/diagnostic",
+ "//src/tint/utils/ice",
+ "//src/tint/utils/id",
+ "//src/tint/utils/macros",
+ "//src/tint/utils/math",
+ "//src/tint/utils/memory",
+ "//src/tint/utils/reflection",
+ "//src/tint/utils/result",
+ "//src/tint/utils/rtti",
+ "//src/tint/utils/symbol",
+ "//src/tint/utils/text",
+ "//src/tint/utils/traits",
+ "@gtest",
+ ] + select({
+ ":tint_build_ir_binary": [
+ "//src/tint/lang/core/ir/binary",
+ ],
+ "//conditions:default": [],
+ }),
+ copts = COPTS,
+ visibility = ["//visibility:public"],
+)
+
+alias(
+ name = "tint_build_ir_binary",
+ actual = "//src/tint:tint_build_ir_binary_true",
+)
+
diff --git a/src/tint/lang/core/ir/binary/BUILD.cfg b/src/tint/lang/core/ir/binary/BUILD.cfg
new file mode 100644
index 0000000..deb7ad2
--- /dev/null
+++ b/src/tint/lang/core/ir/binary/BUILD.cfg
@@ -0,0 +1,3 @@
+{
+ "condition": "tint_build_ir_binary"
+}
diff --git a/src/tint/lang/core/ir/binary/BUILD.cmake b/src/tint/lang/core/ir/binary/BUILD.cmake
new file mode 100644
index 0000000..61650da
--- /dev/null
+++ b/src/tint/lang/core/ir/binary/BUILD.cmake
@@ -0,0 +1,133 @@
+# 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.
+
+################################################################################
+# File generated by 'tools/src/cmd/gen' using the template:
+# tools/src/cmd/gen/build/BUILD.cmake.tmpl
+#
+# To regenerate run: './tools/run gen'
+#
+# Do not modify this file directly
+################################################################################
+
+if(TINT_BUILD_IR_BINARY)
+################################################################################
+# Target: tint_lang_core_ir_binary
+# Kind: lib
+# Condition: TINT_BUILD_IR_BINARY
+################################################################################
+tint_add_target(tint_lang_core_ir_binary lib
+ lang/core/ir/binary/decode.cc
+ lang/core/ir/binary/decode.h
+ lang/core/ir/binary/encode.cc
+ lang/core/ir/binary/encode.h
+)
+
+tint_target_add_dependencies(tint_lang_core_ir_binary lib
+ tint_api_common
+ tint_lang_core
+ tint_lang_core_constant
+ tint_lang_core_intrinsic
+ tint_lang_core_ir
+ tint_lang_core_type
+ tint_utils_containers
+ tint_utils_diagnostic
+ tint_utils_ice
+ tint_utils_id
+ tint_utils_macros
+ tint_utils_math
+ tint_utils_memory
+ tint_utils_reflection
+ tint_utils_result
+ tint_utils_rtti
+ tint_utils_symbol
+ tint_utils_text
+ tint_utils_traits
+)
+
+if(TINT_BUILD_IR_BINARY)
+ tint_target_add_dependencies(tint_lang_core_ir_binary lib
+ tint_lang_core_ir_binary_proto
+ )
+endif(TINT_BUILD_IR_BINARY)
+
+endif(TINT_BUILD_IR_BINARY)
+if(TINT_BUILD_IR_BINARY)
+################################################################################
+# Target: tint_lang_core_ir_binary_proto
+# Kind: proto
+# Condition: TINT_BUILD_IR_BINARY
+################################################################################
+tint_add_target(tint_lang_core_ir_binary_proto proto
+ lang/core/ir/binary/ir.proto
+)
+
+endif(TINT_BUILD_IR_BINARY)
+if(TINT_BUILD_IR_BINARY)
+################################################################################
+# Target: tint_lang_core_ir_binary_test
+# Kind: test
+# Condition: TINT_BUILD_IR_BINARY
+################################################################################
+tint_add_target(tint_lang_core_ir_binary_test test
+ lang/core/ir/binary/roundtrip_test.cc
+)
+
+tint_target_add_dependencies(tint_lang_core_ir_binary_test test
+ tint_api_common
+ tint_lang_core
+ tint_lang_core_constant
+ tint_lang_core_intrinsic
+ tint_lang_core_ir
+ tint_lang_core_ir_test
+ tint_lang_core_type
+ tint_utils_containers
+ tint_utils_diagnostic
+ tint_utils_ice
+ tint_utils_id
+ tint_utils_macros
+ tint_utils_math
+ tint_utils_memory
+ tint_utils_reflection
+ tint_utils_result
+ tint_utils_rtti
+ tint_utils_symbol
+ tint_utils_text
+ tint_utils_traits
+)
+
+tint_target_add_external_dependencies(tint_lang_core_ir_binary_test test
+ "gtest"
+)
+
+if(TINT_BUILD_IR_BINARY)
+ tint_target_add_dependencies(tint_lang_core_ir_binary_test test
+ tint_lang_core_ir_binary
+ )
+endif(TINT_BUILD_IR_BINARY)
+
+endif(TINT_BUILD_IR_BINARY)
\ No newline at end of file
diff --git a/src/tint/lang/core/ir/binary/BUILD.gn b/src/tint/lang/core/ir/binary/BUILD.gn
new file mode 100644
index 0000000..d0333c8
--- /dev/null
+++ b/src/tint/lang/core/ir/binary/BUILD.gn
@@ -0,0 +1,118 @@
+# 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.
+
+################################################################################
+# File generated by 'tools/src/cmd/gen' using the template:
+# tools/src/cmd/gen/build/BUILD.gn.tmpl
+#
+# To regenerate run: './tools/run gen'
+#
+# Do not modify this file directly
+################################################################################
+
+import("../../../../../../scripts/tint_overrides_with_defaults.gni")
+
+import("${tint_src_dir}/tint.gni")
+
+if (tint_build_unittests || tint_build_benchmarks) {
+ import("//testing/test.gni")
+}
+if (tint_build_ir_binary) {
+ libtint_source_set("binary") {
+ sources = [
+ "decode.cc",
+ "decode.h",
+ "encode.cc",
+ "encode.h",
+ ]
+ deps = [
+ "${tint_src_dir}/api/common",
+ "${tint_src_dir}/lang/core",
+ "${tint_src_dir}/lang/core/constant",
+ "${tint_src_dir}/lang/core/intrinsic",
+ "${tint_src_dir}/lang/core/ir",
+ "${tint_src_dir}/lang/core/type",
+ "${tint_src_dir}/utils/containers",
+ "${tint_src_dir}/utils/diagnostic",
+ "${tint_src_dir}/utils/ice",
+ "${tint_src_dir}/utils/id",
+ "${tint_src_dir}/utils/macros",
+ "${tint_src_dir}/utils/math",
+ "${tint_src_dir}/utils/memory",
+ "${tint_src_dir}/utils/reflection",
+ "${tint_src_dir}/utils/result",
+ "${tint_src_dir}/utils/rtti",
+ "${tint_src_dir}/utils/symbol",
+ "${tint_src_dir}/utils/text",
+ "${tint_src_dir}/utils/traits",
+ ]
+
+ if (tint_build_ir_binary) {
+ deps += [ "${tint_src_dir}/lang/core/ir/binary:proto" ]
+ }
+ }
+}
+if (tint_build_ir_binary) {
+ tint_proto_library("proto") {
+ sources = [ "ir.proto" ]
+ deps = []
+ }
+}
+if (tint_build_unittests) {
+ if (tint_build_ir_binary) {
+ tint_unittests_source_set("unittests") {
+ sources = [ "roundtrip_test.cc" ]
+ deps = [
+ "${tint_src_dir}:gmock_and_gtest",
+ "${tint_src_dir}/api/common",
+ "${tint_src_dir}/lang/core",
+ "${tint_src_dir}/lang/core/constant",
+ "${tint_src_dir}/lang/core/intrinsic",
+ "${tint_src_dir}/lang/core/ir",
+ "${tint_src_dir}/lang/core/ir:unittests",
+ "${tint_src_dir}/lang/core/type",
+ "${tint_src_dir}/utils/containers",
+ "${tint_src_dir}/utils/diagnostic",
+ "${tint_src_dir}/utils/ice",
+ "${tint_src_dir}/utils/id",
+ "${tint_src_dir}/utils/macros",
+ "${tint_src_dir}/utils/math",
+ "${tint_src_dir}/utils/memory",
+ "${tint_src_dir}/utils/reflection",
+ "${tint_src_dir}/utils/result",
+ "${tint_src_dir}/utils/rtti",
+ "${tint_src_dir}/utils/symbol",
+ "${tint_src_dir}/utils/text",
+ "${tint_src_dir}/utils/traits",
+ ]
+
+ if (tint_build_ir_binary) {
+ deps += [ "${tint_src_dir}/lang/core/ir/binary" ]
+ }
+ }
+ }
+}
diff --git a/src/tint/lang/core/ir/binary/decode.cc b/src/tint/lang/core/ir/binary/decode.cc
new file mode 100644
index 0000000..cf9576f
--- /dev/null
+++ b/src/tint/lang/core/ir/binary/decode.cc
@@ -0,0 +1,235 @@
+// 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/core/ir/binary/decode.h"
+
+#include <utility>
+
+#include "src/tint/lang/core/ir/builder.h"
+#include "src/tint/lang/core/ir/module.h"
+#include "src/tint/utils/macros/compiler.h"
+
+TINT_BEGIN_DISABLE_PROTOBUF_WARNINGS();
+#include "src/tint/lang/core/ir/binary/ir.pb.h"
+TINT_END_DISABLE_PROTOBUF_WARNINGS();
+
+using namespace tint::core::fluent_types; // NOLINT
+
+namespace tint::core::ir::binary {
+namespace {
+
+struct Decoder {
+ pb::Module& mod_in_;
+ Module& mod_out_;
+ Hashmap<uint32_t, ir::Block*, 32> blocks_{};
+ Hashmap<uint32_t, const type::Type*, 32> types_{};
+ Hashmap<uint32_t, ir::Value*, 32> values_{};
+ Builder b{mod_out_};
+
+ void Decode() {
+ // Build all the functions in a separate pass, before we decode them.
+ // This allows for forward references, while preserving function declaration order.
+ for (size_t i = 0, n = static_cast<size_t>(mod_in_.functions().size()); i < n; i++) {
+ b.ir.functions.Push(b.ir.values.Create<ir::Function>());
+ }
+ for (size_t i = 0, n = static_cast<size_t>(mod_in_.functions().size()); i < n; i++) {
+ Function(b.ir.functions[i], mod_in_.functions()[static_cast<int>(i)]);
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ // Functions
+ ////////////////////////////////////////////////////////////////////////////
+ void Function(ir::Function* fn_out, const pb::Function& fn_in) {
+ if (!fn_in.name().empty()) {
+ b.ir.SetName(fn_out, fn_in.name());
+ }
+ fn_out->SetReturnType(Type(fn_in.return_type()));
+ if (fn_in.has_pipeline_stage()) {
+ fn_out->SetStage(PipelineStage(fn_in.pipeline_stage()));
+ }
+ if (fn_in.has_workgroup_size()) {
+ auto& wg_size_in = fn_in.workgroup_size();
+ fn_out->SetWorkgroupSize(wg_size_in.x(), wg_size_in.y(), wg_size_in.z());
+ }
+
+ Vector<FunctionParam*, 8> params_out;
+ for (auto param_in : fn_in.parameters()) {
+ params_out.Push(ValueAs<ir::FunctionParam>(param_in));
+ }
+ fn_out->SetParams(std::move(params_out));
+ fn_out->SetBlock(Block(fn_in.block()));
+ }
+
+ Function::PipelineStage PipelineStage(pb::PipelineStage stage) {
+ switch (stage) {
+ case pb::PipelineStage::Compute:
+ return Function::PipelineStage::kCompute;
+ case pb::PipelineStage::Fragment:
+ return Function::PipelineStage::kFragment;
+ case pb::PipelineStage::Vertex:
+ return Function::PipelineStage::kVertex;
+ default:
+ TINT_ICE() << "unhandled PipelineStage: " << stage;
+ return Function::PipelineStage::kCompute;
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ // Blocks
+ ////////////////////////////////////////////////////////////////////////////
+ ir::Block* Block(uint32_t id) {
+ if (id == 0) {
+ return nullptr;
+ }
+ return blocks_.GetOrCreate(id, [&] {
+ auto& block_in = mod_in_.blocks().at(static_cast<int>(id) - 1);
+ auto* block_out = b.Block();
+ for (auto& inst : block_in.instructions()) {
+ block_out->Append(Instruction(inst));
+ }
+ return block_out;
+ });
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ // Instructions
+ ////////////////////////////////////////////////////////////////////////////
+ ir::Instruction* Instruction(const pb::Instruction& inst_in) {
+ ir::Instruction* inst_out = nullptr;
+ switch (inst_in.kind()) {
+ case pb::InstructionKind::Return:
+ inst_out = b.ir.instructions.Create<ir::Return>();
+ break;
+ default:
+ TINT_UNIMPLEMENTED() << inst_in.kind();
+ break;
+ }
+ TINT_ASSERT_OR_RETURN_VALUE(inst_out, nullptr);
+
+ return inst_out;
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ // Types
+ ////////////////////////////////////////////////////////////////////////////
+ const type::Type* Type(uint32_t id) {
+ if (id == 0) {
+ return nullptr;
+ }
+ return types_.GetOrCreate(id, [&]() -> const type::Type* {
+ auto& ty_in = mod_in_.types().at(static_cast<int>(id) - 1);
+ switch (ty_in.kind_case()) {
+ case pb::TypeDecl::KindCase::kBasic:
+ switch (ty_in.basic()) {
+ case pb::BasicType::void_:
+ return mod_out_.Types().Get<void>();
+ case pb::BasicType::bool_:
+ return mod_out_.Types().Get<bool>();
+ case pb::BasicType::i32:
+ return mod_out_.Types().Get<i32>();
+ case pb::BasicType::u32:
+ return mod_out_.Types().Get<u32>();
+ case pb::BasicType::f32:
+ return mod_out_.Types().Get<f32>();
+ default:
+ TINT_ICE() << "invalid BasicType: " << ty_in.basic();
+ return nullptr;
+ }
+ case pb::TypeDecl::KindCase::kVector:
+ case pb::TypeDecl::KindCase::kMatrix:
+ case pb::TypeDecl::KindCase::kArray:
+ case pb::TypeDecl::KindCase::kAtomic:
+ TINT_UNIMPLEMENTED() << ty_in.kind_case();
+ return nullptr;
+
+ case pb::TypeDecl::KindCase::KIND_NOT_SET:
+ break;
+ }
+ TINT_ICE() << "invalid TypeDecl.kind";
+ return nullptr;
+ });
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ // Values
+ ////////////////////////////////////////////////////////////////////////////
+ ir::Value* Value(uint32_t id) {
+ if (id == 0) {
+ return nullptr;
+ }
+ return values_.GetOrCreate(id, [&]() -> ir::Value* {
+ auto& val_in = mod_in_.values().at(static_cast<int>(id) - 1);
+ auto* type = Type(val_in.type());
+ ir::Value* val_out = nullptr;
+ switch (val_in.kind()) {
+ case pb::ValueKind::instruction_result:
+ val_out = b.InstructionResult(type);
+ break;
+ case pb::ValueKind::function_parameter:
+ val_out = b.FunctionParam(type);
+ break;
+ default:
+ TINT_ICE() << "invalid TypeDecl.kind";
+ return nullptr;
+ }
+ if (val_in.has_name()) {
+ mod_out_.SetName(val_out, val_in.name());
+ }
+ return val_out;
+ });
+ }
+
+ template <typename T>
+ T* ValueAs(uint32_t id) {
+ auto* value = Value(id);
+ if (auto cast = value->As<T>(); TINT_LIKELY(cast)) {
+ return cast;
+ }
+ TINT_ICE() << "Value " << id << " is " << value->TypeInfo().name << " expected "
+ << TypeInfo::Of<T>().name;
+ return nullptr;
+ }
+};
+
+} // namespace
+
+Result<Module> Decode(Slice<const std::byte> encoded) {
+ GOOGLE_PROTOBUF_VERIFY_VERSION;
+
+ pb::Module mod_in;
+ if (!mod_in.ParseFromArray(encoded.data, static_cast<int>(encoded.len))) {
+ return Failure{"failed to deserialize protobuf"};
+ }
+
+ Module mod_out;
+ Decoder{mod_in, mod_out}.Decode();
+
+ return mod_out;
+}
+
+} // namespace tint::core::ir::binary
diff --git a/src/tint/lang/core/ir/binary/decode.h b/src/tint/lang/core/ir/binary/decode.h
new file mode 100644
index 0000000..d4810b3
--- /dev/null
+++ b/src/tint/lang/core/ir/binary/decode.h
@@ -0,0 +1,44 @@
+// 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.
+
+#ifndef SRC_TINT_LANG_CORE_IR_BINARY_DECODE_H_
+#define SRC_TINT_LANG_CORE_IR_BINARY_DECODE_H_
+
+#include "src/tint/utils/result/result.h"
+
+// Forward declarartion
+namespace tint::core::ir {
+class Module;
+} // namespace tint::core::ir
+
+namespace tint::core::ir::binary {
+
+Result<Module> Decode(Slice<const std::byte> encoded);
+
+} // namespace tint::core::ir::binary
+
+#endif // SRC_TINT_LANG_CORE_IR_BINARY_DECODE_H_
diff --git a/src/tint/lang/core/ir/binary/encode.cc b/src/tint/lang/core/ir/binary/encode.cc
new file mode 100644
index 0000000..340ef66
--- /dev/null
+++ b/src/tint/lang/core/ir/binary/encode.cc
@@ -0,0 +1,192 @@
+// 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/core/ir/binary/encode.h"
+
+#include "src/tint/lang/core/ir/function_param.h"
+#include "src/tint/lang/core/ir/module.h"
+#include "src/tint/lang/core/ir/return.h"
+#include "src/tint/lang/core/type/bool.h"
+#include "src/tint/lang/core/type/f32.h"
+#include "src/tint/lang/core/type/i32.h"
+#include "src/tint/lang/core/type/u32.h"
+#include "src/tint/lang/core/type/void.h"
+#include "src/tint/utils/macros/compiler.h"
+#include "src/tint/utils/rtti/switch.h"
+
+TINT_BEGIN_DISABLE_PROTOBUF_WARNINGS();
+#include "src/tint/lang/core/ir/binary/ir.pb.h"
+TINT_END_DISABLE_PROTOBUF_WARNINGS();
+
+namespace tint::core::ir::binary {
+namespace {
+struct Encoder {
+ const Module& mod_in_;
+ pb::Module& mod_out_;
+ Hashmap<const core::ir::Function*, uint32_t, 32> functions_{};
+ Hashmap<const core::ir::Block*, uint32_t, 32> blocks_{};
+ Hashmap<const core::type::Type*, uint32_t, 32> types_{};
+ Hashmap<const core::ir::Value*, uint32_t, 32> values_{};
+
+ void Encode() {
+ Vector<pb::Function*, 8> fns_out;
+ for (auto& fn_in : mod_in_.functions) {
+ uint32_t id = static_cast<uint32_t>(fns_out.Length() + 1);
+ fns_out.Push(mod_out_.add_functions());
+ functions_.Add(fn_in, id);
+ }
+ for (size_t i = 0, n = mod_in_.functions.Length(); i < n; i++) {
+ Function(fns_out[i], mod_in_.functions[i]);
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ // Functions
+ ////////////////////////////////////////////////////////////////////////////
+ void Function(pb::Function* fn_out, const ir::Function* fn_in) {
+ if (auto name = mod_in_.NameOf(fn_in)) {
+ fn_out->set_name(name.Name());
+ }
+ fn_out->set_return_type(Type(fn_in->ReturnType()));
+ if (fn_in->Stage() != Function::PipelineStage::kUndefined) {
+ fn_out->set_pipeline_stage(PipelineStage(fn_in->Stage()));
+ }
+ if (auto wg_size_in = fn_in->WorkgroupSize()) {
+ auto& wg_size_out = *fn_out->mutable_workgroup_size();
+ wg_size_out.set_x((*wg_size_in)[0]);
+ wg_size_out.set_y((*wg_size_in)[1]);
+ wg_size_out.set_z((*wg_size_in)[2]);
+ }
+ for (auto* param_in : fn_in->Params()) {
+ fn_out->add_parameters(FunctionParam(param_in));
+ }
+ fn_out->set_block(Block(fn_in->Block()));
+ }
+
+ pb::PipelineStage PipelineStage(Function::PipelineStage stage) {
+ switch (stage) {
+ case Function::PipelineStage::kCompute:
+ return pb::PipelineStage::Compute;
+ case Function::PipelineStage::kFragment:
+ return pb::PipelineStage::Fragment;
+ case Function::PipelineStage::kVertex:
+ return pb::PipelineStage::Vertex;
+ default:
+ TINT_ICE() << "unhandled PipelineStage: " << stage;
+ return pb::PipelineStage::Compute;
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ // Blocks
+ ////////////////////////////////////////////////////////////////////////////
+ uint32_t Block(const ir::Block* block_in) {
+ if (block_in == nullptr) {
+ return 0;
+ }
+ return blocks_.GetOrCreate(block_in, [&]() -> uint32_t {
+ auto& block_out = *mod_out_.add_blocks();
+ for (auto* inst : *block_in) {
+ Instruction(block_out.add_instructions(), inst);
+ }
+ return static_cast<uint32_t>(blocks_.Count());
+ });
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ // Instructions
+ ////////////////////////////////////////////////////////////////////////////
+ void Instruction(pb::Instruction* inst_out, const ir::Instruction* inst_in) {
+ auto kind = Switch(
+ inst_in, //
+ [&](const ir::Return*) { return pb::InstructionKind::Return; }, //
+ TINT_ICE_ON_NO_MATCH);
+ inst_out->set_kind(kind);
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ // Types
+ ////////////////////////////////////////////////////////////////////////////
+ uint32_t Type(const core::type::Type* type) {
+ if (type == nullptr) {
+ return 0;
+ }
+ return types_.GetOrCreate(type, [&]() -> uint32_t {
+ auto basic = tint::Switch<pb::BasicType>(
+ type, //
+ [&](const core::type::Void*) { return pb::BasicType::void_; },
+ [&](const core::type::Bool*) { return pb::BasicType::bool_; },
+ [&](const core::type::I32*) { return pb::BasicType::i32; },
+ [&](const core::type::U32*) { return pb::BasicType::u32; },
+ [&](const core::type::F32*) { return pb::BasicType::f32; }, //
+ TINT_ICE_ON_NO_MATCH);
+ mod_out_.add_types()->set_basic(basic);
+ return static_cast<uint32_t>(types_.Count());
+ });
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ // Values
+ ////////////////////////////////////////////////////////////////////////////
+ // uint32_t Value(const ir::Value* value) {
+ // return Switch(value, //
+ // [&](const ir::FunctionParam* p) { return FunctionParam(p); });
+ // }
+
+ uint32_t FunctionParam(const ir::FunctionParam* param) {
+ return values_.GetOrCreate(param, [&] {
+ auto& val_out = *mod_out_.add_values();
+ val_out.set_kind(pb::ValueKind::function_parameter);
+ val_out.set_type(Type(param->Type()));
+ if (auto name = mod_in_.NameOf(param); name.IsValid()) {
+ val_out.set_name(name.Name());
+ }
+ return static_cast<uint32_t>(values_.Count());
+ });
+ }
+};
+
+} // namespace
+
+Result<Vector<std::byte, 0>> Encode(const Module& mod_in) {
+ GOOGLE_PROTOBUF_VERIFY_VERSION;
+
+ pb::Module mod_out;
+ Encoder{mod_in, mod_out}.Encode();
+
+ Vector<std::byte, 0> buffer;
+ size_t len = mod_out.ByteSizeLong();
+ buffer.Resize(len);
+ if (len > 0) {
+ if (!mod_out.SerializeToArray(&buffer[0], static_cast<int>(len))) {
+ return Failure{"failed to serialize protobuf"};
+ }
+ }
+ return buffer;
+}
+
+} // namespace tint::core::ir::binary
diff --git a/src/tint/lang/core/ir/binary/encode.h b/src/tint/lang/core/ir/binary/encode.h
new file mode 100644
index 0000000..3cdd520
--- /dev/null
+++ b/src/tint/lang/core/ir/binary/encode.h
@@ -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.
+
+#ifndef SRC_TINT_LANG_CORE_IR_BINARY_ENCODE_H_
+#define SRC_TINT_LANG_CORE_IR_BINARY_ENCODE_H_
+
+#include "src/tint/utils/containers/vector.h"
+#include "src/tint/utils/result/result.h"
+
+// Forward declarartion
+namespace tint::core::ir {
+class Module;
+} // namespace tint::core::ir
+
+namespace tint::core::ir::binary {
+
+Result<Vector<std::byte, 0>> Encode(const Module& module);
+
+} // namespace tint::core::ir::binary
+
+#endif // SRC_TINT_LANG_CORE_IR_BINARY_ENCODE_H_
diff --git a/src/tint/lang/core/ir/binary/ir.proto b/src/tint/lang/core/ir/binary/ir.proto
new file mode 100644
index 0000000..c85bb8e
--- /dev/null
+++ b/src/tint/lang/core/ir/binary/ir.proto
@@ -0,0 +1,128 @@
+// 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.
+
+syntax = "proto3";
+
+package tint.core.ir.binary.pb;
+
+message Module {
+ repeated TypeDecl types = 1;
+ repeated Value values = 2;
+ Block root_block = 3;
+ repeated Function functions = 4;
+ repeated Block blocks = 5;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Types
+////////////////////////////////////////////////////////////////////////////////
+message TypeDecl {
+ oneof kind {
+ BasicType basic = 1;
+ VectorType vector = 2;
+ MatrixType matrix = 3;
+ ArrayType array = 4;
+ uint32 atomic = 5; // Module.types
+ // TODO: textures, samplers
+ }
+}
+
+// Non-compound types
+enum BasicType {
+ void = 0;
+ bool = 1;
+ i32 = 2;
+ u32 = 3;
+ f32 = 4;
+ f16 = 5;
+}
+
+message VectorType {
+ uint32 width = 1;
+ uint32 element_type = 2; // Module.types
+}
+
+message MatrixType {
+ uint32 num_columns = 1;
+ uint32 num_width = 2;
+ uint32 element_type = 3; // Module.types
+}
+
+message ArrayType {
+ uint32 count = 1;
+ uint32 element_type = 2; // Module.types
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Values
+////////////////////////////////////////////////////////////////////////////////
+message Value {
+ ValueKind kind = 1;
+ uint32 type = 2; // Module.types
+ optional string name = 3;
+}
+
+enum ValueKind {
+ instruction_result = 0;
+ function_parameter = 1;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Functions
+////////////////////////////////////////////////////////////////////////////////
+message Function {
+ optional string name = 1;
+ uint32 return_type = 2;
+ optional PipelineStage pipeline_stage = 3;
+ optional WorkgroupSize workgroup_size = 4;
+ repeated uint32 parameters = 5; // Module.values
+ uint32 block = 6; // Module.blocks
+}
+
+enum PipelineStage {
+ Compute = 0;
+ Fragment = 1;
+ Vertex = 2;
+}
+
+message WorkgroupSize {
+ uint32 x = 1;
+ uint32 y = 2;
+ uint32 z = 3;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Blocks
+////////////////////////////////////////////////////////////////////////////////
+message Block {
+ repeated uint32 parameters = 1; // Module.values
+ repeated Instruction instructions = 2;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Instructions
+////////////////////////////////////////////////////////////////////////////////
+message Instruction {
+ InstructionKind kind = 1;
+ repeated uint32 operands = 2;
+ repeated uint32 results = 3;
+}
+
+enum InstructionKind {
+ Return = 0;
+ UnaryOp = 1;
+ BinaryOp = 2;
+ Builtin = 3;
+ Constructor = 4;
+}
diff --git a/src/tint/lang/core/ir/binary/roundtrip_test.cc b/src/tint/lang/core/ir/binary/roundtrip_test.cc
new file mode 100644
index 0000000..90a5309
--- /dev/null
+++ b/src/tint/lang/core/ir/binary/roundtrip_test.cc
@@ -0,0 +1,114 @@
+// 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/core/ir/ir_helper_test.h"
+
+#include "src/tint/lang/core/ir/binary/decode.h"
+#include "src/tint/lang/core/ir/binary/encode.h"
+#include "src/tint/lang/core/ir/disassembler.h"
+
+namespace tint::core::ir::binary {
+namespace {
+
+using namespace tint::core::number_suffixes; // NOLINT
+
+template <typename T = testing::Test>
+class IRBinaryRoundtripTestBase : public IRTestParamHelper<T> {
+ public:
+ std::pair<std::string, std::string> Roundtrip() {
+ auto pre = Disassemble(this->mod);
+ auto encoded = Encode(this->mod);
+ if (!encoded) {
+ return {pre, encoded.Failure().reason.str()};
+ }
+ auto decoded = Decode(encoded->Slice());
+ if (!decoded) {
+ return {pre, decoded.Failure().reason.str()};
+ }
+ auto post = Disassemble(decoded.Get());
+ return {pre, post};
+ }
+};
+
+#define RUN_TEST() \
+ { \
+ auto [pre, post] = Roundtrip(); \
+ EXPECT_EQ(pre, post); \
+ } \
+ TINT_REQUIRE_SEMICOLON
+
+using IRBinaryRoundtripTest = IRBinaryRoundtripTestBase<>;
+TEST_F(IRBinaryRoundtripTest, EmptyModule) {
+ RUN_TEST();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Functions
+////////////////////////////////////////////////////////////////////////////////
+TEST_F(IRBinaryRoundtripTest, Fn_i32_ret) {
+ b.Function("Function", ty.i32());
+ RUN_TEST();
+}
+
+using IRBinaryRoundtripTest_FnPipelineStage = IRBinaryRoundtripTestBase<Function::PipelineStage>;
+TEST_P(IRBinaryRoundtripTest_FnPipelineStage, Test) {
+ b.Function("Function", ty.i32(), GetParam());
+ RUN_TEST();
+}
+INSTANTIATE_TEST_SUITE_P(,
+ IRBinaryRoundtripTest_FnPipelineStage,
+ testing::Values(Function::PipelineStage::kCompute,
+ Function::PipelineStage::kFragment,
+ Function::PipelineStage::kVertex));
+
+TEST_F(IRBinaryRoundtripTest, Fn_WorkgroupSize) {
+ b.Function("Function", ty.i32(), Function::PipelineStage::kCompute,
+ std::array<uint32_t, 3>{1, 2, 3});
+ RUN_TEST();
+}
+
+TEST_F(IRBinaryRoundtripTest, Fn_Parameters) {
+ auto* fn = b.Function("Function", ty.void_());
+ auto* p0 = b.FunctionParam(ty.i32());
+ auto* p1 = b.FunctionParam(ty.u32());
+ auto* p2 = b.FunctionParam(ty.f32());
+ b.ir.SetName(p1, "p1");
+ fn->SetParams({p0, p1, p2});
+ RUN_TEST();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Instructions
+////////////////////////////////////////////////////////////////////////////////
+TEST_F(IRBinaryRoundtripTest, Return) {
+ auto* fn = b.Function("Function", ty.void_());
+ b.Append(fn->Block(), [&] { b.Return(fn); });
+ RUN_TEST();
+}
+
+} // namespace
+} // namespace tint::core::ir::binary
diff --git a/src/tint/lang/core/ir/function.cc b/src/tint/lang/core/ir/function.cc
index d3edbf1..8c095e0 100644
--- a/src/tint/lang/core/ir/function.cc
+++ b/src/tint/lang/core/ir/function.cc
@@ -36,6 +36,8 @@
namespace tint::core::ir {
+Function::Function() = default;
+
Function::Function(const core::type::Type* rt,
PipelineStage stage,
std::optional<std::array<uint32_t, 3>> wg_size)
diff --git a/src/tint/lang/core/ir/function.h b/src/tint/lang/core/ir/function.h
index 1937673..0193884 100644
--- a/src/tint/lang/core/ir/function.h
+++ b/src/tint/lang/core/ir/function.h
@@ -73,6 +73,9 @@
};
/// Constructor
+ Function();
+
+ /// Constructor
/// @param rt the function return type
/// @param stage the function stage
/// @param wg_size the workgroup_size
@@ -103,6 +106,9 @@
/// @returns the workgroup size information
std::optional<std::array<uint32_t, 3>> WorkgroupSize() const { return workgroup_size_; }
+ /// @param type the return type for the function
+ void SetReturnType(const core::type::Type* type) { return_.type = type; }
+
/// @returns the return type for the function
const core::type::Type* ReturnType() const { return return_.type; }
@@ -165,7 +171,7 @@
void Destroy() override;
private:
- PipelineStage pipeline_stage_;
+ PipelineStage pipeline_stage_ = PipelineStage::kUndefined;
std::optional<std::array<uint32_t, 3>> workgroup_size_;
struct {
diff --git a/src/tint/lang/core/ir/return.cc b/src/tint/lang/core/ir/return.cc
index f105afc..fb6cd8a 100644
--- a/src/tint/lang/core/ir/return.cc
+++ b/src/tint/lang/core/ir/return.cc
@@ -37,6 +37,8 @@
namespace tint::core::ir {
+Return::Return() = default;
+
Return::Return(Function* func) {
AddOperand(Return::kFunctionOperandOffset, func);
}
diff --git a/src/tint/lang/core/ir/return.h b/src/tint/lang/core/ir/return.h
index 4fcdc86..4e8827b 100644
--- a/src/tint/lang/core/ir/return.h
+++ b/src/tint/lang/core/ir/return.h
@@ -49,6 +49,9 @@
/// The offset in Operands() for the return argument
static constexpr size_t kArgsOperandOffset = 1;
+ /// Constructor (no operands)
+ Return();
+
/// Constructor (no return value)
/// @param func the function being returned
explicit Return(Function* func);
diff --git a/src/tint/lang/core/type/manager.h b/src/tint/lang/core/type/manager.h
index ada8c7e..8f361da 100644
--- a/src/tint/lang/core/type/manager.h
+++ b/src/tint/lang/core/type/manager.h
@@ -121,6 +121,8 @@
return Get<core::type::F16>(std::forward<ARGS>(args)...);
} else if constexpr (std::is_same_v<T, bool>) {
return Get<core::type::Bool>(std::forward<ARGS>(args)...);
+ } else if constexpr (std::is_same_v<T, void>) {
+ return Get<core::type::Void>(std::forward<ARGS>(args)...);
} else if constexpr (core::fluent_types::IsVector<T>) {
return vec<typename T::type, T::width>(std::forward<ARGS>(args)...);
} else if constexpr (core::fluent_types::IsMatrix<T>) {
diff --git a/src/tint/utils/macros/compiler.h b/src/tint/utils/macros/compiler.h
index b1fc791..623e4c4 100644
--- a/src/tint/utils/macros/compiler.h
+++ b/src/tint/utils/macros/compiler.h
@@ -45,8 +45,14 @@
#define TINT_DISABLE_WARNING_WEAK_VTABLES /* currently no-op */
#define TINT_DISABLE_WARNING_FLOAT_EQUAL /* currently no-op */
#define TINT_DISABLE_WARNING_DEPRECATED __pragma(warning(disable : 4996))
-#define TINT_DISABLE_WARNING_RESERVED_IDENTIFIER /* currently no-op */
-#define TINT_DISABLE_WARNING_UNUSED_VALUE /* currently no-op */
+#define TINT_DISABLE_WARNING_RESERVED_IDENTIFIER /* currently no-op */
+#define TINT_DISABLE_WARNING_RESERVED_MACRO_IDENTIFIER /* currently no-op */
+#define TINT_DISABLE_WARNING_UNUSED_VALUE /* currently no-op */
+#define TINT_DISABLE_WARNING_UNUSED_PARAMETER __pragma(warning(disable : 4100))
+#define TINT_DISABLE_WARNING_SHADOW_FIELD_IN_CONSTRUCTOR /* currently no-op */
+#define TINT_DISABLE_WARNING_EXTRA_SEMICOLON /* currently no-op */
+#define TINT_DISABLE_WARNING_ZERO_AS_NULLPTR /* currently no-op */
+#define TINT_DISABLE_WARNING_MISSING_DESTRUCTOR_OVERRIDE /* currently no-op */
// clang-format off
#define TINT_BEGIN_DISABLE_WARNING(name) \
@@ -58,14 +64,20 @@
TINT_REQUIRE_SEMICOLON
// clang-format on
+#define TINT_BEGIN_DISABLE_PROTOBUF_WARNINGS() \
+ __pragma(warning(push)) TINT_DISABLE_WARNING_UNUSED_PARAMETER TINT_REQUIRE_SEMICOLON
+#define TINT_END_DISABLE_PROTOBUF_WARNINGS() __pragma(warning(pop)) TINT_REQUIRE_SEMICOLON
+
#define TINT_UNLIKELY(x) x /* currently no-op */
#define TINT_LIKELY(x) x /* currently no-op */
+
#elif defined(__clang__)
////////////////////////////////////////////////////////////////////////////////
// Clang
////////////////////////////////////////////////////////////////////////////////
-#define TINT_DISABLE_WARNING_CONSTANT_OVERFLOW /* currently no-op */
-#define TINT_DISABLE_WARNING_MAYBE_UNINITIALIZED /* currently no-op */
+#define TINT_DISABLE_WARNING_CONSTANT_OVERFLOW /* currently no-op */
+#define TINT_DISABLE_WARNING_MAYBE_UNINITIALIZED \
+ _Pragma("clang diagnostic ignored \"-Wconditional-uninitialized\"")
#define TINT_DISABLE_WARNING_NEWLINE_EOF _Pragma("clang diagnostic ignored \"-Wnewline-eof\"")
#define TINT_DISABLE_WARNING_OLD_STYLE_CAST _Pragma("clang diagnostic ignored \"-Wold-style-cast\"")
#define TINT_DISABLE_WARNING_SIGN_CONVERSION \
@@ -76,13 +88,45 @@
#define TINT_DISABLE_WARNING_DEPRECATED /* currently no-op */
#define TINT_DISABLE_WARNING_RESERVED_IDENTIFIER \
_Pragma("clang diagnostic ignored \"-Wreserved-identifier\"")
+#define TINT_DISABLE_WARNING_RESERVED_MACRO_IDENTIFIER \
+ _Pragma("clang diagnostic ignored \"-Wreserved-macro-identifier\"")
#define TINT_DISABLE_WARNING_UNUSED_VALUE _Pragma("clang diagnostic ignored \"-Wunused-value\"")
+#define TINT_DISABLE_WARNING_UNUSED_PARAMETER \
+ _Pragma("clang diagnostic ignored \"-Wunused-parameter\"")
+#define TINT_DISABLE_WARNING_SHADOW_FIELD_IN_CONSTRUCTOR \
+ _Pragma("clang diagnostic ignored \"-Wshadow-field-in-constructor\"")
+#define TINT_DISABLE_WARNING_EXTRA_SEMICOLON \
+ _Pragma("clang diagnostic ignored \"-Wextra-semi-stmt\"")
+#define TINT_DISABLE_WARNING_ZERO_AS_NULLPTR \
+ _Pragma("clang diagnostic ignored \"-Wzero-as-null-pointer-constant\"")
+#define TINT_DISABLE_WARNING_MISSING_DESTRUCTOR_OVERRIDE \
+ _Pragma("clang diagnostic ignored \"-Wsuggest-destructor-override\"") \
+ _Pragma("clang diagnostic ignored \"-Winconsistent-missing-destructor-override\"")
// clang-format off
+#define TINT_BEGIN_DISABLE_PROTOBUF_WARNINGS() \
+ _Pragma("clang diagnostic push") \
+ TINT_DISABLE_WARNING_EXTRA_SEMICOLON \
+ TINT_DISABLE_WARNING_MAYBE_UNINITIALIZED \
+ TINT_DISABLE_WARNING_MISSING_DESTRUCTOR_OVERRIDE \
+ TINT_DISABLE_WARNING_RESERVED_IDENTIFIER \
+ TINT_DISABLE_WARNING_RESERVED_MACRO_IDENTIFIER \
+ TINT_DISABLE_WARNING_SHADOW_FIELD_IN_CONSTRUCTOR \
+ TINT_DISABLE_WARNING_SIGN_CONVERSION \
+ TINT_DISABLE_WARNING_UNUSED_PARAMETER \
+ TINT_DISABLE_WARNING_WEAK_VTABLES \
+ TINT_DISABLE_WARNING_ZERO_AS_NULLPTR \
+ TINT_REQUIRE_SEMICOLON
+
+#define TINT_END_DISABLE_PROTOBUF_WARNINGS() \
+ _Pragma("clang diagnostic pop") \
+ TINT_REQUIRE_SEMICOLON
+
#define TINT_BEGIN_DISABLE_WARNING(name) \
_Pragma("clang diagnostic push") \
TINT_CONCAT(TINT_DISABLE_WARNING_, name) \
TINT_REQUIRE_SEMICOLON
+
#define TINT_END_DISABLE_WARNING(name) \
_Pragma("clang diagnostic pop") \
TINT_REQUIRE_SEMICOLON
@@ -97,15 +141,26 @@
#define TINT_DISABLE_WARNING_CONSTANT_OVERFLOW /* currently no-op */
#define TINT_DISABLE_WARNING_MAYBE_UNINITIALIZED \
_Pragma("GCC diagnostic ignored \"-Wmaybe-uninitialized\"")
-#define TINT_DISABLE_WARNING_NEWLINE_EOF /* currently no-op */
-#define TINT_DISABLE_WARNING_OLD_STYLE_CAST /* currently no-op */
-#define TINT_DISABLE_WARNING_SIGN_CONVERSION /* currently no-op */
-#define TINT_DISABLE_WARNING_UNREACHABLE_CODE /* currently no-op */
-#define TINT_DISABLE_WARNING_WEAK_VTABLES /* currently no-op */
-#define TINT_DISABLE_WARNING_FLOAT_EQUAL /* currently no-op */
-#define TINT_DISABLE_WARNING_DEPRECATED /* currently no-op */
-#define TINT_DISABLE_WARNING_RESERVED_IDENTIFIER /* currently no-op */
+#define TINT_DISABLE_WARNING_NEWLINE_EOF /* currently no-op */
+#define TINT_DISABLE_WARNING_OLD_STYLE_CAST /* currently no-op */
+#define TINT_DISABLE_WARNING_SIGN_CONVERSION /* currently no-op */
+#define TINT_DISABLE_WARNING_UNREACHABLE_CODE /* currently no-op */
+#define TINT_DISABLE_WARNING_WEAK_VTABLES /* currently no-op */
+#define TINT_DISABLE_WARNING_FLOAT_EQUAL /* currently no-op */
+#define TINT_DISABLE_WARNING_DEPRECATED /* currently no-op */
+#define TINT_DISABLE_WARNING_RESERVED_IDENTIFIER /* currently no-op */
+#define TINT_DISABLE_WARNING_RESERVED_MACRO_IDENTIFIER /* currently no-op */
#define TINT_DISABLE_WARNING_UNUSED_VALUE _Pragma("GCC diagnostic ignored \"-Wunused-value\"")
+#define TINT_DISABLE_WARNING_UNUSED_PARAMETER \
+ _Pragma("GCC diagnostic ignored \"-Wunused-parameter\"")
+#define TINT_DISABLE_WARNING_SHADOW_FIELD_IN_CONSTRUCTOR /* currently no-op */
+#define TINT_DISABLE_WARNING_EXTRA_SEMICOLON /* currently no-op */
+#define TINT_DISABLE_WARNING_ZERO_AS_NULLPTR /* currently no-op */
+#define TINT_DISABLE_WARNING_MISSING_DESTRUCTOR_OVERRIDE /* currently no-op */
+
+#define TINT_BEGIN_DISABLE_PROTOBUF_WARNINGS() \
+ _Pragma("GCC diagnostic push") TINT_DISABLE_WARNING_UNUSED_PARAMETER TINT_REQUIRE_SEMICOLON
+#define TINT_END_DISABLE_PROTOBUF_WARNINGS() _Pragma("GCC diagnostic pop") TINT_REQUIRE_SEMICOLON
// clang-format off
#define TINT_BEGIN_DISABLE_WARNING(name) \
@@ -125,6 +180,8 @@
////////////////////////////////////////////////////////////////////////////////
#define TINT_BEGIN_DISABLE_WARNING(name) TINT_REQUIRE_SEMICOLON
#define TINT_END_DISABLE_WARNING(name) TINT_REQUIRE_SEMICOLON
+#define TINT_BEGIN_DISABLE_PROTOBUF_WARNINGS() TINT_REQUIRE_SEMICOLON
+#define TINT_END_DISABLE_PROTOBUF_WARNINGS() TINT_REQUIRE_SEMICOLON
#define TINT_UNLIKELY(x) x
#define TINT_LIKELY(x) x
diff --git a/third_party/protobuf.cmake b/third_party/protobuf.cmake
index 731068f..f1686e8 100644
--- a/third_party/protobuf.cmake
+++ b/third_party/protobuf.cmake
@@ -158,6 +158,8 @@
set(COMMENT "${COMMENT}, plugin-options: ${PLUGIN_OPTIONS}")
endif()
+ file(MAKE_DIRECTORY "${ARGS_PROTOC_OUT_DIR}/${REL_DIR}")
+
add_custom_command(
OUTPUT ${GENERATED_SRCS}
COMMAND protobuf::protoc