[spirv-reader] Add --use-ir-reader option to exe

This performs the following two steps:
- Convert SPIR-V binary to a core IR module
- Convert core IR module to a WGSL program

Bug: tint:1907
Change-Id: I42e8024f022d70d3446ecbc8a250d76d12e60670
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/165302
Kokoro: Kokoro <noreply+kokoro@google.com>
Commit-Queue: James Price <jrprice@google.com>
Reviewed-by: Ben Clayton <bclayton@google.com>
diff --git a/src/tint/cmd/common/helper.cc b/src/tint/cmd/common/helper.cc
index 4570f41..4e2bc38 100644
--- a/src/tint/cmd/common/helper.cc
+++ b/src/tint/cmd/common/helper.cc
@@ -37,6 +37,7 @@
 #endif
 
 #if TINT_BUILD_WGSL_WRITER
+#include "src/tint/lang/wgsl/writer/ir_to_program/ir_to_program.h"
 #include "src/tint/lang/wgsl/writer/writer.h"
 #endif
 
@@ -109,6 +110,38 @@
     }
 }
 
+#if TINT_BUILD_SPV_READER
+tint::Program ReadSpirv(const std::vector<uint32_t>& data, const LoadProgramOptions& opts) {
+    if (opts.use_ir) {
+#if TINT_BUILD_WGSL_WRITER
+        // Parse the SPIR-V binary to a core Tint IR module.
+        auto result = tint::spirv::reader::ReadIR(data);
+        if (!result) {
+            std::cerr << "Failed to parse SPIR-V: " << result.Failure() << "\n";
+            exit(1);
+        }
+
+        // Convert the IR module to a WGSL AST program.
+        tint::wgsl::writer::ProgramOptions options;
+        options.allow_non_uniform_derivatives =
+            opts.spirv_reader_options.allow_non_uniform_derivatives;
+        options.allowed_features = opts.spirv_reader_options.allowed_features;
+        auto ast = tint::wgsl::writer::IRToProgram(result.Get(), options);
+        if (!ast.IsValid() || ast.Diagnostics().contains_errors()) {
+            std::cerr << "Failed to convert IR to AST:\n\n" << ast.Diagnostics() << "\n";
+            exit(1);
+        }
+        return ast;
+#else
+        std::cerr << "Tint not built with the WGSL writer enabled" << std::endl;
+        exit(1);
+#endif  // TINT_BUILD_WGSL_READER
+    } else {
+        return tint::spirv::reader::Read(data, opts.spirv_reader_options);
+    }
+}
+#endif  // TINT_BUILD_SPV_READER
+
 }  // namespace
 
 [[noreturn]] void TintInternalCompilerErrorReporter(const InternalCompilerError& err) {
@@ -180,7 +213,7 @@
                 }
 
                 return ProgramInfo{
-                    /* program */ tint::spirv::reader::Read(data, opts.spirv_reader_options),
+                    /* program */ ReadSpirv(data, opts),
                     /* source_file */ nullptr,
                 };
 #else
@@ -211,7 +244,7 @@
                     opts.filename, std::string(text.begin(), text.end()));
 
                 return ProgramInfo{
-                    /* program */ tint::spirv::reader::Read(data, opts.spirv_reader_options),
+                    /* program */ ReadSpirv(data, opts),
                     /* source_file */ std::move(file),
                 };
 #else
diff --git a/src/tint/cmd/common/helper.h b/src/tint/cmd/common/helper.h
index c711346..04e6961 100644
--- a/src/tint/cmd/common/helper.h
+++ b/src/tint/cmd/common/helper.h
@@ -79,6 +79,7 @@
     std::string filename;
 #if TINT_BUILD_SPV_READER
     /// Spirv-reader options
+    bool use_ir = false;
     tint::spirv::reader::Options spirv_reader_options;
 #endif
 };
diff --git a/src/tint/cmd/tint/main.cc b/src/tint/cmd/tint/main.cc
index 07bf73b..57aaa08 100644
--- a/src/tint/cmd/tint/main.cc
+++ b/src/tint/cmd/tint/main.cc
@@ -179,6 +179,7 @@
 
     bool dump_ir = false;
     bool use_ir = false;
+    bool use_ir_reader = false;
 
 #if TINT_BUILD_SYNTAX_TREE_WRITER
     bool dump_ast = false;
@@ -292,6 +293,10 @@
         "use-ir", "Use the IR for writers and transforms when possible", Default{false});
     TINT_DEFER(opts->use_ir = *use_ir.value);
 
+    auto& use_ir_reader = options.Add<BoolOption>(
+        "use-ir-reader", "Use the IR for the SPIR-V reader", Default{false});
+    TINT_DEFER(opts->use_ir_reader = *use_ir_reader.value);
+
     auto& verbose =
         options.Add<BoolOption>("verbose", "Verbose output", ShortName{"v"}, Default{false});
     TINT_DEFER(opts->verbose = *verbose.value);
@@ -1149,6 +1154,7 @@
     tint::cmd::LoadProgramOptions opts;
     opts.filename = options.input_filename;
 #if TINT_BUILD_SPV_READER
+    opts.use_ir = options.use_ir_reader;
     opts.spirv_reader_options = options.spirv_reader_options;
 #endif