SPIRV-Tools/source/validate_id.cpp

2623 lines
92 KiB
C++
Raw Normal View History

// Copyright (c) 2015 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 <libspirv/libspirv.h>
#include "diagnostic.h"
#include "opcode.h"
#include "validate.h"
#include <assert.h>
#include <iostream>
#include <unordered_map>
#include <vector>
#define spvCheck(condition, action) \
if (condition) { \
action; \
}
namespace {
class idUsage {
public:
idUsage(const spv_opcode_table opcodeTable,
const spv_operand_table operandTable,
const spv_ext_inst_table extInstTable, const spv_id_info_t *pIdUses,
const uint64_t idUsesCount, const spv_id_info_t *pIdDefs,
const uint64_t idDefsCount, const spv_instruction_t *pInsts,
const uint64_t instCount, spv_position position,
spv_diagnostic *pDiagnostic)
: opcodeTable(opcodeTable),
operandTable(operandTable),
extInstTable(extInstTable),
firstInst(pInsts),
instCount(instCount),
position(position),
pDiagnostic(pDiagnostic) {
for (uint64_t idUsesIndex = 0; idUsesIndex < idUsesCount; ++idUsesIndex) {
idUses[pIdUses[idUsesIndex].id].push_back(pIdUses[idUsesIndex]);
}
for (uint64_t idDefsIndex = 0; idDefsIndex < idDefsCount; ++idDefsIndex) {
idDefs[pIdDefs[idDefsIndex].id] = pIdDefs[idDefsIndex];
}
}
bool isValid(const spv_instruction_t *inst);
template <Op>
bool isValid(const spv_instruction_t *inst, const spv_opcode_desc);
std::unordered_map<uint32_t, spv_id_info_t>::iterator find(
const uint32_t &id) {
return idDefs.find(id);
}
std::unordered_map<uint32_t, spv_id_info_t>::const_iterator find(
const uint32_t &id) const {
return idDefs.find(id);
}
bool found(std::unordered_map<uint32_t, spv_id_info_t>::iterator item) {
return idDefs.end() != item;
}
bool found(std::unordered_map<uint32_t, spv_id_info_t>::const_iterator item) {
return idDefs.end() != item;
}
std::unordered_map<uint32_t, std::vector<spv_id_info_t>>::iterator findUses(
const uint32_t &id) {
return idUses.find(id);
}
std::unordered_map<uint32_t, std::vector<spv_id_info_t>>::const_iterator
findUses(const uint32_t &id) const {
return idUses.find(id);
}
bool foundUses(
std::unordered_map<uint32_t, std::vector<spv_id_info_t>>::iterator item) {
return idUses.end() != item;
}
bool foundUses(std::unordered_map<
2015-09-14 14:05:37 +00:00
uint32_t, std::vector<spv_id_info_t>>::const_iterator item) {
return idUses.end() != item;
}
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;
std::unordered_map<uint32_t, std::vector<spv_id_info_t>> idUses;
std::unordered_map<uint32_t, spv_id_info_t> idDefs;
};
#define DIAG(INDEX) \
position->index += INDEX; \
DIAGNOSTIC
#if 0
template <>
bool idUsage::isValid<OpUndef>(const spv_instruction_t *inst,
const spv_opcode_desc) {
assert(0 && "Unimplemented!");
return false;
}
#endif
template <>
bool idUsage::isValid<OpName>(const spv_instruction_t *inst,
const spv_opcode_desc) {
auto targetIndex = 1;
auto target = find(inst->words[targetIndex]);
spvCheck(!found(target), DIAG(targetIndex) << "OpName Target <id> '"
<< inst->words[targetIndex]
<< "' is not defined.";
return false);
return true;
}
template <>
bool idUsage::isValid<OpMemberName>(const spv_instruction_t *inst,
const spv_opcode_desc) {
auto typeIndex = 1;
auto type = find(inst->words[typeIndex]);
spvCheck(!found(type), DIAG(typeIndex) << "OpMemberName Type <id> '"
<< inst->words[typeIndex]
<< "' is not defined.";
return false);
spvCheck(OpTypeStruct != type->second.opcode,
DIAG(typeIndex) << "OpMemberName Type <id> '"
<< inst->words[typeIndex]
<< "' is not a struct type.";
return false);
auto memberIndex = 2;
auto member = inst->words[memberIndex];
auto memberCount = (uint32_t)(type->second.inst->wordCount - 2);
spvCheck(memberCount <= member, DIAG(memberIndex)
<< "OpMemberName Member <id> '"
<< inst->words[memberIndex]
<< "' index is larger than Type <id> '"
<< type->second.id << "'s member count.";
return false);
return true;
}
template <>
bool idUsage::isValid<OpLine>(const spv_instruction_t *inst,
const spv_opcode_desc) {
auto targetIndex = 1;
auto target = find(inst->words[targetIndex]);
spvCheck(!found(target), DIAG(targetIndex) << "OpLine Target <id> '"
<< inst->words[targetIndex]
<< "' is not defined.";
return false);
auto fileIndex = 2;
auto file = find(inst->words[fileIndex]);
spvCheck(!found(file), DIAG(fileIndex) << "OpLine Target <id> '"
<< inst->words[fileIndex]
<< "' is not defined.";
return false);
spvCheck(OpString != file->second.opcode,
DIAG(fileIndex) << "OpLine Target <id> '" << inst->words[fileIndex]
<< "' is not an OpString.";
return false);
return true;
}
template <>
bool idUsage::isValid<OpDecorate>(const spv_instruction_t *inst,
const spv_opcode_desc) {
auto targetIndex = 1;
auto target = find(inst->words[targetIndex]);
spvCheck(!found(target), DIAG(targetIndex) << "OpDecorate Target <id> '"
<< inst->words[targetIndex]
<< "' is not defined.";
return false);
return true;
}
template <>
bool idUsage::isValid<OpMemberDecorate>(const spv_instruction_t *inst,
const spv_opcode_desc) {
auto structTypeIndex = 1;
auto structType = find(inst->words[structTypeIndex]);
spvCheck(!found(structType), DIAG(structTypeIndex)
<< "OpMemberDecorate Structure type <id> '"
<< inst->words[structTypeIndex]
<< "' is not defined.";
return false);
spvCheck(OpTypeStruct != structType->second.inst->opcode,
DIAG(structTypeIndex) << "OpMemberDecorate Structure type <id> '"
<< inst->words[structTypeIndex]
<< "' is not a struct type.";
return false);
auto memberIndex = 2;
auto member = inst->words[memberIndex];
auto memberCount = (uint32_t)(structType->second.inst->wordCount - 2);
spvCheck(memberCount < member, DIAG(memberIndex)
<< "OpMemberDecorate Structure type <id> '"
<< inst->words[memberIndex]
<< "' member count is less than Member";
return false);
return true;
}
template <>
bool idUsage::isValid<OpGroupDecorate>(const spv_instruction_t *inst,
const spv_opcode_desc) {
auto decorationGroupIndex = 1;
auto decorationGroup = find(inst->words[decorationGroupIndex]);
spvCheck(!found(decorationGroup),
DIAG(decorationGroupIndex)
<< "OpGroupDecorate Decoration group <id> '"
<< inst->words[decorationGroupIndex] << "' is not defined.";
return false);
spvCheck(OpDecorationGroup != decorationGroup->second.opcode,
DIAG(decorationGroupIndex)
<< "OpGroupDecorate Decoration group <id> '"
<< inst->words[decorationGroupIndex]
<< "' is not a decoration group.";
return false);
for (uint64_t targetIndex = 2; targetIndex < inst->wordCount; ++targetIndex) {
auto target = find(inst->words[targetIndex]);
spvCheck(!found(target), DIAG(targetIndex)
<< "OpGroupDecorate Target <id> '"
<< inst->words[targetIndex]
<< "' is not defined.";
return false);
}
return true;
}
#if 0
template <>
bool idUsage::isValid<OpGroupMemberDecorate>(
const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
#endif
#if 0
template <>
bool idUsage::isValid<OpExtInst>(const spv_instruction_t *inst,
const spv_opcode_desc opcodeEntry) {}
#endif
template <>
bool idUsage::isValid<OpEntryPoint>(const spv_instruction_t *inst,
const spv_opcode_desc) {
auto entryPointIndex = 2;
auto entryPoint = find(inst->words[entryPointIndex]);
spvCheck(!found(entryPoint), DIAG(entryPointIndex)
<< "OpEntryPoint Entry Point <id> '"
<< inst->words[entryPointIndex]
<< "' is not defined.";
return false);
spvCheck(OpFunction != entryPoint->second.opcode,
DIAG(entryPointIndex) << "OpEntryPoint Entry Point <id> '"
<< inst->words[entryPointIndex]
<< "' is not a function.";
return false);
// TODO: Check the entry point signature is void main(void), may be subject
// to change
auto entryPointType = find(entryPoint->second.inst->words[4]);
spvCheck(!found(entryPointType), assert(0 && "Unreachable!"));
spvCheck(3 != entryPointType->second.inst->wordCount,
DIAG(entryPointIndex) << "OpEntryPoint Entry Point <id> '"
<< inst->words[entryPointIndex]
<< "'s function parameter count is not zero.";
return false);
auto returnType = find(entryPoint->second.inst->words[1]);
spvCheck(!found(returnType), assert(0 && "Unreachable!"));
spvCheck(OpTypeVoid != returnType->second.opcode,
DIAG(entryPointIndex) << "OpEntryPoint Entry Point <id> '"
<< inst->words[entryPointIndex]
<< "'s function return type is not void.";
return false);
return true;
}
template <>
bool idUsage::isValid<OpExecutionMode>(const spv_instruction_t *inst,
const spv_opcode_desc) {
auto entryPointIndex = 1;
auto entryPoint = find(inst->words[entryPointIndex]);
spvCheck(!found(entryPoint), DIAG(entryPointIndex)
<< "OpExecutionMode Entry Point <id> '"
<< inst->words[entryPointIndex]
<< "' is not defined.";
return false);
auto entryPointUses = findUses(inst->words[entryPointIndex]);
spvCheck(!foundUses(entryPointUses), assert(0 && "Unreachable!"));
bool foundEntryPointUse = false;
for (auto use : entryPointUses->second) {
if (OpEntryPoint == use.opcode) {
foundEntryPointUse = true;
}
}
spvCheck(!foundEntryPointUse, DIAG(entryPointIndex)
<< "OpExecutionMode Entry Point <id> '"
<< inst->words[entryPointIndex]
<< "' is not the Entry Point "
"operand of an OpEntryPoint.";
return false);
return true;
}
template <>
bool idUsage::isValid<OpTypeVector>(const spv_instruction_t *inst,
const spv_opcode_desc) {
auto componentIndex = 2;
auto componentType = find(inst->words[componentIndex]);
spvCheck(!found(componentType), DIAG(componentIndex)
<< "OpTypeVector Component Type <id> '"
<< inst->words[componentIndex]
<< "' is not defined.";
return false);
spvCheck(!spvOpcodeIsScalarType(componentType->second.opcode),
DIAG(componentIndex) << "OpTypeVector Component Type <id> '"
<< inst->words[componentIndex]
<< "' is not a scalar type.";
return false);
return true;
}
template <>
bool idUsage::isValid<OpTypeMatrix>(const spv_instruction_t *inst,
const spv_opcode_desc) {
auto columnTypeIndex = 2;
auto columnType = find(inst->words[columnTypeIndex]);
spvCheck(!found(columnType), DIAG(columnTypeIndex)
<< "OpTypeMatrix Column Type <id> '"
<< inst->words[columnTypeIndex]
<< "' is not defined.";
return false);
spvCheck(OpTypeVector != columnType->second.opcode,
DIAG(columnTypeIndex) << "OpTypeMatrix Column Type <id> '"
<< inst->words[columnTypeIndex]
<< "' is not a vector.";
return false);
return true;
}
template <>
Use opcode operand definitions from SPIR-V specification generator. The assembler and disassembler now use a dynamically adjusted sequence of expected operand types. (Internally, it is a deque, for readability.) Both parsers repeatedly pull an expected operand type from the left of this pattern list, and try to match the next input token against it. The expected pattern is adjusted during the parse to accommodate: - an extended instruction's expected operands, depending on the extended instruction's index. - when an operand itself has operands - to handle sequences of zero or more operands, or pairs of operands. These are expanded lazily during the parse. Adds spv::OperandClass from the SPIR-V specification generator. Modifies spv_operand_desc_t: - adds hasResult, hasType, and operandClass array to the opcode description type. - "wordCount" is replaced with "numTypes", which counts the number of entries in operandTypes. And each of those describes a *logical* operand, including the type id for the instruction, and the result id for the instruction. A logical operand could be variable-width, such as a literal string. Adds opcode.inc, an automatically-generated table of operation descriptions, with one line to describe each core instruction. Externally, we have modified the SPIR-V spec doc generator to emit this file. (We have hacked this copy to use the old semantics for OpLine.) Inside the assembler, parsing an operand may fail with new error code SPV_FAIL_MATCH. For an optional operand, this is not fatal, but should trigger backtracking at a higher level. The spvTextIsStartOfNewInst checks the case of the third letter of what might be an opcode. So now, "OpenCL" does not look like an opcode name. In assembly, the EntryPoint name field is mandatory, but can be an empty string. Adjust tests for changes to: - OpSampedImage - OpTypeSampler
2015-08-27 17:03:52 +00:00
bool idUsage::isValid<OpTypeSampler>(const spv_instruction_t *,
const spv_opcode_desc) {
Use opcode operand definitions from SPIR-V specification generator. The assembler and disassembler now use a dynamically adjusted sequence of expected operand types. (Internally, it is a deque, for readability.) Both parsers repeatedly pull an expected operand type from the left of this pattern list, and try to match the next input token against it. The expected pattern is adjusted during the parse to accommodate: - an extended instruction's expected operands, depending on the extended instruction's index. - when an operand itself has operands - to handle sequences of zero or more operands, or pairs of operands. These are expanded lazily during the parse. Adds spv::OperandClass from the SPIR-V specification generator. Modifies spv_operand_desc_t: - adds hasResult, hasType, and operandClass array to the opcode description type. - "wordCount" is replaced with "numTypes", which counts the number of entries in operandTypes. And each of those describes a *logical* operand, including the type id for the instruction, and the result id for the instruction. A logical operand could be variable-width, such as a literal string. Adds opcode.inc, an automatically-generated table of operation descriptions, with one line to describe each core instruction. Externally, we have modified the SPIR-V spec doc generator to emit this file. (We have hacked this copy to use the old semantics for OpLine.) Inside the assembler, parsing an operand may fail with new error code SPV_FAIL_MATCH. For an optional operand, this is not fatal, but should trigger backtracking at a higher level. The spvTextIsStartOfNewInst checks the case of the third letter of what might be an opcode. So now, "OpenCL" does not look like an opcode name. In assembly, the EntryPoint name field is mandatory, but can be an empty string. Adjust tests for changes to: - OpSampedImage - OpTypeSampler
2015-08-27 17:03:52 +00:00
// OpTypeSampler takes no arguments in Rev31 and beyond.
return true;
}
template <>
bool idUsage::isValid<OpTypeArray>(const spv_instruction_t *inst,
const spv_opcode_desc) {
auto elementTypeIndex = 2;
auto elementType = find(inst->words[elementTypeIndex]);
spvCheck(!found(elementType), DIAG(elementTypeIndex)
<< "OpTypeArray Element Type <id> '"
<< inst->words[elementTypeIndex]
<< "' is not defined.";
return false);
spvCheck(!spvOpcodeIsType(elementType->second.opcode),
DIAG(elementTypeIndex) << "OpTypeArray Element Type <id> '"
<< inst->words[elementTypeIndex]
<< "' is not a type.";
return false);
auto lengthIndex = 3;
auto length = find(inst->words[lengthIndex]);
spvCheck(!found(length), DIAG(lengthIndex) << "OpTypeArray Length <id> '"
<< inst->words[lengthIndex]
<< "' is not defined.";
return false);
spvCheck(OpConstant != length->second.opcode &&
OpSpecConstant != length->second.opcode,
DIAG(lengthIndex) << "OpTypeArray Length <id> '"
<< inst->words[lengthIndex]
<< "' is not a scalar constant type.";
return false);
// NOTE: Check the initialiser value of the constant
auto constInst = length->second.inst;
auto constResultTypeIndex = 1;
auto constResultType = find(constInst->words[constResultTypeIndex]);
spvCheck(!found(constResultType), DIAG(lengthIndex)
<< "OpTypeArray Length <id> '"
<< inst->words[constResultTypeIndex]
<< "' result type is not defined.";
return false);
spvCheck(OpTypeInt != constResultType->second.opcode,
DIAG(lengthIndex) << "OpTypeArray Length <id> '"
<< inst->words[lengthIndex]
<< "' is not a constant integer type.";
return false);
if (4 == constInst->wordCount) {
spvCheck(1 > constInst->words[3], DIAG(lengthIndex)
<< "OpTypeArray Length <id> '"
<< inst->words[lengthIndex]
<< "' value must be at least 1.";
return false);
} else if (5 == constInst->wordCount) {
uint64_t value =
constInst->words[3] | ((uint64_t)constInst->words[4]) << 32;
bool signedness = constResultType->second.inst->words[3];
if (signedness) {
spvCheck(1 > (int64_t)value, DIAG(lengthIndex)
<< "OpTypeArray Length <id> '"
<< inst->words[lengthIndex]
<< "' value must be at least 1.";
return false);
} else {
spvCheck(1 > value, DIAG(lengthIndex) << "OpTypeArray Length <id> '"
<< inst->words[lengthIndex]
<< "' value must be at least 1.";
return false);
}
}
return true;
}
template <>
bool idUsage::isValid<OpTypeRuntimeArray>(const spv_instruction_t *inst,
const spv_opcode_desc) {
auto elementTypeIndex = 2;
auto elementType = find(inst->words[elementTypeIndex]);
spvCheck(!found(elementType), DIAG(elementTypeIndex)
<< "OpTypeRuntimeArray Element Type <id> '"
<< inst->words[elementTypeIndex]
<< "' is not defined.";
return false);
spvCheck(!spvOpcodeIsType(elementType->second.opcode),
DIAG(elementTypeIndex) << "OpTypeRuntimeArray Element Type <id> '"
<< inst->words[elementTypeIndex]
<< "' is not a type.";
return false);
return true;
}
template <>
bool idUsage::isValid<OpTypeStruct>(const spv_instruction_t *inst,
const spv_opcode_desc) {
for (uint64_t memberTypeIndex = 2; memberTypeIndex < inst->wordCount;
++memberTypeIndex) {
auto memberType = find(inst->words[memberTypeIndex]);
spvCheck(!found(memberType), DIAG(memberTypeIndex)
<< "OpTypeStruct Member Type <id> '"
<< inst->words[memberTypeIndex]
<< "' is not defined.";
return false);
spvCheck(!spvOpcodeIsType(memberType->second.opcode),
DIAG(memberTypeIndex) << "OpTypeStruct Member Type <id> '"
<< inst->words[memberTypeIndex]
<< "' is not a type.";
return false);
}
return true;
}
template <>
bool idUsage::isValid<OpTypePointer>(const spv_instruction_t *inst,
const spv_opcode_desc) {
auto typeIndex = 3;
auto type = find(inst->words[typeIndex]);
spvCheck(!found(type), DIAG(typeIndex) << "OpTypePointer Type <id> '"
<< inst->words[typeIndex]
<< "' is not defined.";
return false);
spvCheck(!spvOpcodeIsType(type->second.opcode),
DIAG(typeIndex) << "OpTypePointer Type <id> '"
<< inst->words[typeIndex] << "' is not a type.";
return false);
return true;
}
template <>
bool idUsage::isValid<OpTypeFunction>(const spv_instruction_t *inst,
const spv_opcode_desc) {
auto returnTypeIndex = 2;
auto returnType = find(inst->words[returnTypeIndex]);
spvCheck(!found(returnType), DIAG(returnTypeIndex)
<< "OpTypeFunction Return Type <id> '"
<< inst->words[returnTypeIndex]
<< "' is not defined";
return false);
spvCheck(!spvOpcodeIsType(returnType->second.opcode),
DIAG(returnTypeIndex) << "OpTypeFunction Return Type <id> '"
<< inst->words[returnTypeIndex]
<< "' is not a type.";
return false);
for (uint64_t paramTypeIndex = 3; paramTypeIndex < inst->wordCount;
++paramTypeIndex) {
auto paramType = find(inst->words[paramTypeIndex]);
spvCheck(!found(paramType), DIAG(paramTypeIndex)
<< "OpTypeFunction Parameter Type <id> '"
<< inst->words[paramTypeIndex]
<< "' is not defined.";
return false);
spvCheck(!spvOpcodeIsType(paramType->second.opcode),
DIAG(paramTypeIndex) << "OpTypeFunction Parameter Type <id> '"
<< inst->words[paramTypeIndex]
<< "' is not a type.";
return false);
}
return true;
}
template <>
bool idUsage::isValid<OpTypePipe>(const spv_instruction_t *inst,
const spv_opcode_desc) {
auto typeIndex = 2;
auto type = find(inst->words[typeIndex]);
spvCheck(!found(type), DIAG(typeIndex) << "OpTypePipe Type <id> '"
<< inst->words[typeIndex]
<< "' is not defined.";
return false);
spvCheck(!spvOpcodeIsType(type->second.opcode),
DIAG(typeIndex) << "OpTypePipe Type <id> '" << inst->words[typeIndex]
<< "' is not a type.";
return false);
return true;
}
template <>
bool idUsage::isValid<OpConstantTrue>(const spv_instruction_t *inst,
const spv_opcode_desc) {
auto resultTypeIndex = 1;
auto resultType = find(inst->words[resultTypeIndex]);
spvCheck(!found(resultType), DIAG(resultTypeIndex)
<< "OpConstantTrue Result Type <id> '"
<< inst->words[resultTypeIndex]
<< "' is not defined.";
return false);
spvCheck(OpTypeBool != resultType->second.opcode,
DIAG(resultTypeIndex) << "OpConstantTrue Result Type <id> '"
<< inst->words[resultTypeIndex]
<< "' is not a boolean type.";
return false);
return true;
}
template <>
bool idUsage::isValid<OpConstantFalse>(const spv_instruction_t *inst,
const spv_opcode_desc) {
auto resultTypeIndex = 1;
auto resultType = find(inst->words[resultTypeIndex]);
spvCheck(!found(resultType), DIAG(resultTypeIndex)
<< "OpConstantFalse Result Type <id> '"
<< inst->words[resultTypeIndex]
<< "' is not defined.";
return false);
spvCheck(OpTypeBool != resultType->second.opcode,
DIAG(resultTypeIndex) << "OpConstantFalse Result Type <id> '"
<< inst->words[resultTypeIndex]
<< "' is not a boolean type.";
return false);
return true;
}
template <>
bool idUsage::isValid<OpConstant>(const spv_instruction_t *inst,
const spv_opcode_desc) {
auto resultTypeIndex = 1;
auto resultType = find(inst->words[resultTypeIndex]);
spvCheck(!found(resultType), DIAG(resultTypeIndex)
<< "OpConstant Result Type <id> '"
<< inst->words[resultTypeIndex]
<< "' is not defined.";
return false);
spvCheck(!spvOpcodeIsScalarType(resultType->second.opcode),
DIAG(resultTypeIndex)
<< "OpConstant Result Type <id> '"
<< inst->words[resultTypeIndex]
<< "' is not a scalar integer or floating point type.";
return false);
return true;
}
template <>
bool idUsage::isValid<OpConstantComposite>(const spv_instruction_t *inst,
const spv_opcode_desc) {
auto resultTypeIndex = 1;
auto resultType = find(inst->words[resultTypeIndex]);
spvCheck(!found(resultType), DIAG(resultTypeIndex)
<< "OpConstantComposite Result Type <id> '"
<< inst->words[resultTypeIndex]
<< "' is not defined.";
return false);
spvCheck(!spvOpcodeIsComposite(resultType->second.opcode),
DIAG(resultTypeIndex) << "OpConstantComposite Result Type <id> '"
<< inst->words[resultTypeIndex]
<< "' is not a composite type.";
return false);
uint32_t constituentCount = inst->wordCount - 3;
switch (resultType->second.opcode) {
case OpTypeVector: {
auto componentCount = resultType->second.inst->words[3];
spvCheck(
componentCount != constituentCount,
// TODO: Output ID's on diagnostic
DIAG(inst->wordCount - 1)
<< "OpConstantComposite Constituent <id> count does not match "
2015-09-14 14:05:37 +00:00
"Result Type <id> '"
<< resultType->second.id << "'s vector component count.";
return false);
auto componentType = find(resultType->second.inst->words[2]);
spvCheck(!found(componentType), assert(0 && "Unreachable!"));
for (uint64_t constituentIndex = 3; constituentIndex < inst->wordCount;
constituentIndex++) {
auto constituent = find(inst->words[constituentIndex]);
spvCheck(!found(constituent), assert(0 && "Unreachable!"));
spvCheck(!spvOpcodeIsConstant(constituent->second.opcode),
DIAG(constituentIndex)
<< "OpConstantComposite Constituent <id> '"
<< inst->words[constituentIndex] << "' is not a constant.";
return false);
auto constituentResultType = find(constituent->second.inst->words[1]);
spvCheck(!found(constituentResultType), assert(0 && "Unreachable!"));
spvCheck(componentType->second.opcode !=
constituentResultType->second.opcode,
DIAG(constituentIndex)
<< "OpConstantComposite Constituent <id> '"
<< inst->words[constituentIndex]
<< "'s type does not match Result Type <id> '"
<< resultType->second.id << "'s vector element type.";
return false);
}
} break;
case OpTypeMatrix: {
auto columnCount = resultType->second.inst->words[3];
spvCheck(
columnCount != constituentCount,
// TODO: Output ID's on diagnostic
DIAG(inst->wordCount - 1)
<< "OpConstantComposite Constituent <id> count does not match "
2015-09-14 14:05:37 +00:00
"Result Type <id> '"
<< resultType->second.id << "'s matrix column count.";
return false);
auto columnType = find(resultType->second.inst->words[2]);
spvCheck(!found(columnType), assert(0 && "Unreachable!"));
auto componentCount = columnType->second.inst->words[3];
auto componentType = find(columnType->second.inst->words[2]);
spvCheck(!found(componentType), assert(0 && "Unreachable!"));
for (uint64_t constituentIndex = 3; constituentIndex < inst->wordCount;
constituentIndex++) {
auto constituent = find(inst->words[constituentIndex]);
spvCheck(!found(constituent),
DIAG(constituentIndex)
<< "OpConstantComposite Constituent <id> '"
<< inst->words[constituentIndex] << "' is not defined.";
return false);
spvCheck(OpConstantComposite != constituent->second.opcode,
DIAG(constituentIndex)
<< "OpConstantComposite Constituent <id> '"
<< inst->words[constituentIndex]
<< "' is not a constant composite.";
return false);
auto vector = find(constituent->second.inst->words[1]);
spvCheck(!found(vector), assert(0 && "Unreachable!"));
spvCheck(columnType->second.opcode != vector->second.opcode,
DIAG(constituentIndex)
<< "OpConstantComposite Constituent <id> '"
<< inst->words[constituentIndex]
<< "' type does not match Result Type <id> '"
<< resultType->second.id << "'s matrix column type.";
return false);
auto vectorComponentType = find(vector->second.inst->words[2]);
spvCheck(!found(vectorComponentType), assert(0 && "Unreachable!"));
spvCheck(!spvOpcodeAreTypesEqual(componentType->second.inst,
vectorComponentType->second.inst),
DIAG(constituentIndex)
<< "OpConstantComposite Constituent <id> '"
<< inst->words[constituentIndex]
<< "' component type does not match Result Type <id> '"
<< resultType->second.id
<< "'s matrix column component type.";
return false);
spvCheck(
componentCount != vector->second.inst->words[3],
DIAG(constituentIndex)
<< "OpConstantComposite Constituent <id> '"
<< inst->words[constituentIndex]
<< "' vector component count does not match Result Type <id> '"
<< resultType->second.id << "'s vector component count.";
return false);
}
} break;
case OpTypeArray: {
auto elementType = find(resultType->second.inst->words[2]);
spvCheck(!found(elementType), assert(0 && "Unreachable!"));
auto length = find(resultType->second.inst->words[3]);
spvCheck(!found(length), assert(0 && "Unreachable!"));
spvCheck(length->second.inst->words[3] != constituentCount,
DIAG(inst->wordCount - 1)
<< "OpConstantComposite Constituent count does not match "
2015-09-14 14:05:37 +00:00
"Result Type <id> '"
<< resultType->second.id << "'s array length.";
return false);
for (uint64_t constituentIndex = 3; constituentIndex < inst->wordCount;
constituentIndex++) {
auto constituent = find(inst->words[constituentIndex]);
spvCheck(!found(constituent),
DIAG(constituentIndex)
<< "OpConstantComposite Constituent <id> '"
<< inst->words[constituentIndex] << "' is not defined.";
return false);
spvCheck(!spvOpcodeIsConstant(constituent->second.opcode),
DIAG(constituentIndex)
<< "OpConstantComposite Constituent <id> '"
<< inst->words[constituentIndex] << "' is not a constant.";
return false);
auto constituentType = find(constituent->second.inst->words[1]);
spvCheck(!found(constituentType), assert(0 && "Unreachable!"));
spvCheck(!spvOpcodeAreTypesEqual(elementType->second.inst,
constituentType->second.inst),
DIAG(constituentIndex)
<< "OpConstantComposite Constituent <id> '"
<< inst->words[constituentIndex]
<< "'s type does not match Result Type <id> '"
<< resultType->second.id << "'s array element type.";
return false);
}
} break;
case OpTypeStruct: {
uint32_t memberCount = resultType->second.inst->wordCount - 2;
spvCheck(memberCount != constituentCount,
DIAG(resultTypeIndex)
<< "OpConstantComposite Constituent <id> '"
<< inst->words[resultTypeIndex]
<< "' count does not match Result Type <id> '"
<< resultType->second.id << "'s struct member count.";
return false);
for (uint32_t constituentIndex = 3, memberIndex = 2;
constituentIndex < inst->wordCount;
constituentIndex++, memberIndex++) {
auto constituent = find(inst->words[constituentIndex]);
spvCheck(!found(constituent),
DIAG(constituentIndex)
<< "OpConstantComposite Constituent <id> '"
<< inst->words[constituentIndex] << "' is not define.";
return false);
spvCheck(!spvOpcodeIsConstant(constituent->second.opcode),
DIAG(constituentIndex)
<< "OpConstantComposite Constituent <id> '"
<< inst->words[constituentIndex] << "' is not a constant.";
return false);
auto constituentType = find(constituent->second.inst->words[1]);
spvCheck(!found(constituentType), assert(0 && "Unreachable!"));
auto memberType = find(resultType->second.inst->words[memberIndex]);
spvCheck(!found(memberType), assert(0 && "Unreachable!"));
spvCheck(!spvOpcodeAreTypesEqual(memberType->second.inst,
constituentType->second.inst),
DIAG(constituentIndex)
<< "OpConstantComposite Constituent <id> '"
<< inst->words[constituentIndex]
<< "' type does not match the Result Type <id> '"
<< resultType->second.id << "'s member type.";
return false);
}
} break;
default: { assert(0 && "Unreachable!"); } break;
}
return true;
}
template <>
bool idUsage::isValid<OpConstantSampler>(const spv_instruction_t *inst,
const spv_opcode_desc) {
auto resultTypeIndex = 1;
auto resultType = find(inst->words[resultTypeIndex]);
spvCheck(!found(resultType), DIAG(resultTypeIndex)
<< "OpConstantSampler Result Type <id> '"
<< inst->words[resultTypeIndex]
<< "' is not defined.";
return false);
spvCheck(OpTypeSampler != resultType->second.opcode,
DIAG(resultTypeIndex) << "OpConstantSampler Result Type <id> '"
<< inst->words[resultTypeIndex]
<< "' is not a sampler type.";
return false);
return true;
}
template <>
bool idUsage::isValid<OpConstantNull>(const spv_instruction_t *inst,
const spv_opcode_desc) {
auto resultTypeIndex = 1;
auto resultType = find(inst->words[resultTypeIndex]);
spvCheck(!found(resultType), DIAG(resultTypeIndex)
<< "OpConstantNull Result Type <id> '"
<< inst->words[resultTypeIndex]
<< "' is not defined.";
return false);
switch (resultType->second.inst->opcode) {
default: {
spvCheck(!spvOpcodeIsBasicTypeNullable(resultType->second.inst->opcode),
DIAG(resultTypeIndex) << "OpConstantNull Result Type <id> '"
<< inst->words[resultTypeIndex]
<< "' can not be null.";
return false);
} break;
case OpTypeVector: {
auto type = find(resultType->second.inst->words[2]);
spvCheck(!found(type), assert(0 && "Unreachable!"));
spvCheck(!spvOpcodeIsBasicTypeNullable(type->second.inst->opcode),
DIAG(resultTypeIndex)
<< "OpConstantNull Result Type <id> '"
<< inst->words[resultTypeIndex]
<< "'s vector component type can not be null.";
return false);
} break;
case OpTypeArray: {
auto type = find(resultType->second.inst->words[2]);
spvCheck(!found(type), assert(0 && "Unreachable!"));
spvCheck(!spvOpcodeIsBasicTypeNullable(type->second.inst->opcode),
DIAG(resultTypeIndex)
<< "OpConstantNull Result Type <id> '"
<< inst->words[resultTypeIndex]
<< "'s array element type can not be null.";
return false);
} break;
case OpTypeMatrix: {
auto columnType = find(resultType->second.inst->words[2]);
spvCheck(!found(columnType), assert(0 && "Unreachable!"));
auto type = find(columnType->second.inst->words[2]);
spvCheck(!found(type), assert(0 && "Unreachable!"));
spvCheck(!spvOpcodeIsBasicTypeNullable(type->second.inst->opcode),
DIAG(resultTypeIndex)
<< "OpConstantNull Result Type <id> '"
<< inst->words[resultTypeIndex]
<< "'s matrix component type cna not be null.";
return false);
} break;
case OpTypeStruct: {
for (uint64_t elementIndex = 2;
elementIndex < resultType->second.inst->wordCount; ++elementIndex) {
auto element = find(resultType->second.inst->words[elementIndex]);
spvCheck(!found(element), assert(0 && "Unreachable!"));
spvCheck(!spvOpcodeIsBasicTypeNullable(element->second.inst->opcode),
DIAG(resultTypeIndex)
<< "OpConstantNull Result Type <id> '"
<< inst->words[resultTypeIndex]
<< "'s struct element type can not be null.";
return false);
}
} break;
}
return true;
}
template <>
bool idUsage::isValid<OpSpecConstantTrue>(const spv_instruction_t *inst,
const spv_opcode_desc) {
auto resultTypeIndex = 1;
auto resultType = find(inst->words[resultTypeIndex]);
spvCheck(!found(resultType), DIAG(resultTypeIndex)
<< "OpSpecConstantTrue Result Type <id> '"
<< inst->words[resultTypeIndex]
<< "' is not defined.";
return false);
spvCheck(OpTypeBool != resultType->second.opcode,
DIAG(resultTypeIndex) << "OpSpecConstantTrue Result Type <id> '"
<< inst->words[resultTypeIndex]
<< "' is not a boolean type.";
return false);
return true;
}
template <>
bool idUsage::isValid<OpSpecConstantFalse>(const spv_instruction_t *inst,
const spv_opcode_desc) {
auto resultTypeIndex = 1;
auto resultType = find(inst->words[resultTypeIndex]);
spvCheck(!found(resultType), DIAG(resultTypeIndex)
<< "OpSpecConstantFalse Result Type <id> '"
<< inst->words[resultTypeIndex]
<< "' is not defined.";
return false);
spvCheck(OpTypeBool != resultType->second.opcode,
DIAG(resultTypeIndex) << "OpSpecConstantFalse Result Type <id> '"
<< inst->words[resultTypeIndex]
<< "' is not a boolean type.";
return false);
return true;
}
template <>
bool idUsage::isValid<OpSpecConstant>(const spv_instruction_t *inst,
const spv_opcode_desc) {
auto resultTypeIndex = 1;
auto resultType = find(inst->words[resultTypeIndex]);
spvCheck(!found(resultType), DIAG(resultTypeIndex)
<< "OpSpecConstant Result Type <id> '"
<< inst->words[resultTypeIndex]
<< "' is not defined.";
return false);
spvCheck(!spvOpcodeIsScalarType(resultType->second.opcode),
DIAG(resultTypeIndex) << "OpSpecConstant Result Type <id> '"
<< inst->words[resultTypeIndex]
<< "' is not a scalar type.";
return false);
return true;
}
#if 0
template <>
bool idUsage::isValid<OpSpecConstantComposite>(
const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
#endif
#if 0
template <>
bool idUsage::isValid<OpSpecConstantOp>(const spv_instruction_t *inst) {}
#endif
template <>
bool idUsage::isValid<OpVariable>(const spv_instruction_t *inst,
const spv_opcode_desc opcodeEntry) {
auto resultTypeIndex = 1;
auto resultType = find(inst->words[resultTypeIndex]);
spvCheck(!found(resultType), DIAG(resultTypeIndex)
<< "OpVariable Result Type <id> '"
<< inst->words[resultTypeIndex]
<< "' is not defined.";
return false);
spvCheck(OpTypePointer != resultType->second.opcode,
DIAG(resultTypeIndex) << "OpVariable Result Type <id> '"
<< inst->words[resultTypeIndex]
<< "' is not a pointer type.";
return false);
Use opcode operand definitions from SPIR-V specification generator. The assembler and disassembler now use a dynamically adjusted sequence of expected operand types. (Internally, it is a deque, for readability.) Both parsers repeatedly pull an expected operand type from the left of this pattern list, and try to match the next input token against it. The expected pattern is adjusted during the parse to accommodate: - an extended instruction's expected operands, depending on the extended instruction's index. - when an operand itself has operands - to handle sequences of zero or more operands, or pairs of operands. These are expanded lazily during the parse. Adds spv::OperandClass from the SPIR-V specification generator. Modifies spv_operand_desc_t: - adds hasResult, hasType, and operandClass array to the opcode description type. - "wordCount" is replaced with "numTypes", which counts the number of entries in operandTypes. And each of those describes a *logical* operand, including the type id for the instruction, and the result id for the instruction. A logical operand could be variable-width, such as a literal string. Adds opcode.inc, an automatically-generated table of operation descriptions, with one line to describe each core instruction. Externally, we have modified the SPIR-V spec doc generator to emit this file. (We have hacked this copy to use the old semantics for OpLine.) Inside the assembler, parsing an operand may fail with new error code SPV_FAIL_MATCH. For an optional operand, this is not fatal, but should trigger backtracking at a higher level. The spvTextIsStartOfNewInst checks the case of the third letter of what might be an opcode. So now, "OpenCL" does not look like an opcode name. In assembly, the EntryPoint name field is mandatory, but can be an empty string. Adjust tests for changes to: - OpSampedImage - OpTypeSampler
2015-08-27 17:03:52 +00:00
if (opcodeEntry->numTypes < inst->wordCount) {
auto initialiserIndex = 4;
auto initialiser = find(inst->words[initialiserIndex]);
spvCheck(!found(initialiser), DIAG(initialiserIndex)
<< "OpVariable Initializer <id> '"
<< inst->words[initialiserIndex]
<< "' is not defined.";
return false);
spvCheck(!spvOpcodeIsConstant(initialiser->second.opcode),
DIAG(initialiserIndex) << "OpVariable Initializer <id> '"
<< inst->words[initialiserIndex]
<< "' is not a constant.";
return false);
}
return true;
}
template <>
bool idUsage::isValid<OpLoad>(const spv_instruction_t *inst,
const spv_opcode_desc) {
auto resultTypeIndex = 1;
auto resultType = find(inst->words[resultTypeIndex]);
spvCheck(!found(resultType), DIAG(resultTypeIndex)
<< "OpLoad Result Type <id> '"
<< inst->words[resultTypeIndex]
<< "' is not defind.";
return false);
auto pointerIndex = 3;
auto pointer = find(inst->words[pointerIndex]);
spvCheck(!found(pointer), DIAG(pointerIndex) << "OpLoad Pointer <id> '"
<< inst->words[pointerIndex]
<< "' is not defined.";
return false);
spvCheck(!spvOpcodeIsPointer(pointer->second.opcode),
DIAG(pointerIndex) << "OpLoad Pointer <id> '"
<< inst->words[pointerIndex]
<< "' is not a pointer.";
return false);
auto type = find(pointer->second.inst->words[1]);
spvCheck(!found(type), assert(0 && "Unreachable!"));
spvCheck(resultType != type, DIAG(resultTypeIndex)
<< "OpLoad Result Type <id> '"
<< inst->words[resultTypeIndex]
<< " does not match Pointer <id> '"
<< pointer->second.id << "'s type.";
return false);
return true;
}
template <>
bool idUsage::isValid<OpStore>(const spv_instruction_t *inst,
const spv_opcode_desc) {
auto pointerIndex = 1;
auto pointer = find(inst->words[pointerIndex]);
spvCheck(!found(pointer), DIAG(pointerIndex) << "OpStore Pointer <id> '"
<< inst->words[pointerIndex]
<< "' is not defined.";
return false);
spvCheck(!spvOpcodeIsPointer(pointer->second.opcode),
DIAG(pointerIndex) << "OpStore Pointer <id> '"
<< inst->words[pointerIndex]
<< "' is not a pointer.";
return false);
auto pointerType = find(pointer->second.inst->words[1]);
spvCheck(!found(pointerType), assert(0 && "Unreachable!"));
auto type = find(pointerType->second.inst->words[3]);
spvCheck(!found(type), assert(0 && "Unreachable!"));
spvCheck(OpTypeVoid == type->second.opcode, DIAG(pointerIndex)
<< "OpStore Pointer <id> '"
<< inst->words[pointerIndex]
<< "'s type is void.";
return false);
auto objectIndex = 2;
auto object = find(inst->words[objectIndex]);
spvCheck(!found(object), DIAG(objectIndex) << "OpStore Object <id> '"
<< inst->words[objectIndex]
<< "' is not defined.";
return false);
spvCheck(!spvOpcodeIsObject(object->second.opcode),
DIAG(objectIndex) << "OpStore Object <id> '"
<< inst->words[objectIndex]
<< "' in not an object.";
return false);
auto objectType = find(object->second.inst->words[1]);
spvCheck(!found(objectType), assert(0 && "Unreachable!"));
spvCheck(OpTypeVoid == objectType->second.opcode,
DIAG(objectIndex) << "OpStore Object <id> '"
<< inst->words[objectIndex] << "'s type is void.";
return false);
spvCheck(!spvOpcodeAreTypesEqual(type->second.inst, objectType->second.inst),
DIAG(pointerIndex) << "OpStore Pointer <id> '"
<< inst->words[pointerIndex]
<< "'s type does not match Object <id> '"
<< objectType->second.id << "'s type.";
return false);
return true;
}
template <>
bool idUsage::isValid<OpCopyMemory>(const spv_instruction_t *inst,
const spv_opcode_desc) {
auto targetIndex = 1;
auto target = find(inst->words[targetIndex]);
spvCheck(!found(target), DIAG(targetIndex) << "OpCopyMemory Target <id> '"
<< inst->words[targetIndex]
<< "' is not defined.";
return false);
auto sourceIndex = 2;
auto source = find(inst->words[sourceIndex]);
spvCheck(!found(source), DIAG(targetIndex) << "OpCopyMemory Source <id> '"
<< inst->words[targetIndex]
<< "' is not defined.";
return false);
auto targetPointerType = find(target->second.inst->words[1]);
spvCheck(!found(targetPointerType), assert(0 && "Unreachable!"));
auto targetType = find(targetPointerType->second.inst->words[3]);
spvCheck(!found(targetType), assert(0 && "Unreachable!"));
auto sourcePointerType = find(source->second.inst->words[1]);
spvCheck(!found(sourcePointerType), assert(0 && "Unreachable!"));
auto sourceType = find(sourcePointerType->second.inst->words[3]);
spvCheck(!found(sourceType), assert(0 && "Unreachable!"));
spvCheck(
!spvOpcodeAreTypesEqual(targetType->second.inst, sourceType->second.inst),
DIAG(sourceIndex) << "OpCopyMemory Target <id> '"
<< inst->words[sourceIndex]
<< "'s type does not match Source <id> '"
<< sourceType->second.id << "'s type.";
return false);
return true;
}
template <>
bool idUsage::isValid<OpCopyMemorySized>(const spv_instruction_t *inst,
const spv_opcode_desc) {
auto targetIndex = 1;
auto target = find(inst->words[targetIndex]);
spvCheck(!found(target),
DIAG(targetIndex) << "OpCopyMemorySized Target <id> '"
<< inst->words[targetIndex] << "' is not defined.";
return false);
auto sourceIndex = 2;
auto source = find(inst->words[sourceIndex]);
spvCheck(!found(source),
DIAG(sourceIndex) << "OpCopyMemorySized Source <id> '"
<< inst->words[sourceIndex] << "' is not defined.";
return false);
auto sizeIndex = 3;
auto size = find(inst->words[sizeIndex]);
spvCheck(!found(size), DIAG(sizeIndex) << "OpCopyMemorySized, Size <id> '"
<< inst->words[sizeIndex]
<< "' is not defined.";
return false);
auto targetPointerType = find(target->second.inst->words[1]);
spvCheck(!found(targetPointerType), assert(0 && "Unreachable!"));
spvCheck(OpTypePointer != targetPointerType->second.opcode,
DIAG(targetIndex) << "OpCopyMemorySized Target <id> '"
<< inst->words[targetIndex]
<< "' is not a pointer.";
return false);
auto sourcePointerType = find(source->second.inst->words[1]);
spvCheck(!found(sourcePointerType), assert(0 && "Unreachable!"));
spvCheck(OpTypePointer != sourcePointerType->second.opcode,
DIAG(sourceIndex) << "OpCopyMemorySized Source <id> '"
<< 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 OpConstant:
case OpSpecConstant: {
auto sizeType = find(size->second.inst->words[1]);
spvCheck(!found(sizeType), assert(0 && "Unreachable!"));
spvCheck(OpTypeInt != sizeType->second.opcode,
DIAG(sizeIndex) << "OpCopyMemorySized Size <id> '"
<< inst->words[sizeIndex]
<< "'s type is not an integer type.";
return false);
} break;
case OpVariable: {
auto pointerType = find(size->second.inst->words[1]);
spvCheck(!found(pointerType), assert(0 && "Unreachable!"));
auto sizeType = find(pointerType->second.inst->words[1]);
spvCheck(!found(sizeType), assert(0 && "Unreachable!"));
spvCheck(OpTypeInt != sizeType->second.opcode,
DIAG(sizeIndex) << "OpCopyMemorySized Size <id> '"
<< inst->words[sizeIndex]
<< "'s variable type is not an integer type.";
return false);
} break;
default:
DIAG(sizeIndex) << "OpCopyMemorySized Size <id> '"
<< 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<OpAccessChain>(const spv_instruction_t *inst,
const spv_opcode_desc opcodeEntry) {}
#endif
#if 0
template <>
bool idUsage::isValid<OpInBoundsAccessChain>(
const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
#endif
#if 0
template <>
bool idUsage::isValid<OpArrayLength>(const spv_instruction_t *inst,
const spv_opcode_desc opcodeEntry) {}
#endif
#if 0
template <>
bool idUsage::isValid<OpImagePointer>(const spv_instruction_t *inst,
const spv_opcode_desc opcodeEntry) {}
#endif
#if 0
template <>
bool idUsage::isValid<OpGenericPtrMemSemantics>(
const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
#endif
template <>
bool idUsage::isValid<OpFunction>(const spv_instruction_t *inst,
const spv_opcode_desc) {
auto resultTypeIndex = 1;
auto resultType = find(inst->words[resultTypeIndex]);
spvCheck(!found(resultType), DIAG(resultTypeIndex)
<< "OpFunction Result Type <id> '"
<< inst->words[resultTypeIndex]
<< "' is not defined.";
return false);
auto functionTypeIndex = 4;
auto functionType = find(inst->words[functionTypeIndex]);
spvCheck(!found(functionType), DIAG(functionTypeIndex)
<< "OpFunction Function Type <id> '"
<< inst->words[functionTypeIndex]
<< "' is not defined.";
return false);
spvCheck(OpTypeFunction != functionType->second.opcode,
DIAG(functionTypeIndex) << "OpFunction Function Type <id> '"
<< inst->words[functionTypeIndex]
<< "' is not a function type.";
return false);
auto returnType = find(functionType->second.inst->words[2]);
spvCheck(!found(returnType), assert(0 && "Unreachable!"));
spvCheck(returnType != resultType,
DIAG(resultTypeIndex) << "OpFunction Result Type <id> '"
<< inst->words[resultTypeIndex]
<< "' does not match the Function Type <id> '"
<< resultType->second.id << "'s return type.";
return false);
return true;
}
template <>
bool idUsage::isValid<OpFunctionParameter>(const spv_instruction_t *inst,
const spv_opcode_desc) {
auto resultTypeIndex = 1;
auto resultType = find(inst->words[resultTypeIndex]);
spvCheck(!found(resultType), DIAG(resultTypeIndex)
<< "OpFunctionParameter Result Type <id> '"
<< inst->words[resultTypeIndex]
<< "' is not defined.";
return false);
auto function = inst - 1;
// NOTE: Find OpFunction & ensure OpFunctionParameter is not out of place.
uint64_t paramIndex = 0;
while (firstInst != function) {
spvCheck(OpFunction != function->opcode &&
OpFunctionParameter != function->opcode,
DIAG(0) << "OpFunctionParameter is not preceded by OpFunction or "
"OpFunctionParameter sequence.";
return false);
if (OpFunction == function->opcode) {
break;
} else {
paramIndex++;
}
}
auto functionType = find(function->words[4]);
spvCheck(!found(functionType), assert(0 && "Unreachable!"));
auto paramType = find(functionType->second.inst->words[paramIndex + 3]);
spvCheck(!found(paramType), assert(0 && "Unreachable!"));
spvCheck(
!spvOpcodeAreTypesEqual(resultType->second.inst, paramType->second.inst),
DIAG(resultTypeIndex) << "OpFunctionParameter Result Type <id> '"
<< inst->words[resultTypeIndex]
<< "' does not match the OpTypeFunction parameter "
"type of the same index.";
return false);
return true;
}
template <>
bool idUsage::isValid<OpFunctionCall>(const spv_instruction_t *inst,
const spv_opcode_desc) {
auto resultTypeIndex = 1;
auto resultType = find(inst->words[resultTypeIndex]);
spvCheck(!found(resultType), DIAG(resultTypeIndex)
<< "OpFunctionCall Result Type <id> '"
<< inst->words[resultTypeIndex]
<< "' is not defined.";
return false);
auto functionIndex = 3;
auto function = find(inst->words[functionIndex]);
spvCheck(!found(function), DIAG(functionIndex)
<< "OpFunctionCall Function <id> '"
<< inst->words[functionIndex]
<< "' is not defined.";
return false);
spvCheck(OpFunction != function->second.opcode,
DIAG(functionIndex) << "OpFunctionCall Function <id> '"
<< inst->words[functionIndex]
<< "' is not a function.";
return false);
auto returnType = find(function->second.inst->words[1]);
spvCheck(!found(returnType), assert(0 && "Unreachable!"));
spvCheck(
!spvOpcodeAreTypesEqual(returnType->second.inst, resultType->second.inst),
DIAG(resultTypeIndex)
<< "OpFunctionCall Result Type <id> '" << inst->words[resultTypeIndex]
<< "'s type does not match Function <id> '" << returnType->second.id
<< "'s return type.";
return false);
auto functionType = find(function->second.inst->words[4]);
spvCheck(!found(functionType), assert(0 && "Unreachable!"));
auto functionCallArgCount = inst->wordCount - 4;
auto functionParamCount = functionType->second.inst->wordCount - 3;
spvCheck(
functionParamCount != functionCallArgCount,
DIAG(inst->wordCount - 1)
<< "OpFunctionCall Function <id>'s parameter count does not match "
"the argument count.";
return false);
for (uint64_t argumentIndex = 4, paramIndex = 3;
argumentIndex < inst->wordCount; argumentIndex++, paramIndex++) {
auto argument = find(inst->words[argumentIndex]);
spvCheck(!found(argument), DIAG(argumentIndex)
<< "OpFunctionCall Argument <id> '"
<< inst->words[argumentIndex]
<< "' is not defined.";
return false);
auto argumentType = find(argument->second.inst->words[1]);
spvCheck(!found(argumentType), assert(0 && "Unreachable!"));
auto parameterType = find(functionType->second.inst->words[paramIndex]);
spvCheck(!found(parameterType), assert(0 && "Unreachable!"));
spvCheck(!spvOpcodeAreTypesEqual(argumentType->second.inst,
parameterType->second.inst),
DIAG(argumentIndex) << "OpFunctionCall Argument <id> '"
<< inst->words[argumentIndex]
<< "'s type does not match Function <id> '"
<< parameterType->second.id
<< "'s parameter type.";
return false);
}
return true;
}
#if 0
template <>
bool idUsage::isValid<OpConvertUToF>(const spv_instruction_t *inst,
const spv_opcode_desc opcodeEntry) {}
#endif
#if 0
template <>
bool idUsage::isValid<OpConvertFToS>(const spv_instruction_t *inst,
const spv_opcode_desc opcodeEntry) {}
#endif
#if 0
template <>
bool idUsage::isValid<OpConvertSToF>(const spv_instruction_t *inst,
const spv_opcode_desc opcodeEntry) {}
#endif
#if 0
template <>
bool idUsage::isValid<OpConvertUToF>(const spv_instruction_t *inst,
const spv_opcode_desc opcodeEntry) {}
#endif
#if 0
template <>
bool idUsage::isValid<OpUConvert>(const spv_instruction_t *inst,
const spv_opcode_desc opcodeEntry) {}
#endif
#if 0
template <>
bool idUsage::isValid<OpSConvert>(const spv_instruction_t *inst,
const spv_opcode_desc opcodeEntry) {}
#endif
#if 0
template <>
bool idUsage::isValid<OpFConvert>(const spv_instruction_t *inst,
const spv_opcode_desc opcodeEntry) {}
#endif
#if 0
template <>
bool idUsage::isValid<OpConvertPtrToU>(const spv_instruction_t *inst,
const spv_opcode_desc opcodeEntry) {
}
#endif
#if 0
template <>
bool idUsage::isValid<OpConvertUToPtr>(const spv_instruction_t *inst,
const spv_opcode_desc opcodeEntry) {
}
#endif
#if 0
template <>
bool idUsage::isValid<OpPtrCastToGeneric>(
const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
#endif
#if 0
template <>
bool idUsage::isValid<OpGenericCastToPtr>(
const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
#endif
#if 0
template <>
bool idUsage::isValid<OpBitcast>(const spv_instruction_t *inst,
const spv_opcode_desc opcodeEntry) {}
#endif
#if 0
template <>
bool idUsage::isValid<OpGenericCastToPtrExplicit>(
const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
#endif
#if 0
template <>
bool idUsage::isValid<OpSatConvertSToU>(const spv_instruction_t *inst) {}
#endif
#if 0
template <>
bool idUsage::isValid<OpSatConvertUToS>(const spv_instruction_t *inst) {}
#endif
#if 0
template <>
bool idUsage::isValid<OpVectorExtractDynamic>(
const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
#endif
#if 0
template <>
bool idUsage::isValid<OpVectorInsertDynamic>(
const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
#endif
#if 0
template <>
bool idUsage::isValid<OpVectorShuffle>(const spv_instruction_t *inst,
const spv_opcode_desc opcodeEntry) {
}
#endif
#if 0
template <>
bool idUsage::isValid<OpCompositeConstruct>(
const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
#endif
#if 0
template <>
bool idUsage::isValid<OpCompositeExtract>(
const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
#endif
#if 0
template <>
bool idUsage::isValid<OpCompositeInsert>(
const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
#endif
#if 0
template <>
bool idUsage::isValid<OpCopyObject>(const spv_instruction_t *inst,
const spv_opcode_desc opcodeEntry) {}
#endif
#if 0
template <>
bool idUsage::isValid<OpTranspose>(const spv_instruction_t *inst,
const spv_opcode_desc opcodeEntry) {}
#endif
#if 0
template <>
bool idUsage::isValid<OpSNegate>(const spv_instruction_t *inst,
const spv_opcode_desc opcodeEntry) {}
#endif
#if 0
template <>
bool idUsage::isValid<OpFNegate>(const spv_instruction_t *inst,
const spv_opcode_desc opcodeEntry) {}
#endif
#if 0
template <>
bool idUsage::isValid<OpNot>(const spv_instruction_t *inst,
const spv_opcode_desc opcodeEntry) {}
#endif
#if 0
template <>
bool idUsage::isValid<OpIAdd>(const spv_instruction_t *inst,
const spv_opcode_desc opcodeEntry) {}
#endif
#if 0
template <>
bool idUsage::isValid<OpFAdd>(const spv_instruction_t *inst,
const spv_opcode_desc opcodeEntry) {}
#endif
#if 0
template <>
bool idUsage::isValid<OpISub>(const spv_instruction_t *inst,
const spv_opcode_desc opcodeEntry) {}
#endif
#if 0
template <>
bool idUsage::isValid<OpFSub>(const spv_instruction_t *inst,
const spv_opcode_desc opcodeEntry) {}
#endif
#if 0
template <>
bool idUsage::isValid<OpIMul>(const spv_instruction_t *inst,
const spv_opcode_desc opcodeEntry) {}
#endif
#if 0
template <>
bool idUsage::isValid<OpFMul>(const spv_instruction_t *inst,
const spv_opcode_desc opcodeEntry) {}
#endif
#if 0
template <>
bool idUsage::isValid<OpUDiv>(const spv_instruction_t *inst,
const spv_opcode_desc opcodeEntry) {}
#endif
#if 0
template <>
bool idUsage::isValid<OpSDiv>(const spv_instruction_t *inst,
const spv_opcode_desc opcodeEntry) {}
#endif
#if 0
template <>
bool idUsage::isValid<OpFDiv>(const spv_instruction_t *inst,
const spv_opcode_desc opcodeEntry) {}
#endif
#if 0
template <>
bool idUsage::isValid<OpUMod>(const spv_instruction_t *inst,
const spv_opcode_desc opcodeEntry) {}
#endif
#if 0
template <>
bool idUsage::isValid<OpSRem>(const spv_instruction_t *inst,
const spv_opcode_desc opcodeEntry) {}
#endif
#if 0
template <>
bool idUsage::isValid<OpSMod>(const spv_instruction_t *inst,
const spv_opcode_desc opcodeEntry) {}
#endif
#if 0
template <>
bool idUsage::isValid<OpFRem>(const spv_instruction_t *inst,
const spv_opcode_desc opcodeEntry) {}
#endif
#if 0
template <>
bool idUsage::isValid<OpFMod>(const spv_instruction_t *inst,
const spv_opcode_desc opcodeEntry) {}
#endif
#if 0
template <>
bool idUsage::isValid<OpVectorTimesScalar>(
const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
#endif
#if 0
template <>
bool idUsage::isValid<OpMatrixTimesScalar>(
const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
#endif
#if 0
template <>
bool idUsage::isValid<OpVectorTimesMatrix>(
const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
#endif
#if 0
template <>
bool idUsage::isValid<OpMatrixTimesVector>(
const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
#endif
#if 0
template <>
bool idUsage::isValid<OpMatrixTimesMatrix>(
const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
#endif
#if 0
template <>
bool idUsage::isValid<OpOuterProduct>(const spv_instruction_t *inst,
const spv_opcode_desc opcodeEntry) {}
#endif
#if 0
template <>
bool idUsage::isValid<OpDot>(const spv_instruction_t *inst,
const spv_opcode_desc opcodeEntry) {}
#endif
#if 0
template <>
bool idUsage::isValid<OpShiftRightLogical>(
const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
#endif
#if 0
template <>
bool idUsage::isValid<OpShiftRightArithmetic>(
const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
#endif
#if 0
template <>
bool idUsage::isValid<OpShiftLeftLogical>(
const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
#endif
#if 0
template <>
bool idUsage::isValid<OpBitwiseOr>(const spv_instruction_t *inst,
const spv_opcode_desc opcodeEntry) {}
#endif
#if 0
template <>
bool idUsage::isValid<OpBitwiseXor>(const spv_instruction_t *inst,
const spv_opcode_desc opcodeEntry) {}
#endif
#if 0
template <>
bool idUsage::isValid<OpBitwiseAnd>(const spv_instruction_t *inst,
const spv_opcode_desc opcodeEntry) {}
#endif
#if 0
template <>
bool idUsage::isValid<OpAny>(const spv_instruction_t *inst,
const spv_opcode_desc opcodeEntry) {}
#endif
#if 0
template <>
bool idUsage::isValid<OpAll>(const spv_instruction_t *inst,
const spv_opcode_desc opcodeEntry) {}
#endif
#if 0
template <>
bool idUsage::isValid<OpIsNan>(const spv_instruction_t *inst,
const spv_opcode_desc opcodeEntry) {}
#endif
#if 0
template <>
bool idUsage::isValid<OpIsInf>(const spv_instruction_t *inst,
const spv_opcode_desc opcodeEntry) {}
#endif
#if 0
template <>
bool idUsage::isValid<OpIsFinite>(const spv_instruction_t *inst,
const spv_opcode_desc opcodeEntry) {}
#endif
#if 0
template <>
bool idUsage::isValid<OpIsNormal>(const spv_instruction_t *inst,
const spv_opcode_desc opcodeEntry) {}
#endif
#if 0
template <>
bool idUsage::isValid<OpSignBitSet>(const spv_instruction_t *inst,
const spv_opcode_desc opcodeEntry) {}
#endif
#if 0
template <>
bool idUsage::isValid<OpLessOrGreater>(const spv_instruction_t *inst,
const spv_opcode_desc opcodeEntry) {
}
#endif
#if 0
template <>
bool idUsage::isValid<OpOrdered>(const spv_instruction_t *inst,
const spv_opcode_desc opcodeEntry) {}
#endif
#if 0
template <>
bool idUsage::isValid<OpUnordered>(const spv_instruction_t *inst,
const spv_opcode_desc opcodeEntry) {}
#endif
#if 0
template <>
bool idUsage::isValid<OpLogicalOr>(const spv_instruction_t *inst,
const spv_opcode_desc opcodeEntry) {}
#endif
#if 0
template <>
bool idUsage::isValid<OpLogicalXor>(const spv_instruction_t *inst,
const spv_opcode_desc opcodeEntry) {}
#endif
#if 0
template <>
bool idUsage::isValid<OpLogicalAnd>(const spv_instruction_t *inst,
const spv_opcode_desc opcodeEntry) {}
#endif
#if 0
template <>
bool idUsage::isValid<OpSelect>(const spv_instruction_t *inst,
const spv_opcode_desc opcodeEntry) {}
#endif
#if 0
template <>
bool idUsage::isValid<OpIEqual>(const spv_instruction_t *inst,
const spv_opcode_desc opcodeEntry) {}
#endif
#if 0
template <>
bool idUsage::isValid<OpFOrdEqual>(const spv_instruction_t *inst,
const spv_opcode_desc opcodeEntry) {}
#endif
#if 0
template <>
bool idUsage::isValid<OpFUnordEqual>(const spv_instruction_t *inst,
const spv_opcode_desc opcodeEntry) {}
#endif
#if 0
template <>
bool idUsage::isValid<OpINotEqual>(const spv_instruction_t *inst,
const spv_opcode_desc opcodeEntry) {}
#endif
#if 0
template <>
bool idUsage::isValid<OpFOrdNotEqual>(const spv_instruction_t *inst,
const spv_opcode_desc opcodeEntry) {}
#endif
#if 0
template <>
bool idUsage::isValid<OpFUnordNotEqual>(
const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
#endif
#if 0
template <>
bool idUsage::isValid<OpULessThan>(const spv_instruction_t *inst,
const spv_opcode_desc opcodeEntry) {}
#endif
#if 0
template <>
bool idUsage::isValid<OpSLessThan>(const spv_instruction_t *inst,
const spv_opcode_desc opcodeEntry) {}
#endif
#if 0
template <>
bool idUsage::isValid<OpFOrdLessThan>(const spv_instruction_t *inst,
const spv_opcode_desc opcodeEntry) {}
#endif
#if 0
template <>
bool idUsage::isValid<OpFUnordLessThan>(
const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
#endif
#if 0
template <>
bool idUsage::isValid<OpUGreaterThan>(const spv_instruction_t *inst,
const spv_opcode_desc opcodeEntry) {}
#endif
#if 0
template <>
bool idUsage::isValid<OpSGreaterThan>(const spv_instruction_t *inst,
const spv_opcode_desc opcodeEntry) {}
#endif
#if 0
template <>
bool idUsage::isValid<OpFOrdGreaterThan>(
const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
#endif
#if 0
template <>
bool idUsage::isValid<OpFUnordGreaterThan>(
const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
#endif
#if 0
template <>
bool idUsage::isValid<OpULessThanEqual>(
const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
#endif
#if 0
template <>
bool idUsage::isValid<OpSLessThanEqual>(
const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
#endif
#if 0
template <>
bool idUsage::isValid<OpFOrdLessThanEqual>(
const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
#endif
#if 0
template <>
bool idUsage::isValid<OpFUnordLessThanEqual>(
const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
#endif
#if 0
template <>
bool idUsage::isValid<OpUGreaterThanEqual>(
const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
#endif
#if 0
template <>
bool idUsage::isValid<OpSGreaterThanEqual>(
const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
#endif
#if 0
template <>
bool idUsage::isValid<OpFOrdGreaterThanEqual>(
const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
#endif
#if 0
template <>
bool idUsage::isValid<OpFUnordGreaterThanEqual>(
const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
#endif
#if 0
template <>
bool idUsage::isValid<OpDPdx>(const spv_instruction_t *inst,
const spv_opcode_desc opcodeEntry) {}
#endif
#if 0
template <>
bool idUsage::isValid<OpDPdy>(const spv_instruction_t *inst,
const spv_opcode_desc opcodeEntry) {}
#endif
#if 0
template <>
bool idUsage::isValid<OpFWidth>(const spv_instruction_t *inst,
const spv_opcode_desc opcodeEntry) {}
#endif
#if 0
template <>
bool idUsage::isValid<OpDPdxFine>(const spv_instruction_t *inst,
const spv_opcode_desc opcodeEntry) {}
#endif
#if 0
template <>
bool idUsage::isValid<OpDPdyFine>(const spv_instruction_t *inst,
const spv_opcode_desc opcodeEntry) {}
#endif
#if 0
template <>
bool idUsage::isValid<OpFwidthFine>(const spv_instruction_t *inst,
const spv_opcode_desc opcodeEntry) {}
#endif
#if 0
template <>
bool idUsage::isValid<OpDPdxCoarse>(const spv_instruction_t *inst,
const spv_opcode_desc opcodeEntry) {}
#endif
#if 0
template <>
bool idUsage::isValid<OpDPdyCoarse>(const spv_instruction_t *inst,
const spv_opcode_desc opcodeEntry) {}
#endif
#if 0
template <>
bool idUsage::isValid<OpFwidthCoarse>(const spv_instruction_t *inst,
const spv_opcode_desc opcodeEntry) {}
#endif
#if 0
template <>
bool idUsage::isValid<OpPhi>(const spv_instruction_t *inst,
const spv_opcode_desc opcodeEntry) {}
#endif
#if 0
template <>
bool idUsage::isValid<OpLoopMerge>(const spv_instruction_t *inst,
const spv_opcode_desc opcodeEntry) {}
#endif
#if 0
template <>
bool idUsage::isValid<OpSelectionMerge>(
const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
#endif
#if 0
template <>
bool idUsage::isValid<OpBranch>(const spv_instruction_t *inst,
const spv_opcode_desc opcodeEntry) {}
#endif
#if 0
template <>
bool idUsage::isValid<OpBranchConditional>(
const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
#endif
#if 0
template <>
bool idUsage::isValid<OpSwitch>(const spv_instruction_t *inst,
const spv_opcode_desc opcodeEntry) {}
#endif
template <>
bool idUsage::isValid<OpReturnValue>(const spv_instruction_t *inst,
const spv_opcode_desc) {
auto valueIndex = 1;
auto value = find(inst->words[valueIndex]);
spvCheck(!found(value), DIAG(valueIndex) << "OpReturnValue Value <id> '"
<< inst->words[valueIndex]
<< "' is not defined.";
return false);
spvCheck(!spvOpcodeIsValue(value->second.opcode),
DIAG(valueIndex) << "OpReturnValue Value <id> '"
<< inst->words[valueIndex]
<< "' does not represent a value.";
return false);
auto valueType = find(value->second.inst->words[1]);
spvCheck(!found(valueType), assert(0 && "Unreachable!"));
// NOTE: Find OpFunction
const spv_instruction_t *function = inst - 1;
while (firstInst != function) {
spvCheck(OpFunction == function->opcode, break);
function--;
}
spvCheck(OpFunction != function->opcode,
DIAG(valueIndex) << "OpReturnValue is not in a basic block.";
return false);
auto returnType = find(function->words[1]);
spvCheck(!found(returnType), assert(0 && "Unreachable!"));
if (OpTypePointer == valueType->second.opcode) {
auto pointerValueType = find(valueType->second.inst->words[3]);
spvCheck(!found(pointerValueType), assert(0 && "Unreachable!"));
spvCheck(!spvOpcodeAreTypesEqual(returnType->second.inst,
pointerValueType->second.inst),
DIAG(valueIndex)
<< "OpReturnValue Value <id> '" << inst->words[valueIndex]
<< "'s pointer type does not match OpFunction's return type.";
return false);
} else {
spvCheck(!spvOpcodeAreTypesEqual(returnType->second.inst,
valueType->second.inst),
DIAG(valueIndex)
<< "OpReturnValue Value <id> '" << inst->words[valueIndex]
<< "'s type does not match OpFunction's return type.";
return false);
}
return true;
}
#if 0
template <>
bool idUsage::isValid<OpLifetimeStart>(const spv_instruction_t *inst,
const spv_opcode_desc opcodeEntry) {
}
#endif
#if 0
template <>
bool idUsage::isValid<OpLifetimeStop>(const spv_instruction_t *inst,
const spv_opcode_desc opcodeEntry) {}
#endif
#if 0
template <>
bool idUsage::isValid<OpAtomicInit>(const spv_instruction_t *inst,
const spv_opcode_desc opcodeEntry) {}
#endif
#if 0
template <>
bool idUsage::isValid<OpAtomicLoad>(const spv_instruction_t *inst,
const spv_opcode_desc opcodeEntry) {}
#endif
#if 0
template <>
bool idUsage::isValid<OpAtomicStore>(const spv_instruction_t *inst,
const spv_opcode_desc opcodeEntry) {}
#endif
#if 0
template <>
bool idUsage::isValid<OpAtomicExchange>(
const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
#endif
#if 0
template <>
bool idUsage::isValid<OpAtomicCompareExchange>(
const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
#endif
#if 0
template <>
bool idUsage::isValid<OpAtomicCompareExchangeWeak>(
const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
#endif
#if 0
template <>
bool idUsage::isValid<OpAtomicIIncrement>(
const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
#endif
#if 0
template <>
bool idUsage::isValid<OpAtomicIDecrement>(
const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
#endif
#if 0
template <>
bool idUsage::isValid<OpAtomicIAdd>(const spv_instruction_t *inst,
const spv_opcode_desc opcodeEntry) {}
#endif
#if 0
template <>
bool idUsage::isValid<OpAtomicISub>(const spv_instruction_t *inst,
const spv_opcode_desc opcodeEntry) {}
#endif
#if 0
template <>
bool idUsage::isValid<OpAtomicUMin>(const spv_instruction_t *inst,
const spv_opcode_desc opcodeEntry) {}
#endif
#if 0
template <>
bool idUsage::isValid<OpAtomicUMax>(const spv_instruction_t *inst,
const spv_opcode_desc opcodeEntry) {}
#endif
#if 0
template <>
bool idUsage::isValid<OpAtomicAnd>(const spv_instruction_t *inst,
const spv_opcode_desc opcodeEntry) {}
#endif
#if 0
template <>
bool idUsage::isValid<OpAtomicOr>(const spv_instruction_t *inst,
const spv_opcode_desc opcodeEntry) {}
#endif
#if 0
template <>
bool idUsage::isValid<OpAtomicXor>(const spv_instruction_t *inst,
const spv_opcode_desc opcodeEntry) {}
#endif
#if 0
template <>
bool idUsage::isValid<OpAtomicIMin>(const spv_instruction_t *inst,
const spv_opcode_desc opcodeEntry) {}
#endif
#if 0
template <>
bool idUsage::isValid<OpAtomicIMax>(const spv_instruction_t *inst,
const spv_opcode_desc opcodeEntry) {}
#endif
#if 0
template <>
bool idUsage::isValid<OpEmitStreamVertex>(
const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
#endif
#if 0
template <>
bool idUsage::isValid<OpEndStreamPrimitive>(
const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
#endif
#if 0
template <>
bool idUsage::isValid<OpAsyncGroupCopy>(
const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
#endif
#if 0
template <>
bool idUsage::isValid<OpWaitGroupEvents>(
const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
#endif
#if 0
template <>
bool idUsage::isValid<OpGroupAll>(const spv_instruction_t *inst,
const spv_opcode_desc opcodeEntry) {}
#endif
#if 0
template <>
bool idUsage::isValid<OpGroupAny>(const spv_instruction_t *inst,
const spv_opcode_desc opcodeEntry) {}
#endif
#if 0
template <>
bool idUsage::isValid<OpGroupBroadcast>(
const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
#endif
#if 0
template <>
bool idUsage::isValid<OpGroupIAdd>(const spv_instruction_t *inst,
const spv_opcode_desc opcodeEntry) {}
#endif
#if 0
template <>
bool idUsage::isValid<OpGroupFAdd>(const spv_instruction_t *inst,
const spv_opcode_desc opcodeEntry) {}
#endif
#if 0
template <>
bool idUsage::isValid<OpGroupFMin>(const spv_instruction_t *inst,
const spv_opcode_desc opcodeEntry) {}
#endif
#if 0
template <>
bool idUsage::isValid<OpGroupUMin>(const spv_instruction_t *inst,
const spv_opcode_desc opcodeEntry) {}
#endif
#if 0
template <>
bool idUsage::isValid<OpGroupSMin>(const spv_instruction_t *inst,
const spv_opcode_desc opcodeEntry) {}
#endif
#if 0
template <>
bool idUsage::isValid<OpGroupFMax>(const spv_instruction_t *inst,
const spv_opcode_desc opcodeEntry) {}
#endif
#if 0
template <>
bool idUsage::isValid<OpGroupUMax>(const spv_instruction_t *inst,
const spv_opcode_desc opcodeEntry) {}
#endif
#if 0
template <>
bool idUsage::isValid<OpGroupSMax>(const spv_instruction_t *inst,
const spv_opcode_desc opcodeEntry) {}
#endif
#if 0
template <>
bool idUsage::isValid<OpEnqueueMarker>(const spv_instruction_t *inst,
const spv_opcode_desc opcodeEntry) {
}
#endif
#if 0
template <>
bool idUsage::isValid<OpEnqueueKernel>(const spv_instruction_t *inst,
const spv_opcode_desc opcodeEntry) {
}
#endif
#if 0
template <>
bool idUsage::isValid<OpGetKernelNDrangeSubGroupCount>(
const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
#endif
#if 0
template <>
bool idUsage::isValid<OpGetKernelNDrangeMaxSubGroupSize>(
const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
#endif
#if 0
template <>
bool idUsage::isValid<OpGetKernelWorkGroupSize>(
const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
#endif
#if 0
template <>
bool idUsage::isValid<OpGetKernelPreferredWorkGroupSizeMultiple>(
const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
#endif
#if 0
template <>
bool idUsage::isValid<OpRetainEvent>(const spv_instruction_t *inst,
const spv_opcode_desc opcodeEntry) {}
#endif
#if 0
template <>
bool idUsage::isValid<OpReleaseEvent>(const spv_instruction_t *inst,
const spv_opcode_desc opcodeEntry) {}
#endif
#if 0
template <>
bool idUsage::isValid<OpCreateUserEvent>(
const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
#endif
#if 0
template <>
bool idUsage::isValid<OpIsValidEvent>(const spv_instruction_t *inst,
const spv_opcode_desc opcodeEntry) {}
#endif
#if 0
template <>
bool idUsage::isValid<OpSetUserEventStatus>(
const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
#endif
#if 0
template <>
bool idUsage::isValid<OpCaptureEventProfilingInfo>(
const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
#endif
#if 0
template <>
bool idUsage::isValid<OpGetDefaultQueue>(
const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
#endif
#if 0
template <>
bool idUsage::isValid<OpBuildNDRange>(const spv_instruction_t *inst,
const spv_opcode_desc opcodeEntry) {}
#endif
#if 0
template <>
bool idUsage::isValid<OpReadPipe>(const spv_instruction_t *inst,
const spv_opcode_desc opcodeEntry) {}
#endif
#if 0
template <>
bool idUsage::isValid<OpWritePipe>(const spv_instruction_t *inst,
const spv_opcode_desc opcodeEntry) {}
#endif
#if 0
template <>
bool idUsage::isValid<OpReservedReadPipe>(
const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
#endif
#if 0
template <>
bool idUsage::isValid<OpReservedWritePipe>(
const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
#endif
#if 0
template <>
bool idUsage::isValid<OpReserveReadPipePackets>(
const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
#endif
#if 0
template <>
bool idUsage::isValid<OpReserveWritePipePackets>(
const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
#endif
#if 0
template <>
bool idUsage::isValid<OpCommitReadPipe>(
const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
#endif
#if 0
template <>
bool idUsage::isValid<OpCommitWritePipe>(
const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
#endif
#if 0
template <>
bool idUsage::isValid<OpIsValidReserveId>(
const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
#endif
#if 0
template <>
bool idUsage::isValid<OpGetNumPipePackets>(
const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
#endif
#if 0
template <>
bool idUsage::isValid<OpGetMaxPipePackets>(
const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
#endif
#if 0
template <>
bool idUsage::isValid<OpGroupReserveReadPipePackets>(
const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
#endif
#if 0
template <>
bool idUsage::isValid<OpGroupReserveWritePipePackets>(
const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
#endif
#if 0
template <>
bool idUsage::isValid<OpGroupCommitReadPipe>(
const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
#endif
#if 0
template <>
bool idUsage::isValid<OpGroupCommitWritePipe>(
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 OpCode: \
return isValid<OpCode>(inst, opcodeEntry);
#define FAIL(OpCode) \
case OpCode: \
std::cerr << "Not implemented: " << #OpCode << "\n"; \
return false;
switch (inst->opcode) {
FAIL(OpUndef)
CASE(OpName)
CASE(OpMemberName)
CASE(OpLine)
CASE(OpDecorate)
CASE(OpMemberDecorate)
CASE(OpGroupDecorate)
FAIL(OpGroupMemberDecorate)
FAIL(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(OpConstant)
CASE(OpConstantComposite)
CASE(OpConstantSampler)
CASE(OpConstantNull)
CASE(OpSpecConstantTrue)
CASE(OpSpecConstantFalse)
CASE(OpSpecConstant)
FAIL(OpSpecConstantComposite)
FAIL(OpSpecConstantOp)
CASE(OpVariable)
CASE(OpLoad)
CASE(OpStore)
CASE(OpCopyMemory)
CASE(OpCopyMemorySized)
FAIL(OpAccessChain)
FAIL(OpInBoundsAccessChain)
FAIL(OpArrayLength)
FAIL(OpGenericPtrMemSemantics)
CASE(OpFunction)
CASE(OpFunctionParameter)
CASE(OpFunctionCall)
FAIL(OpConvertUToF)
FAIL(OpConvertFToS)
FAIL(OpConvertSToF)
FAIL(OpUConvert)
FAIL(OpSConvert)
FAIL(OpFConvert)
FAIL(OpConvertPtrToU)
FAIL(OpConvertUToPtr)
FAIL(OpPtrCastToGeneric)
FAIL(OpGenericCastToPtr)
FAIL(OpBitcast)
FAIL(OpGenericCastToPtrExplicit)
FAIL(OpSatConvertSToU)
FAIL(OpSatConvertUToS)
FAIL(OpVectorExtractDynamic)
FAIL(OpVectorInsertDynamic)
FAIL(OpVectorShuffle)
FAIL(OpCompositeConstruct)
FAIL(OpCompositeExtract)
FAIL(OpCompositeInsert)
FAIL(OpCopyObject)
FAIL(OpTranspose)
FAIL(OpSNegate)
FAIL(OpFNegate)
FAIL(OpNot)
FAIL(OpIAdd)
FAIL(OpFAdd)
FAIL(OpISub)
FAIL(OpFSub)
FAIL(OpIMul)
FAIL(OpFMul)
FAIL(OpUDiv)
FAIL(OpSDiv)
FAIL(OpFDiv)
FAIL(OpUMod)
FAIL(OpSRem)
FAIL(OpSMod)
FAIL(OpFRem)
FAIL(OpFMod)
FAIL(OpVectorTimesScalar)
FAIL(OpMatrixTimesScalar)
FAIL(OpVectorTimesMatrix)
FAIL(OpMatrixTimesVector)
FAIL(OpMatrixTimesMatrix)
FAIL(OpOuterProduct)
FAIL(OpDot)
FAIL(OpShiftRightLogical)
FAIL(OpShiftRightArithmetic)
FAIL(OpShiftLeftLogical)
FAIL(OpBitwiseOr)
FAIL(OpBitwiseXor)
FAIL(OpBitwiseAnd)
FAIL(OpAny)
FAIL(OpAll)
FAIL(OpIsNan)
FAIL(OpIsInf)
FAIL(OpIsFinite)
FAIL(OpIsNormal)
FAIL(OpSignBitSet)
FAIL(OpLessOrGreater)
FAIL(OpOrdered)
FAIL(OpUnordered)
FAIL(OpLogicalOr)
FAIL(OpLogicalAnd)
FAIL(OpSelect)
FAIL(OpIEqual)
FAIL(OpFOrdEqual)
FAIL(OpFUnordEqual)
FAIL(OpINotEqual)
FAIL(OpFOrdNotEqual)
FAIL(OpFUnordNotEqual)
FAIL(OpULessThan)
FAIL(OpSLessThan)
FAIL(OpFOrdLessThan)
FAIL(OpFUnordLessThan)
FAIL(OpUGreaterThan)
FAIL(OpSGreaterThan)
FAIL(OpFOrdGreaterThan)
FAIL(OpFUnordGreaterThan)
FAIL(OpULessThanEqual)
FAIL(OpSLessThanEqual)
FAIL(OpFOrdLessThanEqual)
FAIL(OpFUnordLessThanEqual)
FAIL(OpUGreaterThanEqual)
FAIL(OpSGreaterThanEqual)
FAIL(OpFOrdGreaterThanEqual)
FAIL(OpFUnordGreaterThanEqual)
FAIL(OpDPdx)
FAIL(OpDPdy)
FAIL(OpFwidth)
FAIL(OpDPdxFine)
FAIL(OpDPdyFine)
FAIL(OpFwidthFine)
FAIL(OpDPdxCoarse)
FAIL(OpDPdyCoarse)
FAIL(OpFwidthCoarse)
FAIL(OpPhi)
FAIL(OpLoopMerge)
FAIL(OpSelectionMerge)
FAIL(OpBranch)
FAIL(OpBranchConditional)
FAIL(OpSwitch)
CASE(OpReturnValue)
FAIL(OpLifetimeStart)
FAIL(OpLifetimeStop)
FAIL(OpAtomicLoad)
FAIL(OpAtomicStore)
FAIL(OpAtomicExchange)
FAIL(OpAtomicCompareExchange)
FAIL(OpAtomicCompareExchangeWeak)
FAIL(OpAtomicIIncrement)
FAIL(OpAtomicIDecrement)
FAIL(OpAtomicIAdd)
FAIL(OpAtomicISub)
FAIL(OpAtomicUMin)
FAIL(OpAtomicUMax)
FAIL(OpAtomicAnd)
FAIL(OpAtomicOr)
FAIL(OpAtomicSMin)
FAIL(OpAtomicSMax)
FAIL(OpEmitStreamVertex)
FAIL(OpEndStreamPrimitive)
FAIL(OpAsyncGroupCopy)
FAIL(OpWaitGroupEvents)
FAIL(OpGroupAll)
FAIL(OpGroupAny)
FAIL(OpGroupBroadcast)
FAIL(OpGroupIAdd)
FAIL(OpGroupFAdd)
FAIL(OpGroupFMin)
FAIL(OpGroupUMin)
FAIL(OpGroupSMin)
FAIL(OpGroupFMax)
FAIL(OpGroupUMax)
FAIL(OpGroupSMax)
FAIL(OpEnqueueMarker)
FAIL(OpEnqueueKernel)
FAIL(OpGetKernelNDrangeSubGroupCount)
FAIL(OpGetKernelNDrangeMaxSubGroupSize)
FAIL(OpGetKernelWorkGroupSize)
FAIL(OpGetKernelPreferredWorkGroupSizeMultiple)
FAIL(OpRetainEvent)
FAIL(OpReleaseEvent)
FAIL(OpCreateUserEvent)
FAIL(OpIsValidEvent)
FAIL(OpSetUserEventStatus)
FAIL(OpCaptureEventProfilingInfo)
FAIL(OpGetDefaultQueue)
FAIL(OpBuildNDRange)
FAIL(OpReadPipe)
FAIL(OpWritePipe)
FAIL(OpReservedReadPipe)
FAIL(OpReservedWritePipe)
FAIL(OpReserveReadPipePackets)
FAIL(OpReserveWritePipePackets)
FAIL(OpCommitReadPipe)
FAIL(OpCommitWritePipe)
FAIL(OpIsValidReserveId)
FAIL(OpGetNumPipePackets)
FAIL(OpGetMaxPipePackets)
FAIL(OpGroupReserveReadPipePackets)
FAIL(OpGroupReserveWritePipePackets)
FAIL(OpGroupCommitReadPipe)
FAIL(OpGroupCommitWritePipe)
default:
return true;
}
#undef FAIL
#undef CASE
}
2015-09-14 14:05:37 +00:00
} // anonymous namespace
spv_result_t spvValidateInstructionIDs(
const spv_instruction_t *pInsts, const uint64_t instCount,
const spv_id_info_t *pIdUses, const uint64_t idUsesCount,
const spv_id_info_t *pIdDefs, const uint64_t idDefsCount,
const spv_opcode_table opcodeTable, const spv_operand_table operandTable,
const spv_ext_inst_table extInstTable, spv_position position,
spv_diagnostic *pDiag) {
idUsage idUsage(opcodeTable, operandTable, extInstTable, pIdUses, idUsesCount,
pIdDefs, idDefsCount, pInsts, instCount, position, pDiag);
for (uint64_t instIndex = 0; instIndex < instCount; ++instIndex) {
spvCheck(!idUsage.isValid(&pInsts[instIndex]), return SPV_ERROR_INVALID_ID);
position->index += pInsts[instIndex].wordCount;
}
return SPV_SUCCESS;
}