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 "operand.h" 28 29 #include <assert.h> 30 #include <string.h> 31 32 #include "macro.h" 33 34 // Pull in operand info tables automatically generated from JSON grammar. 35 namespace v1_0 { 36 #include "operand.kinds-1.0.inc" 37 } // namespace v1_0 38 namespace v1_1 { 39 #include "operand.kinds-1.1.inc" 40 } // namespace v1_1 41 42 spv_result_t spvOperandTableGet(spv_operand_table* pOperandTable, 43 spv_target_env env) { 44 if (!pOperandTable) return SPV_ERROR_INVALID_POINTER; 45 46 static const spv_operand_table_t table_1_0 = { 47 ARRAY_SIZE(v1_0::pygen_variable_OperandInfoTable), 48 v1_0::pygen_variable_OperandInfoTable}; 49 static const spv_operand_table_t table_1_1 = { 50 ARRAY_SIZE(v1_1::pygen_variable_OperandInfoTable), 51 v1_1::pygen_variable_OperandInfoTable}; 52 53 switch (env) { 54 case SPV_ENV_UNIVERSAL_1_0: 55 case SPV_ENV_VULKAN_1_0: 56 *pOperandTable = &table_1_0; 57 return SPV_SUCCESS; 58 case SPV_ENV_UNIVERSAL_1_1: 59 *pOperandTable = &table_1_1; 60 return SPV_SUCCESS; 61 } 62 assert(0 && "Unknown spv_target_env in spvOperandTableGet()"); 63 return SPV_ERROR_INVALID_TABLE; 64 } 65 66 #undef ARRAY_SIZE 67 68 spv_result_t spvOperandTableNameLookup(const spv_operand_table table, 69 const spv_operand_type_t type, 70 const char* name, 71 const size_t nameLength, 72 spv_operand_desc* pEntry) { 73 if (!table) return SPV_ERROR_INVALID_TABLE; 74 if (!name || !pEntry) return SPV_ERROR_INVALID_POINTER; 75 76 for (uint64_t typeIndex = 0; typeIndex < table->count; ++typeIndex) { 77 const auto& group = table->types[typeIndex]; 78 if (type != group.type) continue; 79 for (uint64_t index = 0; index < group.count; ++index) { 80 const auto& entry = group.entries[index]; 81 if (nameLength == strlen(entry.name) && 82 !strncmp(entry.name, name, nameLength)) { 83 *pEntry = &entry; 84 return SPV_SUCCESS; 85 } 86 } 87 } 88 89 return SPV_ERROR_INVALID_LOOKUP; 90 } 91 92 spv_result_t spvOperandTableValueLookup(const spv_operand_table table, 93 const spv_operand_type_t type, 94 const uint32_t value, 95 spv_operand_desc* pEntry) { 96 if (!table) return SPV_ERROR_INVALID_TABLE; 97 if (!pEntry) return SPV_ERROR_INVALID_POINTER; 98 99 for (uint64_t typeIndex = 0; typeIndex < table->count; ++typeIndex) { 100 const auto& group = table->types[typeIndex]; 101 if (type != group.type) continue; 102 for (uint64_t index = 0; index < group.count; ++index) { 103 const auto& entry = group.entries[index]; 104 if (value == entry.value) { 105 *pEntry = &entry; 106 return SPV_SUCCESS; 107 } 108 } 109 } 110 111 return SPV_ERROR_INVALID_LOOKUP; 112 } 113 114 const char* spvOperandTypeStr(spv_operand_type_t type) { 115 switch (type) { 116 case SPV_OPERAND_TYPE_ID: 117 case SPV_OPERAND_TYPE_OPTIONAL_ID: 118 return "ID"; 119 case SPV_OPERAND_TYPE_TYPE_ID: 120 return "type ID"; 121 case SPV_OPERAND_TYPE_RESULT_ID: 122 return "result ID"; 123 case SPV_OPERAND_TYPE_LITERAL_INTEGER: 124 case SPV_OPERAND_TYPE_OPTIONAL_LITERAL_INTEGER: 125 case SPV_OPERAND_TYPE_OPTIONAL_LITERAL_NUMBER: 126 return "literal number"; 127 case SPV_OPERAND_TYPE_OPTIONAL_TYPED_LITERAL_INTEGER: 128 return "possibly multi-word literal integer"; 129 case SPV_OPERAND_TYPE_TYPED_LITERAL_NUMBER: 130 return "possibly multi-word literal number"; 131 case SPV_OPERAND_TYPE_EXTENSION_INSTRUCTION_NUMBER: 132 return "extension instruction number"; 133 case SPV_OPERAND_TYPE_SPEC_CONSTANT_OP_NUMBER: 134 return "OpSpecConstantOp opcode"; 135 case SPV_OPERAND_TYPE_LITERAL_STRING: 136 case SPV_OPERAND_TYPE_OPTIONAL_LITERAL_STRING: 137 return "literal string"; 138 case SPV_OPERAND_TYPE_SOURCE_LANGUAGE: 139 return "source language"; 140 case SPV_OPERAND_TYPE_EXECUTION_MODEL: 141 return "execution model"; 142 case SPV_OPERAND_TYPE_ADDRESSING_MODEL: 143 return "addressing model"; 144 case SPV_OPERAND_TYPE_MEMORY_MODEL: 145 return "memory model"; 146 case SPV_OPERAND_TYPE_EXECUTION_MODE: 147 return "execution mode"; 148 case SPV_OPERAND_TYPE_STORAGE_CLASS: 149 return "storage class"; 150 case SPV_OPERAND_TYPE_DIMENSIONALITY: 151 return "dimensionality"; 152 case SPV_OPERAND_TYPE_SAMPLER_ADDRESSING_MODE: 153 return "sampler addressing mode"; 154 case SPV_OPERAND_TYPE_SAMPLER_FILTER_MODE: 155 return "sampler filter mode"; 156 case SPV_OPERAND_TYPE_SAMPLER_IMAGE_FORMAT: 157 return "image format"; 158 case SPV_OPERAND_TYPE_FP_FAST_MATH_MODE: 159 return "floating-point fast math mode"; 160 case SPV_OPERAND_TYPE_FP_ROUNDING_MODE: 161 return "floating-point rounding mode"; 162 case SPV_OPERAND_TYPE_LINKAGE_TYPE: 163 return "linkage type"; 164 case SPV_OPERAND_TYPE_ACCESS_QUALIFIER: 165 case SPV_OPERAND_TYPE_OPTIONAL_ACCESS_QUALIFIER: 166 return "access qualifier"; 167 case SPV_OPERAND_TYPE_FUNCTION_PARAMETER_ATTRIBUTE: 168 return "function parameter attribute"; 169 case SPV_OPERAND_TYPE_DECORATION: 170 return "decoration"; 171 case SPV_OPERAND_TYPE_BUILT_IN: 172 return "built-in"; 173 case SPV_OPERAND_TYPE_SELECTION_CONTROL: 174 return "selection control"; 175 case SPV_OPERAND_TYPE_LOOP_CONTROL: 176 return "loop control"; 177 case SPV_OPERAND_TYPE_FUNCTION_CONTROL: 178 return "function control"; 179 case SPV_OPERAND_TYPE_MEMORY_SEMANTICS_ID: 180 return "memory semantics ID"; 181 case SPV_OPERAND_TYPE_MEMORY_ACCESS: 182 case SPV_OPERAND_TYPE_OPTIONAL_MEMORY_ACCESS: 183 return "memory access"; 184 case SPV_OPERAND_TYPE_SCOPE_ID: 185 return "scope ID"; 186 case SPV_OPERAND_TYPE_GROUP_OPERATION: 187 return "group operation"; 188 case SPV_OPERAND_TYPE_KERNEL_ENQ_FLAGS: 189 return "kernel enqeue flags"; 190 case SPV_OPERAND_TYPE_KERNEL_PROFILING_INFO: 191 return "kernel profiling info"; 192 case SPV_OPERAND_TYPE_CAPABILITY: 193 return "capability"; 194 case SPV_OPERAND_TYPE_IMAGE: 195 case SPV_OPERAND_TYPE_OPTIONAL_IMAGE: 196 return "image"; 197 case SPV_OPERAND_TYPE_OPTIONAL_CIV: 198 return "context-insensitive value"; 199 200 // The next values are for values returned from an instruction, not actually 201 // an operand. So the specific strings don't matter. But let's add them 202 // for completeness and ease of testing. 203 case SPV_OPERAND_TYPE_IMAGE_CHANNEL_ORDER: 204 return "image channel order"; 205 case SPV_OPERAND_TYPE_IMAGE_CHANNEL_DATA_TYPE: 206 return "image channel data type"; 207 208 case SPV_OPERAND_TYPE_NONE: 209 return "NONE"; 210 default: 211 assert(0 && "Unhandled operand type!"); 212 break; 213 } 214 return "unknown"; 215 } 216 217 void spvPrependOperandTypes(const spv_operand_type_t* types, 218 spv_operand_pattern_t* pattern) { 219 const spv_operand_type_t* endTypes; 220 for (endTypes = types; *endTypes != SPV_OPERAND_TYPE_NONE; ++endTypes) 221 ; 222 pattern->insert(pattern->begin(), types, endTypes); 223 } 224 225 void spvPrependOperandTypesForMask(const spv_operand_table operandTable, 226 const spv_operand_type_t type, 227 const uint32_t mask, 228 spv_operand_pattern_t* pattern) { 229 // Scan from highest bits to lowest bits because we will prepend in LIFO 230 // fashion, and we need the operands for lower order bits to appear first. 231 for (uint32_t candidate_bit = (1u << 31u); candidate_bit; candidate_bit >>= 1) { 232 if (candidate_bit & mask) { 233 spv_operand_desc entry = nullptr; 234 if (SPV_SUCCESS == spvOperandTableValueLookup(operandTable, type, 235 candidate_bit, &entry)) { 236 spvPrependOperandTypes(entry->operandTypes, pattern); 237 } 238 } 239 } 240 } 241 242 bool spvOperandIsConcreteMask(spv_operand_type_t type) { 243 return SPV_OPERAND_TYPE_FIRST_CONCRETE_MASK_TYPE <= type && 244 type <= SPV_OPERAND_TYPE_LAST_CONCRETE_MASK_TYPE; 245 } 246 247 bool spvOperandIsOptional(spv_operand_type_t type) { 248 return SPV_OPERAND_TYPE_FIRST_OPTIONAL_TYPE <= type && 249 type <= SPV_OPERAND_TYPE_LAST_OPTIONAL_TYPE; 250 } 251 252 bool spvOperandIsVariable(spv_operand_type_t type) { 253 return SPV_OPERAND_TYPE_FIRST_VARIABLE_TYPE <= type && 254 type <= SPV_OPERAND_TYPE_LAST_VARIABLE_TYPE; 255 } 256 257 bool spvExpandOperandSequenceOnce(spv_operand_type_t type, 258 spv_operand_pattern_t* pattern) { 259 switch (type) { 260 case SPV_OPERAND_TYPE_VARIABLE_ID: 261 pattern->insert(pattern->begin(), {SPV_OPERAND_TYPE_OPTIONAL_ID, type}); 262 return true; 263 case SPV_OPERAND_TYPE_VARIABLE_LITERAL_INTEGER: 264 pattern->insert(pattern->begin(), 265 {SPV_OPERAND_TYPE_OPTIONAL_LITERAL_INTEGER, type}); 266 return true; 267 case SPV_OPERAND_TYPE_VARIABLE_LITERAL_INTEGER_ID: 268 // Represents Zero or more (Literal number, Id) pairs, 269 // where the literal number must be a scalar integer. 270 pattern->insert(pattern->begin(), 271 {SPV_OPERAND_TYPE_OPTIONAL_TYPED_LITERAL_INTEGER, 272 SPV_OPERAND_TYPE_ID, type}); 273 return true; 274 case SPV_OPERAND_TYPE_VARIABLE_ID_LITERAL_INTEGER: 275 // Represents Zero or more (Id, Literal number) pairs. 276 pattern->insert(pattern->begin(), 277 {SPV_OPERAND_TYPE_OPTIONAL_ID, 278 SPV_OPERAND_TYPE_LITERAL_INTEGER, type}); 279 return true; 280 default: 281 break; 282 } 283 return false; 284 } 285 286 spv_operand_type_t spvTakeFirstMatchableOperand( 287 spv_operand_pattern_t* pattern) { 288 assert(!pattern->empty()); 289 spv_operand_type_t result; 290 do { 291 result = pattern->front(); 292 pattern->pop_front(); 293 } while (spvExpandOperandSequenceOnce(result, pattern)); 294 return result; 295 } 296 297 spv_operand_pattern_t spvAlternatePatternFollowingImmediate( 298 const spv_operand_pattern_t& pattern) { 299 spv_operand_pattern_t alternatePattern; 300 for (const auto& operand : pattern) { 301 if (operand == SPV_OPERAND_TYPE_RESULT_ID) { 302 alternatePattern.push_back(operand); 303 alternatePattern.push_back(SPV_OPERAND_TYPE_OPTIONAL_CIV); 304 return alternatePattern; 305 } 306 alternatePattern.push_back(SPV_OPERAND_TYPE_OPTIONAL_CIV); 307 } 308 // No result-id found, so just expect CIVs. 309 return {SPV_OPERAND_TYPE_OPTIONAL_CIV}; 310 } 311 312 bool spvIsIdType(spv_operand_type_t type) { 313 switch (type) { 314 case SPV_OPERAND_TYPE_ID: 315 case SPV_OPERAND_TYPE_TYPE_ID: 316 case SPV_OPERAND_TYPE_RESULT_ID: 317 case SPV_OPERAND_TYPE_MEMORY_SEMANTICS_ID: 318 case SPV_OPERAND_TYPE_SCOPE_ID: 319 return true; 320 default: 321 return false; 322 } 323 } 324