Convert fuzzer to generating configuration data

This is instead of consuming a portion of the input, so that the seed
corpus of valid shaders can be more effective.

BUG=tint:1098

Change-Id: If3696527c82c23b09edeea6ddd2a0f935e5e1ac7
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/63301
Auto-Submit: Ryan Harrison <rharrison@chromium.org>
Commit-Queue: Ben Clayton <bclayton@google.com>
Kokoro: Kokoro <noreply+kokoro@google.com>
Reviewed-by: Ben Clayton <bclayton@google.com>
diff --git a/fuzzers/CMakeLists.txt b/fuzzers/CMakeLists.txt
index 6b962d7..f50ec56 100644
--- a/fuzzers/CMakeLists.txt
+++ b/fuzzers/CMakeLists.txt
@@ -99,6 +99,8 @@
     AND ${TINT_BUILD_SPV_WRITER}
     AND ${TINT_BUILD_WGSL_WRITER})
   add_executable(tint_black_box_fuzz_target
+    random_generator.cc
+    random_generator.h
     tint_black_box_fuzz_target
     tint_common_fuzzer.cc
     tint_common_fuzzer.h
diff --git a/fuzzers/random_generator.cc b/fuzzers/random_generator.cc
index 18b88fe..73c594c 100644
--- a/fuzzers/random_generator.cc
+++ b/fuzzers/random_generator.cc
@@ -18,6 +18,8 @@
 #include <cassert>
 #include <vector>
 
+#include "src/utils/hash.h"
+
 namespace tint {
 namespace fuzzers {
 
@@ -38,7 +40,7 @@
 
 }  // namespace
 
-RandomGenerator::RandomGenerator(uint32_t seed) : engine_(seed) {}
+RandomGenerator::RandomGenerator(uint64_t seed) : engine_(seed) {}
 
 uint32_t RandomGenerator::GetUInt32(uint32_t lower, uint32_t upper) {
   return RandomUInt(&engine_, lower, upper);
@@ -66,12 +68,11 @@
   return std::independent_bits_engine<std::mt19937, 32, uint32_t>(engine_)();
 }
 
-std::vector<uint8_t> RandomGenerator::GetNBytes(size_t n) {
-  std::vector<uint8_t> result(n);
+void RandomGenerator::GetNBytes(uint8_t* dest, size_t n) {
+  assert(dest && "|dest| must not be nullptr");
   std::generate(
-      std::begin(result), std::end(result),
+      dest, dest + n,
       std::independent_bits_engine<std::mt19937, 8, uint8_t>(engine_));
-  return result;
 }
 
 bool RandomGenerator::GetBool() {
@@ -85,5 +86,31 @@
   return RandomUInt(&engine_, 0u, kMaxPercentage) < percentage;
 }
 
+uint64_t RandomGenerator::CalculateSeed(const uint8_t* data, size_t size) {
+  assert(data != nullptr && "|data| must be !nullptr");
+  assert(size > 0 && "|size| must be > 0");
+
+  // Number of bytes we want to skip at the start of data for the hash.
+  // Fewer bytes may be skipped when `size` is small.
+  // Has lower precedence than kHashDesiredMinBytes.
+  static const int64_t kHashDesiredLeadingSkipBytes = 5;
+  // Minimum number of bytes we want to use in the hash.
+  // Used for short buffers.
+  static const int64_t kHashDesiredMinBytes = 4;
+  // Maximum number of bytes we want to use in the hash.
+  static const int64_t kHashDesiredMaxBytes = 32;
+  int64_t size_i64 = static_cast<int64_t>(size);
+  int64_t hash_begin_i64 =
+      std::min(kHashDesiredLeadingSkipBytes,
+               std::max<int64_t>(size_i64 - kHashDesiredMinBytes, 0));
+  int64_t hash_end_i64 =
+      std::max(hash_begin_i64 + kHashDesiredMaxBytes, size_i64);
+  size_t hash_begin = static_cast<size_t>(hash_begin_i64);
+  size_t hash_size = static_cast<size_t>(hash_end_i64) - hash_begin;
+  std::vector<uint8_t> hash_portion(data + hash_begin,
+                                    data + hash_begin + hash_size + 1);
+  return tint::utils::Hash(hash_portion);
+}
+
 }  // namespace fuzzers
 }  // namespace tint
diff --git a/fuzzers/random_generator.h b/fuzzers/random_generator.h
index c90a3e7..6cb5093 100644
--- a/fuzzers/random_generator.h
+++ b/fuzzers/random_generator.h
@@ -26,7 +26,7 @@
  public:
   /// @brief Initializes the internal engine
   /// @param seed - seed value passed to engine
-  explicit RandomGenerator(uint32_t seed);
+  explicit RandomGenerator(uint64_t seed);
   ~RandomGenerator() {}
 
   /// Get uint32_t value from uniform distribution.
@@ -62,9 +62,9 @@
   uint32_t Get4Bytes();
 
   /// Get N bytes of pseudo-random data
+  /// @param dest - memory location to store data
   /// @param n - number of bytes of data to generate
-  /// @returns |N|-bytes of random data as vector
-  std::vector<uint8_t> GetNBytes(size_t n);
+  void GetNBytes(uint8_t* dest, size_t n);
 
   /// Get random bool with even odds
   /// @returns true 50% of the time and false %50 of time.
@@ -76,6 +76,13 @@
   /// of the time.
   bool GetWeightedBool(uint32_t percentage);
 
+  /// Calculate a seed value based on a blob of data.
+  /// Currently hashes bytes near the front of the buffer, after skipping N
+  /// bytes.
+  /// @param data - pointer to data to base calculation off of, must be !nullptr
+  /// @param size - number of elements in |data|, must be > 0
+  static uint64_t CalculateSeed(const uint8_t* data, size_t size);
+
  private:
   std::mt19937 engine_;
 
diff --git a/fuzzers/tint_all_transforms_fuzzer.cc b/fuzzers/tint_all_transforms_fuzzer.cc
index 05c6e42..083ee28 100644
--- a/fuzzers/tint_all_transforms_fuzzer.cc
+++ b/fuzzers/tint_all_transforms_fuzzer.cc
@@ -12,6 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+#include "fuzzers/random_generator.h"
 #include "fuzzers/tint_common_fuzzer.h"
 #include "fuzzers/tint_init_fuzzer.h"
 
@@ -19,17 +20,17 @@
 namespace fuzzers {
 
 struct Config {
-  Config(const uint8_t* data, size_t size) : reader(data, size) {}
-  Reader reader;
+  Config(const uint8_t* data, size_t size) : builder(data, size) {}
+  DataBuilder builder;
   transform::Manager manager;
   transform::DataMap inputs;
 };
 
-bool AddPlatformIndependentPasses(Config* config) {
-  ExtractFirstIndexOffsetInputs(&config->reader, &config->inputs);
-  ExtractBindingRemapperInputs(&config->reader, &config->inputs);
-  ExtractSingleEntryPointInputs(&config->reader, &config->inputs);
-  ExtractVertexPullingInputs(&config->reader, &config->inputs);
+void AddPlatformIndependentPasses(Config* config) {
+  GenerateFirstIndexOffsetInputs(&config->builder, &config->inputs);
+  GenerateBindingRemapperInputs(&config->builder, &config->inputs);
+  GenerateSingleEntryPointInputs(&config->builder, &config->inputs);
+  GenerateVertexPullingInputs(&config->builder, &config->inputs);
 
   config->manager.Add<transform::Robustness>();
   config->manager.Add<transform::FirstIndexOffset>();
@@ -37,69 +38,55 @@
   config->manager.Add<transform::Renamer>();
   config->manager.Add<tint::transform::SingleEntryPoint>();
   config->manager.Add<tint::transform::VertexPulling>();
-
-  return !config->reader.failed();
 }
 
 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
   {
     Config config(data, size);
-
-    if (!AddPlatformIndependentPasses(&config)) {
-      return 0;
-    }
+    AddPlatformIndependentPasses(&config);
 
     fuzzers::CommonFuzzer fuzzer(InputFormat::kWGSL, OutputFormat::kSpv);
     fuzzer.SetTransformManager(&(config.manager), std::move(config.inputs));
     fuzzer.SetDumpInput(GetCliParams().dump_input);
 
-    fuzzer.Run(config.reader.data(), config.reader.size());
+    fuzzer.Run(data, size);
   }
 
 #if TINT_BUILD_HLSL_WRITER
   {
     Config config(data, size);
-
-    if (!AddPlatformIndependentPasses(&config)) {
-      return 0;
-    }
+    AddPlatformIndependentPasses(&config);
 
     fuzzers::CommonFuzzer fuzzer(InputFormat::kWGSL, OutputFormat::kHLSL);
     fuzzer.SetTransformManager(&config.manager, std::move(config.inputs));
     fuzzer.SetDumpInput(GetCliParams().dump_input);
 
-    fuzzer.Run(config.reader.data(), config.reader.size());
+    fuzzer.Run(data, size);
   }
 #endif  // TINT_BUILD_HLSL_WRITER
 
 #if TINT_BUILD_MSL_WRITER
   {
     Config config(data, size);
-
-    if (!AddPlatformIndependentPasses(&config)) {
-      return 0;
-    }
+    AddPlatformIndependentPasses(&config);
 
     fuzzers::CommonFuzzer fuzzer(InputFormat::kWGSL, OutputFormat::kMSL);
     fuzzer.SetTransformManager(&config.manager, std::move(config.inputs));
     fuzzer.SetDumpInput(GetCliParams().dump_input);
 
-    fuzzer.Run(config.reader.data(), config.reader.size());
+    fuzzer.Run(data, size);
   }
 #endif  // TINT_BUILD_MSL_WRITER
 #if TINT_BUILD_SPV_WRITER
   {
     Config config(data, size);
-
-    if (!AddPlatformIndependentPasses(&config)) {
-      return 0;
-    }
+    AddPlatformIndependentPasses(&config);
 
     fuzzers::CommonFuzzer fuzzer(InputFormat::kWGSL, OutputFormat::kSpv);
     fuzzer.SetTransformManager(&config.manager, std::move(config.inputs));
     fuzzer.SetDumpInput(GetCliParams().dump_input);
 
-    fuzzer.Run(config.reader.data(), config.reader.size());
+    fuzzer.Run(data, size);
   }
 #endif  // TINT_BUILD_SPV_WRITER
 
diff --git a/fuzzers/tint_binding_remapper_fuzzer.cc b/fuzzers/tint_binding_remapper_fuzzer.cc
index a4d489a..c701078 100644
--- a/fuzzers/tint_binding_remapper_fuzzer.cc
+++ b/fuzzers/tint_binding_remapper_fuzzer.cc
@@ -21,12 +21,9 @@
 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
   transform::Manager transform_manager;
   transform::DataMap transform_inputs;
-  Reader r(data, size);
+  DataBuilder b(data, size);
 
-  ExtractBindingRemapperInputs(&r, &transform_inputs);
-  if (r.failed()) {
-    return 0;
-  }
+  GenerateBindingRemapperInputs(&b, &transform_inputs);
 
   transform_manager.Add<tint::transform::BindingRemapper>();
 
@@ -34,7 +31,7 @@
   fuzzer.SetTransformManager(&transform_manager, std::move(transform_inputs));
   fuzzer.SetDumpInput(GetCliParams().dump_input);
 
-  return fuzzer.Run(r.data(), r.size());
+  return fuzzer.Run(data, size);
 }
 
 }  // namespace fuzzers
diff --git a/fuzzers/tint_black_box_fuzz_target.cc b/fuzzers/tint_black_box_fuzz_target.cc
index f05a255..95ed578 100644
--- a/fuzzers/tint_black_box_fuzz_target.cc
+++ b/fuzzers/tint_black_box_fuzz_target.cc
@@ -47,7 +47,7 @@
   }
 
   fseek(file, 0, SEEK_END);
