[tint][spirv] Add validate library
Matches the HLSL and MSL validation sub-libraries.
Change-Id: I9fc7e3f31a40a807e292459003192513545fa57d
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/162403
Kokoro: Kokoro <noreply+kokoro@google.com>
Reviewed-by: dan sinclair <dsinclair@chromium.org>
diff --git a/src/tint/cmd/test/BUILD.bazel b/src/tint/cmd/test/BUILD.bazel
index 6c3f01e..baf7681 100644
--- a/src/tint/cmd/test/BUILD.bazel
+++ b/src/tint/cmd/test/BUILD.bazel
@@ -124,6 +124,11 @@
],
"//conditions:default": [],
}) + select({
+ ":tint_build_spv_reader_or_tint_build_spv_writer": [
+ "//src/tint/lang/spirv/validate:test",
+ ],
+ "//conditions:default": [],
+ }) + select({
":tint_build_spv_writer": [
"//src/tint/lang/spirv/writer/ast_printer:test",
"//src/tint/lang/spirv/writer/common:test",
@@ -194,6 +199,14 @@
)
selects.config_setting_group(
+ name = "tint_build_spv_reader_or_tint_build_spv_writer",
+ match_any = [
+ "tint_build_spv_reader",
+ "tint_build_spv_writer",
+ ],
+)
+
+selects.config_setting_group(
name = "tint_build_glsl_writer_and_tint_build_wgsl_reader_and_tint_build_wgsl_writer",
match_all = [
":tint_build_glsl_writer",
diff --git a/src/tint/cmd/test/BUILD.cmake b/src/tint/cmd/test/BUILD.cmake
index 8dac742..519faf7 100644
--- a/src/tint/cmd/test/BUILD.cmake
+++ b/src/tint/cmd/test/BUILD.cmake
@@ -137,6 +137,12 @@
)
endif(TINT_BUILD_SPV_READER AND TINT_BUILD_WGSL_WRITER)
+if(TINT_BUILD_SPV_READER OR TINT_BUILD_SPV_WRITER)
+ tint_target_add_dependencies(tint_cmd_test_test_cmd test_cmd
+ tint_lang_spirv_validate_test
+ )
+endif(TINT_BUILD_SPV_READER OR TINT_BUILD_SPV_WRITER)
+
if(TINT_BUILD_SPV_WRITER)
tint_target_add_dependencies(tint_cmd_test_test_cmd test_cmd
tint_lang_spirv_writer_ast_printer_test
diff --git a/src/tint/cmd/test/BUILD.gn b/src/tint/cmd/test/BUILD.gn
index 9a45716..1700779 100644
--- a/src/tint/cmd/test/BUILD.gn
+++ b/src/tint/cmd/test/BUILD.gn
@@ -130,6 +130,10 @@
deps += [ "${tint_src_dir}/lang/spirv/reader/ast_parser:unittests" ]
}
+ if (tint_build_spv_reader || tint_build_spv_writer) {
+ deps += [ "${tint_src_dir}/lang/spirv/validate:unittests" ]
+ }
+
if (tint_build_spv_writer) {
deps += [
"${tint_src_dir}/lang/spirv/writer:unittests",
diff --git a/src/tint/lang/msl/validate/validate.h b/src/tint/lang/msl/validate/validate.h
index 89581d6..1a303d5 100644
--- a/src/tint/lang/msl/validate/validate.h
+++ b/src/tint/lang/msl/validate/validate.h
@@ -61,7 +61,7 @@
std::string output;
};
-/// Msl attempts to compile the shader with the Metal Shader Compiler,
+/// Validate attempts to compile the shader with the Metal Shader Compiler,
/// verifying that the shader compiles successfully.
/// @param xcrun_path path to xcrun
/// @param source the generated MSL source
@@ -70,7 +70,7 @@
Result Validate(const std::string& xcrun_path, const std::string& source, MslVersion version);
#ifdef __APPLE__
-/// Msl attempts to compile the shader with the runtime Metal Shader Compiler
+/// ValidateUsingMetal attempts to compile the shader with the runtime Metal Shader Compiler
/// API, verifying that the shader compiles successfully.
/// @param source the generated MSL source
/// @param version the version of MSL to validate against
diff --git a/src/tint/lang/spirv/BUILD.cmake b/src/tint/lang/spirv/BUILD.cmake
index 30c3163..06f7cfd 100644
--- a/src/tint/lang/spirv/BUILD.cmake
+++ b/src/tint/lang/spirv/BUILD.cmake
@@ -38,6 +38,7 @@
include(lang/spirv/ir/BUILD.cmake)
include(lang/spirv/reader/BUILD.cmake)
include(lang/spirv/type/BUILD.cmake)
+include(lang/spirv/validate/BUILD.cmake)
include(lang/spirv/writer/BUILD.cmake)
################################################################################
diff --git a/src/tint/lang/spirv/validate/BUILD.bazel b/src/tint/lang/spirv/validate/BUILD.bazel
new file mode 100644
index 0000000..bc1d952
--- /dev/null
+++ b/src/tint/lang/spirv/validate/BUILD.bazel
@@ -0,0 +1,112 @@
+# 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.
+
+################################################################################
+# File generated by 'tools/src/cmd/gen' using the template:
+# tools/src/cmd/gen/build/BUILD.bazel.tmpl
+#
+# To regenerate run: './tools/run gen'
+#
+# Do not modify this file directly
+################################################################################
+
+load("//src/tint:flags.bzl", "COPTS")
+load("@bazel_skylib//lib:selects.bzl", "selects")
+cc_library(
+ name = "validate",
+ srcs = [
+ "validate.cc",
+ ],
+ hdrs = [
+ "validate.h",
+ ],
+ deps = [
+ "//src/tint/utils/containers",
+ "//src/tint/utils/diagnostic",
+ "//src/tint/utils/ice",
+ "//src/tint/utils/macros",
+ "//src/tint/utils/math",
+ "//src/tint/utils/memory",
+ "//src/tint/utils/result",
+ "//src/tint/utils/rtti",
+ "//src/tint/utils/text",
+ "//src/tint/utils/traits",
+ ] + select({
+ ":tint_build_spv_reader_or_tint_build_spv_writer": [
+ "@spirv_tools",
+ ],
+ "//conditions:default": [],
+ }),
+ copts = COPTS,
+ visibility = ["//visibility:public"],
+)
+cc_library(
+ name = "test",
+ alwayslink = True,
+ srcs = [
+ "validate_test.cc",
+ ],
+ deps = [
+ "//src/tint/utils/containers",
+ "//src/tint/utils/diagnostic",
+ "//src/tint/utils/ice",
+ "//src/tint/utils/macros",
+ "//src/tint/utils/math",
+ "//src/tint/utils/memory",
+ "//src/tint/utils/result",
+ "//src/tint/utils/rtti",
+ "//src/tint/utils/text",
+ "//src/tint/utils/traits",
+ "@gtest",
+ ] + select({
+ ":tint_build_spv_reader_or_tint_build_spv_writer": [
+ "//src/tint/lang/spirv/validate",
+ ],
+ "//conditions:default": [],
+ }),
+ copts = COPTS,
+ visibility = ["//visibility:public"],
+)
+
+alias(
+ name = "tint_build_spv_reader",
+ actual = "//src/tint:tint_build_spv_reader_true",
+)
+
+alias(
+ name = "tint_build_spv_writer",
+ actual = "//src/tint:tint_build_spv_writer_true",
+)
+
+selects.config_setting_group(
+ name = "tint_build_spv_reader_or_tint_build_spv_writer",
+ match_any = [
+ "tint_build_spv_reader",
+ "tint_build_spv_writer",
+ ],
+)
+
diff --git a/src/tint/lang/spirv/validate/BUILD.cfg b/src/tint/lang/spirv/validate/BUILD.cfg
new file mode 100644
index 0000000..3b3caf4
--- /dev/null
+++ b/src/tint/lang/spirv/validate/BUILD.cfg
@@ -0,0 +1,3 @@
+{
+ "condition": "tint_build_spv_reader || tint_build_spv_writer"
+}
diff --git a/src/tint/lang/spirv/validate/BUILD.cmake b/src/tint/lang/spirv/validate/BUILD.cmake
new file mode 100644
index 0000000..e50d0e9
--- /dev/null
+++ b/src/tint/lang/spirv/validate/BUILD.cmake
@@ -0,0 +1,101 @@
+# 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.
+
+################################################################################
+# File generated by 'tools/src/cmd/gen' using the template:
+# tools/src/cmd/gen/build/BUILD.cmake.tmpl
+#
+# To regenerate run: './tools/run gen'
+#
+# Do not modify this file directly
+################################################################################
+
+if(TINT_BUILD_SPV_READER OR TINT_BUILD_SPV_WRITER)
+################################################################################
+# Target: tint_lang_spirv_validate
+# Kind: lib
+# Condition: TINT_BUILD_SPV_READER OR TINT_BUILD_SPV_WRITER
+################################################################################
+tint_add_target(tint_lang_spirv_validate lib
+ lang/spirv/validate/validate.cc
+ lang/spirv/validate/validate.h
+)
+
+tint_target_add_dependencies(tint_lang_spirv_validate lib
+ tint_utils_containers
+ tint_utils_diagnostic
+ tint_utils_ice
+ tint_utils_macros
+ tint_utils_math
+ tint_utils_memory
+ tint_utils_result
+ tint_utils_rtti
+ tint_utils_text
+ tint_utils_traits
+)
+
+if(TINT_BUILD_SPV_READER OR TINT_BUILD_SPV_WRITER)
+ tint_target_add_external_dependencies(tint_lang_spirv_validate lib
+ "spirv-tools"
+ )
+endif(TINT_BUILD_SPV_READER OR TINT_BUILD_SPV_WRITER)
+
+endif(TINT_BUILD_SPV_READER OR TINT_BUILD_SPV_WRITER)
+if(TINT_BUILD_SPV_READER OR TINT_BUILD_SPV_WRITER)
+################################################################################
+# Target: tint_lang_spirv_validate_test
+# Kind: test
+# Condition: TINT_BUILD_SPV_READER OR TINT_BUILD_SPV_WRITER
+################################################################################
+tint_add_target(tint_lang_spirv_validate_test test
+ lang/spirv/validate/validate_test.cc
+)
+
+tint_target_add_dependencies(tint_lang_spirv_validate_test test
+ tint_utils_containers
+ tint_utils_diagnostic
+ tint_utils_ice
+ tint_utils_macros
+ tint_utils_math
+ tint_utils_memory
+ tint_utils_result
+ tint_utils_rtti
+ tint_utils_text
+ tint_utils_traits
+)
+
+tint_target_add_external_dependencies(tint_lang_spirv_validate_test test
+ "gtest"
+)
+
+if(TINT_BUILD_SPV_READER OR TINT_BUILD_SPV_WRITER)
+ tint_target_add_dependencies(tint_lang_spirv_validate_test test
+ tint_lang_spirv_validate
+ )
+endif(TINT_BUILD_SPV_READER OR TINT_BUILD_SPV_WRITER)
+
+endif(TINT_BUILD_SPV_READER OR TINT_BUILD_SPV_WRITER)
\ No newline at end of file
diff --git a/src/tint/lang/spirv/validate/BUILD.gn b/src/tint/lang/spirv/validate/BUILD.gn
new file mode 100644
index 0000000..99890f7
--- /dev/null
+++ b/src/tint/lang/spirv/validate/BUILD.gn
@@ -0,0 +1,94 @@
+# 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.
+
+################################################################################
+# File generated by 'tools/src/cmd/gen' using the template:
+# tools/src/cmd/gen/build/BUILD.gn.tmpl
+#
+# To regenerate run: './tools/run gen'
+#
+# Do not modify this file directly
+################################################################################
+
+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_spv_reader || tint_build_spv_writer) {
+ libtint_source_set("validate") {
+ sources = [
+ "validate.cc",
+ "validate.h",
+ ]
+ deps = [
+ "${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/result",
+ "${tint_src_dir}/utils/rtti",
+ "${tint_src_dir}/utils/text",
+ "${tint_src_dir}/utils/traits",
+ ]
+
+ if (tint_build_spv_reader || tint_build_spv_writer) {
+ deps += [
+ "${tint_spirv_tools_dir}:spvtools_headers",
+ "${tint_spirv_tools_dir}:spvtools_val",
+ ]
+ }
+ }
+}
+if (tint_build_unittests) {
+ if (tint_build_spv_reader || tint_build_spv_writer) {
+ tint_unittests_source_set("unittests") {
+ sources = [ "validate_test.cc" ]
+ deps = [
+ "${tint_src_dir}:gmock_and_gtest",
+ "${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/result",
+ "${tint_src_dir}/utils/rtti",
+ "${tint_src_dir}/utils/text",
+ "${tint_src_dir}/utils/traits",
+ ]
+
+ if (tint_build_spv_reader || tint_build_spv_writer) {
+ deps += [ "${tint_src_dir}/lang/spirv/validate" ]
+ }
+ }
+ }
+}
diff --git a/src/tint/lang/spirv/validate/validate.cc b/src/tint/lang/spirv/validate/validate.cc
new file mode 100644
index 0000000..13344b7
--- /dev/null
+++ b/src/tint/lang/spirv/validate/validate.cc
@@ -0,0 +1,91 @@
+// 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 "src/tint/lang/spirv/validate/validate.h"
+
+#include <memory>
+#include <string>
+#include <utility>
+
+#include "spirv-tools/libspirv.hpp"
+
+namespace tint::spirv::validate {
+
+Result<SuccessType> Validate(Slice<const uint32_t> spirv) {
+ Vector<diag::Diagnostic, 4> diags;
+ diags.Push(diag::Diagnostic{}); // Filled in on error
+
+ spvtools::SpirvTools tools(SPV_ENV_VULKAN_1_3);
+ tools.SetMessageConsumer(
+ [&](spv_message_level_t level, const char*, const spv_position_t& pos, const char* msg) {
+ diag::Diagnostic diag;
+ diag.message = msg;
+ diag.source.range.begin.line = pos.line + 1;
+ diag.source.range.begin.column = pos.column + 1;
+ diag.source.range.end = diag.source.range.begin;
+ switch (level) {
+ case SPV_MSG_FATAL:
+ case SPV_MSG_INTERNAL_ERROR:
+ case SPV_MSG_ERROR:
+ diag.severity = diag::Severity::Error;
+ break;
+ case SPV_MSG_WARNING:
+ diag.severity = diag::Severity::Warning;
+ break;
+ case SPV_MSG_INFO:
+ case SPV_MSG_DEBUG:
+ diag.severity = diag::Severity::Note;
+ break;
+ }
+ diags.Push(std::move(diag));
+ });
+
+ if (tools.Validate(spirv.data, spirv.len)) {
+ return Success;
+ }
+
+ std::string disassembly;
+ if (tools.Disassemble(
+ spirv.data, spirv.len, &disassembly,
+ SPV_BINARY_TO_TEXT_OPTION_INDENT | SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES)) {
+ diag::Diagnostic& err = diags.Front();
+ err.message = "SPIR-V failed validation.\n\nDisassembly:\n" + std::move(disassembly);
+ err.severity = diag::Severity::Error;
+ } else {
+ diag::Diagnostic& err = diags.Front();
+ err.message = "SPIR-V failed validation and disassembly\n";
+ err.severity = diag::Severity::Error;
+ }
+ auto file = std::make_shared<Source::File>("spirv", disassembly);
+ for (auto& diag : diags) {
+ diag.source.file = file.get();
+ diag.owned_file = file;
+ }
+ return Failure{diag::List{std::move(diags)}};
+}
+
+} // namespace tint::spirv::validate
diff --git a/src/tint/lang/spirv/validate/validate.h b/src/tint/lang/spirv/validate/validate.h
new file mode 100644
index 0000000..840d90f
--- /dev/null
+++ b/src/tint/lang/spirv/validate/validate.h
@@ -0,0 +1,46 @@
+// 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.
+
+#ifndef SRC_TINT_LANG_SPIRV_VALIDATE_VALIDATE_H_
+#define SRC_TINT_LANG_SPIRV_VALIDATE_VALIDATE_H_
+
+#include "src/tint/utils/result/result.h"
+
+// Forward declarations
+namespace tint {
+class Program;
+} // namespace tint
+
+namespace tint::spirv::validate {
+
+/// Validate checks that the provided SPIR-V passes validation.
+/// @return success or failure(s)
+Result<SuccessType> Validate(Slice<const uint32_t> spirv);
+
+} // namespace tint::spirv::validate
+
+#endif // SRC_TINT_LANG_SPIRV_VALIDATE_VALIDATE_H_
diff --git a/src/tint/lang/spirv/validate/validate_test.cc b/src/tint/lang/spirv/validate/validate_test.cc
new file mode 100644
index 0000000..96ba63e
--- /dev/null
+++ b/src/tint/lang/spirv/validate/validate_test.cc
@@ -0,0 +1,113 @@
+// 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 "gtest/gtest.h"
+
+#include "src/tint/lang/spirv/validate/validate.h"
+
+namespace tint::spirv::validate {
+namespace {
+
+TEST(SpirvValidateTest, Valid) {
+ uint32_t spirv[] = {
+ 0x07230203, 0x00010600, 0x00070000, 0x00000011, 0x00000000, 0x00020011, 0x00000001,
+ 0x0003000e, 0x00000000, 0x00000001, 0x0005000f, 0x00000005, 0x00000001, 0x6e69616d,
+ 0x00000000, 0x00060010, 0x00000001, 0x00000011, 0x00000001, 0x00000001, 0x00000001,
+ 0x00040005, 0x00000001, 0x6e69616d, 0x00000000, 0x00030005, 0x00000002, 0x0000006d,
+ 0x00020013, 0x00000003, 0x00030021, 0x00000004, 0x00000003, 0x00030016, 0x00000005,
+ 0x00000020, 0x00040017, 0x00000006, 0x00000005, 0x00000003, 0x00040018, 0x00000007,
+ 0x00000006, 0x00000003, 0x00040020, 0x00000008, 0x00000007, 0x00000007, 0x0003002e,
+ 0x00000007, 0x00000009, 0x00040015, 0x0000000a, 0x00000020, 0x00000001, 0x0004002b,
+ 0x0000000a, 0x0000000b, 0x00000001, 0x00040020, 0x0000000c, 0x00000007, 0x00000006,
+ 0x00050036, 0x00000003, 0x00000001, 0x00000000, 0x00000004, 0x000200f8, 0x0000000d,
+ 0x0005003b, 0x00000008, 0x00000002, 0x00000007, 0x00000009, 0x00050041, 0x0000000c,
+ 0x0000000e, 0x00000002, 0x0000000b, 0x0004003d, 0x00000006, 0x0000000f, 0x0000000e,
+ 0x00050051, 0x00000005, 0x00000010, 0x0000000f, 0x00000001, 0x000100fd, 0x00010038,
+ };
+ auto res = Validate(spirv);
+ EXPECT_TRUE(res) << res;
+}
+
+TEST(SpirvValidateTest, Invalid) {
+ uint32_t spirv[] = {
+ 0x07230203, 0x00010600, 0x00070000, 0x00000011, 0x00000000, 0x00020011, 0x00000001,
+ 0x0003000e, 0x00000000, 0x00000001, 0x0005000f, 0x00000005, 0x00000001, 0x6e69616d,
+ 0x00000000, 0x00060010, 0x00000001, 0x00000011, 0x00000001, 0x00000001, 0x00000001,
+ 0x00040005, 0x00000001, 0x6e69616d, 0x00000000, 0x00030005, 0x00000002, 0x0000006d,
+ 0x00020013, 0x00000003, 0x00030021, 0x00000004, 0x00000003, 0x00030016, 0x00000005,
+ 0x00000020, 0x00040017, 0x00000006, 0x00000005, 0x00000003, 0x00040018, 0x00000007,
+ 0x00000006, 0x00000003, 0x00040020, 0x00000008, 0x00000007, 0x00000007, 0x0003002e,
+ 0x00000006, 0x00000009, 0x00040015, 0x0000000a, 0x00000020, 0x00000001, 0x0004002b,
+ 0x0000000a, 0x0000000b, 0x00000001, 0x00040020, 0x0000000c, 0x00000007, 0x00000006,
+ 0x00050036, 0x00000003, 0x00000001, 0x00000000, 0x00000004, 0x000200f8, 0x0000000d,
+ 0x0005003b, 0x00000008, 0x00000002, 0x00000007, 0x00000009, 0x00050041, 0x0000000c,
+ 0x0000000e, 0x00000002, 0x0000000b, 0x0004003d, 0x00000006, 0x0000000f, 0x0000000e,
+ 0x00050051, 0x00000005, 0x00000010, 0x0000000f, 0x00000001, 0x000100fd, 0x00010038,
+ };
+ auto res = Validate(spirv);
+ ASSERT_FALSE(res);
+ EXPECT_EQ(res.Failure().reason.str(), R"(spirv error: SPIR-V failed validation.
+
+Disassembly:
+; SPIR-V
+; Version: 1.6
+; Generator: Khronos SPIR-V Tools Assembler; 0
+; Bound: 17
+; Schema: 0
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint GLCompute %main "main"
+ OpExecutionMode %main LocalSize 1 1 1
+ OpName %main "main"
+ OpName %m "m"
+ %void = OpTypeVoid
+ %4 = OpTypeFunction %void
+ %float = OpTypeFloat 32
+ %v3float = OpTypeVector %float 3
+%mat3v3float = OpTypeMatrix %v3float 3
+%_ptr_Function_mat3v3float = OpTypePointer Function %mat3v3float
+ %9 = OpConstantNull %v3float
+ %int = OpTypeInt 32 1
+ %int_1 = OpConstant %int 1
+%_ptr_Function_v3float = OpTypePointer Function %v3float
+ %main = OpFunction %void None %4
+ %13 = OpLabel
+ %m = OpVariable %_ptr_Function_mat3v3float Function %9
+ %14 = OpAccessChain %_ptr_Function_v3float %m %int_1
+ %15 = OpLoad %v3float %14
+ %16 = OpCompositeExtract %float %15 1
+ OpReturn
+ OpFunctionEnd
+
+spirv:1:1 error: Initializer type must match the type pointed to by the Result Type
+ %m = OpVariable %_ptr_Function_mat3v3float Function %9
+
+)");
+}
+
+} // namespace
+} // namespace tint::spirv::validate