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