[fuzz] Reduce the amount of validation in IR fuzzer

Only validate at the beginning of the test case run, instead of per
fuzzing pass, since the switch to properties from capabilities means
the supported features can be tested without a full validation
run. This significantly improves performance for very large inputs.

(WGSL fuzzing still needs to per validation per pass, so that a bad
WGSL->IR conversion doesn't potentially cause per pass spurious issues
to be reported.)

Fixes: 547391714
Change-Id: I0b99b56036aad9a7388379cad7a88a2744808423
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/333115
Auto-Submit: Ryan Harrison <rharrison@chromium.org>
Reviewed-by: dan sinclair <dsinclair@chromium.org>
Commit-Queue: Ryan Harrison <rharrison@chromium.org>
Reviewed-by: James Price <jrprice@google.com>
Commit-Queue: James Price <jrprice@google.com>
diff --git a/src/tint/cmd/fuzz/ir/fuzz.cc b/src/tint/cmd/fuzz/ir/fuzz.cc
index 02b16b8..b27d640 100644
--- a/src/tint/cmd/fuzz/ir/fuzz.cc
+++ b/src/tint/cmd/fuzz/ir/fuzz.cc
@@ -96,10 +96,12 @@
                 return;
             }
 
-            // Validate the IR against the fuzzer's preconditions before running.
-            // We don't consider validation failure here to be an issue, as it only signals that
-            // there is a bug somewhere in the components run above. Those components have their own
-            // IR fuzzers.
+            // Validate the IR before running, because IR passes are not expected to handle invalid
+            // inputs, so don't want spurious reports if the pass crashes.
+            //
+            // NOTE: Do not ICE here, because there is other fuzzer passes that specifically check
+            // the WGSL->IR conversion doesn't create illegal IR. If an ICE occurred here it would
+            // create duplicate issues that obscures where the issue actually lies.
             if (!context.options.disable_ir_validator) {
                 if (auto val = core::ir::Validate(ir.Get(), "start " + std::string(fuzzer.name));
                     val != Success) {
@@ -158,6 +160,18 @@
     Context context;
     context.options = options;
 
+    if (!context.options.disable_ir_validator) {
+        auto mod = acquire_module();
+        // Inputs that fail validation should not be run against the fuzzing passes, since they are
+        // not expected to handle invalid inputs.
+        if (tint::core::ir::Validate(mod, "Pre-run validation") != tint::Success) {
+            if (context.options.verbose) {
+                std::cout << "Failed to validate before running\n";
+            }
+            return;
+        }
+    }
+
     // Run each of the program fuzzer functions
     tint::fuzz::common::RunFuzzers(Fuzzers(), options, [&](const IRFuzzer& fuzzer, size_t i) {
         currently_running = fuzzer.name;
@@ -181,18 +195,6 @@
             return;
         }
 
-        if (!context.options.disable_ir_validator) {
-            if (tint::core::ir::Validate(mod, "start " + std::string(currently_running)) !=
-                tint::Success) {
-                // Failing before running indicates that this input violates the pre-conditions
-                // for this pass, so should be skipped.
-                if (context.options.verbose) {
-                    std::cout << "   Failed to validate before running\n";
-                }
-                return;
-            }
-        }
-
         // Enable validation assertions.
         // Any validation failure after this point is a bug in Tint which we want to find.
         mod.enable_validation_asserts = !context.options.disable_ir_validator;