|
33 | 33 | #include "source/val/validation_state.h" |
34 | 34 | #include "spirv-tools/libspirv.h" |
35 | 35 | #include "spirv/unified1/NonSemanticClspvReflection.h" |
| 36 | +#include "spirv/unified1/NonSemanticGraphDebugInfo.h" |
36 | 37 | #include "spirv/unified1/NonSemanticShaderDebugInfo.h" |
37 | 38 |
|
38 | 39 | namespace spvtools { |
@@ -83,6 +84,55 @@ bool IsUint32Constant(ValidationState_t& _, uint32_t id) { |
83 | 84 | return IsIntScalar(_, inst->type_id(), true, true); |
84 | 85 | } |
85 | 86 |
|
| 87 | +bool IsGraphDebugInfoDebugGraph(const Instruction* inst) { |
| 88 | + return spvIsExtendedInstruction(inst->opcode()) && |
| 89 | + inst->ext_inst_type() == |
| 90 | + SPV_EXT_INST_TYPE_NONSEMANTIC_GRAPH_DEBUGINFO && |
| 91 | + inst->word(4) == NonSemanticGraphDebugInfoDebugGraph; |
| 92 | +} |
| 93 | + |
| 94 | +bool IsTopLevelCompositeOfTensors(ValidationState_t& _, uint32_t type_id) { |
| 95 | + const auto* type = _.FindDef(type_id); |
| 96 | + if (!type) return false; |
| 97 | + |
| 98 | + if (type->opcode() == spv::Op::OpTypeArray || |
| 99 | + type->opcode() == spv::Op::OpTypeRuntimeArray) { |
| 100 | + const auto* element_type = _.FindDef(type->word(2)); |
| 101 | + return element_type && element_type->opcode() == spv::Op::OpTypeTensorARM; |
| 102 | + } |
| 103 | + |
| 104 | + if (type->opcode() == spv::Op::OpTypeStruct) { |
| 105 | + for (uint32_t word_index = 2; word_index < type->words().size(); |
| 106 | + ++word_index) { |
| 107 | + const auto* member_type = _.FindDef(type->word(word_index)); |
| 108 | + if (!member_type || member_type->opcode() != spv::Op::OpTypeTensorARM) { |
| 109 | + return false; |
| 110 | + } |
| 111 | + } |
| 112 | + return true; |
| 113 | + } |
| 114 | + |
| 115 | + return false; |
| 116 | +} |
| 117 | + |
| 118 | +bool IsInstructionInGraph(ValidationState_t& _, uint32_t inst_id, |
| 119 | + uint32_t graph_id) { |
| 120 | + bool in_graph = false; |
| 121 | + for (const auto& module_inst : _.ordered_instructions()) { |
| 122 | + if (module_inst.opcode() == spv::Op::OpGraphARM) { |
| 123 | + in_graph = module_inst.id() == graph_id; |
| 124 | + } |
| 125 | + |
| 126 | + if (in_graph && module_inst.id() == inst_id) return true; |
| 127 | + |
| 128 | + if (in_graph && module_inst.opcode() == spv::Op::OpGraphEndARM) { |
| 129 | + in_graph = false; |
| 130 | + } |
| 131 | + } |
| 132 | + |
| 133 | + return false; |
| 134 | +} |
| 135 | + |
86 | 136 | uint32_t GetUint32Constant(ValidationState_t& _, uint32_t id) { |
87 | 137 | auto inst = _.FindDef(id); |
88 | 138 | return inst->word(3); |
@@ -1354,6 +1404,33 @@ spv_result_t ValidateExtInstImport(ValidationState_t& _, |
1354 | 1404 | _.RegisterShaderDebugInfo(inst->id()); |
1355 | 1405 | } |
1356 | 1406 |
|
| 1407 | + const std::string nsgdi_prefix = "NonSemantic.Graph.DebugInfo."; |
| 1408 | + if (name.find(nsgdi_prefix) == 0) { |
| 1409 | + auto version_string = name.substr(nsgdi_prefix.size()); |
| 1410 | + if (version_string.empty()) { |
| 1411 | + return _.diag(SPV_ERROR_INVALID_DATA, inst) |
| 1412 | + << "NonSemantic.Graph.DebugInfo import does not encode the " |
| 1413 | + "version correctly"; |
| 1414 | + } |
| 1415 | + char* end_ptr; |
| 1416 | + uint32_t ver = static_cast<uint32_t>( |
| 1417 | + std::strtoul(version_string.c_str(), &end_ptr, 10)); |
| 1418 | + if (end_ptr && *end_ptr != '\0') { |
| 1419 | + return _.diag(SPV_ERROR_INVALID_DATA, inst) |
| 1420 | + << "NonSemantic.Graph.DebugInfo import does not encode the " |
| 1421 | + "version correctly"; |
| 1422 | + } |
| 1423 | + if (ver == 0 || ver > NonSemanticGraphDebugInfoRevision) { |
| 1424 | + return _.diag(SPV_ERROR_INVALID_DATA, inst) |
| 1425 | + << "NonSemantic.Graph.DebugInfo import version " << ver |
| 1426 | + << " is not supported"; |
| 1427 | + } |
| 1428 | + if (!_.HasExtension(kSPV_ARM_graph)) { |
| 1429 | + return _.diag(SPV_ERROR_INVALID_DATA, inst) |
| 1430 | + << "NonSemantic.Graph.DebugInfo requires SPV_ARM_graph"; |
| 1431 | + } |
| 1432 | + } |
| 1433 | + |
1357 | 1434 | return SPV_SUCCESS; |
1358 | 1435 | } |
1359 | 1436 |
|
@@ -4196,6 +4273,96 @@ spv_result_t ValidateExtInstDebugInfo(ValidationState_t& _, |
4196 | 4273 | return SPV_SUCCESS; |
4197 | 4274 | } |
4198 | 4275 |
|
| 4276 | +spv_result_t ValidateExtInstGraphDebugInfo(ValidationState_t& _, |
| 4277 | + const Instruction* inst) { |
| 4278 | + if (!_.IsVoidType(inst->type_id())) { |
| 4279 | + return _.diag(SPV_ERROR_INVALID_DATA, inst) |
| 4280 | + << GetExtInstName(_, inst) << ": " |
| 4281 | + << "expected result type must be a result id of OpTypeVoid"; |
| 4282 | + } |
| 4283 | + |
| 4284 | + const auto ext_inst_key = |
| 4285 | + NonSemanticGraphDebugInfoInstructions(inst->word(4)); |
| 4286 | + switch (ext_inst_key) { |
| 4287 | + case NonSemanticGraphDebugInfoDebugGraph: { |
| 4288 | + CHECK_OPERAND("Graph", spv::Op::OpGraphARM, 5); |
| 4289 | + CHECK_OPERAND("Name", spv::Op::OpString, 6); |
| 4290 | + break; |
| 4291 | + } |
| 4292 | + |
| 4293 | + case NonSemanticGraphDebugInfoDebugOperation: { |
| 4294 | + const auto* debug_graph = _.FindDef(inst->word(5)); |
| 4295 | + if (!debug_graph || !IsGraphDebugInfoDebugGraph(debug_graph)) { |
| 4296 | + return _.diag(SPV_ERROR_INVALID_DATA, inst) |
| 4297 | + << GetExtInstName(_, inst) << ": expected operand DebugGraph " |
| 4298 | + << "must be a result id of NonSemantic.Graph.DebugInfo " |
| 4299 | + << "DebugGraph"; |
| 4300 | + } |
| 4301 | + CHECK_OPERAND("Name", spv::Op::OpString, 6); |
| 4302 | + if (inst->words().size() < 8) { |
| 4303 | + return _.diag(SPV_ERROR_INVALID_DATA, inst) |
| 4304 | + << GetExtInstName(_, inst) << ": expected operand " |
| 4305 | + << "Instructions must contain at least one instruction"; |
| 4306 | + } |
| 4307 | + |
| 4308 | + const uint32_t graph_id = debug_graph->word(5); |
| 4309 | + for (uint32_t word_index = 7; word_index < inst->words().size(); |
| 4310 | + ++word_index) { |
| 4311 | + const uint32_t instruction_id = inst->word(word_index); |
| 4312 | + if (!IsInstructionInGraph(_, instruction_id, graph_id)) { |
| 4313 | + return _.diag(SPV_ERROR_INVALID_DATA, inst) |
| 4314 | + << GetExtInstName(_, inst) << ": expected operand " |
| 4315 | + << "Instructions must be result ids of instructions within " |
| 4316 | + << "the graph described by DebugGraph"; |
| 4317 | + } |
| 4318 | + } |
| 4319 | + break; |
| 4320 | + } |
| 4321 | + |
| 4322 | + case NonSemanticGraphDebugInfoDebugTensor: { |
| 4323 | + const auto* tensor = _.FindDef(inst->word(5)); |
| 4324 | + const uint32_t tensor_type_id = tensor ? tensor->type_id() : 0; |
| 4325 | + const auto* tensor_type = _.FindDef(tensor_type_id); |
| 4326 | + const bool is_tensor = |
| 4327 | + tensor_type && tensor_type->opcode() == spv::Op::OpTypeTensorARM; |
| 4328 | + const bool is_composite_tensor = |
| 4329 | + IsTopLevelCompositeOfTensors(_, tensor_type_id); |
| 4330 | + if (!is_tensor && !is_composite_tensor) { |
| 4331 | + return _.diag(SPV_ERROR_INVALID_DATA, inst) |
| 4332 | + << GetExtInstName(_, inst) << ": expected operand Tensor " |
| 4333 | + << "must be a value of OpTypeTensorARM or a composite type " |
| 4334 | + << "whose top-level constituents are OpTypeTensorARM"; |
| 4335 | + } |
| 4336 | + CHECK_OPERAND("Name", spv::Op::OpString, 6); |
| 4337 | + |
| 4338 | + const bool has_index = inst->words().size() > 7; |
| 4339 | + if (is_composite_tensor && !has_index) { |
| 4340 | + return _.diag(SPV_ERROR_INVALID_DATA, inst) |
| 4341 | + << GetExtInstName(_, inst) << ": expected operand Index " |
| 4342 | + << "must be present when Tensor has composite type"; |
| 4343 | + } |
| 4344 | + if (has_index) { |
| 4345 | + if (!is_composite_tensor) { |
| 4346 | + return _.diag(SPV_ERROR_INVALID_DATA, inst) |
| 4347 | + << GetExtInstName(_, inst) << ": expected operand Tensor " |
| 4348 | + << "must have composite type when Index is present"; |
| 4349 | + } |
| 4350 | + if (!IsUint32Constant(_, inst->word(7))) { |
| 4351 | + return _.diag(SPV_ERROR_INVALID_DATA, inst) |
| 4352 | + << GetExtInstName(_, inst) << ": expected operand Index " |
| 4353 | + << "must be a result id of 32-bit unsigned OpConstant"; |
| 4354 | + } |
| 4355 | + } |
| 4356 | + break; |
| 4357 | + } |
| 4358 | + |
| 4359 | + default: |
| 4360 | + break; |
| 4361 | + } |
| 4362 | + |
| 4363 | + return SPV_SUCCESS; |
| 4364 | +} |
| 4365 | + |
4199 | 4366 | spv_result_t ValidateExtInstNonsemanticClspvReflection( |
4200 | 4367 | ValidationState_t& _, const Instruction* inst) { |
4201 | 4368 | auto import_inst = _.FindDef(inst->GetOperandAs<uint32_t>(2)); |
@@ -4236,6 +4403,8 @@ spv_result_t ValidateExtInst(ValidationState_t& _, const Instruction* inst) { |
4236 | 4403 | return ValidateExtInstDebugInfo(_, inst); |
4237 | 4404 | } else if (ext_inst_type == SPV_EXT_INST_TYPE_NONSEMANTIC_CLSPVREFLECTION) { |
4238 | 4405 | return ValidateExtInstNonsemanticClspvReflection(_, inst); |
| 4406 | + } else if (ext_inst_type == SPV_EXT_INST_TYPE_NONSEMANTIC_GRAPH_DEBUGINFO) { |
| 4407 | + return ValidateExtInstGraphDebugInfo(_, inst); |
4239 | 4408 | } |
4240 | 4409 |
|
4241 | 4410 | return SPV_SUCCESS; |
|
0 commit comments