[tint] Add support for benchmarking .spv files

Change-Id: Id687d5208e9f39ae7b40db4d90c194283ebac91b
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/132642
Reviewed-by: James Price <jrprice@google.com>
Kokoro: Ben Clayton <bclayton@google.com>
Commit-Queue: Ben Clayton <bclayton@google.com>
diff --git a/src/tint/CMakeLists.txt b/src/tint/CMakeLists.txt
index 41304ae..ea69d50 100644
--- a/src/tint/CMakeLists.txt
+++ b/src/tint/CMakeLists.txt
@@ -1546,24 +1546,42 @@
 
   if (TINT_EXTERNAL_BENCHMARK_CORPUS_DIR)
     # Glob all the files at TINT_EXTERNAL_BENCHMARK_CORPUS_DIR, and create a header
-    # that lists these with the TINT_BENCHMARK_EXTERNAL_WGSL_PROGRAMS() macro
+    # that lists these with the macros:
+    # TINT_BENCHMARK_EXTERNAL_WGSL_PROGRAMS()
+    # TINT_BENCHMARK_EXTERNAL_SPV_PROGRAMS()
     set(TINT_BENCHMARK_GEN_DIR "${DAWN_BUILD_GEN_DIR}/src/tint/benchmark/")
-    set(TINT_BENCHMARK_EXTERNAL_WGSL_PROGRAM_HEADER "${TINT_BENCHMARK_GEN_DIR}/external_wgsl_programs.h")
+    set(TINT_BENCHMARK_EXTERNAL_SHADERS_HEADER "${TINT_BENCHMARK_GEN_DIR}/external_wgsl_programs.h")
     message("Globbing ${TINT_EXTERNAL_BENCHMARK_CORPUS_DIR}...")
+
     file(GLOB_RECURSE
-      TINT_EXTERNAL_BENCHMARK_FILES
+      TINT_EXTERNAL_WGSL_BENCHMARK_FILES
       RELATIVE "${TINT_EXTERNAL_BENCHMARK_CORPUS_DIR}"
       "${TINT_EXTERNAL_BENCHMARK_CORPUS_DIR}/**.wgsl")