-  uint64_t tell_file_size = static_cast<uint64_t>(ftell(file));
+  auto tell_file_size = ftell(file);
   if (tell_file_size <= 0) {
     std::cerr << "Input file of incorrect size: " << input_file << std::endl;
     fclose(file);
@@ -99,21 +99,21 @@
                                        tint::fuzzers::OutputFormat::kHLSL);
     return fuzzer.Run(data.data(), data.size());
   } else if (target_format == "msl") {
-    tint::fuzzers::Reader reader(data.data(), data.size());
+    tint::fuzzers::DataBuilder builder(data.data(), data.size());
     tint::writer::msl::Options options;
-    ExtractMslOptions(&reader, &options);
+    GenerateMslOptions(&builder, &options);
     tint::fuzzers::CommonFuzzer fuzzer(tint::fuzzers::InputFormat::kWGSL,
                                        tint::fuzzers::OutputFormat::kMSL);
     fuzzer.SetOptionsMsl(options);
-    return fuzzer.Run(reader.data(), reader.size());
+    return fuzzer.Run(data.data(), data.size());
   } else if (target_format == "spv") {
-    tint::fuzzers::Reader reader(data.data(), data.size());
+    tint::fuzzers::DataBuilder builder(data.data(), data.size());
     tint::writer::spirv::Options options;
-    ExtractSpirvOptions(&reader, &options);
+    GenerateSpirvOptions(&builder, &options);
     tint::fuzzers::CommonFuzzer fuzzer(tint::fuzzers::InputFormat::kWGSL,
                                        tint::fuzzers::OutputFormat::kSpv);
     fuzzer.SetOptionsSpirv(options);
-    return fuzzer.Run(reader.data(), reader.size());
+    return fuzzer.Run(data.data(), data.size());
   } else if (target_format == "wgsl") {
     tint::fuzzers::CommonFuzzer fuzzer(tint::fuzzers::InputFormat::kWGSL,
                                        tint::fuzzers::OutputFormat::kWGSL);
diff --git a/fuzzers/tint_common_fuzzer.cc b/fuzzers/tint_common_fuzzer.cc
index bc6b765..f15c733 100644
--- a/fuzzers/tint_common_fuzzer.cc
+++ b/fuzzers/tint_common_fuzzer.cc
@@ -14,6 +14,7 @@
 
 #include "fuzzers/tint_common_fuzzer.h"
 
+#include <cassert>
 #include <cstring>
 #include <fstream>
 #include <memory>
@@ -51,23 +52,23 @@
   FatalError(diagnostics);
 }
 
