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 "opcode.h" 28 29 #include <assert.h> 30 #include <string.h> 31 32 #include <cstdlib> 33 34 #include "instruction.h" 35 #include "macro.h" 36 #include "spirv-tools/libspirv.h" 37 #include "spirv_constant.h" 38 #include "spirv_endian.h" 39 40 namespace { 41 42 // Descriptions of each opcode. Each entry describes the format of the 43 // instruction that follows a particular opcode. 44 const spv_opcode_desc_t opcodeTableEntries_1_0[] = { 45 #include "core.insts-1.0.inc" 46 }; 47 const spv_opcode_desc_t opcodeTableEntries_1_1[] = { 48 #include "core.insts-1.1.inc" 49 }; 50 51 } // anonymous namespace 52 53 const char* spvGeneratorStr(uint32_t generator) { 54 switch (generator) { 55 case SPV_GENERATOR_KHRONOS: 56 return "Khronos"; 57 case SPV_GENERATOR_LUNARG: 58 return "LunarG"; 59 case SPV_GENERATOR_VALVE: 60 return "Valve"; 61 case SPV_GENERATOR_CODEPLAY: 62 return "Codeplay Software Ltd."; 63 case SPV_GENERATOR_NVIDIA: 64 return "NVIDIA"; 65 case SPV_GENERATOR_ARM: 66 return "ARM"; 67 case SPV_GENERATOR_KHRONOS_LLVM_TRANSLATOR: 68 return "Khronos LLVM/SPIR-V Translator"; 69 case SPV_GENERATOR_KHRONOS_ASSEMBLER: 70 return "Khronos SPIR-V Tools Assembler"; 71 case SPV_GENERATOR_KHRONOS_GLSLANG: 72 return "Khronos Glslang Reference Front End"; 73 default: 74 return "Unknown"; 75 } 76 } 77 78 uint32_t spvOpcodeMake(uint16_t wordCount, SpvOp opcode) { 79 return ((uint32_t)opcode) | (((uint32_t)wordCount) << 16); 80 } 81 82 void spvOpcodeSplit(const uint32_t word, uint16_t* pWordCount, 83 uint16_t* pOpcode) { 84 if (pWordCount) { 85 *pWordCount = (uint16_t)((0xffff0000 & word) >> 16); 86 } 87 if (pOpcode) { 88 *pOpcode = 0x0000ffff & word; 89 } 90 } 91 92 spv_result_t spvOpcodeTableGet(spv_opcode_table* pInstTable, 93 spv_target_env env) { 94 if (!pInstTable) return SPV_ERROR_INVALID_POINTER; 95 96 static const spv_opcode_table_t table_1_0 = { 97 ARRAY_SIZE(opcodeTableEntries_1_0), opcodeTableEntries_1_0}; 98 static const spv_opcode_table_t table_1_1 = { 99 ARRAY_SIZE(opcodeTableEntries_1_1), opcodeTableEntries_1_1}; 100 101 switch (env) { 102 case SPV_ENV_UNIVERSAL_1_0: 103 case SPV_ENV_VULKAN_1_0: 104 *pInstTable = &table_1_0; 105 return SPV_SUCCESS; 106 case SPV_ENV_UNIVERSAL_1_1: 107 *pInstTable = &table_1_1; 108 return SPV_SUCCESS; 109 } 110 assert(0 && "Unknown spv_target_env in spvOpcodeTableGet()"); 111 return SPV_ERROR_INVALID_TABLE; 112 } 113 114 spv_result_t spvOpcodeTableNameLookup(const spv_opcode_table table, 115 const char* name, 116 spv_opcode_desc* pEntry) { 117 if (!name || !pEntry) return SPV_ERROR_INVALID_POINTER; 118 if (!table) return SPV_ERROR_INVALID_TABLE; 119 120 // TODO: This lookup of the Opcode table is suboptimal! Binary sort would be 121 // preferable but the table requires sorting on the Opcode name, but it's 122 // static 123 // const initialized and matches the order of the spec. 124 const size_t nameLength = strlen(name); 125 for (uint64_t opcodeIndex = 0; opcodeIndex < table->count; ++opcodeIndex) { 126 if (nameLength == strlen(table->entries[opcodeIndex].name) && 127 !strncmp(name, table->entries[opcodeIndex].name, nameLength)) { 128 // NOTE: Found out Opcode! 129 *pEntry = &table->entries[opcodeIndex]; 130 return SPV_SUCCESS; 131 } 132 } 133 134 return SPV_ERROR_INVALID_LOOKUP; 135 } 136 137 spv_result_t spvOpcodeTableValueLookup(const spv_opcode_table table, 138 const SpvOp opcode, 139 spv_opcode_desc* pEntry) { 140 if (!table) return SPV_ERROR_INVALID_TABLE; 141 if (!pEntry) return SPV_ERROR_INVALID_POINTER; 142 143 // TODO: As above this lookup is not optimal. 144 for (uint64_t opcodeIndex = 0; opcodeIndex < table->count; ++opcodeIndex) { 145 if (opcode == table->entries[opcodeIndex].opcode) { 146 // NOTE: Found the Opcode! 147 *pEntry = &table->entries[opcodeIndex]; 148 return SPV_SUCCESS; 149 } 150 } 151 152 return SPV_ERROR_INVALID_LOOKUP; 153 } 154 155 int32_t spvOpcodeRequiresCapabilities(spv_opcode_desc entry) { 156 return entry->capabilities != 0; 157 } 158 159 void spvInstructionCopy(const uint32_t* words, const SpvOp opcode, 160 const uint16_t wordCount, const spv_endianness_t endian, 161 spv_instruction_t* pInst) { 162 pInst->opcode = opcode; 163 pInst->words.resize(wordCount); 164 for (uint16_t wordIndex = 0; wordIndex < wordCount; ++wordIndex) { 165 pInst->words[wordIndex] = spvFixWord(words[wordIndex], endian); 166 if (!wordIndex) { 167 uint16_t thisWordCount; 168 uint16_t thisOpcode; 169 spvOpcodeSplit(pInst->words[wordIndex], &thisWordCount, &thisOpcode); 170 assert(opcode == static_cast<SpvOp>(thisOpcode) && 171 wordCount == thisWordCount && "Endianness failed!"); 172 } 173 } 174 } 175 176 const char* spvOpcodeString(const SpvOp opcode) { 177 // Use the latest SPIR-V version, which should be backward-compatible with all 178 // previous ones. 179 for (uint32_t i = 0; i < ARRAY_SIZE(opcodeTableEntries_1_1); ++i) { 180 if (opcodeTableEntries_1_1[i].opcode == opcode) 181 return opcodeTableEntries_1_1[i].name; 182 } 183 assert(0 && "Unreachable!"); 184 return "unknown"; 185 } 186 187 int32_t spvOpcodeIsScalarType(const SpvOp opcode) { 188 switch (opcode) { 189 case SpvOpTypeInt: 190 case SpvOpTypeFloat: 191 case SpvOpTypeBool: 192 return true; 193 default: 194 return false; 195 } 196 } 197 198 int32_t spvOpcodeIsConstant(const SpvOp opcode) { 199 switch (opcode) { 200 case SpvOpConstantTrue: 201 case SpvOpConstantFalse: 202 case SpvOpConstant: 203 case SpvOpConstantComposite: 204 case SpvOpConstantSampler: 205 case SpvOpConstantNull: 206 case SpvOpSpecConstantTrue: 207 case SpvOpSpecConstantFalse: 208 case SpvOpSpecConstant: 209 case SpvOpSpecConstantComposite: 210 case SpvOpSpecConstantOp: 211 return true; 212 default: 213 return false; 214 } 215 } 216 217 int32_t spvOpcodeIsComposite(const SpvOp opcode) { 218 switch (opcode) { 219 case SpvOpTypeVector: 220 case SpvOpTypeMatrix: 221 case SpvOpTypeArray: 222 case SpvOpTypeStruct: 223 return true; 224 default: 225 return false; 226 } 227 } 228 229 int32_t spvOpcodeReturnsLogicalPointer(const SpvOp opcode) { 230 switch (opcode) { 231 case SpvOpVariable: 232 case SpvOpAccessChain: 233 case SpvOpInBoundsAccessChain: 234 case SpvOpFunctionParameter: 235 case SpvOpImageTexelPointer: 236 case SpvOpCopyObject: 237 return true; 238 default: 239 return false; 240 } 241 } 242 243 int32_t spvOpcodeGeneratesType(SpvOp op) { 244 switch (op) { 245 case SpvOpTypeVoid: 246 case SpvOpTypeBool: 247 case SpvOpTypeInt: 248 case SpvOpTypeFloat: 249 case SpvOpTypeVector: 250 case SpvOpTypeMatrix: 251 case SpvOpTypeImage: 252 case SpvOpTypeSampler: 253 case SpvOpTypeSampledImage: 254 case SpvOpTypeArray: 255 case SpvOpTypeRuntimeArray: 256 case SpvOpTypeStruct: 257 case SpvOpTypeOpaque: 258 case SpvOpTypePointer: 259 case SpvOpTypeFunction: 260 case SpvOpTypeEvent: 261 case SpvOpTypeDeviceEvent: 262 case SpvOpTypeReserveId: 263 case SpvOpTypeQueue: 264 case SpvOpTypePipe: 265 return true; 266 default: 267 // In particular, OpTypeForwardPointer does not generate a type, 268 // but declares a storage class for a pointer type generated 269 // by a different instruction. 270 break; 271 } 272 return 0; 273 } 274