// Performs validation on instructions that appear inside of a SPIR-V block.
#include <cassert>
+#include <sstream>
+#include <string>
+
+#include "diagnostic.h"
+#include "opcode.h"
+#include "spirv_definition.h"
#include "validate_passes.h"
+using libspirv::AssemblyGrammar;
+using libspirv::DiagnosticStream;
using libspirv::ValidationState_t;
namespace {
-#define STORAGE_CLASS_CASE(CLASS, CAPABILITY) \
- case SpvStorageClass##CLASS: \
- if (_.hasCapability(SpvCapability##CAPABILITY) == false) { \
- return _.diag(SPV_ERROR_INVALID_CAPABILITY) \
- << #CLASS " storage class requires " #CAPABILITY " capability"; \
- } \
- break
-
-spv_result_t StorageClassCapabilityCheck(ValidationState_t& _,
- SpvStorageClass storage_class) {
- switch (storage_class) {
- STORAGE_CLASS_CASE(Input, Shader);
- STORAGE_CLASS_CASE(Uniform, Shader);
- STORAGE_CLASS_CASE(Output, Shader);
- STORAGE_CLASS_CASE(Private, Shader);
- STORAGE_CLASS_CASE(Generic, Kernel);
- STORAGE_CLASS_CASE(PushConstant, Shader);
- STORAGE_CLASS_CASE(AtomicCounter, AtomicStorage);
- default:
- // No capabilities are required for UniformConstant, WorkgroupLocal,
- // WorkgroupGlobal, Function, and Image
- break;
- }
- return SPV_SUCCESS;
-}
-#undef VARIABLE_STORAGE_CASE
-
-#define DECORATION_CASE(DECORATION, CAPABILITY) \
- case SpvDecoration##DECORATION: \
- if (_.hasCapability(SpvCapability##CAPABILITY) == false) { \
- return _.diag(SPV_ERROR_INVALID_CAPABILITY) \
- << #DECORATION " decoration requires " #CAPABILITY " capability"; \
- } \
- break
-
-#define BUILTIN_CASE(BUILTIN, CAPABILITY) \
- case SpvBuiltIn##BUILTIN: \
- if (_.hasCapability(SpvCapability##CAPABILITY) == false) { \
- return _.diag(SPV_ERROR_INVALID_CAPABILITY) \
- << #BUILTIN " builtin requires " #CAPABILITY " capability"; \
- } \
- break
-
-#define BUILTIN_CASE2(BUILTIN, CAPABILITY1, CAPABILITY2) \
- case SpvBuiltIn##BUILTIN: \
- if (_.hasCapability(SpvCapability##CAPABILITY1) == false && \
- _.hasCapability(SpvCapability##CAPABILITY2) == false) { \
- return _.diag(SPV_ERROR_INVALID_CAPABILITY) \
- << #BUILTIN " builtin requires " #CAPABILITY1 " or " #CAPABILITY2 \
- " capabilities"; \
- } \
- break
-
-spv_result_t DecorationCapabilityCheck(ValidationState_t& _,
- SpvDecoration decoration,
- SpvBuiltIn optional_builtin) {
- switch (decoration) {
- DECORATION_CASE(RelaxedPrecision, Shader);
- DECORATION_CASE(SpecId, Shader);
- DECORATION_CASE(Block, Shader);
- DECORATION_CASE(BufferBlock, Shader);
- DECORATION_CASE(RowMajor, Matrix);
- DECORATION_CASE(ColMajor, Matrix);
- DECORATION_CASE(ArrayStride, Shader);
- DECORATION_CASE(MatrixStride, Shader);
- DECORATION_CASE(GLSLShared, Shader);
- DECORATION_CASE(GLSLPacked, Shader);
- DECORATION_CASE(CPacked, Kernel);
- DECORATION_CASE(NoPerspective, Shader);
- DECORATION_CASE(Flat, Shader);
- DECORATION_CASE(Patch, Tessellation);
- DECORATION_CASE(Centroid, Shader);
- DECORATION_CASE(Sample, Shader);
- DECORATION_CASE(Invariant, Shader);
- DECORATION_CASE(Constant, Kernel);
- DECORATION_CASE(Uniform, Shader);
- DECORATION_CASE(SaturatedConversion, Kernel);
- DECORATION_CASE(Stream, GeometryStreams);
- DECORATION_CASE(Location, Shader);
- DECORATION_CASE(Component, Shader);
- DECORATION_CASE(Index, Shader);
- DECORATION_CASE(Binding, Shader);
- DECORATION_CASE(DescriptorSet, Shader);
- DECORATION_CASE(XfbBuffer, TransformFeedback);
- DECORATION_CASE(XfbStride, TransformFeedback);
- DECORATION_CASE(FuncParamAttr, Kernel);
- DECORATION_CASE(FPRoundingMode, Kernel);
- DECORATION_CASE(FPFastMathMode, Kernel);
- DECORATION_CASE(LinkageAttributes, Linkage);
- DECORATION_CASE(NoContraction, Shader);
- DECORATION_CASE(Alignment, Kernel);
- DECORATION_CASE(InputAttachmentIndex, InputAttachment);
- case SpvDecorationBuiltIn:
- switch (optional_builtin) {
- BUILTIN_CASE(Position, Shader);
- BUILTIN_CASE(PointSize, Shader);
- BUILTIN_CASE(ClipDistance, ClipDistance);
- BUILTIN_CASE(CullDistance, CullDistance);
- BUILTIN_CASE(VertexId, Shader);
- BUILTIN_CASE(InstanceId, Shader);
- BUILTIN_CASE2(PrimitiveId, Geometry, Tessellation);
- BUILTIN_CASE2(InvocationId, Geometry, Tessellation);
- BUILTIN_CASE(Layer, Geometry);
- case SpvBuiltInViewportIndex:
- assert(
- false &&
- "UNHANDLED"); // TODO(umar): missing SpvCapabilityMultiViewport
- // BUILTIN_CASE(ViewportIndex, MultiViewport);
- BUILTIN_CASE(TessLevelOuter, Tessellation);
- BUILTIN_CASE(TessLevelInner, Tessellation);
- BUILTIN_CASE(TessCoord, Tessellation);
- BUILTIN_CASE(PatchVertices, Tessellation);
- BUILTIN_CASE(FragCoord, Shader);
- BUILTIN_CASE(PointCoord, Shader);
- BUILTIN_CASE(FrontFacing, Shader);
- BUILTIN_CASE(SampleId, SampleRateShading);
- BUILTIN_CASE(SamplePosition, SampleRateShading);
- BUILTIN_CASE(SampleMask, SampleRateShading);
- BUILTIN_CASE(FragDepth, Shader);
- BUILTIN_CASE(HelperInvocation, Shader);
- BUILTIN_CASE(WorkDim, Kernel);
- BUILTIN_CASE(GlobalSize, Kernel);
- BUILTIN_CASE(EnqueuedWorkgroupSize, Kernel);
- BUILTIN_CASE(GlobalOffset, Kernel);
- BUILTIN_CASE(GlobalLinearId, Kernel);
- BUILTIN_CASE(SubgroupSize, Kernel);
- BUILTIN_CASE(SubgroupMaxSize, Kernel);
- BUILTIN_CASE(NumSubgroups, Kernel);
- BUILTIN_CASE(NumEnqueuedSubgroups, Kernel);
- BUILTIN_CASE(SubgroupId, Kernel);
- BUILTIN_CASE(SubgroupLocalInvocationId, Kernel);
- BUILTIN_CASE(VertexIndex, Shader);
- BUILTIN_CASE(InstanceIndex, Shader);
- case SpvBuiltInNumWorkgroups:
- case SpvBuiltInWorkgroupSize:
- case SpvBuiltInWorkgroupId:
- case SpvBuiltInLocalInvocationId:
- case SpvBuiltInGlobalInvocationId:
- case SpvBuiltInLocalInvocationIndex:
- break;
- }
- default:
- // No capabilities are required for Restrict, Aliased, BuiltIn, Volatile,
- // Coherent, NonWritable, NonReadable, and Offset
- break;
- }
-#undef DECORATION_CASE
-#undef BUILTIN_CASE
-#undef BUILTIN_CASE2
-
- return SPV_SUCCESS;
-}
-
-#define EXECUTION_MODEL_CASE(MODEL, CAPABILITY) \
- case SpvExecutionModel##MODEL: \
- if (_.hasCapability(SpvCapability##CAPABILITY) == false) { \
- return _.diag(SPV_ERROR_INVALID_CAPABILITY) \
- << #MODEL " execution model requires " #CAPABILITY " capability"; \
- } \
- break
-
-spv_result_t ExecutionModelCapabilityCheck(ValidationState_t& _,
- SpvExecutionModel execution_model) {
- switch (execution_model) {
- EXECUTION_MODEL_CASE(Vertex, Shader);
- EXECUTION_MODEL_CASE(TessellationControl, Tessellation);
- EXECUTION_MODEL_CASE(TessellationEvaluation, Tessellation);
- EXECUTION_MODEL_CASE(Geometry, Geometry);
- EXECUTION_MODEL_CASE(Fragment, Shader);
- EXECUTION_MODEL_CASE(GLCompute, Shader);
- EXECUTION_MODEL_CASE(Kernel, Kernel);
- }
-#undef EXECUTION_MODEL_CASE
- return SPV_SUCCESS;
+std::string ToString(spv_capability_mask_t mask,
+ const AssemblyGrammar& grammar) {
+ std::stringstream ss;
+ libspirv::ForEach(mask, [&grammar, &ss](SpvCapability cap) {
+ spv_operand_desc desc;
+ if (SPV_SUCCESS ==
+ grammar.lookupOperand(SPV_OPERAND_TYPE_CAPABILITY, cap, &desc))
+ ss << desc->name << " ";
+ else
+ ss << cap << " ";
+ });
+ return ss.str();
}
-spv_result_t AddressingAndMemoryModelCapabilityCheck(
- ValidationState_t& _, SpvAddressingModel addressing_model,
- SpvMemoryModel memory_model) {
- switch (addressing_model) {
- case SpvAddressingModelPhysical32:
- case SpvAddressingModelPhysical64:
- if (_.hasCapability(SpvCapabilityAddresses) == false) {
- return _.diag(SPV_ERROR_INVALID_CAPABILITY)
- << "Physical32 and Physical64 addressing models require the "
- "Addresses capability";
- }
- break;
- case SpvAddressingModelLogical:
- break;
- }
-
- switch (memory_model) {
- case SpvMemoryModelSimple:
- case SpvMemoryModelGLSL450:
- if (_.hasCapability(SpvCapabilityShader) == false) {
- return _.diag(SPV_ERROR_INVALID_CAPABILITY)
- << "Simple and GLSL450 memory models require the Shader "
- "capability";
- }
- break;
- case SpvMemoryModelOpenCL:
- if (_.hasCapability(SpvCapabilityKernel) == false) {
- return _.diag(SPV_ERROR_INVALID_CAPABILITY)
- << "OpenCL memory model requires the Kernel capability";
- }
- break;
- }
- return SPV_SUCCESS;
+// Reports a missing-capability error to _'s diagnostic stream and returns
+// SPV_ERROR_INVALID_CAPABILITY.
+spv_result_t CapabilityError(ValidationState_t& _, int which_operand,
+ SpvOp opcode,
+ const std::string& required_capabilities) {
+ return _.diag(SPV_ERROR_INVALID_CAPABILITY)
+ << "Operand " << which_operand << " of " << spvOpcodeString(opcode)
+ << " requires one of these capabilities: " << required_capabilities;
}
-#define EXECUTION_MODE_CASE(MODE, CAPABILITY) \
- case SpvExecutionMode##MODE: \
- if (_.hasCapability(SpvCapability##CAPABILITY) == false) { \
- return _.diag(SPV_ERROR_INVALID_CAPABILITY) \
- << #MODE " mode requires " #CAPABILITY " capability"; \
- } \
- break
-#define EXECUTION_MODE_CASE2(MODE, CAPABILITY1, CAPABILITY2) \
- case SpvExecutionMode##MODE: \
- if (_.hasCapability(SpvCapability##CAPABILITY1) == false && \
- _.hasCapability(SpvCapability##CAPABILITY2) == false) { \
- return _.diag(SPV_ERROR_INVALID_CAPABILITY) << #MODE \
- " mode requires " #CAPABILITY1 " or " #CAPABILITY2 " capability"; \
- } \
- break
-spv_result_t ExecutionModeCapabilityCheck(ValidationState_t& _,
- SpvExecutionMode execution_mode) {
- switch (execution_mode) {
- EXECUTION_MODE_CASE(Invocations, Geometry);
- EXECUTION_MODE_CASE(SpacingEqual, Tessellation);
- EXECUTION_MODE_CASE(SpacingFractionalEven, Tessellation);
- EXECUTION_MODE_CASE(SpacingFractionalOdd, Tessellation);
- EXECUTION_MODE_CASE(VertexOrderCw, Tessellation);
- EXECUTION_MODE_CASE(VertexOrderCcw, Tessellation);
- EXECUTION_MODE_CASE(PixelCenterInteger, Shader);
- EXECUTION_MODE_CASE(OriginUpperLeft, Shader);
- EXECUTION_MODE_CASE(OriginLowerLeft, Shader);
- EXECUTION_MODE_CASE(EarlyFragmentTests, Shader);
- EXECUTION_MODE_CASE(PointMode, Tessellation);
- EXECUTION_MODE_CASE(Xfb, TransformFeedback);
- EXECUTION_MODE_CASE(DepthReplacing, Shader);
- EXECUTION_MODE_CASE(DepthGreater, Shader);
- EXECUTION_MODE_CASE(DepthLess, Shader);
- EXECUTION_MODE_CASE(DepthUnchanged, Shader);
- EXECUTION_MODE_CASE(LocalSizeHint, Kernel);
- EXECUTION_MODE_CASE(InputPoints, Geometry);
- EXECUTION_MODE_CASE(InputLines, Geometry);
- EXECUTION_MODE_CASE(InputLinesAdjacency, Geometry);
- EXECUTION_MODE_CASE2(Triangles, Geometry, Tessellation);
- EXECUTION_MODE_CASE(InputTrianglesAdjacency, Geometry);
- EXECUTION_MODE_CASE(Quads, Tessellation);
- EXECUTION_MODE_CASE(Isolines, Tessellation);
- EXECUTION_MODE_CASE2(OutputVertices, Geometry, Tessellation);
- EXECUTION_MODE_CASE(OutputPoints, Geometry);
- EXECUTION_MODE_CASE(OutputLineStrip, Geometry);
- EXECUTION_MODE_CASE(OutputTriangleStrip, Geometry);
- EXECUTION_MODE_CASE(VecTypeHint, Kernel);
- EXECUTION_MODE_CASE(ContractionOff, Kernel);
- case SpvExecutionModeLocalSize:
- break;
- }
-#undef EXECUTION_MODE_CASE
-#undef EXECUTION_MODE_CASE2
- return SPV_SUCCESS;
+// Returns an operand's required capabilities.
+spv_capability_mask_t RequiredCapabilities(const AssemblyGrammar& grammar,
+ spv_operand_type_t type,
+ uint32_t operand) {
+ spv_operand_desc operand_desc;
+ if (SPV_SUCCESS == grammar.lookupOperand(type, operand, &operand_desc))
+ return operand_desc->capabilities;
+ else
+ return 0;
}
-#define DIM_CASE(DIM, CAPABILITY) \
- case SpvDim##DIM: \
- if (_.hasCapability(SpvCapability##CAPABILITY) == false) { \
- return _.diag(SPV_ERROR_INVALID_CAPABILITY) \
- << "Dim " #DIM " requires " #CAPABILITY " capability"; \
- } \
- break
+} // namespace anonymous
-spv_result_t DimCapabilityCheck(ValidationState_t& _, SpvDim dim) {
- switch (dim) {
- DIM_CASE(1D, Sampled1D);
- DIM_CASE(Cube, Shader);
- DIM_CASE(Rect, SampledRect);
- DIM_CASE(Buffer, SampledBuffer);
- DIM_CASE(SubpassData, InputAttachment);
- case SpvDim2D:
- case SpvDim3D:
- break;
- }
-#undef DIM_CASE
- return SPV_SUCCESS;
-}
+namespace libspirv {
-spv_result_t SamplerAddressingModeCapabilityCheck(
- ValidationState_t& _, SpvSamplerAddressingMode sampler_addressing_mode) {
- std::string mode;
- switch (sampler_addressing_mode) {
- case SpvSamplerAddressingModeNone:
- mode = "None";
- break;
- case SpvSamplerAddressingModeClampToEdge:
- mode = "ClampToEdge";
- break;
- case SpvSamplerAddressingModeClamp:
- mode = "Clamp";
- break;
- case SpvSamplerAddressingModeRepeat:
- mode = "Repeat";
- break;
- case SpvSamplerAddressingModeRepeatMirrored:
- mode = "RepeatMirrored";
- break;
- }
- if (_.hasCapability(SpvCapabilityKernel) == false) {
+spv_result_t CapCheck(ValidationState_t& _,
+ const spv_parsed_instruction_t* inst) {
+ spv_opcode_desc opcode_desc;
+ if (SPV_SUCCESS == _.grammar().lookupOpcode(inst->opcode, &opcode_desc) &&
+ !_.HasAnyOf(opcode_desc->capabilities))
return _.diag(SPV_ERROR_INVALID_CAPABILITY)
- << mode + " sample address mode requires Kernel capability";
+ << "Opcode " << spvOpcodeString(inst->opcode)
+ << " requires one of these capabilities: "
+ << ToString(opcode_desc->capabilities, _.grammar());
+ for (int i = 0; i < inst->num_operands; ++i) {
+ const auto& operand = inst->operands[i];
+ const auto word = inst->words[operand.offset];
+ auto caps = RequiredCapabilities(_.grammar(), operand.type, word);
+ if (!_.HasAnyOf(caps))
+ return CapabilityError(_, i + 1, inst->opcode,
+ ToString(caps, _.grammar()));
+ if (operand.type == SPV_OPERAND_TYPE_IMAGE)
+ for (auto individual_operand :
+ {SpvImageOperandsBiasMask, SpvImageOperandsLodMask,
+ SpvImageOperandsGradMask, SpvImageOperandsConstOffsetMask,
+ SpvImageOperandsOffsetMask, SpvImageOperandsConstOffsetsMask,
+ SpvImageOperandsSampleMask, SpvImageOperandsMinLodMask})
+ if (word & individual_operand) {
+ caps = RequiredCapabilities(_.grammar(), SPV_OPERAND_TYPE_IMAGE,
+ individual_operand);
+ if (!_.HasAnyOf(caps))
+ return CapabilityError(_, i + 1, inst->opcode,
+ ToString(caps, _.grammar()));
+ }
}
return SPV_SUCCESS;
}
-}
-
-namespace libspirv {
// clang-format off
spv_result_t InstructionPass(ValidationState_t& _,
const spv_parsed_instruction_t* inst) {
if (_.is_enabled(SPV_VALIDATE_INSTRUCTION_BIT)) {
- SpvOp opcode = inst->opcode;
- switch (opcode) {
- case SpvOpNop: break;
- case SpvOpSourceContinued: break;
- case SpvOpSource: break;
- case SpvOpSourceExtension: break;
- case SpvOpName: break;
- case SpvOpMemberName: break;
- case SpvOpString: break;
- case SpvOpLine: break;
- case SpvOpNoLine: break;
- case SpvOpDecorate: {
- SpvDecoration decoration =
- static_cast<SpvDecoration>(inst->words[inst->operands[1].offset]);
- SpvBuiltIn builtin = static_cast<SpvBuiltIn>(0);
- if(decoration == SpvDecorationBuiltIn) {
- builtin = static_cast<SpvBuiltIn>(inst->words[inst->operands[2].offset]);
- }
- spvCheckReturn(DecorationCapabilityCheck(_, decoration, builtin));
- } break;
-
- case SpvOpMemberDecorate: {
- SpvDecoration decoration =
- static_cast<SpvDecoration>(inst->words[inst->operands[2].offset]);
- SpvBuiltIn builtin = static_cast<SpvBuiltIn>(0);
- if(decoration == SpvDecorationBuiltIn) {
- builtin = static_cast<SpvBuiltIn>(inst->words[inst->operands[3].offset]);
- }
- spvCheckReturn(DecorationCapabilityCheck(_, decoration, builtin));
- } break;
-
- case SpvOpDecorationGroup: break;
- case SpvOpGroupDecorate: break;
- case SpvOpGroupMemberDecorate: break;
- case SpvOpExtension: break;
- case SpvOpExtInstImport: break;
- case SpvOpExtInst: break;
- case SpvOpMemoryModel: {
- SpvAddressingModel addressing_model =
- static_cast<SpvAddressingModel>(inst->words[inst->operands[0].offset]);
- SpvMemoryModel memory_model =
- static_cast<SpvMemoryModel>(inst->words[inst->operands[1].offset]);
- spvCheckReturn(AddressingAndMemoryModelCapabilityCheck(_,
- addressing_model, memory_model));
- } break;
-
- case SpvOpEntryPoint: {
- SpvExecutionModel execution_model =
- static_cast<SpvExecutionModel>(inst->words[inst->operands[0].offset]);
- spvCheckReturn(ExecutionModelCapabilityCheck(_, execution_model));
- } break;
-
- case SpvOpExecutionMode: {
- SpvExecutionMode execution_mode =
- static_cast<SpvExecutionMode>(inst->words[inst->operands[1].offset]);
- spvCheckReturn(ExecutionModeCapabilityCheck(_, execution_mode));
- } break;
-
- case SpvOpCapability:
+ if (inst->opcode == SpvOpCapability)
_.registerCapability(
static_cast<SpvCapability>(inst->words[inst->operands[0].offset]));
- break;
-
- case SpvOpTypeVoid: break;
- case SpvOpTypeBool: break;
- case SpvOpTypeInt: break;
- case SpvOpTypeFloat: break;
- case SpvOpTypeVector: break;
- case SpvOpTypeMatrix:
- if (_.hasCapability(SpvCapabilityMatrix) == false) {
- return _.diag(SPV_ERROR_INVALID_CAPABILITY)
- << "Matrix type requires Matrix capability";
- }
- break;
- case SpvOpTypeImage: {
- if (_.hasCapability(SpvCapabilityImageBasic) == false) {
- return _.diag(SPV_ERROR_INVALID_CAPABILITY)
- << "TypeImage requires the ImageBasic capability";
- }
- SpvDim dim =
- static_cast<SpvDim>(inst->words[inst->operands[2].offset]);
- spvCheckReturn(DimCapabilityCheck(_, dim));
-
- } break;
-
- case SpvOpTypeSampler: break;
- case SpvOpTypeSampledImage: break;
- case SpvOpTypeArray: break;
- case SpvOpTypeRuntimeArray: break;
- case SpvOpTypeStruct: break;
- case SpvOpTypeOpaque: break;
- case SpvOpTypePointer: {
- const SpvStorageClass storage_class =
- static_cast<SpvStorageClass>(inst->words[inst->operands[1].offset]);
- spvCheckReturn(StorageClassCapabilityCheck(_, storage_class));
- } break;
-
- case SpvOpTypeFunction: break;
- case SpvOpTypeEvent: break;
- case SpvOpTypeDeviceEvent: break;
- case SpvOpTypeReserveId: break;
- case SpvOpTypeQueue: break;
- case SpvOpTypePipe: break;
- case SpvOpTypeForwardPointer: {
- const SpvStorageClass storage_class =
- static_cast<SpvStorageClass>(inst->words[inst->operands[1].offset]);
- spvCheckReturn(StorageClassCapabilityCheck(_, storage_class));
- } break;
-
- case SpvOpUndef: break;
- case SpvOpConstantTrue: break;
- case SpvOpConstantFalse: break;
- case SpvOpConstant: break;
- case SpvOpConstantComposite: break;
- case SpvOpConstantSampler: {
- if (_.hasCapability(SpvCapabilityLiteralSampler) == false) {
- return _.diag(SPV_ERROR_INVALID_CAPABILITY)
- << "ConstantSampler requires the LiteralSampler capability";
- }
- const SpvSamplerAddressingMode sampler_addressing_mode =
- static_cast<SpvSamplerAddressingMode>(inst->words[inst->operands[1].offset]);
- spvCheckReturn(SamplerAddressingModeCapabilityCheck(_, sampler_addressing_mode));
- } break;
-
- case SpvOpConstantNull: break;
- case SpvOpSpecConstantTrue: break;
- case SpvOpSpecConstantFalse: break;
- case SpvOpSpecConstant: break;
- case SpvOpSpecConstantComposite: break;
- case SpvOpSpecConstantOp: break;
- case SpvOpVariable: {
- const SpvStorageClass storage_class =
+ if (inst->opcode == SpvOpVariable) {
+ const auto storage_class =
static_cast<SpvStorageClass>(inst->words[inst->operands[2].offset]);
if (storage_class == SpvStorageClassGeneric)
return _.diag(SPV_ERROR_INVALID_BINARY)
<< "OpVariable storage class cannot be Generic";
- spvCheckReturn(StorageClassCapabilityCheck(_, storage_class));
-
if (_.getLayoutSection() == kLayoutFunctionDefinitions) {
if (storage_class != SpvStorageClassFunction) {
return _.diag(SPV_ERROR_INVALID_LAYOUT)
"outside of a function";
}
}
- } break;
-
- case SpvOpImageTexelPointer: break;
- case SpvOpLoad: break;
- case SpvOpStore: break;
- case SpvOpCopyMemory: break;
- case SpvOpCopyMemorySized: break;
- case SpvOpAccessChain: break;
- case SpvOpInBoundsAccessChain: break;
- case SpvOpPtrAccessChain: break;
- case SpvOpArrayLength: break;
- case SpvOpGenericPtrMemSemantics: break;
- case SpvOpInBoundsPtrAccessChain: break;
- case SpvOpFunction: break;
- case SpvOpFunctionParameter: break;
- case SpvOpFunctionEnd: break;
- case SpvOpFunctionCall: break;
- case SpvOpSampledImage: break;
- case SpvOpImageSampleImplicitLod: break;
- case SpvOpImageSampleExplicitLod: break;
- case SpvOpImageSampleDrefImplicitLod: break;
- case SpvOpImageSampleDrefExplicitLod: break;
- case SpvOpImageSampleProjImplicitLod: break;
- case SpvOpImageSampleProjExplicitLod: break;
- case SpvOpImageSampleProjDrefImplicitLod: break;
- case SpvOpImageSampleProjDrefExplicitLod: break;
- case SpvOpImageFetch: break;
- case SpvOpImageGather: break;
- case SpvOpImageDrefGather: break;
- case SpvOpImageRead: break;
- case SpvOpImageWrite: break;
- case SpvOpImage: break;
- case SpvOpImageQueryFormat: break;
- case SpvOpImageQueryOrder: break;
- case SpvOpImageQuerySizeLod: break;
- case SpvOpImageQuerySize: break;
- case SpvOpImageQueryLod: break;
- case SpvOpImageQueryLevels: break;
- case SpvOpImageQuerySamples: break;
- case SpvOpImageSparseSampleImplicitLod: break;
- case SpvOpImageSparseSampleExplicitLod: break;
- case SpvOpImageSparseSampleDrefImplicitLod: break;
- case SpvOpImageSparseSampleDrefExplicitLod: break;
- case SpvOpImageSparseSampleProjImplicitLod: break;
- case SpvOpImageSparseSampleProjExplicitLod: break;
- case SpvOpImageSparseSampleProjDrefImplicitLod: break;
- case SpvOpImageSparseSampleProjDrefExplicitLod: break;
- case SpvOpImageSparseFetch: break;
- case SpvOpImageSparseGather: break;
- case SpvOpImageSparseDrefGather: break;
- case SpvOpImageSparseTexelsResident: break;
- case SpvOpConvertFToU: break;
- case SpvOpConvertFToS: break;
- case SpvOpConvertSToF: break;
- case SpvOpConvertUToF: break;
- case SpvOpUConvert: break;
- case SpvOpSConvert: break;
- case SpvOpFConvert: break;
- case SpvOpQuantizeToF16: break;
- case SpvOpConvertPtrToU: break;
- case SpvOpSatConvertSToU: break;
- case SpvOpSatConvertUToS: break;
- case SpvOpConvertUToPtr: break;
- case SpvOpPtrCastToGeneric: break;
- case SpvOpGenericCastToPtr: break;
- case SpvOpGenericCastToPtrExplicit: {
- const SpvStorageClass storage_class =
- static_cast<SpvStorageClass>(inst->words[inst->operands[3].offset]);
- spvCheckReturn(StorageClassCapabilityCheck(_, storage_class));
- } break;
-
- case SpvOpBitcast: break;
- case SpvOpVectorExtractDynamic: break;
- case SpvOpVectorInsertDynamic: break;
- case SpvOpVectorShuffle: break;
- case SpvOpCompositeConstruct: break;
- case SpvOpCompositeExtract: break;
- case SpvOpCompositeInsert: break;
- case SpvOpCopyObject: break;
- case SpvOpTranspose: break;
- case SpvOpSNegate: break;
- case SpvOpFNegate: break;
- case SpvOpIAdd: break;
- case SpvOpFAdd: break;
- case SpvOpISub: break;
- case SpvOpFSub: break;
- case SpvOpIMul: break;
- case SpvOpFMul: break;
- case SpvOpUDiv: break;
- case SpvOpSDiv: break;
- case SpvOpFDiv: break;
- case SpvOpUMod: break;
- case SpvOpSRem: break;
- case SpvOpSMod: break;
- case SpvOpFRem: break;
- case SpvOpFMod: break;
- case SpvOpVectorTimesScalar: break;
- case SpvOpMatrixTimesScalar: break;
- case SpvOpVectorTimesMatrix: break;
- case SpvOpMatrixTimesVector: break;
- case SpvOpMatrixTimesMatrix: break;
- case SpvOpOuterProduct: break;
- case SpvOpDot: break;
- case SpvOpIAddCarry: break;
- case SpvOpISubBorrow: break;
- case SpvOpUMulExtended: break;
- case SpvOpSMulExtended: break; break;
- case SpvOpShiftRightLogical: break;
- case SpvOpShiftRightArithmetic: break;
- case SpvOpShiftLeftLogical: break;
- case SpvOpBitwiseOr: break;
- case SpvOpBitwiseXor: break;
- case SpvOpBitwiseAnd: break;
- case SpvOpNot: break;
- case SpvOpBitFieldInsert: break;
- case SpvOpBitFieldSExtract: break;
- case SpvOpBitFieldUExtract: break;
- case SpvOpBitReverse: break;
- case SpvOpBitCount: break;
- case SpvOpAny: break;
- case SpvOpAll: break;
- case SpvOpIsNan: break;
- case SpvOpIsInf: break;
- case SpvOpIsFinite: break;
- case SpvOpIsNormal: break;
- case SpvOpSignBitSet: break;
- case SpvOpLessOrGreater: break;
- case SpvOpOrdered: break;
- case SpvOpUnordered: break;
- case SpvOpLogicalEqual: break;
- case SpvOpLogicalNotEqual: break;
- case SpvOpLogicalOr: break;
- case SpvOpLogicalAnd: break;
- case SpvOpLogicalNot: break;
- case SpvOpSelect: break;
- case SpvOpIEqual: break;
- case SpvOpINotEqual: break;
- case SpvOpUGreaterThan: break;
- case SpvOpSGreaterThan: break;
- case SpvOpUGreaterThanEqual: break;
- case SpvOpSGreaterThanEqual: break;
- case SpvOpULessThan: break;
- case SpvOpSLessThan: break;
- case SpvOpULessThanEqual: break;
- case SpvOpSLessThanEqual: break;
- case SpvOpFOrdEqual: break;
- case SpvOpFUnordEqual: break;
- case SpvOpFOrdNotEqual: break;
- case SpvOpFUnordNotEqual: break;
- case SpvOpFOrdLessThan: break;
- case SpvOpFUnordLessThan: break;
- case SpvOpFOrdGreaterThan: break;
- case SpvOpFUnordGreaterThan: break;
- case SpvOpFOrdLessThanEqual: break;
- case SpvOpFUnordLessThanEqual: break;
- case SpvOpFOrdGreaterThanEqual: break;
- case SpvOpFUnordGreaterThanEqual: break;
- case SpvOpDPdx: break;
- case SpvOpDPdy: break;
- case SpvOpFwidth: break;
- case SpvOpDPdxFine: break;
- case SpvOpDPdyFine: break;
- case SpvOpFwidthFine: break;
- case SpvOpDPdxCoarse: break;
- case SpvOpDPdyCoarse: break;
- case SpvOpFwidthCoarse: break;
- case SpvOpPhi: break;
- case SpvOpLoopMerge: break;
- case SpvOpSelectionMerge: break;
- case SpvOpLabel: break;
- case SpvOpBranch: break;
- case SpvOpBranchConditional: break;
- case SpvOpSwitch: break;
- case SpvOpKill: break;
- case SpvOpReturn: break;
- case SpvOpReturnValue: break;
- case SpvOpUnreachable: break;
- case SpvOpLifetimeStart: break;
- case SpvOpLifetimeStop: break;
- case SpvOpAtomicLoad: break;
- case SpvOpAtomicStore: break;
- case SpvOpAtomicExchange: break;
- case SpvOpAtomicCompareExchange: break;
- case SpvOpAtomicCompareExchangeWeak: break;
- case SpvOpAtomicIIncrement: break;
- case SpvOpAtomicIDecrement: break;
- case SpvOpAtomicIAdd: break;
- case SpvOpAtomicISub: break;
- case SpvOpAtomicSMin: break;
- case SpvOpAtomicUMin: break;
- case SpvOpAtomicSMax: break;
- case SpvOpAtomicUMax: break;
- case SpvOpAtomicAnd: break;
- case SpvOpAtomicOr: break;
- case SpvOpAtomicXor: break;
- case SpvOpAtomicFlagTestAndSet: break;
- case SpvOpAtomicFlagClear: break;
- case SpvOpEmitVertex: break;
- case SpvOpEndPrimitive: break;
- case SpvOpEmitStreamVertex: break;
- case SpvOpEndStreamPrimitive: break;
- case SpvOpControlBarrier: break;
- case SpvOpMemoryBarrier: break;
- case SpvOpGroupAsyncCopy: break;
- case SpvOpGroupWaitEvents: break;
- case SpvOpGroupAll: break;
- case SpvOpGroupAny: break;
- case SpvOpGroupBroadcast: break;
- case SpvOpGroupIAdd: break;
- case SpvOpGroupFAdd: break;
- case SpvOpGroupFMin: break;
- case SpvOpGroupUMin: break;
- case SpvOpGroupSMin: break;
- case SpvOpGroupFMax: break;
- case SpvOpGroupUMax: break;
- case SpvOpGroupSMax: break;
- case SpvOpEnqueueMarker: break;
- case SpvOpEnqueueKernel: break;
- case SpvOpGetKernelNDrangeSubGroupCount: break;
- case SpvOpGetKernelNDrangeMaxSubGroupSize: break;
- case SpvOpGetKernelWorkGroupSize: break;
- case SpvOpGetKernelPreferredWorkGroupSizeMultiple: break;
- case SpvOpRetainEvent: break;
- case SpvOpReleaseEvent: break;
- case SpvOpCreateUserEvent: break;
- case SpvOpIsValidEvent: break;
- case SpvOpSetUserEventStatus: break;
- case SpvOpCaptureEventProfilingInfo: break;
- case SpvOpGetDefaultQueue: break;
- case SpvOpBuildNDRange: break;
- case SpvOpReadPipe: break;
- case SpvOpWritePipe: break;
- case SpvOpReservedReadPipe: break;
- case SpvOpReservedWritePipe: break;
- case SpvOpReserveReadPipePackets: break;
- case SpvOpReserveWritePipePackets: break;
- case SpvOpCommitReadPipe: break;
- case SpvOpCommitWritePipe: break;
- case SpvOpIsValidReserveId: break;
- case SpvOpGetNumPipePackets: break;
- case SpvOpGetMaxPipePackets: break;
- case SpvOpGroupReserveReadPipePackets: break;
- case SpvOpGroupReserveWritePipePackets: break;
- case SpvOpGroupCommitReadPipe: break;
- case SpvOpGroupCommitWritePipe: break;
}
+ return CapCheck(_, inst);
}
return SPV_SUCCESS;
}
// clang-format on
-}
+} // namespace libspirv
#include "UnitSPIRV.h"
#include "ValidateFixtures.h"
-#include <functional>
#include <sstream>
#include <string>
+#include <tuple>
#include <utility>
-using std::function;
-using std::ostream;
-using std::ostream_iterator;
+namespace {
+
using std::pair;
using std::make_pair;
using std::stringstream;
using std::string;
-using std::tie;
using std::tuple;
using std::vector;
-using ::testing::HasSubstr;
+using testing::Combine;
+using testing::Values;
+using testing::ValuesIn;
using ValidateCapability =
spvtest::ValidateBase<tuple<string, pair<string, vector<string>>>,
"SampledRect",
"ImageRect"};
return *r;
-};
+}
const vector<string>& SampledBufferDependencies() {
static const auto r = new vector<string>{
"SampledBuffer",
"ImageBuffer"};
return *r;
-};
+}
-INSTANTIATE_TEST_CASE_P(ExecutionModel,
- ValidateCapability,
- ::testing::Combine(
- testing::ValuesIn(AllCapabilities()),
- testing::Values(
+INSTANTIATE_TEST_CASE_P(ExecutionModel, ValidateCapability,
+ Combine(
+ ValuesIn(AllCapabilities()),
+ Values(
make_pair("OpEntryPoint Vertex %func \"shader\" %var1 %var2\n", ShaderDependencies()),
make_pair("OpEntryPoint TessellationControl %func \"shader\" %var1 %var2\n", TessellationDependencies()),
make_pair("OpEntryPoint TessellationEvaluation %func \"shader\" %var1 %var2\n", TessellationDependencies()),
make_pair("OpEntryPoint Kernel %func \"shader\" %var1 %var2\n", KernelDependencies())
)));
-INSTANTIATE_TEST_CASE_P(AddressingAndMemoryModel,
- ValidateCapability,
- ::testing::Combine(
- testing::ValuesIn(AllCapabilities()),
- testing::Values(
+INSTANTIATE_TEST_CASE_P(AddressingAndMemoryModel, ValidateCapability,
+ Combine(
+ ValuesIn(AllCapabilities()),
+ Values(
make_pair(" OpCapability Shader"
" OpMemoryModel Logical Simple", AllCapabilities()),
make_pair(" OpCapability Shader"
" OpMemoryModel Physical64 OpenCL", AddressesDependencies())
)));
-INSTANTIATE_TEST_CASE_P(ExecutionMode,
- ValidateCapability,
- ::testing::Combine(
- testing::ValuesIn(AllCapabilities()),
- testing::Values(
+INSTANTIATE_TEST_CASE_P(ExecutionMode, ValidateCapability,
+ Combine(
+ ValuesIn(AllCapabilities()),
+ Values(
make_pair("OpExecutionMode %func Invocations 42", GeometryDependencies()),
make_pair("OpExecutionMode %func SpacingEqual", TessellationDependencies()),
make_pair("OpExecutionMode %func SpacingFractionalEven", TessellationDependencies()),
make_pair("OpExecutionMode %func ContractionOff", KernelDependencies())
)));
-INSTANTIATE_TEST_CASE_P(StorageClass,
- ValidateCapability,
- ::testing::Combine(
-testing::ValuesIn(AllCapabilities()),
-testing::Values(
+INSTANTIATE_TEST_CASE_P(StorageClass, ValidateCapability,
+ Combine(
+ ValuesIn(AllCapabilities()),
+ Values(
make_pair(" %intt = OpTypeInt 32 0\n"
" %ptrt = OpTypePointer UniformConstant %intt\n"
" %var = OpVariable %ptrt UniformConstant\n", AllCapabilities()),
" %var = OpVariable %ptrt Image\n", AllCapabilities())
)));
-INSTANTIATE_TEST_CASE_P(Dim,
- ValidateCapability,
- ::testing::Combine(
- testing::ValuesIn(AllCapabilities()),
- testing::Values(
+INSTANTIATE_TEST_CASE_P(Dim, ValidateCapability,
+ Combine(
+ ValuesIn(AllCapabilities()),
+ Values(
make_pair(" OpCapability ImageBasic"
" %voidt = OpTypeVoid"
" %imgt = OpTypeImage %voidt 1D 0 0 0 0 Unknown", Sampled1DDependencies()),
// NOTE: All Sampler Address Modes require kernel capabilities but the
// OpConstantSampler requires LiteralSampler which depends on Kernel
-INSTANTIATE_TEST_CASE_P(SamplerAddressingMode,
- ValidateCapability,
- ::testing::Combine(
- testing::ValuesIn(AllCapabilities()),
- testing::Values(
+INSTANTIATE_TEST_CASE_P(SamplerAddressingMode, ValidateCapability,
+ Combine(
+ ValuesIn(AllCapabilities()),
+ Values(
make_pair(" %samplert = OpTypeSampler"
" %sampler = OpConstantSampler %samplert None 1 Nearest", vector<string>{"LiteralSampler"}),
make_pair(" %samplert = OpTypeSampler"
//TODO(umar): Access Qualifier
//TODO(umar): Function Parameter Attribute
-INSTANTIATE_TEST_CASE_P(Decoration,
- ValidateCapability,
- ::testing::Combine(
- testing::ValuesIn(AllCapabilities()),
- testing::Values(
+INSTANTIATE_TEST_CASE_P(Decoration, ValidateCapability,
+ Combine(
+ ValuesIn(AllCapabilities()),
+ Values(
make_pair("OpDecorate %intt RelaxedPrecision\n", ShaderDependencies()),
make_pair("OpDecorate %intt SpecId 1\n", ShaderDependencies()),
make_pair("OpDecorate %intt Block\n", ShaderDependencies()),
)));
-INSTANTIATE_TEST_CASE_P(BuiltIn,
- ValidateCapability,
- ::testing::Combine(
- testing::ValuesIn(AllCapabilities()),
- testing::Values(
+INSTANTIATE_TEST_CASE_P(BuiltIn, ValidateCapability,
+ Combine(
+ ValuesIn(AllCapabilities()),
+ Values(
make_pair("OpDecorate %intt BuiltIn Position\n", ShaderDependencies()),
make_pair("OpDecorate %intt BuiltIn PointSize\n", ShaderDependencies()),
-make_pair("OpDecorate %intt BuiltIn ClipDistance\n", vector<string>{"ClipDistance"}),
-make_pair("OpDecorate %intt BuiltIn CullDistance\n", vector<string>{"CullDistance"}),
+make_pair("OpDecorate %intt BuiltIn ClipDistance\n", ShaderDependencies()),
+make_pair("OpDecorate %intt BuiltIn CullDistance\n", ShaderDependencies()),
make_pair("OpDecorate %intt BuiltIn VertexId\n", ShaderDependencies()),
make_pair("OpDecorate %intt BuiltIn InstanceId\n", ShaderDependencies()),
make_pair("OpDecorate %intt BuiltIn PrimitiveId\n", GeometryTessellationDependencies()),
make_pair("OpDecorate %intt BuiltIn InvocationId\n", GeometryTessellationDependencies()),
make_pair("OpDecorate %intt BuiltIn Layer\n", GeometryDependencies()),
-//make_pair("OpDecorate %intt BuiltIn ViewPortIndex\n", vector<string>{"MultiViewport"}),
+make_pair("OpDecorate %intt BuiltIn ViewportIndex\n", GeometryDependencies()),
make_pair("OpDecorate %intt BuiltIn TessLevelOuter\n", TessellationDependencies()),
make_pair("OpDecorate %intt BuiltIn TessLevelInner\n", TessellationDependencies()),
make_pair("OpDecorate %intt BuiltIn TessCoord\n", TessellationDependencies()),
make_pair("OpDecorate %intt BuiltIn FragCoord\n", ShaderDependencies()),
make_pair("OpDecorate %intt BuiltIn PointCoord\n", ShaderDependencies()),
make_pair("OpDecorate %intt BuiltIn FrontFacing\n", ShaderDependencies()),
-make_pair("OpDecorate %intt BuiltIn SampleId\n", vector<string>{"SampleRateShading"}),
-make_pair("OpDecorate %intt BuiltIn SamplePosition\n", vector<string>{"SampleRateShading"}),
-make_pair("OpDecorate %intt BuiltIn SampleMask\n", vector<string>{"SampleRateShading"}),
+make_pair("OpDecorate %intt BuiltIn SampleId\n", ShaderDependencies()),
+make_pair("OpDecorate %intt BuiltIn SamplePosition\n", ShaderDependencies()),
+make_pair("OpDecorate %intt BuiltIn SampleMask\n", ShaderDependencies()),
make_pair("OpDecorate %intt BuiltIn FragDepth\n", ShaderDependencies()),
make_pair("OpDecorate %intt BuiltIn HelperInvocation\n", ShaderDependencies()),
-make_pair("OpDecorate %intt BuiltIn NumWorkgroups\n", AllCapabilities()),
-make_pair("OpDecorate %intt BuiltIn WorkgroupSize\n", AllCapabilities()),
-make_pair("OpDecorate %intt BuiltIn WorkgroupId\n", AllCapabilities()),
-make_pair("OpDecorate %intt BuiltIn LocalInvocationId\n", AllCapabilities()),
-make_pair("OpDecorate %intt BuiltIn GlobalInvocationId\n", AllCapabilities()),
-make_pair("OpDecorate %intt BuiltIn LocalInvocationIndex", AllCapabilities()),
-make_pair("OpDecorate %intt BuiltIn WorkDim\n", KernelDependencies()),
-make_pair("OpDecorate %intt BuiltIn GlobalSize\n", KernelDependencies()),
-make_pair("OpDecorate %intt BuiltIn EnqueuedWorkgroupSize\n", KernelDependencies()),
-make_pair("OpDecorate %intt BuiltIn GlobalOffset\n", KernelDependencies()),
-make_pair("OpDecorate %intt BuiltIn GlobalLinearId\n", KernelDependencies()),
-make_pair("OpDecorate %intt BuiltIn SubgroupSize\n", KernelDependencies()),
-make_pair("OpDecorate %intt BuiltIn SubgroupMaxSize\n", KernelDependencies()),
-make_pair("OpDecorate %intt BuiltIn NumSubgroups\n", KernelDependencies()),
-make_pair("OpDecorate %intt BuiltIn NumEnqueuedSubgroups\n", KernelDependencies()),
-make_pair("OpDecorate %intt BuiltIn SubgroupId\n", KernelDependencies()),
-make_pair("OpDecorate %intt BuiltIn SubgroupLocalInvocationId\n", KernelDependencies()),
make_pair("OpDecorate %intt BuiltIn VertexIndex\n", ShaderDependencies()),
-make_pair("OpDecorate %intt BuiltIn InstanceIndex\n", ShaderDependencies())
+make_pair("OpDecorate %intt BuiltIn InstanceIndex\n", ShaderDependencies()),
+// Though the remaining builtins don't require Shader, the BuiltIn keyword
+// itself currently does require it.
+make_pair("OpDecorate %intt BuiltIn NumWorkgroups\n", ShaderDependencies()),
+make_pair("OpDecorate %intt BuiltIn WorkgroupSize\n", ShaderDependencies()),
+make_pair("OpDecorate %intt BuiltIn WorkgroupId\n", ShaderDependencies()),
+make_pair("OpDecorate %intt BuiltIn LocalInvocationId\n", ShaderDependencies()),
+make_pair("OpDecorate %intt BuiltIn GlobalInvocationId\n", ShaderDependencies()),
+make_pair("OpDecorate %intt BuiltIn LocalInvocationIndex", ShaderDependencies()),
+make_pair("OpCapability Shader\n"
+ "OpDecorate %intt BuiltIn WorkDim\n", KernelDependencies()),
+make_pair("OpCapability Shader\n"
+ "OpDecorate %intt BuiltIn GlobalSize\n", KernelDependencies()),
+make_pair("OpCapability Shader\n"
+ "OpDecorate %intt BuiltIn EnqueuedWorkgroupSize\n", KernelDependencies()),
+make_pair("OpCapability Shader\n"
+ "OpDecorate %intt BuiltIn GlobalOffset\n", KernelDependencies()),
+make_pair("OpCapability Shader\n"
+ "OpDecorate %intt BuiltIn GlobalLinearId\n", KernelDependencies()),
+make_pair("OpCapability Shader\n"
+ "OpDecorate %intt BuiltIn SubgroupSize\n", KernelDependencies()),
+make_pair("OpCapability Shader\n"
+ "OpDecorate %intt BuiltIn SubgroupMaxSize\n", KernelDependencies()),
+make_pair("OpCapability Shader\n"
+ "OpDecorate %intt BuiltIn NumSubgroups\n", KernelDependencies()),
+make_pair("OpCapability Shader\n"
+ "OpDecorate %intt BuiltIn NumEnqueuedSubgroups\n", KernelDependencies()),
+make_pair("OpCapability Shader\n"
+ "OpDecorate %intt BuiltIn SubgroupId\n", KernelDependencies()),
+make_pair("OpCapability Shader\n"
+ "OpDecorate %intt BuiltIn SubgroupLocalInvocationId\n", KernelDependencies())
)));
// TODO(umar): Selection Control
// TODO(umar): Kernel Enqueue Flags
// TODO(umar): Kernel Profiling Flags
-INSTANTIATE_TEST_CASE_P(MatrixOp,
- ValidateCapability,
- ::testing::Combine(
- testing::ValuesIn(AllCapabilities()),
- testing::Values(
+INSTANTIATE_TEST_CASE_P(MatrixOp, ValidateCapability,
+ Combine(
+ ValuesIn(AllCapabilities()),
+ Values(
make_pair(
"%intt = OpTypeInt 32 1\n"
"%vec3 = OpTypeVector %intt 3\n"
"%mat33 = OpTypeMatrix %vec3 3\n", MatrixDependencies()))));
// clang-format on
+// Creates assembly containing an OpImageFetch instruction using operands for
+// the image-operands part. The assembly defines constants %fzero and %izero
+// that can be used for operands where IDs are required. The assembly is valid,
+// apart from not declaring any capabilities required by the operands.
+string ImageOperandsTemplate(const string& operands) {
+ stringstream ss;
+ // clang-format off
+ ss << R"(
+OpCapability Kernel
+OpMemoryModel Logical OpenCL
+
+%i32 = OpTypeInt 32 1
+%f32 = OpTypeFloat 32
+%v4i32 = OpTypeVector %i32 4
+%timg = OpTypeImage %i32 2D 0 0 0 0 Unknown
+%pimg = OpTypePointer UniformConstant %timg
+%tfun = OpTypeFunction %i32
+
+%vimg = OpVariable %pimg UniformConstant
+%izero = OpConstant %i32 0
+%fzero = OpConstant %f32 0.
+
+%main = OpFunction %i32 None %tfun
+%lbl = OpLabel
+%img = OpLoad %timg %vimg
+%r1 = OpImageFetch %v4i32 %img %izero )" << operands << R"(
+OpReturnValue %izero
+OpFunctionEnd
+)";
+ // clang-format on
+ return ss.str();
+}
+
+INSTANTIATE_TEST_CASE_P(
+ TwoImageOperandsMask, ValidateCapability,
+ Combine(
+ ValuesIn(AllCapabilities()),
+ Values(make_pair(ImageOperandsTemplate("Bias|Lod %fzero %fzero"),
+ ShaderDependencies()),
+ make_pair(ImageOperandsTemplate("Lod|Offset %fzero %izero"),
+ vector<string>{"ImageGatherExtended"}),
+ make_pair(ImageOperandsTemplate("Sample|MinLod %izero %fzero"),
+ vector<string>{"MinLod"}),
+ make_pair(ImageOperandsTemplate("Lod|Sample %fzero %izero"),
+ AllCapabilities()))));
+
// TODO(umar): Instruction capability checks
TEST_P(ValidateCapability, Capability) {
CompileSuccessfully(ss.str());
ASSERT_EQ(res, ValidateInstructions());
}
+
+} // namespace anonymous