| 154 | } |
| 155 | |
| 156 | spv_result_t ValidateFunctionCall(ValidationState_t& _, |
| 157 | const Instruction* inst) { |
| 158 | const auto function_id = inst->GetOperandAs<uint32_t>(2); |
| 159 | const auto function = _.FindDef(function_id); |
| 160 | if (!function || spv::Op::OpFunction != function->opcode()) { |
| 161 | return _.diag(SPV_ERROR_INVALID_ID, inst) |
| 162 | << "OpFunctionCall Function <id> " << _.getIdName(function_id) |
| 163 | << " is not a function."; |
| 164 | } |
| 165 | |
| 166 | auto return_type = _.FindDef(function->type_id()); |
| 167 | if (!return_type || return_type->id() != inst->type_id()) { |
| 168 | return _.diag(SPV_ERROR_INVALID_ID, inst) |
| 169 | << "OpFunctionCall Result Type <id> " << _.getIdName(inst->type_id()) |
| 170 | << "s type does not match Function <id> " |
| 171 | << _.getIdName(return_type->id()) << "s return type."; |
| 172 | } |
| 173 | if (!_.options()->relax_logical_pointer && |
| 174 | (_.addressing_model() == spv::AddressingModel::Logical || |
| 175 | _.addressing_model() == spv::AddressingModel::PhysicalStorageBuffer64)) { |
| 176 | if (return_type->opcode() == spv::Op::OpTypePointer || |
| 177 | return_type->opcode() == spv::Op::OpTypeUntypedPointerKHR) { |
| 178 | const auto sc = return_type->GetOperandAs<spv::StorageClass>(1); |
| 179 | if (sc != spv::StorageClass::PhysicalStorageBuffer) { |
| 180 | if (!_.HasCapability(spv::Capability::VariablePointersStorageBuffer) && |
| 181 | sc == spv::StorageClass::StorageBuffer) { |
| 182 | return _.diag(SPV_ERROR_INVALID_ID, inst) |
| 183 | << "In Logical addressing, functions may only return a " |
| 184 | "storage buffer pointer if the " |
| 185 | "VariablePointersStorageBuffer capability is declared"; |
| 186 | } else if (!_.HasCapability(spv::Capability::VariablePointers) && |
| 187 | sc == spv::StorageClass::Workgroup) { |
| 188 | return _.diag(SPV_ERROR_INVALID_ID, inst) |
| 189 | << "In Logical addressing, functions may only return a " |
| 190 | "workgroup pointer if the VariablePointers capability is " |
| 191 | "declared"; |
| 192 | } else if (sc != spv::StorageClass::StorageBuffer && |
| 193 | sc != spv::StorageClass::Workgroup) { |
| 194 | return _.diag(SPV_ERROR_INVALID_ID, inst) |
| 195 | << "In Logical addressing, functions may not return a pointer " |
| 196 | "in this storage class"; |
| 197 | } |
| 198 | } |
| 199 | } |
| 200 | } |
| 201 | |
| 202 | const auto function_type_id = function->GetOperandAs<uint32_t>(3); |
| 203 | const auto function_type = _.FindDef(function_type_id); |
| 204 | if (!function_type || function_type->opcode() != spv::Op::OpTypeFunction) { |
| 205 | return _.diag(SPV_ERROR_INVALID_ID, inst) |
| 206 | << "Missing function type definition."; |
| 207 | } |
| 208 | |
| 209 | const auto function_call_arg_count = inst->words().size() - 4; |
| 210 | const auto function_param_count = function_type->words().size() - 3; |
| 211 | if (function_param_count != function_call_arg_count) { |
| 212 | return _.diag(SPV_ERROR_INVALID_ID, inst) |
| 213 | << "OpFunctionCall Function <id>'s parameter count does not match " |
no test coverage detected