mirror of
https://github.com/KhronosGroup/SPIRV-Tools
synced 2024-11-23 04:00:05 +00:00
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:
parent
3fade33c06
commit
61a627586b
@ -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
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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(); }
|
||||
}
|
||||
|
579
test/Validate.Capability.cpp
Normal file
579
test/Validate.Capability.cpp
Normal 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());
|
||||
}
|
@ -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>;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user