Import Tint changes from Dawn

Changes:
  - 591f05655be3c53bccab2426cc23a47ebb7b2927 [tint][fuzzers] Port IRRoundtripFuzzer to tint_wgsl_fuzzer by Ben Clayton <bclayton@google.com>
  - 3fdd0eb605f3e74bcfb288fbb86ac6afb72ccbef [tint][fuzzers] Add AST ZeroInitWorkgroupMemory transform... by Ben Clayton <bclayton@google.com>
GitOrigin-RevId: 591f05655be3c53bccab2426cc23a47ebb7b2927
Change-Id: I9b742acaa89db40f338c8ac28e6d39185011a695
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/157780
Kokoro: Kokoro <noreply+kokoro@google.com>
Commit-Queue: Ben Clayton <bclayton@google.com>
Reviewed-by: Ben Clayton <bclayton@google.com>
diff --git a/src/tint/cmd/fuzz/wgsl/BUILD.cmake b/src/tint/cmd/fuzz/wgsl/BUILD.cmake
index 6046baf..b485bef 100644
--- a/src/tint/cmd/fuzz/wgsl/BUILD.cmake
+++ b/src/tint/cmd/fuzz/wgsl/BUILD.cmake
@@ -52,6 +52,7 @@
   tint_lang_wgsl_ast
   tint_lang_wgsl_program
   tint_lang_wgsl_sem
+  tint_lang_wgsl_fuzz
   tint_utils_containers
   tint_utils_diagnostic
   tint_utils_ice
@@ -69,6 +70,7 @@
 if(TINT_BUILD_WGSL_READER)
   tint_target_add_dependencies(tint_cmd_fuzz_wgsl_fuzz_cmd fuzz_cmd
     tint_cmd_fuzz_wgsl_fuzz
+    tint_lang_wgsl_ast_transform_fuzz
   )
 endif(TINT_BUILD_WGSL_READER)
 
diff --git a/src/tint/cmd/fuzz/wgsl/BUILD.gn b/src/tint/cmd/fuzz/wgsl/BUILD.gn
index 3748626..908cd3b 100644
--- a/src/tint/cmd/fuzz/wgsl/BUILD.gn
+++ b/src/tint/cmd/fuzz/wgsl/BUILD.gn
@@ -82,6 +82,7 @@
       "${tint_src_dir}/lang/core/constant",
       "${tint_src_dir}/lang/core/type",
       "${tint_src_dir}/lang/wgsl",
+      "${tint_src_dir}/lang/wgsl:fuzz",
       "${tint_src_dir}/lang/wgsl/ast",
       "${tint_src_dir}/lang/wgsl/program",
       "${tint_src_dir}/lang/wgsl/sem",
@@ -100,7 +101,10 @@
     ]
 
     if (tint_build_wgsl_reader) {
-      deps += [ "${tint_src_dir}/cmd/fuzz/wgsl:fuzz" ]
+      deps += [
+        "${tint_src_dir}/cmd/fuzz/wgsl:fuzz",
+        "${tint_src_dir}/lang/wgsl/ast/transform:fuzz",
+      ]
     }
   }
 }
diff --git a/src/tint/fuzzers/CMakeLists.txt b/src/tint/fuzzers/CMakeLists.txt
index 2330ec0..cd5a057 100644
--- a/src/tint/fuzzers/CMakeLists.txt
+++ b/src/tint/fuzzers/CMakeLists.txt
@@ -71,11 +71,6 @@
   add_tint_fuzzer(tint_wgsl_reader_spv_writer_fuzzer)
 endif()
 
-if (TINT_BUILD_WGSL_READER AND TINT_BUILD_WGSL_WRITER)
-  add_tint_fuzzer(tint_ir_roundtrip_fuzzer)
-  target_link_libraries(tint_ir_roundtrip_fuzzer PRIVATE tint_lang_wgsl_writer_ir_to_program)
-endif()
-
 if (${TINT_BUILD_WGSL_READER} AND ${TINT_BUILD_HLSL_WRITER})
   add_tint_fuzzer(tint_wgsl_reader_hlsl_writer_fuzzer)
 endif()
