[tint][wgsl][fuzz] Parse base64 encoded comments

As additional data that can be used for other fuzzer input for WGSL
fuzzer tests.

Change-Id: I07d564879f28fd214eefc28ec105d1f044eaab3a
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/162305
Kokoro: Kokoro <noreply+kokoro@google.com>
Reviewed-by: dan sinclair <dsinclair@chromium.org>
diff --git a/src/tint/cmd/fuzz/wgsl/BUILD.cmake b/src/tint/cmd/fuzz/wgsl/BUILD.cmake
index 362fd58..ca70b10 100644
--- a/src/tint/cmd/fuzz/wgsl/BUILD.cmake
+++ b/src/tint/cmd/fuzz/wgsl/BUILD.cmake
@@ -54,6 +54,7 @@
   tint_lang_wgsl_program_fuzz
   tint_lang_wgsl_sem
   tint_lang_wgsl_fuzz
+  tint_utils_bytes
   tint_utils_cli
   tint_utils_containers
   tint_utils_diagnostic
@@ -62,6 +63,7 @@
   tint_utils_macros
   tint_utils_math
   tint_utils_memory
+  tint_utils_reflection
   tint_utils_result
   tint_utils_rtti
   tint_utils_strconv
@@ -108,6 +110,7 @@
   tint_lang_wgsl_common
   tint_lang_wgsl_program
   tint_lang_wgsl_sem
+  tint_utils_bytes
   tint_utils_containers
   tint_utils_diagnostic
   tint_utils_ice
diff --git a/src/tint/cmd/fuzz/wgsl/BUILD.gn b/src/tint/cmd/fuzz/wgsl/BUILD.gn
index 090fb75..5b10e5a 100644
--- a/src/tint/cmd/fuzz/wgsl/BUILD.gn
+++ b/src/tint/cmd/fuzz/wgsl/BUILD.gn
@@ -55,6 +55,7 @@
       "${tint_src_dir}/lang/wgsl/common",
       "${tint_src_dir}/lang/wgsl/program",
       "${tint_src_dir}/lang/wgsl/sem",
+      "${tint_src_dir}/utils/bytes",
       "${tint_src_dir}/utils/containers",
       "${tint_src_dir}/utils/diagnostic",
       "${tint_src_dir}/utils/ice",
@@ -89,6 +90,7 @@
       "${tint_src_dir}/lang/wgsl/program",
       "${tint_src_dir}/lang/wgsl/program:fuzz",
       "${tint_src_dir}/lang/wgsl/sem",
+      "${tint_src_dir}/utils/bytes",
       "${tint_src_dir}/utils/cli",
       "${tint_src_dir}/utils/containers",
       "${tint_src_dir}/utils/diagnostic",
@@ -97,6 +99,7 @@
       "${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/strconv",
diff --git a/src/tint/cmd/fuzz/wgsl/fuzz.cc b/src/tint/cmd/fuzz/wgsl/fuzz.cc
index b5a09b0..d6b90ec 100644
--- a/src/tint/cmd/fuzz/wgsl/fuzz.cc
+++ b/src/tint/cmd/fuzz/wgsl/fuzz.cc
@@ -60,7 +60,7 @@
     Fuzzers().Push(fuzzer);
 }
 