-    list(TRANSFORM TINT_EXTERNAL_BENCHMARK_FILES REPLACE
+    list(TRANSFORM TINT_EXTERNAL_WGSL_BENCHMARK_FILES REPLACE
       "(.+)"
       "    BENCHMARK_CAPTURE\(FUNC, \"\\1\", \"${TINT_EXTERNAL_BENCHMARK_CORPUS_DIR}/\\1\")")
-    list(JOIN TINT_EXTERNAL_BENCHMARK_FILES "; \\\n" TINT_EXTERNAL_BENCHMARK_FILES)
+    list(JOIN TINT_EXTERNAL_WGSL_BENCHMARK_FILES "; \\\n" TINT_EXTERNAL_WGSL_BENCHMARK_FILES)
+
+    file(GLOB_RECURSE
+      TINT_EXTERNAL_SPV_BENCHMARK_FILES
+      RELATIVE "${TINT_EXTERNAL_BENCHMARK_CORPUS_DIR}"
+      "${TINT_EXTERNAL_BENCHMARK_CORPUS_DIR}/**.spv")
+
+      list(TRANSFORM TINT_EXTERNAL_SPV_BENCHMARK_FILES REPLACE
+      "(.+)"
+      "    BENCHMARK_CAPTURE\(FUNC, \"\\1\", \"${TINT_EXTERNAL_BENCHMARK_CORPUS_DIR}/\\1\")")
+    list(JOIN TINT_EXTERNAL_SPV_BENCHMARK_FILES "; \\\n" TINT_EXTERNAL_SPV_BENCHMARK_FILES)
+
     file(CONFIGURE
-      OUTPUT "${TINT_BENCHMARK_EXTERNAL_WGSL_PROGRAM_HEADER}"
-      CONTENT "#define TINT_BENCHMARK_EXTERNAL_WGSL_PROGRAMS(FUNC) \\
-${TINT_EXTERNAL_BENCHMARK_FILES};")
-    # Define TINT_BENCHMARK_EXTERNAL_WGSL_PROGRAM_HEADER to the generated header path
+      OUTPUT "${TINT_BENCHMARK_EXTERNAL_SHADERS_HEADER}"
+      CONTENT "
+#define TINT_BENCHMARK_EXTERNAL_WGSL_PROGRAMS(FUNC) \\
+${TINT_EXTERNAL_WGSL_BENCHMARK_FILES};
+
+#define TINT_BENCHMARK_EXTERNAL_SPV_PROGRAMS(FUNC) \\
+${TINT_EXTERNAL_SPV_BENCHMARK_FILES};")
+    # Define TINT_BENCHMARK_EXTERNAL_SHADERS_HEADER to the generated header path
     target_compile_definitions(tint-benchmark PRIVATE
-      "TINT_BENCHMARK_EXTERNAL_WGSL_PROGRAM_HEADER=\"${TINT_BENCHMARK_EXTERNAL_WGSL_PROGRAM_HEADER}\"")
+      "TINT_BENCHMARK_EXTERNAL_SHADERS_HEADER=\"${TINT_BENCHMARK_EXTERNAL_SHADERS_HEADER}\"")
   endif()
 endif(TINT_BUILD_BENCHMARKS)
diff --git a/src/tint/bench/benchmark.cc b/src/tint/bench/benchmark.cc
index 5a28e95..2338681 100644
--- a/src/tint/bench/benchmark.cc
+++ b/src/tint/bench/benchmark.cc
@@ -89,12 +89,30 @@
 }  // namespace
 
 std::variant<tint::Source::File, Error> LoadInputFile(std::string name) {
-    auto path = (kInputFileDir / name).string();
-    auto data = ReadFile<uint8_t>(path);
-    if (auto* buf = std::get_if<std::vector<uint8_t>>(&data)) {
-        return tint::Source::File(path, std::string(buf->begin(), buf->end()));
+    auto path = std::filesystem::path(name).is_absolute() ? name : (kInputFileDir / name).string();
+    if (utils::HasSuffix(path, ".wgsl")) {
+        auto data = ReadFile<uint8_t>(path);
+        if (auto* buf = std::get_if<std::vector<uint8_t>>(&data)) {
+            return tint::Source::File(path, std::string(buf->begin(), buf->end()));
+        }
+        return std::get<Error>(data);
     }
-    return std::get<Error>(data);
+    if (utils::HasSuffix(path, ".spv")) {
+        auto spirv = ReadFile<uint32_t>(path);
+        if (auto* buf = std::get_if<std::vector<uint32_t>>(&spirv)) {
+            auto program = tint::reader::spirv::Parse(*buf, {});
+            if (!program.IsValid()) {
+                return Error{program.Diagnostics().str()};
+            }
+            auto result = tint::writer::wgsl::Generate(&program, {});
+            if (!result.success) {
+                return Error{result.error};
+            }
+            return tint::Source::File(path, result.wgsl);
+        }
+        return std::get<Error>(spirv);
+    }
+    return Error{"unsupported file extension: '" + name + "'"};
 }
 
 std::variant<ProgramAndFile, Error> LoadProgram(std::string name) {
diff --git a/src/tint/bench/benchmark.h b/src/tint/bench/benchmark.h
index adb28b8..4a0b29e 100644
--- a/src/tint/bench/benchmark.h
+++ b/src/tint/bench/benchmark.h
@@ -40,7 +40,8 @@
 };
 
 /// LoadInputFile attempts to load a benchmark input file with the given file
-/// name.
+/// name. Accepts files with the .wgsl and .spv extension.
+/// SPIR-V files are automatically converted to WGSL.
 /// @param name the file name
 /// @returns either the loaded Source::File or an Error
 std::variant<Source::File, Error> LoadInputFile(std::string name);
@@ -51,20 +52,21 @@
 /// @returns either the loaded Program or an Error
 std::variant<ProgramAndFile, Error> LoadProgram(std::string name);
 
-// If TINT_BENCHMARK_EXTERNAL_WGSL_PROGRAM_HEADER is defined, include that to
-// declare the TINT_BENCHMARK_EXTERNAL_WGSL_PROGRAMS() macro, which appends
-// external programs to the TINT_BENCHMARK_WGSL_PROGRAMS() list.
-#ifdef TINT_BENCHMARK_EXTERNAL_WGSL_PROGRAM_HEADER
-#include TINT_BENCHMARK_EXTERNAL_WGSL_PROGRAM_HEADER
+// If TINT_BENCHMARK_EXTERNAL_SHADERS_HEADER is defined, include that to
+// declare the TINT_BENCHMARK_EXTERNAL_WGSL_PROGRAMS() and TINT_BENCHMARK_EXTERNAL_SPV_PROGRAMS()
+// macros, which appends external programs to the TINT_BENCHMARK_WGSL_PROGRAMS() and
+// TINT_BENCHMARK_SPV_PROGRAMS() list.
+#ifdef TINT_BENCHMARK_EXTERNAL_SHADERS_HEADER
+#include TINT_BENCHMARK_EXTERNAL_SHADERS_HEADER
 #else
 #define TINT_BENCHMARK_EXTERNAL_WGSL_PROGRAMS(x)
+#define TINT_BENCHMARK_EXTERNAL_SPV_PROGRAMS(x)
 #endif
 
 /// Declares a benchmark with the given function and WGSL file name
 #define TINT_BENCHMARK_WGSL_PROGRAM(FUNC, WGSL_NAME) BENCHMARK_CAPTURE(FUNC, WGSL_NAME, WGSL_NAME);
 
-/// Declares a set of benchmarks for the given function using a list of WGSL
-/// files in `<tint>/test/benchmark`.
+/// Declares a set of benchmarks for the given function using a list of WGSL files.
 #define TINT_BENCHMARK_WGSL_PROGRAMS(FUNC)                                   \
     TINT_BENCHMARK_WGSL_PROGRAM(FUNC, "animometer.wgsl");                    \
     TINT_BENCHMARK_WGSL_PROGRAM(FUNC, "atan2-const-eval.wgsl");              \
@@ -81,6 +83,14 @@
     TINT_BENCHMARK_WGSL_PROGRAM(FUNC, "skinned-shadowed-pbr-vertex.wgsl");   \
     TINT_BENCHMARK_EXTERNAL_WGSL_PROGRAMS(FUNC)
 
+/// Declares a set of benchmarks for the given function using a list of SPIR-V files.
+#define TINT_BENCHMARK_SPV_PROGRAMS(FUNC) TINT_BENCHMARK_EXTERNAL_SPV_PROGRAMS(FUNC)
+
+/// Declares a set of benchmarks for the given function using a list of WGSL and SPIR-V files.
+#define TINT_BENCHMARK_PROGRAMS(FUNC)  \
+    TINT_BENCHMARK_WGSL_PROGRAMS(FUNC) \
+    TINT_BENCHMARK_SPV_PROGRAMS(FUNC)
+
 }  // namespace tint::bench
 
 #endif  // SRC_TINT_BENCH_BENCHMARK_H_