diff --git a/src/tint/fuzzers/tint_ir_roundtrip_fuzzer.cc b/src/tint/fuzzers/tint_ir_roundtrip_fuzzer.cc
deleted file mode 100644
index 9c888ec..0000000
--- a/src/tint/fuzzers/tint_ir_roundtrip_fuzzer.cc
+++ /dev/null
@@ -1,120 +0,0 @@
-// 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 <iostream>
-#include <string>
-#include <unordered_set>
-
-#include "src/tint/lang/wgsl/helpers/apply_substitute_overrides.h"
-#include "src/tint/lang/wgsl/reader/lower/lower.h"
-#include "src/tint/lang/wgsl/reader/parser/parser.h"
-#include "src/tint/lang/wgsl/reader/program_to_ir/program_to_ir.h"
-#include "src/tint/lang/wgsl/writer/ir_to_program/ir_to_program.h"
-#include "src/tint/lang/wgsl/writer/raise/raise.h"
-#include "src/tint/lang/wgsl/writer/writer.h"
-
-[[noreturn]] void TintInternalCompilerErrorReporter(const tint::InternalCompilerError& err) {
-    std::cerr << err.Error() << std::endl;
-    __builtin_trap();
-}
-
-extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
-    std::string str(reinterpret_cast<const char*>(data), size);
-
-    tint::SetInternalCompilerErrorReporter(&TintInternalCompilerErrorReporter);
-
-    tint::Source::File file("test.wgsl", str);
-
-    // Parse the wgsl, create the src program
-    tint::wgsl::reader::Parser parser(&file);
-    parser.set_max_errors(1);
-    if (!parser.Parse()) {
-        return 0;
-    }
-    auto src = parser.program();
-    if (!src.IsValid()) {
-        return 0;
-    }
-
-    auto is_unsupported = [](const tint::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;
-    };
-
-    if (src.AST().Enables().Any(is_unsupported)) {
-        return 0;
-    }
-
-    if (auto transformed = tint::wgsl::ApplySubstituteOverrides(src)) {
-        src = std::move(*transformed);
-        if (!src.IsValid()) {
-            return 0;
-        }
-    }
-
-    auto ir = tint::wgsl::reader::ProgramToIR(src);
-    if (!ir) {
-        std::cerr << ir.Failure() << std::endl;
-        __builtin_trap();
-    }
-
-    if (auto res = tint::wgsl::reader::Lower(ir.Get()); !res) {
-        std::cerr << res.Failure() << std::endl;
-        __builtin_trap();
-    }
-
-    if (auto res = tint::wgsl::writer::Raise(ir.Get()); !res) {
-        std::cerr << res.Failure() << std::endl;
-        __builtin_trap();
-    }
-
-    auto dst = tint::wgsl::writer::IRToProgram(ir.Get());
-    if (!dst.IsValid()) {
-#if TINT_BUILD_WGSL_WRITER
-        if (auto result = tint::wgsl::writer::Generate(dst, {}); result) {
-            std::cerr << result->wgsl << std::endl << std::endl;
-        }
-#endif
-
-        std::cerr << dst.Diagnostics() << std::endl;
-        __builtin_trap();
-    }
-
-    return 0;
-}
diff --git a/src/tint/lang/wgsl/BUILD.cmake b/src/tint/lang/wgsl/BUILD.cmake
index cf1d40c..cea7aa0 100644
--- a/src/tint/lang/wgsl/BUILD.cmake
+++ b/src/tint/lang/wgsl/BUILD.cmake
@@ -161,3 +161,60 @@
 tint_target_add_external_dependencies(tint_lang_wgsl_bench bench
   "google-benchmark"
 )