-void Run(std::string_view wgsl, const Options& options) {
+void Run(std::string_view wgsl, Slice<const std::byte> data, const Options& options) {
     tint::SetInternalCompilerErrorReporter(&TintInternalCompilerErrorReporter);
 
     // Ensure that fuzzers are sorted. Without this, the fuzzers may be registered in any order,
@@ -82,10 +82,10 @@
         tint::Vector<std::thread, 32> threads;
         threads.Resize(n);
         for (size_t i = 0; i < n; i++) {
-            threads[i] = std::thread([i, &program] {
+            threads[i] = std::thread([i, &program, &data] {
                 auto& fuzzer = Fuzzers()[i];
                 currently_running = fuzzer.name;
-                fuzzer.fn(program);
+                fuzzer.fn(program, data);
             });
         }
         for (auto& thread : threads) {
@@ -95,7 +95,7 @@
         TINT_DEFER(currently_running = "");
         for (auto& fuzzer : Fuzzers()) {
             currently_running = fuzzer.name;
-            fuzzer.fn(program);
+            fuzzer.fn(program, data);
         }
     }
 }
diff --git a/src/tint/cmd/fuzz/wgsl/fuzz.h b/src/tint/cmd/fuzz/wgsl/fuzz.h
index 7e68732..744ceb5 100644
--- a/src/tint/cmd/fuzz/wgsl/fuzz.h
+++ b/src/tint/cmd/fuzz/wgsl/fuzz.h
@@ -29,22 +29,47 @@
 #define SRC_TINT_CMD_FUZZ_WGSL_FUZZ_H_
 
 #include <string>
+#include <tuple>
+#include <utility>
 
 #include "src/tint/lang/wgsl/program/program.h"
+#include "src/tint/utils/bytes/decoder.h"
 #include "src/tint/utils/containers/slice.h"
 #include "src/tint/utils/macros/static_init.h"
+#include "src/tint/utils/reflection/reflection.h"
 
 namespace tint::fuzz::wgsl {
 
 /// ProgramFuzzer describes a fuzzer function that takes a WGSL program as input
 struct ProgramFuzzer {
-    /// The function signature
-    using Fn = void(const Program&);
+    /// @param name the name of the fuzzer
+    /// @param fn the fuzzer function
+    /// @returns a ProgramFuzzer that invokes the function @p fn with the Program, along with any
+    /// additional arguments which are deserialized from the fuzzer input.
+    template <typename... ARGS>
+    static ProgramFuzzer Create(std::string_view name, void (*fn)(const Program&, ARGS...)) {
+        if constexpr (sizeof...(ARGS) > 0) {
+            auto fn_with_decode = [fn](const Program& program, Slice<const std::byte> data) {
+                bytes::Reader reader{data};
+                if (auto data_args = bytes::Decode<std::tuple<std::decay_t<ARGS>...>>(reader)) {
+                    auto all_args =
+                        std::tuple_cat(std::tuple<const Program&>{program}, data_args.Get());
+                    std::apply(*fn, all_args);
+                }
+            };
+            return ProgramFuzzer{name, std::move(fn_with_decode)};
+        } else {
+            return ProgramFuzzer{
+                name,
+                [fn](const Program& program, Slice<const std::byte>) { fn(program); },
+            };
+        }
+    }
 
     /// Name of the fuzzer function
     std::string_view name;
-    /// The fuzzer function pointer
-    Fn* fn = nullptr;
+    /// The fuzzer function
+    std::function<void(const Program&, Slice<const std::byte> data)> fn;
 };
 
 /// Options for Run()
@@ -55,16 +80,18 @@
 
 /// Runs all the registered WGSL fuzzers with the supplied WGSL
 /// @param wgsl the input WGSL
+/// @param data additional data used for fuzzing
 /// @param options the options for running the fuzzers
-void Run(std::string_view wgsl, const Options& options);
+void Run(std::string_view wgsl, Slice<const std::byte> data, const Options& options);
 
 /// Registers the fuzzer function with the WGSL fuzzer executable.
 /// @param fuzzer the fuzzer
 void Register(const ProgramFuzzer& fuzzer);
 
 /// TINT_WGSL_PROGRAM_FUZZER registers the fuzzer function to run as part of `tint_wgsl_fuzzer`
-#define TINT_WGSL_PROGRAM_FUZZER(FUNCTION) \
-    TINT_STATIC_INIT(::tint::fuzz::wgsl::Register({#FUNCTION, FUNCTION}))
+#define TINT_WGSL_PROGRAM_FUZZER(FUNCTION)         \
+    TINT_STATIC_INIT(::tint::fuzz::wgsl::Register( \
+        ::tint::fuzz::wgsl::ProgramFuzzer::Create(#FUNCTION, FUNCTION)))
 
 }  // namespace tint::fuzz::wgsl
 
diff --git a/src/tint/cmd/fuzz/wgsl/main_fuzz.cc b/src/tint/cmd/fuzz/wgsl/main_fuzz.cc
index 9b65369..1edcd04 100644
--- a/src/tint/cmd/fuzz/wgsl/main_fuzz.cc
+++ b/src/tint/cmd/fuzz/wgsl/main_fuzz.cc
@@ -29,17 +29,20 @@
 
 #include "src/tint/cmd/fuzz/wgsl/fuzz.h"
 #include "src/tint/utils/cli/cli.h"
+#include "src/tint/utils/macros/defer.h"
+#include "src/tint/utils/text/base64.h"
 
 namespace {
 
 tint::fuzz::wgsl::Options options;
 
-}
+}  // namespace
 
-extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* input, size_t size) {
     if (size > 0) {
-        std::string_view wgsl(reinterpret_cast<const char*>(data), size);
-        tint::fuzz::wgsl::Run(wgsl, options);
+        std::string_view wgsl(reinterpret_cast<const char*>(input), size);
+        auto data = tint::DecodeBase64FromComments(wgsl);
+        tint::fuzz::wgsl::Run(wgsl, data.Slice(), options);
     }
     return 0;
 }
diff --git a/src/tint/lang/wgsl/BUILD.cmake b/src/tint/lang/wgsl/BUILD.cmake
index 7e09df7..5c9aa4b 100644
--- a/src/tint/lang/wgsl/BUILD.cmake
+++ b/src/tint/lang/wgsl/BUILD.cmake
@@ -190,6 +190,7 @@
   tint_lang_wgsl_sem
   tint_lang_wgsl_writer_ir_to_program
   tint_lang_wgsl_writer_raise
+  tint_utils_bytes
   tint_utils_containers
   tint_utils_diagnostic
   tint_utils_ice
diff --git a/src/tint/lang/wgsl/BUILD.gn b/src/tint/lang/wgsl/BUILD.gn
index e27e459..9aa5213 100644
--- a/src/tint/lang/wgsl/BUILD.gn
+++ b/src/tint/lang/wgsl/BUILD.gn
@@ -164,6 +164,7 @@
     "${tint_src_dir}/lang/wgsl/sem",
     "${tint_src_dir}/lang/wgsl/writer/ir_to_program",
     "${tint_src_dir}/lang/wgsl/writer/raise",
+    "${tint_src_dir}/utils/bytes",
     "${tint_src_dir}/utils/containers",
     "${tint_src_dir}/utils/diagnostic",
     "${tint_src_dir}/utils/ice",
diff --git a/src/tint/lang/wgsl/ast/transform/BUILD.cmake b/src/tint/lang/wgsl/ast/transform/BUILD.cmake
index 9100dc7..ef57905 100644
--- a/src/tint/lang/wgsl/ast/transform/BUILD.cmake
+++ b/src/tint/lang/wgsl/ast/transform/BUILD.cmake
@@ -242,6 +242,7 @@
   tint_lang_wgsl_ast_transform
   tint_lang_wgsl_program
   tint_lang_wgsl_sem
+  tint_utils_bytes
   tint_utils_containers
   tint_utils_diagnostic
   tint_utils_ice
@@ -249,6 +250,7 @@
   tint_utils_macros
   tint_utils_math
   tint_utils_memory
+  tint_utils_reflection
   tint_utils_result
   tint_utils_rtti
   tint_utils_symbol
diff --git a/src/tint/lang/wgsl/ast/transform/BUILD.gn b/src/tint/lang/wgsl/ast/transform/BUILD.gn
index 0a1bc92..c4250ef 100644
--- a/src/tint/lang/wgsl/ast/transform/BUILD.gn
+++ b/src/tint/lang/wgsl/ast/transform/BUILD.gn
@@ -229,6 +229,7 @@
       "${tint_src_dir}/lang/wgsl/ast/transform",
       "${tint_src_dir}/lang/wgsl/program",
       "${tint_src_dir}/lang/wgsl/sem",
+      "${tint_src_dir}/utils/bytes",
       "${tint_src_dir}/utils/containers",
       "${tint_src_dir}/utils/diagnostic",
       "${tint_src_dir}/utils/ice",
@@ -236,6 +237,7 @@
       "${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",
diff --git a/src/tint/lang/wgsl/program/BUILD.cmake b/src/tint/lang/wgsl/program/BUILD.cmake
index 2e04315..d558e88 100644
--- a/src/tint/lang/wgsl/program/BUILD.cmake
+++ b/src/tint/lang/wgsl/program/BUILD.cmake
@@ -129,6 +129,7 @@
   tint_lang_wgsl_program
   tint_lang_wgsl_resolver
   tint_lang_wgsl_sem
+  tint_utils_bytes
   tint_utils_containers
   tint_utils_diagnostic
   tint_utils_ice
diff --git a/src/tint/lang/wgsl/program/BUILD.gn b/src/tint/lang/wgsl/program/BUILD.gn
index 03d0b77..63b864e 100644
--- a/src/tint/lang/wgsl/program/BUILD.gn
+++ b/src/tint/lang/wgsl/program/BUILD.gn
@@ -124,6 +124,7 @@
     "${tint_src_dir}/lang/wgsl/program",
     "${tint_src_dir}/lang/wgsl/resolver",
     "${tint_src_dir}/lang/wgsl/sem",
+    "${tint_src_dir}/utils/bytes",
     "${tint_src_dir}/utils/containers",
     "${tint_src_dir}/utils/diagnostic",
     "${tint_src_dir}/utils/ice",
diff --git a/src/tint/lang/wgsl/writer/ast_printer/BUILD.cmake b/src/tint/lang/wgsl/writer/ast_printer/BUILD.cmake
index 94c711f..bc7f349 100644
--- a/src/tint/lang/wgsl/writer/ast_printer/BUILD.cmake
+++ b/src/tint/lang/wgsl/writer/ast_printer/BUILD.cmake
@@ -166,6 +166,7 @@
   tint_lang_wgsl_ast
   tint_lang_wgsl_program
   tint_lang_wgsl_sem
+  tint_utils_bytes
   tint_utils_containers
   tint_utils_diagnostic
   tint_utils_generator
@@ -174,6 +175,7 @@
   tint_utils_macros
   tint_utils_math
   tint_utils_memory
+  tint_utils_reflection
   tint_utils_result
   tint_utils_rtti
   tint_utils_symbol
diff --git a/src/tint/lang/wgsl/writer/ast_printer/BUILD.gn b/src/tint/lang/wgsl/writer/ast_printer/BUILD.gn
index 88734f2..a1c4700 100644
--- a/src/tint/lang/wgsl/writer/ast_printer/BUILD.gn
+++ b/src/tint/lang/wgsl/writer/ast_printer/BUILD.gn
@@ -154,6 +154,7 @@
       "${tint_src_dir}/lang/wgsl/ast",
       "${tint_src_dir}/lang/wgsl/program",
       "${tint_src_dir}/lang/wgsl/sem",
+      "${tint_src_dir}/utils/bytes",
       "${tint_src_dir}/utils/containers",
       "${tint_src_dir}/utils/diagnostic",
       "${tint_src_dir}/utils/generator",
@@ -162,6 +163,7 @@
       "${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",