tint: Add generating IR protobufs to CLI
Adds the Tint IR protobuf binary format to the list of formats that
the CLI can output. Additionally adds a debugging flag for emitting a
human readable version of the protobuf.
Issue: 340582174
Change-Id: Ifea9d4699fa1c22b493f6bf67072081a9dda6b87
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/188320
Auto-Submit: Ryan Harrison <rharrison@chromium.org>
Reviewed-by: Ben Clayton <bclayton@google.com>
Commit-Queue: Ryan Harrison <rharrison@chromium.org>
Commit-Queue: Ben Clayton <bclayton@google.com>
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 6abb9f0..7dc8b01 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -234,6 +234,9 @@
option_if_not_defined(TINT_BUILD_SYNTAX_TREE_WRITER "Build the syntax tree writer" OFF)
+option_if_not_defined(TINT_BUILD_IR_BINARY "Build IR binary format support" ON)
+
+
option_if_not_defined(TINT_BUILD_FUZZERS "Build fuzzers" OFF)
option_if_not_defined(TINT_BUILD_AST_FUZZER "Build AST fuzzer" OFF)
option_if_not_defined(TINT_BUILD_REGEX_FUZZER "Build regex fuzzer" OFF)
diff --git a/src/tint/BUILD.gn b/src/tint/BUILD.gn
index f17d0f3..af3d7a5 100644
--- a/src/tint/BUILD.gn
+++ b/src/tint/BUILD.gn
@@ -108,6 +108,12 @@
defines += [ "TINT_BUILD_SYNTAX_TREE_WRITER=0" ]
}
+ if (tint_build_ir_binary) {
+ defines += [ "TINT_BUILD_IR_BINARY=1" ]
+ } else {
+ defines += [ "TINT_BUILD_IR_BINARY=0" ]
+ }
+
if (tint_build_is_win) {
defines += [ "TINT_BUILD_IS_WIN=1" ]
} else {
diff --git a/src/tint/cmd/tint/BUILD.bazel b/src/tint/cmd/tint/BUILD.bazel
index bdba7b0..05c18b3 100644
--- a/src/tint/cmd/tint/BUILD.bazel
+++ b/src/tint/cmd/tint/BUILD.bazel
@@ -97,6 +97,11 @@
],
"//conditions:default": [],
}) + select({
+ ":tint_build_ir_binary": [
+ "//src/tint/lang/core/ir/binary",
+ ],
+ "//conditions:default": [],
+ }) + select({
":tint_build_msl_writer": [
"//src/tint/lang/msl/validate",
"//src/tint/lang/msl/writer",
@@ -153,6 +158,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/tint/BUILD.cmake b/src/tint/cmd/tint/BUILD.cmake
index 8ed82d1..5622503 100644
--- a/src/tint/cmd/tint/BUILD.cmake
+++ b/src/tint/cmd/tint/BUILD.cmake
@@ -102,6 +102,12 @@
)
endif(TINT_BUILD_HLSL_WRITER)
+if(TINT_BUILD_IR_BINARY)
+ tint_target_add_dependencies(tint_cmd_tint_cmd cmd
+ tint_lang_core_ir_binary
+ )
+endif(TINT_BUILD_IR_BINARY)
+
if(TINT_BUILD_MSL_WRITER)
tint_target_add_dependencies(tint_cmd_tint_cmd cmd
tint_lang_msl_validate
diff --git a/src/tint/cmd/tint/BUILD.gn b/src/tint/cmd/tint/BUILD.gn
index 7f3584f..5edef93 100644
--- a/src/tint/cmd/tint/BUILD.gn
+++ b/src/tint/cmd/tint/BUILD.gn
@@ -99,6 +99,10 @@
]
}
+ if (tint_build_ir_binary) {
+ deps += [ "${tint_src_dir}/lang/core/ir/binary" ]
+ }
+
if (tint_build_msl_writer) {
deps += [
"${tint_src_dir}/lang/msl/validate",
diff --git a/src/tint/cmd/tint/main.cc b/src/tint/cmd/tint/main.cc
index f413485..ccfdcf1 100644
--- a/src/tint/cmd/tint/main.cc
+++ b/src/tint/cmd/tint/main.cc
@@ -68,6 +68,11 @@
#if TINT_BUILD_WGSL_READER
#include "src/tint/lang/wgsl/reader/program_to_ir/program_to_ir.h"
#include "src/tint/lang/wgsl/reader/reader.h"
+
+#if TINT_BUILD_IR_BINARY
+#include "src/tint/lang/core/ir/binary/encode.h"
+#endif // TINT_BUILD_IR_BINARY
+
#endif // TINT_BUILD_WGSL_READER
#if TINT_BUILD_SPV_WRITER
@@ -105,6 +110,8 @@
#define WGSL_READER_ONLY(x)
#endif
+#define WGSL_READER_AND_IR_BINARY (TINT_BUILD_WGSL_READER && TINT_BUILD_IR_BINARY)
+
#if TINT_BUILD_SPV_WRITER
#define SPV_WRITER_ONLY(x) x
#else
@@ -135,6 +142,12 @@
#define GLSL_WRITER_ONLY(x)
#endif
+#if WGSL_READER_AND_IR_BINARY
+#define WGSL_READER_AND_IR_BINARY_ONLY(x) x
+#else
+#define WGSL_READER_AND_IR_BINARY_ONLY(x)
+#endif
+
namespace {
/// Prints the given hash value in a format string that the end-to-end test runner can parse.
@@ -152,6 +165,7 @@
kHlsl,
kGlsl,
kIr,
+ kIrBin
};
#if TINT_BUILD_HLSL_WRITER
@@ -216,6 +230,7 @@
#endif // TINT_BUILD_HLSL_WRITER
bool dump_ir = false;
+ bool dump_ir_bin = false;
bool use_ir = false;
bool use_ir_reader = false;
@@ -285,6 +300,12 @@
}
#endif // TINT_BUILD_HLSL_WRITER
+#if WGSL_READER_AND_IR_BINARY
+ if (tint::HasSuffix(filename, ".tirb")) {
+ return Format::kIrBin;
+ }
+#endif // WGSL_READER_AND_IR_BINARY
+
return Format::kUnknown;
}
@@ -304,6 +325,7 @@
HLSL_WRITER_ONLY(format_enum_names.Emplace(Format::kHlsl, "hlsl"));
GLSL_WRITER_ONLY(format_enum_names.Emplace(Format::kGlsl, "glsl"));
WGSL_READER_ONLY(format_enum_names.Emplace(Format::kIr, "ir"));
+ WGSL_READER_AND_IR_BINARY_ONLY(format_enum_names.Emplace(Format::kIrBin, "ir_bin"));
OptionSet options;
auto& fmt = options.Add<EnumOption<Format>>("format",
@@ -313,7 +335,8 @@
.spv -> spirv
.wgsl -> wgsl
.metal -> msl
- .hlsl -> hlsl)",
+ .hlsl -> hlsl)" WGSL_READER_AND_IR_BINARY_ONLY(R"(
+ .tirb -> ir binary protobuf)"),
format_enum_names, ShortName{"f"});
TINT_DEFER(opts->format = fmt.value.value_or(Format::kUnknown));
@@ -370,6 +393,11 @@
Default{false});
TINT_DEFER(opts->dump_ir = *dump_ir.value);
+ auto& dump_ir_bin = options.Add<BoolOption>(
+ "dump-ir-bin", "Writes the IR as a human readable protobuf to stdout", Alias{"emit-ir-bin"},
+ Default{false});
+ TINT_DEFER(opts->dump_ir_bin = *dump_ir_bin.value);
+
auto& use_ir = options.Add<BoolOption>(
"use-ir", "Use the IR for writers and transforms when possible", Default{false});
TINT_DEFER(opts->use_ir = *use_ir.value);
@@ -1223,12 +1251,76 @@
std::cerr << "Failed to build IR from program: " << result.Failure() << "\n";
return false;
}
+
options.printer->Print(tint::core::ir::Disassemble(result.Get()).Text());
options.printer->Print(tint::StyledText{} << "\n");
+
return true;
#endif
}
+/// Generate IR binary protobuf for a program.
+/// @param program the program to generate
+/// @param options the options that Tint was invoked with
+/// @returns true on success
+bool GenerateIrProtoBinary([[maybe_unused]] const tint::Program& program,
+ [[maybe_unused]] const Options& options) {
+#if !TINT_BUILD_WGSL_READER
+ std::cerr << "WGSL reader not enabled in tint build" << std::endl;
+ return false;
+#elif !TINT_BUILD_IR_BINARY
+ std::cerr << "IR binary not enabled in tint build" << std::endl;
+ return false;
+#else
+ auto module = tint::wgsl::reader::ProgramToLoweredIR(program);
+ if (module != tint::Success) {
+ std::cerr << "Failed to build IR from program: " << module.Failure() << "\n";
+ return false;
+ }
+ auto pb = tint::core::ir::binary::Encode(module.Get());
+ if (pb != tint::Success) {
+ std::cerr << "Failed to encode IR module to protobuf: " << pb.Failure() << "\n";
+ return false;
+ }
+
+ if (!WriteFile(options.output_file, "wb", ToStdVector(pb.Get()))) {
+ std::cerr << "Failed to write protobuf binary out to file"
+ << "\n";
+ return false;
+ }
+
+ return true;
+#endif
+}
+
+/// Generate IR human readable protobuf for a program.
+/// @param program the program to generate
+/// @param options the options that Tint was invoked with
+/// @returns true on success
+#if WGSL_READER_AND_IR_BINARY
+bool GenerateIrProtoDebug([[maybe_unused]] const tint::Program& program,
+ [[maybe_unused]] const Options& options) {
+ auto module = tint::wgsl::reader::ProgramToLoweredIR(program);
+ if (module != tint::Success) {
+ std::cerr << "Failed to build IR from program: " << module.Failure() << "\n";
+ return false;
+ }
+ auto pb = tint::core::ir::binary::EncodeDebug(module.Get());
+ if (pb != tint::Success) {
+ std::cerr << "Failed to encode IR module to protobuf: " << pb.Failure() << "\n";
+ return false;
+ }
+
+ if (!WriteFile(options.output_file, "w", pb.Get())) {
+ std::cerr << "Failed to write protobuf debug text out to file"
+ << "\n";
+ return false;
+ }
+
+ return true;
+}
+#endif // WGSL_READER_AND_IR_BINARY
+
} // namespace
int main(int argc, const char** argv) {
@@ -1370,6 +1462,12 @@
}
#endif // TINT_BUILD_WGSL_READER
+#if WGSL_READER_AND_IR_BINARY
+ if (options.dump_ir_bin) {
+ GenerateIrProtoDebug(info.program, options);
+ }
+#endif // WGSL_READER_AND_IR_BINARY
+
tint::inspector::Inspector inspector(info.program);
if (options.dump_inspector_bindings) {
tint::cmd::PrintInspectorBindings(inspector);
@@ -1480,6 +1578,9 @@
case Format::kIr:
success = GenerateIr(program, options);
break;
+ case Format::kIrBin:
+ success = GenerateIrProtoBinary(program, options);
+ break;
case Format::kNone:
break;
default:
diff --git a/src/tint/lang/core/ir/binary/encode.cc b/src/tint/lang/core/ir/binary/encode.cc
index 74d00ac..d908788 100644
--- a/src/tint/lang/core/ir/binary/encode.cc
+++ b/src/tint/lang/core/ir/binary/encode.cc
@@ -27,6 +27,7 @@
#include "src/tint/lang/core/ir/binary/encode.h"
+#include <string>
#include <utility>
#include "src/tint/lang/core/builtin_fn.h"
@@ -1153,4 +1154,13 @@
return buffer;
}
+Result<std::string> EncodeDebug(const Module& mod_in) {
+ GOOGLE_PROTOBUF_VERIFY_VERSION;
+
+ pb::Module mod_out;
+ Encoder{mod_in, mod_out}.Encode();
+
+ return mod_out.DebugString();
+}
+
} // 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
index 3cdd520..5095eff 100644
--- a/src/tint/lang/core/ir/binary/encode.h
+++ b/src/tint/lang/core/ir/binary/encode.h
@@ -28,18 +28,24 @@
#ifndef SRC_TINT_LANG_CORE_IR_BINARY_ENCODE_H_
#define SRC_TINT_LANG_CORE_IR_BINARY_ENCODE_H_
+#include <string>
+
#include "src/tint/utils/containers/vector.h"
#include "src/tint/utils/result/result.h"
-// Forward declarartion
+// Forward declaration
namespace tint::core::ir {
class Module;
} // namespace tint::core::ir
namespace tint::core::ir::binary {
+// Encode the module into a binary representation.
Result<Vector<std::byte, 0>> Encode(const Module& module);
+// Encode the module into a human readable debug representation.
+Result<std::string> EncodeDebug(const Module& module);
+
} // namespace tint::core::ir::binary
#endif // SRC_TINT_LANG_CORE_IR_BINARY_ENCODE_H_