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