Home | History | Annotate | Download | only in buildHeaders
      1 // Copyright (c) 2014-2019 The Khronos Group Inc.
      2 //
      3 // Permission is hereby granted, free of charge, to any person obtaining a copy
      4 // of this software and/or associated documentation files (the "Materials"),
      5 // to deal in the Materials without restriction, including without limitation
      6 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
      7 // and/or sell copies of the Materials, and to permit persons to whom the
      8 // Materials are furnished to do so, subject to the following conditions:
      9 //
     10 // The above copyright notice and this permission notice shall be included in
     11 // all copies or substantial portions of the Materials.
     12 //
     13 // MODIFICATIONS TO THIS FILE MAY MEAN IT NO LONGER ACCURATELY REFLECTS KHRONOS
     14 // STANDARDS. THE UNMODIFIED, NORMATIVE VERSIONS OF KHRONOS SPECIFICATIONS AND
     15 // HEADER INFORMATION ARE LOCATED AT https://www.khronos.org/registry/
     16 //
     17 // THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
     18 // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     19 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
     20 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     21 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
     22 // FROM,OUT OF OR IN CONNECTION WITH THE MATERIALS OR THE USE OR OTHER DEALINGS
     23 // IN THE MATERIALS.
     24 
     25 #include <assert.h>
     26 #include <string.h>
     27 #include <algorithm>
     28 #include <iostream>
     29 #include <unordered_map>
     30 #include <utility>
     31 #include <fstream>
     32 
     33 #include "jsoncpp/dist/json/json.h"
     34 
     35 #include "jsonToSpirv.h"
     36 
     37 namespace spv {
     38 
     39 // The set of objects that hold all the instruction/operand
     40 // parameterization information.
     41 InstructionValues InstructionDesc;
     42 
     43 // Note: There is no entry for OperandOpcode. Use InstructionDesc instead.
     44 EnumDefinition OperandClassParams[OperandOpcode];
     45 EnumValues SourceLanguageParams;
     46 EnumValues ExecutionModelParams;
     47 EnumValues AddressingParams;
     48 EnumValues MemoryParams;
     49 EnumValues ExecutionModeParams;
     50 EnumValues StorageParams;
     51 EnumValues SamplerAddressingModeParams;
     52 EnumValues SamplerFilterModeParams;
     53 EnumValues ImageFormatParams;
     54 EnumValues ImageChannelOrderParams;
     55 EnumValues ImageChannelDataTypeParams;
     56 EnumValues ImageOperandsParams;
     57 EnumValues FPFastMathParams;
     58 EnumValues FPRoundingModeParams;
     59 EnumValues LinkageTypeParams;
     60 EnumValues DecorationParams;
     61 EnumValues BuiltInParams;
     62 EnumValues DimensionalityParams;
     63 EnumValues FuncParamAttrParams;
     64 EnumValues AccessQualifierParams;
     65 EnumValues GroupOperationParams;
     66 EnumValues LoopControlParams;
     67 EnumValues SelectionControlParams;
     68 EnumValues FunctionControlParams;
     69 EnumValues MemorySemanticsParams;
     70 EnumValues MemoryAccessParams;
     71 EnumValues ScopeParams;
     72 EnumValues KernelEnqueueFlagsParams;
     73 EnumValues KernelProfilingInfoParams;
     74 EnumValues CapabilityParams;
     75 
     76 std::pair<bool, std::string> ReadFile(const std::string& path)
     77 {
     78     std::ifstream fstream(path, std::ios::in);
     79     if (fstream) {
     80         std::string contents;
     81         fstream.seekg(0, std::ios::end);
     82         contents.reserve((unsigned int)fstream.tellg());
     83         fstream.seekg(0, std::ios::beg);
     84         contents.assign((std::istreambuf_iterator<char>(fstream)),
     85                         std::istreambuf_iterator<char>());
     86         return std::make_pair(true, contents);
     87     }
     88     return std::make_pair(false, "");
     89 }
     90 
     91 struct ClassOptionality {
     92     OperandClass type;
     93     bool optional;
     94 };
     95 
     96 // Converts the |operandKind| and |quantifier| pair used to describe operands
     97 // in the JSON grammar to OperandClass and optionality used in this repo.
     98 ClassOptionality ToOperandClassAndOptionality(const std::string& operandKind, const std::string& quantifier)
     99 {
    100     assert(quantifier.empty() || quantifier == "?" || quantifier == "*");
    101 
    102     if (operandKind == "IdRef") {
    103         if (quantifier.empty())
    104             return {OperandId, false};
    105         else if (quantifier == "?")
    106             return {OperandId, true};
    107         else
    108             return {OperandVariableIds, false};
    109     } else if (operandKind == "LiteralInteger") {
    110         if (quantifier.empty())
    111             return {OperandLiteralNumber, false};
    112         if (quantifier == "?")
    113             return {OperandOptionalLiteral, true};
    114         else
    115             return {OperandVariableLiterals, false};
    116     } else if (operandKind == "LiteralString") {
    117         if (quantifier.empty())
    118             return {OperandLiteralString, false};
    119         else if (quantifier == "?")
    120             return {OperandLiteralString, true};
    121         else {
    122             assert(0 && "this case should not exist");
    123             return {OperandNone, false};
    124         }
    125     } else if (operandKind == "PairLiteralIntegerIdRef") {
    126         // Used by OpSwitch in the grammar
    127         return {OperandVariableLiteralId, false};
    128     } else if (operandKind == "PairIdRefLiteralInteger") {
    129         // Used by OpGroupMemberDecorate in the grammar
    130         return {OperandVariableIdLiteral, false};
    131     } else if (operandKind == "PairIdRefIdRef") {
    132         // Used by OpPhi in the grammar
    133         return {OperandVariableIds, false};
    134     } else {
    135         OperandClass type = OperandNone;
    136         if (operandKind == "IdMemorySemantics" || operandKind == "MemorySemantics") {
    137             type = OperandMemorySemantics;
    138         } else if (operandKind == "IdScope" || operandKind == "Scope") {
    139             type = OperandScope;
    140         } else if (operandKind == "LiteralExtInstInteger") {
    141             type = OperandLiteralNumber;
    142         } else if (operandKind == "LiteralSpecConstantOpInteger") {
    143             type = OperandLiteralNumber;
    144         } else if (operandKind == "LiteralContextDependentNumber") {
    145             type = OperandVariableLiterals;
    146         } else if (operandKind == "SourceLanguage") {
    147             type = OperandSource;
    148         } else if (operandKind == "ExecutionModel") {
    149             type = OperandExecutionModel;
    150         } else if (operandKind == "AddressingModel") {
    151             type = OperandAddressing;
    152         } else if (operandKind == "MemoryModel") {
    153             type = OperandMemory;
    154         } else if (operandKind == "ExecutionMode") {
    155             type = OperandExecutionMode;
    156         } else if (operandKind == "StorageClass") {
    157             type = OperandStorage;
    158         } else if (operandKind == "Dim") {
    159             type = OperandDimensionality;
    160         } else if (operandKind == "SamplerAddressingMode") {
    161             type = OperandSamplerAddressingMode;
    162         } else if (operandKind == "SamplerFilterMode") {
    163             type = OperandSamplerFilterMode;
    164         } else if (operandKind == "ImageFormat") {
    165             type = OperandSamplerImageFormat;
    166         } else if (operandKind == "ImageChannelOrder") {
    167             type = OperandImageChannelOrder;
    168         } else if (operandKind == "ImageChannelDataType") {
    169             type = OperandImageChannelDataType;
    170         } else if (operandKind == "FPRoundingMode") {
    171             type = OperandFPRoundingMode;
    172         } else if (operandKind == "LinkageType") {
    173             type = OperandLinkageType;
    174         } else if (operandKind == "AccessQualifier") {
    175             type = OperandAccessQualifier;
    176         } else if (operandKind == "FunctionParameterAttribute") {
    177             type = OperandFuncParamAttr;
    178         } else if (operandKind == "Decoration") {
    179             type = OperandDecoration;
    180         } else if (operandKind == "BuiltIn") {
    181             type = OperandBuiltIn;
    182         } else if (operandKind == "GroupOperation") {
    183             type = OperandGroupOperation;
    184         } else if (operandKind == "KernelEnqueueFlags") {
    185             type = OperandKernelEnqueueFlags;
    186         } else if (operandKind == "KernelProfilingInfo") {
    187             type = OperandKernelProfilingInfo;
    188         } else if (operandKind == "Capability") {
    189             type = OperandCapability;
    190         } else if (operandKind == "ImageOperands") {
    191             type = OperandImageOperands;
    192         } else if (operandKind == "FPFastMathMode") {
    193             type = OperandFPFastMath;
    194         } else if (operandKind == "SelectionControl") {
    195             type = OperandSelect;
    196         } else if (operandKind == "LoopControl") {
    197             type = OperandLoop;
    198         } else if (operandKind == "FunctionControl") {
    199             type = OperandFunction;
    200         } else if (operandKind == "MemoryAccess") {
    201             type = OperandMemoryAccess;
    202         }
    203 
    204         if (type == OperandNone) {
    205             std::cerr << "Unhandled operand kind found: " << operandKind << std::endl;
    206             exit(1);
    207         }
    208         return {type, !quantifier.empty()};
    209     }
    210 }
    211 
    212 bool IsTypeOrResultId(const std::string& str, bool* isType, bool* isResult)
    213 {
    214     if (str == "IdResultType")
    215         return *isType = true;
    216     if (str == "IdResult")
    217         return *isResult = true;
    218     return false;
    219 }
    220 
    221 // Given a number string, returns the position of the only bits set in the number.
    222 // So it requires the number is a power of two.
    223 unsigned int NumberStringToBit(const std::string& str)
    224 {
    225     char* parseEnd;
    226     unsigned int value = (unsigned int)std::strtol(str.c_str(), &parseEnd, 16);
    227     assert(!(value & (value - 1)) && "input number is not a power of 2");
    228     unsigned int bit = 0;
    229     for (; value; value >>= 1) ++bit;
    230     return bit;
    231 }
    232 
    233 void jsonToSpirv(const std::string& jsonPath)
    234 {
    235     // only do this once.
    236     static bool initialized = false;
    237     if (initialized)
    238         return;
    239     initialized = true;
    240 
    241     // Read the JSON grammar file.
    242     bool fileReadOk = false;
    243     std::string content;
    244     std::tie(fileReadOk, content) = ReadFile(jsonPath);
    245     if (!fileReadOk) {
    246         std::cerr << "Failed to read JSON grammar file: "
    247                   << jsonPath << std::endl;
    248         exit(1);
    249     }
    250 
    251     // Decode the JSON grammar file.
    252     Json::Reader reader;
    253     Json::Value root;
    254     if (!reader.parse(content, root)) {
    255         std::cerr << "Failed to parse JSON grammar:\n"
    256                   << reader.getFormattedErrorMessages();
    257         exit(1);
    258     }
    259 
    260     // Layouts for all instructions.
    261 
    262     // A lambda for returning capabilities from a JSON object as strings.
    263     const auto getCaps = [](const Json::Value& object) {
    264         EnumCaps result;
    265         const auto& caps = object["capabilities"];
    266         if (!caps.empty()) {
    267             assert(caps.isArray());
    268             for (const auto& cap : caps) {
    269                 result.emplace_back(cap.asString());
    270             }
    271         }
    272         return result;
    273     };
    274 
    275     // A lambda for returning extensions from a JSON object as strings.
    276     const auto getExts = [](const Json::Value& object) {
    277         Extensions result;
    278         const auto& exts = object["extensions"];
    279         if (!exts.empty()) {
    280             assert(exts.isArray());
    281             for (const auto& ext : exts) {
    282                 result.emplace_back(ext.asString());
    283             }
    284         }
    285         return result;
    286     };
    287 
    288     const Json::Value insts = root["instructions"];
    289     for (const auto& inst : insts) {
    290         const unsigned int opcode = inst["opcode"].asUInt();
    291         const std::string name = inst["opname"].asString();
    292         EnumCaps caps = getCaps(inst);
    293         std::string version = inst["version"].asString();
    294         Extensions exts = getExts(inst);
    295         OperandParameters operands;
    296         bool defResultId = false;
    297         bool defTypeId = false;
    298         for (const auto& operand : inst["operands"]) {
    299             const std::string kind = operand["kind"].asString();
    300             const std::string quantifier = operand.get("quantifier", "").asString();
    301             const std::string doc = operand.get("name", "").asString();
    302             if (!IsTypeOrResultId(kind, &defTypeId, &defResultId)) {
    303                 const auto p = ToOperandClassAndOptionality(kind, quantifier);
    304                 operands.push(p.type, doc, p.optional);
    305             }
    306         }
    307         InstructionDesc.emplace_back(
    308             std::move(EnumValue(opcode, name,
    309                                 std::move(caps), std::move(version), std::move(exts),
    310                                 std::move(operands))),
    311             defTypeId, defResultId);
    312     }
    313 
    314     // Specific additional context-dependent operands
    315 
    316     // Populate dest with EnumValue objects constructed from source.
    317     const auto populateEnumValues = [&getCaps,&getExts](EnumValues* dest, const Json::Value& source, bool bitEnum) {
    318         // A lambda for determining the numeric value to be used for a given
    319         // enumerant in JSON form, and whether that value is a 0 in a bitfield.
    320         auto getValue = [&bitEnum](const Json::Value& enumerant) {
    321             std::pair<unsigned, bool> result{0u,false};
    322             if (!bitEnum) {
    323                 result.first = enumerant["value"].asUInt();
    324             } else {
    325                 const unsigned int bit = NumberStringToBit(enumerant["value"].asString());
    326                 if (bit == 0)
    327                     result.second = true;
    328                 else
    329                     result.first = bit - 1;  // This is the *shift* amount.
    330             }
    331             return result;
    332         };
    333 
    334         for (const auto& enumerant : source["enumerants"]) {
    335             unsigned value;
    336             bool skip_zero_in_bitfield;
    337             std::tie(value, skip_zero_in_bitfield) = getValue(enumerant);
    338             if (skip_zero_in_bitfield)
    339                 continue;
    340             EnumCaps caps(getCaps(enumerant));
    341             std::string version = enumerant["version"].asString();
    342             Extensions exts(getExts(enumerant));
    343             OperandParameters params;
    344             const Json::Value& paramsJson = enumerant["parameters"];
    345             if (!paramsJson.empty()) {  // This enumerant has parameters.
    346                 assert(paramsJson.isArray());
    347                 for (const auto& param : paramsJson) {
    348                     const std::string kind = param["kind"].asString();
    349                     const std::string doc = param.get("name", "").asString();
    350                     const auto p = ToOperandClassAndOptionality(kind, ""); // All parameters are required!
    351                     params.push(p.type, doc);
    352                 }
    353             }
    354             dest->emplace_back(
    355                 value, enumerant["enumerant"].asString(),
    356                 std::move(caps), std::move(version), std::move(exts), std::move(params));
    357         }
    358     };
    359 
    360     const auto establishOperandClass = [&populateEnumValues](
    361             const std::string& enumName, spv::OperandClass operandClass,
    362             spv::EnumValues* enumValues, const Json::Value& operandEnum, const std::string& category) {
    363         assert(category == "BitEnum" || category == "ValueEnum");
    364         bool bitEnum = (category == "BitEnum");
    365         populateEnumValues(enumValues, operandEnum, bitEnum);
    366         OperandClassParams[operandClass].set(enumName, enumValues, bitEnum);
    367     };
    368 
    369     const Json::Value operandEnums = root["operand_kinds"];
    370     for (const auto& operandEnum : operandEnums) {
    371         const std::string enumName = operandEnum["kind"].asString();
    372         const std::string category = operandEnum["category"].asString();
    373         if (enumName == "SourceLanguage") {
    374             establishOperandClass(enumName, OperandSource, &SourceLanguageParams, operandEnum, category);
    375         } else if (enumName == "Decoration") {
    376             establishOperandClass(enumName, OperandDecoration, &DecorationParams, operandEnum, category);
    377         } else if (enumName == "ExecutionMode") {
    378             establishOperandClass(enumName, OperandExecutionMode, &ExecutionModeParams, operandEnum, category);
    379         } else if (enumName == "Capability") {
    380             establishOperandClass(enumName, OperandCapability, &CapabilityParams, operandEnum, category);
    381         } else if (enumName == "AddressingModel") {
    382             establishOperandClass(enumName, OperandAddressing, &AddressingParams, operandEnum, category);
    383         } else if (enumName == "MemoryModel") {
    384             establishOperandClass(enumName, OperandMemory, &MemoryParams, operandEnum, category);
    385         } else if (enumName == "MemorySemantics") {
    386             establishOperandClass(enumName, OperandMemorySemantics, &MemorySemanticsParams, operandEnum, category);
    387         } else if (enumName == "ExecutionModel") {
    388             establishOperandClass(enumName, OperandExecutionModel, &ExecutionModelParams, operandEnum, category);
    389         } else if (enumName == "StorageClass") {
    390             establishOperandClass(enumName, OperandStorage, &StorageParams, operandEnum, category);
    391         } else if (enumName == "SamplerAddressingMode") {
    392             establishOperandClass(enumName, OperandSamplerAddressingMode, &SamplerAddressingModeParams, operandEnum, category);
    393         } else if (enumName == "SamplerFilterMode") {
    394             establishOperandClass(enumName, OperandSamplerFilterMode, &SamplerFilterModeParams, operandEnum, category);
    395         } else if (enumName == "ImageFormat") {
    396             establishOperandClass(enumName, OperandSamplerImageFormat, &ImageFormatParams, operandEnum, category);
    397         } else if (enumName == "ImageChannelOrder") {
    398             establishOperandClass(enumName, OperandImageChannelOrder, &ImageChannelOrderParams, operandEnum, category);
    399         } else if (enumName == "ImageChannelDataType") {
    400             establishOperandClass(enumName, OperandImageChannelDataType, &ImageChannelDataTypeParams, operandEnum, category);
    401         } else if (enumName == "ImageOperands") {
    402             establishOperandClass(enumName, OperandImageOperands, &ImageOperandsParams, operandEnum, category);
    403         } else if (enumName == "FPFastMathMode") {
    404             establishOperandClass(enumName, OperandFPFastMath, &FPFastMathParams, operandEnum, category);
    405         } else if (enumName == "FPRoundingMode") {
    406             establishOperandClass(enumName, OperandFPRoundingMode, &FPRoundingModeParams, operandEnum, category);
    407         } else if (enumName == "LinkageType") {
    408             establishOperandClass(enumName, OperandLinkageType, &LinkageTypeParams, operandEnum, category);
    409         } else if (enumName == "FunctionParameterAttribute") {
    410             establishOperandClass(enumName, OperandFuncParamAttr, &FuncParamAttrParams, operandEnum, category);
    411         } else if (enumName == "AccessQualifier") {
    412             establishOperandClass(enumName, OperandAccessQualifier, &AccessQualifierParams, operandEnum, category);
    413         } else if (enumName == "BuiltIn") {
    414             establishOperandClass(enumName, OperandBuiltIn, &BuiltInParams, operandEnum, category);
    415         } else if (enumName == "SelectionControl") {
    416             establishOperandClass(enumName, OperandSelect, &SelectionControlParams, operandEnum, category);
    417         } else if (enumName == "LoopControl") {
    418             establishOperandClass(enumName, OperandLoop, &LoopControlParams, operandEnum, category);
    419         } else if (enumName == "FunctionControl") {
    420             establishOperandClass(enumName, OperandFunction, &FunctionControlParams, operandEnum, category);
    421         } else if (enumName == "Dim") {
    422             establishOperandClass(enumName, OperandDimensionality, &DimensionalityParams, operandEnum, category);
    423         } else if (enumName == "MemoryAccess") {
    424             establishOperandClass(enumName, OperandMemoryAccess, &MemoryAccessParams, operandEnum, category);
    425         } else if (enumName == "Scope") {
    426             establishOperandClass(enumName, OperandScope, &ScopeParams, operandEnum, category);
    427         } else if (enumName == "GroupOperation") {
    428             establishOperandClass(enumName, OperandGroupOperation, &GroupOperationParams, operandEnum, category);
    429         } else if (enumName == "KernelEnqueueFlags") {
    430             establishOperandClass(enumName, OperandKernelEnqueueFlags, &KernelEnqueueFlagsParams, operandEnum, category);
    431         } else if (enumName == "KernelProfilingInfo") {
    432             establishOperandClass(enumName, OperandKernelProfilingInfo, &KernelProfilingInfoParams, operandEnum, category);
    433         }
    434     }
    435 }
    436 
    437 };  // end namespace spv
    438