1 // Copyright (c) 2015-2016 The Khronos Group Inc. 2 // 3 // Permission is hereby granted, free of charge, to any person obtaining a 4 // copy of this software and/or associated documentation files (the 5 // "Materials"), to deal in the Materials without restriction, including 6 // without limitation the rights to use, copy, modify, merge, publish, 7 // distribute, sublicense, and/or sell copies of the Materials, and to 8 // permit persons to whom the Materials are furnished to do so, subject to 9 // the following conditions: 10 // 11 // The above copyright notice and this permission notice shall be included 12 // in all copies or substantial portions of the Materials. 13 // 14 // MODIFICATIONS TO THIS FILE MAY MEAN IT NO LONGER ACCURATELY REFLECTS 15 // KHRONOS STANDARDS. THE UNMODIFIED, NORMATIVE VERSIONS OF KHRONOS 16 // SPECIFICATIONS AND HEADER INFORMATION ARE LOCATED AT 17 // https://www.khronos.org/registry/ 18 // 19 // THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 20 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 21 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 22 // IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 23 // CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 24 // TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 25 // MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. 26 27 #include "val/ValidationState.h" 28 29 #include <cassert> 30 31 #include "val/BasicBlock.h" 32 #include "val/Construct.h" 33 #include "val/Function.h" 34 35 using std::list; 36 using std::string; 37 using std::vector; 38 39 namespace libspirv { 40 41 namespace { 42 bool IsInstructionInLayoutSection(ModuleLayoutSection layout, SpvOp op) { 43 // See Section 2.4 44 bool out = false; 45 // clang-format off 46 switch (layout) { 47 case kLayoutCapabilities: out = op == SpvOpCapability; break; 48 case kLayoutExtensions: out = op == SpvOpExtension; break; 49 case kLayoutExtInstImport: out = op == SpvOpExtInstImport; break; 50 case kLayoutMemoryModel: out = op == SpvOpMemoryModel; break; 51 case kLayoutEntryPoint: out = op == SpvOpEntryPoint; break; 52 case kLayoutExecutionMode: out = op == SpvOpExecutionMode; break; 53 case kLayoutDebug1: 54 switch (op) { 55 case SpvOpSourceContinued: 56 case SpvOpSource: 57 case SpvOpSourceExtension: 58 case SpvOpString: 59 out = true; 60 break; 61 default: break; 62 } 63 break; 64 case kLayoutDebug2: 65 switch (op) { 66 case SpvOpName: 67 case SpvOpMemberName: 68 out = true; 69 break; 70 default: break; 71 } 72 break; 73 case kLayoutAnnotations: 74 switch (op) { 75 case SpvOpDecorate: 76 case SpvOpMemberDecorate: 77 case SpvOpGroupDecorate: 78 case SpvOpGroupMemberDecorate: 79 case SpvOpDecorationGroup: 80 out = true; 81 break; 82 default: break; 83 } 84 break; 85 case kLayoutTypes: 86 switch (op) { 87 case SpvOpTypeVoid: 88 case SpvOpTypeBool: 89 case SpvOpTypeInt: 90 case SpvOpTypeFloat: 91 case SpvOpTypeVector: 92 case SpvOpTypeMatrix: 93 case SpvOpTypeImage: 94 case SpvOpTypeSampler: 95 case SpvOpTypeSampledImage: 96 case SpvOpTypeArray: 97 case SpvOpTypeRuntimeArray: 98 case SpvOpTypeStruct: 99 case SpvOpTypeOpaque: 100 case SpvOpTypePointer: 101 case SpvOpTypeFunction: 102 case SpvOpTypeEvent: 103 case SpvOpTypeDeviceEvent: 104 case SpvOpTypeReserveId: 105 case SpvOpTypeQueue: 106 case SpvOpTypePipe: 107 case SpvOpTypeForwardPointer: 108 case SpvOpConstantTrue: 109 case SpvOpConstantFalse: 110 case SpvOpConstant: 111 case SpvOpConstantComposite: 112 case SpvOpConstantSampler: 113 case SpvOpConstantNull: 114 case SpvOpSpecConstantTrue: 115 case SpvOpSpecConstantFalse: 116 case SpvOpSpecConstant: 117 case SpvOpSpecConstantComposite: 118 case SpvOpSpecConstantOp: 119 case SpvOpVariable: 120 case SpvOpLine: 121 case SpvOpNoLine: 122 out = true; 123 break; 124 default: break; 125 } 126 break; 127 case kLayoutFunctionDeclarations: 128 case kLayoutFunctionDefinitions: 129 // NOTE: These instructions should NOT be in these layout sections 130 switch (op) { 131 case SpvOpCapability: 132 case SpvOpExtension: 133 case SpvOpExtInstImport: 134 case SpvOpMemoryModel: 135 case SpvOpEntryPoint: 136 case SpvOpExecutionMode: 137 case SpvOpSourceContinued: 138 case SpvOpSource: 139 case SpvOpSourceExtension: 140 case SpvOpString: 141 case SpvOpName: 142 case SpvOpMemberName: 143 case SpvOpDecorate: 144 case SpvOpMemberDecorate: 145 case SpvOpGroupDecorate: 146 case SpvOpGroupMemberDecorate: 147 case SpvOpDecorationGroup: 148 case SpvOpTypeVoid: 149 case SpvOpTypeBool: 150 case SpvOpTypeInt: 151 case SpvOpTypeFloat: 152 case SpvOpTypeVector: 153 case SpvOpTypeMatrix: 154 case SpvOpTypeImage: 155 case SpvOpTypeSampler: 156 case SpvOpTypeSampledImage: 157 case SpvOpTypeArray: 158 case SpvOpTypeRuntimeArray: 159 case SpvOpTypeStruct: 160 case SpvOpTypeOpaque: 161 case SpvOpTypePointer: 162 case SpvOpTypeFunction: 163 case SpvOpTypeEvent: 164 case SpvOpTypeDeviceEvent: 165 case SpvOpTypeReserveId: 166 case SpvOpTypeQueue: 167 case SpvOpTypePipe: 168 case SpvOpTypeForwardPointer: 169 case SpvOpConstantTrue: 170 case SpvOpConstantFalse: 171 case SpvOpConstant: 172 case SpvOpConstantComposite: 173 case SpvOpConstantSampler: 174 case SpvOpConstantNull: 175 case SpvOpSpecConstantTrue: 176 case SpvOpSpecConstantFalse: 177 case SpvOpSpecConstant: 178 case SpvOpSpecConstantComposite: 179 case SpvOpSpecConstantOp: 180 out = false; 181 break; 182 default: 183 out = true; 184 break; 185 } 186 } 187 // clang-format on 188 return out; 189 } 190 191 } // anonymous namespace 192 193 ValidationState_t::ValidationState_t(spv_diagnostic* diagnostic, 194 const spv_const_context context) 195 : diagnostic_(diagnostic), 196 instruction_counter_(0), 197 unresolved_forward_ids_{}, 198 operand_names_{}, 199 current_layout_section_(kLayoutCapabilities), 200 module_functions_(), 201 module_capabilities_(0u), 202 grammar_(context), 203 addressing_model_(SpvAddressingModelLogical), 204 memory_model_(SpvMemoryModelSimple), 205 in_function_(false) {} 206 207 spv_result_t ValidationState_t::ForwardDeclareId(uint32_t id) { 208 unresolved_forward_ids_.insert(id); 209 return SPV_SUCCESS; 210 } 211 212 spv_result_t ValidationState_t::RemoveIfForwardDeclared(uint32_t id) { 213 unresolved_forward_ids_.erase(id); 214 return SPV_SUCCESS; 215 } 216 217 void ValidationState_t::AssignNameToId(uint32_t id, string name) { 218 operand_names_[id] = name; 219 } 220 221 string ValidationState_t::getIdName(uint32_t id) const { 222 std::stringstream out; 223 out << id; 224 if (operand_names_.find(id) != end(operand_names_)) { 225 out << "[" << operand_names_.at(id) << "]"; 226 } 227 return out.str(); 228 } 229 230 string ValidationState_t::getIdOrName(uint32_t id) const { 231 std::stringstream out; 232 if (operand_names_.find(id) != end(operand_names_)) { 233 out << operand_names_.at(id); 234 } else { 235 out << id; 236 } 237 return out.str(); 238 } 239 240 size_t ValidationState_t::unresolved_forward_id_count() const { 241 return unresolved_forward_ids_.size(); 242 } 243 244 vector<uint32_t> ValidationState_t::UnresolvedForwardIds() const { 245 vector<uint32_t> out(begin(unresolved_forward_ids_), 246 end(unresolved_forward_ids_)); 247 return out; 248 } 249 250 bool ValidationState_t::IsDefinedId(uint32_t id) const { 251 return usedefs_.FindDef(id).first; 252 } 253 254 // Increments the instruction count. Used for diagnostic 255 int ValidationState_t::increment_instruction_count() { 256 return instruction_counter_++; 257 } 258 259 ModuleLayoutSection ValidationState_t::current_layout_section() const { 260 return current_layout_section_; 261 } 262 263 void ValidationState_t::ProgressToNextLayoutSectionOrder() { 264 // Guard against going past the last element(kLayoutFunctionDefinitions) 265 if (current_layout_section_ <= kLayoutFunctionDefinitions) { 266 current_layout_section_ = 267 static_cast<ModuleLayoutSection>(current_layout_section_ + 1); 268 } 269 } 270 271 bool ValidationState_t::IsOpcodeInCurrentLayoutSection(SpvOp op) { 272 return IsInstructionInLayoutSection(current_layout_section_, op); 273 } 274 275 DiagnosticStream ValidationState_t::diag(spv_result_t error_code) const { 276 return libspirv::DiagnosticStream( 277 {0, 0, static_cast<size_t>(instruction_counter_)}, diagnostic_, 278 error_code); 279 } 280 281 list<Function>& ValidationState_t::functions() { return module_functions_; } 282 283 Function& ValidationState_t::current_function() { 284 assert(in_function_body()); 285 return module_functions_.back(); 286 } 287 288 bool ValidationState_t::in_function_body() const { return in_function_; } 289 290 bool ValidationState_t::in_block() const { 291 return module_functions_.empty() == false && 292 module_functions_.back().current_block() != nullptr; 293 } 294 295 void ValidationState_t::RegisterCapability(SpvCapability cap) { 296 module_capabilities_ |= SPV_CAPABILITY_AS_MASK(cap); 297 spv_operand_desc desc; 298 if (SPV_SUCCESS == 299 grammar_.lookupOperand(SPV_OPERAND_TYPE_CAPABILITY, cap, &desc)) 300 libspirv::ForEach(desc->capabilities, 301 [this](SpvCapability c) { RegisterCapability(c); }); 302 } 303 304 bool ValidationState_t::has_capability(SpvCapability cap) const { 305 return (module_capabilities_ & SPV_CAPABILITY_AS_MASK(cap)) != 0; 306 } 307 308 bool ValidationState_t::HasAnyOf(spv_capability_mask_t capabilities) const { 309 if (!capabilities) 310 return true; // No capabilities requested: trivially satisfied. 311 bool found = false; 312 libspirv::ForEach(capabilities, [&found, this](SpvCapability c) { 313 found |= has_capability(c); 314 }); 315 return found; 316 } 317 318 void ValidationState_t::set_addressing_model(SpvAddressingModel am) { 319 addressing_model_ = am; 320 } 321 322 SpvAddressingModel ValidationState_t::addressing_model() const { 323 return addressing_model_; 324 } 325 326 void ValidationState_t::set_memory_model(SpvMemoryModel mm) { 327 memory_model_ = mm; 328 } 329 330 SpvMemoryModel ValidationState_t::memory_model() const { 331 return memory_model_; 332 } 333 334 spv_result_t ValidationState_t::RegisterFunction( 335 uint32_t id, uint32_t ret_type_id, SpvFunctionControlMask function_control, 336 uint32_t function_type_id) { 337 assert(in_function_body() == false && 338 "RegisterFunction can only be called when parsing the binary outside " 339 "of another function"); 340 in_function_ = true; 341 module_functions_.emplace_back(id, ret_type_id, function_control, 342 function_type_id, *this); 343 344 // TODO(umar): validate function type and type_id 345 346 return SPV_SUCCESS; 347 } 348 349 spv_result_t ValidationState_t::RegisterFunctionEnd() { 350 assert(in_function_body() == true && 351 "RegisterFunctionEnd can only be called when parsing the binary " 352 "inside of another function"); 353 assert(in_block() == false && 354 "RegisterFunctionParameter can only be called when parsing the binary " 355 "ouside of a block"); 356 current_function().RegisterFunctionEnd(); 357 in_function_ = false; 358 return SPV_SUCCESS; 359 } 360 361 } /// namespace libspirv 362