Add WGSL writer helper to create a WGSL program.

This CL adds a `ProgramFromIR` to the WGSL writer. This will raise the
core IR to a WGSL dialect and then return the resulting WGSL program.
This allows us to use the IR without round tripping through the WGSL
reader.

Bug: 338577206
Change-Id: Ied4ca866c3c8f1d13fa7c7d6b846dda145c767ab
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/187720
Reviewed-by: James Price <jrprice@google.com>
Commit-Queue: dan sinclair <dsinclair@chromium.org>
Commit-Queue: dan sinclair <dsinclair@google.com>
diff --git a/src/tint/cmd/common/helper.cc b/src/tint/cmd/common/helper.cc
index 49fcf79..9f83e9a 100644
--- a/src/tint/cmd/common/helper.cc
+++ b/src/tint/cmd/common/helper.cc
@@ -124,23 +124,19 @@
             exit(1);
         }
 
-        // Convert the IR module to a WGSL string.
+        // Convert the IR module to a Program.
         tint::wgsl::writer::ProgramOptions writer_options;
         writer_options.allow_non_uniform_derivatives =
             opts.spirv_reader_options.allow_non_uniform_derivatives;
         writer_options.allowed_features = opts.spirv_reader_options.allowed_features;
-        auto wgsl_result = tint::wgsl::writer::WgslFromIR(result.Get(), writer_options);
-        if (wgsl_result != Success) {
-            std::cerr << "Failed to convert IR to WGSL:\n\n"
-                      << wgsl_result.Failure().reason << "\n";
+        auto prog_result = tint::wgsl::writer::ProgramFromIR(result.Get(), writer_options);
+        if (prog_result != Success) {
+            std::cerr << "Failed to convert IR to Program:\n\n"
+                      << prog_result.Failure().reason << "\n";
             exit(1);
         }
 
-        // Parse the WGSL string to produce a WGSL AST.
-        tint::wgsl::reader::Options reader_options;
-        reader_options.allowed_features = tint::wgsl::AllowedFeatures::Everything();
-        auto file = std::make_unique<tint::Source::File>(opts.filename, wgsl_result->wgsl);
-        return tint::wgsl::reader::Parse(file.get(), reader_options);
+        return prog_result.Move();
 #else
         std::cerr << "Tint not built with the WGSL writer enabled" << std::endl;
         exit(1);
diff --git a/src/tint/lang/wgsl/writer/writer.cc b/src/tint/lang/wgsl/writer/writer.cc
index 92819c0..4013848 100644
--- a/src/tint/lang/wgsl/writer/writer.cc
+++ b/src/tint/lang/wgsl/writer/writer.cc
@@ -68,6 +68,14 @@
 }
 
 Result<Output> WgslFromIR(core::ir::Module& module, const ProgramOptions& options) {
+    auto res = ProgramFromIR(module, options);
+    if (res != Success) {
+        return res.Failure();
+    }
+    return Generate(res.Move(), Options{});
+}
+
+Result<Program> ProgramFromIR(core::ir::Module& module, const ProgramOptions& options) {
     // core-dialect -> WGSL-dialect
     if (auto res = Raise(module); res != Success) {
         return res.Failure();
@@ -78,7 +86,7 @@
         return Failure{program.Diagnostics()};
     }
 
-    return Generate(program, Options{});
+    return program;
 }
 
 }  // namespace tint::wgsl::writer
diff --git a/src/tint/lang/wgsl/writer/writer.h b/src/tint/lang/wgsl/writer/writer.h
index 604ace2..a79ea4d 100644
--- a/src/tint/lang/wgsl/writer/writer.h
+++ b/src/tint/lang/wgsl/writer/writer.h
@@ -56,6 +56,11 @@
 /// @returns the resulting WGSL, or failure
 Result<Output> WgslFromIR(core::ir::Module& module, const ProgramOptions& options);
 
+/// Generate a Program from a core-dialect ir::Module.
+/// @param module the core-dialect ir::Module.
+/// @returns the resulting Program, or failure
+Result<Program> ProgramFromIR(core::ir::Module& module, const ProgramOptions& options);
+
 }  // namespace tint::wgsl::writer
 
 #endif  // SRC_TINT_LANG_WGSL_WRITER_WRITER_H_