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