// 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 #include #include #include #include #include "gmock/gmock.h" #include "source/assembly_grammar.h" #include "source/spirv_target_env.h" #include "spirv-tools/libspirv.h" #include "test/test_fixture.h" #include "test/unit_spirv.h" #include "test/val/val_fixtures.h" namespace spvtools { namespace val { namespace { using spvtest::ScopedContext; using testing::Combine; using testing::Eq; using testing::HasSubstr; using testing::Values; using testing::ValuesIn; // Parameter for validation test fixtures. The first std::string is a // capability name that will begin the assembly under test, the second the // remainder assembly, and the std::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 // std::vector of capabilities that make the remainder assembly succeed. So if // the first-line capability exists in that std::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 = std::tuple>>; const std::string& Capability(const CapTestParameter& p) { return std::get<0>(p); } const std::string& Remainder(const CapTestParameter& p) { return std::get<1>(p).first; } const std::vector& MustSucceed(const CapTestParameter& p) { return std::get<1>(p).second; } // Creates assembly to test from p. std::string MakeAssembly(const CapTestParameter& p) { std::ostringstream ss; const std::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; // Always assembles using v1.1. using ValidateCapabilityV11 = spvtest::ValidateBase; // Always assembles using Vulkan 1.0. // TODO(dneto): Refactor all these tests to scale better across environments. using ValidateCapabilityVulkan10 = spvtest::ValidateBase; // Always assembles using OpenGL 4.0. using ValidateCapabilityOpenGL40 = spvtest::ValidateBase; // Always assembles using Vulkan 1.1. using ValidateCapabilityVulkan11 = spvtest::ValidateBase; // Always assembles using Vulkan 1.2. using ValidateCapabilityVulkan12 = spvtest::ValidateBase; TEST_F(ValidateCapability, Default) { const char str[] = R"( OpCapability Kernel OpCapability Linkage 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 std::vector& AllCapabilities() { static const auto r = new std::vector{ "", "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", "GroupNonUniform", "GroupNonUniformVote", "GroupNonUniformArithmetic", "GroupNonUniformBallot", "GroupNonUniformShuffle", "GroupNonUniformShuffleRelative", "GroupNonUniformClustered", "GroupNonUniformQuad", "DrawParameters", "StorageBuffer16BitAccess", "StorageUniformBufferBlock16", "UniformAndStorageBuffer16BitAccess", "StorageUniform16", "StoragePushConstant16", "StorageInputOutput16", "DeviceGroup", "MultiView", "VariablePointersStorageBuffer", "VariablePointers"}; return *r; } const std::vector& AllSpirV15Capabilities() { static const auto r = new std::vector{ "", "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", "GroupNonUniform", "GroupNonUniformVote", "GroupNonUniformArithmetic", "GroupNonUniformBallot", "GroupNonUniformShuffle", "GroupNonUniformShuffleRelative", "GroupNonUniformClustered", "GroupNonUniformQuad", "DrawParameters", "StorageBuffer16BitAccess", "StorageUniformBufferBlock16", "UniformAndStorageBuffer16BitAccess", "StorageUniform16", "StoragePushConstant16", "StorageInputOutput16", "DeviceGroup", "MultiView", "VariablePointersStorageBuffer", "VariablePointers", "DenormPreserve", "DenormFlushToZero", "SignedZeroInfNanPreserve", "RoundingModeRTE", "RoundingModeRTZ", // Omitted due to extra validation requirements on memory model. //"VulkanMemoryModel", //"VulkanMemoryModelDeviceScope", "StorageBuffer8BitAccess", "UniformAndStorageBuffer8BitAccess", "StoragePushConstant8", "ShaderViewportIndex", "ShaderLayer", "PhysicalStorageBufferAddresses", "RuntimeDescriptorArray", "UniformTexelBufferArrayDynamicIndexing", "StorageTexelBufferArrayDynamicIndexing", "UniformBufferArrayNonUniformIndexing", "SampledImageArrayNonUniformIndexing", "StorageBufferArrayNonUniformIndexing", "StorageImageArrayNonUniformIndexing", "InputAttachmentArrayNonUniformIndexing", "UniformTexelBufferArrayNonUniformIndexing", "StorageTexelBufferArrayNonUniformIndexing"}; return *r; } const std::vector& AllSpirV10Capabilities() { static const auto r = new std::vector{ "", "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 std::vector& AllVulkan10Capabilities() { static const auto r = new std::vector{ "", "Matrix", "Shader", "InputAttachment", "Sampled1D", "Image1D", "SampledBuffer", "ImageBuffer", "ImageQuery", "DerivativeControl", "Geometry", "Tessellation", "Float16", "Float64", "Int64", "Int64Atomics", "Int16", "TessellationPointSize", "GeometryPointSize", "ImageGatherExtended", "StorageImageMultisample", "UniformBufferArrayDynamicIndexing", "SampledImageArrayDynamicIndexing", "StorageBufferArrayDynamicIndexing", "StorageImageArrayDynamicIndexing", "ClipDistance", "CullDistance", "ImageCubeArray", "SampleRateShading", "Int8", "SparseResidency", "MinLod", "SampledCubeArray", "ImageMSArray", "StorageImageExtendedFormats", "InterpolationFunction", "StorageImageReadWithoutFormat", "StorageImageWriteWithoutFormat", "MultiViewport", "TransformFeedback", "GeometryStreams"}; return *r; } const std::vector& AllVulkan11Capabilities() { static const auto r = new std::vector{ "", "Matrix", "Shader", "InputAttachment", "Sampled1D", "Image1D", "SampledBuffer", "ImageBuffer", "ImageQuery", "DerivativeControl", "Geometry", "Tessellation", "Float16", "Float64", "Int64", "Int64Atomics", "Int16", "TessellationPointSize", "GeometryPointSize", "ImageGatherExtended", "StorageImageMultisample", "UniformBufferArrayDynamicIndexing", "SampledImageArrayDynamicIndexing", "StorageBufferArrayDynamicIndexing", "StorageImageArrayDynamicIndexing", "ClipDistance", "CullDistance", "ImageCubeArray", "SampleRateShading", "Int8", "SparseResidency", "MinLod", "SampledCubeArray", "ImageMSArray", "StorageImageExtendedFormats", "InterpolationFunction", "StorageImageReadWithoutFormat", "StorageImageWriteWithoutFormat", "MultiViewport", "GroupNonUniform", "GroupNonUniformVote", "GroupNonUniformArithmetic", "GroupNonUniformBallot", "GroupNonUniformShuffle", "GroupNonUniformShuffleRelative", "GroupNonUniformClustered", "GroupNonUniformQuad", "DrawParameters", "StorageBuffer16BitAccess", "StorageUniformBufferBlock16", "UniformAndStorageBuffer16BitAccess", "StorageUniform16", "StoragePushConstant16", "StorageInputOutput16", "DeviceGroup", "MultiView", "VariablePointersStorageBuffer", "VariablePointers", "TransformFeedback", "GeometryStreams"}; return *r; } const std::vector& AllVulkan12Capabilities() { static const auto r = new std::vector{ "", "Matrix", "Shader", "InputAttachment", "Sampled1D", "Image1D", "SampledBuffer", "ImageBuffer", "ImageQuery", "DerivativeControl", "Geometry", "Tessellation", "Float16", "Float64", "Int64", "Int64Atomics", "Int16", "TessellationPointSize", "GeometryPointSize", "ImageGatherExtended", "StorageImageMultisample", "UniformBufferArrayDynamicIndexing", "SampledImageArrayDynamicIndexing", "StorageBufferArrayDynamicIndexing", "StorageImageArrayDynamicIndexing", "ClipDistance", "CullDistance", "ImageCubeArray", "SampleRateShading", "Int8", "SparseResidency", "MinLod", "SampledCubeArray", "ImageMSArray", "StorageImageExtendedFormats", "InterpolationFunction", "StorageImageReadWithoutFormat", "StorageImageWriteWithoutFormat", "MultiViewport", "GroupNonUniform", "GroupNonUniformVote", "GroupNonUniformArithmetic", "GroupNonUniformBallot", "GroupNonUniformShuffle", "GroupNonUniformShuffleRelative", "GroupNonUniformClustered", "GroupNonUniformQuad", "DrawParameters", "StorageBuffer16BitAccess", "StorageUniformBufferBlock16", "UniformAndStorageBuffer16BitAccess", "StorageUniform16", "StoragePushConstant16", "StorageInputOutput16", "DeviceGroup", "MultiView", "VariablePointersStorageBuffer", "VariablePointers", "TransformFeedback", "GeometryStreams", "DenormPreserve", "DenormFlushToZero", "SignedZeroInfNanPreserve", "RoundingModeRTE", "RoundingModeRTZ", "VulkanMemoryModel", "VulkanMemoryModelDeviceScope", "StorageBuffer8BitAccess", "UniformAndStorageBuffer8BitAccess", "StoragePushConstant8", "ShaderViewportIndex", "ShaderLayer", "PhysicalStorageBufferAddresses", "RuntimeDescriptorArray", "UniformTexelBufferArrayDynamicIndexing", "StorageTexelBufferArrayDynamicIndexing", "UniformBufferArrayNonUniformIndexing", "SampledImageArrayNonUniformIndexing", "StorageBufferArrayNonUniformIndexing", "StorageImageArrayNonUniformIndexing", "InputAttachmentArrayNonUniformIndexing", "UniformTexelBufferArrayNonUniformIndexing", "StorageTexelBufferArrayNonUniformIndexing"}; return *r; } const std::vector& MatrixDependencies() { static const auto r = new std::vector{ "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", "DrawParameters", "MultiView", "VariablePointersStorageBuffer", "VariablePointers"}; return *r; } const std::vector& ShaderDependencies() { static const auto r = new std::vector{ "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", "DrawParameters", "MultiView", "VariablePointersStorageBuffer", "VariablePointers"}; return *r; } const std::vector& TessellationDependencies() { static const auto r = new std::vector{ "Tessellation", "TessellationPointSize"}; return *r; } const std::vector& GeometryDependencies() { static const auto r = new std::vector{ "Geometry", "GeometryPointSize", "GeometryStreams", "MultiViewport"}; return *r; } const std::vector& GeometryTessellationDependencies() { static const auto r = new std::vector{ "Tessellation", "TessellationPointSize", "Geometry", "GeometryPointSize", "GeometryStreams", "MultiViewport"}; return *r; } // Returns the names of capabilities that directly depend on Kernel, // plus itself. const std::vector& KernelDependencies() { static const auto r = new std::vector{ "Kernel", "Vector16", "Float16Buffer", "ImageBasic", "ImageReadWrite", "ImageMipmap", "Pipes", "DeviceEnqueue", "LiteralSampler", "SubgroupDispatch", "NamedBarrier", "PipeStorage"}; return *r; } const std::vector& KernelAndGroupNonUniformDependencies() { static const auto r = new std::vector{ "Kernel", "Vector16", "Float16Buffer", "ImageBasic", "ImageReadWrite", "ImageMipmap", "Pipes", "DeviceEnqueue", "LiteralSampler", "SubgroupDispatch", "NamedBarrier", "PipeStorage", "GroupNonUniform", "GroupNonUniformVote", "GroupNonUniformArithmetic", "GroupNonUniformBallot", "GroupNonUniformShuffle", "GroupNonUniformShuffleRelative", "GroupNonUniformClustered", "GroupNonUniformQuad"}; return *r; } const std::vector& AddressesDependencies() { static const auto r = new std::vector{ "Addresses", "GenericPointer"}; return *r; } const std::vector& Sampled1DDependencies() { static const auto r = new std::vector{ "Sampled1D", "Image1D"}; return *r; } const std::vector& SampledRectDependencies() { static const auto r = new std::vector{ "SampledRect", "ImageRect"}; return *r; } const std::vector& SampledBufferDependencies() { static const auto r = new std::vector{ "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 "; const char kVoidFVoid2[] = \ " %void_f = OpTypeFunction %voidt" " %func = OpFunction %voidt None %void_f" " %label = OpLabel" " OpReturn" " OpFunctionEnd "; INSTANTIATE_TEST_SUITE_P(ExecutionModel, ValidateCapability, Combine( ValuesIn(AllCapabilities()), Values( std::make_pair(std::string(kOpenCLMemoryModel) + " OpEntryPoint Vertex %func \"shader\"" + std::string(kVoidFVoid), ShaderDependencies()), std::make_pair(std::string(kOpenCLMemoryModel) + " OpEntryPoint TessellationControl %func \"shader\"" + std::string(kVoidFVoid), TessellationDependencies()), std::make_pair(std::string(kOpenCLMemoryModel) + " OpEntryPoint TessellationEvaluation %func \"shader\"" + std::string(kVoidFVoid), TessellationDependencies()), std::make_pair(std::string(kOpenCLMemoryModel) + " OpEntryPoint Geometry %func \"shader\"" + " OpExecutionMode %func InputPoints" + " OpExecutionMode %func OutputPoints" + std::string(kVoidFVoid), GeometryDependencies()), std::make_pair(std::string(kOpenCLMemoryModel) + " OpEntryPoint Fragment %func \"shader\"" + " OpExecutionMode %func OriginUpperLeft" + std::string(kVoidFVoid), ShaderDependencies()), std::make_pair(std::string(kOpenCLMemoryModel) + " OpEntryPoint GLCompute %func \"shader\"" + std::string(kVoidFVoid), ShaderDependencies()), std::make_pair(std::string(kGLSL450MemoryModel) + " OpEntryPoint Kernel %func \"shader\"" + std::string(kVoidFVoid), KernelDependencies()) ))); INSTANTIATE_TEST_SUITE_P(AddressingAndMemoryModel, ValidateCapability, Combine( ValuesIn(AllCapabilities()), Values( std::make_pair(" OpCapability Shader" " OpMemoryModel Logical Simple" " OpEntryPoint Vertex %func \"shader\"" + std::string(kVoidFVoid), AllCapabilities()), std::make_pair(" OpCapability Shader" " OpMemoryModel Logical GLSL450" " OpEntryPoint Vertex %func \"shader\"" + std::string(kVoidFVoid), AllCapabilities()), std::make_pair(" OpCapability Kernel" " OpMemoryModel Logical OpenCL" " OpEntryPoint Kernel %func \"compute\"" + std::string(kVoidFVoid), AllCapabilities()), std::make_pair(" OpCapability Shader" " OpMemoryModel Physical32 Simple" " OpEntryPoint Vertex %func \"shader\"" + std::string(kVoidFVoid), AddressesDependencies()), std::make_pair(" OpCapability Shader" " OpMemoryModel Physical32 GLSL450" " OpEntryPoint Vertex %func \"shader\"" + std::string(kVoidFVoid), AddressesDependencies()), std::make_pair(" OpCapability Kernel" " OpMemoryModel Physical32 OpenCL" " OpEntryPoint Kernel %func \"compute\"" + std::string(kVoidFVoid), AddressesDependencies()), std::make_pair(" OpCapability Shader" " OpMemoryModel Physical64 Simple" " OpEntryPoint Vertex %func \"shader\"" + std::string(kVoidFVoid), AddressesDependencies()), std::make_pair(" OpCapability Shader" " OpMemoryModel Physical64 GLSL450" " OpEntryPoint Vertex %func \"shader\"" + std::string(kVoidFVoid), AddressesDependencies()), std::make_pair(" OpCapability Kernel" " OpMemoryModel Physical64 OpenCL" " OpEntryPoint Kernel %func \"compute\"" + std::string(kVoidFVoid), AddressesDependencies()) ))); INSTANTIATE_TEST_SUITE_P(ExecutionMode, ValidateCapability, Combine( ValuesIn(AllCapabilities()), Values( std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Geometry %func \"shader\" " "OpExecutionMode %func Invocations 42" + " OpExecutionMode %func InputPoints" + " OpExecutionMode %func OutputPoints" + std::string(kVoidFVoid), GeometryDependencies()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint TessellationControl %func \"shader\" " "OpExecutionMode %func SpacingEqual" + std::string(kVoidFVoid), TessellationDependencies()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint TessellationControl %func \"shader\" " "OpExecutionMode %func SpacingFractionalEven" + std::string(kVoidFVoid), TessellationDependencies()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint TessellationControl %func \"shader\" " "OpExecutionMode %func SpacingFractionalOdd" + std::string(kVoidFVoid), TessellationDependencies()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint TessellationControl %func \"shader\" " "OpExecutionMode %func VertexOrderCw" + std::string(kVoidFVoid), TessellationDependencies()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint TessellationControl %func \"shader\" " "OpExecutionMode %func VertexOrderCcw" + std::string(kVoidFVoid), TessellationDependencies()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Fragment %func \"shader\" " "OpExecutionMode %func PixelCenterInteger" + " OpExecutionMode %func OriginUpperLeft" + std::string(kVoidFVoid), ShaderDependencies()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Fragment %func \"shader\" " "OpExecutionMode %func OriginUpperLeft" + std::string(kVoidFVoid), ShaderDependencies()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Fragment %func \"shader\" " "OpExecutionMode %func OriginLowerLeft" + std::string(kVoidFVoid), ShaderDependencies()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Fragment %func \"shader\" " "OpExecutionMode %func EarlyFragmentTests" + " OpExecutionMode %func OriginUpperLeft" + std::string(kVoidFVoid), ShaderDependencies()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint TessellationControl %func \"shader\" " "OpExecutionMode %func PointMode" + std::string(kVoidFVoid), TessellationDependencies()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Vertex %func \"shader\" " "OpExecutionMode %func Xfb" + std::string(kVoidFVoid), std::vector{"TransformFeedback"}), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Fragment %func \"shader\" " "OpExecutionMode %func DepthReplacing" + " OpExecutionMode %func OriginUpperLeft" + std::string(kVoidFVoid), ShaderDependencies()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Fragment %func \"shader\" " "OpExecutionMode %func DepthGreater" + " OpExecutionMode %func OriginUpperLeft" + std::string(kVoidFVoid), ShaderDependencies()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Fragment %func \"shader\" " "OpExecutionMode %func DepthLess" + " OpExecutionMode %func OriginUpperLeft" + std::string(kVoidFVoid), ShaderDependencies()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Fragment %func \"shader\" " "OpExecutionMode %func DepthUnchanged" + " OpExecutionMode %func OriginUpperLeft" + std::string(kVoidFVoid), ShaderDependencies()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Kernel %func \"shader\" " "OpExecutionMode %func LocalSize 42 42 42" + std::string(kVoidFVoid), AllCapabilities()), std::make_pair(std::string(kGLSL450MemoryModel) + "OpEntryPoint Kernel %func \"shader\" " "OpExecutionMode %func LocalSizeHint 42 42 42" + std::string(kVoidFVoid), KernelDependencies()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Geometry %func \"shader\" " "OpExecutionMode %func InputPoints" + " OpExecutionMode %func OutputPoints" + std::string(kVoidFVoid), GeometryDependencies()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Geometry %func \"shader\" " "OpExecutionMode %func InputLines" + " OpExecutionMode %func OutputLineStrip" + std::string(kVoidFVoid), GeometryDependencies()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Geometry %func \"shader\" " "OpExecutionMode %func InputLinesAdjacency" + " OpExecutionMode %func OutputLineStrip" + std::string(kVoidFVoid), GeometryDependencies()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Geometry %func \"shader\" " "OpExecutionMode %func Triangles" + " OpExecutionMode %func OutputTriangleStrip" + std::string(kVoidFVoid), GeometryDependencies()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint TessellationControl %func \"shader\" " "OpExecutionMode %func Triangles" + std::string(kVoidFVoid), TessellationDependencies()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Geometry %func \"shader\" " "OpExecutionMode %func InputTrianglesAdjacency" + " OpExecutionMode %func OutputTriangleStrip" + std::string(kVoidFVoid), GeometryDependencies()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint TessellationControl %func \"shader\" " "OpExecutionMode %func Quads" + std::string(kVoidFVoid), TessellationDependencies()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint TessellationControl %func \"shader\" " "OpExecutionMode %func Isolines" + std::string(kVoidFVoid), TessellationDependencies()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Geometry %func \"shader\" " "OpExecutionMode %func OutputVertices 42" + " OpExecutionMode %func OutputPoints" + " OpExecutionMode %func InputPoints" + std::string(kVoidFVoid), GeometryDependencies()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint TessellationControl %func \"shader\" " "OpExecutionMode %func OutputVertices 42" + std::string(kVoidFVoid), TessellationDependencies()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Geometry %func \"shader\" " "OpExecutionMode %func OutputPoints" + " OpExecutionMode %func InputPoints" + std::string(kVoidFVoid), GeometryDependencies()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Geometry %func \"shader\" " "OpExecutionMode %func OutputLineStrip" + " OpExecutionMode %func InputLines" + std::string(kVoidFVoid), GeometryDependencies()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Geometry %func \"shader\" " "OpExecutionMode %func OutputTriangleStrip" + " OpExecutionMode %func Triangles" + std::string(kVoidFVoid), GeometryDependencies()), std::make_pair(std::string(kGLSL450MemoryModel) + "OpEntryPoint Kernel %func \"shader\" " "OpExecutionMode %func VecTypeHint 2" + std::string(kVoidFVoid), KernelDependencies()), std::make_pair(std::string(kGLSL450MemoryModel) + "OpEntryPoint Kernel %func \"shader\" " "OpExecutionMode %func ContractionOff" + std::string(kVoidFVoid), KernelDependencies())))); // clang-format on INSTANTIATE_TEST_SUITE_P( ExecutionModeV11, ValidateCapabilityV11, Combine(ValuesIn(AllCapabilities()), Values(std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Kernel %func \"shader\" " "OpExecutionMode %func SubgroupSize 1" + std::string(kVoidFVoid), std::vector{"SubgroupDispatch"}), std::make_pair( std::string(kOpenCLMemoryModel) + "OpEntryPoint Kernel %func \"shader\" " "OpExecutionMode %func SubgroupsPerWorkgroup 65535" + std::string(kVoidFVoid), std::vector{"SubgroupDispatch"})))); // clang-format off INSTANTIATE_TEST_SUITE_P(StorageClass, ValidateCapability, Combine( ValuesIn(AllCapabilities()), Values( std::make_pair(std::string(kGLSL450MemoryModel) + " OpEntryPoint Vertex %func \"shader\"" + " %intt = OpTypeInt 32 0\n" " %ptrt = OpTypePointer UniformConstant %intt\n" " %var = OpVariable %ptrt UniformConstant\n" + std::string(kVoidFVoid), AllCapabilities()), std::make_pair(std::string(kOpenCLMemoryModel) + " OpEntryPoint Kernel %func \"compute\"" + " %intt = OpTypeInt 32 0\n" " %ptrt = OpTypePointer Input %intt" " %var = OpVariable %ptrt Input\n" + std::string(kVoidFVoid), AllCapabilities()), std::make_pair(std::string(kOpenCLMemoryModel) + " OpEntryPoint Vertex %func \"shader\"" + " %intt = OpTypeInt 32 0\n" " %ptrt = OpTypePointer Uniform %intt\n" " %var = OpVariable %ptrt Uniform\n" + std::string(kVoidFVoid), ShaderDependencies()), std::make_pair(std::string(kOpenCLMemoryModel) + " OpEntryPoint Vertex %func \"shader\"" + " %intt = OpTypeInt 32 0\n" " %ptrt = OpTypePointer Output %intt\n" " %var = OpVariable %ptrt Output\n" + std::string(kVoidFVoid), ShaderDependencies()), std::make_pair(std::string(kGLSL450MemoryModel) + " OpEntryPoint Vertex %func \"shader\"" + " %intt = OpTypeInt 32 0\n" " %ptrt = OpTypePointer Workgroup %intt\n" " %var = OpVariable %ptrt Workgroup\n" + std::string(kVoidFVoid), AllCapabilities()), std::make_pair(std::string(kGLSL450MemoryModel) + " OpEntryPoint Vertex %func \"shader\"" + " %intt = OpTypeInt 32 0\n" " %ptrt = OpTypePointer CrossWorkgroup %intt\n" " %var = OpVariable %ptrt CrossWorkgroup\n" + std::string(kVoidFVoid), AllCapabilities()), std::make_pair(std::string(kOpenCLMemoryModel) + " OpEntryPoint Kernel %func \"compute\"" + " %intt = OpTypeInt 32 0\n" " %ptrt = OpTypePointer Private %intt\n" " %var = OpVariable %ptrt Private\n" + std::string(kVoidFVoid), ShaderDependencies()), std::make_pair(std::string(kOpenCLMemoryModel) + " OpEntryPoint Kernel %func \"compute\"" + " %intt = OpTypeInt 32 0\n" " %ptrt = OpTypePointer PushConstant %intt\n" " %var = OpVariable %ptrt PushConstant\n" + std::string(kVoidFVoid), ShaderDependencies()), std::make_pair(std::string(kGLSL450MemoryModel) + " OpEntryPoint Vertex %func \"shader\"" + " %intt = OpTypeInt 32 0\n" " %ptrt = OpTypePointer AtomicCounter %intt\n" " %var = OpVariable %ptrt AtomicCounter\n" + std::string(kVoidFVoid), std::vector{"AtomicStorage"}), std::make_pair(std::string(kGLSL450MemoryModel) + " OpEntryPoint Vertex %func \"shader\"" + " %intt = OpTypeInt 32 0\n" " %ptrt = OpTypePointer Image %intt\n" " %var = OpVariable %ptrt Image\n" + std::string(kVoidFVoid), AllCapabilities()) ))); INSTANTIATE_TEST_SUITE_P(Dim, ValidateCapability, Combine( ValuesIn(AllCapabilities()), Values( std::make_pair(" OpCapability ImageBasic" + std::string(kOpenCLMemoryModel) + std::string(" OpEntryPoint Kernel %func \"compute\"") + " %voidt = OpTypeVoid" " %imgt = OpTypeImage %voidt 1D 0 0 0 0 Unknown" + std::string(kVoidFVoid2), Sampled1DDependencies()), std::make_pair(" OpCapability ImageBasic" + std::string(kOpenCLMemoryModel) + std::string(" OpEntryPoint Kernel %func \"compute\"") + " %voidt = OpTypeVoid" " %imgt = OpTypeImage %voidt 2D 0 0 0 0 Unknown" + std::string(kVoidFVoid2), AllCapabilities()), std::make_pair(" OpCapability ImageBasic" + std::string(kOpenCLMemoryModel) + std::string(" OpEntryPoint Kernel %func \"compute\"") + " %voidt = OpTypeVoid" " %imgt = OpTypeImage %voidt 3D 0 0 0 0 Unknown" + std::string(kVoidFVoid2), AllCapabilities()), std::make_pair(" OpCapability ImageBasic" + std::string(kOpenCLMemoryModel) + std::string(" OpEntryPoint Kernel %func \"compute\"") + " %voidt = OpTypeVoid" " %imgt = OpTypeImage %voidt Cube 0 0 0 0 Unknown" + std::string(kVoidFVoid2), ShaderDependencies()), std::make_pair(" OpCapability ImageBasic" + std::string(kOpenCLMemoryModel) + std::string(" OpEntryPoint Kernel %func \"compute\"") + " %voidt = OpTypeVoid" " %imgt = OpTypeImage %voidt Rect 0 0 0 0 Unknown" + std::string(kVoidFVoid2), SampledRectDependencies()), std::make_pair(" OpCapability ImageBasic" + std::string(kOpenCLMemoryModel) + std::string(" OpEntryPoint Kernel %func \"compute\"") + " %voidt = OpTypeVoid" " %imgt = OpTypeImage %voidt Buffer 0 0 0 0 Unknown" + std::string(kVoidFVoid2), SampledBufferDependencies()), std::make_pair(" OpCapability ImageBasic" + std::string(kOpenCLMemoryModel) + std::string(" OpEntryPoint Kernel %func \"compute\"") + " %voidt = OpTypeVoid" " %imgt = OpTypeImage %voidt SubpassData 0 0 0 2 Unknown" + std::string(kVoidFVoid2), std::vector{"InputAttachment"}) ))); // NOTE: All Sampler Address Modes require kernel capabilities but the // OpConstantSampler requires LiteralSampler which depends on Kernel INSTANTIATE_TEST_SUITE_P(SamplerAddressingMode, ValidateCapability, Combine( ValuesIn(AllCapabilities()), Values( std::make_pair(std::string(kGLSL450MemoryModel) + " OpEntryPoint Vertex %func \"shader\"" " %samplert = OpTypeSampler" " %sampler = OpConstantSampler %samplert None 1 Nearest" + std::string(kVoidFVoid), std::vector{"LiteralSampler"}), std::make_pair(std::string(kGLSL450MemoryModel) + " OpEntryPoint Vertex %func \"shader\"" " %samplert = OpTypeSampler" " %sampler = OpConstantSampler %samplert ClampToEdge 1 Nearest" + std::string(kVoidFVoid), std::vector{"LiteralSampler"}), std::make_pair(std::string(kGLSL450MemoryModel) + " OpEntryPoint Vertex %func \"shader\"" " %samplert = OpTypeSampler" " %sampler = OpConstantSampler %samplert Clamp 1 Nearest" + std::string(kVoidFVoid), std::vector{"LiteralSampler"}), std::make_pair(std::string(kGLSL450MemoryModel) + " OpEntryPoint Vertex %func \"shader\"" " %samplert = OpTypeSampler" " %sampler = OpConstantSampler %samplert Repeat 1 Nearest" + std::string(kVoidFVoid), std::vector{"LiteralSampler"}), std::make_pair(std::string(kGLSL450MemoryModel) + " OpEntryPoint Vertex %func \"shader\"" " %samplert = OpTypeSampler" " %sampler = OpConstantSampler %samplert RepeatMirrored 1 Nearest" + std::string(kVoidFVoid), std::vector{"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_SUITE_P(Decoration, ValidateCapability, Combine( ValuesIn(AllCapabilities()), Values( std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Kernel %func \"compute\" \n" "OpDecorate %var RelaxedPrecision\n" "%intt = OpTypeInt 32 0\n" "%ptr = OpTypePointer Private %intt\n" "%var = OpVariable %ptr Private\n" + std::string(kVoidFVoid), ShaderDependencies()), std::make_pair(std::string(kOpenCLMemoryModel) + // Block applies to struct type. "OpEntryPoint Kernel %func \"compute\" \n" "OpDecorate %block Block\n" "%intt = OpTypeInt 32 0\n" "%block = OpTypeStruct %intt\n" + std::string(kVoidFVoid), ShaderDependencies()), std::make_pair(std::string(kOpenCLMemoryModel) + // BufferBlock applies to struct type. "OpEntryPoint Kernel %func \"compute\" \n" "OpDecorate %block BufferBlock\n" "%intt = OpTypeInt 32 0\n" "%block = OpTypeStruct %intt\n" + std::string(kVoidFVoid), ShaderDependencies()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Kernel %func \"compute\" \n" "OpMemberDecorate %structt 0 RowMajor\n" "%floatt = OpTypeFloat 32\n" "%float2 = OpTypeVector %floatt 2\n" "%mat2x2 = OpTypeMatrix %float2 2\n" "%structt = OpTypeStruct %mat2x2\n" + std::string(kVoidFVoid), MatrixDependencies()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Kernel %func \"compute\" \n" "OpMemberDecorate %structt 0 ColMajor\n" "%floatt = OpTypeFloat 32\n" "%float2 = OpTypeVector %floatt 2\n" "%mat2x2 = OpTypeMatrix %float2 2\n" "%structt = OpTypeStruct %mat2x2\n" + std::string(kVoidFVoid), MatrixDependencies()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Kernel %func \"compute\" \n" "OpDecorate %array ArrayStride 4\n" "%intt = OpTypeInt 32 0\n" "%array = OpTypeRuntimeArray %intt\n" + std::string(kVoidFVoid), ShaderDependencies()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Kernel %func \"compute\" \n" "OpMemberDecorate %structt 0 MatrixStride 8\n" "%floatt = OpTypeFloat 32\n" "%float2 = OpTypeVector %floatt 2\n" "%mat2x2 = OpTypeMatrix %float2 2\n" "%structt = OpTypeStruct %mat2x2\n" + std::string(kVoidFVoid), MatrixDependencies()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Kernel %func \"compute\" \n" "OpDecorate %struct GLSLShared\n" "%struct = OpTypeStruct\n" + std::string(kVoidFVoid), ShaderDependencies()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Kernel %func \"compute\" \n" "OpDecorate %struct GLSLPacked\n" "%struct = OpTypeStruct\n" + std::string(kVoidFVoid), ShaderDependencies()), std::make_pair(std::string(kGLSL450MemoryModel) + "OpEntryPoint Vertex %func \"shader\" \n" "OpDecorate %struct CPacked\n" "%struct = OpTypeStruct\n" + std::string(kVoidFVoid), KernelDependencies()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Kernel %func \"compute\" \n" "OpDecorate %var NoPerspective\n" "%intt = OpTypeInt 32 0\n" "%ptr = OpTypePointer Input %intt\n" "%var = OpVariable %ptr Input\n" + std::string(kVoidFVoid), ShaderDependencies()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Kernel %func \"compute\" \n" "OpDecorate %var Flat\n" "%intt = OpTypeInt 32 0\n" "%ptr = OpTypePointer Input %intt\n" "%var = OpVariable %ptr Input\n" + std::string(kVoidFVoid), ShaderDependencies()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Kernel %func \"compute\" \n" "OpDecorate %var Patch\n" "%intt = OpTypeInt 32 0\n" "%ptr = OpTypePointer Input %intt\n" "%var = OpVariable %ptr Input\n" + std::string(kVoidFVoid), TessellationDependencies()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Kernel %func \"compute\" \n" "OpDecorate %var Centroid\n" "%intt = OpTypeInt 32 0\n" "%ptr = OpTypePointer Input %intt\n" "%var = OpVariable %ptr Input\n" + std::string(kVoidFVoid), ShaderDependencies()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Kernel %func \"compute\" \n" "OpDecorate %var Sample\n" "%intt = OpTypeInt 32 0\n" "%ptr = OpTypePointer Input %intt\n" "%var = OpVariable %ptr Input\n" + std::string(kVoidFVoid), std::vector{"SampleRateShading"}), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Kernel %func \"compute\" \n" "OpDecorate %var Invariant\n" "%intt = OpTypeInt 32 0\n" "%ptr = OpTypePointer Input %intt\n" "%var = OpVariable %ptr Input\n" + std::string(kVoidFVoid), ShaderDependencies()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Kernel %func \"compute\" \n" "OpDecorate %var Restrict\n" "%intt = OpTypeInt 32 0\n" "%ptr = OpTypePointer Input %intt\n" "%var = OpVariable %ptr Input\n" + std::string(kVoidFVoid), AllCapabilities()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Kernel %func \"compute\" \n" "OpDecorate %var Aliased\n" "%intt = OpTypeInt 32 0\n" "%ptr = OpTypePointer Input %intt\n" "%var = OpVariable %ptr Input\n" + std::string(kVoidFVoid), AllCapabilities()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Kernel %func \"compute\" \n" "OpDecorate %var Volatile\n" "%intt = OpTypeInt 32 0\n" "%ptr = OpTypePointer Input %intt\n" "%var = OpVariable %ptr Input\n" + std::string(kVoidFVoid), AllCapabilities()), std::make_pair(std::string(kGLSL450MemoryModel) + "OpEntryPoint Vertex %func \"shader\" \n" "OpDecorate %var Constant\n" "%intt = OpTypeInt 32 0\n" "%ptr = OpTypePointer Input %intt\n" "%var = OpVariable %ptr Input\n" + std::string(kVoidFVoid), KernelDependencies()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Kernel %func \"compute\" \n" "OpDecorate %var Coherent\n" "%intt = OpTypeInt 32 0\n" "%ptr = OpTypePointer Input %intt\n" "%var = OpVariable %ptr Input\n" + std::string(kVoidFVoid), AllCapabilities()), std::make_pair(std::string(kOpenCLMemoryModel) + // NonWritable must target something valid, such as a storage image. "OpEntryPoint Kernel %func \"compute\" \n" "OpDecorate %var NonWritable " "%float = OpTypeFloat 32 " "%imstor = OpTypeImage %float 2D 0 0 0 2 Unknown " "%ptr = OpTypePointer UniformConstant %imstor " "%var = OpVariable %ptr UniformConstant " + std::string(kVoidFVoid), AllCapabilities()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Kernel %func \"compute\" \n" "OpDecorate %var NonReadable " "%float = OpTypeFloat 32 " "%imstor = OpTypeImage %float 2D 0 0 0 2 Unknown " "%ptr = OpTypePointer UniformConstant %imstor " "%var = OpVariable %ptr UniformConstant " + std::string(kVoidFVoid), AllCapabilities()), std::make_pair(std::string(kOpenCLMemoryModel) + // Uniform must target a non-void value. "OpEntryPoint Kernel %func \"compute\" \n" "OpDecorate %int0 Uniform\n" "%intt = OpTypeInt 32 0\n" + "%int0 = OpConstantNull %intt" + std::string(kVoidFVoid), ShaderDependencies()), std::make_pair(std::string(kGLSL450MemoryModel) + "OpEntryPoint Vertex %func \"shader\" \n" "OpDecorate %intt SaturatedConversion\n" "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid), KernelDependencies()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Kernel %func \"compute\" \n" "OpDecorate %var Stream 0\n" "%intt = OpTypeInt 32 0\n" "%ptr = OpTypePointer Output %intt\n" "%var = OpVariable %ptr Output\n" + std::string(kVoidFVoid), std::vector{"GeometryStreams"}), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Kernel %func \"compute\" \n" "OpMemberDecorate %struct 0 Location 0\n" "%intt = OpTypeInt 32 0\n" "%struct = OpTypeStruct %intt\n" + std::string(kVoidFVoid), ShaderDependencies()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Kernel %func \"compute\" \n" "OpDecorate %var Component 0\n" "%intt = OpTypeInt 32 0\n" "%ptr = OpTypePointer Input %intt\n" "%var = OpVariable %ptr Input\n" + std::string(kVoidFVoid), ShaderDependencies()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Kernel %func \"compute\" \n" "OpDecorate %var Index 0\n" "%intt = OpTypeInt 32 0\n" "%ptr = OpTypePointer Input %intt\n" "%var = OpVariable %ptr Input\n" + std::string(kVoidFVoid), ShaderDependencies()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Kernel %func \"compute\" \n" "OpDecorate %var Binding 0\n" "%intt = OpTypeInt 32 0\n" "%ptr = OpTypePointer Uniform %intt\n" "%var = OpVariable %ptr Uniform\n" + std::string(kVoidFVoid), ShaderDependencies()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Kernel %func \"compute\" \n" "OpDecorate %var DescriptorSet 0\n" "%intt = OpTypeInt 32 0\n" "%ptr = OpTypePointer Uniform %intt\n" "%var = OpVariable %ptr Uniform\n" + std::string(kVoidFVoid), ShaderDependencies()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Kernel %func \"compute\" \n" "OpMemberDecorate %structt 0 Offset 0\n" "%intt = OpTypeInt 32 0\n" "%structt = OpTypeStruct %intt\n" + std::string(kVoidFVoid), ShaderDependencies()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Kernel %func \"compute\" \n" "OpDecorate %var XfbBuffer 0\n" "%intt = OpTypeInt 32 0\n" "%ptr = OpTypePointer Uniform %intt\n" "%var = OpVariable %ptr Uniform\n" + std::string(kVoidFVoid), std::vector{"TransformFeedback"}), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Kernel %func \"compute\" \n" "OpDecorate %var XfbStride 0\n" "%intt = OpTypeInt 32 0\n" "%ptr = OpTypePointer Uniform %intt\n" "%var = OpVariable %ptr Uniform\n" + std::string(kVoidFVoid), std::vector{"TransformFeedback"}), std::make_pair(std::string(kGLSL450MemoryModel) + "OpEntryPoint Vertex %func \"shader\" \n" "OpDecorate %intt FuncParamAttr Zext\n" "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid), KernelDependencies()), std::make_pair(std::string(kGLSL450MemoryModel) + "OpEntryPoint Vertex %func \"shader\" \n" "OpDecorate %intt FPFastMathMode Fast\n" "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid), KernelDependencies()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Kernel %func \"compute\" \n" "OpDecorate %intt LinkageAttributes \"other\" Import\n" "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid), std::vector{"Linkage"}), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Kernel %func \"compute\" \n" "OpDecorate %intt NoContraction\n" "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid), ShaderDependencies()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Kernel %func \"compute\" \n" "OpDecorate %var InputAttachmentIndex 0\n" "%intt = OpTypeInt 32 0\n" "%ptr = OpTypePointer UniformConstant %intt\n" "%var = OpVariable %ptr UniformConstant\n" + std::string(kVoidFVoid), std::vector{"InputAttachment"}), std::make_pair(std::string(kGLSL450MemoryModel) + "OpEntryPoint Vertex %func \"shader\" \n" "OpDecorate %intt Alignment 4\n" "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid), KernelDependencies()) ))); // clang-format on INSTANTIATE_TEST_SUITE_P( DecorationSpecId, ValidateCapability, Combine( ValuesIn(AllSpirV10Capabilities()), Values(std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Vertex %func \"shader\" \n" + "OpDecorate %1 SpecId 1\n" "%intt = OpTypeInt 32 0\n" "%1 = OpSpecConstant %intt 0\n" + std::string(kVoidFVoid), ShaderDependencies())))); INSTANTIATE_TEST_SUITE_P( DecorationV11, ValidateCapabilityV11, Combine(ValuesIn(AllCapabilities()), Values(std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Kernel %func \"compute\" \n" "OpDecorate %p MaxByteOffset 0 " "%i32 = OpTypeInt 32 0 " "%pi32 = OpTypePointer Workgroup %i32 " "%p = OpVariable %pi32 Workgroup " + std::string(kVoidFVoid), AddressesDependencies()), // Trying to test OpDecorate here, but if this fails due to // incorrect OpMemoryModel validation, that must also be // fixed. std::make_pair( std::string("OpMemoryModel Logical OpenCL " "OpEntryPoint Kernel %func \"compute\" \n" "OpDecorate %1 SpecId 1 " "%intt = OpTypeInt 32 0 " "%1 = OpSpecConstant %intt 0") + std::string(kVoidFVoid), KernelDependencies()), std::make_pair( std::string("OpMemoryModel Logical Simple " "OpEntryPoint Vertex %func \"shader\" \n" "OpDecorate %1 SpecId 1 " "%intt = OpTypeInt 32 0 " "%1 = OpSpecConstant %intt 0") + std::string(kVoidFVoid), ShaderDependencies())))); // clang-format off INSTANTIATE_TEST_SUITE_P(BuiltIn, ValidateCapability, Combine( ValuesIn(AllCapabilities()), Values( std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Kernel %func \"compute\" \n" + "OpDecorate %var BuiltIn Position\n" "%intt = OpTypeInt 32 0\n" "%ptr = OpTypePointer Input %intt\n" "%var = OpVariable %ptr Input\n" + std::string(kVoidFVoid), 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 std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Kernel %func \"compute\" \n" + "OpDecorate %var BuiltIn PointSize\n" "%intt = OpTypeInt 32 0\n" "%ptr = OpTypePointer Input %intt\n" "%var = OpVariable %ptr Input\n" + std::string(kVoidFVoid), AllCapabilities()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Kernel %func \"compute\" \n" + "OpDecorate %var BuiltIn ClipDistance\n" "%intt = OpTypeInt 32 0\n" "%ptr = OpTypePointer Input %intt\n" "%var = OpVariable %ptr Input\n" + std::string(kVoidFVoid), AllCapabilities()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Kernel %func \"compute\" \n" + "OpDecorate %var BuiltIn CullDistance\n" "%intt = OpTypeInt 32 0\n" "%ptr = OpTypePointer Input %intt\n" "%var = OpVariable %ptr Input\n" + std::string(kVoidFVoid), AllCapabilities()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Kernel %func \"compute\" \n" + "OpDecorate %var BuiltIn VertexId\n" "%intt = OpTypeInt 32 0\n" "%ptr = OpTypePointer Input %intt\n" "%var = OpVariable %ptr Input\n" + std::string(kVoidFVoid), ShaderDependencies()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Kernel %func \"compute\" \n" + "OpDecorate %var BuiltIn InstanceId\n" "%intt = OpTypeInt 32 0\n" "%ptr = OpTypePointer Input %intt\n" "%var = OpVariable %ptr Input\n" + std::string(kVoidFVoid), ShaderDependencies()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Kernel %func \"compute\" \n" + "OpDecorate %var BuiltIn PrimitiveId\n" "%intt = OpTypeInt 32 0\n" "%ptr = OpTypePointer Input %intt\n" "%var = OpVariable %ptr Input\n" + std::string(kVoidFVoid), GeometryTessellationDependencies()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Kernel %func \"compute\" \n" + "OpDecorate %var BuiltIn InvocationId\n" "%intt = OpTypeInt 32 0\n" "%ptr = OpTypePointer Input %intt\n" "%var = OpVariable %ptr Input\n" + std::string(kVoidFVoid), GeometryTessellationDependencies()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Kernel %func \"compute\" \n" + "OpDecorate %var BuiltIn Layer\n" "%intt = OpTypeInt 32 0\n" "%ptr = OpTypePointer Input %intt\n" "%var = OpVariable %ptr Input\n" + std::string(kVoidFVoid), GeometryDependencies()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Kernel %func \"compute\" \n" + "OpDecorate %var BuiltIn ViewportIndex\n" "%intt = OpTypeInt 32 0\n" "%ptr = OpTypePointer Input %intt\n" "%var = OpVariable %ptr Input\n" + std::string(kVoidFVoid), std::vector{"MultiViewport"}), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Kernel %func \"compute\" \n" + "OpDecorate %var BuiltIn TessLevelOuter\n" "%intt = OpTypeInt 32 0\n" "%ptr = OpTypePointer Input %intt\n" "%var = OpVariable %ptr Input\n" + std::string(kVoidFVoid), TessellationDependencies()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Kernel %func \"compute\" \n" + "OpDecorate %var BuiltIn TessLevelInner\n" "%intt = OpTypeInt 32 0\n" "%ptr = OpTypePointer Input %intt\n" "%var = OpVariable %ptr Input\n" + std::string(kVoidFVoid), TessellationDependencies()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Kernel %func \"compute\" \n" + "OpDecorate %var BuiltIn TessCoord\n" "%intt = OpTypeInt 32 0\n" "%ptr = OpTypePointer Input %intt\n" "%var = OpVariable %ptr Input\n" + std::string(kVoidFVoid), TessellationDependencies()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Kernel %func \"compute\" \n" + "OpDecorate %var BuiltIn PatchVertices\n" "%intt = OpTypeInt 32 0\n" "%ptr = OpTypePointer Input %intt\n" "%var = OpVariable %ptr Input\n" + std::string(kVoidFVoid), TessellationDependencies()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Kernel %func \"compute\" \n" + "OpDecorate %var BuiltIn FragCoord\n" "%intt = OpTypeInt 32 0\n" "%ptr = OpTypePointer Input %intt\n" "%var = OpVariable %ptr Input\n" + std::string(kVoidFVoid), ShaderDependencies()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Kernel %func \"compute\" \n" + "OpDecorate %var BuiltIn PointCoord\n" "%intt = OpTypeInt 32 0\n" "%ptr = OpTypePointer Input %intt\n" "%var = OpVariable %ptr Input\n" + std::string(kVoidFVoid), ShaderDependencies()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Kernel %func \"compute\" \n" + "OpDecorate %var BuiltIn FrontFacing\n" "%intt = OpTypeInt 32 0\n" "%ptr = OpTypePointer Input %intt\n" "%var = OpVariable %ptr Input\n" + std::string(kVoidFVoid), ShaderDependencies()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Kernel %func \"compute\" \n" + "OpDecorate %var BuiltIn SampleId\n" "%intt = OpTypeInt 32 0\n" "%ptr = OpTypePointer Input %intt\n" "%var = OpVariable %ptr Input\n" + std::string(kVoidFVoid), std::vector{"SampleRateShading"}), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Kernel %func \"compute\" \n" + "OpDecorate %var BuiltIn SamplePosition\n" "%intt = OpTypeInt 32 0\n" "%ptr = OpTypePointer Input %intt\n" "%var = OpVariable %ptr Input\n" + std::string(kVoidFVoid), std::vector{"SampleRateShading"}), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Kernel %func \"compute\" \n" + "OpDecorate %var BuiltIn SampleMask\n" "%intt = OpTypeInt 32 0\n" "%ptr = OpTypePointer Input %intt\n" "%var = OpVariable %ptr Input\n" + std::string(kVoidFVoid), ShaderDependencies()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Kernel %func \"compute\" \n" + "OpDecorate %var BuiltIn FragDepth\n" "%intt = OpTypeInt 32 0\n" "%ptr = OpTypePointer Input %intt\n" "%var = OpVariable %ptr Input\n" + std::string(kVoidFVoid), ShaderDependencies()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Kernel %func \"compute\" \n" + "OpDecorate %var BuiltIn HelperInvocation\n" "%intt = OpTypeInt 32 0\n" "%ptr = OpTypePointer Input %intt\n" "%var = OpVariable %ptr Input\n" + std::string(kVoidFVoid), ShaderDependencies()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Kernel %func \"compute\" \n" + "OpDecorate %var BuiltIn VertexIndex\n" "%intt = OpTypeInt 32 0\n" "%ptr = OpTypePointer Input %intt\n" "%var = OpVariable %ptr Input\n" + std::string(kVoidFVoid), ShaderDependencies()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Kernel %func \"compute\" \n" + "OpDecorate %var BuiltIn InstanceIndex\n" "%intt = OpTypeInt 32 0\n" "%ptr = OpTypePointer Input %intt\n" "%var = OpVariable %ptr Input\n" + std::string(kVoidFVoid), ShaderDependencies()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Kernel %func \"compute\" \n" + "OpDecorate %var BuiltIn NumWorkgroups\n" "%intt = OpTypeInt 32 0\n" "%ptr = OpTypePointer Input %intt\n" "%var = OpVariable %ptr Input\n" + std::string(kVoidFVoid), AllCapabilities()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Kernel %func \"compute\" \n" + "OpDecorate %var BuiltIn WorkgroupId\n" "%intt = OpTypeInt 32 0\n" "%ptr = OpTypePointer Input %intt\n" "%var = OpVariable %ptr Input\n" + std::string(kVoidFVoid), AllCapabilities()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Kernel %func \"compute\" \n" + "OpDecorate %var BuiltIn LocalInvocationId\n" "%intt = OpTypeInt 32 0\n" "%ptr = OpTypePointer Input %intt\n" "%var = OpVariable %ptr Input\n" + std::string(kVoidFVoid), AllCapabilities()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Kernel %func \"compute\" \n" + "OpDecorate %var BuiltIn GlobalInvocationId\n" "%intt = OpTypeInt 32 0\n" "%ptr = OpTypePointer Input %intt\n" "%var = OpVariable %ptr Input\n" + std::string(kVoidFVoid), AllCapabilities()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Kernel %func \"compute\" \n" + "OpDecorate %var BuiltIn LocalInvocationIndex\n" "%intt = OpTypeInt 32 0\n" "%ptr = OpTypePointer Input %intt\n" "%var = OpVariable %ptr Input\n" + std::string(kVoidFVoid), AllCapabilities()), std::make_pair(std::string(kGLSL450MemoryModel) + "OpEntryPoint Vertex %func \"shader\" \n" + "OpDecorate %var BuiltIn WorkDim\n" "%intt = OpTypeInt 32 0\n" "%ptr = OpTypePointer Input %intt\n" "%var = OpVariable %ptr Input\n" + std::string(kVoidFVoid), KernelDependencies()), std::make_pair(std::string(kGLSL450MemoryModel) + "OpEntryPoint Vertex %func \"shader\" \n" + "OpDecorate %var BuiltIn GlobalSize\n" "%intt = OpTypeInt 32 0\n" "%ptr = OpTypePointer Input %intt\n" "%var = OpVariable %ptr Input\n" + std::string(kVoidFVoid), KernelDependencies()), std::make_pair(std::string(kGLSL450MemoryModel) + "OpEntryPoint Vertex %func \"shader\" \n" + "OpDecorate %var BuiltIn EnqueuedWorkgroupSize\n" "%intt = OpTypeInt 32 0\n" "%ptr = OpTypePointer Input %intt\n" "%var = OpVariable %ptr Input\n" + std::string(kVoidFVoid), KernelDependencies()), std::make_pair(std::string(kGLSL450MemoryModel) + "OpEntryPoint Vertex %func \"shader\" \n" + "OpDecorate %var BuiltIn GlobalOffset\n" "%intt = OpTypeInt 32 0\n" "%ptr = OpTypePointer Input %intt\n" "%var = OpVariable %ptr Input\n" + std::string(kVoidFVoid), KernelDependencies()), std::make_pair(std::string(kGLSL450MemoryModel) + "OpEntryPoint Vertex %func \"shader\" \n" + "OpDecorate %var BuiltIn GlobalLinearId\n" "%intt = OpTypeInt 32 0\n" "%ptr = OpTypePointer Input %intt\n" "%var = OpVariable %ptr Input\n" + std::string(kVoidFVoid), KernelDependencies()), std::make_pair(std::string(kGLSL450MemoryModel) + "OpEntryPoint Vertex %func \"shader\" \n" + "OpDecorate %var BuiltIn SubgroupSize\n" "%intt = OpTypeInt 32 0\n" "%ptr = OpTypePointer Input %intt\n" "%var = OpVariable %ptr Input\n" + std::string(kVoidFVoid), KernelAndGroupNonUniformDependencies()), std::make_pair(std::string(kGLSL450MemoryModel) + "OpEntryPoint Vertex %func \"shader\" \n" + "OpDecorate %var BuiltIn SubgroupMaxSize\n" "%intt = OpTypeInt 32 0\n" "%ptr = OpTypePointer Input %intt\n" "%var = OpVariable %ptr Input\n" + std::string(kVoidFVoid), KernelDependencies()), std::make_pair(std::string(kGLSL450MemoryModel) + "OpEntryPoint Vertex %func \"shader\" \n" + "OpDecorate %var BuiltIn NumSubgroups\n" "%intt = OpTypeInt 32 0\n" "%ptr = OpTypePointer Input %intt\n" "%var = OpVariable %ptr Input\n" + std::string(kVoidFVoid), KernelAndGroupNonUniformDependencies()), std::make_pair(std::string(kGLSL450MemoryModel) + "OpEntryPoint Vertex %func \"shader\" \n" + "OpDecorate %var BuiltIn NumEnqueuedSubgroups\n" "%intt = OpTypeInt 32 0\n" "%ptr = OpTypePointer Input %intt\n" "%var = OpVariable %ptr Input\n" + std::string(kVoidFVoid), KernelDependencies()), std::make_pair(std::string(kGLSL450MemoryModel) + "OpEntryPoint Vertex %func \"shader\" \n" + "OpDecorate %var BuiltIn SubgroupId\n" "%intt = OpTypeInt 32 0\n" "%ptr = OpTypePointer Input %intt\n" "%var = OpVariable %ptr Input\n" + std::string(kVoidFVoid), KernelAndGroupNonUniformDependencies()), std::make_pair(std::string(kGLSL450MemoryModel) + "OpEntryPoint Vertex %func \"shader\" \n" + "OpDecorate %var BuiltIn SubgroupLocalInvocationId\n" "%intt = OpTypeInt 32 0\n" "%ptr = OpTypePointer Input %intt\n" "%var = OpVariable %ptr Input\n" + std::string(kVoidFVoid), KernelAndGroupNonUniformDependencies()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Kernel %func \"compute\" \n" + "OpDecorate %var BuiltIn VertexIndex\n" "%intt = OpTypeInt 32 0\n" "%ptr = OpTypePointer Input %intt\n" "%var = OpVariable %ptr Input\n" + std::string(kVoidFVoid), ShaderDependencies()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Kernel %func \"compute\" \n" + "OpDecorate %var BuiltIn InstanceIndex\n" "%intt = OpTypeInt 32 0\n" "%ptr = OpTypePointer Input %intt\n" "%var = OpVariable %ptr Input\n" + std::string(kVoidFVoid), 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_SUITE_P(BuiltIn, ValidateCapabilityVulkan10, Combine( // All capabilities to try. ValuesIn(AllSpirV10Capabilities()), Values( std::make_pair(std::string(kGLSL450MemoryModel) + "OpEntryPoint Vertex %func \"shader\" %var\n" + "OpDecorate %var BuiltIn PointSize\n" "%float = OpTypeFloat 32\n" "%ptr_output_float = OpTypePointer Output %float\n" "%var = OpVariable %ptr_output_float Output\n" + std::string(kVoidFVoid), // Capabilities which should succeed. AllVulkan10Capabilities()), std::make_pair(std::string(kGLSL450MemoryModel) + "OpEntryPoint Vertex %func \"shader\" \n" "OpMemberDecorate %block 0 BuiltIn ClipDistance\n" "%f32 = OpTypeFloat 32\n" "%intt = OpTypeInt 32 0\n" "%intt_4 = OpConstant %intt 4\n" "%f32arr4 = OpTypeArray %f32 %intt_4\n" "%block = OpTypeStruct %f32arr4\n" + std::string(kVoidFVoid), AllVulkan10Capabilities()), std::make_pair(std::string(kGLSL450MemoryModel) + "OpEntryPoint Vertex %func \"shader\" \n" "OpMemberDecorate %block 0 BuiltIn CullDistance\n" "%f32 = OpTypeFloat 32\n" "%intt = OpTypeInt 32 0\n" "%intt_4 = OpConstant %intt 4\n" "%f32arr4 = OpTypeArray %f32 %intt_4\n" "%block = OpTypeStruct %f32arr4\n" + std::string(kVoidFVoid), AllVulkan10Capabilities()) ))); INSTANTIATE_TEST_SUITE_P(BuiltIn, ValidateCapabilityOpenGL40, Combine( // OpenGL 4.0 is based on SPIR-V 1.0 ValuesIn(AllSpirV10Capabilities()), Values( std::make_pair(std::string(kGLSL450MemoryModel) + "OpEntryPoint Vertex %func \"shader\" %var\n" + "OpDecorate %var BuiltIn PointSize\n" "%float = OpTypeFloat 32\n" "%ptr_output_float = OpTypePointer Output %float\n" "%var = OpVariable %ptr_output_float Output\n" + std::string(kVoidFVoid), AllSpirV10Capabilities()), std::make_pair(std::string(kGLSL450MemoryModel) + "OpEntryPoint Vertex %func \"shader\" %var\n" + "OpDecorate %var BuiltIn ClipDistance\n" "%float = OpTypeFloat 32\n" "%int = OpTypeInt 32 0\n" "%int_1 = OpConstant %int 1\n" "%array = OpTypeArray %float %int_1\n" "%ptr = OpTypePointer Output %array\n" "%var = OpVariable %ptr Output\n" + std::string(kVoidFVoid), AllSpirV10Capabilities()), std::make_pair(std::string(kGLSL450MemoryModel) + "OpEntryPoint Vertex %func \"shader\" %var\n" + "OpDecorate %var BuiltIn CullDistance\n" "%float = OpTypeFloat 32\n" "%int = OpTypeInt 32 0\n" "%int_1 = OpConstant %int 1\n" "%array = OpTypeArray %float %int_1\n" "%ptr = OpTypePointer Output %array\n" "%var = OpVariable %ptr Output\n" + std::string(kVoidFVoid), AllSpirV10Capabilities()) ))); INSTANTIATE_TEST_SUITE_P(Capabilities, ValidateCapabilityVulkan11, Combine( // All capabilities to try. ValuesIn(AllCapabilities()), Values( std::make_pair(std::string(kGLSL450MemoryModel) + "OpEntryPoint Vertex %func \"shader\" %var\n" + "OpDecorate %var BuiltIn PointSize\n" "%float = OpTypeFloat 32\n" "%ptr_output_float = OpTypePointer Output %float\n" "%var = OpVariable %ptr_output_float Output\n" + std::string(kVoidFVoid), AllVulkan11Capabilities()), std::make_pair(std::string(kGLSL450MemoryModel) + "OpEntryPoint Vertex %func \"shader\" %var\n" + "OpDecorate %var BuiltIn CullDistance\n" "%float = OpTypeFloat 32\n" "%int = OpTypeInt 32 0\n" "%int_1 = OpConstant %int 1\n" "%array = OpTypeArray %float %int_1\n" "%ptr = OpTypePointer Output %array\n" "%var = OpVariable %ptr Output\n" + std::string(kVoidFVoid), AllVulkan11Capabilities()) ))); INSTANTIATE_TEST_SUITE_P(Capabilities, ValidateCapabilityVulkan12, Combine( // All capabilities to try. ValuesIn(AllSpirV15Capabilities()), Values( std::make_pair(std::string(kGLSL450MemoryModel) + "OpEntryPoint Vertex %func \"shader\" %var\n" + "OpDecorate %var BuiltIn PointSize\n" "%float = OpTypeFloat 32\n" "%ptr_output_float = OpTypePointer Output %float\n" "%var = OpVariable %ptr_output_float Output\n" + std::string(kVoidFVoid), AllVulkan12Capabilities()), std::make_pair(std::string(kGLSL450MemoryModel) + "OpEntryPoint Vertex %func \"shader\" %var\n" + "OpDecorate %var BuiltIn CullDistance\n" "%float = OpTypeFloat 32\n" "%int = OpTypeInt 32 0\n" "%int_1 = OpConstant %int 1\n" "%array = OpTypeArray %float %int_1\n" "%ptr = OpTypePointer Output %array\n" "%var = OpVariable %ptr Output\n" + std::string(kVoidFVoid), AllVulkan12Capabilities()) ))); // 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_SUITE_P(MatrixOp, ValidateCapability, Combine( ValuesIn(AllCapabilities()), Values( std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Kernel %func \"compute\" \n" + "%f32 = OpTypeFloat 32\n" "%vec3 = OpTypeVector %f32 3\n" "%mat33 = OpTypeMatrix %vec3 3\n" + std::string(kVoidFVoid), MatrixDependencies())))); // clang-format on #if 0 // TODO(atgoo@github.com) The following test is not valid as it generates // invalid combinations of images, instructions and image operands. // // 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 std::string& operands) { ostringstream ss; // clang-format off ss << R"( OpCapability Kernel OpCapability Linkage OpMemoryModel Logical OpenCL %i32 = OpTypeInt 32 0 %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_SUITE_P( TwoImageOperandsMask, ValidateCapability, Combine( ValuesIn(AllCapabilities()), Values(std::make_pair(ImageOperandsTemplate("Bias|Lod %fzero %fzero"), ShaderDependencies()), std::make_pair(ImageOperandsTemplate("Lod|Offset %fzero %izero"), std::vector{"ImageGatherExtended"}), std::make_pair(ImageOperandsTemplate("Sample|MinLod %izero %fzero"), std::vector{"MinLod"}), std::make_pair(ImageOperandsTemplate("Lod|Sample %fzero %izero"), AllCapabilities()))), ); #endif // TODO(umar): Instruction capability checks spv_result_t spvCoreOperandTableNameLookup(spv_target_env env, const spv_operand_table table, const spv_operand_type_t type, const char* name, const size_t nameLength) { if (!table) return SPV_ERROR_INVALID_TABLE; if (!name) return SPV_ERROR_INVALID_POINTER; for (uint64_t typeIndex = 0; typeIndex < table->count; ++typeIndex) { const auto& group = table->types[typeIndex]; if (type != group.type) continue; for (uint64_t index = 0; index < group.count; ++index) { const auto& entry = group.entries[index]; // Check for min version only. if (spvVersionForTargetEnv(env) >= entry.minVersion && nameLength == strlen(entry.name) && !strncmp(entry.name, name, nameLength)) { return SPV_SUCCESS; } } } return SPV_ERROR_INVALID_LOOKUP; } // True if capability exists in core spec of env. bool Exists(const std::string& capability, spv_target_env env) { ScopedContext sc(env); return SPV_SUCCESS == spvCoreOperandTableNameLookup(env, sc.context->operand_table, SPV_OPERAND_TYPE_CAPABILITY, capability.c_str(), capability.size()); } TEST_P(ValidateCapability, Capability) { const std::string capability = Capability(GetParam()); spv_target_env env = SPV_ENV_UNIVERSAL_1_0; if (!capability.empty()) { if (Exists(capability, SPV_ENV_UNIVERSAL_1_0)) env = SPV_ENV_UNIVERSAL_1_0; else if (Exists(capability, SPV_ENV_UNIVERSAL_1_1)) env = SPV_ENV_UNIVERSAL_1_1; else if (Exists(capability, SPV_ENV_UNIVERSAL_1_2)) env = SPV_ENV_UNIVERSAL_1_2; else env = SPV_ENV_UNIVERSAL_1_3; } const std::string test_code = MakeAssembly(GetParam()); CompileSuccessfully(test_code, env); ASSERT_EQ(ExpectedResult(GetParam()), ValidateInstructions(env)) << "target env: " << spvTargetEnvDescription(env) << "\ntest code:\n" << test_code; } TEST_P(ValidateCapabilityV11, Capability) { const std::string capability = Capability(GetParam()); if (Exists(capability, SPV_ENV_UNIVERSAL_1_1)) { const std::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 std::string capability = Capability(GetParam()); if (Exists(capability, SPV_ENV_VULKAN_1_0)) { const std::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(ValidateCapabilityVulkan11, Capability) { const std::string capability = Capability(GetParam()); if (Exists(capability, SPV_ENV_VULKAN_1_1)) { const std::string test_code = MakeAssembly(GetParam()); CompileSuccessfully(test_code, SPV_ENV_VULKAN_1_1); ASSERT_EQ(ExpectedResult(GetParam()), ValidateInstructions(SPV_ENV_VULKAN_1_1)) << test_code; } } TEST_P(ValidateCapabilityVulkan12, Capability) { const std::string capability = Capability(GetParam()); if (Exists(capability, SPV_ENV_VULKAN_1_2)) { const std::string test_code = MakeAssembly(GetParam()); CompileSuccessfully(test_code, SPV_ENV_VULKAN_1_2); ASSERT_EQ(ExpectedResult(GetParam()), ValidateInstructions(SPV_ENV_VULKAN_1_2)) << test_code; } } TEST_P(ValidateCapabilityOpenGL40, Capability) { const std::string capability = Capability(GetParam()); if (Exists(capability, SPV_ENV_OPENGL_4_0)) { const std::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 OpCapability Linkage OpMemoryModel Logical OpenCL ; %i32 has ID 1 %i32 = OpTypeInt 32 0 %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 64, the "id bound" in the binary header // must be overwritten so that 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()); } TEST_F(ValidateCapability, IntSignednessKernelGood) { const std::string spirv = R"( OpCapability Kernel OpCapability Linkage OpMemoryModel Logical OpenCL %i32 = OpTypeInt 32 0 )"; CompileSuccessfully(spirv); EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); } TEST_F(ValidateCapability, IntSignednessKernelBad) { const std::string spirv = R"( OpCapability Kernel OpCapability Linkage OpMemoryModel Logical OpenCL %i32 = OpTypeInt 32 1 )"; CompileSuccessfully(spirv); EXPECT_EQ(SPV_ERROR_INVALID_BINARY, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), HasSubstr("The Signedness in OpTypeInt must always be 0 when " "Kernel capability is used.")); } TEST_F(ValidateCapability, IntSignednessShaderGood) { const std::string spirv = R"( OpCapability Shader OpCapability Linkage OpMemoryModel Logical GLSL450 %u32 = OpTypeInt 32 0 %i32 = OpTypeInt 32 1 )"; CompileSuccessfully(spirv); EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); } TEST_F(ValidateCapability, NonVulkan10Capability) { const std::string spirv = R"( OpCapability Shader OpCapability Linkage OpMemoryModel Logical GLSL450 %u32 = OpTypeInt 32 0 %i32 = OpTypeInt 32 1 )"; CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_0); EXPECT_EQ(SPV_ERROR_INVALID_CAPABILITY, ValidateInstructions(SPV_ENV_VULKAN_1_0)); EXPECT_THAT(getDiagnosticString(), HasSubstr("Capability Linkage is not allowed by Vulkan 1.0")); } TEST_F(ValidateCapability, Vulkan10EnabledByExtension) { const std::string spirv = R"( OpCapability Shader OpCapability DrawParameters OpExtension "SPV_KHR_shader_draw_parameters" OpMemoryModel Logical GLSL450 OpEntryPoint Vertex %func "shader" OpMemberDecorate %block 0 BuiltIn PointSize %f32 = OpTypeFloat 32 %block = OpTypeStruct %f32 )" + std::string(kVoidFVoid); CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_0); EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_0)); } TEST_F(ValidateCapability, Vulkan10NotEnabledByExtension) { const std::string spirv = R"( OpCapability Shader OpCapability DrawParameters OpMemoryModel Logical GLSL450 OpEntryPoint Vertex %func "shader" OpDecorate %intt BuiltIn PointSize %intt = OpTypeInt 32 0 )" + std::string(kVoidFVoid); CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_0); EXPECT_EQ(SPV_ERROR_INVALID_CAPABILITY, ValidateInstructions(SPV_ENV_VULKAN_1_0)); EXPECT_THAT( getDiagnosticString(), HasSubstr("Capability DrawParameters is not allowed by Vulkan 1.0")); } TEST_F(ValidateCapability, NonOpenCL12FullCapability) { const std::string spirv = R"( OpCapability Kernel OpCapability Addresses OpCapability Linkage OpCapability Pipes OpMemoryModel Physical64 OpenCL %u32 = OpTypeInt 32 0 )"; CompileSuccessfully(spirv, SPV_ENV_OPENCL_1_2); EXPECT_EQ(SPV_ERROR_INVALID_CAPABILITY, ValidateInstructions(SPV_ENV_OPENCL_1_2)); EXPECT_THAT( getDiagnosticString(), HasSubstr("Capability Pipes is not allowed by OpenCL 1.2 Full Profile")); } TEST_F(ValidateCapability, OpenCL12FullEnabledByCapability) { const std::string spirv = R"( OpCapability Kernel OpCapability Addresses OpCapability Linkage OpCapability ImageBasic OpCapability Sampled1D OpMemoryModel Physical64 OpenCL %u32 = OpTypeInt 32 0 )" + std::string(kVoidFVoid); CompileSuccessfully(spirv, SPV_ENV_OPENCL_1_2); EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_OPENCL_1_2)); } TEST_F(ValidateCapability, OpenCL12FullNotEnabledByCapability) { const std::string spirv = R"( OpCapability Kernel OpCapability Addresses OpCapability Linkage OpCapability Sampled1D OpMemoryModel Physical64 OpenCL %u32 = OpTypeInt 32 0 )" + std::string(kVoidFVoid); CompileSuccessfully(spirv, SPV_ENV_OPENCL_1_2); EXPECT_EQ(SPV_ERROR_INVALID_CAPABILITY, ValidateInstructions(SPV_ENV_OPENCL_1_2)); EXPECT_THAT( getDiagnosticString(), HasSubstr( "Capability Sampled1D is not allowed by OpenCL 1.2 Full Profile")); } TEST_F(ValidateCapability, NonOpenCL12EmbeddedCapability) { const std::string spirv = R"( OpCapability Kernel OpCapability Addresses OpCapability Linkage OpCapability Int64 OpMemoryModel Physical64 OpenCL %u32 = OpTypeInt 32 0 )"; CompileSuccessfully(spirv, SPV_ENV_OPENCL_EMBEDDED_1_2); EXPECT_EQ(SPV_ERROR_INVALID_CAPABILITY, ValidateInstructions(SPV_ENV_OPENCL_EMBEDDED_1_2)); EXPECT_THAT( getDiagnosticString(), HasSubstr( "Capability Int64 is not allowed by OpenCL 1.2 Embedded Profile")); } TEST_F(ValidateCapability, OpenCL12EmbeddedEnabledByCapability) { const std::string spirv = R"( OpCapability Kernel OpCapability Addresses OpCapability Linkage OpCapability ImageBasic OpCapability Sampled1D OpMemoryModel Physical64 OpenCL %u32 = OpTypeInt 32 0 )" + std::string(kVoidFVoid); CompileSuccessfully(spirv, SPV_ENV_OPENCL_EMBEDDED_1_2); EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_OPENCL_EMBEDDED_1_2)); } TEST_F(ValidateCapability, OpenCL12EmbeddedNotEnabledByCapability) { const std::string spirv = R"( OpCapability Kernel OpCapability Addresses OpCapability Linkage OpCapability Sampled1D OpMemoryModel Physical64 OpenCL %u32 = OpTypeInt 32 0 )" + std::string(kVoidFVoid); CompileSuccessfully(spirv, SPV_ENV_OPENCL_EMBEDDED_1_2); EXPECT_EQ(SPV_ERROR_INVALID_CAPABILITY, ValidateInstructions(SPV_ENV_OPENCL_EMBEDDED_1_2)); EXPECT_THAT(getDiagnosticString(), HasSubstr("Capability Sampled1D is not allowed by OpenCL 1.2 " "Embedded Profile")); } TEST_F(ValidateCapability, OpenCL12EmbeddedNoLongerEnabledByCapability) { const std::string spirv = R"( OpCapability Kernel OpCapability Addresses OpCapability Linkage OpCapability Pipes OpMemoryModel Physical64 OpenCL %u32 = OpTypeInt 32 0 )" + std::string(kVoidFVoid); CompileSuccessfully(spirv, SPV_ENV_OPENCL_EMBEDDED_1_2); EXPECT_EQ(SPV_ERROR_INVALID_CAPABILITY, ValidateInstructions(SPV_ENV_OPENCL_EMBEDDED_1_2)); EXPECT_THAT(getDiagnosticString(), HasSubstr("Capability Pipes is not allowed by OpenCL 1.2 " "Embedded Profile")); } TEST_F(ValidateCapability, OpenCL20FullCapability) { const std::string spirv = R"( OpCapability Kernel OpCapability Addresses OpCapability Linkage OpCapability Groups OpCapability Pipes OpMemoryModel Physical64 OpenCL %u32 = OpTypeInt 32 0 )"; CompileSuccessfully(spirv, SPV_ENV_OPENCL_2_0); EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_OPENCL_2_0)); } TEST_F(ValidateCapability, NonOpenCL20FullCapability) { const std::string spirv = R"( OpCapability Kernel OpCapability Addresses OpCapability Linkage OpCapability Matrix OpMemoryModel Physical64 OpenCL %u32 = OpTypeInt 32 0 )"; CompileSuccessfully(spirv, SPV_ENV_OPENCL_2_0); EXPECT_EQ(SPV_ERROR_INVALID_CAPABILITY, ValidateInstructions(SPV_ENV_OPENCL_2_0)); EXPECT_THAT( getDiagnosticString(), HasSubstr( "Capability Matrix is not allowed by OpenCL 2.0/2.1 Full Profile")); } TEST_F(ValidateCapability, OpenCL20FullEnabledByCapability) { const std::string spirv = R"( OpCapability Kernel OpCapability Addresses OpCapability Linkage OpCapability ImageBasic OpCapability Sampled1D OpMemoryModel Physical64 OpenCL %u32 = OpTypeInt 32 0 )" + std::string(kVoidFVoid); CompileSuccessfully(spirv, SPV_ENV_OPENCL_2_0); EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_OPENCL_2_0)); } TEST_F(ValidateCapability, OpenCL20FullNotEnabledByCapability) { const std::string spirv = R"( OpCapability Kernel OpCapability Addresses OpCapability Linkage OpCapability Sampled1D OpMemoryModel Physical64 OpenCL %u32 = OpTypeInt 32 0 )" + std::string(kVoidFVoid); CompileSuccessfully(spirv, SPV_ENV_OPENCL_2_0); EXPECT_EQ(SPV_ERROR_INVALID_CAPABILITY, ValidateInstructions(SPV_ENV_OPENCL_2_0)); EXPECT_THAT(getDiagnosticString(), HasSubstr("Capability Sampled1D is not allowed by OpenCL 2.0/2.1 " "Full Profile")); } TEST_F(ValidateCapability, NonOpenCL20EmbeddedCapability) { const std::string spirv = R"( OpCapability Kernel OpCapability Addresses OpCapability Linkage OpCapability Int64 OpMemoryModel Physical64 OpenCL %u32 = OpTypeInt 32 0 )"; CompileSuccessfully(spirv, SPV_ENV_OPENCL_EMBEDDED_2_0); EXPECT_EQ(SPV_ERROR_INVALID_CAPABILITY, ValidateInstructions(SPV_ENV_OPENCL_EMBEDDED_2_0)); EXPECT_THAT(getDiagnosticString(), HasSubstr("Capability Int64 is not allowed by OpenCL 2.0/2.1 " "Embedded Profile")); } TEST_F(ValidateCapability, OpenCL20EmbeddedEnabledByCapability) { const std::string spirv = R"( OpCapability Kernel OpCapability Addresses OpCapability Linkage OpCapability ImageBasic OpCapability Sampled1D OpMemoryModel Physical64 OpenCL %u32 = OpTypeInt 32 0 )" + std::string(kVoidFVoid); CompileSuccessfully(spirv, SPV_ENV_OPENCL_EMBEDDED_2_0); EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_OPENCL_EMBEDDED_2_0)); } TEST_F(ValidateCapability, OpenCL20EmbeddedNotEnabledByCapability) { const std::string spirv = R"( OpCapability Kernel OpCapability Addresses OpCapability Linkage OpCapability Sampled1D OpMemoryModel Physical64 OpenCL %u32 = OpTypeInt 32 0 )" + std::string(kVoidFVoid); CompileSuccessfully(spirv, SPV_ENV_OPENCL_EMBEDDED_2_0); EXPECT_EQ(SPV_ERROR_INVALID_CAPABILITY, ValidateInstructions(SPV_ENV_OPENCL_EMBEDDED_2_0)); EXPECT_THAT(getDiagnosticString(), HasSubstr("Capability Sampled1D is not allowed by OpenCL 2.0/2.1 " "Embedded Profile")); } TEST_F(ValidateCapability, OpenCL22FullCapability) { const std::string spirv = R"( OpCapability Kernel OpCapability Addresses OpCapability Linkage OpCapability PipeStorage OpMemoryModel Physical64 OpenCL %u32 = OpTypeInt 32 0 )"; CompileSuccessfully(spirv, SPV_ENV_OPENCL_2_2); EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_OPENCL_2_2)); } TEST_F(ValidateCapability, NonOpenCL22FullCapability) { const std::string spirv = R"( OpCapability Kernel OpCapability Addresses OpCapability Linkage OpCapability Matrix OpMemoryModel Physical64 OpenCL %u32 = OpTypeInt 32 0 )"; CompileSuccessfully(spirv, SPV_ENV_OPENCL_2_2); EXPECT_EQ(SPV_ERROR_INVALID_CAPABILITY, ValidateInstructions(SPV_ENV_OPENCL_2_2)); EXPECT_THAT( getDiagnosticString(), HasSubstr("Capability Matrix is not allowed by OpenCL 2.2 Full Profile")); } TEST_F(ValidateCapability, OpenCL22FullEnabledByCapability) { const std::string spirv = R"( OpCapability Kernel OpCapability Addresses OpCapability Linkage OpCapability ImageBasic OpCapability Sampled1D OpMemoryModel Physical64 OpenCL %u32 = OpTypeInt 32 0 )" + std::string(kVoidFVoid); CompileSuccessfully(spirv, SPV_ENV_OPENCL_2_2); EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_OPENCL_2_2)); } TEST_F(ValidateCapability, OpenCL22FullNotEnabledByCapability) { const std::string spirv = R"( OpCapability Kernel OpCapability Addresses OpCapability Linkage OpCapability Sampled1D OpMemoryModel Physical64 OpenCL %u32 = OpTypeInt 32 0 )" + std::string(kVoidFVoid); CompileSuccessfully(spirv, SPV_ENV_OPENCL_2_2); EXPECT_EQ(SPV_ERROR_INVALID_CAPABILITY, ValidateInstructions(SPV_ENV_OPENCL_2_2)); EXPECT_THAT( getDiagnosticString(), HasSubstr( "Capability Sampled1D is not allowed by OpenCL 2.2 Full Profile")); } TEST_F(ValidateCapability, NonOpenCL22EmbeddedCapability) { const std::string spirv = R"( OpCapability Kernel OpCapability Addresses OpCapability Linkage OpCapability Int64 OpMemoryModel Physical64 OpenCL %u32 = OpTypeInt 32 0 )"; CompileSuccessfully(spirv, SPV_ENV_OPENCL_EMBEDDED_2_2); EXPECT_EQ(SPV_ERROR_INVALID_CAPABILITY, ValidateInstructions(SPV_ENV_OPENCL_EMBEDDED_2_2)); EXPECT_THAT( getDiagnosticString(), HasSubstr( "Capability Int64 is not allowed by OpenCL 2.2 Embedded Profile")); } TEST_F(ValidateCapability, OpenCL22EmbeddedEnabledByCapability) { const std::string spirv = R"( OpCapability Kernel OpCapability Addresses OpCapability Linkage OpCapability ImageBasic OpCapability Sampled1D OpMemoryModel Physical64 OpenCL %u32 = OpTypeInt 32 0 )" + std::string(kVoidFVoid); CompileSuccessfully(spirv, SPV_ENV_OPENCL_EMBEDDED_2_2); EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_OPENCL_EMBEDDED_2_2)); } TEST_F(ValidateCapability, OpenCL22EmbeddedNotEnabledByCapability) { const std::string spirv = R"( OpCapability Kernel OpCapability Addresses OpCapability Linkage OpCapability Sampled1D OpMemoryModel Physical64 OpenCL %u32 = OpTypeInt 32 0 )" + std::string(kVoidFVoid); CompileSuccessfully(spirv, SPV_ENV_OPENCL_EMBEDDED_2_2); EXPECT_EQ(SPV_ERROR_INVALID_CAPABILITY, ValidateInstructions(SPV_ENV_OPENCL_EMBEDDED_2_2)); EXPECT_THAT(getDiagnosticString(), HasSubstr("Capability Sampled1D is not allowed by OpenCL 2.2 " "Embedded Profile")); } // Three tests to check enablement of an enum (a decoration) which is not // in core, and is directly enabled by a capability, but not directly enabled // by an extension. See https://github.com/KhronosGroup/SPIRV-Tools/issues/1596 TEST_F(ValidateCapability, DecorationFromExtensionMissingEnabledByCapability) { // Decoration ViewportRelativeNV is enabled by ShaderViewportMaskNV, which in // turn is enabled by SPV_NV_viewport_array2. const std::string spirv = R"( OpCapability Shader OpMemoryModel Logical Simple OpDecorate %void ViewportRelativeNV )" + std::string(kVoidFVoid); CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_0); EXPECT_EQ(SPV_ERROR_INVALID_CAPABILITY, ValidateInstructions(SPV_ENV_UNIVERSAL_1_0)); EXPECT_THAT(getDiagnosticString(), HasSubstr("Operand 2 of Decorate requires one of these " "capabilities: ShaderViewportMaskNV")); } TEST_F(ValidateCapability, CapabilityEnabledByMissingExtension) { // Capability ShaderViewportMaskNV is enabled by SPV_NV_viewport_array2. const std::string spirv = R"( OpCapability Shader OpCapability ShaderViewportMaskNV OpMemoryModel Logical Simple )" + std::string(kVoidFVoid); CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_0); EXPECT_EQ(SPV_ERROR_MISSING_EXTENSION, ValidateInstructions(SPV_ENV_UNIVERSAL_1_0)); EXPECT_THAT(getDiagnosticString(), HasSubstr("operand ShaderViewportMaskNV(5255) requires one of " "these extensions: SPV_NV_viewport_array2")); } TEST_F(ValidateCapability, DecorationEnabledByCapabilityEnabledByPresentExtension) { // Decoration ViewportRelativeNV is enabled by ShaderViewportMaskNV, which in // turn is enabled by SPV_NV_viewport_array2. const std::string spirv = R"( OpCapability Shader OpCapability Linkage OpCapability ShaderViewportMaskNV OpExtension "SPV_NV_viewport_array2" OpMemoryModel Logical Simple OpDecorate %void ViewportRelativeNV %void = OpTypeVoid )"; CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_0); EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_0)) << getDiagnosticString(); } // Three tests to check enablement of an instruction which is not in core, and // is directly enabled by a capability, but not directly enabled by an // extension. See https://github.com/KhronosGroup/SPIRV-Tools/issues/1624 // Instruction OpSubgroupShuffleINTEL is enabled by SubgroupShuffleINTEL, which // in turn is enabled by SPV_INTEL_subgroups. TEST_F(ValidateCapability, InstructionFromExtensionMissingEnabledByCapability) { // Decoration ViewportRelativeNV is enabled by ShaderViewportMaskNV, which in // turn is enabled by SPV_NV_viewport_array2. const std::string spirv = R"( OpCapability Kernel OpCapability Addresses ; OpCapability SubgroupShuffleINTEL OpExtension "SPV_INTEL_subgroups" OpMemoryModel Physical32 OpenCL OpEntryPoint Kernel %main "main" %void = OpTypeVoid %uint = OpTypeInt 32 0 %voidfn = OpTypeFunction %void %zero = OpConstant %uint 0 %main = OpFunction %void None %voidfn %entry = OpLabel %foo = OpSubgroupShuffleINTEL %uint %zero %zero OpReturn OpFunctionEnd )"; CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_0); EXPECT_EQ(SPV_ERROR_INVALID_CAPABILITY, ValidateInstructions(SPV_ENV_UNIVERSAL_1_0)); EXPECT_THAT(getDiagnosticString(), HasSubstr("Opcode SubgroupShuffleINTEL requires one of these " "capabilities: SubgroupShuffleINTEL")); } TEST_F(ValidateCapability, InstructionEnablingCapabilityEnabledByMissingExtension) { const std::string spirv = R"( OpCapability Kernel OpCapability Addresses OpCapability SubgroupShuffleINTEL ; OpExtension "SPV_INTEL_subgroups" OpMemoryModel Physical32 OpenCL OpEntryPoint Kernel %main "main" %void = OpTypeVoid %uint = OpTypeInt 32 0 %voidfn = OpTypeFunction %void %zero = OpConstant %uint 0 %main = OpFunction %void None %voidfn %entry = OpLabel %foo = OpSubgroupShuffleINTEL %uint %zero %zero OpReturn OpFunctionEnd )"; CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_0); EXPECT_EQ(SPV_ERROR_MISSING_EXTENSION, ValidateInstructions(SPV_ENV_UNIVERSAL_1_0)); EXPECT_THAT(getDiagnosticString(), HasSubstr("operand SubgroupShuffleINTEL(5568) requires one of " "these extensions: SPV_INTEL_subgroups")); } TEST_F(ValidateCapability, InstructionEnabledByCapabilityEnabledByPresentExtension) { const std::string spirv = R"( OpCapability Kernel OpCapability Addresses OpCapability SubgroupShuffleINTEL OpExtension "SPV_INTEL_subgroups" OpMemoryModel Physical32 OpenCL OpEntryPoint Kernel %main "main" %void = OpTypeVoid %uint = OpTypeInt 32 0 %voidfn = OpTypeFunction %void %zero = OpConstant %uint 0 %main = OpFunction %void None %voidfn %entry = OpLabel %foo = OpSubgroupShuffleINTEL %uint %zero %zero OpReturn OpFunctionEnd )"; CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_0); EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_0)) << getDiagnosticString(); } TEST_F(ValidateCapability, VulkanMemoryModelWithVulkanKHR) { const std::string spirv = R"( OpCapability Shader OpCapability VulkanMemoryModelKHR OpCapability Linkage OpExtension "SPV_KHR_vulkan_memory_model" OpMemoryModel Logical VulkanKHR )"; CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3); EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)) << getDiagnosticString(); } TEST_F(ValidateCapability, VulkanMemoryModelWithGLSL450) { const std::string spirv = R"( OpCapability Shader OpCapability VulkanMemoryModelKHR OpCapability Linkage OpExtension "SPV_KHR_vulkan_memory_model" OpMemoryModel Logical GLSL450 )"; CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3); EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); EXPECT_THAT(getDiagnosticString(), HasSubstr("VulkanMemoryModelKHR capability must only be " "specified if the VulkanKHR memory model is used")); } // In the grammar, SubgroupEqMask and SubgroupMaskKHR have different enabling // lists of extensions. TEST_F(ValidateCapability, SubgroupEqMaskEnabledByExtension) { const std::string spirv = R"( OpCapability Shader OpCapability SubgroupBallotKHR OpExtension "SPV_KHR_shader_ballot" OpMemoryModel Logical Simple OpEntryPoint GLCompute %main "main" OpDecorate %var BuiltIn SubgroupEqMask %void = OpTypeVoid %uint = OpTypeInt 32 0 %ptr_uint = OpTypePointer Private %uint %var = OpVariable %ptr_uint Private %fn = OpTypeFunction %void %main = OpFunction %void None %fn %entry = OpLabel %val = OpLoad %uint %var OpReturn OpFunctionEnd )"; CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_0); EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_0)) << getDiagnosticString(); } // Test that extensions incorporated into SPIR-V 1.5 no longer require // the associated OpExtension instruction. Test one capability per extension. struct CapabilityExtensionVersionCase { std::string capability; std::string capability_new_name; std::string extension; spv_target_env last_version_requiring_extension; spv_target_env first_version_in_core; }; using ValidateCapabilityExtensionVersionTest = spvtest::ValidateBase; // Returns a minimal shader module with the given capability instruction. std::string MinimalShaderModuleWithCapability(std::string cap) { std::string mem_model = (cap.find("VulkanMemory") == 0) ? "VulkanKHR" : "GLSL450"; std::string extra_cap = (cap.find("VulkanMemoryModelDeviceScope") == 0) ? "\nOpCapability VulkanMemoryModelKHR\n" : ""; return std::string("OpCapability ") + cap + extra_cap + R"( OpCapability Shader OpMemoryModel Logical )" + mem_model + R"( OpEntryPoint Vertex %main "main" %void = OpTypeVoid %void_fn = OpTypeFunction %void %main = OpFunction %void None %void_fn %entry = OpLabel OpReturn OpFunctionEnd )"; } TEST_P(ValidateCapabilityExtensionVersionTest, FailsInOlderSpirvVersion) { const auto spirv = MinimalShaderModuleWithCapability(GetParam().capability); CompileSuccessfully(spirv, GetParam().last_version_requiring_extension); EXPECT_EQ(SPV_ERROR_MISSING_EXTENSION, ValidateInstructions(GetParam().last_version_requiring_extension)); EXPECT_THAT(getDiagnosticString(), HasSubstr(std::string("1st operand of Capability: operand ") + GetParam().capability_new_name)) << spirv << "\n"; EXPECT_THAT(getDiagnosticString(), HasSubstr(std::string("requires one of these extensions: ") + GetParam().extension)); } TEST_P(ValidateCapabilityExtensionVersionTest, SucceedsInNewerSpirvVersionWithOldName) { const auto spirv = MinimalShaderModuleWithCapability(GetParam().capability); CompileSuccessfully(spirv, GetParam().first_version_in_core); EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(GetParam().first_version_in_core)); EXPECT_THAT(getDiagnosticString(), Eq("")) << spirv << "\n"; } TEST_P(ValidateCapabilityExtensionVersionTest, SucceedsInNewerSpirvVersionWithNewName) { const auto spirv = MinimalShaderModuleWithCapability(GetParam().capability_new_name); CompileSuccessfully(spirv, GetParam().first_version_in_core); EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(GetParam().first_version_in_core)); EXPECT_THAT(getDiagnosticString(), Eq("")) << spirv << "\n"; } std::vector CapVersionCases1_5() { #define IN15NOSUFFIX(C, E) \ { C, C, E, SPV_ENV_UNIVERSAL_1_4, SPV_ENV_UNIVERSAL_1_5 } #define IN15(C, C_WITHOUT_SUFFIX, E) \ { C, C_WITHOUT_SUFFIX, E, SPV_ENV_UNIVERSAL_1_4, SPV_ENV_UNIVERSAL_1_5 } return std::vector{ // SPV_KHR_8bit_storage IN15NOSUFFIX("StorageBuffer8BitAccess", "SPV_KHR_8bit_storage"), IN15NOSUFFIX("UniformAndStorageBuffer8BitAccess", "SPV_KHR_8bit_storage"), IN15NOSUFFIX("StoragePushConstant8", "SPV_KHR_8bit_storage"), // SPV_EXT_descriptor_indexing IN15("ShaderNonUniformEXT", "ShaderNonUniform", "SPV_EXT_descriptor_indexing"), IN15("RuntimeDescriptorArrayEXT", "RuntimeDescriptorArray", "SPV_EXT_descriptor_indexing"), IN15("InputAttachmentArrayDynamicIndexingEXT", "InputAttachmentArrayDynamicIndexing", "SPV_EXT_descriptor_indexing"), IN15("UniformTexelBufferArrayDynamicIndexingEXT", "UniformTexelBufferArrayDynamicIndexing", "SPV_EXT_descriptor_indexing"), IN15("StorageTexelBufferArrayDynamicIndexingEXT", "StorageTexelBufferArrayDynamicIndexing", "SPV_EXT_descriptor_indexing"), IN15("UniformBufferArrayNonUniformIndexingEXT", "UniformBufferArrayNonUniformIndexing", "SPV_EXT_descriptor_indexing"), IN15("SampledImageArrayNonUniformIndexingEXT", "SampledImageArrayNonUniformIndexing", "SPV_EXT_descriptor_indexing"), IN15("StorageBufferArrayNonUniformIndexingEXT", "StorageBufferArrayNonUniformIndexing", "SPV_EXT_descriptor_indexing"), IN15("StorageImageArrayNonUniformIndexingEXT", "StorageImageArrayNonUniformIndexing", "SPV_EXT_descriptor_indexing"), IN15("InputAttachmentArrayNonUniformIndexingEXT", "InputAttachmentArrayNonUniformIndexing", "SPV_EXT_descriptor_indexing"), IN15("UniformTexelBufferArrayNonUniformIndexingEXT", "UniformTexelBufferArrayNonUniformIndexing", "SPV_EXT_descriptor_indexing"), IN15("StorageTexelBufferArrayNonUniformIndexingEXT", "StorageTexelBufferArrayNonUniformIndexing", "SPV_EXT_descriptor_indexing"), // SPV_EXT_physical_storage_buffer IN15("PhysicalStorageBufferAddresses", "PhysicalStorageBufferAddresses", "SPV_EXT_physical_storage_buffer"), // SPV_KHR_vulkan_memory_model IN15("VulkanMemoryModelKHR", "VulkanMemoryModel", "SPV_KHR_vulkan_memory_model"), IN15("VulkanMemoryModelDeviceScopeKHR", "VulkanMemoryModelDeviceScope", "SPV_KHR_vulkan_memory_model"), }; #undef IN15 } INSTANTIATE_TEST_SUITE_P(NewInSpirv1_5, ValidateCapabilityExtensionVersionTest, ValuesIn(CapVersionCases1_5())); TEST_P(ValidateCapability, CapShaderViewportIndexLayerFailsInOlderSpirvVersion) { const auto spirv = MinimalShaderModuleWithCapability("ShaderViewportIndexLayerEXT"); CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4); EXPECT_EQ(SPV_ERROR_MISSING_EXTENSION, ValidateInstructions(SPV_ENV_UNIVERSAL_1_4)); EXPECT_THAT( getDiagnosticString(), HasSubstr( "1st operand of Capability: operand ShaderViewportIndexLayerEXT")); EXPECT_THAT(getDiagnosticString(), HasSubstr("requires one of these extensions: " "SPV_EXT_shader_viewport_index_layer")); } TEST_P(ValidateCapability, CapShaderViewportIndexLayerFailsInNewSpirvVersion) { const auto spirv = MinimalShaderModuleWithCapability("ShaderViewportIndexLayerEXT"); CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_5); EXPECT_EQ(SPV_ERROR_MISSING_EXTENSION, ValidateInstructions(SPV_ENV_UNIVERSAL_1_5)); EXPECT_THAT( getDiagnosticString(), HasSubstr( "1st operand of Capability: operand ShaderViewportIndexLayerEXT")); EXPECT_THAT(getDiagnosticString(), HasSubstr("requires one of these extensions: " "SPV_EXT_shader_viewport_index_layer")); } TEST_F(ValidateCapability, CapShaderViewportIndexSucceedsInNewSpirvVersion) { const auto spirv = MinimalShaderModuleWithCapability("ShaderViewportIndex"); CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_5); EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_5)); EXPECT_THAT(getDiagnosticString(), Eq("")); } TEST_F(ValidateCapability, CapShaderLayerSucceedsInNewSpirvVersion) { const auto spirv = MinimalShaderModuleWithCapability("ShaderLayer"); CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_5); EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_5)); EXPECT_THAT(getDiagnosticString(), Eq("")); } } // namespace } // namespace val } // namespace spvtools