| 2233 | } |
| 2234 | |
| 2235 | spv_result_t ValidatePtrAccessChain(ValidationState_t& _, |
| 2236 | const Instruction* inst) { |
| 2237 | // Need to call first, will make sure Base is a valid ID |
| 2238 | if (auto error = ValidateAccessChain(_, inst)) return error; |
| 2239 | |
| 2240 | const bool untyped_pointer = spvOpcodeGeneratesUntypedPointer(inst->opcode()); |
| 2241 | |
| 2242 | const auto base_idx = untyped_pointer ? 3 : 2; |
| 2243 | const auto base = _.FindDef(inst->GetOperandAs<uint32_t>(base_idx)); |
| 2244 | const auto base_type = _.FindDef(base->type_id()); |
| 2245 | const auto base_type_storage_class = |
| 2246 | base_type->GetOperandAs<spv::StorageClass>(1); |
| 2247 | |
| 2248 | const auto element_idx = untyped_pointer ? 4 : 3; |
| 2249 | const auto element = _.FindDef(inst->GetOperandAs<uint32_t>(element_idx)); |
| 2250 | const auto element_type = _.FindDef(element->type_id()); |
| 2251 | if (!element_type || element_type->opcode() != spv::Op::OpTypeInt) { |
| 2252 | return _.diag(SPV_ERROR_INVALID_DATA, inst) << "Element must be an integer"; |
| 2253 | } |
| 2254 | uint64_t element_val = 0; |
| 2255 | if (_.EvalConstantValUint64(element->id(), &element_val)) { |
| 2256 | if (element_val != 0) { |
| 2257 | const auto interp_type = |
| 2258 | untyped_pointer ? _.FindDef(inst->GetOperandAs<uint32_t>(2)) |
| 2259 | : _.FindDef(base_type->GetOperandAs<uint32_t>(2)); |
| 2260 | if (interp_type->opcode() == spv::Op::OpTypeStruct && |
| 2261 | (_.HasDecoration(interp_type->id(), spv::Decoration::Block) || |
| 2262 | _.HasDecoration(interp_type->id(), spv::Decoration::BufferBlock))) { |
| 2263 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
| 2264 | << "Element must be 0 if the interpretation type is a Block- or " |
| 2265 | "BufferBlock-decorated structure"; |
| 2266 | } |
| 2267 | } |
| 2268 | } |
| 2269 | |
| 2270 | if (_.HasCapability(spv::Capability::Shader) && |
| 2271 | (base_type_storage_class == spv::StorageClass::Uniform || |
| 2272 | base_type_storage_class == spv::StorageClass::StorageBuffer || |
| 2273 | base_type_storage_class == spv::StorageClass::PhysicalStorageBuffer || |
| 2274 | base_type_storage_class == spv::StorageClass::PushConstant || |
| 2275 | (_.HasCapability(spv::Capability::WorkgroupMemoryExplicitLayoutKHR) && |
| 2276 | base_type_storage_class == spv::StorageClass::Workgroup)) && |
| 2277 | (!_.HasDecoration(base_type->id(), spv::Decoration::ArrayStride) && |
| 2278 | !_.HasDecoration(base_type->id(), spv::Decoration::ArrayStrideIdEXT))) { |
| 2279 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
| 2280 | << "OpPtrAccessChain must have a Base whose type is decorated " |
| 2281 | "with ArrayStride or ArrayStrideIdEXT"; |
| 2282 | } |
| 2283 | |
| 2284 | if (spvIsVulkanEnv(_.context()->target_env)) { |
| 2285 | const auto untyped_cap = |
| 2286 | untyped_pointer && _.HasCapability(spv::Capability::UntypedPointersKHR); |
| 2287 | if (base_type_storage_class == spv::StorageClass::Workgroup) { |
| 2288 | if (!_.HasCapability(spv::Capability::VariablePointers) && !untyped_cap) { |
| 2289 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
| 2290 | << _.VkErrorID(7651) |
| 2291 | << "OpPtrAccessChain Base operand pointing to Workgroup " |
| 2292 | "storage class must use VariablePointers capability"; |
no test coverage detected