aboutsummaryrefslogtreecommitdiff
path: root/test/val/val_capability_test.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'test/val/val_capability_test.cpp')
-rw-r--r--test/val/val_capability_test.cpp1239
1 files changed, 1239 insertions, 0 deletions
diff --git a/test/val/val_capability_test.cpp b/test/val/val_capability_test.cpp
new file mode 100644
index 00000000..2604187e
--- /dev/null
+++ b/test/val/val_capability_test.cpp
@@ -0,0 +1,1239 @@
+// Copyright (c) 2015-2016 The Khronos Group Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// Validation tests for Logical Layout
+
+#include <sstream>
+#include <string>
+#include <tuple>
+#include <utility>
+
+#include <gmock/gmock.h>
+
+#include "source/assembly_grammar.h"
+#include "test_fixture.h"
+#include "unit_spirv.h"
+#include "val_fixtures.h"
+
+namespace {
+
+using spvtest::ScopedContext;
+using std::get;
+using std::make_pair;
+using std::ostringstream;
+using std::pair;
+using std::string;
+using std::tuple;
+using std::vector;
+using testing::Combine;
+using testing::Values;
+using testing::ValuesIn;
+
+// Parameter for validation test fixtures. The first string is a capability
+// name that will begin the assembly under test, the second the remainder
+// assembly, and the vector at the end determines whether the test expects
+// success or failure. See below for details and convenience methods to access
+// each one.
+//
+// The assembly to test is composed from a variable top line and a fixed
+// remainder. The top line will be an OpCapability instruction, while the
+// remainder will be some assembly text that succeeds or fails to assemble
+// depending on which capability was chosen. For instance, the following will
+// succeed:
+//
+// OpCapability Pipes ; implies Kernel
+// OpLifetimeStop %1 0 ; requires Kernel
+//
+// and the following will fail:
+//
+// OpCapability Kernel
+// %1 = OpTypeNamedBarrier ; requires NamedBarrier
+//
+// So how does the test parameter capture which capabilities should cause
+// success and which shouldn't? The answer is in the last element: it's a
+// vector of capabilities that make the remainder assembly succeed. So if the
+// first-line capability exists in that vector, success is expected; otherwise,
+// failure is expected in the tests.
+//
+// We will use testing::Combine() to vary the first line: when we combine
+// AllCapabilities() with a single remainder assembly, we generate enough test
+// cases to try the assembly with every possible capability that could be
+// declared. However, Combine() only produces tuples -- it cannot produce, say,
+// a struct. Therefore, this type must be a tuple.
+using CapTestParameter = tuple<string, pair<string, vector<string>>>;
+
+const string& Capability(const CapTestParameter& p) { return get<0>(p); }
+const string& Remainder(const CapTestParameter& p) { return get<1>(p).first; }
+const vector<string>& MustSucceed(const CapTestParameter& p) {
+ return get<1>(p).second;
+}
+
+// Creates assembly to test from p.
+string MakeAssembly(const CapTestParameter& p) {
+ ostringstream ss;
+ const string& capability = Capability(p);
+ if (!capability.empty()) {
+ ss << "OpCapability " << capability << "\n";
+ }
+ ss << Remainder(p);
+ return ss.str();
+}
+
+// Expected validation result for p.
+spv_result_t ExpectedResult(const CapTestParameter& p) {
+ const auto& caps = MustSucceed(p);
+ auto found = find(begin(caps), end(caps), Capability(p));
+ return (found == end(caps)) ? SPV_ERROR_INVALID_CAPABILITY : SPV_SUCCESS;
+}
+
+// Assembles using v1.0, unless the parameter's capability requires v1.1.
+using ValidateCapability = spvtest::ValidateBase<CapTestParameter>;
+
+// Always assembles using v1.1.
+using ValidateCapabilityV11 = spvtest::ValidateBase<CapTestParameter>;
+
+// Always assembles using Vulkan 1.0.
+// TODO(dneto): Refactor all these tests to scale better across environments.
+using ValidateCapabilityVulkan10 = spvtest::ValidateBase<CapTestParameter>;
+// Always assembles using OpenGL 4.0.
+using ValidateCapabilityOpenGL40 = spvtest::ValidateBase<CapTestParameter>;
+
+TEST_F(ValidateCapability, Default) {
+ const char str[] = R"(
+ OpCapability Kernel
+ OpCapability Matrix
+ OpMemoryModel Logical OpenCL
+%f32 = OpTypeFloat 32
+%vec3 = OpTypeVector %f32 3
+%mat33 = OpTypeMatrix %vec3 3
+)";
+
+ CompileSuccessfully(str);
+ ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
+}
+
+// clang-format off
+const vector<string>& AllCapabilities() {
+ static const auto r = new vector<string>{
+ "",
+ "Matrix",
+ "Shader",
+ "Geometry",
+ "Tessellation",
+ "Addresses",
+ "Linkage",
+ "Kernel",
+ "Vector16",
+ "Float16Buffer",
+ "Float16",
+ "Float64",
+ "Int64",
+ "Int64Atomics",
+ "ImageBasic",
+ "ImageReadWrite",
+ "ImageMipmap",
+ "Pipes",
+ "Groups",
+ "DeviceEnqueue",
+ "LiteralSampler",
+ "AtomicStorage",
+ "Int16",
+ "TessellationPointSize",
+ "GeometryPointSize",
+ "ImageGatherExtended",
+ "StorageImageMultisample",
+ "UniformBufferArrayDynamicIndexing",
+ "SampledImageArrayDynamicIndexing",
+ "StorageBufferArrayDynamicIndexing",
+ "StorageImageArrayDynamicIndexing",
+ "ClipDistance",
+ "CullDistance",
+ "ImageCubeArray",
+ "SampleRateShading",
+ "ImageRect",
+ "SampledRect",
+ "GenericPointer",
+ "Int8",
+ "InputAttachment",
+ "SparseResidency",
+ "MinLod",
+ "Sampled1D",
+ "Image1D",
+ "SampledCubeArray",
+ "SampledBuffer",
+ "ImageBuffer",
+ "ImageMSArray",
+ "StorageImageExtendedFormats",
+ "ImageQuery",
+ "DerivativeControl",
+ "InterpolationFunction",
+ "TransformFeedback",
+ "GeometryStreams",
+ "StorageImageReadWithoutFormat",
+ "StorageImageWriteWithoutFormat",
+ "MultiViewport",
+ "SubgroupDispatch",
+ "NamedBarrier",
+ "PipeStorage"};
+ return *r;
+}
+
+const vector<string>& AllV10Capabilities() {
+ static const auto r = new vector<string>{
+ "",
+ "Matrix",
+ "Shader",
+ "Geometry",
+ "Tessellation",
+ "Addresses",
+ "Linkage",
+ "Kernel",
+ "Vector16",
+ "Float16Buffer",
+ "Float16",
+ "Float64",
+ "Int64",
+ "Int64Atomics",
+ "ImageBasic",
+ "ImageReadWrite",
+ "ImageMipmap",
+ "Pipes",
+ "Groups",
+ "DeviceEnqueue",
+ "LiteralSampler",
+ "AtomicStorage",
+ "Int16",
+ "TessellationPointSize",
+ "GeometryPointSize",
+ "ImageGatherExtended",
+ "StorageImageMultisample",
+ "UniformBufferArrayDynamicIndexing",
+ "SampledImageArrayDynamicIndexing",
+ "StorageBufferArrayDynamicIndexing",
+ "StorageImageArrayDynamicIndexing",
+ "ClipDistance",
+ "CullDistance",
+ "ImageCubeArray",
+ "SampleRateShading",
+ "ImageRect",
+ "SampledRect",
+ "GenericPointer",
+ "Int8",
+ "InputAttachment",
+ "SparseResidency",
+ "MinLod",
+ "Sampled1D",
+ "Image1D",
+ "SampledCubeArray",
+ "SampledBuffer",
+ "ImageBuffer",
+ "ImageMSArray",
+ "StorageImageExtendedFormats",
+ "ImageQuery",
+ "DerivativeControl",
+ "InterpolationFunction",
+ "TransformFeedback",
+ "GeometryStreams",
+ "StorageImageReadWithoutFormat",
+ "StorageImageWriteWithoutFormat",
+ "MultiViewport"};
+ return *r;
+}
+
+const vector<string>& MatrixDependencies() {
+ static const auto r = new vector<string>{
+ "Matrix",
+ "Shader",
+ "Geometry",
+ "Tessellation",
+ "AtomicStorage",
+ "TessellationPointSize",
+ "GeometryPointSize",
+ "ImageGatherExtended",
+ "StorageImageMultisample",
+ "UniformBufferArrayDynamicIndexing",
+ "SampledImageArrayDynamicIndexing",
+ "StorageBufferArrayDynamicIndexing",
+ "StorageImageArrayDynamicIndexing",
+ "ClipDistance",
+ "CullDistance",
+ "ImageCubeArray",
+ "SampleRateShading",
+ "ImageRect",
+ "SampledRect",
+ "InputAttachment",
+ "SparseResidency",
+ "MinLod",
+ "SampledCubeArray",
+ "ImageMSArray",
+ "StorageImageExtendedFormats",
+ "ImageQuery",
+ "DerivativeControl",
+ "InterpolationFunction",
+ "TransformFeedback",
+ "GeometryStreams",
+ "StorageImageReadWithoutFormat",
+ "StorageImageWriteWithoutFormat",
+ "MultiViewport"};
+ return *r;
+}
+
+const vector<string>& ShaderDependencies() {
+ static const auto r = new vector<string>{
+ "Shader",
+ "Geometry",
+ "Tessellation",
+ "AtomicStorage",
+ "TessellationPointSize",
+ "GeometryPointSize",
+ "ImageGatherExtended",
+ "StorageImageMultisample",
+ "UniformBufferArrayDynamicIndexing",
+ "SampledImageArrayDynamicIndexing",
+ "StorageBufferArrayDynamicIndexing",
+ "StorageImageArrayDynamicIndexing",
+ "ClipDistance",
+ "CullDistance",
+ "ImageCubeArray",
+ "SampleRateShading",
+ "ImageRect",
+ "SampledRect",
+ "InputAttachment",
+ "SparseResidency",
+ "MinLod",
+ "SampledCubeArray",
+ "ImageMSArray",
+ "StorageImageExtendedFormats",
+ "ImageQuery",
+ "DerivativeControl",
+ "InterpolationFunction",
+ "TransformFeedback",
+ "GeometryStreams",
+ "StorageImageReadWithoutFormat",
+ "StorageImageWriteWithoutFormat",
+ "MultiViewport"};
+ return *r;
+}
+
+const vector<string>& TessellationDependencies() {
+ static const auto r = new vector<string>{
+ "Tessellation",
+ "TessellationPointSize"};
+ return *r;
+}
+
+const vector<string>& GeometryDependencies() {
+ static const auto r = new vector<string>{
+ "Geometry",
+ "GeometryPointSize",
+ "GeometryStreams",
+ "MultiViewport"};
+ return *r;
+}
+
+const vector<string>& GeometryTessellationDependencies() {
+ static const auto r = new vector<string>{
+ "Tessellation",
+ "TessellationPointSize",
+ "Geometry",
+ "GeometryPointSize",
+ "GeometryStreams",
+ "MultiViewport"};
+ return *r;
+}
+
+// Returns the names of capabilities that directly depend on Kernel,
+// plus itself.
+const vector<string>& KernelDependencies() {
+ static const auto r = new vector<string>{
+ "Kernel",
+ "Vector16",
+ "Float16Buffer",
+ "ImageBasic",
+ "ImageReadWrite",
+ "ImageMipmap",
+ "Pipes",
+ "DeviceEnqueue",
+ "LiteralSampler",
+ "Int8",
+ "SubgroupDispatch",
+ "NamedBarrier",
+ "PipeStorage"};
+ return *r;
+}
+
+const vector<string>& AddressesDependencies() {
+ static const auto r = new vector<string>{
+ "Addresses",
+ "GenericPointer"};
+ return *r;
+}
+
+const vector<string>& Sampled1DDependencies() {
+ static const auto r = new vector<string>{
+ "Sampled1D",
+ "Image1D"};
+ return *r;
+}
+
+const vector<string>& SampledRectDependencies() {
+ static const auto r = new vector<string>{
+ "SampledRect",
+ "ImageRect"};
+ return *r;
+}
+
+const vector<string>& SampledBufferDependencies() {
+ static const auto r = new vector<string>{
+ "SampledBuffer",
+ "ImageBuffer"};
+ return *r;
+}
+
+const char kOpenCLMemoryModel[] = \
+ " OpCapability Kernel"
+ " OpMemoryModel Logical OpenCL ";
+
+const char kGLSL450MemoryModel[] = \
+ " OpCapability Shader"
+ " OpMemoryModel Logical GLSL450 ";
+
+const char kVoidFVoid[] = \
+ " %void = OpTypeVoid"
+ " %void_f = OpTypeFunction %void"
+ " %func = OpFunction %void None %void_f"
+ " %label = OpLabel"
+ " OpReturn"
+ " OpFunctionEnd ";
+
+INSTANTIATE_TEST_CASE_P(ExecutionModel, ValidateCapability,
+ Combine(
+ ValuesIn(AllCapabilities()),
+ Values(
+make_pair(string(kOpenCLMemoryModel) +
+ " OpEntryPoint Vertex %func \"shader\"" +
+ string(kVoidFVoid), ShaderDependencies()),
+make_pair(string(kOpenCLMemoryModel) +
+ " OpEntryPoint TessellationControl %func \"shader\"" +
+ string(kVoidFVoid), TessellationDependencies()),
+make_pair(string(kOpenCLMemoryModel) +
+ " OpEntryPoint TessellationEvaluation %func \"shader\"" +
+ string(kVoidFVoid), TessellationDependencies()),
+make_pair(string(kOpenCLMemoryModel) +
+ " OpEntryPoint Geometry %func \"shader\"" +
+ string(kVoidFVoid), GeometryDependencies()),
+make_pair(string(kOpenCLMemoryModel) +
+ " OpEntryPoint Fragment %func \"shader\"" +
+ string(kVoidFVoid), ShaderDependencies()),
+make_pair(string(kOpenCLMemoryModel) +
+ " OpEntryPoint GLCompute %func \"shader\"" +
+ string(kVoidFVoid), ShaderDependencies()),
+make_pair(string(kGLSL450MemoryModel) +
+ " OpEntryPoint Kernel %func \"shader\"" +
+ string(kVoidFVoid), KernelDependencies())
+)),);
+
+INSTANTIATE_TEST_CASE_P(AddressingAndMemoryModel, ValidateCapability,
+ Combine(
+ ValuesIn(AllCapabilities()),
+ Values(
+make_pair(" OpCapability Shader"
+ " OpMemoryModel Logical Simple", AllCapabilities()),
+make_pair(" OpCapability Shader"
+ " OpMemoryModel Logical GLSL450", AllCapabilities()),
+make_pair(" OpCapability Kernel"
+ " OpMemoryModel Logical OpenCL", AllCapabilities()),
+make_pair(" OpCapability Shader"
+ " OpMemoryModel Physical32 Simple", AddressesDependencies()),
+make_pair(" OpCapability Shader"
+ " OpMemoryModel Physical32 GLSL450", AddressesDependencies()),
+make_pair(" OpCapability Kernel"
+ " OpMemoryModel Physical32 OpenCL", AddressesDependencies()),
+make_pair(" OpCapability Shader"
+ " OpMemoryModel Physical64 Simple", AddressesDependencies()),
+make_pair(" OpCapability Shader"
+ " OpMemoryModel Physical64 GLSL450", AddressesDependencies()),
+make_pair(" OpCapability Kernel"
+ " OpMemoryModel Physical64 OpenCL", AddressesDependencies())
+)),);
+
+INSTANTIATE_TEST_CASE_P(ExecutionMode, ValidateCapability,
+ Combine(
+ ValuesIn(AllCapabilities()),
+ Values(
+make_pair(string(kOpenCLMemoryModel) +
+ "OpEntryPoint Geometry %func \"shader\" "
+ "OpExecutionMode %func Invocations 42" +
+ string(kVoidFVoid), GeometryDependencies()),
+make_pair(string(kOpenCLMemoryModel) +
+ "OpEntryPoint TessellationControl %func \"shader\" "
+ "OpExecutionMode %func SpacingEqual" +
+ string(kVoidFVoid), TessellationDependencies()),
+make_pair(string(kOpenCLMemoryModel) +
+ "OpEntryPoint TessellationControl %func \"shader\" "
+ "OpExecutionMode %func SpacingFractionalEven" +
+ string(kVoidFVoid), TessellationDependencies()),
+make_pair(string(kOpenCLMemoryModel) +
+ "OpEntryPoint TessellationControl %func \"shader\" "
+ "OpExecutionMode %func SpacingFractionalOdd" +
+ string(kVoidFVoid), TessellationDependencies()),
+make_pair(string(kOpenCLMemoryModel) +
+ "OpEntryPoint TessellationControl %func \"shader\" "
+ "OpExecutionMode %func VertexOrderCw" +
+ string(kVoidFVoid), TessellationDependencies()),
+make_pair(string(kOpenCLMemoryModel) +
+ "OpEntryPoint TessellationControl %func \"shader\" "
+ "OpExecutionMode %func VertexOrderCcw" +
+ string(kVoidFVoid), TessellationDependencies()),
+make_pair(string(kOpenCLMemoryModel) +
+ "OpEntryPoint Vertex %func \"shader\" "
+ "OpExecutionMode %func PixelCenterInteger" +
+ string(kVoidFVoid), ShaderDependencies()),
+make_pair(string(kOpenCLMemoryModel) +
+ "OpEntryPoint Vertex %func \"shader\" "
+ "OpExecutionMode %func OriginUpperLeft" +
+ string(kVoidFVoid), ShaderDependencies()),
+make_pair(string(kOpenCLMemoryModel) +
+ "OpEntryPoint Vertex %func \"shader\" "
+ "OpExecutionMode %func OriginLowerLeft" +
+ string(kVoidFVoid), ShaderDependencies()),
+make_pair(string(kOpenCLMemoryModel) +
+ "OpEntryPoint Vertex %func \"shader\" "
+ "OpExecutionMode %func EarlyFragmentTests" +
+ string(kVoidFVoid), ShaderDependencies()),
+make_pair(string(kOpenCLMemoryModel) +
+ "OpEntryPoint TessellationControl %func \"shader\" "
+ "OpExecutionMode %func PointMode" +
+ string(kVoidFVoid), TessellationDependencies()),
+make_pair(string(kOpenCLMemoryModel) +
+ "OpEntryPoint Vertex %func \"shader\" "
+ "OpExecutionMode %func Xfb" +
+ string(kVoidFVoid), vector<string>{"TransformFeedback"}),
+make_pair(string(kOpenCLMemoryModel) +
+ "OpEntryPoint Vertex %func \"shader\" "
+ "OpExecutionMode %func DepthReplacing" +
+ string(kVoidFVoid), ShaderDependencies()),
+make_pair(string(kOpenCLMemoryModel) +
+ "OpEntryPoint Vertex %func \"shader\" "
+ "OpExecutionMode %func DepthGreater" +
+ string(kVoidFVoid), ShaderDependencies()),
+make_pair(string(kOpenCLMemoryModel) +
+ "OpEntryPoint Vertex %func \"shader\" "
+ "OpExecutionMode %func DepthLess" +
+ string(kVoidFVoid), ShaderDependencies()),
+make_pair(string(kOpenCLMemoryModel) +
+ "OpEntryPoint Vertex %func \"shader\" "
+ "OpExecutionMode %func DepthUnchanged" +
+ string(kVoidFVoid), ShaderDependencies()),
+make_pair(string(kOpenCLMemoryModel) +
+ "OpEntryPoint Kernel %func \"shader\" "
+ "OpExecutionMode %func LocalSize 42 42 42" +
+ string(kVoidFVoid), AllCapabilities()),
+make_pair(string(kGLSL450MemoryModel) +
+ "OpEntryPoint Kernel %func \"shader\" "
+ "OpExecutionMode %func LocalSizeHint 42 42 42" +
+ string(kVoidFVoid), KernelDependencies()),
+make_pair(string(kOpenCLMemoryModel) +
+ "OpEntryPoint Geometry %func \"shader\" "
+ "OpExecutionMode %func InputPoints" +
+ string(kVoidFVoid), GeometryDependencies()),
+make_pair(string(kOpenCLMemoryModel) +
+ "OpEntryPoint Geometry %func \"shader\" "
+ "OpExecutionMode %func InputLines" +
+ string(kVoidFVoid), GeometryDependencies()),
+make_pair(string(kOpenCLMemoryModel) +
+ "OpEntryPoint Geometry %func \"shader\" "
+ "OpExecutionMode %func InputLinesAdjacency" +
+ string(kVoidFVoid), GeometryDependencies()),
+make_pair(string(kOpenCLMemoryModel) +
+ "OpEntryPoint Geometry %func \"shader\" "
+ "OpExecutionMode %func Triangles" +
+ string(kVoidFVoid), GeometryDependencies()),
+make_pair(string(kOpenCLMemoryModel) +
+ "OpEntryPoint TessellationControl %func \"shader\" "
+ "OpExecutionMode %func Triangles" +
+ string(kVoidFVoid), TessellationDependencies()),
+make_pair(string(kOpenCLMemoryModel) +
+ "OpEntryPoint Geometry %func \"shader\" "
+ "OpExecutionMode %func InputTrianglesAdjacency" +
+ string(kVoidFVoid), GeometryDependencies()),
+make_pair(string(kOpenCLMemoryModel) +
+ "OpEntryPoint TessellationControl %func \"shader\" "
+ "OpExecutionMode %func Quads" +
+ string(kVoidFVoid), TessellationDependencies()),
+make_pair(string(kOpenCLMemoryModel) +
+ "OpEntryPoint TessellationControl %func \"shader\" "
+ "OpExecutionMode %func Isolines" +
+ string(kVoidFVoid), TessellationDependencies()),
+make_pair(string(kOpenCLMemoryModel) +
+ "OpEntryPoint Geometry %func \"shader\" "
+ "OpExecutionMode %func OutputVertices 42" +
+ string(kVoidFVoid), GeometryDependencies()),
+make_pair(string(kOpenCLMemoryModel) +
+ "OpEntryPoint TessellationControl %func \"shader\" "
+ "OpExecutionMode %func OutputVertices 42" +
+ string(kVoidFVoid), TessellationDependencies()),
+make_pair(string(kOpenCLMemoryModel) +
+ "OpEntryPoint Geometry %func \"shader\" "
+ "OpExecutionMode %func OutputPoints" +
+ string(kVoidFVoid), GeometryDependencies()),
+make_pair(string(kOpenCLMemoryModel) +
+ "OpEntryPoint Geometry %func \"shader\" "
+ "OpExecutionMode %func OutputLineStrip" +
+ string(kVoidFVoid), GeometryDependencies()),
+make_pair(string(kOpenCLMemoryModel) +
+ "OpEntryPoint Geometry %func \"shader\" "
+ "OpExecutionMode %func OutputTriangleStrip" +
+ string(kVoidFVoid), GeometryDependencies()),
+make_pair(string(kGLSL450MemoryModel) +
+ "OpEntryPoint Kernel %func \"shader\" "
+ "OpExecutionMode %func VecTypeHint 2" +
+ string(kVoidFVoid), KernelDependencies()),
+make_pair(string(kGLSL450MemoryModel) +
+ "OpEntryPoint Kernel %func \"shader\" "
+ "OpExecutionMode %func ContractionOff" +
+ string(kVoidFVoid), KernelDependencies()))),);
+
+// clang-format on
+
+INSTANTIATE_TEST_CASE_P(
+ ExecutionModeV11, ValidateCapabilityV11,
+ Combine(ValuesIn(AllCapabilities()),
+ Values(make_pair(string(kOpenCLMemoryModel) +
+ "OpEntryPoint Kernel %func \"shader\" "
+ "OpExecutionMode %func SubgroupSize 1" +
+ string(kVoidFVoid),
+ vector<string>{"SubgroupDispatch"}),
+ make_pair(
+ string(kOpenCLMemoryModel) +
+ "OpEntryPoint Kernel %func \"shader\" "
+ "OpExecutionMode %func SubgroupsPerWorkgroup 65535" +
+ string(kVoidFVoid),
+ vector<string>{"SubgroupDispatch"}))), );
+// clang-format off
+
+INSTANTIATE_TEST_CASE_P(StorageClass, ValidateCapability,
+ Combine(
+ ValuesIn(AllCapabilities()),
+ Values(
+make_pair(string(kGLSL450MemoryModel) +
+ " %intt = OpTypeInt 32 0\n"
+ " %ptrt = OpTypePointer UniformConstant %intt\n"
+ " %var = OpVariable %ptrt UniformConstant\n", AllCapabilities()),
+make_pair(string(kOpenCLMemoryModel) +
+ " %intt = OpTypeInt 32 0\n"
+ " %ptrt = OpTypePointer Input %intt"
+ " %var = OpVariable %ptrt Input\n", AllCapabilities()),
+make_pair(string(kOpenCLMemoryModel) +
+ " %intt = OpTypeInt 32 0\n"
+ " %ptrt = OpTypePointer Uniform %intt\n"
+ " %var = OpVariable %ptrt Uniform\n", ShaderDependencies()),
+make_pair(string(kOpenCLMemoryModel) +
+ " %intt = OpTypeInt 32 0\n"
+ " %ptrt = OpTypePointer Output %intt\n"
+ " %var = OpVariable %ptrt Output\n", ShaderDependencies()),
+make_pair(string(kGLSL450MemoryModel) +
+ " %intt = OpTypeInt 32 0\n"
+ " %ptrt = OpTypePointer Workgroup %intt\n"
+ " %var = OpVariable %ptrt Workgroup\n", AllCapabilities()),
+make_pair(string(kGLSL450MemoryModel) +
+ " %intt = OpTypeInt 32 0\n"
+ " %ptrt = OpTypePointer CrossWorkgroup %intt\n"
+ " %var = OpVariable %ptrt CrossWorkgroup\n", AllCapabilities()),
+make_pair(string(kOpenCLMemoryModel) +
+ " %intt = OpTypeInt 32 0\n"
+ " %ptrt = OpTypePointer Private %intt\n"
+ " %var = OpVariable %ptrt Private\n", ShaderDependencies()),
+make_pair(string(kOpenCLMemoryModel) +
+ " %intt = OpTypeInt 32 0\n"
+ " %ptrt = OpTypePointer PushConstant %intt\n"
+ " %var = OpVariable %ptrt PushConstant\n", ShaderDependencies()),
+make_pair(string(kGLSL450MemoryModel) +
+ " %intt = OpTypeInt 32 0\n"
+ " %ptrt = OpTypePointer AtomicCounter %intt\n"
+ " %var = OpVariable %ptrt AtomicCounter\n", vector<string>{"AtomicStorage"}),
+make_pair(string(kGLSL450MemoryModel) +
+ " %intt = OpTypeInt 32 0\n"
+ " %ptrt = OpTypePointer Image %intt\n"
+ " %var = OpVariable %ptrt Image\n", AllCapabilities())
+)),);
+
+INSTANTIATE_TEST_CASE_P(Dim, ValidateCapability,
+ Combine(
+ ValuesIn(AllCapabilities()),
+ Values(
+make_pair(" OpCapability ImageBasic" +
+ string(kOpenCLMemoryModel) +
+ " %voidt = OpTypeVoid"
+ " %imgt = OpTypeImage %voidt 1D 0 0 0 0 Unknown",
+ Sampled1DDependencies()),
+make_pair(" OpCapability ImageBasic" +
+ string(kOpenCLMemoryModel) +
+ " %voidt = OpTypeVoid"
+ " %imgt = OpTypeImage %voidt 2D 0 0 0 0 Unknown",
+ AllCapabilities()),
+make_pair(" OpCapability ImageBasic" +
+ string(kOpenCLMemoryModel) +
+ " %voidt = OpTypeVoid"
+ " %imgt = OpTypeImage %voidt 3D 0 0 0 0 Unknown",
+ AllCapabilities()),
+make_pair(" OpCapability ImageBasic" +
+ string(kOpenCLMemoryModel) +
+ " %voidt = OpTypeVoid"
+ " %imgt = OpTypeImage %voidt Cube 0 0 0 0 Unknown",
+ ShaderDependencies()),
+make_pair(" OpCapability ImageBasic" +
+ string(kOpenCLMemoryModel) +
+ " %voidt = OpTypeVoid"
+ " %imgt = OpTypeImage %voidt Rect 0 0 0 0 Unknown",
+ SampledRectDependencies()),
+make_pair(" OpCapability ImageBasic" +
+ string(kOpenCLMemoryModel) +
+ " %voidt = OpTypeVoid"
+ " %imgt = OpTypeImage %voidt Buffer 0 0 0 0 Unknown",
+ SampledBufferDependencies()),
+make_pair(" OpCapability ImageBasic" +
+ string(kOpenCLMemoryModel) +
+ " %voidt = OpTypeVoid"
+ " %imgt = OpTypeImage %voidt SubpassData 0 0 0 2 Unknown",
+ vector<string>{"InputAttachment"})
+)),);
+
+// NOTE: All Sampler Address Modes require kernel capabilities but the
+// OpConstantSampler requires LiteralSampler which depends on Kernel
+INSTANTIATE_TEST_CASE_P(SamplerAddressingMode, ValidateCapability,
+ Combine(
+ ValuesIn(AllCapabilities()),
+ Values(
+make_pair(string(kGLSL450MemoryModel) +
+ " %samplert = OpTypeSampler"
+ " %sampler = OpConstantSampler %samplert None 1 Nearest",
+ vector<string>{"LiteralSampler"}),
+make_pair(string(kGLSL450MemoryModel) +
+ " %samplert = OpTypeSampler"
+ " %sampler = OpConstantSampler %samplert ClampToEdge 1 Nearest",
+ vector<string>{"LiteralSampler"}),
+make_pair(string(kGLSL450MemoryModel) +
+ " %samplert = OpTypeSampler"
+ " %sampler = OpConstantSampler %samplert Clamp 1 Nearest",
+ vector<string>{"LiteralSampler"}),
+make_pair(string(kGLSL450MemoryModel) +
+ " %samplert = OpTypeSampler"
+ " %sampler = OpConstantSampler %samplert Repeat 1 Nearest",
+ vector<string>{"LiteralSampler"}),
+make_pair(string(kGLSL450MemoryModel) +
+ " %samplert = OpTypeSampler"
+ " %sampler = OpConstantSampler %samplert RepeatMirrored 1 Nearest",
+ vector<string>{"LiteralSampler"})
+)),);
+
+//TODO(umar): Sampler Filter Mode
+//TODO(umar): Image Format
+//TODO(umar): Image Channel Order
+//TODO(umar): Image Channel Data Type
+//TODO(umar): Image Operands
+//TODO(umar): FP Fast Math Mode
+//TODO(umar): FP Rounding Mode
+//TODO(umar): Linkage Type
+//TODO(umar): Access Qualifier
+//TODO(umar): Function Parameter Attribute
+
+INSTANTIATE_TEST_CASE_P(Decoration, ValidateCapability,
+ Combine(
+ ValuesIn(AllCapabilities()),
+ Values(
+make_pair(string(kOpenCLMemoryModel) +
+ "OpDecorate %intt RelaxedPrecision\n"
+ "%intt = OpTypeInt 32 1\n", ShaderDependencies()),
+make_pair(string(kOpenCLMemoryModel) +
+ "OpDecorate %intt Block\n"
+ "%intt = OpTypeInt 32 1\n", ShaderDependencies()),
+make_pair(string(kOpenCLMemoryModel) +
+ "OpDecorate %intt BufferBlock\n"
+ "%intt = OpTypeInt 32 1\n", ShaderDependencies()),
+make_pair(string(kOpenCLMemoryModel) +
+ "OpDecorate %intt RowMajor\n"
+ "%intt = OpTypeInt 32 1\n", MatrixDependencies()),
+make_pair(string(kOpenCLMemoryModel) +
+ "OpDecorate %intt ColMajor\n"
+ "%intt = OpTypeInt 32 1\n", MatrixDependencies()),
+make_pair(string(kOpenCLMemoryModel) +
+ "OpDecorate %intt ArrayStride 1\n"
+ "%intt = OpTypeInt 32 1\n", ShaderDependencies()),
+make_pair(string(kOpenCLMemoryModel) +
+ "OpDecorate %intt MatrixStride 1\n"
+ "%intt = OpTypeInt 32 1\n", MatrixDependencies()),
+make_pair(string(kOpenCLMemoryModel) +
+ "OpDecorate %intt GLSLShared\n"
+ "%intt = OpTypeInt 32 1\n", ShaderDependencies()),
+make_pair(string(kOpenCLMemoryModel) +
+ "OpDecorate %intt GLSLPacked\n"
+ "%intt = OpTypeInt 32 1\n", ShaderDependencies()),
+make_pair(string(kGLSL450MemoryModel) +
+ "OpDecorate %intt CPacked\n"
+ "%intt = OpTypeInt 32 1\n", KernelDependencies()),
+make_pair(string(kOpenCLMemoryModel) +
+ "OpDecorate %intt NoPerspective\n"
+ "%intt = OpTypeInt 32 1\n", ShaderDependencies()),
+make_pair(string(kOpenCLMemoryModel) +
+ "OpDecorate %intt Flat\n"
+ "%intt = OpTypeInt 32 1\n", ShaderDependencies()),
+make_pair(string(kOpenCLMemoryModel) +
+ "OpDecorate %intt Patch\n"
+ "%intt = OpTypeInt 32 1\n", TessellationDependencies()),
+make_pair(string(kOpenCLMemoryModel) +
+ "OpDecorate %intt Centroid\n"
+ "%intt = OpTypeInt 32 1\n", ShaderDependencies()),
+make_pair(string(kOpenCLMemoryModel) +
+ "OpDecorate %intt Sample\n"
+ "%intt = OpTypeInt 32 1\n", vector<string>{"SampleRateShading"}),
+make_pair(string(kOpenCLMemoryModel) +
+ "OpDecorate %intt Invariant\n"
+ "%intt = OpTypeInt 32 1\n", ShaderDependencies()),
+make_pair(string(kOpenCLMemoryModel) +
+ "OpDecorate %intt Restrict\n"
+ "%intt = OpTypeInt 32 1\n", AllCapabilities()),
+make_pair(string(kOpenCLMemoryModel) +
+ "OpDecorate %intt Aliased\n"
+ "%intt = OpTypeInt 32 1\n", AllCapabilities()),
+make_pair(string(kOpenCLMemoryModel) +
+ "OpDecorate %intt Volatile\n"
+ "%intt = OpTypeInt 32 1\n", AllCapabilities()),
+make_pair(string(kGLSL450MemoryModel) +
+ "OpDecorate %intt Constant\n"
+ "%intt = OpTypeInt 32 1\n", KernelDependencies()),
+make_pair(string(kOpenCLMemoryModel) +
+ "OpDecorate %intt Coherent\n"
+ "%intt = OpTypeInt 32 1\n", AllCapabilities()),
+make_pair(string(kOpenCLMemoryModel) +
+ "OpDecorate %intt NonWritable\n"
+ "%intt = OpTypeInt 32 1\n", AllCapabilities()),
+make_pair(string(kOpenCLMemoryModel) +
+ "OpDecorate %intt NonReadable\n"
+ "%intt = OpTypeInt 32 1\n", AllCapabilities()),
+make_pair(string(kOpenCLMemoryModel) +
+ "OpDecorate %intt Uniform\n"
+ "%intt = OpTypeInt 32 1\n", ShaderDependencies()),
+make_pair(string(kGLSL450MemoryModel) +
+ "OpDecorate %intt SaturatedConversion\n"
+ "%intt = OpTypeInt 32 1\n", KernelDependencies()),
+make_pair(string(kOpenCLMemoryModel) +
+ "OpDecorate %intt Stream 0\n"
+ "%intt = OpTypeInt 32 1\n", vector<string>{"GeometryStreams"}),
+make_pair(string(kOpenCLMemoryModel) +
+ "OpDecorate %intt Location 0\n"
+ "%intt = OpTypeInt 32 1\n", ShaderDependencies()),
+make_pair(string(kOpenCLMemoryModel) +
+ "OpDecorate %intt Component 0\n"
+ "%intt = OpTypeInt 32 1\n", ShaderDependencies()),
+make_pair(string(kOpenCLMemoryModel) +
+ "OpDecorate %intt Index 0\n"
+ "%intt = OpTypeInt 32 1\n", ShaderDependencies()),
+make_pair(string(kOpenCLMemoryModel) +
+ "OpDecorate %intt Binding 0\n"
+ "%intt = OpTypeInt 32 1\n", ShaderDependencies()),
+make_pair(string(kOpenCLMemoryModel) +
+ "OpDecorate %intt DescriptorSet 0\n"
+ "%intt = OpTypeInt 32 1\n", ShaderDependencies()),
+make_pair(string(kOpenCLMemoryModel) +
+ "OpDecorate %intt Offset 0\n"
+ "%intt = OpTypeInt 32 1\n", ShaderDependencies()),
+make_pair(string(kOpenCLMemoryModel) +
+ "OpDecorate %intt XfbBuffer 0\n"
+ "%intt = OpTypeInt 32 1\n", vector<string>{"TransformFeedback"}),
+make_pair(string(kOpenCLMemoryModel) +
+ "OpDecorate %intt XfbStride 0\n"
+ "%intt = OpTypeInt 32 1\n", vector<string>{"TransformFeedback"}),
+make_pair(string(kGLSL450MemoryModel) +
+ "OpDecorate %intt FuncParamAttr Zext\n"
+ "%intt = OpTypeInt 32 1\n", KernelDependencies()),
+make_pair(string(kGLSL450MemoryModel) +
+ "OpDecorate %intt FPRoundingMode RTE\n"
+ "%intt = OpTypeInt 32 1\n", KernelDependencies()),
+make_pair(string(kGLSL450MemoryModel) +
+ "OpDecorate %intt FPFastMathMode Fast\n"
+ "%intt = OpTypeInt 32 1\n", KernelDependencies()),
+make_pair(string(kOpenCLMemoryModel) +
+ "OpDecorate %intt LinkageAttributes \"other\" Import\n"
+ "%intt = OpTypeInt 32 1\n", vector<string>{"Linkage"}),
+make_pair(string(kOpenCLMemoryModel) +
+ "OpDecorate %intt NoContraction\n"
+ "%intt = OpTypeInt 32 1\n", ShaderDependencies()),
+make_pair(string(kOpenCLMemoryModel) +
+ "OpDecorate %intt InputAttachmentIndex 0\n"
+ "%intt = OpTypeInt 32 1\n", vector<string>{"InputAttachment"}),
+make_pair(string(kGLSL450MemoryModel) +
+ "OpDecorate %intt Alignment 4\n"
+ "%intt = OpTypeInt 32 1\n", KernelDependencies())
+)),);
+
+// clang-format on
+INSTANTIATE_TEST_CASE_P(
+ DecorationSpecId, ValidateCapability,
+ Combine(ValuesIn(AllV10Capabilities()),
+ Values(make_pair(string(kOpenCLMemoryModel) +
+ "OpDecorate %intt SpecId 1\n"
+ "%intt = OpTypeInt 32 1\n",
+ ShaderDependencies()))), );
+
+INSTANTIATE_TEST_CASE_P(
+ DecorationV11, ValidateCapabilityV11,
+ Combine(ValuesIn(AllCapabilities()),
+ Values(make_pair(string(kOpenCLMemoryModel) +
+ "OpDecorate %p MaxByteOffset 0 "
+ "%i32 = OpTypeInt 32 1 "
+ "%pi32 = OpTypePointer Workgroup %i32 "
+ "%p = OpVariable %pi32 Workgroup ",
+ AddressesDependencies()),
+ // Trying to test OpDecorate here, but if this fails due to
+ // incorrect OpMemoryModel validation, that must also be
+ // fixed.
+ make_pair(string("OpMemoryModel Logical OpenCL "
+ "OpDecorate %intt SpecId 1 "
+ "%intt = OpTypeInt 32 1 "),
+ KernelDependencies()),
+ make_pair(string("OpMemoryModel Logical Simple "
+ "OpDecorate %intt SpecId 1 "
+ "%intt = OpTypeInt 32 1 "),
+ ShaderDependencies()))), );
+// clang-format off
+
+INSTANTIATE_TEST_CASE_P(BuiltIn, ValidateCapability,
+ Combine(
+ ValuesIn(AllCapabilities()),
+ Values(
+make_pair(string(kOpenCLMemoryModel) +
+ "OpDecorate %intt BuiltIn Position\n"
+ "%intt = OpTypeInt 32 1\n", ShaderDependencies()),
+// Just mentioning PointSize, ClipDistance, or CullDistance as a BuiltIn does
+// not trigger the requirement for the associated capability.
+// See https://github.com/KhronosGroup/SPIRV-Tools/issues/365
+make_pair(string(kOpenCLMemoryModel) +
+ "OpDecorate %intt BuiltIn PointSize\n"
+ "%intt = OpTypeInt 32 1\n", AllCapabilities()),
+make_pair(string(kOpenCLMemoryModel) +
+ "OpDecorate %intt BuiltIn ClipDistance\n"
+ "%intt = OpTypeInt 32 1\n", AllCapabilities()),
+make_pair(string(kOpenCLMemoryModel) +
+ "OpDecorate %intt BuiltIn CullDistance\n"
+ "%intt = OpTypeInt 32 1\n", AllCapabilities()),
+make_pair(string(kOpenCLMemoryModel) +
+ "OpDecorate %intt BuiltIn VertexId\n"
+ "%intt = OpTypeInt 32 1\n", ShaderDependencies()),
+make_pair(string(kOpenCLMemoryModel) +
+ "OpDecorate %intt BuiltIn InstanceId\n"
+ "%intt = OpTypeInt 32 1\n", ShaderDependencies()),
+make_pair(string(kOpenCLMemoryModel) +
+ "OpDecorate %intt BuiltIn PrimitiveId\n"
+ "%intt = OpTypeInt 32 1\n", GeometryTessellationDependencies()),
+make_pair(string(kOpenCLMemoryModel) +
+ "OpDecorate %intt BuiltIn InvocationId\n"
+ "%intt = OpTypeInt 32 1\n", GeometryTessellationDependencies()),
+make_pair(string(kOpenCLMemoryModel) +
+ "OpDecorate %intt BuiltIn Layer\n"
+ "%intt = OpTypeInt 32 1\n", GeometryDependencies()),
+make_pair(string(kOpenCLMemoryModel) +
+ "OpDecorate %intt BuiltIn ViewportIndex\n"
+ "%intt = OpTypeInt 32 1\n", vector<string>{"MultiViewport"}),
+make_pair(string(kOpenCLMemoryModel) +
+ "OpDecorate %intt BuiltIn TessLevelOuter\n"
+ "%intt = OpTypeInt 32 1\n", TessellationDependencies()),
+make_pair(string(kOpenCLMemoryModel) +
+ "OpDecorate %intt BuiltIn TessLevelInner\n"
+ "%intt = OpTypeInt 32 1\n", TessellationDependencies()),
+make_pair(string(kOpenCLMemoryModel) +
+ "OpDecorate %intt BuiltIn TessCoord\n"
+ "%intt = OpTypeInt 32 1\n", TessellationDependencies()),
+make_pair(string(kOpenCLMemoryModel) +
+ "OpDecorate %intt BuiltIn PatchVertices\n"
+ "%intt = OpTypeInt 32 1\n", TessellationDependencies()),
+make_pair(string(kOpenCLMemoryModel) +
+ "OpDecorate %intt BuiltIn FragCoord\n"
+ "%intt = OpTypeInt 32 1\n", ShaderDependencies()),
+make_pair(string(kOpenCLMemoryModel) +
+ "OpDecorate %intt BuiltIn PointCoord\n"
+ "%intt = OpTypeInt 32 1\n", ShaderDependencies()),
+make_pair(string(kOpenCLMemoryModel) +
+ "OpDecorate %intt BuiltIn FrontFacing\n"
+ "%intt = OpTypeInt 32 1\n", ShaderDependencies()),
+make_pair(string(kOpenCLMemoryModel) +
+ "OpDecorate %intt BuiltIn SampleId\n"
+ "%intt = OpTypeInt 32 1\n", vector<string>{"SampleRateShading"}),
+make_pair(string(kOpenCLMemoryModel) +
+ "OpDecorate %intt BuiltIn SamplePosition\n"
+ "%intt = OpTypeInt 32 1\n", vector<string>{"SampleRateShading"}),
+make_pair(string(kOpenCLMemoryModel) +
+ "OpDecorate %intt BuiltIn SampleMask\n"
+ "%intt = OpTypeInt 32 1\n", vector<string>{"SampleRateShading"}),
+make_pair(string(kOpenCLMemoryModel) +
+ "OpDecorate %intt BuiltIn FragDepth\n"
+ "%intt = OpTypeInt 32 1\n", ShaderDependencies()),
+make_pair(string(kOpenCLMemoryModel) +
+ "OpDecorate %intt BuiltIn HelperInvocation\n"
+ "%intt = OpTypeInt 32 1\n", ShaderDependencies()),
+make_pair(string(kOpenCLMemoryModel) +
+ "OpDecorate %intt BuiltIn VertexIndex\n"
+ "%intt = OpTypeInt 32 1\n", ShaderDependencies()),
+make_pair(string(kOpenCLMemoryModel) +
+ "OpDecorate %intt BuiltIn InstanceIndex\n"
+ "%intt = OpTypeInt 32 1\n", ShaderDependencies()),
+make_pair(string(kOpenCLMemoryModel) +
+ "OpDecorate %intt BuiltIn NumWorkgroups\n"
+ "%intt = OpTypeInt 32 1\n", AllCapabilities()),
+make_pair(string(kOpenCLMemoryModel) +
+ "OpDecorate %intt BuiltIn WorkgroupSize\n"
+ "%intt = OpTypeInt 32 1\n", AllCapabilities()),
+make_pair(string(kOpenCLMemoryModel) +
+ "OpDecorate %intt BuiltIn WorkgroupId\n"
+ "%intt = OpTypeInt 32 1\n", AllCapabilities()),
+make_pair(string(kOpenCLMemoryModel) +
+ "OpDecorate %intt BuiltIn LocalInvocationId\n"
+ "%intt = OpTypeInt 32 1\n", AllCapabilities()),
+make_pair(string(kOpenCLMemoryModel) +
+ "OpDecorate %intt BuiltIn GlobalInvocationId\n"
+ "%intt = OpTypeInt 32 1\n", AllCapabilities()),
+make_pair(string(kOpenCLMemoryModel) +
+ "OpDecorate %intt BuiltIn LocalInvocationIndex\n"
+ "%intt = OpTypeInt 32 1\n", AllCapabilities()),
+make_pair(string(kGLSL450MemoryModel) +
+ "OpDecorate %intt BuiltIn WorkDim\n"
+ "%intt = OpTypeInt 32 1\n", KernelDependencies()),
+make_pair(string(kGLSL450MemoryModel) +
+ "OpDecorate %intt BuiltIn GlobalSize\n"
+ "%intt = OpTypeInt 32 1\n", KernelDependencies()),
+make_pair(string(kGLSL450MemoryModel) +
+ "OpDecorate %intt BuiltIn EnqueuedWorkgroupSize\n"
+ "%intt = OpTypeInt 32 1\n", KernelDependencies()),
+make_pair(string(kGLSL450MemoryModel) +
+ "OpDecorate %intt BuiltIn GlobalOffset\n"
+ "%intt = OpTypeInt 32 1\n", KernelDependencies()),
+make_pair(string(kGLSL450MemoryModel) +
+ "OpDecorate %intt BuiltIn GlobalLinearId\n"
+ "%intt = OpTypeInt 32 1\n", KernelDependencies()),
+make_pair(string(kGLSL450MemoryModel) +
+ "OpDecorate %intt BuiltIn SubgroupSize\n"
+ "%intt = OpTypeInt 32 1\n", KernelDependencies()),
+make_pair(string(kGLSL450MemoryModel) +
+ "OpDecorate %intt BuiltIn SubgroupMaxSize\n"
+ "%intt = OpTypeInt 32 1\n", KernelDependencies()),
+make_pair(string(kGLSL450MemoryModel) +
+ "OpDecorate %intt BuiltIn NumSubgroups\n"
+ "%intt = OpTypeInt 32 1\n", KernelDependencies()),
+make_pair(string(kGLSL450MemoryModel) +
+ "OpDecorate %intt BuiltIn NumEnqueuedSubgroups\n"
+ "%intt = OpTypeInt 32 1\n", KernelDependencies()),
+make_pair(string(kGLSL450MemoryModel) +
+ "OpDecorate %intt BuiltIn SubgroupId\n"
+ "%intt = OpTypeInt 32 1\n", KernelDependencies()),
+make_pair(string(kGLSL450MemoryModel) +
+ "OpDecorate %intt BuiltIn SubgroupLocalInvocationId\n"
+ "%intt = OpTypeInt 32 1\n", KernelDependencies()),
+make_pair(string(kOpenCLMemoryModel) +
+ "OpDecorate %intt BuiltIn VertexIndex\n"
+ "%intt = OpTypeInt 32 1\n", ShaderDependencies()),
+make_pair(string(kOpenCLMemoryModel) +
+ "OpDecorate %intt BuiltIn InstanceIndex\n"
+ "%intt = OpTypeInt 32 1\n", ShaderDependencies())
+)),);
+
+// Ensure that mere mention of PointSize, ClipDistance, or CullDistance as
+// BuiltIns does not trigger the requirement for the associated
+// capability.
+// See https://github.com/KhronosGroup/SPIRV-Tools/issues/365
+INSTANTIATE_TEST_CASE_P(BuiltIn, ValidateCapabilityVulkan10,
+ Combine(
+ // Vulkan 1.0 is based on SPIR-V 1.0
+ ValuesIn(AllV10Capabilities()),
+ Values(
+make_pair(string(kGLSL450MemoryModel) +
+ "OpDecorate %intt BuiltIn PointSize\n"
+ "%intt = OpTypeInt 32 1\n", AllV10Capabilities()),
+make_pair(string(kGLSL450MemoryModel) +
+ "OpDecorate %intt BuiltIn ClipDistance\n"
+ "%intt = OpTypeInt 32 1\n", AllV10Capabilities()),
+make_pair(string(kGLSL450MemoryModel) +
+ "OpDecorate %intt BuiltIn CullDistance\n"
+ "%intt = OpTypeInt 32 1\n", AllV10Capabilities())
+)),);
+
+INSTANTIATE_TEST_CASE_P(BuiltIn, ValidateCapabilityOpenGL40,
+ Combine(
+ // OpenGL 4.0 is based on SPIR-V 1.0
+ ValuesIn(AllV10Capabilities()),
+ Values(
+make_pair(string(kGLSL450MemoryModel) +
+ "OpDecorate %intt BuiltIn PointSize\n"
+ "%intt = OpTypeInt 32 1\n", AllV10Capabilities()),
+make_pair(string(kGLSL450MemoryModel) +
+ "OpDecorate %intt BuiltIn ClipDistance\n"
+ "%intt = OpTypeInt 32 1\n", AllV10Capabilities()),
+make_pair(string(kGLSL450MemoryModel) +
+ "OpDecorate %intt BuiltIn CullDistance\n"
+ "%intt = OpTypeInt 32 1\n", AllV10Capabilities())
+)),);
+
+// TODO(umar): Selection Control
+// TODO(umar): Loop Control
+// TODO(umar): Function Control
+// TODO(umar): Memory Semantics
+// TODO(umar): Memory Access
+// TODO(umar): Scope
+// TODO(umar): Group Operation
+// TODO(umar): Kernel Enqueue Flags
+// TODO(umar): Kernel Profiling Flags
+
+INSTANTIATE_TEST_CASE_P(MatrixOp, ValidateCapability,
+ Combine(
+ ValuesIn(AllCapabilities()),
+ Values(
+make_pair(string(kOpenCLMemoryModel) +
+ "%f32 = OpTypeFloat 32\n"
+ "%vec3 = OpTypeVector %f32 3\n"
+ "%mat33 = OpTypeMatrix %vec3 3\n", MatrixDependencies()))),);
+// clang-format on
+
+// Creates assembly containing an OpImageFetch instruction using operands for
+// the image-operands part. The assembly defines constants %fzero and %izero
+// that can be used for operands where IDs are required. The assembly is valid,
+// apart from not declaring any capabilities required by the operands.
+string ImageOperandsTemplate(const string& operands) {
+ ostringstream ss;
+ // clang-format off
+ ss << R"(
+OpCapability Kernel
+OpMemoryModel Logical OpenCL
+
+%i32 = OpTypeInt 32 1
+%f32 = OpTypeFloat 32
+%v4i32 = OpTypeVector %i32 4
+%timg = OpTypeImage %i32 2D 0 0 0 0 Unknown
+%pimg = OpTypePointer UniformConstant %timg
+%tfun = OpTypeFunction %i32
+
+%vimg = OpVariable %pimg UniformConstant
+%izero = OpConstant %i32 0
+%fzero = OpConstant %f32 0.
+
+%main = OpFunction %i32 None %tfun
+%lbl = OpLabel
+%img = OpLoad %timg %vimg
+%r1 = OpImageFetch %v4i32 %img %izero )" << operands << R"(
+OpReturnValue %izero
+OpFunctionEnd
+)";
+ // clang-format on
+ return ss.str();
+}
+
+INSTANTIATE_TEST_CASE_P(
+ TwoImageOperandsMask, ValidateCapability,
+ Combine(
+ ValuesIn(AllCapabilities()),
+ Values(make_pair(ImageOperandsTemplate("Bias|Lod %fzero %fzero"),
+ ShaderDependencies()),
+ make_pair(ImageOperandsTemplate("Lod|Offset %fzero %izero"),
+ vector<string>{"ImageGatherExtended"}),
+ make_pair(ImageOperandsTemplate("Sample|MinLod %izero %fzero"),
+ vector<string>{"MinLod"}),
+ make_pair(ImageOperandsTemplate("Lod|Sample %fzero %izero"),
+ AllCapabilities()))), );
+
+// TODO(umar): Instruction capability checks
+
+// True if capability exists in env.
+bool Exists(const std::string& capability, spv_target_env env) {
+ spv_operand_desc dummy;
+ return SPV_SUCCESS ==
+ libspirv::AssemblyGrammar(ScopedContext(env).context)
+ .lookupOperand(SPV_OPERAND_TYPE_CAPABILITY, capability.c_str(),
+ capability.size(), &dummy);
+}
+
+TEST_P(ValidateCapability, Capability) {
+ const string capability = Capability(GetParam());
+ spv_target_env env =
+ (capability.empty() || Exists(capability, SPV_ENV_UNIVERSAL_1_0))
+ ? SPV_ENV_UNIVERSAL_1_0
+ : SPV_ENV_UNIVERSAL_1_1;
+ const string test_code = MakeAssembly(GetParam());
+ CompileSuccessfully(test_code, env);
+ ASSERT_EQ(ExpectedResult(GetParam()), ValidateInstructions(env)) << test_code;
+}
+
+TEST_P(ValidateCapabilityV11, Capability) {
+ const string test_code = MakeAssembly(GetParam());
+ CompileSuccessfully(test_code, SPV_ENV_UNIVERSAL_1_1);
+ ASSERT_EQ(ExpectedResult(GetParam()),
+ ValidateInstructions(SPV_ENV_UNIVERSAL_1_1))
+ << test_code;
+}
+
+TEST_P(ValidateCapabilityVulkan10, Capability) {
+ const string test_code = MakeAssembly(GetParam());
+ CompileSuccessfully(test_code, SPV_ENV_VULKAN_1_0);
+ ASSERT_EQ(ExpectedResult(GetParam()),
+ ValidateInstructions(SPV_ENV_VULKAN_1_0))
+ << test_code;
+}
+
+TEST_P(ValidateCapabilityOpenGL40, Capability) {
+ const string test_code = MakeAssembly(GetParam());
+ CompileSuccessfully(test_code, SPV_ENV_OPENGL_4_0);
+ ASSERT_EQ(ExpectedResult(GetParam()),
+ ValidateInstructions(SPV_ENV_OPENGL_4_0))
+ << test_code;
+}
+
+TEST_F(ValidateCapability, SemanticsIdIsAnIdNotALiteral) {
+ // From https://github.com/KhronosGroup/SPIRV-Tools/issues/248
+ // The validator was interpreting the memory semantics ID number
+ // as the value to be checked rather than an ID that references
+ // another value to be checked.
+ // In this case a raw ID of 64 was mistaken to mean a literal
+ // semantic value of UniformMemory, which would require the Shader
+ // capability.
+ const char str[] = R"(
+OpCapability Kernel
+OpMemoryModel Logical OpenCL
+
+; %i32 has ID 1
+%i32 = OpTypeInt 32 1
+%tf = OpTypeFunction %i32
+%pi32 = OpTypePointer CrossWorkgroup %i32
+%var = OpVariable %pi32 CrossWorkgroup
+%c = OpConstant %i32 100
+%scope = OpConstant %i32 1 ; Device scope
+
+; Fake an instruction with 64 as the result id.
+; !64 = OpConstantNull %i32
+!0x3002e !1 !64
+
+%f = OpFunction %i32 None %tf
+%l = OpLabel
+%result = OpAtomicIAdd %i32 %var %scope !64 %c
+OpReturnValue %result
+OpFunctionEnd
+)";
+
+ CompileSuccessfully(str);
+
+ // Since we are forcing usage of <id> 64, the "id bound" in the binary header
+ // must be overwritten so that <id> 64 is considered within bound.
+ // ID Bound is at index 3 of the binary. Set it to 65.
+ OverwriteAssembledBinary(3, 65);
+
+ ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
+}
+
+} // namespace anonymous