// Copyright (c) 2014-2020 The Khronos Group Inc. // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and/or associated documentation files (the "Materials"), // to deal in the Materials without restriction, including without limitation // the rights to use, copy, modify, merge, publish, distribute, sublicense, // and/or sell copies of the Materials, and to permit persons to whom the // Materials are furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Materials. // // MODIFICATIONS TO THIS FILE MAY MEAN IT NO LONGER ACCURATELY REFLECTS KHRONOS // STANDARDS. THE UNMODIFIED, NORMATIVE VERSIONS OF KHRONOS SPECIFICATIONS AND // HEADER INFORMATION ARE LOCATED AT https://www.khronos.org/registry/ // // THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING // FROM,OUT OF OR IN CONNECTION WITH THE MATERIALS OR THE USE OR OTHER DEALINGS // IN THE MATERIALS. #pragma once #ifndef JSON_TO_SPIRV #define JSON_TO_SPIRV #include #include #include #include namespace spv { // Reads the file in the given |path|. Returns true and the contents of the // file on success; otherwise, returns false and an empty string. std::pair ReadFile(const std::string& path); // Fill in all the parameters void jsonToSpirv(const std::string& jsonPath, bool buildingHeaders); // For parameterizing operands. // The ordering here affects the printing order in the SPIR-V specification. // Please add new operand classes at the end. enum OperandClass { OperandNone, OperandId, OperandVariableIds, OperandOptionalLiteral, OperandOptionalLiteralString, OperandOptionalLiteralStrings, OperandVariableLiterals, OperandVariableIdLiteral, OperandVariableLiteralId, OperandAnySizeLiteralNumber, OperandLiteralNumber, OperandLiteralString, OperandSource, OperandExecutionModel, OperandAddressing, OperandMemory, OperandExecutionMode, OperandStorage, OperandDimensionality, OperandSamplerAddressingMode, OperandSamplerFilterMode, OperandSamplerImageFormat, OperandImageChannelOrder, OperandImageChannelDataType, OperandImageOperands, OperandFPFastMath, OperandFPRoundingMode, OperandLinkageType, OperandAccessQualifier, OperandFuncParamAttr, OperandDecoration, OperandBuiltIn, OperandSelect, OperandLoop, OperandFunction, OperandMemorySemantics, OperandMemoryOperands, OperandScope, OperandGroupOperation, OperandKernelEnqueueFlags, OperandKernelProfilingInfo, OperandCapability, OperandRayFlags, OperandRayQueryIntersection, OperandRayQueryCommittedIntersectionType, OperandRayQueryCandidateIntersectionType, OperandFragmentShadingRate, OperandFPDenormMode, OperandFPOperationMode, OperandQuantizationModes, OperandOverflowModes, OperandPackedVectorFormat, OperandOpcode, OperandCount }; // For direct representation of the JSON grammar "instruction_printing_class". struct PrintingClass { std::string tag; std::string heading; }; using PrintingClasses = std::vector; // Any specific enum can have a set of capabilities that allow it: typedef std::vector EnumCaps; // A set of extensions. typedef std::vector Extensions; // Parameterize a set of operands with their OperandClass(es) and descriptions. class OperandParameters { public: OperandParameters() { } void push(OperandClass oc, const std::string& d, bool opt = false) { opClass.push_back(oc); desc.push_back(d); optional.push_back(opt); } void setOptional(); OperandClass getClass(int op) const { return opClass[op]; } const char* getDesc(int op) const { return desc[op].c_str(); } bool isOptional(int op) const { return optional[op]; } int getNum() const { return (int)opClass.size(); } protected: std::vector opClass; std::vector desc; std::vector optional; }; // An ordered sequence of EValue. We'll preserve the order found in the // JSON file. You can look up a value by enum or by name. If there are // duplicate values, then take the first. We assume names are unique. // The EValue must have an unsigned |value| field and a string |name| field. template class EnumValuesContainer { public: using ContainerType = std::vector; using iterator = typename ContainerType::iterator; using const_iterator = typename ContainerType::const_iterator; EnumValuesContainer() {} // Constructs an EValue in place as a new element at the end of the // sequence. template void emplace_back(Args&&... args) { values.emplace_back(std::forward(args)...); } // Returns the first EValue in the sequence with the given value. // More than one EValue might have the same value. EValue& operator[](unsigned value) { auto where = std::find_if(begin(), end(), [&value](const EValue& e) { return value == e.value; }); assert((where != end()) && "Could not find enum in the enum list"); return *where; } // gets *all* entries for the value, including the first one void gatherAliases(unsigned value, std::vector& aliases) { std::for_each(begin(), end(), [&](EValue& e) { if (value == e.value) aliases.push_back(&e);}); } // Returns the EValue with the given name. We assume uniqueness // by name. EValue& at(std::string name) { auto where = std::find_if(begin(), end(), [&name](const EValue& e) { return name == e.name; }); assert((where != end()) && "Could not find name in the enum list"); return *where; } iterator begin() { return values.begin(); } iterator end() { return values.end(); } private: ContainerType values; }; // A single enumerant value. Corresponds to a row in an enumeration table // in the spec. class EnumValue { public: 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) : value(the_value), name(the_name), capabilities(std::move(the_caps)), firstVersion(std::move(the_firstVersion)), lastVersion(std::move(the_lastVersion)), extensions(std::move(the_extensions)), operands(std::move(the_operands)), desc(nullptr) { } // For ValueEnum, the value from the JSON file. // For BitEnum, the index of the bit position represented by this mask. // (That is, what you shift 1 by to get the mask.) unsigned value; std::string name; EnumCaps capabilities; std::string firstVersion; std::string lastVersion; // A feature only be enabled by certain extensions. // An empty list means the feature does not require an extension. // Normally, only Capability enums are enabled by extension. In turn, // other enums and instructions are enabled by those capabilities. Extensions extensions; OperandParameters operands; const char* desc; }; using EnumValues = EnumValuesContainer; // Parameterize a set of enumerants that form an enum class EnumDefinition { public: EnumDefinition() : desc(0), bitmask(false), enumValues(nullptr) { } void set(const std::string& enumName, EnumValues* enumValuesArg, bool mask = false) { codeName = enumName; bitmask = mask; enumValues = enumValuesArg; } // Returns the first EnumValue in the sequence with the given value. // More than one EnumValue might have the same value. Only valid // if enumValues has been populated. EnumValue& operator[](unsigned value) { assert(enumValues != nullptr); return (*enumValues)[value]; } // Returns the name of the first EnumValue with the given value. // Assumes enumValues has been populated. const char* getName(unsigned value) { return (*this)[value].name.c_str(); } using iterator = EnumValues::iterator; iterator begin() { return enumValues->begin(); } iterator end() { return enumValues->end(); } std::string codeName; // name to use when declaring headers for code const char* desc; bool bitmask; // true if these enumerants combine into a bitmask EnumValues* enumValues; // parameters for each individual enumerant }; // Parameterize an instruction's logical format, including its known set of operands, // per OperandParameters above. class InstructionValue : public EnumValue { public: InstructionValue(EnumValue&& e, const std::string& printClass, bool has_type, bool has_result) : EnumValue(std::move(e)), printingClass(printClass), opDesc("TBD"), typePresent(has_type), resultPresent(has_result), alias(this) { } InstructionValue(const InstructionValue& v) { *this = v; alias = this; } bool hasResult() const { return resultPresent != 0; } bool hasType() const { return typePresent != 0; } void setAlias(const InstructionValue& a) { alias = &a; } const InstructionValue& getAlias() const { return *alias; } bool isAlias() const { return alias != this; } std::string printingClass; const char* opDesc; protected: int typePresent : 1; int resultPresent : 1; const InstructionValue* alias; // correct only after discovering the aliases; otherwise points to this }; using InstructionValues = EnumValuesContainer; // Parameterization info for all instructions. extern InstructionValues InstructionDesc; extern PrintingClasses InstructionPrintingClasses; // These hold definitions of the enumerants used for operands. // This is indexed by OperandClass, but not including OperandOpcode. extern EnumDefinition OperandClassParams[]; }; // end namespace spv #endif // JSON_TO_SPIRV