| 430 | } |
| 431 | |
| 432 | spv_result_t ValidateVariableInitializer(ValidationState_t& _, |
| 433 | const Instruction* inst, |
| 434 | spv::StorageClass storage_class, |
| 435 | uint32_t value_id) { |
| 436 | const bool untyped_pointer = inst->opcode() == spv::Op::OpUntypedVariableKHR; |
| 437 | const uint32_t initializer_index = untyped_pointer ? 4u : 3u; |
| 438 | if (initializer_index < inst->operands().size()) { |
| 439 | const uint32_t initializer_id = |
| 440 | inst->GetOperandAs<uint32_t>(initializer_index); |
| 441 | const Instruction* initializer = _.FindDef(initializer_id); |
| 442 | const uint32_t storage_class_index = 2u; |
| 443 | const bool is_module_scope_var = |
| 444 | initializer && |
| 445 | (initializer->opcode() == spv::Op::OpVariable || |
| 446 | initializer->opcode() == spv::Op::OpUntypedVariableKHR) && |
| 447 | (initializer->GetOperandAs<spv::StorageClass>(storage_class_index) != |
| 448 | spv::StorageClass::Function); |
| 449 | const bool is_constant = |
| 450 | initializer && spvOpcodeIsConstant(initializer->opcode()); |
| 451 | if (!initializer || !(is_constant || is_module_scope_var)) { |
| 452 | return _.diag(SPV_ERROR_INVALID_ID, inst) |
| 453 | << "Variable Initializer <id> " << _.getIdName(initializer_id) |
| 454 | << " is not a constant or module-scope variable."; |
| 455 | } |
| 456 | if (initializer->type_id() != value_id) { |
| 457 | return _.diag(SPV_ERROR_INVALID_ID, inst) |
| 458 | << "Initializer type must match the data type"; |
| 459 | } |
| 460 | } |
| 461 | |
| 462 | // Vulkan Appendix A: Check that if contains initializer, then |
| 463 | // storage class is Output, Private, or Function. |
| 464 | if (inst->operands().size() > initializer_index && |
| 465 | storage_class != spv::StorageClass::Output && |
| 466 | storage_class != spv::StorageClass::Private && |
| 467 | storage_class != spv::StorageClass::Function) { |
| 468 | if (spvIsVulkanEnv(_.context()->target_env)) { |
| 469 | if (storage_class == spv::StorageClass::Workgroup) { |
| 470 | auto init_id = inst->GetOperandAs<uint32_t>(initializer_index); |
| 471 | auto init = _.FindDef(init_id); |
| 472 | if (init->opcode() != spv::Op::OpConstantNull) { |
| 473 | return _.diag(SPV_ERROR_INVALID_ID, inst) |
| 474 | << _.VkErrorID(4734) << "OpVariable, <id> " |
| 475 | << _.getIdName(inst->id()) |
| 476 | << ", initializers are limited to OpConstantNull in " |
| 477 | "Workgroup " |
| 478 | "storage class"; |
| 479 | } |
| 480 | } else if (storage_class != spv::StorageClass::Output && |
| 481 | storage_class != spv::StorageClass::Private && |
| 482 | storage_class != spv::StorageClass::Function) { |
| 483 | return _.diag(SPV_ERROR_INVALID_ID, inst) |
| 484 | << _.VkErrorID(4651) << "OpVariable, <id> " |
| 485 | << _.getIdName(inst->id()) |
| 486 | << ", has a disallowed initializer & storage class " |
| 487 | << "combination.\n" |
| 488 | << "From " << spvLogStringForEnv(_.context()->target_env) |
| 489 | << " spec:\n" |
no test coverage detected