Initial capability implementation and unit tests

* Register capabilility and checks
* Add validate storage class capabilities checks and tests
* Instruction pass refactor
  - More generic form of capability checking by checking operands
    instead of instructions
* Execution Model capabilities checks
* Decorate BuiltIn capability checks
* Addressing Model capability checks
* Memory Model capability checks
* Execution Mode capability checks
* Dim capability checks
* SamplerAddressingMode capability checks
This commit is contained in:
Umar Arshad 2016-01-23 14:14:32 -05:00
parent 3fade33c06
commit 61a627586b
7 changed files with 1385 additions and 13 deletions

View File

@ -234,6 +234,7 @@ if (NOT ${SPIRV_SKIP_EXECUTABLES})
${CMAKE_CURRENT_SOURCE_DIR}/test/TextWordGet.cpp
${CMAKE_CURRENT_SOURCE_DIR}/test/UnitSPIRV.cpp
${CMAKE_CURRENT_SOURCE_DIR}/test/ValidateFixtures.cpp
${CMAKE_CURRENT_SOURCE_DIR}/test/Validate.Capability.cpp
${CMAKE_CURRENT_SOURCE_DIR}/test/Validate.Layout.cpp
${CMAKE_CURRENT_SOURCE_DIR}/test/Validate.SSA.cpp
${CMAKE_CURRENT_SOURCE_DIR}/test/ValidateID.cpp

View File

@ -76,6 +76,7 @@ typedef enum spv_result_t {
SPV_ERROR_INVALID_ID = -10,
SPV_ERROR_INVALID_CFG = -11,
SPV_ERROR_INVALID_LAYOUT = -12,
SPV_ERROR_INVALID_CAPABILITY = -13,
SPV_FORCE_32_BIT_ENUM(spv_result_t)
} spv_result_t;

View File

@ -261,6 +261,12 @@ class ValidationState_t {
std::vector<uint32_t>& entry_points() { return entry_points_; }
const std::vector<uint32_t>& entry_points() const { return entry_points_; }
// Registers the capability and its dependent capabilities
void registerCapability(SpvCapability cap);
// Returns true if the capabillity is enabled in the module
bool hasCapability(SpvCapability cap);
private:
spv_diagnostic* diagnostic_;
// Tracks the number of instructions evaluated by the validator
@ -279,13 +285,14 @@ class ValidationState_t {
Functions module_functions_;
std::vector<SpvCapability> module_capabilities_;
std::vector<bool> module_capabilities_;
// Definitions and uses of all the IDs in the module.
UseDefTracker usedefs_;
// IDs that are entry points, ie, arguments to OpEntryPoint.
std::vector<uint32_t> entry_points_;
};
} // namespace libspirv

View File

@ -26,18 +26,473 @@
// Performs validation on instructions that appear inside of a SPIR-V block.
#include <cassert>
#include "validate_passes.h"
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;
}
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;
}
#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;
}
#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
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;
}
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) {
return _.diag(SPV_ERROR_INVALID_CAPABILITY)
<< mode + " sample address mode requires Kernel capability";
}
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:
_.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 uint32_t storage_class = inst->words[inst->operands[2].offset];
if (_.getLayoutSection() > kLayoutFunctionDeclarations) {
const SpvStorageClass storage_class =
static_cast<SpvStorageClass>(inst->words[inst->operands[2].offset]);
spvCheckReturn(StorageClassCapabilityCheck(_, storage_class));
if (_.getLayoutSection() == kLayoutFunctionDeclarations) {
if (storage_class != SpvStorageClassFunction) {
return _.diag(SPV_ERROR_INVALID_LAYOUT)
<< "Variables must have a function[7] storage class inside"
@ -51,11 +506,253 @@ spv_result_t InstructionPass(ValidationState_t& _,
}
}
} break;
default:
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 SPV_SUCCESS;
}
// clang-format on
}

View File

