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