|
|
@@ -81,6 +81,7 @@ bool DoesDebugInfoOperandMatchExpectation(
|
|
|
const ValidationState_t& _,
|
|
|
const std::function<bool(OpenCLDebugInfo100Instructions)>& expectation,
|
|
|
const Instruction* inst, uint32_t word_index) {
|
|
|
+ if (inst->words().size() <= word_index) return false;
|
|
|
auto* debug_inst = _.FindDef(inst->word(word_index));
|
|
|
if (debug_inst->opcode() != SpvOpExtInst ||
|
|
|
debug_inst->ext_inst_type() != SPV_EXT_INST_TYPE_OPENCL_DEBUGINFO_100 ||
|
|
|
@@ -167,9 +168,16 @@ spv_result_t ValidateOperandLexicalScope(
|
|
|
spv_result_t ValidateOperandDebugType(
|
|
|
ValidationState_t& _, const std::string& debug_inst_name,
|
|
|
const Instruction* inst, uint32_t word_index,
|
|
|
- const std::function<std::string()>& ext_inst_name) {
|
|
|
+ const std::function<std::string()>& ext_inst_name,
|
|
|
+ bool allow_template_param) {
|
|
|
std::function<bool(OpenCLDebugInfo100Instructions)> expectation =
|
|
|
- [](OpenCLDebugInfo100Instructions dbg_inst) {
|
|
|
+ [&allow_template_param](OpenCLDebugInfo100Instructions dbg_inst) {
|
|
|
+ if (allow_template_param &&
|
|
|
+ (dbg_inst == OpenCLDebugInfo100DebugTypeTemplateParameter ||
|
|
|
+ dbg_inst ==
|
|
|
+ OpenCLDebugInfo100DebugTypeTemplateTemplateParameter)) {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
return OpenCLDebugInfo100DebugTypeBasic <= dbg_inst &&
|
|
|
dbg_inst <= OpenCLDebugInfo100DebugTypePtrToMember;
|
|
|
};
|
|
|
@@ -636,6 +644,45 @@ spv_result_t ValidateClspvReflectionInstruction(ValidationState_t& _,
|
|
|
return SPV_SUCCESS;
|
|
|
}
|
|
|
|
|
|
+bool IsConstIntScalarTypeWith32Or64Bits(ValidationState_t& _,
|
|
|
+ Instruction* instr) {
|
|
|
+ if (instr->opcode() != SpvOpConstant) return false;
|
|
|
+ if (!_.IsIntScalarType(instr->type_id())) return false;
|
|
|
+ uint32_t size_in_bits = _.GetBitWidth(instr->type_id());
|
|
|
+ return size_in_bits == 32 || size_in_bits == 64;
|
|
|
+}
|
|
|
+
|
|
|
+bool IsConstWithIntScalarType(ValidationState_t& _, const Instruction* inst,
|
|
|
+ uint32_t word_index) {
|
|
|
+ auto* int_scalar_const = _.FindDef(inst->word(word_index));
|
|
|
+ if (int_scalar_const->opcode() == SpvOpConstant &&
|
|
|
+ _.IsIntScalarType(int_scalar_const->type_id())) {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ return false;
|
|
|
+}
|
|
|
+
|
|
|
+bool IsDebugVariableWithIntScalarType(ValidationState_t& _,
|
|
|
+ const Instruction* inst,
|
|
|
+ uint32_t word_index) {
|
|
|
+ auto* dbg_int_scalar_var = _.FindDef(inst->word(word_index));
|
|
|
+ if (OpenCLDebugInfo100Instructions(dbg_int_scalar_var->word(4)) ==
|
|
|
+ OpenCLDebugInfo100DebugLocalVariable ||
|
|
|
+ OpenCLDebugInfo100Instructions(dbg_int_scalar_var->word(4)) ==
|
|
|
+ OpenCLDebugInfo100DebugGlobalVariable) {
|
|
|
+ auto* dbg_type = _.FindDef(dbg_int_scalar_var->word(6));
|
|
|
+ if (OpenCLDebugInfo100Instructions(dbg_type->word(4)) ==
|
|
|
+ OpenCLDebugInfo100DebugTypeBasic &&
|
|
|
+ (OpenCLDebugInfo100DebugBaseTypeAttributeEncoding(dbg_type->word(7)) ==
|
|
|
+ OpenCLDebugInfo100Signed ||
|
|
|
+ OpenCLDebugInfo100DebugBaseTypeAttributeEncoding(dbg_type->word(7)) ==
|
|
|
+ OpenCLDebugInfo100Unsigned)) {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return false;
|
|
|
+}
|
|
|
+
|
|
|
} // anonymous namespace
|
|
|
|
|
|
spv_result_t ValidateExtension(ValidationState_t& _, const Instruction* inst) {
|
|
|
@@ -2678,17 +2725,53 @@ spv_result_t ValidateExtInst(ValidationState_t& _, const Instruction* inst) {
|
|
|
break;
|
|
|
}
|
|
|
case OpenCLDebugInfo100DebugTypeArray: {
|
|
|
- auto validate_base_type =
|
|
|
- ValidateOperandDebugType(_, "Base Type", inst, 5, ext_inst_name);
|
|
|
+ auto validate_base_type = ValidateOperandDebugType(
|
|
|
+ _, "Base Type", inst, 5, ext_inst_name, false);
|
|
|
if (validate_base_type != SPV_SUCCESS) return validate_base_type;
|
|
|
for (uint32_t i = 6; i < num_words; ++i) {
|
|
|
- CHECK_OPERAND("Component Count", SpvOpConstant, i);
|
|
|
+ bool invalid = false;
|
|
|
auto* component_count = _.FindDef(inst->word(i));
|
|
|
- if (!_.IsIntScalarType(component_count->type_id()) ||
|
|
|
- !component_count->word(3)) {
|
|
|
+ if (IsConstIntScalarTypeWith32Or64Bits(_, component_count)) {
|
|
|
+ // TODO: We need a spec discussion for the bindless array.
|
|
|
+ if (!component_count->word(3)) {
|
|
|
+ invalid = true;
|
|
|
+ }
|
|
|
+ } else if (component_count->words().size() > 6 &&
|
|
|
+ (OpenCLDebugInfo100Instructions(component_count->word(
|
|
|
+ 4)) == OpenCLDebugInfo100DebugLocalVariable ||
|
|
|
+ OpenCLDebugInfo100Instructions(component_count->word(
|
|
|
+ 4)) == OpenCLDebugInfo100DebugGlobalVariable)) {
|
|
|
+ auto* component_count_type = _.FindDef(component_count->word(6));
|
|
|
+ if (component_count_type->words().size() > 7) {
|
|
|
+ if (OpenCLDebugInfo100Instructions(component_count_type->word(
|
|
|
+ 4)) != OpenCLDebugInfo100DebugTypeBasic ||
|
|
|
+ OpenCLDebugInfo100DebugBaseTypeAttributeEncoding(
|
|
|
+ component_count_type->word(7)) !=
|
|
|
+ OpenCLDebugInfo100Unsigned) {
|
|
|
+ invalid = true;
|
|
|
+ } else {
|
|
|
+ // DebugTypeBasic for DebugLocalVariable/DebugGlobalVariable
|
|
|
+ // must have Unsigned encoding and 32 or 64 as its size in bits.
|
|
|
+ Instruction* size_in_bits =
|
|
|
+ _.FindDef(component_count_type->word(6));
|
|
|
+ if (!_.IsIntScalarType(size_in_bits->type_id()) ||
|
|
|
+ (size_in_bits->word(3) != 32 &&
|
|
|
+ size_in_bits->word(3) != 64)) {
|
|
|
+ invalid = true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ invalid = true;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ invalid = true;
|
|
|
+ }
|
|
|
+ if (invalid) {
|
|
|
return _.diag(SPV_ERROR_INVALID_DATA, inst)
|
|
|
- << ext_inst_name() << ": Component Count must be positive "
|
|
|
- << "integer";
|
|
|
+ << ext_inst_name() << ": Component Count must be "
|
|
|
+ << "OpConstant with a 32- or 64-bits integer scalar type or "
|
|
|
+ << "DebugGlobalVariable or DebugLocalVariable with a 32- or "
|
|
|
+ << "64-bits unsigned integer scalar type";
|
|
|
}
|
|
|
}
|
|
|
break;
|
|
|
@@ -2706,14 +2789,16 @@ spv_result_t ValidateExtInst(ValidationState_t& _, const Instruction* inst) {
|
|
|
}
|
|
|
case OpenCLDebugInfo100DebugTypeFunction: {
|
|
|
auto* return_type = _.FindDef(inst->word(6));
|
|
|
+ // TODO: We need a spec discussion that we have to allow return and
|
|
|
+ // parameter types of a DebugTypeFunction to have template parameter.
|
|
|
if (return_type->opcode() != SpvOpTypeVoid) {
|
|
|
auto validate_return = ValidateOperandDebugType(
|
|
|
- _, "Return Type", inst, 6, ext_inst_name);
|
|
|
+ _, "Return Type", inst, 6, ext_inst_name, true);
|
|
|
if (validate_return != SPV_SUCCESS) return validate_return;
|
|
|
}
|
|
|
for (uint32_t word_index = 7; word_index < num_words; ++word_index) {
|
|
|
auto validate_param = ValidateOperandDebugType(
|
|
|
- _, "Parameter Types", inst, word_index, ext_inst_name);
|
|
|
+ _, "Parameter Types", inst, word_index, ext_inst_name, true);
|
|
|
if (validate_param != SPV_SUCCESS) return validate_param;
|
|
|
}
|
|
|
break;
|
|
|
@@ -2727,7 +2812,7 @@ spv_result_t ValidateExtInst(ValidationState_t& _, const Instruction* inst) {
|
|
|
},
|
|
|
inst, 6)) {
|
|
|
auto validate_underlying_type = ValidateOperandDebugType(
|
|
|
- _, "Underlying Types", inst, 6, ext_inst_name);
|
|
|
+ _, "Underlying Types", inst, 6, ext_inst_name, false);
|
|
|
if (validate_underlying_type != SPV_SUCCESS)
|
|
|
return validate_underlying_type;
|
|
|
}
|
|
|
@@ -2784,8 +2869,10 @@ spv_result_t ValidateExtInst(ValidationState_t& _, const Instruction* inst) {
|
|
|
}
|
|
|
case OpenCLDebugInfo100DebugTypeMember: {
|
|
|
CHECK_OPERAND("Name", SpvOpString, 5);
|
|
|
+ // TODO: We need a spec discussion that we have to allow member types
|
|
|
+ // to have template parameter.
|
|
|
auto validate_type =
|
|
|
- ValidateOperandDebugType(_, "Type", inst, 6, ext_inst_name);
|
|
|
+ ValidateOperandDebugType(_, "Type", inst, 6, ext_inst_name, true);
|
|
|
if (validate_type != SPV_SUCCESS) return validate_type;
|
|
|
CHECK_DEBUG_OPERAND("Source", OpenCLDebugInfo100DebugSource, 7);
|
|
|
CHECK_DEBUG_OPERAND("Parent", OpenCLDebugInfo100DebugTypeComposite, 10);
|
|
|
@@ -2823,18 +2910,13 @@ spv_result_t ValidateExtInst(ValidationState_t& _, const Instruction* inst) {
|
|
|
case OpenCLDebugInfo100DebugFunction: {
|
|
|
CHECK_OPERAND("Name", SpvOpString, 5);
|
|
|
auto validate_type =
|
|
|
- ValidateOperandDebugType(_, "Type", inst, 6, ext_inst_name);
|
|
|
+ ValidateOperandDebugType(_, "Type", inst, 6, ext_inst_name, false);
|
|
|
if (validate_type != SPV_SUCCESS) return validate_type;
|
|
|
CHECK_DEBUG_OPERAND("Source", OpenCLDebugInfo100DebugSource, 7);
|
|
|
auto validate_parent =
|
|
|
ValidateOperandLexicalScope(_, "Parent", inst, 10, ext_inst_name);
|
|
|
if (validate_parent != SPV_SUCCESS) return validate_parent;
|
|
|
CHECK_OPERAND("Linkage Name", SpvOpString, 11);
|
|
|
- // TODO: The current OpenCL.100.DebugInfo spec says "Function
|
|
|
- // is an OpFunction which is described by this instruction.".
|
|
|
- // However, the function definition can be opted-out e.g.,
|
|
|
- // inlining. We assume that Function operand can be a
|
|
|
- // DebugInfoNone, but we must discuss it and update the spec.
|
|
|
if (!DoesDebugInfoOperandMatchExpectation(
|
|
|
_,
|
|
|
[](OpenCLDebugInfo100Instructions dbg_inst) {
|
|
|
@@ -2852,7 +2934,7 @@ spv_result_t ValidateExtInst(ValidationState_t& _, const Instruction* inst) {
|
|
|
case OpenCLDebugInfo100DebugFunctionDeclaration: {
|
|
|
CHECK_OPERAND("Name", SpvOpString, 5);
|
|
|
auto validate_type =
|
|
|
- ValidateOperandDebugType(_, "Type", inst, 6, ext_inst_name);
|
|
|
+ ValidateOperandDebugType(_, "Type", inst, 6, ext_inst_name, false);
|
|
|
if (validate_type != SPV_SUCCESS) return validate_type;
|
|
|
CHECK_DEBUG_OPERAND("Source", OpenCLDebugInfo100DebugSource, 7);
|
|
|
auto validate_parent =
|
|
|
@@ -2870,9 +2952,6 @@ spv_result_t ValidateExtInst(ValidationState_t& _, const Instruction* inst) {
|
|
|
break;
|
|
|
}
|
|
|
case OpenCLDebugInfo100DebugScope: {
|
|
|
- // TODO(https://gitlab.khronos.org/spirv/SPIR-V/issues/533): We are
|
|
|
- // still in spec discussion about what must be "Scope" operand of
|
|
|
- // DebugScope. Update this code if the conclusion is different.
|
|
|
auto validate_scope =
|
|
|
ValidateOperandLexicalScope(_, "Scope", inst, 5, ext_inst_name);
|
|
|
if (validate_scope != SPV_SUCCESS) return validate_scope;
|
|
|
@@ -2884,8 +2963,10 @@ spv_result_t ValidateExtInst(ValidationState_t& _, const Instruction* inst) {
|
|
|
}
|
|
|
case OpenCLDebugInfo100DebugLocalVariable: {
|
|
|
CHECK_OPERAND("Name", SpvOpString, 5);
|
|
|
+ // TODO: We need a spec discussion that we have to allow local variable
|
|
|
+ // types to have template parameter.
|
|
|
auto validate_type =
|
|
|
- ValidateOperandDebugType(_, "Type", inst, 6, ext_inst_name);
|
|
|
+ ValidateOperandDebugType(_, "Type", inst, 6, ext_inst_name, true);
|
|
|
if (validate_type != SPV_SUCCESS) return validate_type;
|
|
|
CHECK_DEBUG_OPERAND("Source", OpenCLDebugInfo100DebugSource, 7);
|
|
|
auto validate_parent =
|
|
|
@@ -2896,11 +2977,6 @@ spv_result_t ValidateExtInst(ValidationState_t& _, const Instruction* inst) {
|
|
|
case OpenCLDebugInfo100DebugDeclare: {
|
|
|
CHECK_DEBUG_OPERAND("Local Variable",
|
|
|
OpenCLDebugInfo100DebugLocalVariable, 5);
|
|
|
-
|
|
|
- // TODO: We must discuss DebugDeclare.Variable of
|
|
|
- // OpenCL.100.DebugInfo. Currently, it says "Variable must be an id of
|
|
|
- // OpVariable instruction which defines the local variable.", but we
|
|
|
- // want to allow OpFunctionParameter as well.
|
|
|
auto* operand = _.FindDef(inst->word(6));
|
|
|
if (operand->opcode() != SpvOpVariable &&
|
|
|
operand->opcode() != SpvOpFunctionParameter) {
|
|
|
@@ -2920,18 +2996,120 @@ spv_result_t ValidateExtInst(ValidationState_t& _, const Instruction* inst) {
|
|
|
}
|
|
|
break;
|
|
|
}
|
|
|
+ case OpenCLDebugInfo100DebugTypeTemplate: {
|
|
|
+ if (!DoesDebugInfoOperandMatchExpectation(
|
|
|
+ _,
|
|
|
+ [](OpenCLDebugInfo100Instructions dbg_inst) {
|
|
|
+ return dbg_inst == OpenCLDebugInfo100DebugTypeComposite ||
|
|
|
+ dbg_inst == OpenCLDebugInfo100DebugFunction;
|
|
|
+ },
|
|
|
+ inst, 5)) {
|
|
|
+ return _.diag(SPV_ERROR_INVALID_DATA, inst)
|
|
|
+ << ext_inst_name() << ": "
|
|
|
+ << "expected operand Target must be DebugTypeComposite "
|
|
|
+ << "or DebugFunction";
|
|
|
+ }
|
|
|
+ for (uint32_t word_index = 6; word_index < num_words; ++word_index) {
|
|
|
+ if (!DoesDebugInfoOperandMatchExpectation(
|
|
|
+ _,
|
|
|
+ [](OpenCLDebugInfo100Instructions dbg_inst) {
|
|
|
+ return dbg_inst ==
|
|
|
+ OpenCLDebugInfo100DebugTypeTemplateParameter ||
|
|
|
+ dbg_inst ==
|
|
|
+ OpenCLDebugInfo100DebugTypeTemplateTemplateParameter;
|
|
|
+ },
|
|
|
+ inst, word_index)) {
|
|
|
+ return _.diag(SPV_ERROR_INVALID_DATA, inst)
|
|
|
+ << ext_inst_name() << ": "
|
|
|
+ << "expected operand Parameters must be "
|
|
|
+ << "DebugTypeTemplateParameter or "
|
|
|
+ << "DebugTypeTemplateTemplateParameter";
|
|
|
+ }
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ case OpenCLDebugInfo100DebugTypeTemplateParameter: {
|
|
|
+ CHECK_OPERAND("Name", SpvOpString, 5);
|
|
|
+ auto validate_actual_type = ValidateOperandDebugType(
|
|
|
+ _, "Actual Type", inst, 6, ext_inst_name, false);
|
|
|
+ if (validate_actual_type != SPV_SUCCESS) return validate_actual_type;
|
|
|
+ if (!DoesDebugInfoOperandMatchExpectation(
|
|
|
+ _,
|
|
|
+ [](OpenCLDebugInfo100Instructions dbg_inst) {
|
|
|
+ return dbg_inst == OpenCLDebugInfo100DebugInfoNone;
|
|
|
+ },
|
|
|
+ inst, 7)) {
|
|
|
+ CHECK_OPERAND("Value", SpvOpConstant, 7);
|
|
|
+ }
|
|
|
+ CHECK_DEBUG_OPERAND("Source", OpenCLDebugInfo100DebugSource, 8);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ case OpenCLDebugInfo100DebugGlobalVariable: {
|
|
|
+ CHECK_OPERAND("Name", SpvOpString, 5);
|
|
|
+ auto validate_type =
|
|
|
+ ValidateOperandDebugType(_, "Type", inst, 6, ext_inst_name, false);
|
|
|
+ if (validate_type != SPV_SUCCESS) return validate_type;
|
|
|
+ CHECK_DEBUG_OPERAND("Source", OpenCLDebugInfo100DebugSource, 7);
|
|
|
+ auto validate_scope =
|
|
|
+ ValidateOperandLexicalScope(_, "Scope", inst, 10, ext_inst_name);
|
|
|
+ if (validate_scope != SPV_SUCCESS) return validate_scope;
|
|
|
+ CHECK_OPERAND("Linkage Name", SpvOpString, 11);
|
|
|
+ if (!DoesDebugInfoOperandMatchExpectation(
|
|
|
+ _,
|
|
|
+ [](OpenCLDebugInfo100Instructions dbg_inst) {
|
|
|
+ return dbg_inst == OpenCLDebugInfo100DebugInfoNone;
|
|
|
+ },
|
|
|
+ inst, 12)) {
|
|
|
+ auto* operand = _.FindDef(inst->word(12));
|
|
|
+ if (operand->opcode() != SpvOpVariable &&
|
|
|
+ operand->opcode() != SpvOpConstant) {
|
|
|
+ return _.diag(SPV_ERROR_INVALID_DATA, inst)
|
|
|
+ << ext_inst_name() << ": "
|
|
|
+ << "expected operand Variable must be a result id of "
|
|
|
+ "OpVariable or OpConstant or DebugInfoNone";
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (num_words == 15) {
|
|
|
+ CHECK_DEBUG_OPERAND("Static Member Declaration",
|
|
|
+ OpenCLDebugInfo100DebugTypeMember, 14);
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ case OpenCLDebugInfo100DebugInlinedAt: {
|
|
|
+ auto validate_scope =
|
|
|
+ ValidateOperandLexicalScope(_, "Scope", inst, 6, ext_inst_name);
|
|
|
+ if (validate_scope != SPV_SUCCESS) return validate_scope;
|
|
|
+ if (num_words == 8) {
|
|
|
+ CHECK_DEBUG_OPERAND("Inlined", OpenCLDebugInfo100DebugInlinedAt, 7);
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ case OpenCLDebugInfo100DebugValue: {
|
|
|
+ CHECK_DEBUG_OPERAND("Local Variable",
|
|
|
+ OpenCLDebugInfo100DebugLocalVariable, 5);
|
|
|
+ CHECK_DEBUG_OPERAND("Expression", OpenCLDebugInfo100DebugExpression, 7);
|
|
|
+
|
|
|
+ for (uint32_t word_index = 8; word_index < num_words; ++word_index) {
|
|
|
+ // TODO: The following code simply checks if it is a const int scalar
|
|
|
+ // or a DebugLocalVariable or DebugGlobalVariable, but we have to
|
|
|
+ // check it using the same validation for Indexes of OpAccessChain.
|
|
|
+ if (!IsConstWithIntScalarType(_, inst, word_index) &&
|
|
|
+ !IsDebugVariableWithIntScalarType(_, inst, word_index)) {
|
|
|
+ return _.diag(SPV_ERROR_INVALID_DATA, inst)
|
|
|
+ << ext_inst_name() << ": expected operand Indexes is "
|
|
|
+ << "OpConstant, DebugGlobalVariable, or "
|
|
|
+ << "type is OpConstant with an integer scalar type";
|
|
|
+ }
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ }
|
|
|
|
|
|
// TODO: Add validation rules for remaining cases as well.
|
|
|
case OpenCLDebugInfo100DebugTypePtrToMember:
|
|
|
- case OpenCLDebugInfo100DebugTypeTemplate:
|
|
|
- case OpenCLDebugInfo100DebugTypeTemplateParameter:
|
|
|
case OpenCLDebugInfo100DebugTypeTemplateTemplateParameter:
|
|
|
case OpenCLDebugInfo100DebugTypeTemplateParameterPack:
|
|
|
- case OpenCLDebugInfo100DebugGlobalVariable:
|
|
|
case OpenCLDebugInfo100DebugLexicalBlockDiscriminator:
|
|
|
- case OpenCLDebugInfo100DebugInlinedAt:
|
|
|
case OpenCLDebugInfo100DebugInlinedVariable:
|
|
|
- case OpenCLDebugInfo100DebugValue:
|
|
|
case OpenCLDebugInfo100DebugMacroDef:
|
|
|
case OpenCLDebugInfo100DebugMacroUndef:
|
|
|
case OpenCLDebugInfo100DebugImportedEntity:
|