@ -203,7 +203,15 @@ bool IsInstructionInLayoutSection(ModuleLayoutSection layout, SpvOp op) {
// clang-format on
return out;
}
}
// NOTE: We are using vector to map the ID of the capability to its
// availability. this variable needs to be the maximum id plus one to cover the
// entire range of the capability. Currently capability 26 is missing so the
// count is actually 54
// The maximum ID of capabilities plus one
static const size_t kCapabilitiesCount = 56;
} // anonymous namespace
namespace libspirv {
@ -215,7 +223,8 @@ ValidationState_t::ValidationState_t(spv_diagnostic* diagnostic,
validation_flags_(options),
operand_names_{},
current_layout_section_(kLayoutCapabilities),
module_functions_(*this) {}
module_functions_(*this),
module_capabilities_(kCapabilitiesCount, false) {}
spv_result_t ValidationState_t::forwardDeclareId(uint32_t id) {
unresolved_forward_ids_.insert(id);
@ -295,6 +304,85 @@ bool ValidationState_t::in_block() const {
return module_functions_.in_block();
}
// Returns the dependant capability of the input capibility. If the capability
// does not have a capability then the same capability is returned.
// clang-format off
SpvCapability
getDependantCapability(SpvCapability cap) {
SpvCapability out;
switch(cap) {
case SpvCapabilityShader: out = SpvCapabilityMatrix; break;
case SpvCapabilityGeometry: out = SpvCapabilityShader; break;
case SpvCapabilityTessellation: out = SpvCapabilityShader; break;
case SpvCapabilityVector16: out = SpvCapabilityKernel; break;
case SpvCapabilityFloat16Buffer: out = SpvCapabilityKernel; break;
case SpvCapabilityFloat16: out = SpvCapabilityFloat16Buffer; break;
case SpvCapabilityInt64Atomics: out = SpvCapabilityInt64; break;
case SpvCapabilityImageBasic: out = SpvCapabilityKernel; break;
case SpvCapabilityImageReadWrite: out = SpvCapabilityImageBasic; break;
case SpvCapabilityImageMipmap: out = SpvCapabilityImageBasic; break;
//case SpvCapabilityImageSRGBWrite: break;
case SpvCapabilityPipes: out = SpvCapabilityKernel; break;
case SpvCapabilityDeviceEnqueue: out = SpvCapabilityKernel; break;
case SpvCapabilityLiteralSampler: out = SpvCapabilityKernel; break;
case SpvCapabilityAtomicStorage: out = SpvCapabilityShader; break;
case SpvCapabilityTessellationPointSize: out = SpvCapabilityTessellation; break;
case SpvCapabilityGeometryPointSize: out = SpvCapabilityGeometry; break;
case SpvCapabilityImageGatherExtended: out = SpvCapabilityShader; break;
case SpvCapabilityStorageImageMultisample: out = SpvCapabilityShader; break;
case SpvCapabilityUniformBufferArrayDynamicIndexing: out = SpvCapabilityShader; break;
case SpvCapabilitySampledImageArrayDynamicIndexing: out = SpvCapabilityShader; break;
case SpvCapabilityStorageBufferArrayDynamicIndexing: out = SpvCapabilityShader; break;
case SpvCapabilityStorageImageArrayDynamicIndexing: out = SpvCapabilityShader; break;
case SpvCapabilityClipDistance: out = SpvCapabilityShader; break;
case SpvCapabilityCullDistance: out = SpvCapabilityShader; break;
case SpvCapabilityImageCubeArray: out = SpvCapabilitySampledCubeArray; break;
case SpvCapabilitySampleRateShading: out = SpvCapabilityShader; break;
case SpvCapabilityImageRect: out = SpvCapabilitySampledRect; break;
case SpvCapabilitySampledRect: out = SpvCapabilityShader; break;
case SpvCapabilityGenericPointer: out = SpvCapabilityAddresses; break;
case SpvCapabilityInt8: out = SpvCapabilityKernel; break;
case SpvCapabilityInputAttachment: out = SpvCapabilityShader; break;
case SpvCapabilitySparseResidency: out = SpvCapabilityShader; break;
case SpvCapabilityMinLod: out = SpvCapabilityShader; break;
case SpvCapabilitySampled1D: out = SpvCapabilityShader; break;
case SpvCapabilityImage1D: out = SpvCapabilitySampled1D; break;
case SpvCapabilitySampledCubeArray: out = SpvCapabilityShader; break;
case SpvCapabilitySampledBuffer: out = SpvCapabilityShader; break;
case SpvCapabilityImageBuffer: out = SpvCapabilitySampledBuffer; break;
case SpvCapabilityImageMSArray: out = SpvCapabilityShader; break;
case SpvCapabilityStorageImageExtendedFormats: out = SpvCapabilityShader; break;
case SpvCapabilityImageQuery: out = SpvCapabilityShader; break;
case SpvCapabilityDerivativeControl: out = SpvCapabilityShader; break;
case SpvCapabilityInterpolationFunction: out = SpvCapabilityShader; break;
case SpvCapabilityTransformFeedback: out = SpvCapabilityShader; break;
case SpvCapabilityGeometryStreams: out = SpvCapabilityGeometry; break;
case SpvCapabilityStorageImageReadWithoutFormat: out = SpvCapabilityShader; break;
case SpvCapabilityStorageImageWriteWithoutFormat: out = SpvCapabilityShader; break;
default:
out = cap;
break;
}
return out;
}
// clang-format on
void ValidationState_t::registerCapability(SpvCapability cap) {
SpvCapability capability = cap;
// Set dependant capabilities
do {
module_capabilities_[capability] = true;
capability = getDependantCapability(capability);
} while (getDependantCapability(capability) != capability);
// Set Base capability
module_capabilities_[capability] = true;
}
bool ValidationState_t::hasCapability(SpvCapability cap) {
return module_capabilities_[cap];
}
Functions::Functions(ValidationState_t& module)
: module_(module), in_function_(false), in_block_(false) {}
@ -359,8 +447,7 @@ spv_result_t Functions::RegisterBlock(uint32_t id) {
spv_result_t Functions::RegisterFunctionEnd() {
assert(in_function_ == true &&
"Function end can only be called in functions");
assert(in_block_ == false &&
"Function end cannot be called inside a block");
assert(in_block_ == false && "Function end cannot be called inside a block");
in_function_ = false;
return SPV_SUCCESS;
}
@ -374,7 +461,5 @@ spv_result_t Functions::RegisterBlockEnd() {
return SPV_SUCCESS;
}
size_t Functions::get_block_count() const {
return block_ids_.back().size();
}
size_t Functions::get_block_count() const { return block_ids_.back().size(); }
}

View File

@ -0,0 +1,579 @@
// Copyright (c) 2015-2016 The Khronos Group Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and/or associated documentation files (the
// "Materials"), to deal in the Materials without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Materials, and to
// permit persons to whom the Materials are furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Materials.
//
// MODIFICATIONS TO THIS FILE MAY MEAN IT NO LONGER ACCURATELY REFLECTS
// KHRONOS STANDARDS. THE UNMODIFIED, NORMATIVE VERSIONS OF KHRONOS
// SPECIFICATIONS AND HEADER INFORMATION ARE LOCATED AT
// https://www.khronos.org/registry/
//
// THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
// MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
// Validation tests for Logical Layout
#include <gmock/gmock.h>
#include "UnitSPIRV.h"
#include "ValidateFixtures.h"
#include <functional>
#include <sstream>
#include <string>
#include <utility>
using std::function;
using std::ostream;
using std::ostream_iterator;
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 ValidateCapability =
spvtest::ValidateBase<tuple<string, pair<string, vector<string>>>,
SPV_VALIDATE_INSTRUCTION_BIT>;
TEST_F(ValidateCapability, Default) {
const char str[] = R"(
OpCapability Kernel
OpCapability Matrix
OpMemoryModel Logical OpenCL
%intt = OpTypeInt 32 1
%vec3 = OpTypeVector %intt 3
%mat33 = OpTypeMatrix %vec3 3
)";
CompileSuccessfully(str);
ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
}
// clang-format off
const vector<string> kAllCapabilities =
{
"",
"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"};
const vector<string> kMatrixDependencies = {
"Matrix",
"Shader",
"Geometry",
"Tessellation",
"AtomicStorage",
"TessellationPointSize",
"GeometryPointSize",
"ImageGatherExtended",
"StorageImageMultisample",
"UniformBufferArrayDynamicIndexing",
"SampledImageArrayDynamicIndexing",
"StorageBufferArrayDynamicIndexing",
"StorageImageArrayDynamicIndexing",
"ClipDistance",
"CullDistance",
"ImageCubeArray",
"SampleRateShading",
"ImageRect",
"SampledRect",
"InputAttachment",
"SparseResidency",
"MinLod",
"Sampled1D",
"Image1D",
"SampledCubeArray",
"SampledBuffer",
"ImageMSArray",
"ImageBuffer",
"StorageImageExtendedFormats",
"ImageQuery",
"DerivativeControl",
"InterpolationFunction",
"TransformFeedback",
"GeometryStreams",
"StorageImageReadWithoutFormat",
"StorageImageWriteWithoutFormat",
};
const vector<string> kShaderDependencies = {
"Shader",
"Geometry",
"Tessellation",
"AtomicStorage",
"TessellationPointSize",
"GeometryPointSize",
"ImageGatherExtended",
"StorageImageMultisample",
"UniformBufferArrayDynamicIndexing",
"SampledImageArrayDynamicIndexing",
"StorageBufferArrayDynamicIndexing",
"StorageImageArrayDynamicIndexing",
"ClipDistance",
"CullDistance",
"ImageCubeArray",
"SampleRateShading",
"ImageRect",
"SampledRect",
"InputAttachment",
"SparseResidency",
"MinLod",
"Sampled1D",
"Image1D",
"SampledCubeArray",
"SampledBuffer",
"ImageMSArray",
"ImageBuffer",
"StorageImageExtendedFormats",
"ImageQuery",
"DerivativeControl",
"InterpolationFunction",
"TransformFeedback",
"GeometryStreams",
"StorageImageReadWithoutFormat",
"StorageImageWriteWithoutFormat",
};
const vector<string> kTessellationDependencies = {
"Tessellation",
"TessellationPointSize",
};
const vector<string> kGeometryDependencies = {
"Geometry",
"GeometryPointSize",
"GeometryStreams"
};
const vector<string> kGeometryTessellationDependencies = {
"Tessellation",
"TessellationPointSize",
"Geometry",
"GeometryPointSize",
"GeometryStreams"
};
const vector<string> kKernelDependencies = {
"Kernel",
"Vector16",
"Float16",
"Float16Buffer",
"ImageBasic",
"ImageReadWrite",
"ImageMipmap",
"Pipes",
"DeviceEnqueue",
"LiteralSampler",
"Int8"
};
const vector<string> kAddressesDependencies = {
"Addresses",
"GenericPointer"
};
const vector<string> kSampled1DDependencies = {
"Sampled1D",
"Image1D"
};
const vector<string> kSampledRectDependencies = {
"SampledRect",
"ImageRect",
};
const vector<string> kSampledBufferDependencies = {
"SampledBuffer",
"ImageBuffer",
};
INSTANTIATE_TEST_CASE_P(ExecutionModel,
ValidateCapability,
::testing::Combine(
testing::ValuesIn(kAllCapabilities),
testing::Values(
make_pair("OpEntryPoint Vertex %func \"shader\" %var1 %var2\n", kShaderDependencies),
make_pair("OpEntryPoint TessellationControl %func \"shader\" %var1 %var2\n", kTessellationDependencies),
make_pair("OpEntryPoint TessellationEvaluation %func \"shader\" %var1 %var2\n", kTessellationDependencies),
make_pair("OpEntryPoint Geometry %func \"shader\" %var1 %var2\n", kGeometryDependencies),
make_pair("OpEntryPoint Fragment %func \"shader\" %var1 %var2\n", kShaderDependencies),
make_pair("OpEntryPoint GLCompute %func \"shader\" %var1 %var2\n", kShaderDependencies),
make_pair("OpEntryPoint Kernel %func \"shader\" %var1 %var2\n", kKernelDependencies)
)));
INSTANTIATE_TEST_CASE_P(AddressingAndMemoryModel,
ValidateCapability,
::testing::Combine(
testing::ValuesIn(kAllCapabilities),
testing::Values(
make_pair(" OpCapability Shader"
" OpMemoryModel Logical Simple", kAllCapabilities),
make_pair(" OpCapability Shader"
" OpMemoryModel Logical GLSL450", kAllCapabilities),
make_pair(" OpCapability Kernel"
" OpMemoryModel Logical OpenCL", kAllCapabilities),
make_pair(" OpCapability Shader"
" OpMemoryModel Physical32 Simple", kAddressesDependencies),
make_pair(" OpCapability Shader"
" OpMemoryModel Physical32 GLSL450", kAddressesDependencies),
make_pair(" OpCapability Kernel"
" OpMemoryModel Physical32 OpenCL", kAddressesDependencies),
make_pair(" OpCapability Shader"
" OpMemoryModel Physical64 Simple", kAddressesDependencies),
make_pair(" OpCapability Shader"
" OpMemoryModel Physical64 GLSL450", kAddressesDependencies),
make_pair(" OpCapability Kernel"
" OpMemoryModel Physical64 OpenCL", kAddressesDependencies)
)));
INSTANTIATE_TEST_CASE_P(ExecutionMode,
ValidateCapability,
::testing::Combine(
testing::ValuesIn(kAllCapabilities),
testing::Values(
make_pair("OpExecutionMode %func Invocations 42", kGeometryDependencies),
make_pair("OpExecutionMode %func SpacingEqual", kTessellationDependencies),
make_pair("OpExecutionMode %func SpacingFractionalEven", kTessellationDependencies),
make_pair("OpExecutionMode %func SpacingFractionalOdd", kTessellationDependencies),
make_pair("OpExecutionMode %func VertexOrderCw", kTessellationDependencies),
make_pair("OpExecutionMode %func VertexOrderCcw", kTessellationDependencies),
make_pair("OpExecutionMode %func PixelCenterInteger", kShaderDependencies),
make_pair("OpExecutionMode %func OriginUpperLeft", kShaderDependencies),
make_pair("OpExecutionMode %func OriginLowerLeft", kShaderDependencies),
make_pair("OpExecutionMode %func EarlyFragmentTests", kShaderDependencies),
make_pair("OpExecutionMode %func PointMode", kTessellationDependencies),
make_pair("OpExecutionMode %func Xfb", vector<string>{"TransformFeedback"}),
make_pair("OpExecutionMode %func DepthReplacing", kShaderDependencies),
make_pair("OpExecutionMode %func DepthGreater", kShaderDependencies),
make_pair("OpExecutionMode %func DepthLess", kShaderDependencies),
make_pair("OpExecutionMode %func DepthUnchanged", kShaderDependencies),
make_pair("OpExecutionMode %func LocalSize 42 42 42", kAllCapabilities),
make_pair("OpExecutionMode %func LocalSizeHint 42 42 42", kKernelDependencies),
make_pair("OpExecutionMode %func InputPoints", kGeometryDependencies),
make_pair("OpExecutionMode %func InputLines", kGeometryDependencies),
make_pair("OpExecutionMode %func InputLinesAdjacency", kGeometryDependencies),
make_pair("OpExecutionMode %func Triangles", kGeometryTessellationDependencies),
make_pair("OpExecutionMode %func InputTrianglesAdjacency", kGeometryDependencies),
make_pair("OpExecutionMode %func Quads", kTessellationDependencies),
make_pair("OpExecutionMode %func Isolines", kTessellationDependencies),
make_pair("OpExecutionMode %func OutputVertices 42", kGeometryTessellationDependencies),
make_pair("OpExecutionMode %func OutputPoints", kGeometryDependencies),
make_pair("OpExecutionMode %func OutputLineStrip", kGeometryDependencies),
make_pair("OpExecutionMode %func OutputTriangleStrip", kGeometryDependencies),
make_pair("OpExecutionMode %func VecTypeHint 2", kKernelDependencies),
make_pair("OpExecutionMode %func ContractionOff", kKernelDependencies)
)));
INSTANTIATE_TEST_CASE_P(StorageClass,
ValidateCapability,
::testing::Combine(
testing::ValuesIn(kAllCapabilities),
testing::Values(
make_pair(" %intt = OpTypeInt 32 0\n"
" %ptrt = OpTypePointer UniformConstant %intt\n"
" %var = OpVariable %ptrt UniformConstant\n", kAllCapabilities),
make_pair(" %intt = OpTypeInt 32 0\n"
" %ptrt = OpTypePointer Input %intt"
" %var = OpVariable %ptrt Input\n", kShaderDependencies),
make_pair(" %intt = OpTypeInt 32 0\n"
" %ptrt = OpTypePointer Uniform %intt\n"
" %var = OpVariable %ptrt Uniform\n", kShaderDependencies),
make_pair(" %intt = OpTypeInt 32 0\n"
" %ptrt = OpTypePointer Output %intt\n"
" %var = OpVariable %ptrt Output\n", kShaderDependencies),
make_pair(" %intt = OpTypeInt 32 0\n"
" %ptrt = OpTypePointer Workgroup %intt\n"
" %var = OpVariable %ptrt Workgroup\n", kAllCapabilities),
make_pair(" %intt = OpTypeInt 32 0\n"
" %ptrt = OpTypePointer CrossWorkgroup %intt\n"
" %var = OpVariable %ptrt CrossWorkgroup\n", kAllCapabilities),
make_pair(" %intt = OpTypeInt 32 0\n"
" %ptrt = OpTypePointer Private %intt\n"
" %var = OpVariable %ptrt Private\n", kShaderDependencies),
make_pair(" %intt = OpTypeInt 32 0\n"
" %ptrt = OpTypePointer Generic %intt\n"
" %var = OpVariable %ptrt Generic\n", kKernelDependencies),
make_pair(" %intt = OpTypeInt 32 0\n"
" %ptrt = OpTypePointer PushConstant %intt\n"
" %var = OpVariable %ptrt PushConstant\n", kShaderDependencies),
make_pair(" %intt = OpTypeInt 32 0\n"
" %ptrt = OpTypePointer AtomicCounter %intt\n"
" %var = OpVariable %ptrt AtomicCounter\n", vector<string>{"AtomicStorage"}),
make_pair(" %intt = OpTypeInt 32 0\n"
" %ptrt = OpTypePointer Image %intt\n"
" %var = OpVariable %ptrt Image\n", kAllCapabilities)
)));
INSTANTIATE_TEST_CASE_P(Dim,
ValidateCapability,
::testing::Combine(
testing::ValuesIn(kAllCapabilities),
testing::Values(
make_pair(" OpCapability ImageBasic"
" %voidt = OpTypeVoid"
" %imgt = OpTypeImage %voidt 1D 0 0 0 0 Unknown", kSampled1DDependencies),
make_pair(" OpCapability ImageBasic"
" %voidt = OpTypeVoid"
" %imgt = OpTypeImage %voidt 2D 0 0 0 0 Unknown", kAllCapabilities),
make_pair(" OpCapability ImageBasic"
" %voidt = OpTypeVoid"
" %imgt = OpTypeImage %voidt 3D 0 0 0 0 Unknown", kAllCapabilities),
make_pair(" OpCapability ImageBasic"
" %voidt = OpTypeVoid"
" %imgt = OpTypeImage %voidt Cube 0 0 0 0 Unknown", kShaderDependencies),
make_pair(" OpCapability ImageBasic"
" %voidt = OpTypeVoid"
" %imgt = OpTypeImage %voidt Rect 0 0 0 0 Unknown", kSampledRectDependencies),
make_pair(" OpCapability ImageBasic"
" %voidt = OpTypeVoid"
" %imgt = OpTypeImage %voidt Buffer 0 0 0 0 Unknown", kSampledBufferDependencies),
make_pair(" OpCapability ImageBasic"
" %voidt = OpTypeVoid"
" %imgt = OpTypeImage %voidt SubpassData 0 0 0 2 Unknown", vector<string>{"InputAttachment"})
)));
// NOTE: All Sampler Address Modes require kernel capabilities but the
// OpConstantSampler requires LiteralSampler which depends on Kernel
INSTANTIATE_TEST_CASE_P(SamplerAddressingMode,
ValidateCapability,
::testing::Combine(
testing::ValuesIn(kAllCapabilities),
testing::Values(
make_pair(" %samplert = OpTypeSampler"
" %sampler = OpConstantSampler %samplert None 1 Nearest", vector<string>{"LiteralSampler"}),
make_pair(" %samplert = OpTypeSampler"
" %sampler = OpConstantSampler %samplert ClampToEdge 1 Nearest", vector<string>{"LiteralSampler"}),
make_pair(" %samplert = OpTypeSampler"
" %sampler = OpConstantSampler %samplert Clamp 1 Nearest", vector<string>{"LiteralSampler"}),
make_pair(" %samplert = OpTypeSampler"
" %sampler = OpConstantSampler %samplert Repeat 1 Nearest", vector<string>{"LiteralSampler"}),
make_pair(" %samplert = OpTypeSampler"
" %sampler = OpConstantSampler %samplert RepeatMirrored 1 Nearest", vector<string>{"LiteralSampler"})
)));
//TODO(umar): Sampler Filter Mode
//TODO(umar): Image Format
//TODO(umar): Image Channel Order
//TODO(umar): Image Channel Data Type
//TODO(umar): Image Operands
//TODO(umar): FP Fast Math Mode
//TODO(umar): FP Rounding Mode
//TODO(umar): Linkage Type
//TODO(umar): Access Qualifier
//TODO(umar): Function Parameter Attribute
INSTANTIATE_TEST_CASE_P(Decoration,
ValidateCapability,
::testing::Combine(
testing::ValuesIn(kAllCapabilities),
testing::Values(
make_pair("OpDecorate %intt RelaxedPrecision\n", kShaderDependencies),
make_pair("OpDecorate %intt SpecId 1\n", kShaderDependencies),
make_pair("OpDecorate %intt Block\n", kShaderDependencies),
make_pair("OpDecorate %intt BufferBlock\n", kShaderDependencies),
make_pair("OpDecorate %intt RowMajor\n", kMatrixDependencies),
make_pair("OpDecorate %intt ColMajor\n", kMatrixDependencies),
make_pair("OpDecorate %intt ArrayStride 1\n", kShaderDependencies),
make_pair("OpDecorate %intt MatrixStride 1\n", kShaderDependencies),
make_pair("OpDecorate %intt GLSLShared\n", kShaderDependencies),
make_pair("OpDecorate %intt GLSLPacked\n", kShaderDependencies),
make_pair("OpDecorate %intt CPacked\n", kKernelDependencies),
make_pair("OpDecorate %intt NoPerspective\n", kShaderDependencies),
make_pair("OpDecorate %intt Flat\n", kShaderDependencies),
make_pair("OpDecorate %intt Patch\n", kTessellationDependencies),
make_pair("OpDecorate %intt Centroid\n", kShaderDependencies),
make_pair("OpDecorate %intt Sample\n", kShaderDependencies),
make_pair("OpDecorate %intt Invariant\n", kShaderDependencies),
make_pair("OpDecorate %intt Restrict\n", kAllCapabilities),
make_pair("OpDecorate %intt Aliased\n", kAllCapabilities),
make_pair("OpDecorate %intt Volatile\n", kAllCapabilities),
make_pair("OpDecorate %intt Constant\n", kKernelDependencies),
make_pair("OpDecorate %intt Coherent\n", kAllCapabilities),
make_pair("OpDecorate %intt NonWritable\n", kAllCapabilities),
make_pair("OpDecorate %intt NonReadable\n", kAllCapabilities),
make_pair("OpDecorate %intt Uniform\n", kShaderDependencies),
make_pair("OpDecorate %intt SaturatedConversion\n", kKernelDependencies),
make_pair("OpDecorate %intt Stream 0\n", vector<string>{"GeometryStreams"}),
make_pair("OpDecorate %intt Location 0\n", kShaderDependencies),
make_pair("OpDecorate %intt Component 0\n", kShaderDependencies),
make_pair("OpDecorate %intt Index 0\n", kShaderDependencies),
make_pair("OpDecorate %intt Binding 0\n", kShaderDependencies),
make_pair("OpDecorate %intt DescriptorSet 0\n", kShaderDependencies),
make_pair("OpDecorate %intt Offset 0\n", kAllCapabilities),
make_pair("OpDecorate %intt XfbBuffer 0\n", vector<string>{"TransformFeedback"}),
make_pair("OpDecorate %intt XfbStride 0\n", vector<string>{"TransformFeedback"}),
make_pair("OpDecorate %intt FuncParamAttr Zext\n", kKernelDependencies),
make_pair("OpDecorate %intt FPRoundingMode RTE\n", kKernelDependencies),
make_pair("OpDecorate %intt FPFastMathMode Fast\n", kKernelDependencies),
make_pair("OpDecorate %intt LinkageAttributes \"other\" Import\n", vector<string>{"Linkage"}),
make_pair("OpDecorate %intt NoContraction\n", kShaderDependencies),
make_pair("OpDecorate %intt InputAttachmentIndex 0\n", vector<string>{"InputAttachment"}),
make_pair("OpDecorate %intt Alignment 4\n", kKernelDependencies)
)));
INSTANTIATE_TEST_CASE_P(BuiltIn,
ValidateCapability,
::testing::Combine(
testing::ValuesIn(kAllCapabilities),
testing::Values(
make_pair("OpDecorate %intt BuiltIn Position\n", kShaderDependencies),
make_pair("OpDecorate %intt BuiltIn PointSize\n", kShaderDependencies),
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 VertexId\n", kShaderDependencies),
make_pair("OpDecorate %intt BuiltIn InstanceId\n", kShaderDependencies),
make_pair("OpDecorate %intt BuiltIn PrimitiveId\n", kGeometryTessellationDependencies),
make_pair("OpDecorate %intt BuiltIn InvocationId\n", kGeometryTessellationDependencies),
make_pair("OpDecorate %intt BuiltIn Layer\n", kGeometryDependencies),
//make_pair("OpDecorate %intt BuiltIn ViewPortIndex\n", vector<string>{"MultiViewport"}),
make_pair("OpDecorate %intt BuiltIn TessLevelOuter\n", kTessellationDependencies),
make_pair("OpDecorate %intt BuiltIn TessLevelInner\n", kTessellationDependencies),
make_pair("OpDecorate %intt BuiltIn TessCoord\n", kTessellationDependencies),
make_pair("OpDecorate %intt BuiltIn PatchVertices\n", kTessellationDependencies),
make_pair("OpDecorate %intt BuiltIn FragCoord\n", kShaderDependencies),
make_pair("OpDecorate %intt BuiltIn PointCoord\n", kShaderDependencies),
make_pair("OpDecorate %intt BuiltIn FrontFacing\n", kShaderDependencies),
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 FragDepth\n", kShaderDependencies),
make_pair("OpDecorate %intt BuiltIn HelperInvocation\n", kShaderDependencies),
make_pair("OpDecorate %intt BuiltIn NumWorkgroups\n", kAllCapabilities),
make_pair("OpDecorate %intt BuiltIn WorkgroupSize\n", kAllCapabilities),
make_pair("OpDecorate %intt BuiltIn WorkgroupId\n", kAllCapabilities),
make_pair("OpDecorate %intt BuiltIn LocalInvocationId\n", kAllCapabilities),
make_pair("OpDecorate %intt BuiltIn GlobalInvocationId\n", kAllCapabilities),
make_pair("OpDecorate %intt BuiltIn LocalInvocationIndex", kAllCapabilities),
make_pair("OpDecorate %intt BuiltIn WorkDim\n", kKernelDependencies),
make_pair("OpDecorate %intt BuiltIn GlobalSize\n", kKernelDependencies),
make_pair("OpDecorate %intt BuiltIn EnqueuedWorkgroupSize\n", kKernelDependencies),
make_pair("OpDecorate %intt BuiltIn GlobalOffset\n", kKernelDependencies),
make_pair("OpDecorate %intt BuiltIn GlobalLinearId\n", kKernelDependencies),
make_pair("OpDecorate %intt BuiltIn SubgroupSize\n", kKernelDependencies),
make_pair("OpDecorate %intt BuiltIn SubgroupMaxSize\n", kKernelDependencies),
make_pair("OpDecorate %intt BuiltIn NumSubgroups\n", kKernelDependencies),
make_pair("OpDecorate %intt BuiltIn NumEnqueuedSubgroups\n", kKernelDependencies),
make_pair("OpDecorate %intt BuiltIn SubgroupId\n", kKernelDependencies),
make_pair("OpDecorate %intt BuiltIn SubgroupLocalInvocationId\n", kKernelDependencies),
make_pair("OpDecorate %intt BuiltIn VertexIndex\n", kShaderDependencies),
make_pair("OpDecorate %intt BuiltIn InstanceIndex\n", kShaderDependencies)
)));
// TODO(umar): Selection Control
// TODO(umar): Loop Control
// TODO(umar): Function Control
// TODO(umar): Memory Semantics
// TODO(umar): Memory Access
// TODO(umar): Scope
// TODO(umar): Group Operation
// TODO(umar): Kernel Enqueue Flags
// TODO(umar): Kernel Profiling Flags
INSTANTIATE_TEST_CASE_P(MatrixOp,
ValidateCapability,
::testing::Combine(
testing::ValuesIn(kAllCapabilities),
testing::Values(
make_pair(
"%intt = OpTypeInt 32 1\n"
"%vec3 = OpTypeVector %intt 3\n"
"%mat33 = OpTypeMatrix %vec3 3\n", kMatrixDependencies))));
// clang-format on
// TODO(umar): Instruction capability checks
TEST_P(ValidateCapability, Capability) {
string capability;
pair<string, vector<string>> operation;
std::tie(capability, operation) = GetParam();
stringstream ss;
if (capability.empty() == false) {
ss << "OpCapability " + capability + " ";
}
ss << operation.first;
spv_result_t res = SPV_ERROR_INTERNAL;
auto& valid_capabilities = operation.second;
auto it =
find(begin(valid_capabilities), end(valid_capabilities), capability);
if (it != end(valid_capabilities)) {
res = SPV_SUCCESS;
} else {
res = SPV_ERROR_INVALID_CAPABILITY;
}
CompileSuccessfully(ss.str());
ASSERT_EQ(res, ValidateInstructions());
}

View File

@ -91,4 +91,6 @@ template class spvtest::ValidateBase<
std::tuple<int, std::tuple<std::string, std::function<spv_result_t(int)>,
std::function<spv_result_t(int)>>>,
SPV_VALIDATE_LAYOUT_BIT>;
template class spvtest::ValidateBase<std::tuple<std::string, std::pair<std::string, std::vector<std::string> > >, SPV_VALIDATE_INSTRUCTION_BIT>;
}