[tint][build] Generate benchmarks for GN and Bazel

These were not emitted, or were emitted incorrectly.

Aside from fuzzers, CMake, GN and Bazel now all generate the same executable, library, test and benchmark targets.

Change-Id: I88c115d4fb974755fc7c476694f4ef79d6e18e49
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/150860
Reviewed-by: James Price <jrprice@google.com>
Kokoro: Kokoro <noreply+kokoro@google.com>
Commit-Queue: Ben Clayton <bclayton@google.com>
diff --git a/src/tint/lang/core/BUILD.bazel b/src/tint/lang/core/BUILD.bazel
index 8b4f3e9..f3b42a9 100644
--- a/src/tint/lang/core/BUILD.bazel
+++ b/src/tint/lang/core/BUILD.bazel
@@ -116,6 +116,7 @@
 )
 cc_library(
   name = "bench",
+  alwayslink = True,
   srcs = [
     "access_bench.cc",
     "address_space_bench.cc",
@@ -129,6 +130,7 @@
   deps = [
     "//src/tint/lang/core",
     "//src/tint/utils/traits",
+    "@benchmark",
   ],
   copts = COPTS,
   visibility = ["//visibility:public"],
diff --git a/src/tint/lang/core/BUILD.cmake b/src/tint/lang/core/BUILD.cmake
index ec43104..3bc86ee 100644
--- a/src/tint/lang/core/BUILD.cmake
+++ b/src/tint/lang/core/BUILD.cmake
@@ -138,3 +138,7 @@
   tint_lang_core
   tint_utils_traits
 )
+
+tint_target_add_external_dependencies(tint_lang_core_bench bench
+  "google-benchmark"
+)
diff --git a/src/tint/lang/core/BUILD.gn b/src/tint/lang/core/BUILD.gn
index 78c9e73..c4ae92e 100644
--- a/src/tint/lang/core/BUILD.gn
+++ b/src/tint/lang/core/BUILD.gn
@@ -25,7 +25,7 @@
 
 import("${tint_src_dir}/tint.gni")
 
-if (tint_build_unittests) {
+if (tint_build_unittests || tint_build_benchmarks) {
   import("//testing/test.gni")
 }
 
@@ -114,3 +114,23 @@
     ]
   }
 }
+if (tint_build_benchmarks) {
+  tint_unittests_source_set("bench") {
+    testonly = true
+    sources = [
+      "access_bench.cc",
+      "address_space_bench.cc",
+      "attribute_bench.cc",
+      "builtin_type_bench.cc",
+      "builtin_value_bench.cc",
+      "interpolation_sampling_bench.cc",
+      "interpolation_type_bench.cc",
+      "texel_format_bench.cc",
+    ]
+    deps = [
+      "${tint_src_dir}:google_benchmark",
+      "${tint_src_dir}/lang/core",
+      "${tint_src_dir}/utils/traits",
+    ]
+  }
+}
diff --git a/src/tint/lang/core/constant/BUILD.gn b/src/tint/lang/core/constant/BUILD.gn
index 2f15285..e96fcd5 100644
--- a/src/tint/lang/core/constant/BUILD.gn
+++ b/src/tint/lang/core/constant/BUILD.gn
@@ -25,7 +25,7 @@
 
 import("${tint_src_dir}/tint.gni")
 
