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