1 // Copyright (c) 2014-2018 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 #pragma once 26 #ifndef JSON_TO_SPIRV 27 #define JSON_TO_SPIRV 28 29 #include <algorithm> 30 #include <string> 31 #include <vector> 32 #include <assert.h> 33 34 namespace spv { 35 36 // Reads the file in the given |path|. Returns true and the contents of the 37 // file on success; otherwise, returns false and an empty string. 38 std::pair<bool, std::string> ReadFile(const std::string& path); 39 40 // Fill in all the parameters 41 void jsonToSpirv(const std::string& jsonPath); 42 43 // For parameterizing operands. 44 enum OperandClass { 45 OperandNone, 46 OperandId, 47 OperandVariableIds, 48 OperandOptionalLiteral, 49 OperandOptionalLiteralString, 50 OperandVariableLiterals, 51 OperandVariableIdLiteral, 52 OperandVariableLiteralId, 53 OperandLiteralNumber, 54 OperandLiteralString, 55 OperandSource, 56 OperandExecutionModel, 57 OperandAddressing, 58 OperandMemory, 59 OperandExecutionMode, 60 OperandStorage, 61 OperandDimensionality, 62 OperandSamplerAddressingMode, 63 OperandSamplerFilterMode, 64 OperandSamplerImageFormat, 65 OperandImageChannelOrder, 66 OperandImageChannelDataType, 67 OperandImageOperands, 68 OperandFPFastMath, 69 OperandFPRoundingMode, 70 OperandLinkageType, 71 OperandAccessQualifier, 72 OperandFuncParamAttr, 73 OperandDecoration, 74 OperandBuiltIn, 75 OperandSelect, 76 OperandLoop, 77 OperandFunction, 78 OperandMemorySemantics, 79 OperandMemoryAccess, 80 OperandScope, 81 OperandGroupOperation, 82 OperandKernelEnqueueFlags, 83 OperandKernelProfilingInfo, 84 OperandCapability, 85 86 OperandOpcode, 87 88 OperandCount 89 }; 90 91 // Any specific enum can have a set of capabilities that allow it: 92 typedef std::vector<std::string> EnumCaps; 93 94 // A set of extensions. 95 typedef std::vector<std::string> Extensions; 96 97 // Parameterize a set of operands with their OperandClass(es) and descriptions. 98 class OperandParameters { 99 public: OperandParameters()100 OperandParameters() { } 101 void push(OperandClass oc, const std::string& d, bool opt = false) 102 { 103 opClass.push_back(oc); 104 desc.push_back(d); 105 optional.push_back(opt); 106 } 107 void setOptional(); getClass(int op)108 OperandClass getClass(int op) const { return opClass[op]; } getDesc(int op)109 const char* getDesc(int op) const { return desc[op].c_str(); } isOptional(int op)110 bool isOptional(int op) const { return optional[op]; } getNum()111 int getNum() const { return (int)opClass.size(); } 112 113 protected: 114 std::vector<OperandClass> opClass; 115 std::vector<std::string> desc; 116 std::vector<bool> optional; 117 }; 118 119 // An ordered sequence of EValue. We'll preserve the order found in the 120 // JSON file. You can look up a value by enum or by name. If there are 121 // duplicate values, then take the first. We assume names are unique. 122 // The EValue must have an unsigned |value| field and a string |name| field. 123 template <typename EValue> 124 class EnumValuesContainer { 125 public: 126 using ContainerType = std::vector<EValue>; 127 using iterator = typename ContainerType::iterator; 128 using const_iterator = typename ContainerType::const_iterator; 129 EnumValuesContainer()130 EnumValuesContainer() {} 131 132 // Constructs an EValue in place as a new element at the end of the 133 // sequence. 134 template <typename... Args> emplace_back(Args &&...args)135 void emplace_back(Args&&... args) { 136 values.emplace_back(std::forward<Args>(args)...); 137 } 138 139 // Returns the first EValue in the sequence with the given value. 140 // More than one EValue might have the same value. 141 EValue& operator[](unsigned value) { 142 auto where = std::find_if(begin(), end(), [&value](const EValue& e) { 143 return value == e.value; 144 }); 145 assert((where != end()) && "Could not find enum in the enum list"); 146 return *where; 147 } 148 // Returns the EValue with the given name. We assume uniqueness 149 // by name. at(std::string name)150 EValue& at(std::string name) { 151 auto where = std::find_if(begin(), end(), [&name](const EValue& e) { 152 return name == e.name; 153 }); 154 assert((where != end()) && "Could not find name in the enum list"); 155 return *where; 156 } 157 begin()158 iterator begin() { return values.begin(); } end()159 iterator end() { return values.end(); } 160 161 private: 162 ContainerType values; 163 }; 164 165 // A single enumerant value. Corresponds to a row in an enumeration table 166 // in the spec. 167 class EnumValue { 168 public: EnumValue()169 EnumValue() : value(0), desc(nullptr) {} EnumValue(unsigned int the_value,const std::string & the_name,EnumCaps && the_caps,const std::string & the_version,Extensions && the_extensions,OperandParameters && the_operands)170 EnumValue(unsigned int the_value, const std::string& the_name, EnumCaps&& the_caps, const std::string& the_version, 171 Extensions&& the_extensions, OperandParameters&& the_operands) : 172 value(the_value), name(the_name), capabilities(std::move(the_caps)), version(std::move(the_version)), 173 extensions(std::move(the_extensions)), operands(std::move(the_operands)), desc(nullptr) { } 174 175 // For ValueEnum, the value from the JSON file. 176 // For BitEnum, the index of the bit position represented by this mask. 177 // (That is, what you shift 1 by to get the mask.) 178 unsigned value; 179 std::string name; 180 EnumCaps capabilities; 181 std::string version; 182 // A feature only be enabled by certain extensions. 183 // An empty list means the feature does not require an extension. 184 // Normally, only Capability enums are enabled by extension. In turn, 185 // other enums and instructions are enabled by those capabilities. 186 Extensions extensions; 187 OperandParameters operands; 188 const char* desc; 189 }; 190 191 using EnumValues = EnumValuesContainer<EnumValue>; 192 193 // Parameterize a set of enumerants that form an enum 194 class EnumDefinition { 195 public: EnumDefinition()196 EnumDefinition() : 197 desc(0), bitmask(false), enumValues(nullptr) { } 198 void set(const std::string& enumName, EnumValues* enumValuesArg, bool mask = false) 199 { 200 codeName = enumName; 201 bitmask = mask; 202 enumValues = enumValuesArg; 203 } 204 // Returns the first EnumValue in the sequence with the given value. 205 // More than one EnumValue might have the same value. Only valid 206 // if enumValues has been populated. 207 EnumValue& operator[](unsigned value) { 208 assert(enumValues != nullptr); 209 return (*enumValues)[value]; 210 } 211 // Returns the name of the first EnumValue with the given value. 212 // Assumes enumValues has been populated. getName(unsigned value)213 const char* getName(unsigned value) { 214 return (*this)[value].name.c_str(); 215 } 216 217 using iterator = EnumValues::iterator; begin()218 iterator begin() { return enumValues->begin(); } end()219 iterator end() { return enumValues->end(); } 220 221 std::string codeName; // name to use when declaring headers for code 222 const char* desc; 223 bool bitmask; // true if these enumerants combine into a bitmask 224 EnumValues* enumValues; // parameters for each individual enumerant 225 }; 226 227 // Parameterize an instruction's logical format, including its known set of operands, 228 // per OperandParameters above. 229 class InstructionValue : public EnumValue { 230 public: InstructionValue(EnumValue && e,bool has_type,bool has_result)231 InstructionValue(EnumValue&& e, bool has_type, bool has_result) 232 : EnumValue(std::move(e)), 233 opDesc("TBD"), 234 opClass(0), 235 typePresent(has_type), 236 resultPresent(has_result) {} 237 hasResult()238 bool hasResult() const { return resultPresent != 0; } hasType()239 bool hasType() const { return typePresent != 0; } 240 241 const char* opDesc; 242 int opClass; 243 244 protected: 245 int typePresent : 1; 246 int resultPresent : 1; 247 }; 248 249 using InstructionValues = EnumValuesContainer<InstructionValue>; 250 251 // Parameterization info for all instructions. 252 extern InstructionValues InstructionDesc; 253 254 // These hold definitions of the enumerants used for operands. 255 // This is indexed by OperandClass, but not including OperandOpcode. 256 extern EnumDefinition OperandClassParams[]; 257 258 }; // end namespace spv 259 260 #endif // JSON_TO_SPIRV 261