tint_wgsl_fuzzer: add '-dump' option to dump input/output shader from fuzzers

Outputs input wgsl, and generated hlsl, msl, and glsl.

Change-Id: I0493b43a3bdf83363bd317bd2e0a8550a8f8cdf5
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/200058
Commit-Queue: Antonio Maiorano <amaiorano@google.com>
Reviewed-by: Ryan Harrison <rharrison@chromium.org>
Reviewed-by: James Price <jrprice@google.com>
diff --git a/src/tint/cmd/fuzz/wgsl/fuzz.cc b/src/tint/cmd/fuzz/wgsl/fuzz.cc
index 2f367bd..3f065f4 100644
--- a/src/tint/cmd/fuzz/wgsl/fuzz.cc
+++ b/src/tint/cmd/fuzz/wgsl/fuzz.cc
@@ -149,6 +149,10 @@
     };
 #endif
 
+    if (options.dump) {
+        std::cout << "Dumping input WGSL:\n" << wgsl << std::endl;
+    }
+
     // Ensure that fuzzers are sorted. Without this, the fuzzers may be registered in any order,
     // leading to non-determinism, which we must avoid.
     TINT_STATIC_INIT(Fuzzers().Sort([](auto& a, auto& b) { return a.name < b.name; }));
diff --git a/src/tint/cmd/fuzz/wgsl/fuzz.h b/src/tint/cmd/fuzz/wgsl/fuzz.h
index 9d20f6c..39d9f61 100644
--- a/src/tint/cmd/fuzz/wgsl/fuzz.h
+++ b/src/tint/cmd/fuzz/wgsl/fuzz.h
@@ -52,6 +52,8 @@
     /// If not empty, load DXC from this path when fuzzing HLSL generation, and fail the fuzzer if
     /// not found, or if DXC fails to compile.
     std::string dxc;
+    /// If true, dump shader input/output text to stdout
+    bool dump = false;
 };
 
 /// ProgramProperties is an enumerator of flags used to describe characteristics of the input
diff --git a/src/tint/cmd/fuzz/wgsl/main_fuzz.cc b/src/tint/cmd/fuzz/wgsl/main_fuzz.cc
index 15cd793..853d0c6 100644
--- a/src/tint/cmd/fuzz/wgsl/main_fuzz.cc
+++ b/src/tint/cmd/fuzz/wgsl/main_fuzz.cc
@@ -115,6 +115,8 @@
     auto& opt_verbose =
         opts.Add<tint::cli::BoolOption>("verbose", "prints the name of each fuzzer before running");
     auto& opt_dxc = opts.Add<tint::cli::StringOption>("dxc", "path to DXC DLL");
+    auto& opt_dump =
+        opts.Add<tint::cli::BoolOption>("dump", "dumps shader input/output from fuzzer");
 
     tint::cli::ParseOptions parse_opts;
     parse_opts.ignore_unknown = true;
@@ -134,6 +136,7 @@
     options.run_concurrently = opt_concurrent.value.value_or(false);
     options.verbose = opt_verbose.value.value_or(false);
     options.dxc = opt_dxc.value.value_or(get_default_dxc_path(argv));
+    options.dump = opt_dump.value.value_or(false);
 
     print_dxc_path_found(options.dxc);
     return 0;
diff --git a/src/tint/lang/glsl/writer/writer_ast_fuzz.cc b/src/tint/lang/glsl/writer/writer_ast_fuzz.cc
index 5a173d6..92ee14b 100644
--- a/src/tint/lang/glsl/writer/writer_ast_fuzz.cc
+++ b/src/tint/lang/glsl/writer/writer_ast_fuzz.cc
@@ -27,6 +27,8 @@
 
 // GEN_BUILD:CONDITION(tint_build_wgsl_reader)
 
+#include <iostream>
+
 #include "src/tint/cmd/fuzz/wgsl/fuzz.h"
 #include "src/tint/lang/core/type/texture.h"
 #include "src/tint/lang/glsl/writer/writer.h"
@@ -84,7 +86,9 @@
     return true;
 }
 
-void ASTFuzzer(const tint::Program& program, const Options& options) {
+void ASTFuzzer(const tint::Program& program,
+               const fuzz::wgsl::Context& context,
+               const Options& options) {
     if (!CanRun(program, options)) {
         return;
     }
@@ -94,7 +98,11 @@
 
     // Test all of the entry points as GLSL requires specifying which one to generate.
     for (const auto& ep : entrypoints) {
-        [[maybe_unused]] auto res = tint::glsl::writer::Generate(program, options, ep.name);
+        auto res = tint::glsl::writer::Generate(program, options, ep.name);
+
+        if (res == Success && context.options.dump) {
+            std::cout << "Dumping generated GLSL:\n" << res->glsl << std::endl;
+        }
     }
 }
 
diff --git a/src/tint/lang/hlsl/writer/writer_ast_fuzz.cc b/src/tint/lang/hlsl/writer/writer_ast_fuzz.cc
index 3ae746c..904ccd3 100644
--- a/src/tint/lang/hlsl/writer/writer_ast_fuzz.cc
+++ b/src/tint/lang/hlsl/writer/writer_ast_fuzz.cc
@@ -68,7 +68,9 @@
     return true;
 }
 
-void ASTFuzzer(const tint::Program& program, const fuzz::wgsl::Context& context, Options options) {
+void ASTFuzzer(const tint::Program& program,
+               const fuzz::wgsl::Context& context,
+               const Options& options) {
     if (!CanRun(program)) {
         return;
     }
@@ -99,6 +101,10 @@
         return;
     }
 
+    if (context.options.dump) {
+        std::cout << "Dumping generated HLSL:\n" << res->hlsl << std::endl;
+    }
+
     auto dxc = tint::Command::LookPath(dxc_path);
     if (dxc.Found()) {
         uint32_t hlsl_shader_model = 60;
diff --git a/src/tint/lang/msl/writer/writer_ast_fuzz.cc b/src/tint/lang/msl/writer/writer_ast_fuzz.cc
index faf63b4..41a6d1b 100644
--- a/src/tint/lang/msl/writer/writer_ast_fuzz.cc
+++ b/src/tint/lang/msl/writer/writer_ast_fuzz.cc
@@ -27,6 +27,8 @@
 
 // GEN_BUILD:CONDITION(tint_build_wgsl_reader)
 
+#include <iostream>
+
 #include "src/tint/cmd/fuzz/wgsl/fuzz.h"
 #include "src/tint/lang/msl/writer/helpers/generate_bindings.h"
 #include "src/tint/lang/msl/writer/writer.h"
@@ -59,7 +61,11 @@
 
     options.bindings = GenerateBindings(program);
 
-    [[maybe_unused]] auto res = tint::msl::writer::Generate(program, options);
+    auto res = tint::msl::writer::Generate(program, options);
+
+    if (res == Success && context.options.dump) {
+        std::cout << "Dumping generated MSL:\n" << res->msl << std::endl;
+    }
 }
 
 }  // namespace