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 "opcode.h" 16 17 #include <assert.h> 18 #include <string.h> 19 20 #include <algorithm> 21 #include <cstdlib> 22 23 #include "instruction.h" 24 #include "macro.h" 25 #include "spirv-tools/libspirv.h" 26 #include "spirv_constant.h" 27 #include "spirv_endian.h" 28 29 namespace { 30 31 // Descriptions of each opcode. Each entry describes the format of the 32 // instruction that follows a particular opcode. 33 const spv_opcode_desc_t opcodeTableEntries_1_0[] = { 34 #include "core.insts-1.0.inc" 35 }; 36 const spv_opcode_desc_t opcodeTableEntries_1_1[] = { 37 #include "core.insts-1.1.inc" 38 }; 39 const spv_opcode_desc_t opcodeTableEntries_1_2[] = { 40 #include "core.insts-1.2.inc" 41 }; 42 43 // Represents a vendor tool entry in the SPIR-V XML Regsitry. 44 struct VendorTool { 45 uint32_t value; 46 const char* vendor; 47 const char* tool; // Might be empty string. 48 const char* vendor_tool; // Combiantion of vendor and tool. 49 }; 50 51 const VendorTool vendor_tools[] = { 52 #include "generators.inc" 53 }; 54 55 } // anonymous namespace 56 57 // TODO(dneto): Move this to another file. It doesn't belong with opcode 58 // processing. 59 const char* spvGeneratorStr(uint32_t generator) { 60 auto where = std::find_if( 61 std::begin(vendor_tools), std::end(vendor_tools), 62 [generator](const VendorTool& vt) { return generator == vt.value; }); 63 if (where != std::end(vendor_tools)) return where->vendor_tool; 64 return "Unknown"; 65 } 66 67 uint32_t spvOpcodeMake(uint16_t wordCount, SpvOp opcode) { 68 return ((uint32_t)opcode) | (((uint32_t)wordCount) << 16); 69 } 70 71 void spvOpcodeSplit(const uint32_t word, uint16_t* pWordCount, 72 uint16_t* pOpcode) { 73 if (pWordCount) { 74 *pWordCount = (uint16_t)((0xffff0000 & word) >> 16); 75 } 76 if (pOpcode) { 77 *pOpcode = 0x0000ffff & word; 78 } 79 } 80 81 spv_result_t spvOpcodeTableGet(spv_opcode_table* pInstTable, 82 spv_target_env env) { 83 if (!pInstTable) return SPV_ERROR_INVALID_POINTER; 84 85 static const spv_opcode_table_t table_1_0 = { 86 ARRAY_SIZE(opcodeTableEntries_1_0), opcodeTableEntries_1_0}; 87 static const spv_opcode_table_t table_1_1 = { 88 ARRAY_SIZE(opcodeTableEntries_1_1), opcodeTableEntries_1_1}; 89 static const spv_opcode_table_t table_1_2 = { 90 ARRAY_SIZE(opcodeTableEntries_1_2), opcodeTableEntries_1_2}; 91 92 switch (env) { 93 case SPV_ENV_UNIVERSAL_1_0: 94 case SPV_ENV_VULKAN_1_0: 95 case SPV_ENV_OPENCL_2_1: 96 case SPV_ENV_OPENGL_4_0: 97 case SPV_ENV_OPENGL_4_1: 98 case SPV_ENV_OPENGL_4_2: 99 case SPV_ENV_OPENGL_4_3: 100 case SPV_ENV_OPENGL_4_5: 101 *pInstTable = &table_1_0; 102 return SPV_SUCCESS; 103 case SPV_ENV_UNIVERSAL_1_1: 104 *pInstTable = &table_1_1; 105 return SPV_SUCCESS; 106 case SPV_ENV_UNIVERSAL_1_2: 107 case SPV_ENV_OPENCL_2_2: 108 *pInstTable = &table_1_2; 109 return SPV_SUCCESS; 110 } 111 assert(0 && "Unknown spv_target_env in spvOpcodeTableGet()"); 112 return SPV_ERROR_INVALID_TABLE; 113 } 114 115 spv_result_t spvOpcodeTableNameLookup(const spv_opcode_table table, 116 const char* name, 117 spv_opcode_desc* pEntry) { 118 if (!name || !pEntry) return SPV_ERROR_INVALID_POINTER; 119 if (!table) return SPV_ERROR_INVALID_TABLE; 120 121 // TODO: This lookup of the Opcode table is suboptimal! Binary sort would be 122 // preferable but the table requires sorting on the Opcode name, but it's 123 // static 124 // const initialized and matches the order of the spec. 125 const size_t nameLength = strlen(name); 126 for (uint64_t opcodeIndex = 0; opcodeIndex < table->count; ++opcodeIndex) { 127 if (nameLength == strlen(table->entries[opcodeIndex].name) && 128 !strncmp(name, table->entries[opcodeIndex].name, nameLength)) { 129 // NOTE: Found out Opcode! 130 *pEntry = &table->entries[opcodeIndex]; 131 return SPV_SUCCESS; 132 } 133 } 134 135 return SPV_ERROR_INVALID_LOOKUP; 136 } 137 138 spv_result_t spvOpcodeTableValueLookup(const spv_opcode_table table, 139 const SpvOp opcode, 140 spv_opcode_desc* pEntry) { 141 if (!table) return SPV_ERROR_INVALID_TABLE; 142 if (!pEntry) return SPV_ERROR_INVALID_POINTER; 143 144 // TODO: As above this lookup is not optimal. 145 for (uint64_t opcodeIndex = 0; opcodeIndex < table->count; ++opcodeIndex) { 146 if (opcode == table->entries[opcodeIndex].opcode) { 147 // NOTE: Found the Opcode! 148 *pEntry = &table->entries[opcodeIndex]; 149 return SPV_SUCCESS; 150 } 151 } 152 153 return SPV_ERROR_INVALID_LOOKUP; 154 } 155 156 void spvInstructionCopy(const uint32_t* words, const SpvOp opcode, 157 const uint16_t wordCount, const spv_endianness_t endian, 158 spv_instruction_t* pInst) { 159 pInst->opcode = opcode; 160 pInst->words.resize(wordCount); 161 for (uint16_t wordIndex = 0; wordIndex < wordCount; ++wordIndex) { 162 pInst->words[wordIndex] = spvFixWord(words[wordIndex], endian); 163 if (!wordIndex) { 164 uint16_t thisWordCount; 165 uint16_t thisOpcode; 166 spvOpcodeSplit(pInst->words[wordIndex], &thisWordCount, &thisOpcode); 167 assert(opcode == static_cast<SpvOp>(thisOpcode) && 168 wordCount == thisWordCount && "Endianness failed!"); 169 } 170 } 171 } 172 173 const char* spvOpcodeString(const SpvOp opcode) { 174 // Use the latest SPIR-V version, which should be backward-compatible with all 175 // previous ones. 176 for (uint32_t i = 0; i < ARRAY_SIZE(opcodeTableEntries_1_2); ++i) { 177 if (opcodeTableEntries_1_2[i].opcode == opcode) 178 return opcodeTableEntries_1_2[i].name; 179 } 180 assert(0 && "Unreachable!"); 181 return "unknown"; 182 } 183 184 int32_t spvOpcodeIsScalarType(const SpvOp opcode) { 185 switch (opcode) { 186 case SpvOpTypeInt: 187 case SpvOpTypeFloat: 188 case SpvOpTypeBool: 189 return true; 190 default: 191 return false; 192 } 193 } 194 195 int32_t spvOpcodeIsConstant(const SpvOp opcode) { 196 switch (opcode) { 197 case SpvOpConstantTrue: 198 case SpvOpConstantFalse: 199 case SpvOpConstant: 200 case SpvOpConstantComposite: 201 case SpvOpConstantSampler: 202 case SpvOpConstantNull: 203 case SpvOpSpecConstantTrue: 204 case SpvOpSpecConstantFalse: 205 case SpvOpSpecConstant: 206 case SpvOpSpecConstantComposite: 207 case SpvOpSpecConstantOp: 208 return true; 209 default: 210 return false; 211 } 212 } 213 214 bool spvOpcodeIsConstantOrUndef(const SpvOp opcode) { 215 return opcode == SpvOpUndef || spvOpcodeIsConstant(opcode); 216 } 217 218 bool spvOpcodeIsScalarSpecConstant(const SpvOp opcode) { 219 switch (opcode) { 220 case SpvOpSpecConstantTrue: 221 case SpvOpSpecConstantFalse: 222 case SpvOpSpecConstant: 223 return true; 224 default: 225 return false; 226 } 227 } 228 229 int32_t spvOpcodeIsComposite(const SpvOp opcode) { 230 switch (opcode) { 231 case SpvOpTypeVector: 232 case SpvOpTypeMatrix: 233 case SpvOpTypeArray: 234 case SpvOpTypeStruct: 235 return true; 236 default: 237 return false; 238 } 239 } 240 241 bool spvOpcodeReturnsLogicalVariablePointer(const SpvOp opcode) { 242 switch (opcode) { 243 case SpvOpVariable: 244 case SpvOpAccessChain: 245 case SpvOpInBoundsAccessChain: 246 case SpvOpFunctionParameter: 247 case SpvOpImageTexelPointer: 248 case SpvOpCopyObject: 249 case SpvOpSelect: 250 case SpvOpPhi: 251 case SpvOpFunctionCall: 252 case SpvOpPtrAccessChain: 253 case SpvOpLoad: 254 case SpvOpConstantNull: 255 return true; 256 default: 257 return false; 258 } 259 } 260 261 int32_t spvOpcodeReturnsLogicalPointer(const SpvOp opcode) { 262 switch (opcode) { 263 case SpvOpVariable: 264 case SpvOpAccessChain: 265 case SpvOpInBoundsAccessChain: 266 case SpvOpFunctionParameter: 267 case SpvOpImageTexelPointer: 268 case SpvOpCopyObject: 269 return true; 270 default: 271 return false; 272 } 273 } 274 275 int32_t spvOpcodeGeneratesType(SpvOp op) { 276 switch (op) { 277 case SpvOpTypeVoid: 278 case SpvOpTypeBool: 279 case SpvOpTypeInt: 280 case SpvOpTypeFloat: 281 case SpvOpTypeVector: 282 case SpvOpTypeMatrix: 283 case SpvOpTypeImage: 284 case SpvOpTypeSampler: 285 case SpvOpTypeSampledImage: 286 case SpvOpTypeArray: 287 case SpvOpTypeRuntimeArray: 288 case SpvOpTypeStruct: 289 case SpvOpTypeOpaque: 290 case SpvOpTypePointer: 291 case SpvOpTypeFunction: 292 case SpvOpTypeEvent: 293 case SpvOpTypeDeviceEvent: 294 case SpvOpTypeReserveId: 295 case SpvOpTypeQueue: 296 case SpvOpTypePipe: 297 case SpvOpTypePipeStorage: 298 case SpvOpTypeNamedBarrier: 299 return true; 300 default: 301 // In particular, OpTypeForwardPointer does not generate a type, 302 // but declares a storage class for a pointer type generated 303 // by a different instruction. 304 break; 305 } 306 return 0; 307 } 308