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 "source/operand.h" 16 17 #include <assert.h> 18 #include <string.h> 19 #include <algorithm> 20 21 #include "source/macro.h" 22 #include "source/spirv_constant.h" 23 #include "source/spirv_target_env.h" 24 25 // For now, assume unified1 contains up to SPIR-V 1.3 and no later 26 // SPIR-V version. 27 // TODO(dneto): Make one set of tables, but with version tags on a 28 // per-item basis. https://github.com/KhronosGroup/SPIRV-Tools/issues/1195 29 30 #include "operand.kinds-unified1.inc" 31 32 static const spv_operand_table_t kOperandTable = { 33 ARRAY_SIZE(pygen_variable_OperandInfoTable), 34 pygen_variable_OperandInfoTable}; 35 36 spv_result_t spvOperandTableGet(spv_operand_table* pOperandTable, 37 spv_target_env) { 38 if (!pOperandTable) return SPV_ERROR_INVALID_POINTER; 39 40 *pOperandTable = &kOperandTable; 41 return SPV_SUCCESS; 42 } 43 44 spv_result_t spvOperandTableNameLookup(spv_target_env env, 45 const spv_operand_table table, 46 const spv_operand_type_t type, 47 const char* name, 48 const size_t nameLength, 49 spv_operand_desc* pEntry) { 50 if (!table) return SPV_ERROR_INVALID_TABLE; 51 if (!name || !pEntry) return SPV_ERROR_INVALID_POINTER; 52 53 for (uint64_t typeIndex = 0; typeIndex < table->count; ++typeIndex) { 54 const auto& group = table->types[typeIndex]; 55 if (type != group.type) continue; 56 for (uint64_t index = 0; index < group.count; ++index) { 57 const auto& entry = group.entries[index]; 58 // We consider the current operand as available as long as 59 // 1. The target environment satisfies the minimal requirement of the 60 // operand; or 61 // 2. There is at least one extension enabling this operand; or 62 // 3. There is at least one capability enabling this operand. 63 // 64 // Note that the second rule assumes the extension enabling this operand 65 // is indeed requested in the SPIR-V code; checking that should be 66 // validator's work. 67 if ((spvVersionForTargetEnv(env) >= entry.minVersion || 68 entry.numExtensions > 0u || entry.numCapabilities > 0u) && 69 nameLength == strlen(entry.name) && 70 !strncmp(entry.name, name, nameLength)) { 71 *pEntry = &entry; 72 return SPV_SUCCESS; 73 } 74 } 75 } 76 77 return SPV_ERROR_INVALID_LOOKUP; 78 } 79 80 spv_result_t spvOperandTableValueLookup(spv_target_env env, 81 const spv_operand_table table, 82 const spv_operand_type_t type, 83 const uint32_t value, 84 spv_operand_desc* pEntry) { 85 if (!table) return SPV_ERROR_INVALID_TABLE; 86 if (!pEntry) return SPV_ERROR_INVALID_POINTER; 87 88 spv_operand_desc_t needle = {"", value, 0, nullptr, 0, nullptr, {}, ~0u}; 89 90 auto comp = [](const spv_operand_desc_t& lhs, const spv_operand_desc_t& rhs) { 91 return lhs.value < rhs.value; 92 }; 93 94 for (uint64_t typeIndex = 0; typeIndex < table->count; ++typeIndex) { 95 const auto& group = table->types[typeIndex]; 96 if (type != group.type) continue; 97 98 const auto beg = group.entries; 99 const auto end = group.entries + group.count; 100 101 // We need to loop here because there can exist multiple symbols for the 102 // same operand value, and they can be introduced in different target 103 // environments, which means they can have different minimal version 104 // requirements. For example, SubgroupEqMaskKHR can exist in any SPIR-V 105 // version as long as the SPV_KHR_shader_ballot extension is there; but 106 // starting from SPIR-V 1.3, SubgroupEqMask, which has the same numeric 107 // value as SubgroupEqMaskKHR, is available in core SPIR-V without extension 108 // requirements. 109 // Assumes the underlying table is already sorted ascendingly according to 110 // opcode value. 111 for (auto it = std::lower_bound(beg, end, needle, comp); 112 it != end && it->value == value; ++it) { 113 // We consider the current operand as available as long as 114 // 1. The target environment satisfies the minimal requirement of the 115 // operand; or 116 // 2. There is at least one extension enabling this operand; or 117 // 3. There is at least one capability enabling this operand. 118 // 119 // Note that the second rule assumes the extension enabling this operand 120 // is indeed requested in the SPIR-V code; checking that should be 121 // validator's work. 122 if (spvVersionForTargetEnv(env) >= it->minVersion || 123 it->numExtensions > 0u || it->numCapabilities > 0u) { 124 *pEntry = it; 125 return SPV_SUCCESS; 126 } 127 } 128 } 129 130 return SPV_ERROR_INVALID_LOOKUP; 131 } 132 133 const char* spvOperandTypeStr(spv_operand_type_t type) { 134 switch (type) { 135 case SPV_OPERAND_TYPE_ID: 136 case SPV_OPERAND_TYPE_OPTIONAL_ID: 137 return "ID"; 138 case SPV_OPERAND_TYPE_TYPE_ID: 139 return "type ID"; 140 case SPV_OPERAND_TYPE_RESULT_ID: 141 return "result ID"; 142 case SPV_OPERAND_TYPE_LITERAL_INTEGER: 143 case SPV_OPERAND_TYPE_OPTIONAL_LITERAL_INTEGER: 144 case SPV_OPERAND_TYPE_OPTIONAL_LITERAL_NUMBER: 145 return "literal number"; 146 case SPV_OPERAND_TYPE_OPTIONAL_TYPED_LITERAL_INTEGER: 147 return "possibly multi-word literal integer"; 148 case SPV_OPERAND_TYPE_TYPED_LITERAL_NUMBER: 149 return "possibly multi-word literal number"; 150 case SPV_OPERAND_TYPE_EXTENSION_INSTRUCTION_NUMBER: 151 return "extension instruction number"; 152 case SPV_OPERAND_TYPE_SPEC_CONSTANT_OP_NUMBER: 153 return "OpSpecConstantOp opcode"; 154 case SPV_OPERAND_TYPE_LITERAL_STRING: 155 case SPV_OPERAND_TYPE_OPTIONAL_LITERAL_STRING: 156 return "literal string"; 157 case SPV_OPERAND_TYPE_SOURCE_LANGUAGE: 158 return "source language"; 159 case SPV_OPERAND_TYPE_EXECUTION_MODEL: 160 return "execution model"; 161 case SPV_OPERAND_TYPE_ADDRESSING_MODEL: 162 return "addressing model"; 163 case SPV_OPERAND_TYPE_MEMORY_MODEL: 164 return "memory model"; 165 case SPV_OPERAND_TYPE_EXECUTION_MODE: 166 return "execution mode"; 167 case SPV_OPERAND_TYPE_STORAGE_CLASS: 168 return "storage class"; 169 case SPV_OPERAND_TYPE_DIMENSIONALITY: 170 return "dimensionality"; 171 case SPV_OPERAND_TYPE_SAMPLER_ADDRESSING_MODE: 172 return "sampler addressing mode"; 173 case SPV_OPERAND_TYPE_SAMPLER_FILTER_MODE: 174 return "sampler filter mode"; 175 case SPV_OPERAND_TYPE_SAMPLER_IMAGE_FORMAT: 176 return "image format"; 177 case SPV_OPERAND_TYPE_FP_FAST_MATH_MODE: 178 return "floating-point fast math mode"; 179 case SPV_OPERAND_TYPE_FP_ROUNDING_MODE: 180 return "floating-point rounding mode"; 181 case SPV_OPERAND_TYPE_LINKAGE_TYPE: 182 return "linkage type"; 183 case SPV_OPERAND_TYPE_ACCESS_QUALIFIER: 184 case SPV_OPERAND_TYPE_OPTIONAL_ACCESS_QUALIFIER: 185 return "access qualifier"; 186 case SPV_OPERAND_TYPE_FUNCTION_PARAMETER_ATTRIBUTE: 187 return "function parameter attribute"; 188 case SPV_OPERAND_TYPE_DECORATION: 189 return "decoration"; 190 case SPV_OPERAND_TYPE_BUILT_IN: 191 return "built-in"; 192 case SPV_OPERAND_TYPE_SELECTION_CONTROL: 193 return "selection control"; 194 case SPV_OPERAND_TYPE_LOOP_CONTROL: 195 return "loop control"; 196 case SPV_OPERAND_TYPE_FUNCTION_CONTROL: 197 return "function control"; 198 case SPV_OPERAND_TYPE_MEMORY_SEMANTICS_ID: 199 return "memory semantics ID"; 200 case SPV_OPERAND_TYPE_MEMORY_ACCESS: 201 case SPV_OPERAND_TYPE_OPTIONAL_MEMORY_ACCESS: 202 return "memory access"; 203 case SPV_OPERAND_TYPE_SCOPE_ID: 204 return "scope ID"; 205 case SPV_OPERAND_TYPE_GROUP_OPERATION: 206 return "group operation"; 207 case SPV_OPERAND_TYPE_KERNEL_ENQ_FLAGS: 208 return "kernel enqeue flags"; 209 case SPV_OPERAND_TYPE_KERNEL_PROFILING_INFO: 210 return "kernel profiling info"; 211 case SPV_OPERAND_TYPE_CAPABILITY: 212 return "capability"; 213 case SPV_OPERAND_TYPE_IMAGE: 214 case SPV_OPERAND_TYPE_OPTIONAL_IMAGE: 215 return "image"; 216 case SPV_OPERAND_TYPE_OPTIONAL_CIV: 217 return "context-insensitive value"; 218 case SPV_OPERAND_TYPE_DEBUG_INFO_FLAGS: 219 return "debug info flags"; 220 case SPV_OPERAND_TYPE_DEBUG_BASE_TYPE_ATTRIBUTE_ENCODING: 221 return "debug base type encoding"; 222 case SPV_OPERAND_TYPE_DEBUG_COMPOSITE_TYPE: 223 return "debug composite type"; 224 case SPV_OPERAND_TYPE_DEBUG_TYPE_QUALIFIER: 225 return "debug type qualifier"; 226 case SPV_OPERAND_TYPE_DEBUG_OPERATION: 227 return "debug operation"; 228 229 // The next values are for values returned from an instruction, not actually 230 // an operand. So the specific strings don't matter. But let's add them 231 // for completeness and ease of testing. 232 case SPV_OPERAND_TYPE_IMAGE_CHANNEL_ORDER: 233 return "image channel order"; 234 case SPV_OPERAND_TYPE_IMAGE_CHANNEL_DATA_TYPE: 235 return "image channel data type"; 236 237 case SPV_OPERAND_TYPE_NONE: 238 return "NONE"; 239 default: 240 assert(0 && "Unhandled operand type!"); 241 break; 242 } 243 return "unknown"; 244 } 245 246 void spvPushOperandTypes(const spv_operand_type_t* types, 247 spv_operand_pattern_t* pattern) { 248 const spv_operand_type_t* endTypes; 249 for (endTypes = types; *endTypes != SPV_OPERAND_TYPE_NONE; ++endTypes) { 250 } 251 252 while (endTypes-- != types) { 253 pattern->push_back(*endTypes); 254 } 255 } 256 257 void spvPushOperandTypesForMask(spv_target_env env, 258 const spv_operand_table operandTable, 259 const spv_operand_type_t type, 260 const uint32_t mask, 261 spv_operand_pattern_t* pattern) { 262 // Scan from highest bits to lowest bits because we will append in LIFO 263 // fashion, and we need the operands for lower order bits to be consumed first 264 for (uint32_t candidate_bit = (1u << 31u); candidate_bit; 265 candidate_bit >>= 1) { 266 if (candidate_bit & mask) { 267 spv_operand_desc entry = nullptr; 268 if (SPV_SUCCESS == spvOperandTableValueLookup(env, operandTable, type, 269 candidate_bit, &entry)) { 270 spvPushOperandTypes(entry->operandTypes, pattern); 271 } 272 } 273 } 274 } 275 276 bool spvOperandIsConcrete(spv_operand_type_t type) { 277 if (spvIsIdType(type) || spvOperandIsConcreteMask(type)) { 278 return true; 279 } 280 switch (type) { 281 case SPV_OPERAND_TYPE_LITERAL_INTEGER: 282 case SPV_OPERAND_TYPE_EXTENSION_INSTRUCTION_NUMBER: 283 case SPV_OPERAND_TYPE_SPEC_CONSTANT_OP_NUMBER: 284 case SPV_OPERAND_TYPE_TYPED_LITERAL_NUMBER: 285 case SPV_OPERAND_TYPE_LITERAL_STRING: 286 case SPV_OPERAND_TYPE_SOURCE_LANGUAGE: 287 case SPV_OPERAND_TYPE_EXECUTION_MODEL: 288 case SPV_OPERAND_TYPE_ADDRESSING_MODEL: 289 case SPV_OPERAND_TYPE_MEMORY_MODEL: 290 case SPV_OPERAND_TYPE_EXECUTION_MODE: 291 case SPV_OPERAND_TYPE_STORAGE_CLASS: 292 case SPV_OPERAND_TYPE_DIMENSIONALITY: 293 case SPV_OPERAND_TYPE_SAMPLER_ADDRESSING_MODE: 294 case SPV_OPERAND_TYPE_SAMPLER_FILTER_MODE: 295 case SPV_OPERAND_TYPE_SAMPLER_IMAGE_FORMAT: 296 case SPV_OPERAND_TYPE_IMAGE_CHANNEL_ORDER: 297 case SPV_OPERAND_TYPE_IMAGE_CHANNEL_DATA_TYPE: 298 case SPV_OPERAND_TYPE_FP_ROUNDING_MODE: 299 case SPV_OPERAND_TYPE_LINKAGE_TYPE: 300 case SPV_OPERAND_TYPE_ACCESS_QUALIFIER: 301 case SPV_OPERAND_TYPE_FUNCTION_PARAMETER_ATTRIBUTE: 302 case SPV_OPERAND_TYPE_DECORATION: 303 case SPV_OPERAND_TYPE_BUILT_IN: 304 case SPV_OPERAND_TYPE_GROUP_OPERATION: 305 case SPV_OPERAND_TYPE_KERNEL_ENQ_FLAGS: 306 case SPV_OPERAND_TYPE_KERNEL_PROFILING_INFO: 307 case SPV_OPERAND_TYPE_CAPABILITY: 308 case SPV_OPERAND_TYPE_DEBUG_BASE_TYPE_ATTRIBUTE_ENCODING: 309 case SPV_OPERAND_TYPE_DEBUG_COMPOSITE_TYPE: 310 case SPV_OPERAND_TYPE_DEBUG_TYPE_QUALIFIER: 311 case SPV_OPERAND_TYPE_DEBUG_OPERATION: 312 return true; 313 default: 314 break; 315 } 316 return false; 317 } 318 319 bool spvOperandIsConcreteMask(spv_operand_type_t type) { 320 switch (type) { 321 case SPV_OPERAND_TYPE_IMAGE: 322 case SPV_OPERAND_TYPE_FP_FAST_MATH_MODE: 323 case SPV_OPERAND_TYPE_SELECTION_CONTROL: 324 case SPV_OPERAND_TYPE_LOOP_CONTROL: 325 case SPV_OPERAND_TYPE_FUNCTION_CONTROL: 326 case SPV_OPERAND_TYPE_MEMORY_ACCESS: 327 case SPV_OPERAND_TYPE_DEBUG_INFO_FLAGS: 328 return true; 329 default: 330 break; 331 } 332 return false; 333 } 334 335 bool spvOperandIsOptional(spv_operand_type_t type) { 336 return SPV_OPERAND_TYPE_FIRST_OPTIONAL_TYPE <= type && 337 type <= SPV_OPERAND_TYPE_LAST_OPTIONAL_TYPE; 338 } 339 340 bool spvOperandIsVariable(spv_operand_type_t type) { 341 return SPV_OPERAND_TYPE_FIRST_VARIABLE_TYPE <= type && 342 type <= SPV_OPERAND_TYPE_LAST_VARIABLE_TYPE; 343 } 344 345 bool spvExpandOperandSequenceOnce(spv_operand_type_t type, 346 spv_operand_pattern_t* pattern) { 347 switch (type) { 348 case SPV_OPERAND_TYPE_VARIABLE_ID: 349 pattern->push_back(type); 350 pattern->push_back(SPV_OPERAND_TYPE_OPTIONAL_ID); 351 return true; 352 case SPV_OPERAND_TYPE_VARIABLE_LITERAL_INTEGER: 353 pattern->push_back(type); 354 pattern->push_back(SPV_OPERAND_TYPE_OPTIONAL_LITERAL_INTEGER); 355 return true; 356 case SPV_OPERAND_TYPE_VARIABLE_LITERAL_INTEGER_ID: 357 // Represents Zero or more (Literal number, Id) pairs, 358 // where the literal number must be a scalar integer. 359 pattern->push_back(type); 360 pattern->push_back(SPV_OPERAND_TYPE_ID); 361 pattern->push_back(SPV_OPERAND_TYPE_OPTIONAL_TYPED_LITERAL_INTEGER); 362 return true; 363 case SPV_OPERAND_TYPE_VARIABLE_ID_LITERAL_INTEGER: 364 // Represents Zero or more (Id, Literal number) pairs. 365 pattern->push_back(type); 366 pattern->push_back(SPV_OPERAND_TYPE_LITERAL_INTEGER); 367 pattern->push_back(SPV_OPERAND_TYPE_OPTIONAL_ID); 368 return true; 369 default: 370 break; 371 } 372 return false; 373 } 374 375 spv_operand_type_t spvTakeFirstMatchableOperand( 376 spv_operand_pattern_t* pattern) { 377 assert(!pattern->empty()); 378 spv_operand_type_t result; 379 do { 380 result = pattern->back(); 381 pattern->pop_back(); 382 } while (spvExpandOperandSequenceOnce(result, pattern)); 383 return result; 384 } 385 386 spv_operand_pattern_t spvAlternatePatternFollowingImmediate( 387 const spv_operand_pattern_t& pattern) { 388 auto it = 389 std::find(pattern.crbegin(), pattern.crend(), SPV_OPERAND_TYPE_RESULT_ID); 390 if (it != pattern.crend()) { 391 spv_operand_pattern_t alternatePattern(it - pattern.crbegin() + 2, 392 SPV_OPERAND_TYPE_OPTIONAL_CIV); 393 alternatePattern[1] = SPV_OPERAND_TYPE_RESULT_ID; 394 return alternatePattern; 395 } 396 397 // No result-id found, so just expect CIVs. 398 return {SPV_OPERAND_TYPE_OPTIONAL_CIV}; 399 } 400 401 bool spvIsIdType(spv_operand_type_t type) { 402 switch (type) { 403 case SPV_OPERAND_TYPE_ID: 404 case SPV_OPERAND_TYPE_TYPE_ID: 405 case SPV_OPERAND_TYPE_RESULT_ID: 406 case SPV_OPERAND_TYPE_MEMORY_SEMANTICS_ID: 407 case SPV_OPERAND_TYPE_SCOPE_ID: 408 return true; 409 default: 410 return false; 411 } 412 } 413 414 bool spvIsInIdType(spv_operand_type_t type) { 415 if (!spvIsIdType(type)) { 416 // If it is not an ID it cannot be an input ID. 417 return false; 418 } 419 switch (type) { 420 // Blacklist non-input IDs. 421 case SPV_OPERAND_TYPE_TYPE_ID: 422 case SPV_OPERAND_TYPE_RESULT_ID: 423 return false; 424 default: 425 return true; 426 } 427 } 428 429 std::function<bool(unsigned)> spvOperandCanBeForwardDeclaredFunction( 430 SpvOp opcode) { 431 std::function<bool(unsigned index)> out; 432 switch (opcode) { 433 case SpvOpExecutionMode: 434 case SpvOpExecutionModeId: 435 case SpvOpEntryPoint: 436 case SpvOpName: 437 case SpvOpMemberName: 438 case SpvOpSelectionMerge: 439 case SpvOpDecorate: 440 case SpvOpMemberDecorate: 441 case SpvOpDecorateId: 442 case SpvOpDecorateStringGOOGLE: 443 case SpvOpMemberDecorateStringGOOGLE: 444 case SpvOpTypeStruct: 445 case SpvOpBranch: 446 case SpvOpLoopMerge: 447 out = [](unsigned) { return true; }; 448 break; 449 case SpvOpGroupDecorate: 450 case SpvOpGroupMemberDecorate: 451 case SpvOpBranchConditional: 452 case SpvOpSwitch: 453 out = [](unsigned index) { return index != 0; }; 454 break; 455 456 case SpvOpFunctionCall: 457 // The Function parameter. 458 out = [](unsigned index) { return index == 2; }; 459 break; 460 461 case SpvOpPhi: 462 out = [](unsigned index) { return index > 1; }; 463 break; 464 465 case SpvOpEnqueueKernel: 466 // The Invoke parameter. 467 out = [](unsigned index) { return index == 8; }; 468 break; 469 470 case SpvOpGetKernelNDrangeSubGroupCount: 471 case SpvOpGetKernelNDrangeMaxSubGroupSize: 472 // The Invoke parameter. 473 out = [](unsigned index) { return index == 3; }; 474 break; 475 476 case SpvOpGetKernelWorkGroupSize: 477 case SpvOpGetKernelPreferredWorkGroupSizeMultiple: 478 // The Invoke parameter. 479 out = [](unsigned index) { return index == 2; }; 480 break; 481 case SpvOpTypeForwardPointer: 482 out = [](unsigned index) { return index == 0; }; 483 break; 484 case SpvOpTypeArray: 485 out = [](unsigned index) { return index == 1; }; 486 break; 487 default: 488 out = [](unsigned) { return false; }; 489 break; 490 } 491 return out; 492 } 493