1 // Copyright (c) 2014-2018 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);
42 
43 // For parameterizing operands.
44 enum OperandClass {
45     OperandNone,
46     OperandId,
47     OperandVariableIds,
48     OperandOptionalLiteral,
49     OperandOptionalLiteralString,
50     OperandVariableLiterals,
51     OperandVariableIdLiteral,
52     OperandVariableLiteralId,
53     OperandLiteralNumber,
54     OperandLiteralString,
55     OperandSource,
56     OperandExecutionModel,
57     OperandAddressing,
58     OperandMemory,
59     OperandExecutionMode,
60     OperandStorage,
61     OperandDimensionality,
62     OperandSamplerAddressingMode,
63     OperandSamplerFilterMode,
64     OperandSamplerImageFormat,
65     OperandImageChannelOrder,
66     OperandImageChannelDataType,
67     OperandImageOperands,
68     OperandFPFastMath,
69     OperandFPRoundingMode,
70     OperandLinkageType,
71     OperandAccessQualifier,
72     OperandFuncParamAttr,
73     OperandDecoration,
74     OperandBuiltIn,
75     OperandSelect,
76     OperandLoop,
77     OperandFunction,
78     OperandMemorySemantics,
79     OperandMemoryAccess,
80     OperandScope,
81 	OperandGroupOperation,
82     OperandKernelEnqueueFlags,
83     OperandKernelProfilingInfo,
84     OperandCapability,
85 
86     OperandOpcode,
87 
88     OperandCount
89 };
90 
91 // Any specific enum can have a set of capabilities that allow it:
92 typedef std::vector<std::string> EnumCaps;
93 
94 // A set of extensions.
95 typedef std::vector<std::string> Extensions;
96 
97 // Parameterize a set of operands with their OperandClass(es) and descriptions.
98 class OperandParameters {
99 public:
OperandParameters()100     OperandParameters() { }
101     void push(OperandClass oc, const std::string& d, bool opt = false)
102     {
103         opClass.push_back(oc);
104         desc.push_back(d);
105         optional.push_back(opt);
106     }
107     void setOptional();
getClass(int op)108     OperandClass getClass(int op) const { return opClass[op]; }
getDesc(int op)109     const char* getDesc(int op) const { return desc[op].c_str(); }
isOptional(int op)110     bool isOptional(int op) const { return optional[op]; }
getNum()111     int getNum() const { return (int)opClass.size(); }
112 
113 protected:
114     std::vector<OperandClass> opClass;
115     std::vector<std::string> desc;
116     std::vector<bool> optional;
117 };
118 
119 // An ordered sequence of EValue.  We'll preserve the order found in the
120 // JSON file.  You can look up a value by enum or by name.  If there are
121 // duplicate values, then take the first.  We assume names are unique.
122 // The EValue must have an unsigned |value| field and a string |name| field.
123 template <typename EValue>
124 class EnumValuesContainer {
125 public:
126     using ContainerType = std::vector<EValue>;
127     using iterator = typename ContainerType::iterator;
128     using const_iterator = typename ContainerType::const_iterator;
129 
EnumValuesContainer()130     EnumValuesContainer() {}
131 
132     // Constructs an EValue in place as a new element at the end of the
133     // sequence.
134     template <typename... Args>
emplace_back(Args &&...args)135     void emplace_back(Args&&... args) {
136         values.emplace_back(std::forward<Args>(args)...);
137     }
138 
139     // Returns the first EValue in the sequence with the given value.
140     // More than one EValue might have the same value.
141     EValue& operator[](unsigned value) {
142         auto where = std::find_if(begin(), end(), [&value](const EValue& e) {
143            return value == e.value;
144         });
145         assert((where != end()) && "Could not find enum in the enum list");
146         return *where;
147     }
148     // Returns the EValue with the given name.  We assume uniqueness
149     // by name.
at(std::string name)150     EValue& at(std::string name) {
151         auto where = std::find_if(begin(), end(), [&name](const EValue& e) {
152            return name == e.name;
153         });
154         assert((where != end()) && "Could not find name in the enum list");
155         return *where;
156     }
157 
begin()158     iterator begin() { return values.begin(); }
end()159     iterator end() { return values.end(); }
160 
161 private:
162     ContainerType values;
163 };
164 
165 // A single enumerant value.  Corresponds to a row in an enumeration table
166 // in the spec.
167 class EnumValue {
168 public:
EnumValue()169     EnumValue() : value(0), desc(nullptr) {}
EnumValue(unsigned int the_value,const std::string & the_name,EnumCaps && the_caps,const std::string & the_version,Extensions && the_extensions,OperandParameters && the_operands)170     EnumValue(unsigned int the_value, const std::string& the_name, EnumCaps&& the_caps, const std::string& the_version,
171               Extensions&& the_extensions, OperandParameters&& the_operands) :
172       value(the_value), name(the_name), capabilities(std::move(the_caps)), version(std::move(the_version)),
173       extensions(std::move(the_extensions)), operands(std::move(the_operands)), desc(nullptr) { }
174 
175     // For ValueEnum, the value from the JSON file.
176     // For BitEnum, the index of the bit position represented by this mask.
177     // (That is, what you shift 1 by to get the mask.)
178     unsigned value;
179     std::string name;
180     EnumCaps capabilities;
181     std::string version;
182     // A feature only be enabled by certain extensions.
183     // An empty list means the feature does not require an extension.
184     // Normally, only Capability enums are enabled by extension.  In turn,
185     // other enums and instructions are enabled by those capabilities.
186     Extensions extensions;
187     OperandParameters operands;
188     const char* desc;
189 };
190 
191 using EnumValues = EnumValuesContainer<EnumValue>;
192 
193 // Parameterize a set of enumerants that form an enum
194 class EnumDefinition {
195 public:
EnumDefinition()196     EnumDefinition() :
197         desc(0), bitmask(false), enumValues(nullptr) { }
198     void set(const std::string& enumName, EnumValues* enumValuesArg, bool mask = false)
199     {
200         codeName = enumName;
201         bitmask = mask;
202         enumValues = enumValuesArg;
203     }
204     // Returns the first EnumValue in the sequence with the given value.
205     // More than one EnumValue might have the same value.  Only valid
206     // if enumValues has been populated.
207     EnumValue& operator[](unsigned value) {
208         assert(enumValues != nullptr);
209         return (*enumValues)[value];
210     }
211     // Returns the name of the first EnumValue with the given value.
212     // Assumes enumValues has been populated.
getName(unsigned value)213     const char* getName(unsigned value) {
214         return (*this)[value].name.c_str();
215     }
216 
217     using iterator = EnumValues::iterator;
begin()218     iterator begin() { return enumValues->begin(); }
end()219     iterator end() { return enumValues->end(); }
220 
221     std::string codeName; // name to use when declaring headers for code
222     const char* desc;
223     bool bitmask;  // true if these enumerants combine into a bitmask
224     EnumValues* enumValues; // parameters for each individual enumerant
225 };
226 
227 // Parameterize an instruction's logical format, including its known set of operands,
228 // per OperandParameters above.
229 class InstructionValue : public EnumValue {
230 public:
InstructionValue(EnumValue && e,bool has_type,bool has_result)231     InstructionValue(EnumValue&& e, bool has_type, bool has_result)
232      : EnumValue(std::move(e)),
233        opDesc("TBD"),
234        opClass(0),
235        typePresent(has_type),
236        resultPresent(has_result) {}
237 
hasResult()238     bool hasResult() const { return resultPresent != 0; }
hasType()239     bool hasType()   const { return typePresent != 0; }
240 
241     const char* opDesc;
242     int opClass;
243 
244 protected:
245     int typePresent   : 1;
246     int resultPresent : 1;
247 };
248 
249 using InstructionValues = EnumValuesContainer<InstructionValue>;
250 
251 // Parameterization info for all instructions.
252 extern InstructionValues InstructionDesc;
253 
254 // These hold definitions of the enumerants used for operands.
255 // This is indexed by OperandClass, but not including OperandOpcode.
256 extern EnumDefinition OperandClassParams[];
257 
258 };  // end namespace spv
259 
260 #endif // JSON_TO_SPIRV
261