1fd4e5da5Sopenharmony_ci// Copyright (c) 2018 Google LLC. 2fd4e5da5Sopenharmony_ci// 3fd4e5da5Sopenharmony_ci// Licensed under the Apache License, Version 2.0 (the "License"); 4fd4e5da5Sopenharmony_ci// you may not use this file except in compliance with the License. 5fd4e5da5Sopenharmony_ci// You may obtain a copy of the License at 6fd4e5da5Sopenharmony_ci// 7fd4e5da5Sopenharmony_ci// http://www.apache.org/licenses/LICENSE-2.0 8fd4e5da5Sopenharmony_ci// 9fd4e5da5Sopenharmony_ci// Unless required by applicable law or agreed to in writing, software 10fd4e5da5Sopenharmony_ci// distributed under the License is distributed on an "AS IS" BASIS, 11fd4e5da5Sopenharmony_ci// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12fd4e5da5Sopenharmony_ci// See the License for the specific language governing permissions and 13fd4e5da5Sopenharmony_ci// limitations under the License. 14fd4e5da5Sopenharmony_ci 15fd4e5da5Sopenharmony_ci#include <algorithm> 16fd4e5da5Sopenharmony_ci 17fd4e5da5Sopenharmony_ci#include "source/enum_string_mapping.h" 18fd4e5da5Sopenharmony_ci#include "source/opcode.h" 19fd4e5da5Sopenharmony_ci#include "source/val/instruction.h" 20fd4e5da5Sopenharmony_ci#include "source/val/validate.h" 21fd4e5da5Sopenharmony_ci#include "source/val/validation_state.h" 22fd4e5da5Sopenharmony_ci 23fd4e5da5Sopenharmony_cinamespace spvtools { 24fd4e5da5Sopenharmony_cinamespace val { 25fd4e5da5Sopenharmony_cinamespace { 26fd4e5da5Sopenharmony_ci 27fd4e5da5Sopenharmony_ci// Returns true if |a| and |b| are instructions defining pointers that point to 28fd4e5da5Sopenharmony_ci// types logically match and the decorations that apply to |b| are a subset 29fd4e5da5Sopenharmony_ci// of the decorations that apply to |a|. 30fd4e5da5Sopenharmony_cibool DoPointeesLogicallyMatch(val::Instruction* a, val::Instruction* b, 31fd4e5da5Sopenharmony_ci ValidationState_t& _) { 32fd4e5da5Sopenharmony_ci if (a->opcode() != spv::Op::OpTypePointer || 33fd4e5da5Sopenharmony_ci b->opcode() != spv::Op::OpTypePointer) { 34fd4e5da5Sopenharmony_ci return false; 35fd4e5da5Sopenharmony_ci } 36fd4e5da5Sopenharmony_ci 37fd4e5da5Sopenharmony_ci const auto& dec_a = _.id_decorations(a->id()); 38fd4e5da5Sopenharmony_ci const auto& dec_b = _.id_decorations(b->id()); 39fd4e5da5Sopenharmony_ci for (const auto& dec : dec_b) { 40fd4e5da5Sopenharmony_ci if (std::find(dec_a.begin(), dec_a.end(), dec) == dec_a.end()) { 41fd4e5da5Sopenharmony_ci return false; 42fd4e5da5Sopenharmony_ci } 43fd4e5da5Sopenharmony_ci } 44fd4e5da5Sopenharmony_ci 45fd4e5da5Sopenharmony_ci uint32_t a_type = a->GetOperandAs<uint32_t>(2); 46fd4e5da5Sopenharmony_ci uint32_t b_type = b->GetOperandAs<uint32_t>(2); 47fd4e5da5Sopenharmony_ci 48fd4e5da5Sopenharmony_ci if (a_type == b_type) { 49fd4e5da5Sopenharmony_ci return true; 50fd4e5da5Sopenharmony_ci } 51fd4e5da5Sopenharmony_ci 52fd4e5da5Sopenharmony_ci Instruction* a_type_inst = _.FindDef(a_type); 53fd4e5da5Sopenharmony_ci Instruction* b_type_inst = _.FindDef(b_type); 54fd4e5da5Sopenharmony_ci 55fd4e5da5Sopenharmony_ci return _.LogicallyMatch(a_type_inst, b_type_inst, true); 56fd4e5da5Sopenharmony_ci} 57fd4e5da5Sopenharmony_ci 58fd4e5da5Sopenharmony_cispv_result_t ValidateFunction(ValidationState_t& _, const Instruction* inst) { 59fd4e5da5Sopenharmony_ci const auto function_type_id = inst->GetOperandAs<uint32_t>(3); 60fd4e5da5Sopenharmony_ci const auto function_type = _.FindDef(function_type_id); 61fd4e5da5Sopenharmony_ci if (!function_type || spv::Op::OpTypeFunction != function_type->opcode()) { 62fd4e5da5Sopenharmony_ci return _.diag(SPV_ERROR_INVALID_ID, inst) 63fd4e5da5Sopenharmony_ci << "OpFunction Function Type <id> " << _.getIdName(function_type_id) 64fd4e5da5Sopenharmony_ci << " is not a function type."; 65fd4e5da5Sopenharmony_ci } 66fd4e5da5Sopenharmony_ci 67fd4e5da5Sopenharmony_ci const auto return_id = function_type->GetOperandAs<uint32_t>(1); 68fd4e5da5Sopenharmony_ci if (return_id != inst->type_id()) { 69fd4e5da5Sopenharmony_ci return _.diag(SPV_ERROR_INVALID_ID, inst) 70fd4e5da5Sopenharmony_ci << "OpFunction Result Type <id> " << _.getIdName(inst->type_id()) 71fd4e5da5Sopenharmony_ci << " does not match the Function Type's return type <id> " 72fd4e5da5Sopenharmony_ci << _.getIdName(return_id) << "."; 73fd4e5da5Sopenharmony_ci } 74fd4e5da5Sopenharmony_ci 75fd4e5da5Sopenharmony_ci const std::vector<spv::Op> acceptable = { 76fd4e5da5Sopenharmony_ci spv::Op::OpGroupDecorate, 77fd4e5da5Sopenharmony_ci spv::Op::OpDecorate, 78fd4e5da5Sopenharmony_ci spv::Op::OpEnqueueKernel, 79fd4e5da5Sopenharmony_ci spv::Op::OpEntryPoint, 80fd4e5da5Sopenharmony_ci spv::Op::OpExecutionMode, 81fd4e5da5Sopenharmony_ci spv::Op::OpExecutionModeId, 82fd4e5da5Sopenharmony_ci spv::Op::OpFunctionCall, 83fd4e5da5Sopenharmony_ci spv::Op::OpGetKernelNDrangeSubGroupCount, 84fd4e5da5Sopenharmony_ci spv::Op::OpGetKernelNDrangeMaxSubGroupSize, 85fd4e5da5Sopenharmony_ci spv::Op::OpGetKernelWorkGroupSize, 86fd4e5da5Sopenharmony_ci spv::Op::OpGetKernelPreferredWorkGroupSizeMultiple, 87fd4e5da5Sopenharmony_ci spv::Op::OpGetKernelLocalSizeForSubgroupCount, 88fd4e5da5Sopenharmony_ci spv::Op::OpGetKernelMaxNumSubgroups, 89fd4e5da5Sopenharmony_ci spv::Op::OpName}; 90fd4e5da5Sopenharmony_ci for (auto& pair : inst->uses()) { 91fd4e5da5Sopenharmony_ci const auto* use = pair.first; 92fd4e5da5Sopenharmony_ci if (std::find(acceptable.begin(), acceptable.end(), use->opcode()) == 93fd4e5da5Sopenharmony_ci acceptable.end() && 94fd4e5da5Sopenharmony_ci !use->IsNonSemantic() && !use->IsDebugInfo()) { 95fd4e5da5Sopenharmony_ci return _.diag(SPV_ERROR_INVALID_ID, use) 96fd4e5da5Sopenharmony_ci << "Invalid use of function result id " << _.getIdName(inst->id()) 97fd4e5da5Sopenharmony_ci << "."; 98fd4e5da5Sopenharmony_ci } 99fd4e5da5Sopenharmony_ci } 100fd4e5da5Sopenharmony_ci 101fd4e5da5Sopenharmony_ci return SPV_SUCCESS; 102fd4e5da5Sopenharmony_ci} 103fd4e5da5Sopenharmony_ci 104fd4e5da5Sopenharmony_cispv_result_t ValidateFunctionParameter(ValidationState_t& _, 105fd4e5da5Sopenharmony_ci const Instruction* inst) { 106fd4e5da5Sopenharmony_ci // NOTE: Find OpFunction & ensure OpFunctionParameter is not out of place. 107fd4e5da5Sopenharmony_ci size_t param_index = 0; 108fd4e5da5Sopenharmony_ci size_t inst_num = inst->LineNum() - 1; 109fd4e5da5Sopenharmony_ci if (inst_num == 0) { 110fd4e5da5Sopenharmony_ci return _.diag(SPV_ERROR_INVALID_LAYOUT, inst) 111fd4e5da5Sopenharmony_ci << "Function parameter cannot be the first instruction."; 112fd4e5da5Sopenharmony_ci } 113fd4e5da5Sopenharmony_ci 114fd4e5da5Sopenharmony_ci auto func_inst = &_.ordered_instructions()[inst_num]; 115fd4e5da5Sopenharmony_ci while (--inst_num) { 116fd4e5da5Sopenharmony_ci func_inst = &_.ordered_instructions()[inst_num]; 117fd4e5da5Sopenharmony_ci if (func_inst->opcode() == spv::Op::OpFunction) { 118fd4e5da5Sopenharmony_ci break; 119fd4e5da5Sopenharmony_ci } else if (func_inst->opcode() == spv::Op::OpFunctionParameter) { 120fd4e5da5Sopenharmony_ci ++param_index; 121fd4e5da5Sopenharmony_ci } 122fd4e5da5Sopenharmony_ci } 123fd4e5da5Sopenharmony_ci 124fd4e5da5Sopenharmony_ci if (func_inst->opcode() != spv::Op::OpFunction) { 125fd4e5da5Sopenharmony_ci return _.diag(SPV_ERROR_INVALID_LAYOUT, inst) 126fd4e5da5Sopenharmony_ci << "Function parameter must be preceded by a function."; 127fd4e5da5Sopenharmony_ci } 128fd4e5da5Sopenharmony_ci 129fd4e5da5Sopenharmony_ci const auto function_type_id = func_inst->GetOperandAs<uint32_t>(3); 130fd4e5da5Sopenharmony_ci const auto function_type = _.FindDef(function_type_id); 131fd4e5da5Sopenharmony_ci if (!function_type) { 132fd4e5da5Sopenharmony_ci return _.diag(SPV_ERROR_INVALID_ID, func_inst) 133fd4e5da5Sopenharmony_ci << "Missing function type definition."; 134fd4e5da5Sopenharmony_ci } 135fd4e5da5Sopenharmony_ci if (param_index >= function_type->words().size() - 3) { 136fd4e5da5Sopenharmony_ci return _.diag(SPV_ERROR_INVALID_ID, inst) 137fd4e5da5Sopenharmony_ci << "Too many OpFunctionParameters for " << func_inst->id() 138fd4e5da5Sopenharmony_ci << ": expected " << function_type->words().size() - 3 139fd4e5da5Sopenharmony_ci << " based on the function's type"; 140fd4e5da5Sopenharmony_ci } 141fd4e5da5Sopenharmony_ci 142fd4e5da5Sopenharmony_ci const auto param_type = 143fd4e5da5Sopenharmony_ci _.FindDef(function_type->GetOperandAs<uint32_t>(param_index + 2)); 144fd4e5da5Sopenharmony_ci if (!param_type || inst->type_id() != param_type->id()) { 145fd4e5da5Sopenharmony_ci return _.diag(SPV_ERROR_INVALID_ID, inst) 146fd4e5da5Sopenharmony_ci << "OpFunctionParameter Result Type <id> " 147fd4e5da5Sopenharmony_ci << _.getIdName(inst->type_id()) 148fd4e5da5Sopenharmony_ci << " does not match the OpTypeFunction parameter " 149fd4e5da5Sopenharmony_ci "type of the same index."; 150fd4e5da5Sopenharmony_ci } 151fd4e5da5Sopenharmony_ci 152fd4e5da5Sopenharmony_ci // Validate that PhysicalStorageBuffer have one of Restrict, Aliased, 153fd4e5da5Sopenharmony_ci // RestrictPointer, or AliasedPointer. 154fd4e5da5Sopenharmony_ci auto param_nonarray_type_id = param_type->id(); 155fd4e5da5Sopenharmony_ci while (_.GetIdOpcode(param_nonarray_type_id) == spv::Op::OpTypeArray) { 156fd4e5da5Sopenharmony_ci param_nonarray_type_id = 157fd4e5da5Sopenharmony_ci _.FindDef(param_nonarray_type_id)->GetOperandAs<uint32_t>(1u); 158fd4e5da5Sopenharmony_ci } 159fd4e5da5Sopenharmony_ci if (_.GetIdOpcode(param_nonarray_type_id) == spv::Op::OpTypePointer) { 160fd4e5da5Sopenharmony_ci auto param_nonarray_type = _.FindDef(param_nonarray_type_id); 161fd4e5da5Sopenharmony_ci if (param_nonarray_type->GetOperandAs<spv::StorageClass>(1u) == 162fd4e5da5Sopenharmony_ci spv::StorageClass::PhysicalStorageBuffer) { 163fd4e5da5Sopenharmony_ci // check for Aliased or Restrict 164fd4e5da5Sopenharmony_ci const auto& decorations = _.id_decorations(inst->id()); 165fd4e5da5Sopenharmony_ci 166fd4e5da5Sopenharmony_ci bool foundAliased = std::any_of( 167fd4e5da5Sopenharmony_ci decorations.begin(), decorations.end(), [](const Decoration& d) { 168fd4e5da5Sopenharmony_ci return spv::Decoration::Aliased == d.dec_type(); 169fd4e5da5Sopenharmony_ci }); 170fd4e5da5Sopenharmony_ci 171fd4e5da5Sopenharmony_ci bool foundRestrict = std::any_of( 172fd4e5da5Sopenharmony_ci decorations.begin(), decorations.end(), [](const Decoration& d) { 173fd4e5da5Sopenharmony_ci return spv::Decoration::Restrict == d.dec_type(); 174fd4e5da5Sopenharmony_ci }); 175fd4e5da5Sopenharmony_ci 176fd4e5da5Sopenharmony_ci if (!foundAliased && !foundRestrict) { 177fd4e5da5Sopenharmony_ci return _.diag(SPV_ERROR_INVALID_ID, inst) 178fd4e5da5Sopenharmony_ci << "OpFunctionParameter " << inst->id() 179fd4e5da5Sopenharmony_ci << ": expected Aliased or Restrict for PhysicalStorageBuffer " 180fd4e5da5Sopenharmony_ci "pointer."; 181fd4e5da5Sopenharmony_ci } 182fd4e5da5Sopenharmony_ci if (foundAliased && foundRestrict) { 183fd4e5da5Sopenharmony_ci return _.diag(SPV_ERROR_INVALID_ID, inst) 184fd4e5da5Sopenharmony_ci << "OpFunctionParameter " << inst->id() 185fd4e5da5Sopenharmony_ci << ": can't specify both Aliased and Restrict for " 186fd4e5da5Sopenharmony_ci "PhysicalStorageBuffer pointer."; 187fd4e5da5Sopenharmony_ci } 188fd4e5da5Sopenharmony_ci } else { 189fd4e5da5Sopenharmony_ci const auto pointee_type_id = 190fd4e5da5Sopenharmony_ci param_nonarray_type->GetOperandAs<uint32_t>(2); 191fd4e5da5Sopenharmony_ci const auto pointee_type = _.FindDef(pointee_type_id); 192fd4e5da5Sopenharmony_ci if (spv::Op::OpTypePointer == pointee_type->opcode() && 193fd4e5da5Sopenharmony_ci pointee_type->GetOperandAs<spv::StorageClass>(1u) == 194fd4e5da5Sopenharmony_ci spv::StorageClass::PhysicalStorageBuffer) { 195fd4e5da5Sopenharmony_ci // check for AliasedPointer/RestrictPointer 196fd4e5da5Sopenharmony_ci const auto& decorations = _.id_decorations(inst->id()); 197fd4e5da5Sopenharmony_ci 198fd4e5da5Sopenharmony_ci bool foundAliased = std::any_of( 199fd4e5da5Sopenharmony_ci decorations.begin(), decorations.end(), [](const Decoration& d) { 200fd4e5da5Sopenharmony_ci return spv::Decoration::AliasedPointer == d.dec_type(); 201fd4e5da5Sopenharmony_ci }); 202fd4e5da5Sopenharmony_ci 203fd4e5da5Sopenharmony_ci bool foundRestrict = std::any_of( 204fd4e5da5Sopenharmony_ci decorations.begin(), decorations.end(), [](const Decoration& d) { 205fd4e5da5Sopenharmony_ci return spv::Decoration::RestrictPointer == d.dec_type(); 206fd4e5da5Sopenharmony_ci }); 207fd4e5da5Sopenharmony_ci 208fd4e5da5Sopenharmony_ci if (!foundAliased && !foundRestrict) { 209fd4e5da5Sopenharmony_ci return _.diag(SPV_ERROR_INVALID_ID, inst) 210fd4e5da5Sopenharmony_ci << "OpFunctionParameter " << inst->id() 211fd4e5da5Sopenharmony_ci << ": expected AliasedPointer or RestrictPointer for " 212fd4e5da5Sopenharmony_ci "PhysicalStorageBuffer pointer."; 213fd4e5da5Sopenharmony_ci } 214fd4e5da5Sopenharmony_ci if (foundAliased && foundRestrict) { 215fd4e5da5Sopenharmony_ci return _.diag(SPV_ERROR_INVALID_ID, inst) 216fd4e5da5Sopenharmony_ci << "OpFunctionParameter " << inst->id() 217fd4e5da5Sopenharmony_ci << ": can't specify both AliasedPointer and " 218fd4e5da5Sopenharmony_ci "RestrictPointer for PhysicalStorageBuffer pointer."; 219fd4e5da5Sopenharmony_ci } 220fd4e5da5Sopenharmony_ci } 221fd4e5da5Sopenharmony_ci } 222fd4e5da5Sopenharmony_ci } 223fd4e5da5Sopenharmony_ci 224fd4e5da5Sopenharmony_ci return SPV_SUCCESS; 225fd4e5da5Sopenharmony_ci} 226fd4e5da5Sopenharmony_ci 227fd4e5da5Sopenharmony_cispv_result_t ValidateFunctionCall(ValidationState_t& _, 228fd4e5da5Sopenharmony_ci const Instruction* inst) { 229fd4e5da5Sopenharmony_ci const auto function_id = inst->GetOperandAs<uint32_t>(2); 230fd4e5da5Sopenharmony_ci const auto function = _.FindDef(function_id); 231fd4e5da5Sopenharmony_ci if (!function || spv::Op::OpFunction != function->opcode()) { 232fd4e5da5Sopenharmony_ci return _.diag(SPV_ERROR_INVALID_ID, inst) 233fd4e5da5Sopenharmony_ci << "OpFunctionCall Function <id> " << _.getIdName(function_id) 234fd4e5da5Sopenharmony_ci << " is not a function."; 235fd4e5da5Sopenharmony_ci } 236fd4e5da5Sopenharmony_ci 237fd4e5da5Sopenharmony_ci auto return_type = _.FindDef(function->type_id()); 238fd4e5da5Sopenharmony_ci if (!return_type || return_type->id() != inst->type_id()) { 239fd4e5da5Sopenharmony_ci return _.diag(SPV_ERROR_INVALID_ID, inst) 240fd4e5da5Sopenharmony_ci << "OpFunctionCall Result Type <id> " << _.getIdName(inst->type_id()) 241fd4e5da5Sopenharmony_ci << "s type does not match Function <id> " 242fd4e5da5Sopenharmony_ci << _.getIdName(return_type->id()) << "s return type."; 243fd4e5da5Sopenharmony_ci } 244fd4e5da5Sopenharmony_ci 245fd4e5da5Sopenharmony_ci const auto function_type_id = function->GetOperandAs<uint32_t>(3); 246fd4e5da5Sopenharmony_ci const auto function_type = _.FindDef(function_type_id); 247fd4e5da5Sopenharmony_ci if (!function_type || function_type->opcode() != spv::Op::OpTypeFunction) { 248fd4e5da5Sopenharmony_ci return _.diag(SPV_ERROR_INVALID_ID, inst) 249fd4e5da5Sopenharmony_ci << "Missing function type definition."; 250fd4e5da5Sopenharmony_ci } 251fd4e5da5Sopenharmony_ci 252fd4e5da5Sopenharmony_ci const auto function_call_arg_count = inst->words().size() - 4; 253fd4e5da5Sopenharmony_ci const auto function_param_count = function_type->words().size() - 3; 254fd4e5da5Sopenharmony_ci if (function_param_count != function_call_arg_count) { 255fd4e5da5Sopenharmony_ci return _.diag(SPV_ERROR_INVALID_ID, inst) 256fd4e5da5Sopenharmony_ci << "OpFunctionCall Function <id>'s parameter count does not match " 257fd4e5da5Sopenharmony_ci "the argument count."; 258fd4e5da5Sopenharmony_ci } 259fd4e5da5Sopenharmony_ci 260fd4e5da5Sopenharmony_ci for (size_t argument_index = 3, param_index = 2; 261fd4e5da5Sopenharmony_ci argument_index < inst->operands().size(); 262fd4e5da5Sopenharmony_ci argument_index++, param_index++) { 263fd4e5da5Sopenharmony_ci const auto argument_id = inst->GetOperandAs<uint32_t>(argument_index); 264fd4e5da5Sopenharmony_ci const auto argument = _.FindDef(argument_id); 265fd4e5da5Sopenharmony_ci if (!argument) { 266fd4e5da5Sopenharmony_ci return _.diag(SPV_ERROR_INVALID_ID, inst) 267fd4e5da5Sopenharmony_ci << "Missing argument " << argument_index - 3 << " definition."; 268fd4e5da5Sopenharmony_ci } 269fd4e5da5Sopenharmony_ci 270fd4e5da5Sopenharmony_ci const auto argument_type = _.FindDef(argument->type_id()); 271fd4e5da5Sopenharmony_ci if (!argument_type) { 272fd4e5da5Sopenharmony_ci return _.diag(SPV_ERROR_INVALID_ID, inst) 273fd4e5da5Sopenharmony_ci << "Missing argument " << argument_index - 3 274fd4e5da5Sopenharmony_ci << " type definition."; 275fd4e5da5Sopenharmony_ci } 276fd4e5da5Sopenharmony_ci 277fd4e5da5Sopenharmony_ci const auto parameter_type_id = 278fd4e5da5Sopenharmony_ci function_type->GetOperandAs<uint32_t>(param_index); 279fd4e5da5Sopenharmony_ci const auto parameter_type = _.FindDef(parameter_type_id); 280fd4e5da5Sopenharmony_ci if (!parameter_type || argument_type->id() != parameter_type->id()) { 281fd4e5da5Sopenharmony_ci if (!_.options()->before_hlsl_legalization || 282fd4e5da5Sopenharmony_ci !DoPointeesLogicallyMatch(argument_type, parameter_type, _)) { 283fd4e5da5Sopenharmony_ci return _.diag(SPV_ERROR_INVALID_ID, inst) 284fd4e5da5Sopenharmony_ci << "OpFunctionCall Argument <id> " << _.getIdName(argument_id) 285fd4e5da5Sopenharmony_ci << "s type does not match Function <id> " 286fd4e5da5Sopenharmony_ci << _.getIdName(parameter_type_id) << "s parameter type."; 287fd4e5da5Sopenharmony_ci } 288fd4e5da5Sopenharmony_ci } 289fd4e5da5Sopenharmony_ci 290fd4e5da5Sopenharmony_ci if (_.addressing_model() == spv::AddressingModel::Logical) { 291fd4e5da5Sopenharmony_ci if (parameter_type->opcode() == spv::Op::OpTypePointer && 292fd4e5da5Sopenharmony_ci !_.options()->relax_logical_pointer) { 293fd4e5da5Sopenharmony_ci spv::StorageClass sc = 294fd4e5da5Sopenharmony_ci parameter_type->GetOperandAs<spv::StorageClass>(1u); 295fd4e5da5Sopenharmony_ci // Validate which storage classes can be pointer operands. 296fd4e5da5Sopenharmony_ci switch (sc) { 297fd4e5da5Sopenharmony_ci case spv::StorageClass::UniformConstant: 298fd4e5da5Sopenharmony_ci case spv::StorageClass::Function: 299fd4e5da5Sopenharmony_ci case spv::StorageClass::Private: 300fd4e5da5Sopenharmony_ci case spv::StorageClass::Workgroup: 301fd4e5da5Sopenharmony_ci case spv::StorageClass::AtomicCounter: 302fd4e5da5Sopenharmony_ci // These are always allowed. 303fd4e5da5Sopenharmony_ci break; 304fd4e5da5Sopenharmony_ci case spv::StorageClass::StorageBuffer: 305fd4e5da5Sopenharmony_ci if (!_.features().variable_pointers) { 306fd4e5da5Sopenharmony_ci return _.diag(SPV_ERROR_INVALID_ID, inst) 307fd4e5da5Sopenharmony_ci << "StorageBuffer pointer operand " 308fd4e5da5Sopenharmony_ci << _.getIdName(argument_id) 309fd4e5da5Sopenharmony_ci << " requires a variable pointers capability"; 310fd4e5da5Sopenharmony_ci } 311fd4e5da5Sopenharmony_ci break; 312fd4e5da5Sopenharmony_ci default: 313fd4e5da5Sopenharmony_ci return _.diag(SPV_ERROR_INVALID_ID, inst) 314fd4e5da5Sopenharmony_ci << "Invalid storage class for pointer operand " 315fd4e5da5Sopenharmony_ci << _.getIdName(argument_id); 316fd4e5da5Sopenharmony_ci } 317fd4e5da5Sopenharmony_ci 318fd4e5da5Sopenharmony_ci // Validate memory object declaration requirements. 319fd4e5da5Sopenharmony_ci if (argument->opcode() != spv::Op::OpVariable && 320fd4e5da5Sopenharmony_ci argument->opcode() != spv::Op::OpFunctionParameter) { 321fd4e5da5Sopenharmony_ci const bool ssbo_vptr = _.features().variable_pointers && 322fd4e5da5Sopenharmony_ci sc == spv::StorageClass::StorageBuffer; 323fd4e5da5Sopenharmony_ci const bool wg_vptr = 324fd4e5da5Sopenharmony_ci _.HasCapability(spv::Capability::VariablePointers) && 325fd4e5da5Sopenharmony_ci sc == spv::StorageClass::Workgroup; 326fd4e5da5Sopenharmony_ci const bool uc_ptr = sc == spv::StorageClass::UniformConstant; 327fd4e5da5Sopenharmony_ci if (!ssbo_vptr && !wg_vptr && !uc_ptr) { 328fd4e5da5Sopenharmony_ci return _.diag(SPV_ERROR_INVALID_ID, inst) 329fd4e5da5Sopenharmony_ci << "Pointer operand " << _.getIdName(argument_id) 330fd4e5da5Sopenharmony_ci << " must be a memory object declaration"; 331fd4e5da5Sopenharmony_ci } 332fd4e5da5Sopenharmony_ci } 333fd4e5da5Sopenharmony_ci } 334fd4e5da5Sopenharmony_ci } 335fd4e5da5Sopenharmony_ci } 336fd4e5da5Sopenharmony_ci return SPV_SUCCESS; 337fd4e5da5Sopenharmony_ci} 338fd4e5da5Sopenharmony_ci 339fd4e5da5Sopenharmony_ci} // namespace 340fd4e5da5Sopenharmony_ci 341fd4e5da5Sopenharmony_cispv_result_t FunctionPass(ValidationState_t& _, const Instruction* inst) { 342fd4e5da5Sopenharmony_ci switch (inst->opcode()) { 343fd4e5da5Sopenharmony_ci case spv::Op::OpFunction: 344fd4e5da5Sopenharmony_ci if (auto error = ValidateFunction(_, inst)) return error; 345fd4e5da5Sopenharmony_ci break; 346fd4e5da5Sopenharmony_ci case spv::Op::OpFunctionParameter: 347fd4e5da5Sopenharmony_ci if (auto error = ValidateFunctionParameter(_, inst)) return error; 348fd4e5da5Sopenharmony_ci break; 349fd4e5da5Sopenharmony_ci case spv::Op::OpFunctionCall: 350fd4e5da5Sopenharmony_ci if (auto error = ValidateFunctionCall(_, inst)) return error; 351fd4e5da5Sopenharmony_ci break; 352fd4e5da5Sopenharmony_ci default: 353fd4e5da5Sopenharmony_ci break; 354fd4e5da5Sopenharmony_ci } 355fd4e5da5Sopenharmony_ci 356fd4e5da5Sopenharmony_ci return SPV_SUCCESS; 357fd4e5da5Sopenharmony_ci} 358fd4e5da5Sopenharmony_ci 359fd4e5da5Sopenharmony_ci} // namespace val 360fd4e5da5Sopenharmony_ci} // namespace spvtools 361