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