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