// 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. #include #include #include #include #include "diagnostic.h" #include "instruction.h" #include "opcode.h" #include "spirv-tools/libspirv.h" #include "validate.h" #define spvCheck(condition, action) \ if (condition) { \ action; \ } using UseDefTracker = libspirv::ValidationState_t::UseDefTracker; namespace { class idUsage { public: idUsage(const spv_opcode_table opcodeTableArg, const spv_operand_table operandTableArg, const spv_ext_inst_table extInstTableArg, const spv_instruction_t* pInsts, const uint64_t instCountArg, const UseDefTracker& usedefs, const std::vector& entry_points, spv_position positionArg, spv_diagnostic* pDiagnosticArg) : opcodeTable(opcodeTableArg), operandTable(operandTableArg), extInstTable(extInstTableArg), firstInst(pInsts), instCount(instCountArg), position(positionArg), pDiagnostic(pDiagnosticArg), usedefs_(usedefs), entry_points_(entry_points) {} bool isValid(const spv_instruction_t* inst); template bool isValid(const spv_instruction_t* inst, const spv_opcode_desc); private: const spv_opcode_table opcodeTable; const spv_operand_table operandTable; const spv_ext_inst_table extInstTable; const spv_instruction_t* const firstInst; const uint64_t instCount; spv_position position; spv_diagnostic* pDiagnostic; UseDefTracker usedefs_; std::vector entry_points_; }; #define DIAG(INDEX) \ position->index += INDEX; \ DIAGNOSTIC #if 0 template <> bool idUsage::isValid(const spv_instruction_t *inst, const spv_opcode_desc) { assert(0 && "Unimplemented!"); return false; } #endif // 0 template <> bool idUsage::isValid(const spv_instruction_t* inst, const spv_opcode_desc) { auto typeIndex = 1; auto type = usedefs_.FindDef(inst->words[typeIndex]); if (!type.first || SpvOpTypeStruct != type.second.opcode) { DIAG(typeIndex) << "OpMemberName Type '" << inst->words[typeIndex] << "' is not a struct type."; return false; } auto memberIndex = 2; auto member = inst->words[memberIndex]; auto memberCount = (uint32_t)(type.second.words.size() - 2); spvCheck(memberCount <= member, DIAG(memberIndex) << "OpMemberName Member '" << inst->words[memberIndex] << "' index is larger than Type '" << type.second.id << "'s member count."; return false); return true; } template <> bool idUsage::isValid(const spv_instruction_t* inst, const spv_opcode_desc) { auto fileIndex = 1; auto file = usedefs_.FindDef(inst->words[fileIndex]); if (!file.first || SpvOpString != file.second.opcode) { DIAG(fileIndex) << "OpLine Target '" << inst->words[fileIndex] << "' is not an OpString."; return false; } return true; } template <> bool idUsage::isValid(const spv_instruction_t* inst, const spv_opcode_desc) { auto structTypeIndex = 1; auto structType = usedefs_.FindDef(inst->words[structTypeIndex]); if (!structType.first || SpvOpTypeStruct != structType.second.opcode) { DIAG(structTypeIndex) << "OpMemberDecorate Structure type '" << inst->words[structTypeIndex] << "' is not a struct type."; return false; } auto memberIndex = 2; auto member = inst->words[memberIndex]; auto memberCount = static_cast(structType.second.words.size() - 2); spvCheck(memberCount < member, DIAG(memberIndex) << "OpMemberDecorate Structure type '" << inst->words[memberIndex] << "' member count is less than Member"; return false); return true; } template <> bool idUsage::isValid(const spv_instruction_t* inst, const spv_opcode_desc) { auto decorationGroupIndex = 1; auto decorationGroup = usedefs_.FindDef(inst->words[decorationGroupIndex]); if (!decorationGroup.first || SpvOpDecorationGroup != decorationGroup.second.opcode) { DIAG(decorationGroupIndex) << "OpGroupDecorate Decoration group '" << inst->words[decorationGroupIndex] << "' is not a decoration group."; return false; } return true; } #if 0 template <> bool idUsage::isValid( const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif // 0 #if 0 template <> bool idUsage::isValid(const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif // 0 template <> bool idUsage::isValid(const spv_instruction_t* inst, const spv_opcode_desc) { auto entryPointIndex = 2; auto entryPoint = usedefs_.FindDef(inst->words[entryPointIndex]); if (!entryPoint.first || SpvOpFunction != entryPoint.second.opcode) { DIAG(entryPointIndex) << "OpEntryPoint Entry Point '" << inst->words[entryPointIndex] << "' is not a function."; return false; } // don't check kernel function signatures auto executionModel = inst->words[1]; if (executionModel != SpvExecutionModelKernel) { // TODO: Check the entry point signature is void main(void), may be subject // to change auto entryPointType = usedefs_.FindDef(entryPoint.second.words[4]); if (!entryPointType.first || 3 != entryPointType.second.words.size()) { DIAG(entryPointIndex) << "OpEntryPoint Entry Point '" << inst->words[entryPointIndex] << "'s function parameter count is not zero."; return false; } } auto returnType = usedefs_.FindDef(entryPoint.second.type_id); if (!returnType.first || SpvOpTypeVoid != returnType.second.opcode) { DIAG(entryPointIndex) << "OpEntryPoint Entry Point '" << inst->words[entryPointIndex] << "'s function return type is not void."; return false; } return true; } template <> bool idUsage::isValid(const spv_instruction_t* inst, const spv_opcode_desc) { auto entryPointIndex = 1; auto entryPointID = inst->words[entryPointIndex]; auto found = std::find(entry_points_.cbegin(), entry_points_.cend(), entryPointID); if (found == entry_points_.cend()) { DIAG(entryPointIndex) << "OpExecutionMode Entry Point '" << inst->words[entryPointIndex] << "' is not the Entry Point " "operand of an OpEntryPoint."; return false; } return true; } template <> bool idUsage::isValid(const spv_instruction_t* inst, const spv_opcode_desc) { auto componentIndex = 2; auto componentType = usedefs_.FindDef(inst->words[componentIndex]); if (!componentType.first || !spvOpcodeIsScalarType(componentType.second.opcode)) { DIAG(componentIndex) << "OpTypeVector Component Type '" << inst->words[componentIndex] << "' is not a scalar type."; return false; } return true; } template <> bool idUsage::isValid(const spv_instruction_t* inst, const spv_opcode_desc) { auto columnTypeIndex = 2; auto columnType = usedefs_.FindDef(inst->words[columnTypeIndex]); if (!columnType.first || SpvOpTypeVector != columnType.second.opcode) { DIAG(columnTypeIndex) << "OpTypeMatrix Column Type '" << inst->words[columnTypeIndex] << "' is not a vector."; return false; } return true; } template <> bool idUsage::isValid(const spv_instruction_t*, const spv_opcode_desc) { // OpTypeSampler takes no arguments in Rev31 and beyond. return true; } template <> bool idUsage::isValid(const spv_instruction_t* inst, const spv_opcode_desc) { auto elementTypeIndex = 2; auto elementType = usedefs_.FindDef(inst->words[elementTypeIndex]); if (!elementType.first || !spvOpcodeGeneratesType(elementType.second.opcode)) { DIAG(elementTypeIndex) << "OpTypeArray Element Type '" << inst->words[elementTypeIndex] << "' is not a type."; return false; } auto lengthIndex = 3; auto length = usedefs_.FindDef(inst->words[lengthIndex]); if (!length.first || (SpvOpConstant != length.second.opcode && SpvOpSpecConstant != length.second.opcode)) { DIAG(lengthIndex) << "OpTypeArray Length '" << inst->words[lengthIndex] << "' is not a scalar constant type."; return false; } // NOTE: Check the initialiser value of the constant auto constInst = length.second.words; auto constResultTypeIndex = 1; auto constResultType = usedefs_.FindDef(constInst[constResultTypeIndex]); if (!constResultType.first || SpvOpTypeInt != constResultType.second.opcode) { DIAG(lengthIndex) << "OpTypeArray Length '" << inst->words[lengthIndex] << "' is not a constant integer type."; return false; } if (4 == constInst.size()) { spvCheck(1 > constInst[3], DIAG(lengthIndex) << "OpTypeArray Length '" << inst->words[lengthIndex] << "' value must be at least 1."; return false); } else if (5 == constInst.size()) { uint64_t value = constInst[3] | ((uint64_t)constInst[4]) << 32; bool signedness = constResultType.second.words[3] != 0; if (signedness) { spvCheck(1 > (int64_t)value, DIAG(lengthIndex) << "OpTypeArray Length '" << inst->words[lengthIndex] << "' value must be at least 1."; return false); } else { spvCheck(1 > value, DIAG(lengthIndex) << "OpTypeArray Length '" << inst->words[lengthIndex] << "' value must be at least 1."; return false); } } return true; } template <> bool idUsage::isValid(const spv_instruction_t* inst, const spv_opcode_desc) { auto elementTypeIndex = 2; auto elementType = usedefs_.FindDef(inst->words[elementTypeIndex]); if (!elementType.first || !spvOpcodeGeneratesType(elementType.second.opcode)) { DIAG(elementTypeIndex) << "OpTypeRuntimeArray Element Type '" << inst->words[elementTypeIndex] << "' is not a type."; return false; } return true; } template <> bool idUsage::isValid(const spv_instruction_t* inst, const spv_opcode_desc) { for (size_t memberTypeIndex = 2; memberTypeIndex < inst->words.size(); ++memberTypeIndex) { auto memberType = usedefs_.FindDef(inst->words[memberTypeIndex]); if (!memberType.first || !spvOpcodeGeneratesType(memberType.second.opcode)) { DIAG(memberTypeIndex) << "OpTypeStruct Member Type '" << inst->words[memberTypeIndex] << "' is not a type."; return false; } } return true; } template <> bool idUsage::isValid(const spv_instruction_t* inst, const spv_opcode_desc) { auto typeIndex = 3; auto type = usedefs_.FindDef(inst->words[typeIndex]); if (!type.first || !spvOpcodeGeneratesType(type.second.opcode)) { DIAG(typeIndex) << "OpTypePointer Type '" << inst->words[typeIndex] << "' is not a type."; return false; } return true; } template <> bool idUsage::isValid(const spv_instruction_t* inst, const spv_opcode_desc) { auto returnTypeIndex = 2; auto returnType = usedefs_.FindDef(inst->words[returnTypeIndex]); if (!returnType.first || !spvOpcodeGeneratesType(returnType.second.opcode)) { DIAG(returnTypeIndex) << "OpTypeFunction Return Type '" << inst->words[returnTypeIndex] << "' is not a type."; return false; } for (size_t paramTypeIndex = 3; paramTypeIndex < inst->words.size(); ++paramTypeIndex) { auto paramType = usedefs_.FindDef(inst->words[paramTypeIndex]); if (!paramType.first || !spvOpcodeGeneratesType(paramType.second.opcode)) { DIAG(paramTypeIndex) << "OpTypeFunction Parameter Type '" << inst->words[paramTypeIndex] << "' is not a type."; return false; } } return true; } template <> bool idUsage::isValid(const spv_instruction_t*, const spv_opcode_desc) { // OpTypePipe has no ID arguments. return true; } template <> bool idUsage::isValid(const spv_instruction_t* inst, const spv_opcode_desc) { auto resultTypeIndex = 1; auto resultType = usedefs_.FindDef(inst->words[resultTypeIndex]); if (!resultType.first || SpvOpTypeBool != resultType.second.opcode) { DIAG(resultTypeIndex) << "OpConstantTrue Result Type '" << inst->words[resultTypeIndex] << "' is not a boolean type."; return false; } return true; } template <> bool idUsage::isValid(const spv_instruction_t* inst, const spv_opcode_desc) { auto resultTypeIndex = 1; auto resultType = usedefs_.FindDef(inst->words[resultTypeIndex]); if (!resultType.first || SpvOpTypeBool != resultType.second.opcode) { DIAG(resultTypeIndex) << "OpConstantFalse Result Type '" << inst->words[resultTypeIndex] << "' is not a boolean type."; return false; } return true; } template <> bool idUsage::isValid(const spv_instruction_t* inst, const spv_opcode_desc) { auto resultTypeIndex = 1; auto resultType = usedefs_.FindDef(inst->words[resultTypeIndex]); if (!resultType.first || !spvOpcodeIsComposite(resultType.second.opcode)) { DIAG(resultTypeIndex) << "OpConstantComposite Result Type '" << inst->words[resultTypeIndex] << "' is not a composite type."; return false; } auto constituentCount = inst->words.size() - 3; switch (resultType.second.opcode) { case SpvOpTypeVector: { auto componentCount = resultType.second.words[3]; spvCheck( componentCount != constituentCount, // TODO: Output ID's on diagnostic DIAG(inst->words.size() - 1) << "OpConstantComposite Constituent count does not match " "Result Type '" << resultType.second.id << "'s vector component count."; return false); auto componentType = usedefs_.FindDef(resultType.second.words[2]); assert(componentType.first); for (size_t constituentIndex = 3; constituentIndex < inst->words.size(); constituentIndex++) { auto constituent = usedefs_.FindDef(inst->words[constituentIndex]); if (!constituent.first || !spvOpcodeIsConstant(constituent.second.opcode)) { DIAG(constituentIndex) << "OpConstantComposite Constituent '" << inst->words[constituentIndex] << "' is not a constant."; return false; } auto constituentResultType = usedefs_.FindDef(constituent.second.type_id); if (!constituentResultType.first || componentType.second.opcode != constituentResultType.second.opcode) { DIAG(constituentIndex) << "OpConstantComposite Constituent '" << inst->words[constituentIndex] << "'s type does not match Result Type '" << resultType.second.id << "'s vector element type."; return false; } } } break; case SpvOpTypeMatrix: { auto columnCount = resultType.second.words[3]; spvCheck( columnCount != constituentCount, // TODO: Output ID's on diagnostic DIAG(inst->words.size() - 1) << "OpConstantComposite Constituent count does not match " "Result Type '" << resultType.second.id << "'s matrix column count."; return false); auto columnType = usedefs_.FindDef(resultType.second.words[2]); assert(columnType.first); auto componentCount = columnType.second.words[3]; auto componentType = usedefs_.FindDef(columnType.second.words[2]); assert(componentType.first); for (size_t constituentIndex = 3; constituentIndex < inst->words.size(); constituentIndex++) { auto constituent = usedefs_.FindDef(inst->words[constituentIndex]); if (!constituent.first || SpvOpConstantComposite != constituent.second.opcode) { DIAG(constituentIndex) << "OpConstantComposite Constituent '" << inst->words[constituentIndex] << "' is not a constant composite."; return false; } auto vector = usedefs_.FindDef(constituent.second.type_id); assert(vector.first); spvCheck(columnType.second.opcode != vector.second.opcode, DIAG(constituentIndex) << "OpConstantComposite Constituent '" << inst->words[constituentIndex] << "' type does not match Result Type '" << resultType.second.id << "'s matrix column type."; return false); auto vectorComponentType = usedefs_.FindDef(vector.second.words[2]); assert(vectorComponentType.first); spvCheck(componentType.second.id != vectorComponentType.second.id, DIAG(constituentIndex) << "OpConstantComposite Constituent '" << inst->words[constituentIndex] << "' component type does not match Result Type '" << resultType.second.id << "'s matrix column component type."; return false); spvCheck( componentCount != vector.second.words[3], DIAG(constituentIndex) << "OpConstantComposite Constituent '" << inst->words[constituentIndex] << "' vector component count does not match Result Type '" << resultType.second.id << "'s vector component count."; return false); } } break; case SpvOpTypeArray: { auto elementType = usedefs_.FindDef(resultType.second.words[2]); assert(elementType.first); auto length = usedefs_.FindDef(resultType.second.words[3]); assert(length.first); spvCheck(length.second.words[3] != constituentCount, DIAG(inst->words.size() - 1) << "OpConstantComposite Constituent count does not match " "Result Type '" << resultType.second.id << "'s array length."; return false); for (size_t constituentIndex = 3; constituentIndex < inst->words.size(); constituentIndex++) { auto constituent = usedefs_.FindDef(inst->words[constituentIndex]); if (!constituent.first || !spvOpcodeIsConstant(constituent.second.opcode)) { DIAG(constituentIndex) << "OpConstantComposite Constituent '" << inst->words[constituentIndex] << "' is not a constant."; return false; } auto constituentType = usedefs_.FindDef(constituent.second.type_id); assert(constituentType.first); spvCheck(elementType.second.id != constituentType.second.id, DIAG(constituentIndex) << "OpConstantComposite Constituent '" << inst->words[constituentIndex] << "'s type does not match Result Type '" << resultType.second.id << "'s array element type."; return false); } } break; case SpvOpTypeStruct: { auto memberCount = resultType.second.words.size() - 2; spvCheck(memberCount != constituentCount, DIAG(resultTypeIndex) << "OpConstantComposite Constituent '" << inst->words[resultTypeIndex] << "' count does not match Result Type '" << resultType.second.id << "'s struct member count."; return false); for (uint32_t constituentIndex = 3, memberIndex = 2; constituentIndex < inst->words.size(); constituentIndex++, memberIndex++) { auto constituent = usedefs_.FindDef(inst->words[constituentIndex]); if (!constituent.first || !spvOpcodeIsConstant(constituent.second.opcode)) { DIAG(constituentIndex) << "OpConstantComposite Constituent '" << inst->words[constituentIndex] << "' is not a constant."; return false; } auto constituentType = usedefs_.FindDef(constituent.second.type_id); assert(constituentType.first); auto memberType = usedefs_.FindDef(resultType.second.words[memberIndex]); assert(memberType.first); spvCheck(memberType.second.id != constituentType.second.id, DIAG(constituentIndex) << "OpConstantComposite Constituent '" << inst->words[constituentIndex] << "' type does not match the Result Type '" << resultType.second.id << "'s member type."; return false); } } break; default: { assert(0 && "Unreachable!"); } break; } return true; } template <> bool idUsage::isValid(const spv_instruction_t* inst, const spv_opcode_desc) { auto resultTypeIndex = 1; auto resultType = usedefs_.FindDef(inst->words[resultTypeIndex]); if (!resultType.first || SpvOpTypeSampler != resultType.second.opcode) { DIAG(resultTypeIndex) << "OpConstantSampler Result Type '" << inst->words[resultTypeIndex] << "' is not a sampler type."; return false; } return true; } // True if instruction defines a type that can have a null value, as defined by // the SPIR-V spec. Tracks composite-type components through usedefs to check // nullability transitively. bool IsTypeNullable(const std::vector& instruction, const UseDefTracker& usedefs) { SpvOp opcode; uint16_t word_count; spvOpcodeSplit(instruction[0], &word_count, &opcode); switch (opcode) { case SpvOpTypeBool: case SpvOpTypeInt: case SpvOpTypeFloat: case SpvOpTypePointer: case SpvOpTypeEvent: case SpvOpTypeDeviceEvent: case SpvOpTypeReserveId: case SpvOpTypeQueue: return true; case SpvOpTypeArray: case SpvOpTypeMatrix: case SpvOpTypeVector: { auto base_type = usedefs.FindDef(instruction[2]); return base_type.first && IsTypeNullable(base_type.second.words, usedefs); } case SpvOpTypeStruct: { for (size_t elementIndex = 2; elementIndex < instruction.size(); ++elementIndex) { auto element = usedefs.FindDef(instruction[elementIndex]); if (!element.first || !IsTypeNullable(element.second.words, usedefs)) return false; } return true; } default: return false; } } template <> bool idUsage::isValid(const spv_instruction_t* inst, const spv_opcode_desc) { auto resultTypeIndex = 1; auto resultType = usedefs_.FindDef(inst->words[resultTypeIndex]); if (!resultType.first || !IsTypeNullable(resultType.second.words, usedefs_)) { DIAG(resultTypeIndex) << "OpConstantNull Result Type '" << inst->words[resultTypeIndex] << "' cannot have a null value."; return false; } return true; } template <> bool idUsage::isValid(const spv_instruction_t* inst, const spv_opcode_desc) { auto resultTypeIndex = 1; auto resultType = usedefs_.FindDef(inst->words[resultTypeIndex]); if (!resultType.first || SpvOpTypeBool != resultType.second.opcode) { DIAG(resultTypeIndex) << "OpSpecConstantTrue Result Type '" << inst->words[resultTypeIndex] << "' is not a boolean type."; return false; } return true; } template <> bool idUsage::isValid(const spv_instruction_t* inst, const spv_opcode_desc) { auto resultTypeIndex = 1; auto resultType = usedefs_.FindDef(inst->words[resultTypeIndex]); if (!resultType.first || SpvOpTypeBool != resultType.second.opcode) { DIAG(resultTypeIndex) << "OpSpecConstantFalse Result Type '" << inst->words[resultTypeIndex] << "' is not a boolean type."; return false; } return true; } #if 0 template <> bool idUsage::isValid( const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif #if 0 template <> bool idUsage::isValid(const spv_instruction_t *inst) {} #endif template <> bool idUsage::isValid(const spv_instruction_t* inst, const spv_opcode_desc opcodeEntry) { auto resultTypeIndex = 1; auto resultType = usedefs_.FindDef(inst->words[resultTypeIndex]); if (!resultType.first || SpvOpTypePointer != resultType.second.opcode) { DIAG(resultTypeIndex) << "OpVariable Result Type '" << inst->words[resultTypeIndex] << "' is not a pointer type."; return false; } if (opcodeEntry->numTypes < inst->words.size()) { auto initialiserIndex = 4; auto initialiser = usedefs_.FindDef(inst->words[initialiserIndex]); if (!initialiser.first || !spvOpcodeIsConstant(initialiser.second.opcode)) { DIAG(initialiserIndex) << "OpVariable Initializer '" << inst->words[initialiserIndex] << "' is not a constant."; return false; } } return true; } template <> bool idUsage::isValid(const spv_instruction_t* inst, const spv_opcode_desc) { auto resultTypeIndex = 1; auto resultType = usedefs_.FindDef(inst->words[resultTypeIndex]); spvCheck(!resultType.first, DIAG(resultTypeIndex) << "OpLoad Result Type '" << inst->words[resultTypeIndex] << "' is not defind."; return false); auto pointerIndex = 3; auto pointer = usedefs_.FindDef(inst->words[pointerIndex]); if (!pointer.first || !spvOpcodeIsPointer(pointer.second.opcode)) { DIAG(pointerIndex) << "OpLoad Pointer '" << inst->words[pointerIndex] << "' is not a pointer."; return false; } auto pointerType = usedefs_.FindDef(pointer.second.type_id); if (!pointerType.first || pointerType.second.opcode != SpvOpTypePointer) { DIAG(pointerIndex) << "OpLoad type for pointer '" << inst->words[pointerIndex] << "' is not a pointer type."; return false; } auto pointeeType = usedefs_.FindDef(pointerType.second.words[3]); if (!pointeeType.first || resultType.second.id != pointeeType.second.id) { DIAG(resultTypeIndex) << "OpLoad Result Type '" << inst->words[resultTypeIndex] << "' does not match Pointer '" << pointer.second.id << "'s type."; return false; } return true; } template <> bool idUsage::isValid(const spv_instruction_t* inst, const spv_opcode_desc) { auto pointerIndex = 1; auto pointer = usedefs_.FindDef(inst->words[pointerIndex]); if (!pointer.first || !spvOpcodeIsPointer(pointer.second.opcode)) { DIAG(pointerIndex) << "OpStore Pointer '" << inst->words[pointerIndex] << "' is not a pointer."; return false; } auto pointerType = usedefs_.FindDef(pointer.second.type_id); assert(pointerType.first); auto type = usedefs_.FindDef(pointerType.second.words[3]); assert(type.first); spvCheck(SpvOpTypeVoid == type.second.opcode, DIAG(pointerIndex) << "OpStore Pointer '" << inst->words[pointerIndex] << "'s type is void."; return false); auto objectIndex = 2; auto object = usedefs_.FindDef(inst->words[objectIndex]); if (!object.first || !object.second.type_id) { DIAG(objectIndex) << "OpStore Object '" << inst->words[objectIndex] << "' is not an object."; return false; } auto objectType = usedefs_.FindDef(object.second.type_id); assert(objectType.first); spvCheck(SpvOpTypeVoid == objectType.second.opcode, DIAG(objectIndex) << "OpStore Object '" << inst->words[objectIndex] << "'s type is void."; return false); spvCheck(type.second.id != objectType.second.id, DIAG(pointerIndex) << "OpStore Pointer '" << inst->words[pointerIndex] << "'s type does not match Object '" << objectType.second.id << "'s type."; return false); return true; } template <> bool idUsage::isValid(const spv_instruction_t* inst, const spv_opcode_desc) { auto targetIndex = 1; auto target = usedefs_.FindDef(inst->words[targetIndex]); if (!target.first) return false; auto sourceIndex = 2; auto source = usedefs_.FindDef(inst->words[sourceIndex]); if (!source.first) return false; auto targetPointerType = usedefs_.FindDef(target.second.type_id); assert(targetPointerType.first); auto targetType = usedefs_.FindDef(targetPointerType.second.words[3]); assert(targetType.first); auto sourcePointerType = usedefs_.FindDef(source.second.type_id); assert(sourcePointerType.first); auto sourceType = usedefs_.FindDef(sourcePointerType.second.words[3]); assert(sourceType.first); spvCheck(targetType.second.id != sourceType.second.id, DIAG(sourceIndex) << "OpCopyMemory Target '" << inst->words[sourceIndex] << "'s type does not match Source '" << sourceType.second.id << "'s type."; return false); return true; } template <> bool idUsage::isValid(const spv_instruction_t* inst, const spv_opcode_desc) { auto targetIndex = 1; auto target = usedefs_.FindDef(inst->words[targetIndex]); if (!target.first) return false; auto sourceIndex = 2; auto source = usedefs_.FindDef(inst->words[sourceIndex]); if (!source.first) return false; auto sizeIndex = 3; auto size = usedefs_.FindDef(inst->words[sizeIndex]); if (!size.first) return false; auto targetPointerType = usedefs_.FindDef(target.second.type_id); spvCheck(!targetPointerType.first || SpvOpTypePointer != targetPointerType.second.opcode, DIAG(targetIndex) << "OpCopyMemorySized Target '" << inst->words[targetIndex] << "' is not a pointer."; return false); auto sourcePointerType = usedefs_.FindDef(source.second.type_id); spvCheck(!sourcePointerType.first || SpvOpTypePointer != sourcePointerType.second.opcode, DIAG(sourceIndex) << "OpCopyMemorySized Source '" << inst->words[sourceIndex] << "' is not a pointer."; return false); switch (size.second.opcode) { // TODO: The following opcode's are assumed to be valid, refer to the // following bug https://cvs.khronos.org/bugzilla/show_bug.cgi?id=13871 for // clarification case SpvOpConstant: case SpvOpSpecConstant: { auto sizeType = usedefs_.FindDef(size.second.type_id); assert(sizeType.first); spvCheck(SpvOpTypeInt != sizeType.second.opcode, DIAG(sizeIndex) << "OpCopyMemorySized Size '" << inst->words[sizeIndex] << "'s type is not an integer type."; return false); } break; case SpvOpVariable: { auto pointerType = usedefs_.FindDef(size.second.type_id); assert(pointerType.first); auto sizeType = usedefs_.FindDef(pointerType.second.type_id); spvCheck(!sizeType.first || SpvOpTypeInt != sizeType.second.opcode, DIAG(sizeIndex) << "OpCopyMemorySized Size '" << inst->words[sizeIndex] << "'s variable type is not an integer type."; return false); } break; default: DIAG(sizeIndex) << "OpCopyMemorySized Size '" << inst->words[sizeIndex] << "' is not a constant or variable."; return false; } // TODO: Check that consant is a least size 1, see the same bug as above for // clarification? return true; } #if 0 template <> bool idUsage::isValid(const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif #if 0 template <> bool idUsage::isValid( const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif #if 0 template <> bool idUsage::isValid(const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif #if 0 template <> bool idUsage::isValid(const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif #if 0 template <> bool idUsage::isValid( const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif template <> bool idUsage::isValid(const spv_instruction_t* inst, const spv_opcode_desc) { auto resultTypeIndex = 1; auto resultType = usedefs_.FindDef(inst->words[resultTypeIndex]); if (!resultType.first) return false; auto functionTypeIndex = 4; auto functionType = usedefs_.FindDef(inst->words[functionTypeIndex]); if (!functionType.first || SpvOpTypeFunction != functionType.second.opcode) { DIAG(functionTypeIndex) << "OpFunction Function Type '" << inst->words[functionTypeIndex] << "' is not a function type."; return false; } auto returnType = usedefs_.FindDef(functionType.second.words[2]); assert(returnType.first); spvCheck(returnType.second.id != resultType.second.id, DIAG(resultTypeIndex) << "OpFunction Result Type '" << inst->words[resultTypeIndex] << "' does not match the Function Type '" << resultType.second.id << "'s return type."; return false); return true; } template <> bool idUsage::isValid(const spv_instruction_t* inst, const spv_opcode_desc) { auto resultTypeIndex = 1; auto resultType = usedefs_.FindDef(inst->words[resultTypeIndex]); if (!resultType.first) return false; // NOTE: Find OpFunction & ensure OpFunctionParameter is not out of place. size_t paramIndex = 0; assert(firstInst < inst && "Invalid instruction pointer"); while (firstInst != --inst) { if (SpvOpFunction == inst->opcode) { break; } else if (SpvOpFunctionParameter == inst->opcode) { paramIndex++; } } auto functionType = usedefs_.FindDef(inst->words[4]); assert(functionType.first); if (paramIndex >= functionType.second.words.size() - 3) { DIAG(0) << "Too many OpFunctionParameters for " << inst->words[2] << ": expected " << functionType.second.words.size() - 3 << " based on the function's type"; return false; } auto paramType = usedefs_.FindDef(functionType.second.words[paramIndex + 3]); assert(paramType.first); spvCheck(resultType.second.id != paramType.second.id, DIAG(resultTypeIndex) << "OpFunctionParameter Result Type '" << inst->words[resultTypeIndex] << "' does not match the OpTypeFunction parameter " "type of the same index."; return false); return true; } template <> bool idUsage::isValid(const spv_instruction_t* inst, const spv_opcode_desc) { auto resultTypeIndex = 1; auto resultType = usedefs_.FindDef(inst->words[resultTypeIndex]); if (!resultType.first) return false; auto functionIndex = 3; auto function = usedefs_.FindDef(inst->words[functionIndex]); if (!function.first || SpvOpFunction != function.second.opcode) { DIAG(functionIndex) << "OpFunctionCall Function '" << inst->words[functionIndex] << "' is not a function."; return false; } auto returnType = usedefs_.FindDef(function.second.type_id); assert(returnType.first); spvCheck(returnType.second.id != resultType.second.id, DIAG(resultTypeIndex) << "OpFunctionCall Result Type '" << inst->words[resultTypeIndex] << "'s type does not match Function '" << returnType.second.id << "'s return type."; return false); auto functionType = usedefs_.FindDef(function.second.words[4]); assert(functionType.first); auto functionCallArgCount = inst->words.size() - 4; auto functionParamCount = functionType.second.words.size() - 3; spvCheck( functionParamCount != functionCallArgCount, DIAG(inst->words.size() - 1) << "OpFunctionCall Function 's parameter count does not match " "the argument count."; return false); for (size_t argumentIndex = 4, paramIndex = 3; argumentIndex < inst->words.size(); argumentIndex++, paramIndex++) { auto argument = usedefs_.FindDef(inst->words[argumentIndex]); if (!argument.first) return false; auto argumentType = usedefs_.FindDef(argument.second.type_id); assert(argumentType.first); auto parameterType = usedefs_.FindDef(functionType.second.words[paramIndex]); assert(parameterType.first); spvCheck(argumentType.second.id != parameterType.second.id, DIAG(argumentIndex) << "OpFunctionCall Argument '" << inst->words[argumentIndex] << "'s type does not match Function '" << parameterType.second.id << "'s parameter type."; return false); } return true; } #if 0 template <> bool idUsage::isValid(const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif #if 0 template <> bool idUsage::isValid(const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif #if 0 template <> bool idUsage::isValid(const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif #if 0 template <> bool idUsage::isValid(const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif #if 0 template <> bool idUsage::isValid(const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif #if 0 template <> bool idUsage::isValid(const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif #if 0 template <> bool idUsage::isValid(const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif #if 0 template <> bool idUsage::isValid(const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) { } #endif #if 0 template <> bool idUsage::isValid(const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) { } #endif #if 0 template <> bool idUsage::isValid( const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif #if 0 template <> bool idUsage::isValid( const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif #if 0 template <> bool idUsage::isValid(const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif #if 0 template <> bool idUsage::isValid( const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif #if 0 template <> bool idUsage::isValid(const spv_instruction_t *inst) {} #endif #if 0 template <> bool idUsage::isValid(const spv_instruction_t *inst) {} #endif #if 0 template <> bool idUsage::isValid( const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif #if 0 template <> bool idUsage::isValid( const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif #if 0 template <> bool idUsage::isValid(const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) { } #endif #if 0 template <> bool idUsage::isValid( const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif #if 0 template <> bool idUsage::isValid( const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif #if 0 template <> bool idUsage::isValid( const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif #if 0 template <> bool idUsage::isValid(const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif #if 0 template <> bool idUsage::isValid(const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif #if 0 template <> bool idUsage::isValid(const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif #if 0 template <> bool idUsage::isValid(const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif #if 0 template <> bool idUsage::isValid(const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif #if 0 template <> bool idUsage::isValid(const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif #if 0 template <> bool idUsage::isValid(const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif #if 0 template <> bool idUsage::isValid(const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif #if 0 template <> bool idUsage::isValid(const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif #if 0 template <> bool idUsage::isValid(const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif #if 0 template <> bool idUsage::isValid(const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif #if 0 template <> bool idUsage::isValid(const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif #if 0 template <> bool idUsage::isValid(const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif #if 0 template <> bool idUsage::isValid(const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif #if 0 template <> bool idUsage::isValid(const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif #if 0 template <> bool idUsage::isValid(const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif #if 0 template <> bool idUsage::isValid(const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif #if 0 template <> bool idUsage::isValid(const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif #if 0 template <> bool idUsage::isValid(const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif #if 0 template <> bool idUsage::isValid( const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif #if 0 template <> bool idUsage::isValid( const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif #if 0 template <> bool idUsage::isValid( const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif #if 0 template <> bool idUsage::isValid( const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif #if 0 template <> bool idUsage::isValid( const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif #if 0 template <> bool idUsage::isValid(const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif #if 0 template <> bool idUsage::isValid(const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif #if 0 template <> bool idUsage::isValid( const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif #if 0 template <> bool idUsage::isValid( const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif #if 0 template <> bool idUsage::isValid( const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif #if 0 template <> bool idUsage::isValid(const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif #if 0 template <> bool idUsage::isValid(const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif #if 0 template <> bool idUsage::isValid(const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif #if 0 template <> bool idUsage::isValid(const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif #if 0 template <> bool idUsage::isValid(const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif #if 0 template <> bool idUsage::isValid(const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif #if 0 template <> bool idUsage::isValid(const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif #if 0 template <> bool idUsage::isValid(const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif #if 0 template <> bool idUsage::isValid(const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif #if 0 template <> bool idUsage::isValid(const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif #if 0 template <> bool idUsage::isValid(const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) { } #endif #if 0 template <> bool idUsage::isValid(const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif #if 0 template <> bool idUsage::isValid(const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif #if 0 template <> bool idUsage::isValid(const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif #if 0 template <> bool idUsage::isValid(const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif #if 0 template <> bool idUsage::isValid(const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif #if 0 template <> bool idUsage::isValid(const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif #if 0 template <> bool idUsage::isValid(const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif #if 0 template <> bool idUsage::isValid(const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif #if 0 template <> bool idUsage::isValid(const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif #if 0 template <> bool idUsage::isValid(const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif #if 0 template <> bool idUsage::isValid(const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif #if 0 template <> bool idUsage::isValid( const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif #if 0 template <> bool idUsage::isValid(const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif #if 0 template <> bool idUsage::isValid(const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif #if 0 template <> bool idUsage::isValid(const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif #if 0 template <> bool idUsage::isValid( const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif #if 0 template <> bool idUsage::isValid(const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif #if 0 template <> bool idUsage::isValid(const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif #if 0 template <> bool idUsage::isValid( const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif #if 0 template <> bool idUsage::isValid( const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif #if 0 template <> bool idUsage::isValid( const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif #if 0 template <> bool idUsage::isValid( const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif #if 0 template <> bool idUsage::isValid( const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif #if 0 template <> bool idUsage::isValid( const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif #if 0 template <> bool idUsage::isValid( const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif #if 0 template <> bool idUsage::isValid( const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif #if 0 template <> bool idUsage::isValid( const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif #if 0 template <> bool idUsage::isValid( const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif #if 0 template <> bool idUsage::isValid(const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif #if 0 template <> bool idUsage::isValid(const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif #if 0 template <> bool idUsage::isValid(const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif #if 0 template <> bool idUsage::isValid(const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif #if 0 template <> bool idUsage::isValid(const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif #if 0 template <> bool idUsage::isValid(const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif #if 0 template <> bool idUsage::isValid(const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif #if 0 template <> bool idUsage::isValid(const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif #if 0 template <> bool idUsage::isValid(const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif #if 0 template <> bool idUsage::isValid(const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif #if 0 template <> bool idUsage::isValid(const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif #if 0 template <> bool idUsage::isValid( const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif #if 0 template <> bool idUsage::isValid(const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif #if 0 template <> bool idUsage::isValid( const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif #if 0 template <> bool idUsage::isValid(const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif template <> bool idUsage::isValid(const spv_instruction_t* inst, const spv_opcode_desc) { auto valueIndex = 1; auto value = usedefs_.FindDef(inst->words[valueIndex]); if (!value.first || !value.second.type_id) { DIAG(valueIndex) << "OpReturnValue Value '" << inst->words[valueIndex] << "' does not represent a value."; return false; } auto valueType = usedefs_.FindDef(value.second.type_id); if (!valueType.first || SpvOpTypeVoid == valueType.second.opcode) { DIAG(valueIndex) << "OpReturnValue value's type '" << value.second.type_id << "' is missing or void."; return false; } if (SpvOpTypePointer == valueType.second.opcode) { DIAG(valueIndex) << "OpReturnValue value's type '" << value.second.type_id << "' is a pointer, but a pointer can only be an operand " "to OpLoad, OpStore, OpAccessChain, or " "OpInBoundsAccessChain."; return false; } // NOTE: Find OpFunction const spv_instruction_t* function = inst - 1; while (firstInst != function) { spvCheck(SpvOpFunction == function->opcode, break); function--; } spvCheck(SpvOpFunction != function->opcode, DIAG(valueIndex) << "OpReturnValue is not in a basic block."; return false); auto returnType = usedefs_.FindDef(function->words[1]); spvCheck(!returnType.first || returnType.second.id != valueType.second.id, DIAG(valueIndex) << "OpReturnValue Value '" << inst->words[valueIndex] << "'s type does not match OpFunction's return type."; return false); return true; } #if 0 template <> bool idUsage::isValid(const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) { } #endif #if 0 template <> bool idUsage::isValid(const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif #if 0 template <> bool idUsage::isValid(const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif #if 0 template <> bool idUsage::isValid(const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif #if 0 template <> bool idUsage::isValid(const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif #if 0 template <> bool idUsage::isValid( const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif #if 0 template <> bool idUsage::isValid( const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif #if 0 template <> bool idUsage::isValid( const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif #if 0 template <> bool idUsage::isValid( const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif #if 0 template <> bool idUsage::isValid( const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif #if 0 template <> bool idUsage::isValid(const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif #if 0 template <> bool idUsage::isValid(const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif #if 0 template <> bool idUsage::isValid(const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif #if 0 template <> bool idUsage::isValid(const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif #if 0 template <> bool idUsage::isValid(const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif #if 0 template <> bool idUsage::isValid(const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif #if 0 template <> bool idUsage::isValid(const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif #if 0 template <> bool idUsage::isValid(const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif #if 0 template <> bool idUsage::isValid(const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif #if 0 template <> bool idUsage::isValid( const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif #if 0 template <> bool idUsage::isValid( const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif #if 0 template <> bool idUsage::isValid( const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif #if 0 template <> bool idUsage::isValid( const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif #if 0 template <> bool idUsage::isValid(const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif #if 0 template <> bool idUsage::isValid(const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif #if 0 template <> bool idUsage::isValid( const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif #if 0 template <> bool idUsage::isValid(const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif #if 0 template <> bool idUsage::isValid(const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif #if 0 template <> bool idUsage::isValid(const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif #if 0 template <> bool idUsage::isValid(const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif #if 0 template <> bool idUsage::isValid(const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif #if 0 template <> bool idUsage::isValid(const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif #if 0 template <> bool idUsage::isValid(const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif #if 0 template <> bool idUsage::isValid(const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif #if 0 template <> bool idUsage::isValid(const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) { } #endif #if 0 template <> bool idUsage::isValid(const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) { } #endif #if 0 template <> bool idUsage::isValid( const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif #if 0 template <> bool idUsage::isValid( const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif #if 0 template <> bool idUsage::isValid( const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif #if 0 template <> bool idUsage::isValid( const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif #if 0 template <> bool idUsage::isValid(const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif #if 0 template <> bool idUsage::isValid(const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif #if 0 template <> bool idUsage::isValid( const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif #if 0 template <> bool idUsage::isValid(const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif #if 0 template <> bool idUsage::isValid( const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif #if 0 template <> bool idUsage::isValid( const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif #if 0 template <> bool idUsage::isValid( const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif #if 0 template <> bool idUsage::isValid(const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif #if 0 template <> bool idUsage::isValid(const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif #if 0 template <> bool idUsage::isValid(const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif #if 0 template <> bool idUsage::isValid( const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif #if 0 template <> bool idUsage::isValid( const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif #if 0 template <> bool idUsage::isValid( const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif #if 0 template <> bool idUsage::isValid( const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif #if 0 template <> bool idUsage::isValid( const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif #if 0 template <> bool idUsage::isValid( const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif #if 0 template <> bool idUsage::isValid( const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif #if 0 template <> bool idUsage::isValid( const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif #if 0 template <> bool idUsage::isValid( const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif #if 0 template <> bool idUsage::isValid( const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif #if 0 template <> bool idUsage::isValid( const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif #if 0 template <> bool idUsage::isValid( const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif #if 0 template <> bool idUsage::isValid( const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif #undef DIAG bool idUsage::isValid(const spv_instruction_t* inst) { spv_opcode_desc opcodeEntry = nullptr; spvCheck(spvOpcodeTableValueLookup(opcodeTable, inst->opcode, &opcodeEntry), return false); #define CASE(OpCode) \ case Spv##OpCode: \ return isValid(inst, opcodeEntry); #define TODO(OpCode) \ case Spv##OpCode: \ return true; switch (inst->opcode) { TODO(OpUndef) CASE(OpMemberName) CASE(OpLine) CASE(OpMemberDecorate) CASE(OpGroupDecorate) TODO(OpGroupMemberDecorate) TODO(OpExtInst) CASE(OpEntryPoint) CASE(OpExecutionMode) CASE(OpTypeVector) CASE(OpTypeMatrix) CASE(OpTypeSampler) CASE(OpTypeArray) CASE(OpTypeRuntimeArray) CASE(OpTypeStruct) CASE(OpTypePointer) CASE(OpTypeFunction) CASE(OpTypePipe) CASE(OpConstantTrue) CASE(OpConstantFalse) CASE(OpConstantComposite) CASE(OpConstantSampler) CASE(OpConstantNull) CASE(OpSpecConstantTrue) CASE(OpSpecConstantFalse) TODO(OpSpecConstantComposite) TODO(OpSpecConstantOp) CASE(OpVariable) CASE(OpLoad) CASE(OpStore) CASE(OpCopyMemory) CASE(OpCopyMemorySized) TODO(OpAccessChain) TODO(OpInBoundsAccessChain) TODO(OpArrayLength) TODO(OpGenericPtrMemSemantics) CASE(OpFunction) CASE(OpFunctionParameter) CASE(OpFunctionCall) TODO(OpConvertUToF) TODO(OpConvertFToS) TODO(OpConvertSToF) TODO(OpUConvert) TODO(OpSConvert) TODO(OpFConvert) TODO(OpConvertPtrToU) TODO(OpConvertUToPtr) TODO(OpPtrCastToGeneric) TODO(OpGenericCastToPtr) TODO(OpBitcast) TODO(OpGenericCastToPtrExplicit) TODO(OpSatConvertSToU) TODO(OpSatConvertUToS) TODO(OpVectorExtractDynamic) TODO(OpVectorInsertDynamic) TODO(OpVectorShuffle) TODO(OpCompositeConstruct) TODO(OpCompositeExtract) TODO(OpCompositeInsert) TODO(OpCopyObject) TODO(OpTranspose) TODO(OpSNegate) TODO(OpFNegate) TODO(OpNot) TODO(OpIAdd) TODO(OpFAdd) TODO(OpISub) TODO(OpFSub) TODO(OpIMul) TODO(OpFMul) TODO(OpUDiv) TODO(OpSDiv) TODO(OpFDiv) TODO(OpUMod) TODO(OpSRem) TODO(OpSMod) TODO(OpFRem) TODO(OpFMod) TODO(OpVectorTimesScalar) TODO(OpMatrixTimesScalar) TODO(OpVectorTimesMatrix) TODO(OpMatrixTimesVector) TODO(OpMatrixTimesMatrix) TODO(OpOuterProduct) TODO(OpDot) TODO(OpShiftRightLogical) TODO(OpShiftRightArithmetic) TODO(OpShiftLeftLogical) TODO(OpBitwiseOr) TODO(OpBitwiseXor) TODO(OpBitwiseAnd) TODO(OpAny) TODO(OpAll) TODO(OpIsNan) TODO(OpIsInf) TODO(OpIsFinite) TODO(OpIsNormal) TODO(OpSignBitSet) TODO(OpLessOrGreater) TODO(OpOrdered) TODO(OpUnordered) TODO(OpLogicalOr) TODO(OpLogicalAnd) TODO(OpSelect) TODO(OpIEqual) TODO(OpFOrdEqual) TODO(OpFUnordEqual) TODO(OpINotEqual) TODO(OpFOrdNotEqual) TODO(OpFUnordNotEqual) TODO(OpULessThan) TODO(OpSLessThan) TODO(OpFOrdLessThan) TODO(OpFUnordLessThan) TODO(OpUGreaterThan) TODO(OpSGreaterThan) TODO(OpFOrdGreaterThan) TODO(OpFUnordGreaterThan) TODO(OpULessThanEqual) TODO(OpSLessThanEqual) TODO(OpFOrdLessThanEqual) TODO(OpFUnordLessThanEqual) TODO(OpUGreaterThanEqual) TODO(OpSGreaterThanEqual) TODO(OpFOrdGreaterThanEqual) TODO(OpFUnordGreaterThanEqual) TODO(OpDPdx) TODO(OpDPdy) TODO(OpFwidth) TODO(OpDPdxFine) TODO(OpDPdyFine) TODO(OpFwidthFine) TODO(OpDPdxCoarse) TODO(OpDPdyCoarse) TODO(OpFwidthCoarse) TODO(OpPhi) TODO(OpLoopMerge) TODO(OpSelectionMerge) TODO(OpBranch) TODO(OpBranchConditional) TODO(OpSwitch) CASE(OpReturnValue) TODO(OpLifetimeStart) TODO(OpLifetimeStop) TODO(OpAtomicLoad) TODO(OpAtomicStore) TODO(OpAtomicExchange) TODO(OpAtomicCompareExchange) TODO(OpAtomicCompareExchangeWeak) TODO(OpAtomicIIncrement) TODO(OpAtomicIDecrement) TODO(OpAtomicIAdd) TODO(OpAtomicISub) TODO(OpAtomicUMin) TODO(OpAtomicUMax) TODO(OpAtomicAnd) TODO(OpAtomicOr) TODO(OpAtomicSMin) TODO(OpAtomicSMax) TODO(OpEmitStreamVertex) TODO(OpEndStreamPrimitive) TODO(OpGroupAsyncCopy) TODO(OpGroupWaitEvents) TODO(OpGroupAll) TODO(OpGroupAny) TODO(OpGroupBroadcast) TODO(OpGroupIAdd) TODO(OpGroupFAdd) TODO(OpGroupFMin) TODO(OpGroupUMin) TODO(OpGroupSMin) TODO(OpGroupFMax) TODO(OpGroupUMax) TODO(OpGroupSMax) TODO(OpEnqueueMarker) TODO(OpEnqueueKernel) TODO(OpGetKernelNDrangeSubGroupCount) TODO(OpGetKernelNDrangeMaxSubGroupSize) TODO(OpGetKernelWorkGroupSize) TODO(OpGetKernelPreferredWorkGroupSizeMultiple) TODO(OpRetainEvent) TODO(OpReleaseEvent) TODO(OpCreateUserEvent) TODO(OpIsValidEvent) TODO(OpSetUserEventStatus) TODO(OpCaptureEventProfilingInfo) TODO(OpGetDefaultQueue) TODO(OpBuildNDRange) TODO(OpReadPipe) TODO(OpWritePipe) TODO(OpReservedReadPipe) TODO(OpReservedWritePipe) TODO(OpReserveReadPipePackets) TODO(OpReserveWritePipePackets) TODO(OpCommitReadPipe) TODO(OpCommitWritePipe) TODO(OpIsValidReserveId) TODO(OpGetNumPipePackets) TODO(OpGetMaxPipePackets) TODO(OpGroupReserveReadPipePackets) TODO(OpGroupReserveWritePipePackets) TODO(OpGroupCommitReadPipe) TODO(OpGroupCommitWritePipe) default: return true; } #undef TODO #undef CASE } } // anonymous namespace spv_result_t spvValidateInstructionIDs(const spv_instruction_t* pInsts, const uint64_t instCount, const spv_opcode_table opcodeTable, const spv_operand_table operandTable, const spv_ext_inst_table extInstTable, const libspirv::ValidationState_t& state, spv_position position, spv_diagnostic* pDiag) { idUsage idUsage(opcodeTable, operandTable, extInstTable, pInsts, instCount, state.usedefs(), state.entry_points(), position, pDiag); for (uint64_t instIndex = 0; instIndex < instCount; ++instIndex) { spvCheck(!idUsage.isValid(&pInsts[instIndex]), return SPV_ERROR_INVALID_ID); position->index += pInsts[instIndex].words.size(); } return SPV_SUCCESS; }