+
+################################################################################
+# Target:    tint_lang_wgsl_fuzz
+# Kind:      fuzz
+################################################################################
+tint_add_target(tint_lang_wgsl_fuzz fuzz
+)
+
+tint_target_add_dependencies(tint_lang_wgsl_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_helpers
+  tint_lang_wgsl_program
+  tint_lang_wgsl_reader_lower
+  tint_lang_wgsl_resolver
+  tint_lang_wgsl_sem
+  tint_lang_wgsl_writer_ir_to_program
+  tint_lang_wgsl_writer_raise
+  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_lang_wgsl_fuzz fuzz
+    tint_cmd_fuzz_wgsl_fuzz
+    tint_lang_wgsl_reader_parser
+    tint_lang_wgsl_reader_program_to_ir
+  )
+endif(TINT_BUILD_WGSL_READER)
+
+if(TINT_BUILD_WGSL_READER AND TINT_BUILD_WGSL_WRITER)
+  tint_target_add_sources(tint_lang_wgsl_fuzz fuzz
+    "lang/wgsl/ir_roundtrip_fuzz.cc"
+  )
+endif(TINT_BUILD_WGSL_READER AND TINT_BUILD_WGSL_WRITER)
+
+if(TINT_BUILD_WGSL_WRITER)
+  tint_target_add_dependencies(tint_lang_wgsl_fuzz fuzz
+    tint_lang_wgsl_writer
+  )
+endif(TINT_BUILD_WGSL_WRITER)
diff --git a/src/tint/lang/wgsl/BUILD.gn b/src/tint/lang/wgsl/BUILD.gn
index a2272f6..10d334a 100644
--- a/src/tint/lang/wgsl/BUILD.gn
+++ b/src/tint/lang/wgsl/BUILD.gn
@@ -141,3 +141,52 @@
     ]
   }
 }
+
+tint_fuzz_source_set("fuzz") {
+  sources = []
+  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/helpers",
+    "${tint_src_dir}/lang/wgsl/program",
+    "${tint_src_dir}/lang/wgsl/reader/lower",
+    "${tint_src_dir}/lang/wgsl/resolver",
+    "${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/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/parser",
+      "${tint_src_dir}/lang/wgsl/reader/program_to_ir",
+    ]
+  }
+
+  if (tint_build_wgsl_reader && tint_build_wgsl_writer) {
+    sources += [ "ir_roundtrip_fuzz.cc" ]
+  }
+
+  if (tint_build_wgsl_writer) {
+    deps += [ "${tint_src_dir}/lang/wgsl/writer" ]
+  }
+}
diff --git a/src/tint/lang/wgsl/ast/module.cc b/src/tint/lang/wgsl/ast/module.cc
index 82179d6..55e6142 100644
--- a/src/tint/lang/wgsl/ast/module.cc
+++ b/src/tint/lang/wgsl/ast/module.cc
@@ -138,6 +138,15 @@
     global_declarations_.Push(func);
 }
 
+bool Module::HasOverrides() const {
+    for (auto* var : global_variables_) {
+        if (var->As<ast::Override>()) {
+            return true;
+        }
+    }
+    return false;
+}
+
 const Module* Module::Clone(CloneContext& ctx) const {
     auto* out = ctx.dst->create<Module>();
     out->Copy(ctx, this);
diff --git a/src/tint/lang/wgsl/ast/module.h b/src/tint/lang/wgsl/ast/module.h
index df28de1..7214aec 100644
--- a/src/tint/lang/wgsl/ast/module.h
+++ b/src/tint/lang/wgsl/ast/module.h
@@ -141,6 +141,9 @@
     /// @returns the functions declared in the module
     const FunctionList& Functions() const { return functions_; }
 
+    /// @returns true if the module has any 'override' declarations
+    bool HasOverrides() const;
+
     /// Clones this node and all transitive child nodes using the `CloneContext`
     /// `ctx`.
     /// @param ctx the clone context
diff --git a/src/tint/lang/wgsl/ast/transform/BUILD.cfg b/src/tint/lang/wgsl/ast/transform/BUILD.cfg
index f31a82c..8c7d501 100644
--- a/src/tint/lang/wgsl/ast/transform/BUILD.cfg
+++ b/src/tint/lang/wgsl/ast/transform/BUILD.cfg
@@ -1,5 +1,8 @@
 {
     "test": {
         "condition": "tint_build_wgsl_reader && tint_build_wgsl_writer"
+    },
+    "fuzz": {
+        "condition": "tint_build_wgsl_reader"
     }
 }
diff --git a/src/tint/lang/wgsl/ast/transform/BUILD.cmake b/src/tint/lang/wgsl/ast/transform/BUILD.cmake
index 084ecbc..af6a354 100644
--- a/src/tint/lang/wgsl/ast/transform/BUILD.cmake
+++ b/src/tint/lang/wgsl/ast/transform/BUILD.cmake
@@ -220,4 +220,44 @@
   )
 endif(TINT_BUILD_WGSL_WRITER)
 
