[tint][fuzz] Add an IR fuzzer framework

This currently registers the IR fuzzers with the WGSL fuzzer using a
ProgramToIR() translation stub.

Change-Id: I116a50dc809d6789ce8510171f91b98fde70d5e7
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/162307
Reviewed-by: dan sinclair <dsinclair@chromium.org>
Reviewed-by: James Price <jrprice@google.com>
Kokoro: Kokoro <noreply+kokoro@google.com>
diff --git a/src/tint/cmd/fuzz/BUILD.cmake b/src/tint/cmd/fuzz/BUILD.cmake
index 65795ac..65ca459 100644
--- a/src/tint/cmd/fuzz/BUILD.cmake
+++ b/src/tint/cmd/fuzz/BUILD.cmake
@@ -34,4 +34,5 @@
 #                       Do not modify this file directly
 ################################################################################
 
+include(cmd/fuzz/ir/BUILD.cmake)
 include(cmd/fuzz/wgsl/BUILD.cmake)
diff --git a/src/tint/cmd/fuzz/ir/BUILD.bazel b/src/tint/cmd/fuzz/ir/BUILD.bazel
new file mode 100644
index 0000000..7c71462
--- /dev/null
+++ b/src/tint/cmd/fuzz/ir/BUILD.bazel
@@ -0,0 +1,44 @@
+# Copyright 2023 The Dawn & Tint Authors
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# 1. Redistributions of source code must retain the above copyright notice, this
+#    list of conditions and the following disclaimer.
+#
+# 2. Redistributions in binary form must reproduce the above copyright notice,
+#    this list of conditions and the following disclaimer in the documentation
+#    and/or other materials provided with the distribution.
+#
+# 3. Neither the name of the copyright holder nor the names of its
+#    contributors may be used to endorse or promote products derived from
+#    this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+################################################################################
+# File generated by 'tools/src/cmd/gen' using the template:
+#   tools/src/cmd/gen/build/BUILD.bazel.tmpl
+#
+# To regenerate run: './tools/run gen'
+#
+#                       Do not modify this file directly
+################################################################################
+
+load("//src/tint:flags.bzl", "COPTS")
+load("@bazel_skylib//lib:selects.bzl", "selects")
+
+alias(
+  name = "tint_build_wgsl_reader",
+  actual = "//src/tint:tint_build_wgsl_reader_true",
+)
+
diff --git a/src/tint/cmd/fuzz/ir/BUILD.cmake b/src/tint/cmd/fuzz/ir/BUILD.cmake
new file mode 100644
index 0000000..87e9013
--- /dev/null
+++ b/src/tint/cmd/fuzz/ir/BUILD.cmake
@@ -0,0 +1,79 @@
+# Copyright 2023 The Dawn & Tint Authors
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# 1. Redistributions of source code must retain the above copyright notice, this
+#    list of conditions and the following disclaimer.
+#
+# 2. Redistributions in binary form must reproduce the above copyright notice,
+#    this list of conditions and the following disclaimer in the documentation
+#    and/or other materials provided with the distribution.
+#
+# 3. Neither the name of the copyright holder nor the names of its
+#    contributors may be used to endorse or promote products derived from
+#    this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+################################################################################
+# File generated by 'tools/src/cmd/gen' using the template:
+#   tools/src/cmd/gen/build/BUILD.cmake.tmpl
+#
+# To regenerate run: './tools/run gen'
+#
+#                       Do not modify this file directly
+################################################################################
+
+################################################################################
+# Target:    tint_cmd_fuzz_ir_fuzz
+# Kind:      fuzz
+################################################################################
+tint_add_target(tint_cmd_fuzz_ir_fuzz fuzz
+  cmd/fuzz/ir/fuzz.cc
+  cmd/fuzz/ir/fuzz.h
+)
+
+tint_target_add_dependencies(tint_cmd_fuzz_ir_fuzz fuzz
+  tint_api_common
+  tint_lang_core
+  tint_lang_core_constant
+  tint_lang_core_ir
+  tint_lang_core_type
+  tint_lang_wgsl
+  tint_lang_wgsl_ast
+  tint_lang_wgsl_common
+  tint_lang_wgsl_helpers
+  tint_lang_wgsl_program
+  tint_lang_wgsl_sem
+  tint_utils_bytes
+  tint_utils_containers
+  tint_utils_diagnostic
+  tint_utils_ice
+  tint_utils_id
+  tint_utils_macros
+  tint_utils_math
+  tint_utils_memory
+  tint_utils_reflection
+  tint_utils_result
+  tint_utils_rtti
+  tint_utils_symbol
+  tint_utils_text
+  tint_utils_traits
+)
+
+if(TINT_BUILD_WGSL_READER)
+  tint_target_add_dependencies(tint_cmd_fuzz_ir_fuzz fuzz
+    tint_cmd_fuzz_wgsl_fuzz
+    tint_lang_wgsl_reader
+  )
+endif(TINT_BUILD_WGSL_READER)
diff --git a/src/tint/cmd/fuzz/ir/BUILD.gn b/src/tint/cmd/fuzz/ir/BUILD.gn
new file mode 100644
index 0000000..e9c37c7
--- /dev/null
+++ b/src/tint/cmd/fuzz/ir/BUILD.gn
@@ -0,0 +1,80 @@
+# Copyright 2023 The Dawn & Tint Authors
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# 1. Redistributions of source code must retain the above copyright notice, this
+#    list of conditions and the following disclaimer.
+#
+# 2. Redistributions in binary form must reproduce the above copyright notice,
+#    this list of conditions and the following disclaimer in the documentation
+#    and/or other materials provided with the distribution.
+#
+# 3. Neither the name of the copyright holder nor the names of its
+#    contributors may be used to endorse or promote products derived from
+#    this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+################################################################################
+# File generated by 'tools/src/cmd/gen' using the template:
+#   tools/src/cmd/gen/build/BUILD.gn.tmpl
+#
+# To regenerate run: './tools/run gen'
+#
+#                       Do not modify this file directly
+################################################################################
+
+import("../../../../../scripts/tint_overrides_with_defaults.gni")
+
+import("${tint_src_dir}/tint.gni")
+
+tint_fuzz_source_set("fuzz") {
+  sources = [
+    "fuzz.cc",
+    "fuzz.h",
+  ]
+  deps = [
+    "${tint_src_dir}/api/common",
+    "${tint_src_dir}/lang/core",
+    "${tint_src_dir}/lang/core/constant",
+    "${tint_src_dir}/lang/core/ir",
+    "${tint_src_dir}/lang/core/type",
+    "${tint_src_dir}/lang/wgsl",
+    "${tint_src_dir}/lang/wgsl/ast",
+    "${tint_src_dir}/lang/wgsl/common",
+    "${tint_src_dir}/lang/wgsl/helpers",
+    "${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",
+    "${tint_src_dir}/utils/id",
+    "${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",
+    "${tint_src_dir}/utils/text",
+    "${tint_src_dir}/utils/traits",
+  ]
+
+  if (tint_build_wgsl_reader) {
+    deps += [
+      "${tint_src_dir}/cmd/fuzz/wgsl:fuzz",
+      "${tint_src_dir}/lang/wgsl/reader",
+    ]
+  }
+}
diff --git a/src/tint/cmd/fuzz/ir/fuzz.cc b/src/tint/cmd/fuzz/ir/fuzz.cc
new file mode 100644
index 0000000..fc96dcc
--- /dev/null
+++ b/src/tint/cmd/fuzz/ir/fuzz.cc
@@ -0,0 +1,100 @@
+// Copyright 2023 The Dawn & Tint Authors
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this
+//    list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice,
+//    this list of conditions and the following disclaimer in the documentation
+//    and/or other materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its
+//    contributors may be used to endorse or promote products derived from
+//    this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "src/tint/cmd/fuzz/ir/fuzz.h"
+
+#include "src/tint/utils/containers/vector.h"
+
+#if TINT_BUILD_WGSL_READER
+#include "src/tint/cmd/fuzz/wgsl/fuzz.h"
+#include "src/tint/lang/wgsl/ast/enable.h"
+#include "src/tint/lang/wgsl/ast/module.h"
+#include "src/tint/lang/wgsl/helpers/apply_substitute_overrides.h"
+#include "src/tint/lang/wgsl/reader/reader.h"
+#endif
+
+#include "src/tint/lang/core/ir/validator.h"
+
+#if TINT_BUILD_WGSL_READER
+namespace tint::fuzz::ir {
+namespace {
+
+bool IsUnsupported(const ast::Enable* enable) {
+    for (auto ext : enable->extensions) {
+        switch (ext->name) {
+            case tint::wgsl::Extension::kChromiumExperimentalDp4A:
+            case tint::wgsl::Extension::kChromiumExperimentalFullPtrParameters:
+            case tint::wgsl::Extension::kChromiumExperimentalPixelLocal:
+            case tint::wgsl::Extension::kChromiumExperimentalPushConstant:
+            case tint::wgsl::Extension::kChromiumInternalDualSourceBlending:
+            case tint::wgsl::Extension::kChromiumInternalRelaxedUniformLayout:
+                return true;
+            default:
+                break;
+        }
+    }
+    return false;
+}
+
+}  // namespace
+
+void Register(const IRFuzzer& fuzzer) {
+    wgsl::Register({
+        fuzzer.name,
+        [fn = fuzzer.fn](const Program& program, Slice<const std::byte> data) {
+            if (program.AST().Enables().Any(IsUnsupported)) {
+                return;
+            }
+
+            auto transformed = tint::wgsl::ApplySubstituteOverrides(program);
+            auto& src = transformed ? transformed.value() : program;
+            if (!src.IsValid()) {
+                return;
+            }
+
+            auto ir = tint::wgsl::reader::ProgramToLoweredIR(src);
+            if (!ir) {
+                return;
+            }
+
+            if (auto val = core::ir::Validate(ir.Get()); !val) {
+                TINT_ICE() << val.Failure();
+                return;
+            }
+
+            return fn(ir.Get(), data);
+        },
+    });
+}
+
+}  // namespace tint::fuzz::ir
+
+#else
+
+void tint::fuzz::ir::Register([[maybe_unused]] const IRFuzzer&) {}
+
+#endif
diff --git a/src/tint/cmd/fuzz/ir/fuzz.h b/src/tint/cmd/fuzz/ir/fuzz.h
new file mode 100644
index 0000000..897f6e1
--- /dev/null
+++ b/src/tint/cmd/fuzz/ir/fuzz.h
@@ -0,0 +1,89 @@
+// Copyright 2023 The Dawn & Tint Authors
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this
+//    list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice,
+//    this list of conditions and the following disclaimer in the documentation
+//    and/or other materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its
+//    contributors may be used to endorse or promote products derived from
+//    this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef SRC_TINT_CMD_FUZZ_IR_FUZZ_H_
+#define SRC_TINT_CMD_FUZZ_IR_FUZZ_H_
+
+#include <functional>
+#include <string>
+#include <tuple>
+#include <utility>
+
+#include "src/tint/utils/bytes/decoder.h"
+#include "src/tint/utils/containers/slice.h"
+#include "src/tint/utils/macros/static_init.h"
+
+namespace tint::core::ir {
+class Module;
+}
+
+namespace tint::fuzz::ir {
+
+/// IRFuzzer describes a fuzzer function that takes a IR module as input
+struct IRFuzzer {
+    /// @param name the name of the fuzzer
+    /// @param fn the fuzzer function
+    /// @returns an IRFuzzer that invokes the function @p fn with the IR module, along with any
+    /// additional arguments which are deserialized from the fuzzer input.
+    template <typename... ARGS>
+    static IRFuzzer Create(std::string_view name, void (*fn)(core::ir::Module&, ARGS...)) {
+        if constexpr (sizeof...(ARGS) > 0) {
+            auto fn_with_decode = [fn](core::ir::Module& module, 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<core::ir::Module&>{module}, data_args.Get());
+                    std::apply(*fn, all_args);
+                }
+            };
+            return IRFuzzer{name, std::move(fn_with_decode)};
+        } else {
+            return IRFuzzer{
+                name,
+                [fn](core::ir::Module& module, Slice<const std::byte>) { fn(module); },
+            };
+        }
+    }
+
+    /// Name of the fuzzer function
+    std::string_view name;
+    /// The fuzzer function
+    std::function<void(core::ir::Module&, Slice<const std::byte> data)> fn;
+};
+
+/// Registers the fuzzer function with the IR fuzzer executable.
+/// @param fuzzer the fuzzer
+void Register(const IRFuzzer& fuzzer);
+
+/// TINT_IR_MODULE_FUZZER registers the fuzzer function.
+#define TINT_IR_MODULE_FUZZER(FUNCTION) \
+    TINT_STATIC_INIT(                   \
+        ::tint::fuzz::ir::Register(::tint::fuzz::ir::IRFuzzer::Create(#FUNCTION, FUNCTION)))
+
+}  // namespace tint::fuzz::ir
+
+#endif  // SRC_TINT_CMD_FUZZ_IR_FUZZ_H_
diff --git a/src/tint/cmd/fuzz/wgsl/BUILD.cmake b/src/tint/cmd/fuzz/wgsl/BUILD.cmake
index b3f6717..90ab52d 100644
--- a/src/tint/cmd/fuzz/wgsl/BUILD.cmake
+++ b/src/tint/cmd/fuzz/wgsl/BUILD.cmake
@@ -45,6 +45,7 @@
 )
 
 tint_target_add_dependencies(tint_cmd_fuzz_wgsl_fuzz_cmd fuzz_cmd
+  tint_cmd_fuzz_ir_fuzz
   tint_lang_core
   tint_lang_core_constant
   tint_lang_core_type
diff --git a/src/tint/cmd/fuzz/wgsl/BUILD.gn b/src/tint/cmd/fuzz/wgsl/BUILD.gn
index f752d35..b853246 100644
--- a/src/tint/cmd/fuzz/wgsl/BUILD.gn
+++ b/src/tint/cmd/fuzz/wgsl/BUILD.gn
@@ -81,6 +81,7 @@
     output_name = "tint_wgsl_fuzzer"
     sources = [ "main_fuzz.cc" ]
     deps = [
+      "${tint_src_dir}/cmd/fuzz/ir:fuzz",
       "${tint_src_dir}/lang/core",
       "${tint_src_dir}/lang/core/constant",
       "${tint_src_dir}/lang/core/type",