1 // Copyright (c) 2015-2016 The Khronos Group Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 #include "val/validation_state.h" 16 17 #include <cassert> 18 19 #include "opcode.h" 20 #include "val/basic_block.h" 21 #include "val/construct.h" 22 #include "val/function.h" 23 24 using std::deque; 25 using std::make_pair; 26 using std::pair; 27 using std::string; 28 using std::unordered_map; 29 using std::vector; 30 31 namespace libspirv { 32 33 namespace { 34 bool IsInstructionInLayoutSection(ModuleLayoutSection layout, SpvOp op) { 35 // See Section 2.4 36 bool out = false; 37 // clang-format off 38 switch (layout) { 39 case kLayoutCapabilities: out = op == SpvOpCapability; break; 40 case kLayoutExtensions: out = op == SpvOpExtension; break; 41 case kLayoutExtInstImport: out = op == SpvOpExtInstImport; break; 42 case kLayoutMemoryModel: out = op == SpvOpMemoryModel; break; 43 case kLayoutEntryPoint: out = op == SpvOpEntryPoint; break; 44 case kLayoutExecutionMode: out = op == SpvOpExecutionMode; break; 45 case kLayoutDebug1: 46 switch (op) { 47 case SpvOpSourceContinued: 48 case SpvOpSource: 49 case SpvOpSourceExtension: 50 case SpvOpString: 51 out = true; 52 break; 53 default: break; 54 } 55 break; 56 case kLayoutDebug2: 57 switch (op) { 58 case SpvOpName: 59 case SpvOpMemberName: 60 out = true; 61 break; 62 default: break; 63 } 64 break; 65 case kLayoutAnnotations: 66 switch (op) { 67 case SpvOpDecorate: 68 case SpvOpMemberDecorate: 69 case SpvOpGroupDecorate: 70 case SpvOpGroupMemberDecorate: 71 case SpvOpDecorationGroup: 72 out = true; 73 break; 74 default: break; 75 } 76 break; 77 case kLayoutTypes: 78 if (spvOpcodeGeneratesType(op) || spvOpcodeIsConstant(op)) { 79 out = true; 80 break; 81 } 82 switch (op) { 83 case SpvOpTypeForwardPointer: 84 case SpvOpVariable: 85 case SpvOpLine: 86 case SpvOpNoLine: 87 case SpvOpUndef: 88 out = true; 89 break; 90 default: break; 91 } 92 break; 93 case kLayoutFunctionDeclarations: 94 case kLayoutFunctionDefinitions: 95 // NOTE: These instructions should NOT be in these layout sections 96 if (spvOpcodeGeneratesType(op) || spvOpcodeIsConstant(op)) { 97 out = false; 98 break; 99 } 100 switch (op) { 101 case SpvOpCapability: 102 case SpvOpExtension: 103 case SpvOpExtInstImport: 104 case SpvOpMemoryModel: 105 case SpvOpEntryPoint: 106 case SpvOpExecutionMode: 107 case SpvOpSourceContinued: 108 case SpvOpSource: 109 case SpvOpSourceExtension: 110 case SpvOpString: 111 case SpvOpName: 112 case SpvOpMemberName: 113 case SpvOpDecorate: 114 case SpvOpMemberDecorate: 115 case SpvOpGroupDecorate: 116 case SpvOpGroupMemberDecorate: 117 case SpvOpDecorationGroup: 118 case SpvOpTypeForwardPointer: 119 out = false; 120 break; 121 default: 122 out = true; 123 break; 124 } 125 } 126 // clang-format on 127 return out; 128 } 129 130 } // anonymous namespace 131 132 ValidationState_t::ValidationState_t(const spv_const_context ctx, 133 const spv_const_validator_options opt) 134 : context_(ctx), 135 options_(opt), 136 instruction_counter_(0), 137 unresolved_forward_ids_{}, 138 operand_names_{}, 139 current_layout_section_(kLayoutCapabilities), 140 module_functions_(), 141 module_capabilities_(), 142 module_extensions_(), 143 ordered_instructions_(), 144 all_definitions_(), 145 global_vars_(), 146 local_vars_(), 147 struct_nesting_depth_(), 148 grammar_(ctx), 149 addressing_model_(SpvAddressingModelLogical), 150 memory_model_(SpvMemoryModelSimple), 151 in_function_(false) { 152 assert(opt && "Validator options may not be Null."); 153 } 154 155 spv_result_t ValidationState_t::ForwardDeclareId(uint32_t id) { 156 unresolved_forward_ids_.insert(id); 157 return SPV_SUCCESS; 158 } 159 160 spv_result_t ValidationState_t::RemoveIfForwardDeclared(uint32_t id) { 161 unresolved_forward_ids_.erase(id); 162 return SPV_SUCCESS; 163 } 164 165 spv_result_t ValidationState_t::RegisterForwardPointer(uint32_t id) { 166 forward_pointer_ids_.insert(id); 167 return SPV_SUCCESS; 168 } 169 170 bool ValidationState_t::IsForwardPointer(uint32_t id) const { 171 return (forward_pointer_ids_.find(id) != forward_pointer_ids_.end()); 172 } 173 174 void ValidationState_t::AssignNameToId(uint32_t id, string name) { 175 operand_names_[id] = name; 176 } 177 178 string ValidationState_t::getIdName(uint32_t id) const { 179 std::stringstream out; 180 out << id; 181 if (operand_names_.find(id) != end(operand_names_)) { 182 out << "[" << operand_names_.at(id) << "]"; 183 } 184 return out.str(); 185 } 186 187 string ValidationState_t::getIdOrName(uint32_t id) const { 188 std::stringstream out; 189 if (operand_names_.find(id) != end(operand_names_)) { 190 out << operand_names_.at(id); 191 } else { 192 out << id; 193 } 194 return out.str(); 195 } 196 197 size_t ValidationState_t::unresolved_forward_id_count() const { 198 return unresolved_forward_ids_.size(); 199 } 200 201 vector<uint32_t> ValidationState_t::UnresolvedForwardIds() const { 202 vector<uint32_t> out(begin(unresolved_forward_ids_), 203 end(unresolved_forward_ids_)); 204 return out; 205 } 206 207 bool ValidationState_t::IsDefinedId(uint32_t id) const { 208 return all_definitions_.find(id) != end(all_definitions_); 209 } 210 211 const Instruction* ValidationState_t::FindDef(uint32_t id) const { 212 auto it = all_definitions_.find(id); 213 if (it == all_definitions_.end()) 214 return nullptr; 215 return it->second; 216 } 217 218 Instruction* ValidationState_t::FindDef(uint32_t id) { 219 auto it = all_definitions_.find(id); 220 if (it == all_definitions_.end()) 221 return nullptr; 222 return it->second; 223 } 224 225 // Increments the instruction count. Used for diagnostic 226 int ValidationState_t::increment_instruction_count() { 227 return instruction_counter_++; 228 } 229 230 ModuleLayoutSection ValidationState_t::current_layout_section() const { 231 return current_layout_section_; 232 } 233 234 void ValidationState_t::ProgressToNextLayoutSectionOrder() { 235 // Guard against going past the last element(kLayoutFunctionDefinitions) 236 if (current_layout_section_ <= kLayoutFunctionDefinitions) { 237 current_layout_section_ = 238 static_cast<ModuleLayoutSection>(current_layout_section_ + 1); 239 } 240 } 241 242 bool ValidationState_t::IsOpcodeInCurrentLayoutSection(SpvOp op) { 243 return IsInstructionInLayoutSection(current_layout_section_, op); 244 } 245 246 DiagnosticStream ValidationState_t::diag(spv_result_t error_code) const { 247 return libspirv::DiagnosticStream( 248 {0, 0, static_cast<size_t>(instruction_counter_)}, context_->consumer, 249 error_code); 250 } 251 252 deque<Function>& ValidationState_t::functions() { return module_functions_; } 253 254 Function& ValidationState_t::current_function() { 255 assert(in_function_body()); 256 return module_functions_.back(); 257 } 258 259 bool ValidationState_t::in_function_body() const { return in_function_; } 260 261 bool ValidationState_t::in_block() const { 262 return module_functions_.empty() == false && 263 module_functions_.back().current_block() != nullptr; 264 } 265 266 void ValidationState_t::RegisterCapability(SpvCapability cap) { 267 // Avoid redundant work. Otherwise the recursion could induce work 268 // quadrdatic in the capability dependency depth. (Ok, not much, but 269 // it's something.) 270 if (module_capabilities_.Contains(cap)) return; 271 272 module_capabilities_.Add(cap); 273 spv_operand_desc desc; 274 if (SPV_SUCCESS == 275 grammar_.lookupOperand(SPV_OPERAND_TYPE_CAPABILITY, cap, &desc)) { 276 desc->capabilities.ForEach( 277 [this](SpvCapability c) { RegisterCapability(c); }); 278 } 279 280 switch (cap) { 281 case SpvCapabilityInt16: 282 features_.declare_int16_type = true; 283 break; 284 case SpvCapabilityFloat16: 285 case SpvCapabilityFloat16Buffer: 286 features_.declare_float16_type = true; 287 break; 288 case SpvCapabilityStorageUniformBufferBlock16: 289 case SpvCapabilityStorageUniform16: 290 case SpvCapabilityStoragePushConstant16: 291 case SpvCapabilityStorageInputOutput16: 292 features_.declare_int16_type = true; 293 features_.declare_float16_type = true; 294 features_.free_fp_rounding_mode = true; 295 break; 296 case SpvCapabilityVariablePointers: 297 features_.variable_pointers = true; 298 features_.variable_pointers_storage_buffer = true; 299 break; 300 case SpvCapabilityVariablePointersStorageBuffer: 301 features_.variable_pointers_storage_buffer = true; 302 break; 303 default: 304 break; 305 } 306 } 307 308 void ValidationState_t::RegisterExtension(Extension ext) { 309 if (module_extensions_.Contains(ext)) return; 310 311 module_extensions_.Add(ext); 312 } 313 314 bool ValidationState_t::HasAnyOfCapabilities( 315 const CapabilitySet& capabilities) const { 316 return module_capabilities_.HasAnyOf(capabilities); 317 } 318 319 bool ValidationState_t::HasAnyOfExtensions( 320 const ExtensionSet& extensions) const { 321 return module_extensions_.HasAnyOf(extensions); 322 } 323 324 void ValidationState_t::set_addressing_model(SpvAddressingModel am) { 325 addressing_model_ = am; 326 } 327 328 SpvAddressingModel ValidationState_t::addressing_model() const { 329 return addressing_model_; 330 } 331 332 void ValidationState_t::set_memory_model(SpvMemoryModel mm) { 333 memory_model_ = mm; 334 } 335 336 SpvMemoryModel ValidationState_t::memory_model() const { return memory_model_; } 337 338 spv_result_t ValidationState_t::RegisterFunction( 339 uint32_t id, uint32_t ret_type_id, SpvFunctionControlMask function_control, 340 uint32_t function_type_id) { 341 assert(in_function_body() == false && 342 "RegisterFunction can only be called when parsing the binary outside " 343 "of another function"); 344 in_function_ = true; 345 module_functions_.emplace_back(id, ret_type_id, function_control, 346 function_type_id); 347 348 // TODO(umar): validate function type and type_id 349 350 return SPV_SUCCESS; 351 } 352 353 spv_result_t ValidationState_t::RegisterFunctionEnd() { 354 assert(in_function_body() == true && 355 "RegisterFunctionEnd can only be called when parsing the binary " 356 "inside of another function"); 357 assert(in_block() == false && 358 "RegisterFunctionParameter can only be called when parsing the binary " 359 "ouside of a block"); 360 current_function().RegisterFunctionEnd(); 361 in_function_ = false; 362 return SPV_SUCCESS; 363 } 364 365 void ValidationState_t::RegisterInstruction( 366 const spv_parsed_instruction_t& inst) { 367 if (in_function_body()) { 368 ordered_instructions_.emplace_back(&inst, ¤t_function(), 369 current_function().current_block()); 370 } else { 371 ordered_instructions_.emplace_back(&inst, nullptr, nullptr); 372 } 373 uint32_t id = ordered_instructions_.back().id(); 374 if (id) { 375 all_definitions_.insert(make_pair(id, &ordered_instructions_.back())); 376 } 377 378 // If the instruction is using an OpTypeSampledImage as an operand, it should 379 // be recorded. The validator will ensure that all usages of an 380 // OpTypeSampledImage and its definition are in the same basic block. 381 for (uint16_t i = 0; i < inst.num_operands; ++i) { 382 const spv_parsed_operand_t& operand = inst.operands[i]; 383 if (SPV_OPERAND_TYPE_ID == operand.type) { 384 const uint32_t operand_word = inst.words[operand.offset]; 385 Instruction* operand_inst = FindDef(operand_word); 386 if (operand_inst && SpvOpSampledImage == operand_inst->opcode()) { 387 RegisterSampledImageConsumer(operand_word, inst.result_id); 388 } 389 } 390 } 391 } 392 393 std::vector<uint32_t> ValidationState_t::getSampledImageConsumers( 394 uint32_t sampled_image_id) const { 395 std::vector<uint32_t> result; 396 auto iter = sampled_image_consumers_.find(sampled_image_id); 397 if (iter != sampled_image_consumers_.end()) { 398 result = iter->second; 399 } 400 return result; 401 } 402 403 void ValidationState_t::RegisterSampledImageConsumer(uint32_t sampled_image_id, 404 uint32_t consumer_id) { 405 sampled_image_consumers_[sampled_image_id].push_back(consumer_id); 406 } 407 408 uint32_t ValidationState_t::getIdBound() const { return id_bound_; } 409 410 void ValidationState_t::setIdBound(const uint32_t bound) { id_bound_ = bound; } 411 412 bool ValidationState_t::RegisterUniqueTypeDeclaration( 413 const spv_parsed_instruction_t& inst) { 414 std::vector<uint32_t> key; 415 key.push_back(static_cast<uint32_t>(inst.opcode)); 416 for (int index = 0; index < inst.num_operands; ++index) { 417 const spv_parsed_operand_t& operand = inst.operands[index]; 418 419 if (operand.type == SPV_OPERAND_TYPE_RESULT_ID) continue; 420 421 const int words_begin = operand.offset; 422 const int words_end = words_begin + operand.num_words; 423 assert(words_end <= static_cast<int>(inst.num_words)); 424 425 key.insert(key.end(), inst.words + words_begin, inst.words + words_end); 426 } 427 428 return unique_type_declarations_.insert(std::move(key)).second; 429 } 430 } /// namespace libspirv 431