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