Home | History | Annotate | Download | only in source
      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