-endif(TINT_BUILD_WGSL_READER AND TINT_BUILD_WGSL_WRITER)
\ No newline at end of file
+endif(TINT_BUILD_WGSL_READER AND TINT_BUILD_WGSL_WRITER)
+if(TINT_BUILD_WGSL_READER)
+################################################################################
+# Target:    tint_lang_wgsl_ast_transform_fuzz
+# Kind:      fuzz
+# Condition: TINT_BUILD_WGSL_READER
+################################################################################
+tint_add_target(tint_lang_wgsl_ast_transform_fuzz fuzz
+  lang/wgsl/ast/transform/zero_init_workgroup_memory_fuzz.cc
+)
+
+tint_target_add_dependencies(tint_lang_wgsl_ast_transform_fuzz fuzz
+  tint_lang_core
+  tint_lang_core_constant
+  tint_lang_core_type
+  tint_lang_wgsl
+  tint_lang_wgsl_ast
+  tint_lang_wgsl_ast_transform
+  tint_lang_wgsl_program
+  tint_lang_wgsl_sem
+  tint_utils_containers
+  tint_utils_diagnostic
+  tint_utils_ice
+  tint_utils_id
+  tint_utils_macros
+  tint_utils_math
+  tint_utils_memory
+  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_lang_wgsl_ast_transform_fuzz fuzz
+    tint_cmd_fuzz_wgsl_fuzz
+  )
+endif(TINT_BUILD_WGSL_READER)
+
+endif(TINT_BUILD_WGSL_READER)
\ No newline at end of file
diff --git a/src/tint/lang/wgsl/ast/transform/BUILD.gn b/src/tint/lang/wgsl/ast/transform/BUILD.gn
index e39126f..46777b2 100644
--- a/src/tint/lang/wgsl/ast/transform/BUILD.gn
+++ b/src/tint/lang/wgsl/ast/transform/BUILD.gn
@@ -215,3 +215,34 @@
     }
   }
 }
