action; \
}
-using UseDefTracker = libspirv::ValidationState_t::UseDefTracker;
+using libspirv::ValidationState_t;
+using std::function;
+using std::ignore;
namespace {
const spv_instruction_t* pInsts, const uint64_t instCountArg,
const SpvMemoryModel memoryModelArg,
const SpvAddressingModel addressingModelArg,
- const UseDefTracker& usedefs,
+ const ValidationState_t& module,
const std::vector<uint32_t>& entry_points, spv_position positionArg,
spv_diagnostic* pDiagnosticArg)
: opcodeTable(opcodeTableArg),
addressingModel(addressingModelArg),
position(positionArg),
pDiagnostic(pDiagnosticArg),
- usedefs_(usedefs),
+ module_(module),
entry_points_(entry_points) {}
bool isValid(const spv_instruction_t* inst);
const SpvAddressingModel addressingModel;
spv_position position;
spv_diagnostic* pDiagnostic;
- UseDefTracker usedefs_;
+ ValidationState_t module_;
std::vector<uint32_t> entry_points_;
};
bool idUsage::isValid<SpvOpMemberName>(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) {
+ auto type = module_.FindDef(inst->words[typeIndex]);
+ if (!type || SpvOpTypeStruct != type->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.words.size() - 2);
+ auto memberCount = (uint32_t)(type->words().size() - 2);
spvCheck(memberCount <= member, DIAG(memberIndex)
<< "OpMemberName Member <id> '"
<< inst->words[memberIndex]
<< "' index is larger than Type <id> '"
- << type.second.id << "'s member count.";
+ << type->id() << "'s member count.";
return false);
return true;
}
bool idUsage::isValid<SpvOpLine>(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) {
+ auto file = module_.FindDef(inst->words[fileIndex]);
+ if (!file || SpvOpString != file->opcode()) {
DIAG(fileIndex) << "OpLine Target <id> '" << inst->words[fileIndex]
<< "' is not an OpString.";
return false;
bool idUsage::isValid<SpvOpMemberDecorate>(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) {
+ auto structType = module_.FindDef(inst->words[structTypeIndex]);
+ if (!structType || SpvOpTypeStruct != structType->opcode()) {
DIAG(structTypeIndex) << "OpMemberDecorate Structure type <id> '"
<< inst->words[structTypeIndex]
<< "' is not a struct type.";
}
auto memberIndex = 2;
auto member = inst->words[memberIndex];
- auto memberCount = static_cast<uint32_t>(structType.second.words.size() - 2);
+ auto memberCount = static_cast<uint32_t>(structType->words().size() - 2);
spvCheck(memberCount < member, DIAG(memberIndex)
<< "OpMemberDecorate Structure type <id> '"
<< inst->words[memberIndex]
bool idUsage::isValid<SpvOpGroupDecorate>(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) {
+ auto decorationGroup = module_.FindDef(inst->words[decorationGroupIndex]);
+ if (!decorationGroup || SpvOpDecorationGroup != decorationGroup->opcode()) {
DIAG(decorationGroupIndex) << "OpGroupDecorate Decoration group <id> '"
<< inst->words[decorationGroupIndex]
<< "' is not a decoration group.";
bool idUsage::isValid<SpvOpEntryPoint>(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) {
+ auto entryPoint = module_.FindDef(inst->words[entryPointIndex]);
+ if (!entryPoint || SpvOpFunction != entryPoint->opcode()) {
DIAG(entryPointIndex) << "OpEntryPoint Entry Point <id> '"
<< inst->words[entryPointIndex]
<< "' is not a function.";
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()) {
+ auto entryPointType = module_.FindDef(entryPoint->words()[4]);
+ if (!entryPointType || 3 != entryPointType->words().size()) {
DIAG(entryPointIndex) << "OpEntryPoint Entry Point <id> '"
<< 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) {
+ auto returnType = module_.FindDef(entryPoint->type_id());
+ if (!returnType || SpvOpTypeVoid != returnType->opcode()) {
DIAG(entryPointIndex) << "OpEntryPoint Entry Point <id> '"
<< inst->words[entryPointIndex]
<< "'s function return type is not void.";
bool idUsage::isValid<SpvOpTypeVector>(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)) {
+ auto componentType = module_.FindDef(inst->words[componentIndex]);
+ if (!componentType || !spvOpcodeIsScalarType(componentType->opcode())) {
DIAG(componentIndex) << "OpTypeVector Component Type <id> '"
<< inst->words[componentIndex]
<< "' is not a scalar type.";
bool idUsage::isValid<SpvOpTypeMatrix>(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) {
+ auto columnType = module_.FindDef(inst->words[columnTypeIndex]);
+ if (!columnType || SpvOpTypeVector != columnType->opcode()) {
DIAG(columnTypeIndex) << "OpTypeMatrix Column Type <id> '"
<< inst->words[columnTypeIndex]
<< "' is not a vector.";
bool idUsage::isValid<SpvOpTypeArray>(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)) {
+ auto elementType = module_.FindDef(inst->words[elementTypeIndex]);
+ if (!elementType || !spvOpcodeGeneratesType(elementType->opcode())) {
DIAG(elementTypeIndex) << "OpTypeArray Element Type <id> '"
<< inst->words[elementTypeIndex]
<< "' is not a type.";
return false;
}
auto lengthIndex = 3;
- auto length = usedefs_.FindDef(inst->words[lengthIndex]);
- if (!length.first || !spvOpcodeIsConstant(length.second.opcode)) {
+ auto length = module_.FindDef(inst->words[lengthIndex]);
+ if (!length || !spvOpcodeIsConstant(length->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.words;
+ auto constInst = length->words();
auto constResultTypeIndex = 1;
- auto constResultType = usedefs_.FindDef(constInst[constResultTypeIndex]);
- if (!constResultType.first || SpvOpTypeInt != constResultType.second.opcode) {
+ auto constResultType = module_.FindDef(constInst[constResultTypeIndex]);
+ if (!constResultType || SpvOpTypeInt != constResultType->opcode()) {
DIAG(lengthIndex) << "OpTypeArray Length <id> '" << inst->words[lengthIndex]
<< "' is not a constant integer type.";
return false;
}
- switch (length.second.opcode) {
+ switch (length->opcode()) {
case SpvOpSpecConstant:
case SpvOpConstant:
- if (aboveZero(length.second.words, constResultType.second.words)) break;
+ if (aboveZero(length->words(), constResultType->words())) break;
// Else fall through!
case SpvOpConstantNull: {
DIAG(lengthIndex) << "OpTypeArray Length <id> '"
bool idUsage::isValid<SpvOpTypeRuntimeArray>(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)) {
+ auto elementType = module_.FindDef(inst->words[elementTypeIndex]);
+ if (!elementType || !spvOpcodeGeneratesType(elementType->opcode())) {
DIAG(elementTypeIndex) << "OpTypeRuntimeArray Element Type <id> '"
<< inst->words[elementTypeIndex]
<< "' is not a type.";
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)) {
+ auto memberType = module_.FindDef(inst->words[memberTypeIndex]);
+ if (!memberType || !spvOpcodeGeneratesType(memberType->opcode())) {
DIAG(memberTypeIndex) << "OpTypeStruct Member Type <id> '"
<< inst->words[memberTypeIndex]
<< "' is not a type.";
bool idUsage::isValid<SpvOpTypePointer>(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)) {
+ auto type = module_.FindDef(inst->words[typeIndex]);
+ if (!type || !spvOpcodeGeneratesType(type->opcode())) {
DIAG(typeIndex) << "OpTypePointer Type <id> '" << inst->words[typeIndex]
<< "' is not a type.";
return false;
bool idUsage::isValid<SpvOpTypeFunction>(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)) {
+ auto returnType = module_.FindDef(inst->words[returnTypeIndex]);
+ if (!returnType || !spvOpcodeGeneratesType(returnType->opcode())) {
DIAG(returnTypeIndex) << "OpTypeFunction Return Type <id> '"
<< 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)) {
+ auto paramType = module_.FindDef(inst->words[paramTypeIndex]);
+ if (!paramType || !spvOpcodeGeneratesType(paramType->opcode())) {
DIAG(paramTypeIndex) << "OpTypeFunction Parameter Type <id> '"
<< inst->words[paramTypeIndex] << "' is not a type.";
return false;
bool idUsage::isValid<SpvOpConstantTrue>(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) {
+ auto resultType = module_.FindDef(inst->words[resultTypeIndex]);
+ if (!resultType || SpvOpTypeBool != resultType->opcode()) {
DIAG(resultTypeIndex) << "OpConstantTrue Result Type <id> '"
<< inst->words[resultTypeIndex]
<< "' is not a boolean type.";
bool idUsage::isValid<SpvOpConstantFalse>(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) {
+ auto resultType = module_.FindDef(inst->words[resultTypeIndex]);
+ if (!resultType || SpvOpTypeBool != resultType->opcode()) {
DIAG(resultTypeIndex) << "OpConstantFalse Result Type <id> '"
<< inst->words[resultTypeIndex]
<< "' is not a boolean type.";
bool idUsage::isValid<SpvOpConstantComposite>(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)) {
+ auto resultType = module_.FindDef(inst->words[resultTypeIndex]);
+ if (!resultType || !spvOpcodeIsComposite(resultType->opcode())) {
DIAG(resultTypeIndex) << "OpConstantComposite Result Type <id> '"
<< inst->words[resultTypeIndex]
<< "' is not a composite type.";
}
auto constituentCount = inst->words.size() - 3;
- switch (resultType.second.opcode) {
+ switch (resultType->opcode()) {
case SpvOpTypeVector: {
- auto componentCount = resultType.second.words[3];
+ auto componentCount = resultType->words()[3];
spvCheck(
componentCount != constituentCount,
// TODO: Output ID's on diagnostic
DIAG(inst->words.size() - 1)
<< "OpConstantComposite Constituent <id> count does not match "
"Result Type <id> '"
- << resultType.second.id << "'s vector component count.";
+ << resultType->id() << "'s vector component count.";
return false);
- auto componentType = usedefs_.FindDef(resultType.second.words[2]);
- assert(componentType.first);
+ auto componentType = module_.FindDef(resultType->words()[2]);
+ assert(componentType);
for (size_t constituentIndex = 3; constituentIndex < inst->words.size();
constituentIndex++) {
- auto constituent = usedefs_.FindDef(inst->words[constituentIndex]);
- if (!constituent.first ||
- !spvOpcodeIsConstant(constituent.second.opcode)) {
+ auto constituent = module_.FindDef(inst->words[constituentIndex]);
+ if (!constituent || !spvOpcodeIsConstant(constituent->opcode())) {
DIAG(constituentIndex) << "OpConstantComposite Constituent <id> '"
<< 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) {
+ auto constituentResultType = module_.FindDef(constituent->type_id());
+ if (!constituentResultType ||
+ componentType->opcode() != constituentResultType->opcode()) {
DIAG(constituentIndex) << "OpConstantComposite Constituent <id> '"
<< inst->words[constituentIndex]
<< "'s type does not match Result Type <id> '"
- << resultType.second.id
+ << resultType->id()
<< "'s vector element type.";
return false;
}
}
} break;
case SpvOpTypeMatrix: {
- auto columnCount = resultType.second.words[3];
+ auto columnCount = resultType->words()[3];
spvCheck(
columnCount != constituentCount,
// TODO: Output ID's on diagnostic
DIAG(inst->words.size() - 1)
<< "OpConstantComposite Constituent <id> count does not match "
"Result Type <id> '"
- << resultType.second.id << "'s matrix column count.";
+ << resultType->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);
+ auto columnType = module_.FindDef(resultType->words()[2]);
+ assert(columnType);
+ auto componentCount = columnType->words()[3];
+ auto componentType = module_.FindDef(columnType->words()[2]);
+ assert(componentType);
for (size_t constituentIndex = 3; constituentIndex < inst->words.size();
constituentIndex++) {
- auto constituent = usedefs_.FindDef(inst->words[constituentIndex]);
- if (!constituent.first ||
- SpvOpConstantComposite != constituent.second.opcode) {
+ auto constituent = module_.FindDef(inst->words[constituentIndex]);
+ if (!constituent || SpvOpConstantComposite != constituent->opcode()) {
DIAG(constituentIndex) << "OpConstantComposite Constituent <id> '"
<< 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,
+ auto vector = module_.FindDef(constituent->type_id());
+ assert(vector);
+ spvCheck(columnType->opcode() != vector->opcode(),
DIAG(constituentIndex)
<< "OpConstantComposite Constituent <id> '"
<< inst->words[constituentIndex]
<< "' type does not match Result Type <id> '"
- << resultType.second.id << "'s matrix column type.";
+ << resultType->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,
+ auto vectorComponentType = module_.FindDef(vector->words()[2]);
+ assert(vectorComponentType);
+ spvCheck(componentType->id() != vectorComponentType->id(),
DIAG(constituentIndex)
<< "OpConstantComposite Constituent <id> '"
<< inst->words[constituentIndex]
<< "' component type does not match Result Type <id> '"
- << resultType.second.id
- << "'s matrix column component type.";
+ << resultType->id() << "'s matrix column component type.";
return false);
spvCheck(
- componentCount != vector.second.words[3],
+ componentCount != vector->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.";
+ << resultType->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,
+ auto elementType = module_.FindDef(resultType->words()[2]);
+ assert(elementType);
+ auto length = module_.FindDef(resultType->words()[3]);
+ assert(length);
+ spvCheck(length->words()[3] != constituentCount,
DIAG(inst->words.size() - 1)
<< "OpConstantComposite Constituent count does not match "
"Result Type <id> '"
- << resultType.second.id << "'s array length.";
+ << resultType->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)) {
+ auto constituent = module_.FindDef(inst->words[constituentIndex]);
+ if (!constituent || !spvOpcodeIsConstant(constituent->opcode())) {
DIAG(constituentIndex) << "OpConstantComposite Constituent <id> '"
<< 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,
+ auto constituentType = module_.FindDef(constituent->type_id());
+ assert(constituentType);
+ spvCheck(elementType->id() != constituentType->id(),
DIAG(constituentIndex)
<< "OpConstantComposite Constituent <id> '"
<< inst->words[constituentIndex]
<< "'s type does not match Result Type <id> '"
- << resultType.second.id << "'s array element type.";
+ << resultType->id() << "'s array element type.";
return false);
}
} break;
case SpvOpTypeStruct: {
- auto memberCount = resultType.second.words.size() - 2;
+ auto memberCount = resultType->words().size() - 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.";
+ << resultType->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)) {
+ auto constituent = module_.FindDef(inst->words[constituentIndex]);
+ if (!constituent || !spvOpcodeIsConstant(constituent->opcode())) {
DIAG(constituentIndex) << "OpConstantComposite Constituent <id> '"
<< inst->words[constituentIndex]
<< "' is not a constant.";
return false;
}
- auto constituentType = usedefs_.FindDef(constituent.second.type_id);
- assert(constituentType.first);
+ auto constituentType = module_.FindDef(constituent->type_id());
+ assert(constituentType);
- auto memberType =
- usedefs_.FindDef(resultType.second.words[memberIndex]);
- assert(memberType.first);
- spvCheck(memberType.second.id != constituentType.second.id,
+ auto memberType = module_.FindDef(resultType->words()[memberIndex]);
+ assert(memberType);
+ spvCheck(memberType->id() != constituentType->id(),
DIAG(constituentIndex)
<< "OpConstantComposite Constituent <id> '"
<< inst->words[constituentIndex]
<< "' type does not match the Result Type <id> '"
- << resultType.second.id << "'s member type.";
+ << resultType->id() << "'s member type.";
return false);
}
} break;
bool idUsage::isValid<SpvOpConstantSampler>(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) {
+ auto resultType = module_.FindDef(inst->words[resultTypeIndex]);
+ if (!resultType || SpvOpTypeSampler != resultType->opcode()) {
DIAG(resultTypeIndex) << "OpConstantSampler Result Type <id> '"
<< inst->words[resultTypeIndex]
<< "' is not a sampler type.";
}
// 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
+// the SPIR-V spec. Tracks composite-type components through module to check
// nullability transitively.
bool IsTypeNullable(const std::vector<uint32_t>& instruction,
- const UseDefTracker& usedefs) {
+ const ValidationState_t& module) {
uint16_t opcode;
uint16_t word_count;
spvOpcodeSplit(instruction[0], &word_count, &opcode);
case SpvOpTypeArray:
case SpvOpTypeMatrix:
case SpvOpTypeVector: {
- auto base_type = usedefs.FindDef(instruction[2]);
- return base_type.first && IsTypeNullable(base_type.second.words, usedefs);
+ auto base_type = module.FindDef(instruction[2]);
+ return base_type && IsTypeNullable(base_type->words(), module);
}
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;
+ auto element = module.FindDef(instruction[elementIndex]);
+ if (!element || !IsTypeNullable(element->words(), module)) return false;
}
return true;
}
bool idUsage::isValid<SpvOpConstantNull>(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_)) {
+ auto resultType = module_.FindDef(inst->words[resultTypeIndex]);
+ if (!resultType || !IsTypeNullable(resultType->words(), module_)) {
DIAG(resultTypeIndex) << "OpConstantNull Result Type <id> '"
<< inst->words[resultTypeIndex]
<< "' cannot have a null value.";
bool idUsage::isValid<SpvOpSpecConstantTrue>(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) {
+ auto resultType = module_.FindDef(inst->words[resultTypeIndex]);
+ if (!resultType || SpvOpTypeBool != resultType->opcode()) {
DIAG(resultTypeIndex) << "OpSpecConstantTrue Result Type <id> '"
<< inst->words[resultTypeIndex]
<< "' is not a boolean type.";
bool idUsage::isValid<SpvOpSpecConstantFalse>(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) {
+ auto resultType = module_.FindDef(inst->words[resultTypeIndex]);
+ if (!resultType || SpvOpTypeBool != resultType->opcode()) {
DIAG(resultTypeIndex) << "OpSpecConstantFalse Result Type <id> '"
<< inst->words[resultTypeIndex]
<< "' is not a boolean type.";
bool idUsage::isValid<SpvOpVariable>(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) {
+ auto resultType = module_.FindDef(inst->words[resultTypeIndex]);
+ if (!resultType || SpvOpTypePointer != resultType->opcode()) {
DIAG(resultTypeIndex) << "OpVariable Result Type <id> '"
<< inst->words[resultTypeIndex]
<< "' is not a pointer type.";
}
if (opcodeEntry->numTypes < inst->words.size()) {
auto initialiserIndex = 4;
- auto initialiser = usedefs_.FindDef(inst->words[initialiserIndex]);
- if (!initialiser.first || !spvOpcodeIsConstant(initialiser.second.opcode)) {
+ auto initialiser = module_.FindDef(inst->words[initialiserIndex]);
+ if (!initialiser || !spvOpcodeIsConstant(initialiser->opcode())) {
DIAG(initialiserIndex) << "OpVariable Initializer <id> '"
<< inst->words[initialiserIndex]
<< "' is not a constant.";
bool idUsage::isValid<SpvOpLoad>(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 <id> '"
- << inst->words[resultTypeIndex]
- << "' is not defind.";
+ auto resultType = module_.FindDef(inst->words[resultTypeIndex]);
+ spvCheck(!resultType, DIAG(resultTypeIndex) << "OpLoad Result Type <id> '"
+ << inst->words[resultTypeIndex]
+ << "' is not defind.";
return false);
auto pointerIndex = 3;
- auto pointer = usedefs_.FindDef(inst->words[pointerIndex]);
- if (!pointer.first ||
- (addressingModel == SpvAddressingModelLogical &&
- !spvOpcodeReturnsLogicalPointer(pointer.second.opcode))) {
+ auto pointer = module_.FindDef(inst->words[pointerIndex]);
+ if (!pointer || (addressingModel == SpvAddressingModelLogical &&
+ !spvOpcodeReturnsLogicalPointer(pointer->opcode()))) {
DIAG(pointerIndex) << "OpLoad Pointer <id> '" << inst->words[pointerIndex]
<< "' is not a pointer.";
return false;
}
- auto pointerType = usedefs_.FindDef(pointer.second.type_id);
- if (!pointerType.first || pointerType.second.opcode != SpvOpTypePointer) {
+ auto pointerType = module_.FindDef(pointer->type_id());
+ if (!pointerType || pointerType->opcode() != SpvOpTypePointer) {
DIAG(pointerIndex) << "OpLoad type for pointer <id> '"
<< 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) {
+ auto pointeeType = module_.FindDef(pointerType->words()[3]);
+ if (!pointeeType || resultType->id() != pointeeType->id()) {
DIAG(resultTypeIndex) << "OpLoad Result Type <id> '"
<< inst->words[resultTypeIndex]
- << "' does not match Pointer <id> '"
- << pointer.second.id << "'s type.";
+ << "' does not match Pointer <id> '" << pointer->id()
+ << "'s type.";
return false;
}
return true;
bool idUsage::isValid<SpvOpStore>(const spv_instruction_t* inst,
const spv_opcode_desc) {
auto pointerIndex = 1;
- auto pointer = usedefs_.FindDef(inst->words[pointerIndex]);
- if (!pointer.first ||
- (addressingModel == SpvAddressingModelLogical &&
- !spvOpcodeReturnsLogicalPointer(pointer.second.opcode))) {
+ auto pointer = module_.FindDef(inst->words[pointerIndex]);
+ if (!pointer || (addressingModel == SpvAddressingModelLogical &&
+ !spvOpcodeReturnsLogicalPointer(pointer->opcode()))) {
DIAG(pointerIndex) << "OpStore Pointer <id> '" << inst->words[pointerIndex]
<< "' is not a pointer.";
return false;
}
- auto pointerType = usedefs_.FindDef(pointer.second.type_id);
- if (!pointer.first || pointerType.second.opcode != SpvOpTypePointer) {
+ auto pointerType = module_.FindDef(pointer->type_id());
+ if (!pointer || pointerType->opcode() != SpvOpTypePointer) {
DIAG(pointerIndex) << "OpStore type for pointer <id> '"
<< inst->words[pointerIndex]
<< "' is not a pointer type.";
return false;
}
- auto type = usedefs_.FindDef(pointerType.second.words[3]);
- assert(type.first);
- spvCheck(SpvOpTypeVoid == type.second.opcode, DIAG(pointerIndex)
- << "OpStore Pointer <id> '"
- << inst->words[pointerIndex]
- << "'s type is void.";
+ auto type = module_.FindDef(pointerType->words()[3]);
+ assert(type);
+ spvCheck(SpvOpTypeVoid == type->opcode(), DIAG(pointerIndex)
+ << "OpStore Pointer <id> '"
+ << 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) {
+ auto object = module_.FindDef(inst->words[objectIndex]);
+ if (!object || !object->type_id()) {
DIAG(objectIndex) << "OpStore Object <id> '" << 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,
+ auto objectType = module_.FindDef(object->type_id());
+ assert(objectType);
+ spvCheck(SpvOpTypeVoid == objectType->opcode(),
DIAG(objectIndex) << "OpStore Object <id> '"
<< inst->words[objectIndex] << "'s type is void.";
return false);
- spvCheck(type.second.id != objectType.second.id,
+ spvCheck(type->id() != objectType->id(),
DIAG(pointerIndex)
<< "OpStore Pointer <id> '" << inst->words[pointerIndex]
- << "'s type does not match Object <id> '" << objectType.second.id
+ << "'s type does not match Object <id> '" << objectType->id()
<< "'s type.";
return false);
return true;
bool idUsage::isValid<SpvOpCopyMemory>(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 target = module_.FindDef(inst->words[targetIndex]);
+ if (!target) 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,
+ auto source = module_.FindDef(inst->words[sourceIndex]);
+ if (!source) return false;
+ auto targetPointerType = module_.FindDef(target->type_id());
+ assert(targetPointerType);
+ auto targetType = module_.FindDef(targetPointerType->words()[3]);
+ assert(targetType);
+ auto sourcePointerType = module_.FindDef(source->type_id());
+ assert(sourcePointerType);
+ auto sourceType = module_.FindDef(sourcePointerType->words()[3]);
+ assert(sourceType);
+ spvCheck(targetType->id() != sourceType->id(),
DIAG(sourceIndex)
<< "OpCopyMemory Target <id> '" << inst->words[sourceIndex]
- << "'s type does not match Source <id> '" << sourceType.second.id
+ << "'s type does not match Source <id> '" << sourceType->id()
<< "'s type.";
return false);
return true;
bool idUsage::isValid<SpvOpCopyMemorySized>(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 target = module_.FindDef(inst->words[targetIndex]);
+ if (!target) return false;
auto sourceIndex = 2;
- auto source = usedefs_.FindDef(inst->words[sourceIndex]);
- if (!source.first) return false;
+ auto source = module_.FindDef(inst->words[sourceIndex]);
+ if (!source) 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 <id> '"
- << 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 <id> '"
- << inst->words[sourceIndex]
- << "' is not a pointer.";
- return false);
- switch (size.second.opcode) {
+ auto size = module_.FindDef(inst->words[sizeIndex]);
+ if (!size) return false;
+ auto targetPointerType = module_.FindDef(target->type_id());
+ spvCheck(
+ !targetPointerType || SpvOpTypePointer != targetPointerType->opcode(),
+ DIAG(targetIndex) << "OpCopyMemorySized Target <id> '"
+ << inst->words[targetIndex] << "' is not a pointer.";
+ return false);
+ auto sourcePointerType = module_.FindDef(source->type_id());
+ spvCheck(
+ !sourcePointerType || SpvOpTypePointer != sourcePointerType->opcode(),
+ DIAG(sourceIndex) << "OpCopyMemorySized Source <id> '"
+ << inst->words[sourceIndex] << "' is not a pointer.";
+ return false);
+ switch (size->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,
+ auto sizeType = module_.FindDef(size->type_id());
+ assert(sizeType);
+ spvCheck(SpvOpTypeInt != sizeType->opcode(),
DIAG(sizeIndex) << "OpCopyMemorySized Size <id> '"
<< 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,
+ auto pointerType = module_.FindDef(size->type_id());
+ assert(pointerType);
+ auto sizeType = module_.FindDef(pointerType->type_id());
+ spvCheck(!sizeType || SpvOpTypeInt != sizeType->opcode(),
DIAG(sizeIndex) << "OpCopyMemorySized Size <id> '"
<< inst->words[sizeIndex]
<< "'s variable type is not an integer type.";
bool idUsage::isValid<SpvOpFunction>(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 resultType = module_.FindDef(inst->words[resultTypeIndex]);
+ if (!resultType) return false;
auto functionTypeIndex = 4;
- auto functionType = usedefs_.FindDef(inst->words[functionTypeIndex]);
- if (!functionType.first || SpvOpTypeFunction != functionType.second.opcode) {
+ auto functionType = module_.FindDef(inst->words[functionTypeIndex]);
+ if (!functionType || SpvOpTypeFunction != functionType->opcode()) {
DIAG(functionTypeIndex) << "OpFunction Function Type <id> '"
<< 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,
+ auto returnType = module_.FindDef(functionType->words()[2]);
+ assert(returnType);
+ spvCheck(returnType->id() != resultType->id(),
DIAG(resultTypeIndex) << "OpFunction Result Type <id> '"
<< inst->words[resultTypeIndex]
<< "' does not match the Function Type <id> '"
- << resultType.second.id << "'s return type.";
+ << resultType->id() << "'s return type.";
return false);
return true;
}
bool idUsage::isValid<SpvOpFunctionParameter>(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 resultType = module_.FindDef(inst->words[resultTypeIndex]);
+ if (!resultType) return false;
// NOTE: Find OpFunction & ensure OpFunctionParameter is not out of place.
size_t paramIndex = 0;
assert(firstInst < inst && "Invalid instruction pointer");
paramIndex++;
}
}
- auto functionType = usedefs_.FindDef(inst->words[4]);
- assert(functionType.first);
- if (paramIndex >= functionType.second.words.size() - 3) {
+ auto functionType = module_.FindDef(inst->words[4]);
+ assert(functionType);
+ if (paramIndex >= functionType->words().size() - 3) {
DIAG(0) << "Too many OpFunctionParameters for " << inst->words[2]
- << ": expected " << functionType.second.words.size() - 3
+ << ": expected " << functionType->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,
+ auto paramType = module_.FindDef(functionType->words()[paramIndex + 3]);
+ assert(paramType);
+ spvCheck(resultType->id() != paramType->id(),
DIAG(resultTypeIndex)
<< "OpFunctionParameter Result Type <id> '"
<< inst->words[resultTypeIndex]
bool idUsage::isValid<SpvOpFunctionCall>(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 resultType = module_.FindDef(inst->words[resultTypeIndex]);
+ if (!resultType) return false;
auto functionIndex = 3;
- auto function = usedefs_.FindDef(inst->words[functionIndex]);
- if (!function.first || SpvOpFunction != function.second.opcode) {
+ auto function = module_.FindDef(inst->words[functionIndex]);
+ if (!function || SpvOpFunction != function->opcode()) {
DIAG(functionIndex) << "OpFunctionCall Function <id> '"
<< 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,
+ auto returnType = module_.FindDef(function->type_id());
+ assert(returnType);
+ spvCheck(returnType->id() != resultType->id(),
DIAG(resultTypeIndex) << "OpFunctionCall Result Type <id> '"
<< inst->words[resultTypeIndex]
<< "'s type does not match Function <id> '"
- << returnType.second.id << "'s return type.";
+ << returnType->id() << "'s return type.";
return false);
- auto functionType = usedefs_.FindDef(function.second.words[4]);
- assert(functionType.first);
+ auto functionType = module_.FindDef(function->words()[4]);
+ assert(functionType);
auto functionCallArgCount = inst->words.size() - 4;
- auto functionParamCount = functionType.second.words.size() - 3;
+ auto functionParamCount = functionType->words().size() - 3;
spvCheck(
functionParamCount != functionCallArgCount,
DIAG(inst->words.size() - 1)
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,
+ auto argument = module_.FindDef(inst->words[argumentIndex]);
+ if (!argument) return false;
+ auto argumentType = module_.FindDef(argument->type_id());
+ assert(argumentType);
+ auto parameterType = module_.FindDef(functionType->words()[paramIndex]);
+ assert(parameterType);
+ spvCheck(argumentType->id() != parameterType->id(),
DIAG(argumentIndex) << "OpFunctionCall Argument <id> '"
<< inst->words[argumentIndex]
<< "'s type does not match Function <id> '"
- << parameterType.second.id
- << "'s parameter type.";
+ << parameterType->id() << "'s parameter type.";
return false);
}
return true;
bool idUsage::isValid<SpvOpReturnValue>(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) {
+ auto value = module_.FindDef(inst->words[valueIndex]);
+ if (!value || !value->type_id()) {
DIAG(valueIndex) << "OpReturnValue Value <id> '" << 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 <id> '"
- << value.second.type_id << "' is missing or void.";
+ auto valueType = module_.FindDef(value->type_id());
+ if (!valueType || SpvOpTypeVoid == valueType->opcode()) {
+ DIAG(valueIndex) << "OpReturnValue value's type <id> '" << value->type_id()
+ << "' is missing or void.";
return false;
}
if (addressingModel == SpvAddressingModelLogical &&
- SpvOpTypePointer == valueType.second.opcode) {
+ SpvOpTypePointer == valueType->opcode()) {
DIAG(valueIndex)
- << "OpReturnValue value's type <id> '" << value.second.type_id
+ << "OpReturnValue value's type <id> '" << value->type_id()
<< "' is a pointer, which is invalid in the Logical addressing model.";
return false;
}
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,
+ auto returnType = module_.FindDef(function->words[1]);
+ spvCheck(!returnType || returnType->id() != valueType->id(),
DIAG(valueIndex)
<< "OpReturnValue Value <id> '" << inst->words[valueIndex]
<< "'s type does not match OpFunction's return type.";
#undef TODO
#undef CASE
}
+// This function takes the opcode of an instruction and returns
+// a function object that will return true if the index
+// of the operand can be forwarad declared. This function will
+// used in the SSA validation stage of the pipeline
+function<bool(unsigned)> getCanBeForwardDeclaredFunction(SpvOp opcode) {
+ function<bool(unsigned index)> out;
+ switch (opcode) {
+ case SpvOpExecutionMode:
+ case SpvOpEntryPoint:
+ case SpvOpName:
+ case SpvOpMemberName:
+ case SpvOpSelectionMerge:
+ case SpvOpDecorate:
+ case SpvOpMemberDecorate:
+ case SpvOpBranch:
+ case SpvOpLoopMerge:
+ out = [](unsigned) { return true; };
+ break;
+ case SpvOpGroupDecorate:
+ case SpvOpGroupMemberDecorate:
+ case SpvOpBranchConditional:
+ case SpvOpSwitch:
+ out = [](unsigned index) { return index != 0; };
+ break;
+
+ case SpvOpFunctionCall:
+ out = [](unsigned index) { return index == 2; };
+ break;
+
+ case SpvOpPhi:
+ out = [](unsigned index) { return index > 1; };
+ break;
+
+ case SpvOpEnqueueKernel:
+ out = [](unsigned index) { return index == 8; };
+ break;
+
+ case SpvOpGetKernelNDrangeSubGroupCount:
+ case SpvOpGetKernelNDrangeMaxSubGroupSize:
+ out = [](unsigned index) { return index == 3; };
+ break;
+
+ case SpvOpGetKernelWorkGroupSize:
+ case SpvOpGetKernelPreferredWorkGroupSizeMultiple:
+ out = [](unsigned index) { return index == 2; };
+ break;
+
+ default:
+ out = [](unsigned) { return false; };
+ break;
+ }
+ return out;
+}
} // anonymous namespace
+namespace libspirv {
+
+// Performs SSA validation on the IDs of an instruction. The
+// can_have_forward_declared_ids functor should return true if the
+// instruction operand's ID can be forward referenced.
+//
+// TODO(umar): Use dominators to correctly validate SSA. For example, the result
+// id from a 'then' block cannot dominate its usage in the 'else' block. This
+// is not yet performed by this function.
+spv_result_t IdPass(ValidationState_t& _,
+ const spv_parsed_instruction_t* inst) {
+ auto can_have_forward_declared_ids =
+ getCanBeForwardDeclaredFunction(static_cast<SpvOp>(inst->opcode));
+
+ for (unsigned i = 0; i < inst->num_operands; i++) {
+ const spv_parsed_operand_t& operand = inst->operands[i];
+ const spv_operand_type_t& type = operand.type;
+ const uint32_t* operand_ptr = inst->words + operand.offset;
+
+ auto ret = SPV_ERROR_INTERNAL;
+ switch (type) {
+ case SPV_OPERAND_TYPE_RESULT_ID:
+ _.RemoveIfForwardDeclared(*operand_ptr);
+ _.AddId(*inst);
+ ret = SPV_SUCCESS;
+ break;
+ case SPV_OPERAND_TYPE_ID:
+ case SPV_OPERAND_TYPE_TYPE_ID:
+ case SPV_OPERAND_TYPE_MEMORY_SEMANTICS_ID:
+ case SPV_OPERAND_TYPE_SCOPE_ID:
+ if (_.IsDefinedId(*operand_ptr)) {
+ _.RegisterUseId(*operand_ptr);
+ ret = SPV_SUCCESS;
+ } else if (can_have_forward_declared_ids(i)) {
+ ret = _.ForwardDeclareId(*operand_ptr);
+ } else {
+ ret = _.diag(SPV_ERROR_INVALID_ID) << "ID "
+ << _.getIdName(*operand_ptr)
+ << " has not been defined";
+ }
+ break;
+ default:
+ ret = SPV_SUCCESS;
+ break;
+ }
+ if (SPV_SUCCESS != ret) {
+ return ret;
+ }
+ }
+ return SPV_SUCCESS;
+}
+} // namespace libspirv
+
spv_result_t spvValidateInstructionIDs(const spv_instruction_t* pInsts,
const uint64_t instCount,
const spv_opcode_table opcodeTable,
spv_position position,
spv_diagnostic* pDiag) {
idUsage idUsage(opcodeTable, operandTable, extInstTable, pInsts, instCount,
- state.memory_model(), state.addressing_model(),
- state.usedefs(), state.entry_points(), position, pDiag);
+ state.memory_model(), state.addressing_model(), state,
+ 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();
#include <utility>
using ::testing::HasSubstr;
+using ::testing::MatchesRegex;
using std::string;
using std::pair;
using std::stringstream;
namespace {
-using Validate = spvtest::ValidateBase<pair<string, bool>>;
+using ValidateSSA = spvtest::ValidateBase<pair<string, bool>>;
-TEST_F(Validate, Default) {
+TEST_F(ValidateSSA, Default) {
char str[] = R"(
OpCapability Shader
OpMemoryModel Logical GLSL450
ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
}
-TEST_F(Validate, IdUndefinedBad) {
+TEST_F(ValidateSSA, IdUndefinedBad) {
char str[] = R"(
OpCapability Shader
OpMemoryModel Logical GLSL450
EXPECT_THAT(getDiagnosticString(), HasSubstr("missing"));
}
-TEST_F(Validate, IdRedefinedBad) {
+TEST_F(ValidateSSA, IdRedefinedBad) {
char str[] = R"(
OpCapability Shader
OpMemoryModel Logical GLSL450
ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
}
-TEST_F(Validate, DominateUsageBad) {
+TEST_F(ValidateSSA, DominateUsageBad) {
char str[] = R"(
OpCapability Shader
OpMemoryModel Logical GLSL450
EXPECT_THAT(getDiagnosticString(), HasSubstr("not_dominant"));
}
-TEST_F(Validate, ForwardNameGood) {
+TEST_F(ValidateSSA, ForwardNameGood) {
char str[] = R"(
OpCapability Shader
OpMemoryModel Logical GLSL450
ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
}
-TEST_F(Validate, ForwardNameMissingTargetBad) {
+TEST_F(ValidateSSA, ForwardNameMissingTargetBad) {
char str[] = R"(
OpCapability Shader
OpMemoryModel Logical GLSL450
EXPECT_THAT(getDiagnosticString(), HasSubstr("main"));
}
-TEST_F(Validate, ForwardMemberNameGood) {
+TEST_F(ValidateSSA, ForwardMemberNameGood) {
char str[] = R"(
OpCapability Shader
OpMemoryModel Logical GLSL450
ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
}
-TEST_F(Validate, ForwardMemberNameMissingTargetBad) {
+TEST_F(ValidateSSA, ForwardMemberNameMissingTargetBad) {
char str[] = R"(
OpCapability Shader
OpMemoryModel Logical GLSL450
EXPECT_THAT(getDiagnosticString(), HasSubstr("size"));
}
-TEST_F(Validate, ForwardDecorateGood) {
+TEST_F(ValidateSSA, ForwardDecorateGood) {
char str[] = R"(
OpCapability Shader
OpMemoryModel Logical GLSL450
ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
}
-TEST_F(Validate, ForwardDecorateInvalidIDBad) {
+TEST_F(ValidateSSA, ForwardDecorateInvalidIDBad) {
char str[] = R"(
OpCapability Shader
OpMemoryModel Logical GLSL450
EXPECT_THAT(getDiagnosticString(), HasSubstr("missing"));
}
-TEST_F(Validate, ForwardMemberDecorateGood) {
+TEST_F(ValidateSSA, ForwardMemberDecorateGood) {
char str[] = R"(
OpCapability Shader
OpMemoryModel Logical GLSL450
ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
}
-TEST_F(Validate, ForwardMemberDecorateInvalidIdBad) {
+TEST_F(ValidateSSA, ForwardMemberDecorateInvalidIdBad) {
char str[] = R"(
OpCapability Shader
OpMemoryModel Logical GLSL450
EXPECT_THAT(getDiagnosticString(), HasSubstr("missing"));
}
-TEST_F(Validate, ForwardGroupDecorateGood) {
+TEST_F(ValidateSSA, ForwardGroupDecorateGood) {
char str[] = R"(
OpCapability Shader
OpMemoryModel Logical GLSL450
ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
}
-TEST_F(Validate, ForwardGroupDecorateMissingGroupBad) {
+TEST_F(ValidateSSA, ForwardGroupDecorateMissingGroupBad) {
char str[] = R"(
OpCapability Shader
OpMemoryModel Logical GLSL450
EXPECT_THAT(getDiagnosticString(), HasSubstr("missing"));
}
-TEST_F(Validate, ForwardGroupDecorateMissingTargetBad) {
+TEST_F(ValidateSSA, ForwardGroupDecorateMissingTargetBad) {
char str[] = R"(
OpCapability Shader
OpMemoryModel Logical GLSL450
EXPECT_THAT(getDiagnosticString(), HasSubstr("missing"));
}
-TEST_F(Validate, ForwardGroupDecorateDecorationGroupDominateBad) {
+TEST_F(ValidateSSA, ForwardGroupDecorateDecorationGroupDominateBad) {
char str[] = R"(
OpCapability Shader
OpMemoryModel Logical GLSL450
EXPECT_THAT(getDiagnosticString(), HasSubstr("group"));
}
-TEST_F(Validate, ForwardDecorateInvalidIdBad) {
+TEST_F(ValidateSSA, ForwardDecorateInvalidIdBad) {
char str[] = R"(
OpCapability Shader
OpMemoryModel Logical GLSL450
EXPECT_THAT(getDiagnosticString(), HasSubstr("missing"));
}
-TEST_F(Validate, FunctionCallGood) {
+TEST_F(ValidateSSA, FunctionCallGood) {
char str[] = R"(
OpCapability Shader
OpMemoryModel Logical GLSL450
ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
}
-TEST_F(Validate, ForwardFunctionCallGood) {
+TEST_F(ValidateSSA, ForwardFunctionCallGood) {
char str[] = R"(
OpCapability Shader
OpMemoryModel Logical GLSL450
ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
}
-TEST_F(Validate, ForwardBranchConditionalGood) {
+TEST_F(ValidateSSA, ForwardBranchConditionalGood) {
char str[] = R"(
OpCapability Shader
OpMemoryModel Logical GLSL450
ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
}
-TEST_F(Validate, ForwardBranchConditionalWithWeightsGood) {
+TEST_F(ValidateSSA, ForwardBranchConditionalWithWeightsGood) {
char str[] = R"(
OpCapability Shader
OpMemoryModel Logical GLSL450
ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
}
-TEST_F(Validate, ForwardBranchConditionalNonDominantConditionBad) {
+TEST_F(ValidateSSA, ForwardBranchConditionalNonDominantConditionBad) {
char str[] = R"(
OpCapability Shader
OpMemoryModel Logical GLSL450
EXPECT_THAT(getDiagnosticString(), HasSubstr("conditional"));
}
-TEST_F(Validate, ForwardBranchConditionalMissingTargetBad) {
+TEST_F(ValidateSSA, ForwardBranchConditionalMissingTargetBad) {
char str[] = R"(
OpCapability Shader
OpMemoryModel Logical GLSL450
%intt = OpTypeInt 32 1
%uintt = OpTypeInt 32 0
%vfunct = OpTypeFunction %voidt
+%intptrt = OpTypePointer UniformConstant %intt
+%zero = OpConstant %intt 0
+%one = OpConstant %intt 1
+%ten = OpConstant %intt 10
)";
const string kKernelTypesAndConstants = R"(
%ndt = OpTypeStruct %intt %arr3t %arr3t %arr3t
%eventt = OpTypeEvent
-%intptrt = OpTypePointer UniformConstant %int8t
%offset = OpConstant %intt 0
%local = OpConstant %intt 1
OpFunctionEnd
)";
-TEST_F(Validate, EnqueueKernelGood) {
+TEST_F(ValidateSSA, EnqueueKernelGood) {
string str = kHeader + kBasicTypes + kKernelTypesAndConstants +
kKernelDefinition + R"(
%main = OpFunction %voidt None %vfunct
ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
}
-TEST_F(Validate, ForwardEnqueueKernelGood) {
+TEST_F(ValidateSSA, ForwardEnqueueKernelGood) {
string str = kHeader + kBasicTypes + kKernelTypesAndConstants + R"(
%main = OpFunction %voidt None %vfunct
%mainl = OpLabel
ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
}
-TEST_F(Validate, EnqueueMissingFunctionBad) {
+TEST_F(ValidateSSA, EnqueueMissingFunctionBad) {
string str = kHeader + "OpName %kfunc \"kfunc\"" + kBasicTypes +
kKernelTypesAndConstants + R"(
%main = OpFunction %voidt None %vfunct
return out;
}
-TEST_F(Validate, ForwardEnqueueKernelMissingParameter1Bad) {
+TEST_F(ValidateSSA, ForwardEnqueueKernelMissingParameter1Bad) {
string str = forwardKernelNonDominantParameterBaseCode("missing") + R"(
%err = OpEnqueueKernel %missing %dqueue %flags %ndval
%nevent %event %revent %kfunc %firstp
EXPECT_THAT(getDiagnosticString(), HasSubstr("missing"));
}
-TEST_F(Validate, ForwardEnqueueKernelNonDominantParameter2Bad) {
+TEST_F(ValidateSSA, ForwardEnqueueKernelNonDominantParameter2Bad) {
string str = forwardKernelNonDominantParameterBaseCode("dqueue2") + R"(
%err = OpEnqueueKernel %uintt %dqueue2 %flags %ndval
%nevent %event %revent %kfunc
EXPECT_THAT(getDiagnosticString(), HasSubstr("dqueue2"));
}
-TEST_F(Validate, ForwardEnqueueKernelNonDominantParameter3Bad) {
+TEST_F(ValidateSSA, ForwardEnqueueKernelNonDominantParameter3Bad) {
string str = forwardKernelNonDominantParameterBaseCode("ndval2") + R"(
%err = OpEnqueueKernel %uintt %dqueue %flags %ndval2
%nevent %event %revent %kfunc %firstp
EXPECT_THAT(getDiagnosticString(), HasSubstr("ndval2"));
}
-TEST_F(Validate, ForwardEnqueueKernelNonDominantParameter4Bad) {
+TEST_F(ValidateSSA, ForwardEnqueueKernelNonDominantParameter4Bad) {
string str = forwardKernelNonDominantParameterBaseCode("nevent2") + R"(
%err = OpEnqueueKernel %uintt %dqueue %flags %ndval %nevent2
%event %revent %kfunc %firstp %psize
EXPECT_THAT(getDiagnosticString(), HasSubstr("nevent2"));
}
-TEST_F(Validate, ForwardEnqueueKernelNonDominantParameter5Bad) {
+TEST_F(ValidateSSA, ForwardEnqueueKernelNonDominantParameter5Bad) {
string str = forwardKernelNonDominantParameterBaseCode("event2") + R"(
%err = OpEnqueueKernel %uintt %dqueue %flags %ndval %nevent
%event2 %revent %kfunc %firstp %psize
EXPECT_THAT(getDiagnosticString(), HasSubstr("event2"));
}
-TEST_F(Validate, ForwardEnqueueKernelNonDominantParameter6Bad) {
+TEST_F(ValidateSSA, ForwardEnqueueKernelNonDominantParameter6Bad) {
string str = forwardKernelNonDominantParameterBaseCode("revent2") + R"(
%err = OpEnqueueKernel %uintt %dqueue %flags %ndval %nevent
%event %revent2 %kfunc %firstp %psize
EXPECT_THAT(getDiagnosticString(), HasSubstr("revent2"));
}
-TEST_F(Validate, ForwardEnqueueKernelNonDominantParameter8Bad) {
+TEST_F(ValidateSSA, ForwardEnqueueKernelNonDominantParameter8Bad) {
string str = forwardKernelNonDominantParameterBaseCode("firstp2") + R"(
%err = OpEnqueueKernel %uintt %dqueue %flags %ndval %nevent
%event %revent %kfunc %firstp2 %psize
EXPECT_THAT(getDiagnosticString(), HasSubstr("firstp2"));
}
-TEST_F(Validate, ForwardEnqueueKernelNonDominantParameter9Bad) {
+TEST_F(ValidateSSA, ForwardEnqueueKernelNonDominantParameter9Bad) {
string str = forwardKernelNonDominantParameterBaseCode("psize2") + R"(
%err = OpEnqueueKernel %uintt %dqueue %flags %ndval %nevent
%event %revent %kfunc %firstp %psize2
EXPECT_THAT(getDiagnosticString(), HasSubstr("psize2"));
}
-TEST_F(Validate, ForwardEnqueueKernelNonDominantParameter10Bad) {
+TEST_F(ValidateSSA, ForwardEnqueueKernelNonDominantParameter10Bad) {
string str = forwardKernelNonDominantParameterBaseCode("palign2") + R"(
%err = OpEnqueueKernel %uintt %dqueue %flags %ndval %nevent
%event %revent %kfunc %firstp %psize
EXPECT_THAT(getDiagnosticString(), HasSubstr("palign2"));
}
-TEST_F(Validate, ForwardEnqueueKernelNonDominantParameter11Bad) {
+TEST_F(ValidateSSA, ForwardEnqueueKernelNonDominantParameter11Bad) {
string str = forwardKernelNonDominantParameterBaseCode("lsize2") + R"(
%err = OpEnqueueKernel %uintt %dqueue %flags %ndval %nevent
%event %revent %kfunc %firstp %psize
{"OpGetKernelWorkGroupSize", kNoNDrange},
{"OpGetKernelPreferredWorkGroupSizeMultiple", kNoNDrange}};
-INSTANTIATE_TEST_CASE_P(KernelArgs, Validate, ::testing::ValuesIn(cases),);
+INSTANTIATE_TEST_CASE_P(KernelArgs, ValidateSSA, ::testing::ValuesIn(cases), );
static const string return_instructions = R"(
OpReturn
OpFunctionEnd
)";
-TEST_P(Validate, GetKernelGood) {
+TEST_P(ValidateSSA, GetKernelGood) {
string instruction = GetParam().first;
bool with_ndrange = GetParam().second;
string ndrange_param = with_ndrange ? " %ndval " : " ";
ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
}
-TEST_P(Validate, ForwardGetKernelGood) {
+TEST_P(ValidateSSA, ForwardGetKernelGood) {
string instruction = GetParam().first;
bool with_ndrange = GetParam().second;
string ndrange_param = with_ndrange ? " %ndval " : " ";
ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
}
-TEST_P(Validate, ForwardGetKernelMissingDefinitionBad) {
+TEST_P(ValidateSSA, ForwardGetKernelMissingDefinitionBad) {
string instruction = GetParam().first;
bool with_ndrange = GetParam().second;
string ndrange_param = with_ndrange ? " %ndval " : " ";
EXPECT_THAT(getDiagnosticString(), HasSubstr("missing"));
}
-TEST_P(Validate, ForwardGetKernelNDrangeSubGroupCountMissingParameter1Bad) {
+TEST_P(ValidateSSA, ForwardGetKernelNDrangeSubGroupCountMissingParameter1Bad) {
string instruction = GetParam().first;
bool with_ndrange = GetParam().second;
string ndrange_param = with_ndrange ? " %ndval " : " ";
EXPECT_THAT(getDiagnosticString(), HasSubstr("missing"));
}
-TEST_P(Validate, ForwardGetKernelNDrangeSubGroupCountNonDominantParameter2Bad) {
+TEST_P(ValidateSSA,
+ ForwardGetKernelNDrangeSubGroupCountNonDominantParameter2Bad) {
string instruction = GetParam().first;
bool with_ndrange = GetParam().second;
string ndrange_param = with_ndrange ? " %ndval2 " : " ";
}
}
-TEST_P(Validate, ForwardGetKernelNDrangeSubGroupCountNonDominantParameter4Bad) {
+TEST_P(ValidateSSA,
+ ForwardGetKernelNDrangeSubGroupCountNonDominantParameter4Bad) {
string instruction = GetParam().first;
bool with_ndrange = GetParam().second;
string ndrange_param = with_ndrange ? " %ndval " : " ";
EXPECT_THAT(getDiagnosticString(), HasSubstr("firstp2"));
}
-TEST_P(Validate, ForwardGetKernelNDrangeSubGroupCountNonDominantParameter5Bad) {
+TEST_P(ValidateSSA,
+ ForwardGetKernelNDrangeSubGroupCountNonDominantParameter5Bad) {
string instruction = GetParam().first;
bool with_ndrange = GetParam().second;
string ndrange_param = with_ndrange ? " %ndval " : " ";
EXPECT_THAT(getDiagnosticString(), HasSubstr("psize2"));
}
-TEST_P(Validate, ForwardGetKernelNDrangeSubGroupCountNonDominantParameter6Bad) {
+TEST_P(ValidateSSA,
+ ForwardGetKernelNDrangeSubGroupCountNonDominantParameter6Bad) {
string instruction = GetParam().first;
bool with_ndrange = GetParam().second;
string ndrange_param = with_ndrange ? " %ndval " : " ";
}
}
-TEST_F(Validate, PhiGood) {
+TEST_F(ValidateSSA, PhiGood) {
string str = kHeader + kBasicTypes +
R"(
-%zero = OpConstant %intt 0
-%one = OpConstant %intt 1
-%ten = OpConstant %intt 10
%func = OpFunction %voidt None %vfunct
%preheader = OpLabel
%init = OpCopyObject %intt %zero
ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
}
-TEST_F(Validate, PhiMissingTypeBad) {
+TEST_F(ValidateSSA, PhiMissingTypeBad) {
string str = kHeader + "OpName %missing \"missing\"" + kBasicTypes +
R"(
-%zero = OpConstant %intt 0
-%one = OpConstant %intt 1
-%ten = OpConstant %intt 10
%func = OpFunction %voidt None %vfunct
%preheader = OpLabel
%init = OpCopyObject %intt %zero
EXPECT_THAT(getDiagnosticString(), HasSubstr("missing"));
}
-TEST_F(Validate, PhiMissingIdBad) {
+TEST_F(ValidateSSA, PhiMissingIdBad) {
string str = kHeader + "OpName %missing \"missing\"" + kBasicTypes +
R"(
-%zero = OpConstant %intt 0
-%one = OpConstant %intt 1
-%ten = OpConstant %intt 10
%func = OpFunction %voidt None %vfunct
%preheader = OpLabel
%init = OpCopyObject %intt %zero
EXPECT_THAT(getDiagnosticString(), HasSubstr("missing"));
}
-TEST_F(Validate, PhiMissingLabelBad) {
+TEST_F(ValidateSSA, PhiMissingLabelBad) {
string str = kHeader + "OpName %missing \"missing\"" + kBasicTypes +
R"(
-%zero = OpConstant %intt 0
-%one = OpConstant %intt 1
-%ten = OpConstant %intt 10
%func = OpFunction %voidt None %vfunct
%preheader = OpLabel
%init = OpCopyObject %intt %zero