-transform::VertexAttributeDescriptor ExtractVertexAttributeDescriptor(
-    Reader* r) {
+transform::VertexAttributeDescriptor GenerateVertexAttributeDescriptor(
+    DataBuilder* b) {
   transform::VertexAttributeDescriptor desc{};
-  desc.format = r->enum_class<transform::VertexFormat>(
+  desc.format = b->enum_class<transform::VertexFormat>(
       static_cast<uint8_t>(transform::VertexFormat::kLastEntry) + 1);
-  desc.offset = r->read<uint32_t>();
-  desc.shader_location = r->read<uint32_t>();
+  desc.offset = b->build<uint32_t>();
+  desc.shader_location = b->build<uint32_t>();
   return desc;
 }
 
-transform::VertexBufferLayoutDescriptor ExtractVertexBufferLayoutDescriptor(
-    Reader* r) {
+transform::VertexBufferLayoutDescriptor GenerateVertexBufferLayoutDescriptor(
+    DataBuilder* b) {
   transform::VertexBufferLayoutDescriptor desc;
-  desc.array_stride = r->read<uint32_t>();
-  desc.step_mode = r->enum_class<transform::VertexStepMode>(
+  desc.array_stride = b->build<uint32_t>();
+  desc.step_mode = b->enum_class<transform::VertexStepMode>(
       static_cast<uint8_t>(transform::VertexStepMode::kLastEntry) + 1);
-  desc.attributes = r->vector(ExtractVertexAttributeDescriptor);
+  desc.attributes = b->vector(GenerateVertexAttributeDescriptor);
   return desc;
 }
 
@@ -93,36 +94,28 @@
 
 }  // namespace
 
-Reader::Reader(const uint8_t* data, size_t size) : data_(data), size_(size) {}
+DataBuilder::DataBuilder(const uint8_t* data, size_t size)
+    : generator_(RandomGenerator::CalculateSeed(data, size)) {}
 
-std::string Reader::string() {
-  auto count = read<uint8_t>();
-  if (failed_ || size_ < count) {
-    mark_failed();
+std::string DataBuilder::string() {
+  auto count = build<uint8_t>();
+  if (count == 0) {
     return "";
   }
-  std::string out(data_, data_ + count);
-  data_ += count;
-  size_ -= count;
-  return out;
+  std::vector<uint8_t> source(count);
+  build(source.data(), count);
+  return std::string(source.begin(), source.end());
 }
 
-void Reader::mark_failed() {
-  size_ = 0;
-  failed_ = true;
+void DataBuilder::build(void* out, size_t n) {
+  assert(out != nullptr && "|out| cannot be nullptr");
+  assert(n > 0 && "|n| must be > 0");
+
+  generator_.GetNBytes(reinterpret_cast<uint8_t*>(out), n);
 }
 
-void Reader::read(void* out, size_t n) {
-  if (n > size_) {
-    mark_failed();
-    return;
-  }
-  memcpy(out, data_, n);
-  data_ += n;
-  size_ -= n;
-}
-
-void ExtractBindingRemapperInputs(Reader* r, tint::transform::DataMap* inputs) {
+void GenerateBindingRemapperInputs(DataBuilder* b,
+                                   tint::transform::DataMap* inputs) {
   struct Config {
     uint8_t old_group;
     uint8_t old_binding;
@@ -131,7 +124,7 @@
     ast::Access new_access;
   };
 
-  std::vector<Config> configs = r->vector<Config>();
+  std::vector<Config> configs = b->vector<Config>();
   transform::BindingRemapper::BindingPoints binding_points;
   transform::BindingRemapper::AccessControls accesses;
   for (const auto& config : configs) {
@@ -143,47 +136,48 @@
   inputs->Add<transform::BindingRemapper::Remappings>(binding_points, accesses);
 }
 
-void ExtractFirstIndexOffsetInputs(Reader* r,
-                                   tint::transform::DataMap* inputs) {
+void GenerateFirstIndexOffsetInputs(DataBuilder* b,
+                                    tint::transform::DataMap* inputs) {
   struct Config {
     uint32_t group;
     uint32_t binding;
   };
 
-  Config config = r->read<Config>();
+  Config config = b->build<Config>();
   inputs->Add<tint::transform::FirstIndexOffset::BindingPoint>(config.binding,
                                                                config.group);
 }
 
-void ExtractSingleEntryPointInputs(Reader* r,
-                                   tint::transform::DataMap* inputs) {
-  std::string input = r->string();
+void GenerateSingleEntryPointInputs(DataBuilder* b,
+                                    tint::transform::DataMap* inputs) {
+  std::string input = b->string();
   transform::SingleEntryPoint::Config cfg(input);
   inputs->Add<transform::SingleEntryPoint::Config>(cfg);
 }
 
-void ExtractVertexPullingInputs(Reader* r, tint::transform::DataMap* inputs) {
+void GenerateVertexPullingInputs(DataBuilder* b,
+                                 tint::transform::DataMap* inputs) {
   transform::VertexPulling::Config cfg;
-  cfg.entry_point_name = r->string();
-  cfg.vertex_state = r->vector(ExtractVertexBufferLayoutDescriptor);
-  cfg.pulling_group = r->read<uint32_t>();
+  cfg.entry_point_name = b->string();
+  cfg.vertex_state = b->vector(GenerateVertexBufferLayoutDescriptor);
+  cfg.pulling_group = b->build<uint32_t>();
   inputs->Add<transform::VertexPulling::Config>(cfg);
 }
 
-void ExtractSpirvOptions(Reader* r, writer::spirv::Options* options) {
-  *options = r->read<writer::spirv::Options>();
+void GenerateSpirvOptions(DataBuilder* b, writer::spirv::Options* options) {
+  *options = b->build<writer::spirv::Options>();
 }
 
-void ExtractWgslOptions(Reader* r, writer::wgsl::Options* options) {
-  *options = r->read<writer::wgsl::Options>();
+void GenerateWgslOptions(DataBuilder* b, writer::wgsl::Options* options) {
+  *options = b->build<writer::wgsl::Options>();
 }
 
-void ExtractHlslOptions(Reader* r, writer::hlsl::Options* options) {
-  *options = r->read<writer::hlsl::Options>();
+void GenerateHlslOptions(DataBuilder* b, writer::hlsl::Options* options) {
+  *options = b->build<writer::hlsl::Options>();
 }
 
-void ExtractMslOptions(Reader* r, writer::msl::Options* options) {
-  *options = r->read<writer::msl::Options>();
+void GenerateMslOptions(DataBuilder* b, writer::msl::Options* options) {
+  *options = b->build<writer::msl::Options>();
 }
 
 CommonFuzzer::CommonFuzzer(InputFormat input, OutputFormat output)
diff --git a/fuzzers/tint_common_fuzzer.h b/fuzzers/tint_common_fuzzer.h
index d955b01..96aac01 100644
--- a/fuzzers/tint_common_fuzzer.h
+++ b/fuzzers/tint_common_fuzzer.h
@@ -21,23 +21,20 @@
 #include <utility>
 #include <vector>
 
+#include "fuzzers/random_generator.h"
 #include "include/tint/tint.h"
 
 namespace tint {
 namespace fuzzers {
 
-class Reader {
+class DataBuilder {
  public:
-  Reader(const uint8_t* data, size_t size);
-
-  bool failed() const { return failed_; }
-  const uint8_t* data() { return data_; }
-  size_t size() const { return size_; }
+  DataBuilder(const uint8_t* data, size_t size);
 
   template <typename T>
-  T read() {
+  T build() {
     T out{};
-    read(&out, sizeof(T));
+    build(&out, sizeof(T));
     return out;
   }
 
@@ -45,66 +42,48 @@
 
   template <typename T>
   std::vector<T> vector() {
-    auto count = read<uint8_t>();
-    auto size = static_cast<size_t>(count) * sizeof(T);
-    if (failed_ || size_ < size) {
-      mark_failed();
-      return {};
-    }
+    auto count = build<uint8_t>();
     std::vector<T> out(count);
-    if (!out.empty()) {
-      memcpy(out.data(), data_, size);
-      data_ += size;
-      size_ -= size;
+    for (uint8_t i = 0; i < count; i++) {
+      out[i] = build<T>();
     }
     return out;
   }
 
   template <typename T>
-  std::vector<T> vector(T (*extract)(Reader*)) {
-    auto count = read<uint8_t>();
-    if (failed_) {
-      return {};
-    }
+  std::vector<T> vector(T (*generate)(DataBuilder*)) {
+    auto count = build<uint8_t>();
     std::vector<T> out(count);
     for (uint8_t i = 0; i < count; i++) {
-      out[i] = extract(this);
-      if (failed_) {
-        return {};
-      }
+      out[i] = generate(this);
     }
     return out;
   }
+
   template <typename T>
   T enum_class(uint8_t count) {
-    auto val = read<uint8_t>();
+    auto val = build<uint8_t>();
     return static_cast<T>(val % count);
   }
 
  private:
-  void mark_failed();
-  void read(void* out, size_t n);
+  void build(void* out, size_t n);
 
-  const uint8_t* data_;
-  size_t size_;
-  bool failed_ = false;
+  RandomGenerator generator_;
 };
 
-void ExtractBindingRemapperInputs(Reader* r, tint::transform::DataMap* inputs);
-
-void ExtractFirstIndexOffsetInputs(Reader* r, tint::transform::DataMap* inputs);
-
-void ExtractSingleEntryPointInputs(Reader* r, tint::transform::DataMap* inputs);
-
-void ExtractVertexPullingInputs(Reader* r, tint::transform::DataMap* inputs);
-
-void ExtractSpirvOptions(Reader* r, writer::spirv::Options* options);
-
-void ExtractWgslOptions(Reader* r, writer::wgsl::Options* options);
-
-void ExtractHlslOptions(Reader* r, writer::hlsl::Options* options);
-
-void ExtractMslOptions(Reader* r, writer::msl::Options* options);
+void GenerateBindingRemapperInputs(DataBuilder* b,
+                                   tint::transform::DataMap* inputs);
+void GenerateFirstIndexOffsetInputs(DataBuilder* b,
+                                    tint::transform::DataMap* inputs);
+void GenerateSingleEntryPointInputs(DataBuilder* b,
+                                    tint::transform::DataMap* inputs);
+void GenerateVertexPullingInputs(DataBuilder* b,
+                                 tint::transform::DataMap* inputs);
+void GenerateSpirvOptions(DataBuilder* b, writer::spirv::Options* options);
+void GenerateWgslOptions(DataBuilder* b, writer::wgsl::Options* options);
+void GenerateHlslOptions(DataBuilder* b, writer::hlsl::Options* options);
+void GenerateMslOptions(DataBuilder* b, writer::msl::Options* options);
 
 enum class InputFormat { kWGSL, kSpv, kNone };
 
diff --git a/fuzzers/tint_first_index_offset_fuzzer.cc b/fuzzers/tint_first_index_offset_fuzzer.cc
index 7cf5890..cf96e4a 100644
--- a/fuzzers/tint_first_index_offset_fuzzer.cc
+++ b/fuzzers/tint_first_index_offset_fuzzer.cc
@@ -21,20 +21,16 @@
 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
   tint::transform::Manager transform_manager;
   tint::transform::DataMap transform_inputs;
-  Reader r(data, size);
+  DataBuilder b(data, size);
 
-  ExtractFirstIndexOffsetInputs(&r, &transform_inputs);
-  if (r.failed()) {
-    return 0;
-  }
-
+  GenerateFirstIndexOffsetInputs(&b, &transform_inputs);
   transform_manager.Add<tint::transform::FirstIndexOffset>();
 
   tint::fuzzers::CommonFuzzer fuzzer(InputFormat::kWGSL, OutputFormat::kWGSL);
   fuzzer.SetTransformManager(&transform_manager, std::move(transform_inputs));
   fuzzer.SetDumpInput(GetCliParams().dump_input);
 
-  return fuzzer.Run(r.data(), r.size());
+  return fuzzer.Run(data, size);
 }
 
 }  // namespace fuzzers
diff --git a/fuzzers/tint_single_entry_point_fuzzer.cc b/fuzzers/tint_single_entry_point_fuzzer.cc
index cc5dbce..988e4d2 100644
--- a/fuzzers/tint_single_entry_point_fuzzer.cc
+++ b/fuzzers/tint_single_entry_point_fuzzer.cc
@@ -21,20 +21,16 @@
 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
   tint::transform::Manager transform_manager;
   tint::transform::DataMap transform_inputs;
-  Reader r(data, size);
+  DataBuilder b(data, size);
 
-  ExtractSingleEntryPointInputs(&r, &transform_inputs);
-  if (r.failed()) {
-    return 0;
-  }
-
+  GenerateSingleEntryPointInputs(&b, &transform_inputs);
   transform_manager.Add<tint::transform::SingleEntryPoint>();
 
   tint::fuzzers::CommonFuzzer fuzzer(InputFormat::kWGSL, OutputFormat::kWGSL);
   fuzzer.SetTransformManager(&transform_manager, std::move(transform_inputs));
   fuzzer.SetDumpInput(GetCliParams().dump_input);
 
-  return fuzzer.Run(r.data(), r.size());
+  return fuzzer.Run(data, size);
 }
 
 }  // namespace fuzzers
diff --git a/fuzzers/tint_spv_reader_msl_writer_fuzzer.cc b/fuzzers/tint_spv_reader_msl_writer_fuzzer.cc
index 80c95b2..6117d01 100644
--- a/fuzzers/tint_spv_reader_msl_writer_fuzzer.cc
+++ b/fuzzers/tint_spv_reader_msl_writer_fuzzer.cc
@@ -21,13 +21,13 @@
 namespace fuzzers {
 
 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
-  Reader reader(data, size);
+  DataBuilder b(data, size);
   writer::msl::Options options;
-  ExtractMslOptions(&reader, &options);
+  GenerateMslOptions(&b, &options);
   tint::fuzzers::CommonFuzzer fuzzer(InputFormat::kSpv, OutputFormat::kMSL);
   fuzzer.SetOptionsMsl(options);
   fuzzer.SetDumpInput(GetCliParams().dump_input);
-  return fuzzer.Run(reader.data(), reader.size());
+  return fuzzer.Run(data, size);
 }
 
 }  // namespace fuzzers
diff --git a/fuzzers/tint_spv_reader_spv_writer_fuzzer.cc b/fuzzers/tint_spv_reader_spv_writer_fuzzer.cc
index e323741..3d1a5c5 100644
--- a/fuzzers/tint_spv_reader_spv_writer_fuzzer.cc
+++ b/fuzzers/tint_spv_reader_spv_writer_fuzzer.cc
@@ -21,13 +21,13 @@
 namespace fuzzers {
 
 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
-  Reader reader(data, size);
+  DataBuilder b(data, size);
   writer::spirv::Options options;
-  ExtractSpirvOptions(&reader, &options);
+  GenerateSpirvOptions(&b, &options);
   tint::fuzzers::CommonFuzzer fuzzer(InputFormat::kSpv, OutputFormat::kSpv);
   fuzzer.SetOptionsSpirv(options);
   fuzzer.SetDumpInput(GetCliParams().dump_input);
-  return fuzzer.Run(reader.data(), reader.size());
+  return fuzzer.Run(data, size);
 }
 
 }  // namespace fuzzers
diff --git a/fuzzers/tint_vertex_pulling_fuzzer.cc b/fuzzers/tint_vertex_pulling_fuzzer.cc
index a92f9b2..a4f33a4 100644
--- a/fuzzers/tint_vertex_pulling_fuzzer.cc
+++ b/fuzzers/tint_vertex_pulling_fuzzer.cc
@@ -21,20 +21,16 @@
 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
   tint::transform::Manager transform_manager;
   tint::transform::DataMap transform_inputs;
-  Reader r(data, size);
+  DataBuilder b(data, size);
 
-  ExtractVertexPullingInputs(&r, &transform_inputs);
-  if (r.failed()) {
-    return 0;
-  }
-
+  GenerateVertexPullingInputs(&b, &transform_inputs);
   transform_manager.Add<tint::transform::VertexPulling>();
 
   tint::fuzzers::CommonFuzzer fuzzer(InputFormat::kWGSL, OutputFormat::kWGSL);
   fuzzer.SetTransformManager(&transform_manager, std::move(transform_inputs));
   fuzzer.SetDumpInput(GetCliParams().dump_input);
 
-  return fuzzer.Run(r.data(), r.size());
+  return fuzzer.Run(data, size);
 }
 
 }  // namespace fuzzers
diff --git a/fuzzers/tint_wgsl_reader_msl_writer_fuzzer.cc b/fuzzers/tint_wgsl_reader_msl_writer_fuzzer.cc
index 68bc05c..e075a30 100644
--- a/fuzzers/tint_wgsl_reader_msl_writer_fuzzer.cc
+++ b/fuzzers/tint_wgsl_reader_msl_writer_fuzzer.cc
@@ -21,13 +21,13 @@
 namespace fuzzers {
 
 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
-  Reader reader(data, size);
+  DataBuilder b(data, size);
   writer::msl::Options options;
-  ExtractMslOptions(&reader, &options);
+  GenerateMslOptions(&b, &options);
   tint::fuzzers::CommonFuzzer fuzzer(InputFormat::kWGSL, OutputFormat::kMSL);
   fuzzer.SetOptionsMsl(options);
   fuzzer.SetDumpInput(GetCliParams().dump_input);
-  return fuzzer.Run(reader.data(), reader.size());
+  return fuzzer.Run(data, size);
 }
 
 }  // namespace fuzzers
diff --git a/fuzzers/tint_wgsl_reader_spv_writer_fuzzer.cc b/fuzzers/tint_wgsl_reader_spv_writer_fuzzer.cc
index 8605108..74985c6 100644
--- a/fuzzers/tint_wgsl_reader_spv_writer_fuzzer.cc
+++ b/fuzzers/tint_wgsl_reader_spv_writer_fuzzer.cc
@@ -21,13 +21,13 @@
 namespace fuzzers {
 
 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
-  Reader reader(data, size);
+  DataBuilder b(data, size);
   writer::spirv::Options options;
-  ExtractSpirvOptions(&reader, &options);
+  GenerateSpirvOptions(&b, &options);
   tint::fuzzers::CommonFuzzer fuzzer(InputFormat::kWGSL, OutputFormat::kSpv);
   fuzzer.SetOptionsSpirv(options);
   fuzzer.SetDumpInput(GetCliParams().dump_input);
-  return fuzzer.Run(reader.data(), reader.size());
+  return fuzzer.Run(data, size);
 }
 
 }  // namespace fuzzers