+if (tint_build_wgsl_reader) {
+  tint_fuzz_source_set("fuzz") {
+    sources = [ "zero_init_workgroup_memory_fuzz.cc" ]
+    deps = [
+      "${tint_src_dir}/lang/core",
+      "${tint_src_dir}/lang/core/constant",
+      "${tint_src_dir}/lang/core/type",
+      "${tint_src_dir}/lang/wgsl",
+      "${tint_src_dir}/lang/wgsl/ast",
+      "${tint_src_dir}/lang/wgsl/ast/transform",
+      "${tint_src_dir}/lang/wgsl/program",
+      "${tint_src_dir}/lang/wgsl/sem",
+      "${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/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" ]
+    }
+  }
+}
diff --git a/src/tint/lang/wgsl/ast/transform/zero_init_workgroup_memory_fuzz.cc b/src/tint/lang/wgsl/ast/transform/zero_init_workgroup_memory_fuzz.cc
new file mode 100644
index 0000000..6c43dfb
--- /dev/null
+++ b/src/tint/lang/wgsl/ast/transform/zero_init_workgroup_memory_fuzz.cc
@@ -0,0 +1,38 @@
+// Copyright 2023 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "src/tint/lang/wgsl/ast/transform/zero_init_workgroup_memory.h"
+
+#include "src/tint/cmd/fuzz/wgsl/wgsl_fuzz.h"
+#include "src/tint/lang/wgsl/ast/module.h"
+
+namespace tint::ast::transform {
+
+void ZeroInitWorkgroupMemoryFuzzer(const tint::Program& program) {
+    if (program.AST().HasOverrides()) {
+        return;
+    }
+
+    DataMap outputs;
+    if (auto result = ZeroInitWorkgroupMemory{}.Apply(program, DataMap{}, outputs)) {
+        if (!result->IsValid()) {
+            TINT_ICE() << "ZeroInitWorkgroupMemory returned invalid program:\n"
+                       << result->Diagnostics();
+        }
+    }
+}
+
+}  // namespace tint::ast::transform
+
+TINT_WGSL_PROGRAM_FUZZER(tint::ast::transform::ZeroInitWorkgroupMemoryFuzzer);
diff --git a/src/tint/lang/wgsl/ir_roundtrip_fuzz.cc b/src/tint/lang/wgsl/ir_roundtrip_fuzz.cc
new file mode 100644
index 0000000..8671ac9
--- /dev/null
+++ b/src/tint/lang/wgsl/ir_roundtrip_fuzz.cc
@@ -0,0 +1,106 @@
+// 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.
+
+// GEN_BUILD:CONDITION(tint_build_wgsl_reader && tint_build_wgsl_writer)
+
+#include <iostream>
+
+#include "src/tint/cmd/fuzz/wgsl/wgsl_fuzz.h"
+#include "src/tint/lang/core/ir/disassembler.h"
+#include "src/tint/lang/wgsl/helpers/apply_substitute_overrides.h"
+#include "src/tint/lang/wgsl/reader/lower/lower.h"
+#include "src/tint/lang/wgsl/reader/parser/parser.h"
+#include "src/tint/lang/wgsl/reader/program_to_ir/program_to_ir.h"
+#include "src/tint/lang/wgsl/writer/ir_to_program/ir_to_program.h"
+#include "src/tint/lang/wgsl/writer/raise/raise.h"
+#include "src/tint/lang/wgsl/writer/writer.h"
+
+namespace tint::wgsl {
+namespace {
+
+bool IsUnsupported(const tint::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 IRRoundtripFuzzer(const tint::Program& program) {
+    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::ProgramToIR(src);
+    if (!ir) {
+        TINT_ICE() << ir.Failure();
+        return;
+    }
+
+    if (auto res = tint::wgsl::reader::Lower(ir.Get()); !res) {
+        TINT_ICE() << res.Failure();
+        return;
+    }
+
+    if (auto res = tint::wgsl::writer::Raise(ir.Get()); !res) {
+        TINT_ICE() << res.Failure();
+        return;
+    }
+
+    auto dst = tint::wgsl::writer::IRToProgram(ir.Get());
+    if (!dst.IsValid()) {
+        std::cerr << "IR:\n" << core::ir::Disassemble(ir.Get()) << std::endl;
+        if (auto result = tint::wgsl::writer::Generate(dst, {}); result) {
+            std::cerr << "WGSL:\n" << result->wgsl << std::endl << std::endl;
+        }
+        TINT_ICE() << dst.Diagnostics();
+        return;
+    }
+
+    return;
+}
+
+}  // namespace tint::wgsl
+
+TINT_WGSL_PROGRAM_FUZZER(tint::wgsl::IRRoundtripFuzzer);
diff --git a/src/tint/utils/containers/slice.h b/src/tint/utils/containers/slice.h
index ca309ee..b88863a 100644
--- a/src/tint/utils/containers/slice.h
+++ b/src/tint/utils/containers/slice.h
@@ -148,6 +148,11 @@
     constexpr Slice(T* d, size_t l, size_t c) : data(d), len(l), cap(c) {}
 
     /// Constructor
+    /// @param d pointer to the first element in the slice
+    /// @param l total number of elements in the slice
+    constexpr Slice(T* d, size_t l) : data(d), len(l), cap(l) {}
+
+    /// Constructor
     /// @param elements c-array of elements
     template <size_t N>
     constexpr Slice(T (&elements)[N])  // NOLINT