-if (tint_build_unittests) {
+if (tint_build_unittests || tint_build_benchmarks) {
   import("//testing/test.gni")
 }
 
diff --git a/src/tint/lang/core/intrinsic/BUILD.gn b/src/tint/lang/core/intrinsic/BUILD.gn
index 2ee3356..679b2d5 100644
--- a/src/tint/lang/core/intrinsic/BUILD.gn
+++ b/src/tint/lang/core/intrinsic/BUILD.gn
@@ -25,7 +25,7 @@
 
 import("${tint_src_dir}/tint.gni")
 
-if (tint_build_unittests) {
+if (tint_build_unittests || tint_build_benchmarks) {
   import("//testing/test.gni")
 }
 
diff --git a/src/tint/lang/core/ir/BUILD.gn b/src/tint/lang/core/ir/BUILD.gn
index ff12f1e..a092238 100644
--- a/src/tint/lang/core/ir/BUILD.gn
+++ b/src/tint/lang/core/ir/BUILD.gn
@@ -25,7 +25,7 @@
 
 import("${tint_src_dir}/tint.gni")
 
-if (tint_build_unittests) {
+if (tint_build_unittests || tint_build_benchmarks) {
   import("//testing/test.gni")
 }
 
diff --git a/src/tint/lang/core/ir/transform/BUILD.gn b/src/tint/lang/core/ir/transform/BUILD.gn
index f6ce734..d6442c7 100644
--- a/src/tint/lang/core/ir/transform/BUILD.gn
+++ b/src/tint/lang/core/ir/transform/BUILD.gn
@@ -25,7 +25,7 @@
 
 import("${tint_src_dir}/tint.gni")
 
-if (tint_build_unittests) {
+if (tint_build_unittests || tint_build_benchmarks) {
   import("//testing/test.gni")
 }
 
diff --git a/src/tint/lang/core/type/BUILD.gn b/src/tint/lang/core/type/BUILD.gn
index c80abf5..db47a50 100644
--- a/src/tint/lang/core/type/BUILD.gn
+++ b/src/tint/lang/core/type/BUILD.gn
@@ -25,7 +25,7 @@
 
 import("${tint_src_dir}/tint.gni")
 
-if (tint_build_unittests) {
+if (tint_build_unittests || tint_build_benchmarks) {
   import("//testing/test.gni")
 }
 
diff --git a/src/tint/lang/glsl/writer/BUILD.bazel b/src/tint/lang/glsl/writer/BUILD.bazel
index a0e6bb2..19020bd 100644
--- a/src/tint/lang/glsl/writer/BUILD.bazel
+++ b/src/tint/lang/glsl/writer/BUILD.bazel
@@ -70,13 +70,14 @@
 )
 cc_library(
   name = "bench",
+  alwayslink = True,
   srcs = [
     "writer_bench.cc",
   ],
   deps = [
     "//src/tint/api/common",
     "//src/tint/api/options",
-    "//src/tint/cmd/bench",
+    "//src/tint/cmd/bench:bench",
     "//src/tint/lang/core",
     "//src/tint/lang/core/constant",
     "//src/tint/lang/core/type",
@@ -97,6 +98,7 @@
     "//src/tint/utils/symbol",
     "//src/tint/utils/text",
     "//src/tint/utils/traits",
+    "@benchmark",
   ] + select({
     ":tint_build_glsl_writer": [
       "//src/tint/lang/glsl/writer",
diff --git a/src/tint/lang/glsl/writer/BUILD.cmake b/src/tint/lang/glsl/writer/BUILD.cmake
index 232ff0d..0afac03 100644
--- a/src/tint/lang/glsl/writer/BUILD.cmake
+++ b/src/tint/lang/glsl/writer/BUILD.cmake
@@ -86,7 +86,7 @@
 tint_target_add_dependencies(tint_lang_glsl_writer_bench bench
   tint_api_common
   tint_api_options
-  tint_cmd_bench
+  tint_cmd_bench_bench
   tint_lang_core
   tint_lang_core_constant
   tint_lang_core_type
@@ -109,6 +109,10 @@
   tint_utils_traits
 )
 
+tint_target_add_external_dependencies(tint_lang_glsl_writer_bench bench
+  "google-benchmark"
+)
+
 if(TINT_BUILD_GLSL_WRITER)
   tint_target_add_dependencies(tint_lang_glsl_writer_bench bench
     tint_lang_glsl_writer
diff --git a/src/tint/lang/glsl/writer/BUILD.gn b/src/tint/lang/glsl/writer/BUILD.gn
index 96574b1..15b8ed7 100644
--- a/src/tint/lang/glsl/writer/BUILD.gn
+++ b/src/tint/lang/glsl/writer/BUILD.gn
@@ -24,6 +24,10 @@
 import("../../../../../scripts/tint_overrides_with_defaults.gni")
 
 import("${tint_src_dir}/tint.gni")
+
+if (tint_build_unittests || tint_build_benchmarks) {
+  import("//testing/test.gni")
+}
 if (tint_build_glsl_writer) {
   libtint_source_set("writer") {
     sources = [
@@ -67,3 +71,44 @@
     }
   }
 }
+if (tint_build_benchmarks) {
+  if (tint_build_glsl_writer) {
+    tint_unittests_source_set("bench") {
+      testonly = true
+      sources = [ "writer_bench.cc" ]
+      deps = [
+        "${tint_src_dir}:google_benchmark",
+        "${tint_src_dir}/api/common",
+        "${tint_src_dir}/api/options",
+        "${tint_src_dir}/cmd/bench:bench",
+        "${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/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/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_glsl_writer) {
+        deps += [
+          "${tint_src_dir}/lang/glsl/writer",
+          "${tint_src_dir}/lang/glsl/writer/common",
+        ]
+      }
+    }
+  }
+}
diff --git a/src/tint/lang/glsl/writer/ast_printer/BUILD.gn b/src/tint/lang/glsl/writer/ast_printer/BUILD.gn
index fc1c41e..2890c90 100644
--- a/src/tint/lang/glsl/writer/ast_printer/BUILD.gn
+++ b/src/tint/lang/glsl/writer/ast_printer/BUILD.gn
@@ -25,7 +25,7 @@
 
 import("${tint_src_dir}/tint.gni")
 
-if (tint_build_unittests) {
+if (tint_build_unittests || tint_build_benchmarks) {
   import("//testing/test.gni")
 }
 if (tint_build_glsl_writer) {
diff --git a/src/tint/lang/glsl/writer/ast_raise/BUILD.gn b/src/tint/lang/glsl/writer/ast_raise/BUILD.gn
index 7b7a0e0..c004912 100644
--- a/src/tint/lang/glsl/writer/ast_raise/BUILD.gn
+++ b/src/tint/lang/glsl/writer/ast_raise/BUILD.gn
@@ -25,7 +25,7 @@
 
 import("${tint_src_dir}/tint.gni")
 
-if (tint_build_unittests) {
+if (tint_build_unittests || tint_build_benchmarks) {
   import("//testing/test.gni")
 }
 if (tint_build_glsl_writer) {
diff --git a/src/tint/lang/glsl/writer/writer_bench.cc b/src/tint/lang/glsl/writer/writer_bench.cc
index de9d3e6..904b4dc 100644
--- a/src/tint/lang/glsl/writer/writer_bench.cc
+++ b/src/tint/lang/glsl/writer/writer_bench.cc
@@ -24,11 +24,11 @@
 
 void GenerateGLSL(benchmark::State& state, std::string input_name) {
     auto res = bench::LoadProgram(input_name);
-    if (auto err = std::get_if<bench::Error>(&res)) {
-        state.SkipWithError(err->msg.c_str());
+    if (!res) {
+        state.SkipWithError(res.Failure().reason.str());
         return;
     }
-    auto& program = std::get<bench::ProgramAndFile>(res).program;
+    auto& program = res->program;
     std::vector<std::string> entry_points;
     for (auto& fn : program.AST().Functions()) {
         if (fn->IsEntryPoint()) {
@@ -38,9 +38,9 @@
 
     for (auto _ : state) {
         for (auto& ep : entry_points) {
-            auto res = Generate(program, {}, ep);
-            if (!res) {
-                state.SkipWithError(res.Failure().reason.str());
+            auto gen_res = Generate(program, {}, ep);
+            if (!gen_res) {
+                state.SkipWithError(gen_res.Failure().reason.str());
             }
         }
     }
diff --git a/src/tint/lang/hlsl/writer/BUILD.bazel b/src/tint/lang/hlsl/writer/BUILD.bazel
index 323d038..58d4602 100644
--- a/src/tint/lang/hlsl/writer/BUILD.bazel
+++ b/src/tint/lang/hlsl/writer/BUILD.bazel
@@ -71,13 +71,14 @@
 )
 cc_library(
   name = "bench",
+  alwayslink = True,
   srcs = [
     "writer_bench.cc",
   ],
   deps = [
     "//src/tint/api/common",
     "//src/tint/api/options",
-    "//src/tint/cmd/bench",
+    "//src/tint/cmd/bench:bench",
     "//src/tint/lang/core",
     "//src/tint/lang/core/constant",
     "//src/tint/lang/core/type",
@@ -99,6 +100,7 @@
     "//src/tint/utils/symbol",
     "//src/tint/utils/text",
     "//src/tint/utils/traits",
+    "@benchmark",
   ] + select({
     ":tint_build_hlsl_writer": [
       "//src/tint/lang/hlsl/writer",
diff --git a/src/tint/lang/hlsl/writer/BUILD.cmake b/src/tint/lang/hlsl/writer/BUILD.cmake
index 887529b..3565fce 100644
--- a/src/tint/lang/hlsl/writer/BUILD.cmake
+++ b/src/tint/lang/hlsl/writer/BUILD.cmake
@@ -87,7 +87,7 @@
 tint_target_add_dependencies(tint_lang_hlsl_writer_bench bench
   tint_api_common
   tint_api_options
-  tint_cmd_bench
+  tint_cmd_bench_bench
   tint_lang_core
   tint_lang_core_constant
   tint_lang_core_type
@@ -111,6 +111,10 @@
   tint_utils_traits
 )
 
+tint_target_add_external_dependencies(tint_lang_hlsl_writer_bench bench
+  "google-benchmark"
+)
+
 if(TINT_BUILD_HLSL_WRITER)
   tint_target_add_dependencies(tint_lang_hlsl_writer_bench bench
     tint_lang_hlsl_writer
diff --git a/src/tint/lang/hlsl/writer/BUILD.gn b/src/tint/lang/hlsl/writer/BUILD.gn
index b270131..dbc5d31 100644
--- a/src/tint/lang/hlsl/writer/BUILD.gn
+++ b/src/tint/lang/hlsl/writer/BUILD.gn
@@ -24,6 +24,10 @@
 import("../../../../../scripts/tint_overrides_with_defaults.gni")
 
 import("${tint_src_dir}/tint.gni")
+
+if (tint_build_unittests || tint_build_benchmarks) {
+  import("//testing/test.gni")
+}
 if (tint_build_hlsl_writer) {
   libtint_source_set("writer") {
     sources = [
@@ -68,3 +72,42 @@
     }
   }
 }
+if (tint_build_benchmarks) {
+  if (tint_build_hlsl_writer) {
+    tint_unittests_source_set("bench") {
+      testonly = true
+      sources = [ "writer_bench.cc" ]
+      deps = [
+        "${tint_src_dir}:google_benchmark",
+        "${tint_src_dir}/api/common",
+        "${tint_src_dir}/api/options",
+        "${tint_src_dir}/cmd/bench:bench",
+        "${tint_src_dir}/lang/core",
+        "${tint_src_dir}/lang/core/constant",
+        "${tint_src_dir}/lang/core/type",
+        "${tint_src_dir}/lang/hlsl/writer/common",
+        "${tint_src_dir}/lang/wgsl",
+        "${tint_src_dir}/lang/wgsl/ast",
+        "${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/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_hlsl_writer) {
+        deps += [ "${tint_src_dir}/lang/hlsl/writer" ]
+      }
+    }
+  }
+}
diff --git a/src/tint/lang/hlsl/writer/ast_printer/BUILD.gn b/src/tint/lang/hlsl/writer/ast_printer/BUILD.gn
index 017911b..619d72a 100644
--- a/src/tint/lang/hlsl/writer/ast_printer/BUILD.gn
+++ b/src/tint/lang/hlsl/writer/ast_printer/BUILD.gn
@@ -25,7 +25,7 @@
 
 import("${tint_src_dir}/tint.gni")
 
-if (tint_build_unittests) {
+if (tint_build_unittests || tint_build_benchmarks) {
   import("//testing/test.gni")
 }
 if (tint_build_hlsl_writer) {
diff --git a/src/tint/lang/hlsl/writer/ast_raise/BUILD.gn b/src/tint/lang/hlsl/writer/ast_raise/BUILD.gn
index 24b8ca4..cbbf8c7 100644
--- a/src/tint/lang/hlsl/writer/ast_raise/BUILD.gn
+++ b/src/tint/lang/hlsl/writer/ast_raise/BUILD.gn
@@ -25,7 +25,7 @@
 
 import("${tint_src_dir}/tint.gni")
 
-if (tint_build_unittests) {
+if (tint_build_unittests || tint_build_benchmarks) {
   import("//testing/test.gni")
 }
 if (tint_build_hlsl_writer) {
diff --git a/src/tint/lang/hlsl/writer/writer_bench.cc b/src/tint/lang/hlsl/writer/writer_bench.cc
index 00c5d39..727e696f 100644
--- a/src/tint/lang/hlsl/writer/writer_bench.cc
+++ b/src/tint/lang/hlsl/writer/writer_bench.cc
@@ -22,15 +22,14 @@
 
 void GenerateHLSL(benchmark::State& state, std::string input_name) {
     auto res = bench::LoadProgram(input_name);
-    if (auto err = std::get_if<bench::Error>(&res)) {
-        state.SkipWithError(err->msg.c_str());
+    if (!res) {
+        state.SkipWithError(res.Failure().reason.str());
         return;
     }
-    auto& program = std::get<bench::ProgramAndFile>(res).program;
     for (auto _ : state) {
-        auto res = Generate(program, {});
-        if (!res) {
-            state.SkipWithError(res.Failure().reason.str());
+        auto gen_res = Generate(res->program, {});
+        if (!gen_res) {
+            state.SkipWithError(gen_res.Failure().reason.str());
         }
     }
 }
diff --git a/src/tint/lang/msl/writer/BUILD.bazel b/src/tint/lang/msl/writer/BUILD.bazel
index 4348b90..8b34a6c 100644
--- a/src/tint/lang/msl/writer/BUILD.bazel
+++ b/src/tint/lang/msl/writer/BUILD.bazel
@@ -74,13 +74,14 @@
 )
 cc_library(
   name = "bench",
+  alwayslink = True,
   srcs = [
     "writer_bench.cc",
   ],
   deps = [
     "//src/tint/api/common",
     "//src/tint/api/options",
-    "//src/tint/cmd/bench",
+    "//src/tint/cmd/bench:bench",
     "//src/tint/lang/core",
     "//src/tint/lang/core/constant",
     "//src/tint/lang/core/type",
@@ -101,6 +102,7 @@
     "//src/tint/utils/symbol",
     "//src/tint/utils/text",
     "//src/tint/utils/traits",
+    "@benchmark",
   ] + select({
     ":tint_build_msl_writer": [
       "//src/tint/lang/msl/writer",
diff --git a/src/tint/lang/msl/writer/BUILD.cmake b/src/tint/lang/msl/writer/BUILD.cmake
index d3291bc..6bcfd2f 100644
--- a/src/tint/lang/msl/writer/BUILD.cmake
+++ b/src/tint/lang/msl/writer/BUILD.cmake
@@ -92,7 +92,7 @@
 tint_target_add_dependencies(tint_lang_msl_writer_bench bench
   tint_api_common
   tint_api_options
-  tint_cmd_bench
+  tint_cmd_bench_bench
   tint_lang_core
   tint_lang_core_constant
   tint_lang_core_type
@@ -115,6 +115,10 @@
   tint_utils_traits
 )
 
+tint_target_add_external_dependencies(tint_lang_msl_writer_bench bench
+  "google-benchmark"
+)
+
 if(TINT_BUILD_MSL_WRITER)
   tint_target_add_dependencies(tint_lang_msl_writer_bench bench
     tint_lang_msl_writer
diff --git a/src/tint/lang/msl/writer/BUILD.gn b/src/tint/lang/msl/writer/BUILD.gn
index 9f13b86..553a1cc 100644
--- a/src/tint/lang/msl/writer/BUILD.gn
+++ b/src/tint/lang/msl/writer/BUILD.gn
@@ -24,6 +24,10 @@
 import("../../../../../scripts/tint_overrides_with_defaults.gni")
 
 import("${tint_src_dir}/tint.gni")
+
+if (tint_build_unittests || tint_build_benchmarks) {
+  import("//testing/test.gni")
+}
 if (tint_build_msl_writer) {
   libtint_source_set("writer") {
     sources = [
@@ -71,3 +75,44 @@
     }
   }
 }
+if (tint_build_benchmarks) {
+  if (tint_build_msl_writer) {
+    tint_unittests_source_set("bench") {
+      testonly = true
+      sources = [ "writer_bench.cc" ]
+      deps = [
+        "${tint_src_dir}:google_benchmark",
+        "${tint_src_dir}/api/common",
+        "${tint_src_dir}/api/options",
+        "${tint_src_dir}/cmd/bench:bench",
+        "${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/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/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_msl_writer) {
+        deps += [
+          "${tint_src_dir}/lang/msl/writer",
+          "${tint_src_dir}/lang/msl/writer/common",
+        ]
+      }
+    }
+  }
+}
diff --git a/src/tint/lang/msl/writer/ast_printer/BUILD.gn b/src/tint/lang/msl/writer/ast_printer/BUILD.gn
index 072b550..229ad23 100644
--- a/src/tint/lang/msl/writer/ast_printer/BUILD.gn
+++ b/src/tint/lang/msl/writer/ast_printer/BUILD.gn
@@ -25,7 +25,7 @@
 
 import("${tint_src_dir}/tint.gni")
 
-if (tint_build_unittests) {
+if (tint_build_unittests || tint_build_benchmarks) {
   import("//testing/test.gni")
 }
 if (tint_build_msl_writer) {
diff --git a/src/tint/lang/msl/writer/ast_raise/BUILD.gn b/src/tint/lang/msl/writer/ast_raise/BUILD.gn
index cf231b6..05d773f 100644
--- a/src/tint/lang/msl/writer/ast_raise/BUILD.gn
+++ b/src/tint/lang/msl/writer/ast_raise/BUILD.gn
@@ -25,7 +25,7 @@
 
 import("${tint_src_dir}/tint.gni")
 
-if (tint_build_unittests) {
+if (tint_build_unittests || tint_build_benchmarks) {
   import("//testing/test.gni")
 }
 if (tint_build_msl_writer) {
diff --git a/src/tint/lang/msl/writer/common/BUILD.gn b/src/tint/lang/msl/writer/common/BUILD.gn
index 8e834d8..30e2d4f 100644
--- a/src/tint/lang/msl/writer/common/BUILD.gn
+++ b/src/tint/lang/msl/writer/common/BUILD.gn
@@ -25,7 +25,7 @@
 
 import("${tint_src_dir}/tint.gni")
 
-if (tint_build_unittests) {
+if (tint_build_unittests || tint_build_benchmarks) {
   import("//testing/test.gni")
 }
 if (tint_build_msl_writer) {
diff --git a/src/tint/lang/msl/writer/printer/BUILD.gn b/src/tint/lang/msl/writer/printer/BUILD.gn
index cf2af5a..9f75e9a 100644
--- a/src/tint/lang/msl/writer/printer/BUILD.gn
+++ b/src/tint/lang/msl/writer/printer/BUILD.gn
@@ -25,7 +25,7 @@
 
 import("${tint_src_dir}/tint.gni")
 
-if (tint_build_unittests) {
+if (tint_build_unittests || tint_build_benchmarks) {
   import("//testing/test.gni")
 }
 if (tint_build_msl_writer) {
diff --git a/src/tint/lang/msl/writer/writer_bench.cc b/src/tint/lang/msl/writer/writer_bench.cc
index aa04473..712d272 100644
--- a/src/tint/lang/msl/writer/writer_bench.cc
+++ b/src/tint/lang/msl/writer/writer_bench.cc
@@ -24,11 +24,11 @@
 
 void GenerateMSL(benchmark::State& state, std::string input_name) {
     auto res = bench::LoadProgram(input_name);
-    if (auto err = std::get_if<bench::Error>(&res)) {
-        state.SkipWithError(err->msg.c_str());
+    if (!res) {
+        state.SkipWithError(res.Failure().reason.str());
         return;
     }
-    auto& program = std::get<bench::ProgramAndFile>(res).program;
+    auto& program = res->program;
 
     tint::msl::writer::Options gen_options = {};
     gen_options.array_length_from_uniform.ubo_binding = tint::BindingPoint{0, 30};
@@ -61,9 +61,9 @@
         }
     }
     for (auto _ : state) {
-        auto res = Generate(program, gen_options);
-        if (!res) {
-            state.SkipWithError(res.Failure().reason.str());
+        auto gen_res = Generate(program, gen_options);
+        if (!gen_res) {
+            state.SkipWithError(gen_res.Failure().reason.str());
         }
     }
 }
diff --git a/src/tint/lang/spirv/ir/BUILD.gn b/src/tint/lang/spirv/ir/BUILD.gn
index 2a81280..52aff36 100644
--- a/src/tint/lang/spirv/ir/BUILD.gn
+++ b/src/tint/lang/spirv/ir/BUILD.gn
@@ -25,7 +25,7 @@
 
 import("${tint_src_dir}/tint.gni")
 
-if (tint_build_unittests) {
+if (tint_build_unittests || tint_build_benchmarks) {
   import("//testing/test.gni")
 }
 
diff --git a/src/tint/lang/spirv/reader/ast_lower/BUILD.gn b/src/tint/lang/spirv/reader/ast_lower/BUILD.gn
index 12924c2..a24ca3e 100644
--- a/src/tint/lang/spirv/reader/ast_lower/BUILD.gn
+++ b/src/tint/lang/spirv/reader/ast_lower/BUILD.gn
@@ -25,7 +25,7 @@
 
 import("${tint_src_dir}/tint.gni")
 
-if (tint_build_unittests) {
+if (tint_build_unittests || tint_build_benchmarks) {
   import("//testing/test.gni")
 }
 if (tint_build_spv_reader) {
diff --git a/src/tint/lang/spirv/reader/ast_parser/BUILD.gn b/src/tint/lang/spirv/reader/ast_parser/BUILD.gn
index 163e8be..7f54ccf 100644
--- a/src/tint/lang/spirv/reader/ast_parser/BUILD.gn
+++ b/src/tint/lang/spirv/reader/ast_parser/BUILD.gn
@@ -25,7 +25,7 @@
 
 import("${tint_src_dir}/tint.gni")
 
-if (tint_build_unittests) {
+if (tint_build_unittests || tint_build_benchmarks) {
   import("//testing/test.gni")
 }
 if (tint_build_spv_reader) {
@@ -88,6 +88,7 @@
         "${tint_spirv_headers_dir}:spv_headers",
         "${tint_spirv_tools_dir}:spvtools",
         "${tint_spirv_tools_dir}:spvtools_opt",
+        "${tint_spirv_tools_dir}:spvtools_val",
       ]
     }
     public_configs = [ "${tint_spirv_tools_dir}/:spvtools_internal_config" ]
@@ -172,6 +173,7 @@
           "${tint_spirv_tools_dir}:spvtools_headers",
           "${tint_spirv_tools_dir}:spvtools_opt",
           "${tint_spirv_tools_dir}:spvtools_val",
+          "${tint_spirv_tools_dir}:spvtools_val",
         ]
       }
       public_configs = [ "${tint_spirv_tools_dir}/:spvtools_internal_config" ]
diff --git a/src/tint/lang/spirv/writer/BUILD.bazel b/src/tint/lang/spirv/writer/BUILD.bazel
index f8d6a11..7c2a7b7 100644
--- a/src/tint/lang/spirv/writer/BUILD.bazel
+++ b/src/tint/lang/spirv/writer/BUILD.bazel
@@ -149,13 +149,14 @@
 )
 cc_library(
   name = "bench",
+  alwayslink = True,
   srcs = [
     "writer_bench.cc",
   ],
   deps = [
     "//src/tint/api/common",
     "//src/tint/api/options",
-    "//src/tint/cmd/bench",
+    "//src/tint/cmd/bench:bench",
     "//src/tint/lang/core",
     "//src/tint/lang/core/constant",
     "//src/tint/lang/core/type",
@@ -176,6 +177,7 @@
     "//src/tint/utils/symbol",
     "//src/tint/utils/text",
     "//src/tint/utils/traits",
+    "@benchmark",
   ] + select({
     ":tint_build_spv_writer": [
       "//src/tint/lang/spirv/writer",
diff --git a/src/tint/lang/spirv/writer/BUILD.cmake b/src/tint/lang/spirv/writer/BUILD.cmake
index 0910cfb..953b266 100644
--- a/src/tint/lang/spirv/writer/BUILD.cmake
+++ b/src/tint/lang/spirv/writer/BUILD.cmake
@@ -176,7 +176,7 @@
 tint_target_add_dependencies(tint_lang_spirv_writer_bench bench
   tint_api_common
   tint_api_options
-  tint_cmd_bench
+  tint_cmd_bench_bench
   tint_lang_core
   tint_lang_core_constant
   tint_lang_core_type
@@ -199,6 +199,10 @@
   tint_utils_traits
 )
 
+tint_target_add_external_dependencies(tint_lang_spirv_writer_bench bench
+  "google-benchmark"
+)
+
 if(TINT_BUILD_SPV_WRITER)
   tint_target_add_dependencies(tint_lang_spirv_writer_bench bench
     tint_lang_spirv_writer
diff --git a/src/tint/lang/spirv/writer/BUILD.gn b/src/tint/lang/spirv/writer/BUILD.gn
index 38d4260..0501f18 100644
--- a/src/tint/lang/spirv/writer/BUILD.gn
+++ b/src/tint/lang/spirv/writer/BUILD.gn
@@ -25,7 +25,7 @@
 
 import("${tint_src_dir}/tint.gni")
 
-if (tint_build_unittests) {
+if (tint_build_unittests || tint_build_benchmarks) {
   import("//testing/test.gni")
 }
 if (tint_build_spv_writer) {
@@ -153,3 +153,44 @@
     }
   }
 }
+if (tint_build_benchmarks) {
+  if (tint_build_spv_writer) {
+    tint_unittests_source_set("bench") {
+      testonly = true
+      sources = [ "writer_bench.cc" ]
+      deps = [
+        "${tint_src_dir}:google_benchmark",
+        "${tint_src_dir}/api/common",
+        "${tint_src_dir}/api/options",
+        "${tint_src_dir}/cmd/bench:bench",
+        "${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/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/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_spv_writer) {
+        deps += [
+          "${tint_src_dir}/lang/spirv/writer",
+          "${tint_src_dir}/lang/spirv/writer/common",
+        ]
+      }
+    }
+  }
+}
diff --git a/src/tint/lang/spirv/writer/ast_printer/BUILD.gn b/src/tint/lang/spirv/writer/ast_printer/BUILD.gn
index 4344f94..577508d 100644
--- a/src/tint/lang/spirv/writer/ast_printer/BUILD.gn
+++ b/src/tint/lang/spirv/writer/ast_printer/BUILD.gn
@@ -25,7 +25,7 @@
 
 import("${tint_src_dir}/tint.gni")
 
-if (tint_build_unittests) {
+if (tint_build_unittests || tint_build_benchmarks) {
   import("//testing/test.gni")
 }
 if (tint_build_spv_writer) {
diff --git a/src/tint/lang/spirv/writer/ast_raise/BUILD.gn b/src/tint/lang/spirv/writer/ast_raise/BUILD.gn
index 5ab53d5..4eb4fe1 100644
--- a/src/tint/lang/spirv/writer/ast_raise/BUILD.gn
+++ b/src/tint/lang/spirv/writer/ast_raise/BUILD.gn
@@ -25,7 +25,7 @@
 
 import("${tint_src_dir}/tint.gni")
 
-if (tint_build_unittests) {
+if (tint_build_unittests || tint_build_benchmarks) {
   import("//testing/test.gni")
 }
 if (tint_build_spv_writer) {
diff --git a/src/tint/lang/spirv/writer/common/BUILD.gn b/src/tint/lang/spirv/writer/common/BUILD.gn
index 5c12785..98f7ec6 100644
--- a/src/tint/lang/spirv/writer/common/BUILD.gn
+++ b/src/tint/lang/spirv/writer/common/BUILD.gn
@@ -25,7 +25,7 @@
 
 import("${tint_src_dir}/tint.gni")
 
-if (tint_build_unittests) {
+if (tint_build_unittests || tint_build_benchmarks) {
   import("//testing/test.gni")
 }
 if (tint_build_spv_writer) {
diff --git a/src/tint/lang/spirv/writer/raise/BUILD.gn b/src/tint/lang/spirv/writer/raise/BUILD.gn
index 6d187d6..7cd648d 100644
--- a/src/tint/lang/spirv/writer/raise/BUILD.gn
+++ b/src/tint/lang/spirv/writer/raise/BUILD.gn
@@ -25,7 +25,7 @@
 
 import("${tint_src_dir}/tint.gni")
 
-if (tint_build_unittests) {
+if (tint_build_unittests || tint_build_benchmarks) {
   import("//testing/test.gni")
 }
 if (tint_build_spv_writer) {
diff --git a/src/tint/lang/spirv/writer/writer_bench.cc b/src/tint/lang/spirv/writer/writer_bench.cc
index adef3df..c5bccce 100644
--- a/src/tint/lang/spirv/writer/writer_bench.cc
+++ b/src/tint/lang/spirv/writer/writer_bench.cc
@@ -22,15 +22,14 @@
 
 void RunBenchmark(benchmark::State& state, std::string input_name, Options options) {
     auto res = bench::LoadProgram(input_name);
-    if (auto err = std::get_if<bench::Error>(&res)) {
-        state.SkipWithError(err->msg.c_str());
+    if (!res) {
+        state.SkipWithError(res.Failure().reason.str());
         return;
     }
-    auto& program = std::get<bench::ProgramAndFile>(res).program;
     for (auto _ : state) {
-        auto res = Generate(program, options);
-        if (!res) {
-            state.SkipWithError(res.Failure().reason.str());
+        auto gen_res = Generate(res->program, options);
+        if (!gen_res) {
+            state.SkipWithError(gen_res.Failure().reason.str());
         }
     }
 }
diff --git a/src/tint/lang/wgsl/BUILD.bazel b/src/tint/lang/wgsl/BUILD.bazel
index 83e4df2..20c24b6 100644
--- a/src/tint/lang/wgsl/BUILD.bazel
+++ b/src/tint/lang/wgsl/BUILD.bazel
@@ -102,6 +102,7 @@
 )
 cc_library(
   name = "bench",
+  alwayslink = True,
   srcs = [
     "diagnostic_rule_bench.cc",
     "diagnostic_severity_bench.cc",
@@ -118,6 +119,7 @@
     "//src/tint/utils/rtti",
     "//src/tint/utils/text",
     "//src/tint/utils/traits",
+    "@benchmark",
   ],
   copts = COPTS,
   visibility = ["//visibility:public"],
diff --git a/src/tint/lang/wgsl/BUILD.cmake b/src/tint/lang/wgsl/BUILD.cmake
index c72aa5e..4b8db03 100644
--- a/src/tint/lang/wgsl/BUILD.cmake
+++ b/src/tint/lang/wgsl/BUILD.cmake
@@ -134,3 +134,7 @@
   tint_utils_text
   tint_utils_traits
 )
+
+tint_target_add_external_dependencies(tint_lang_wgsl_bench bench
+  "google-benchmark"
+)
diff --git a/src/tint/lang/wgsl/BUILD.gn b/src/tint/lang/wgsl/BUILD.gn
index 4ddc480..7b55c18 100644
--- a/src/tint/lang/wgsl/BUILD.gn
+++ b/src/tint/lang/wgsl/BUILD.gn
@@ -25,7 +25,7 @@
 
 import("${tint_src_dir}/tint.gni")
 
-if (tint_build_unittests) {
+if (tint_build_unittests || tint_build_benchmarks) {
   import("//testing/test.gni")
 }
 
@@ -99,3 +99,26 @@
     }
   }
 }
+if (tint_build_benchmarks) {
+  tint_unittests_source_set("bench") {
+    testonly = true
+    sources = [
+      "diagnostic_rule_bench.cc",
+      "diagnostic_severity_bench.cc",
+      "extension_bench.cc",
+    ]
+    deps = [
+      "${tint_src_dir}:google_benchmark",
+      "${tint_src_dir}/lang/wgsl",
+      "${tint_src_dir}/utils/containers",
+      "${tint_src_dir}/utils/diagnostic",
+      "${tint_src_dir}/utils/ice",
+      "${tint_src_dir}/utils/macros",
+      "${tint_src_dir}/utils/math",
+      "${tint_src_dir}/utils/memory",
+      "${tint_src_dir}/utils/rtti",
+      "${tint_src_dir}/utils/text",
+      "${tint_src_dir}/utils/traits",
+    ]
+  }
+}
diff --git a/src/tint/lang/wgsl/ast/BUILD.gn b/src/tint/lang/wgsl/ast/BUILD.gn
index 2cc22fe..2de24e1 100644
--- a/src/tint/lang/wgsl/ast/BUILD.gn
+++ b/src/tint/lang/wgsl/ast/BUILD.gn
@@ -25,7 +25,7 @@
 
 import("${tint_src_dir}/tint.gni")
 
-if (tint_build_unittests) {
+if (tint_build_unittests || tint_build_benchmarks) {
   import("//testing/test.gni")
 }
 
diff --git a/src/tint/lang/wgsl/ast/transform/BUILD.gn b/src/tint/lang/wgsl/ast/transform/BUILD.gn
index 958683e..9286bd0 100644
--- a/src/tint/lang/wgsl/ast/transform/BUILD.gn
+++ b/src/tint/lang/wgsl/ast/transform/BUILD.gn
@@ -25,7 +25,7 @@
 
 import("${tint_src_dir}/tint.gni")
 
-if (tint_build_unittests) {
+if (tint_build_unittests || tint_build_benchmarks) {
   import("//testing/test.gni")
 }
 
diff --git a/src/tint/lang/wgsl/helpers/BUILD.gn b/src/tint/lang/wgsl/helpers/BUILD.gn
index 3ce0df4..d0ff37c 100644
--- a/src/tint/lang/wgsl/helpers/BUILD.gn
+++ b/src/tint/lang/wgsl/helpers/BUILD.gn
@@ -25,7 +25,7 @@
 
 import("${tint_src_dir}/tint.gni")
 
-if (tint_build_unittests) {
+if (tint_build_unittests || tint_build_benchmarks) {
   import("//testing/test.gni")
 }
 
diff --git a/src/tint/lang/wgsl/inspector/BUILD.gn b/src/tint/lang/wgsl/inspector/BUILD.gn
index 566230b..1256404 100644
--- a/src/tint/lang/wgsl/inspector/BUILD.gn
+++ b/src/tint/lang/wgsl/inspector/BUILD.gn
@@ -25,7 +25,7 @@
 
 import("${tint_src_dir}/tint.gni")
 
-if (tint_build_unittests) {
+if (tint_build_unittests || tint_build_benchmarks) {
   import("//testing/test.gni")
 }
 
diff --git a/src/tint/lang/wgsl/program/BUILD.gn b/src/tint/lang/wgsl/program/BUILD.gn
index ea3bd1b..4ebef42 100644
--- a/src/tint/lang/wgsl/program/BUILD.gn
+++ b/src/tint/lang/wgsl/program/BUILD.gn
@@ -25,7 +25,7 @@
 
 import("${tint_src_dir}/tint.gni")
 
-if (tint_build_unittests) {
+if (tint_build_unittests || tint_build_benchmarks) {
   import("//testing/test.gni")
 }
 
diff --git a/src/tint/lang/wgsl/reader/BUILD.bazel b/src/tint/lang/wgsl/reader/BUILD.bazel
index 116874d..e47e37f 100644
--- a/src/tint/lang/wgsl/reader/BUILD.bazel
+++ b/src/tint/lang/wgsl/reader/BUILD.bazel
@@ -64,12 +64,13 @@
 )
 cc_library(
   name = "bench",
+  alwayslink = True,
   srcs = [
     "reader_bench.cc",
   ],
   deps = [
     "//src/tint/api/common",
-    "//src/tint/cmd/bench",
+    "//src/tint/cmd/bench:bench",
     "//src/tint/lang/core",
     "//src/tint/lang/core/constant",
     "//src/tint/lang/core/ir",
@@ -92,6 +93,7 @@
     "//src/tint/utils/symbol",
     "//src/tint/utils/text",
     "//src/tint/utils/traits",
+    "@benchmark",
   ],
   copts = COPTS,
   visibility = ["//visibility:public"],
diff --git a/src/tint/lang/wgsl/reader/BUILD.cmake b/src/tint/lang/wgsl/reader/BUILD.cmake
index 2d94eb5..163a125 100644
--- a/src/tint/lang/wgsl/reader/BUILD.cmake
+++ b/src/tint/lang/wgsl/reader/BUILD.cmake
@@ -73,7 +73,7 @@
 
 tint_target_add_dependencies(tint_lang_wgsl_reader_bench bench
   tint_api_common
-  tint_cmd_bench
+  tint_cmd_bench_bench
   tint_lang_core
   tint_lang_core_constant
   tint_lang_core_ir
@@ -97,3 +97,7 @@
   tint_utils_text
   tint_utils_traits
 )
+
+tint_target_add_external_dependencies(tint_lang_wgsl_reader_bench bench
+  "google-benchmark"
+)
diff --git a/src/tint/lang/wgsl/reader/BUILD.gn b/src/tint/lang/wgsl/reader/BUILD.gn
index 7962250..f4808f9 100644
--- a/src/tint/lang/wgsl/reader/BUILD.gn
+++ b/src/tint/lang/wgsl/reader/BUILD.gn
@@ -25,6 +25,10 @@
 
 import("${tint_src_dir}/tint.gni")
 
+if (tint_build_unittests || tint_build_benchmarks) {
+  import("//testing/test.gni")
+}
+
 libtint_source_set("reader") {
   sources = [
     "reader.cc",
@@ -59,3 +63,36 @@
     "${tint_src_dir}/utils/traits",
   ]
 }
+if (tint_build_benchmarks) {
+  tint_unittests_source_set("bench") {
+    testonly = true
+    sources = [ "reader_bench.cc" ]
+    deps = [
+      "${tint_src_dir}:google_benchmark",
+      "${tint_src_dir}/api/common",
+      "${tint_src_dir}/cmd/bench:bench",
+      "${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/program",
+      "${tint_src_dir}/lang/wgsl/reader",
+      "${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/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",
+    ]
+  }
+}
diff --git a/src/tint/lang/wgsl/reader/lower/BUILD.gn b/src/tint/lang/wgsl/reader/lower/BUILD.gn
index 674130d..490ba6f 100644
--- a/src/tint/lang/wgsl/reader/lower/BUILD.gn
+++ b/src/tint/lang/wgsl/reader/lower/BUILD.gn
@@ -25,7 +25,7 @@
 
 import("${tint_src_dir}/tint.gni")
 
-if (tint_build_unittests) {
+if (tint_build_unittests || tint_build_benchmarks) {
   import("//testing/test.gni")
 }
 
diff --git a/src/tint/lang/wgsl/reader/parser/BUILD.gn b/src/tint/lang/wgsl/reader/parser/BUILD.gn
index f765960..77cc04c 100644
--- a/src/tint/lang/wgsl/reader/parser/BUILD.gn
+++ b/src/tint/lang/wgsl/reader/parser/BUILD.gn
@@ -25,7 +25,7 @@
 
 import("${tint_src_dir}/tint.gni")
 
-if (tint_build_unittests) {
+if (tint_build_unittests || tint_build_benchmarks) {
   import("//testing/test.gni")
 }
 
diff --git a/src/tint/lang/wgsl/reader/program_to_ir/BUILD.gn b/src/tint/lang/wgsl/reader/program_to_ir/BUILD.gn
index 87f764b..f8b67b3 100644
--- a/src/tint/lang/wgsl/reader/program_to_ir/BUILD.gn
+++ b/src/tint/lang/wgsl/reader/program_to_ir/BUILD.gn
@@ -25,7 +25,7 @@
 
 import("${tint_src_dir}/tint.gni")
 
-if (tint_build_unittests) {
+if (tint_build_unittests || tint_build_benchmarks) {
   import("//testing/test.gni")
 }
 
diff --git a/src/tint/lang/wgsl/reader/reader_bench.cc b/src/tint/lang/wgsl/reader/reader_bench.cc
index b5f736a..be3898c 100644
--- a/src/tint/lang/wgsl/reader/reader_bench.cc
+++ b/src/tint/lang/wgsl/reader/reader_bench.cc
@@ -22,15 +22,14 @@
 
 void ParseWGSL(benchmark::State& state, std::string input_name) {
     auto res = bench::LoadInputFile(input_name);
-    if (auto err = std::get_if<bench::Error>(&res)) {
-        state.SkipWithError(err->msg.c_str());
+    if (!res) {
+        state.SkipWithError(res.Failure().reason.str());
         return;
     }
-    auto& file = std::get<Source::File>(res);
     for (auto _ : state) {
-        auto res = Parse(&file);
-        if (res.Diagnostics().contains_errors()) {
-            state.SkipWithError(res.Diagnostics().str().c_str());
+        auto program = Parse(&res.Get());
+        if (program.Diagnostics().contains_errors()) {
+            state.SkipWithError(program.Diagnostics().str());
         }
     }
 }
diff --git a/src/tint/lang/wgsl/resolver/BUILD.gn b/src/tint/lang/wgsl/resolver/BUILD.gn
index c10075f..ba04bbb 100644
--- a/src/tint/lang/wgsl/resolver/BUILD.gn
+++ b/src/tint/lang/wgsl/resolver/BUILD.gn
@@ -25,7 +25,7 @@
 
 import("${tint_src_dir}/tint.gni")
 
-if (tint_build_unittests) {
+if (tint_build_unittests || tint_build_benchmarks) {
   import("//testing/test.gni")
 }
 
diff --git a/src/tint/lang/wgsl/sem/BUILD.gn b/src/tint/lang/wgsl/sem/BUILD.gn
index 2e87dae..82cda60 100644
--- a/src/tint/lang/wgsl/sem/BUILD.gn
+++ b/src/tint/lang/wgsl/sem/BUILD.gn
@@ -25,7 +25,7 @@
 
 import("${tint_src_dir}/tint.gni")
 
-if (tint_build_unittests) {
+if (tint_build_unittests || tint_build_benchmarks) {
   import("//testing/test.gni")
 }
 
diff --git a/src/tint/lang/wgsl/writer/BUILD.bazel b/src/tint/lang/wgsl/writer/BUILD.bazel
index 36cadd8..7d24c91 100644
--- a/src/tint/lang/wgsl/writer/BUILD.bazel
+++ b/src/tint/lang/wgsl/writer/BUILD.bazel
@@ -69,11 +69,12 @@
 )
 cc_library(
   name = "bench",
+  alwayslink = True,
   srcs = [
     "writer_bench.cc",
   ],
   deps = [
-    "//src/tint/cmd/bench",
+    "//src/tint/cmd/bench:bench",
     "//src/tint/lang/core",
     "//src/tint/lang/core/constant",
     "//src/tint/lang/core/type",
@@ -95,6 +96,7 @@
     "//src/tint/utils/symbol",
     "//src/tint/utils/text",
     "//src/tint/utils/traits",
+    "@benchmark",
   ],
   copts = COPTS,
   visibility = ["//visibility:public"],
diff --git a/src/tint/lang/wgsl/writer/BUILD.cmake b/src/tint/lang/wgsl/writer/BUILD.cmake
index c9893f6..bfb510a 100644
--- a/src/tint/lang/wgsl/writer/BUILD.cmake
+++ b/src/tint/lang/wgsl/writer/BUILD.cmake
@@ -78,7 +78,7 @@
 )
 
 tint_target_add_dependencies(tint_lang_wgsl_writer_bench bench
-  tint_cmd_bench
+  tint_cmd_bench_bench
   tint_lang_core
   tint_lang_core_constant
   tint_lang_core_type
@@ -101,3 +101,7 @@
   tint_utils_text
   tint_utils_traits
 )
+
+tint_target_add_external_dependencies(tint_lang_wgsl_writer_bench bench
+  "google-benchmark"
+)
diff --git a/src/tint/lang/wgsl/writer/BUILD.gn b/src/tint/lang/wgsl/writer/BUILD.gn
index 21b27a4..85772cd 100644
--- a/src/tint/lang/wgsl/writer/BUILD.gn
+++ b/src/tint/lang/wgsl/writer/BUILD.gn
@@ -25,6 +25,10 @@
 
 import("${tint_src_dir}/tint.gni")
 
+if (tint_build_unittests || tint_build_benchmarks) {
+  import("//testing/test.gni")
+}
+
 libtint_source_set("writer") {
   sources = [
     "options.cc",
@@ -64,3 +68,34 @@
     "${tint_src_dir}/utils/traits",
   ]
 }
+if (tint_build_benchmarks) {
+  tint_unittests_source_set("bench") {
+    testonly = true
+    sources = [ "writer_bench.cc" ]
+    deps = [
+      "${tint_src_dir}:google_benchmark",
+      "${tint_src_dir}/cmd/bench:bench",
+      "${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/program",
+      "${tint_src_dir}/lang/wgsl/sem",
+      "${tint_src_dir}/lang/wgsl/writer",
+      "${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",
+    ]
+  }
+}
diff --git a/src/tint/lang/wgsl/writer/ast_printer/BUILD.gn b/src/tint/lang/wgsl/writer/ast_printer/BUILD.gn
index dcdec55..d50257d 100644
--- a/src/tint/lang/wgsl/writer/ast_printer/BUILD.gn
+++ b/src/tint/lang/wgsl/writer/ast_printer/BUILD.gn
@@ -25,7 +25,7 @@
 
 import("${tint_src_dir}/tint.gni")
 
-if (tint_build_unittests) {
+if (tint_build_unittests || tint_build_benchmarks) {
   import("//testing/test.gni")
 }
 
diff --git a/src/tint/lang/wgsl/writer/ir_to_program/BUILD.gn b/src/tint/lang/wgsl/writer/ir_to_program/BUILD.gn
index c823bb4..70419b6 100644
--- a/src/tint/lang/wgsl/writer/ir_to_program/BUILD.gn
+++ b/src/tint/lang/wgsl/writer/ir_to_program/BUILD.gn
@@ -25,7 +25,7 @@
 
 import("${tint_src_dir}/tint.gni")
 
-if (tint_build_unittests) {
+if (tint_build_unittests || tint_build_benchmarks) {
   import("//testing/test.gni")
 }
 
diff --git a/src/tint/lang/wgsl/writer/raise/BUILD.gn b/src/tint/lang/wgsl/writer/raise/BUILD.gn
index 7dc51e0..6df44ac 100644
--- a/src/tint/lang/wgsl/writer/raise/BUILD.gn
+++ b/src/tint/lang/wgsl/writer/raise/BUILD.gn
@@ -25,7 +25,7 @@
 
 import("${tint_src_dir}/tint.gni")
 
-if (tint_build_unittests) {
+if (tint_build_unittests || tint_build_benchmarks) {
   import("//testing/test.gni")
 }
 
diff --git a/src/tint/lang/wgsl/writer/writer_bench.cc b/src/tint/lang/wgsl/writer/writer_bench.cc
index 05f349a..3a4157d 100644
--- a/src/tint/lang/wgsl/writer/writer_bench.cc
+++ b/src/tint/lang/wgsl/writer/writer_bench.cc
@@ -22,15 +22,14 @@
 
 void GenerateWGSL(benchmark::State& state, std::string input_name) {
     auto res = bench::LoadProgram(input_name);
-    if (auto err = std::get_if<bench::Error>(&res)) {
-        state.SkipWithError(err->msg.c_str());
+    if (!res) {
+        state.SkipWithError(res.Failure().reason.str());
         return;
     }
-    auto& program = std::get<bench::ProgramAndFile>(res).program;
     for (auto _ : state) {
-        auto res = Generate(program, {});
-        if (!res) {
-            state.SkipWithError(res.Failure().reason.str());
+        auto gen_res = Generate(res->program, {});
+        if (!gen_res) {
+            state.SkipWithError(gen_res.Failure().reason.str());
         }
     }
 }