diff --git a/src/tint/reader/wgsl/parser_bench.cc b/src/tint/reader/wgsl/parser_bench.cc
index 097accf..a7a04d6 100644
--- a/src/tint/reader/wgsl/parser_bench.cc
+++ b/src/tint/reader/wgsl/parser_bench.cc
@@ -34,7 +34,7 @@
     }
 }
 
-TINT_BENCHMARK_WGSL_PROGRAMS(ParseWGSL);
+TINT_BENCHMARK_PROGRAMS(ParseWGSL);
 
 }  // namespace
 }  // namespace tint::reader::wgsl
diff --git a/src/tint/writer/glsl/generator_bench.cc b/src/tint/writer/glsl/generator_bench.cc
index f591011..07a7cdf 100644
--- a/src/tint/writer/glsl/generator_bench.cc
+++ b/src/tint/writer/glsl/generator_bench.cc
@@ -45,7 +45,7 @@
     }
 }
 
-TINT_BENCHMARK_WGSL_PROGRAMS(GenerateGLSL);
+TINT_BENCHMARK_PROGRAMS(GenerateGLSL);
 
 }  // namespace
 }  // namespace tint::writer::glsl
diff --git a/src/tint/writer/hlsl/generator_bench.cc b/src/tint/writer/hlsl/generator_bench.cc
index 4567e2d..b03038d 100644
--- a/src/tint/writer/hlsl/generator_bench.cc
+++ b/src/tint/writer/hlsl/generator_bench.cc
@@ -34,7 +34,7 @@
     }
 }
 
-TINT_BENCHMARK_WGSL_PROGRAMS(GenerateHLSL);
+TINT_BENCHMARK_PROGRAMS(GenerateHLSL);
 
 }  // namespace
 }  // namespace tint::writer::hlsl
diff --git a/src/tint/writer/msl/generator_bench.cc b/src/tint/writer/msl/generator_bench.cc
index c58ede5..a6242dd 100644
--- a/src/tint/writer/msl/generator_bench.cc
+++ b/src/tint/writer/msl/generator_bench.cc
@@ -53,7 +53,7 @@
     }
 }
 
-TINT_BENCHMARK_WGSL_PROGRAMS(GenerateMSL);
+TINT_BENCHMARK_PROGRAMS(GenerateMSL);
 
 }  // namespace
 }  // namespace tint::writer::msl
diff --git a/src/tint/writer/spirv/generator_bench.cc b/src/tint/writer/spirv/generator_bench.cc
index 4aac8bc..09ee791 100644
--- a/src/tint/writer/spirv/generator_bench.cc
+++ b/src/tint/writer/spirv/generator_bench.cc
@@ -34,7 +34,7 @@
     }
 }
 
-TINT_BENCHMARK_WGSL_PROGRAMS(GenerateSPIRV);
+TINT_BENCHMARK_PROGRAMS(GenerateSPIRV);
 
 }  // namespace
 }  // namespace tint::writer::spirv
diff --git a/src/tint/writer/wgsl/generator_bench.cc b/src/tint/writer/wgsl/generator_bench.cc
index a9efacc..5e544e4 100644
--- a/src/tint/writer/wgsl/generator_bench.cc
+++ b/src/tint/writer/wgsl/generator_bench.cc
@@ -34,7 +34,7 @@
     }
 }
 
-TINT_BENCHMARK_WGSL_PROGRAMS(GenerateWGSL);
+TINT_BENCHMARK_PROGRAMS(GenerateWGSL);
 
 }  // namespace
 }  // namespace tint::writer::wgsl