glslangValidator: Add straightforward SPIR-V support (non-optimizing, ~3.x functional...
[platform/upstream/glslang.git] / SPIRV / spvIR.h
1 //\r
2 //Copyright (C) 2014 LunarG, Inc.\r
3 //\r
4 //All rights reserved.\r
5 //\r
6 //Redistribution and use in source and binary forms, with or without\r
7 //modification, are permitted provided that the following conditions\r
8 //are met:\r
9 //\r
10 //    Redistributions of source code must retain the above copyright\r
11 //    notice, this list of conditions and the following disclaimer.\r
12 //\r
13 //    Redistributions in binary form must reproduce the above\r
14 //    copyright notice, this list of conditions and the following\r
15 //    disclaimer in the documentation and/or other materials provided\r
16 //    with the distribution.\r
17 //\r
18 //    Neither the name of 3Dlabs Inc. Ltd. nor the names of its\r
19 //    contributors may be used to endorse or promote products derived\r
20 //    from this software without specific prior written permission.\r
21 //\r
22 //THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\r
23 //"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\r
24 //LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS\r
25 //FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE\r
26 //COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,\r
27 //INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,\r
28 //BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\r
29 //LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\r
30 //CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\r
31 //LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN\r
32 //ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\r
33 //POSSIBILITY OF SUCH DAMAGE.\r
34 \r
35 //\r
36 // Author: John Kessenich, LunarG\r
37 //\r
38 \r
39 // SPIRV-IR\r
40 //\r
41 // Simple in-memory representation (IR) of SPIRV.  Just for holding\r
42 // Each function's CFG of blocks.  Has this hierarchy:\r
43 //  - Module, which is a list of \r
44 //    - Function, which is a list of \r
45 //      - Block, which is a list of \r
46 //        - Instruction\r
47 //\r
48 \r
49 #pragma once\r
50 #ifndef spvIR_H\r
51 #define spvIR_H\r
52 \r
53 #include "spirv.h"\r
54 \r
55 #include <vector>\r
56 #include <iostream>\r
57 \r
58 namespace spv {\r
59 \r
60 class Function;\r
61 class Module;\r
62 \r
63 //\r
64 // SPIR-V IR instruction.\r
65 //\r
66 \r
67 class Instruction {\r
68 public:\r
69     Instruction(Id resultId, Id typeId, OpCode opCode) : resultId(resultId), typeId(typeId), opCode(opCode), string(0) { }\r
70     explicit Instruction(OpCode opCode) : resultId(NoResult), typeId(NoType), opCode(opCode), string(0) { }\r
71     virtual ~Instruction()\r
72     {\r
73         delete string;\r
74     }\r
75     void addIdOperand(Id id) { operands.push_back(id); }\r
76     void addImmediateOperand(unsigned int immediate) { operands.push_back(immediate); }\r
77     void addStringOperand(const char* str)\r
78     {\r
79         string = new std::vector<unsigned int>;\r
80         unsigned int word;\r
81         char* wordString = (char*)&word;\r
82         char* wordPtr = wordString;\r
83         int charCount = 0;\r
84         char c;\r
85         do {\r
86             c = *(str++);\r
87             *(wordPtr++) = c;\r
88             ++charCount;\r
89             if (charCount == 4) {\r
90                 string->push_back(word);\r
91                 wordPtr = wordString;\r
92                 charCount = 0;\r
93             }\r
94         } while (c != 0);\r
95 \r
96         // deal with partial last word\r
97         if (charCount > 0) {\r
98             // pad with 0s\r
99             for (; charCount < 4; ++charCount)\r
100                 *(wordPtr++) = 0;\r
101             string->push_back(word);\r
102         }\r
103 \r
104         originalString = str;\r
105     }\r
106     OpCode getOpCode() const { return opCode; }\r
107     int getNumOperands() const { return operands.size(); }\r
108     Id getResultId() const { return resultId; }\r
109     Id getTypeId() const { return typeId; }\r
110     Id getIdOperand(int op) const { return operands[op]; }\r
111     unsigned int getImmediateOperand(int op) const { return operands[op]; }\r
112     const char* getStringOperand() const { return originalString.c_str(); }\r
113 \r
114     // Write out the binary form.\r
115     void dump(std::vector<unsigned int>& out) const\r
116     {\r
117         // Compute the wordCount\r
118         unsigned int wordCount = 1;\r
119         if (typeId)\r
120             ++wordCount;\r
121         if (resultId)\r
122             ++wordCount;\r
123         wordCount += operands.size();\r
124         if (string)\r
125             wordCount += string->size();\r
126 \r
127         // Write out the beginning of the instruction\r
128         out.push_back(((wordCount) << WordCountShift) | opCode);\r
129         if (typeId)\r
130             out.push_back(typeId);\r
131         if (resultId)\r
132             out.push_back(resultId);\r
133 \r
134         // Write out the operands\r
135         for (int op = 0; op < (int)operands.size(); ++op)\r
136             out.push_back(operands[op]);\r
137         if (string)\r
138             for (int op = 0; op < (int)string->size(); ++op)\r
139                 out.push_back((*string)[op]);\r
140     }\r
141 \r
142 protected:\r
143     Instruction(const Instruction&);\r
144     Id resultId;\r
145     Id typeId;\r
146     OpCode opCode;\r
147     std::vector<Id> operands;\r
148     std::vector<unsigned int>* string; // usually non-existent\r
149     std::string originalString;        // could be optimized away; convenience for getting string operand\r
150 };\r
151 \r
152 //\r
153 // SPIR-V IR block.\r
154 //\r
155 \r
156 class Block {\r
157 public:\r
158     // Setting insert to true indicates to add this new block \r
159     // to the end of the parent function.\r
160     Block(Id id, Function& parent);\r
161     virtual ~Block()\r
162     {\r
163         // TODO: free instructions\r
164     }\r
165     \r
166     Id getId() { return instructions.front()->getResultId(); }\r
167 \r
168     Function& getParent() const { return parent; }\r
169     void addInstruction(Instruction* inst);\r
170     void addPredecessor(Block* pred) { predecessors.push_back(pred); }\r
171     void addLocalVariable(Instruction* inst) { localVariables.push_back(inst); }\r
172     int getNumPredecessors() const { return (int)predecessors.size(); }\r
173 \r
174     bool isTerminated() const\r
175     {\r
176         switch (instructions.back()->getOpCode()) {\r
177         case OpBranch:\r
178         case OpBranchConditional:\r
179         case OpSwitch:\r
180         case OpKill:\r
181         case OpReturn:\r
182         case OpReturnValue:\r
183             return true;\r
184         default:\r
185             return false;\r
186         }\r
187     }\r
188 \r
189     void dump(std::vector<unsigned int>& out) const\r
190     {\r
191         instructions[0]->dump(out);\r
192         for (int i = 0; i < (int)localVariables.size(); ++i)\r
193             localVariables[i]->dump(out);\r
194         for (int i = 1; i < (int)instructions.size(); ++i)\r
195             instructions[i]->dump(out);\r
196     }\r
197 \r
198 protected:\r
199     Block(const Block&);\r
200 \r
201     // To enforce keeping parent and ownership in sync:\r
202     friend Function;\r
203 \r
204     std::vector<Instruction*> instructions;\r
205     std::vector<Block*> predecessors;\r
206     std::vector<Instruction*> localVariables;\r
207     Function& parent;\r
208 };\r
209 \r
210 //\r
211 // SPIR-V IR Function.\r
212 //\r
213 \r
214 class Function {\r
215 public:\r
216     Function(Id id, Id resultType, Id functionType, Id firstParam, Module& parent);\r
217     virtual ~Function()\r
218     {\r
219         for (int i = 0; i < (int)parameterInstructions.size(); ++i)\r
220             delete parameterInstructions[i];\r
221 \r
222         for (int i = 0; i < (int)blocks.size(); ++i)\r
223             delete blocks[i];\r
224     }\r
225     Id getId() const { return functionInstruction.getResultId(); }\r
226     Id getParamId(int p) { return parameterInstructions[p]->getResultId(); }\r
227 \r
228     void addBlock(Block* block) { blocks.push_back(block); }\r
229     void popBlock(Block* block) { assert(blocks.back() == block); blocks.pop_back(); }\r
230 \r
231     Module& getParent() const { return parent; }\r
232     Block* getEntryBlock() const { return blocks.front(); }\r
233     Block* getLastBlock() const { return blocks.back(); }\r
234     void addLocalVariable(Instruction* inst);\r
235     Id getReturnType() const { return functionInstruction.getTypeId(); }\r
236     void dump(std::vector<unsigned int>& out) const\r
237     {\r
238         // OpFunction\r
239         functionInstruction.dump(out);\r
240 \r
241         // OpFunctionParameter\r
242         for (int p = 0; p < (int)parameterInstructions.size(); ++p)\r
243             parameterInstructions[p]->dump(out);\r
244 \r
245         // Blocks\r
246         for (int b = 0; b < (int)blocks.size(); ++b)\r
247             blocks[b]->dump(out);\r
248         Instruction end(0, 0, OpFunctionEnd);\r
249         end.dump(out);\r
250     }\r
251 \r
252 protected:\r
253     Function(const Function&);\r
254     Module& parent;\r
255     Instruction functionInstruction;\r
256     std::vector<Instruction*> parameterInstructions;\r
257     std::vector<Block*> blocks;\r
258 };\r
259 \r
260 //\r
261 // SPIR-V IR Module.\r
262 //\r
263 \r
264 class Module {\r
265 public:\r
266     Module() {}\r
267     virtual ~Module()\r
268     {\r
269         // TODO delete things\r
270     }\r
271 \r
272     void addFunction(Function *fun) { functions.push_back(fun); }\r
273 \r
274     void mapInstruction(Instruction *instruction)\r
275     {\r
276         spv::Id resultId = instruction->getResultId();\r
277         // map the instruction's result id\r
278         if (resultId >= idToInstruction.size())\r
279             idToInstruction.resize(resultId + 16);\r
280         idToInstruction[resultId] = instruction;\r
281     }\r
282 \r
283     Instruction* getInstruction(Id id) const { return idToInstruction[id]; }\r
284     spv::Id getTypeId(Id resultId) const { return idToInstruction[resultId]->getTypeId(); }\r
285     StorageClass getStorageClass(Id typeId) const { return (StorageClass)idToInstruction[typeId]->getImmediateOperand(0); }\r
286     void dump(std::vector<unsigned int>& out) const\r
287     {\r
288         for (int f = 0; f < (int)functions.size(); ++f)\r
289             functions[f]->dump(out);\r
290     }\r
291 \r
292 protected:\r
293     Module(const Module&);\r
294     std::vector<Function*> functions;\r
295 \r
296     // map from result id to instruction having that result id\r
297     std::vector<Instruction*> idToInstruction;\r
298 \r
299     // map from a result id to its type id\r
300 };\r
301 \r
302 //\r
303 // Implementation (it's here due to circular type definitions).\r
304 //\r
305 \r
306 // Add both\r
307 // - the OpFunction instruction\r
308 // - all the OpFunctionParameter instructions\r
309 __inline Function::Function(Id id, Id resultType, Id functionType, Id firstParamId, Module& parent)\r
310     : parent(parent), functionInstruction(id, resultType, OpFunction)\r
311 {\r
312     // OpFunction\r
313     functionInstruction.addImmediateOperand(FunctionControlNone);\r
314     functionInstruction.addIdOperand(functionType);\r
315     parent.mapInstruction(&functionInstruction);\r
316     parent.addFunction(this);\r
317 \r
318     // OpFunctionParameter\r
319     Instruction* typeInst = parent.getInstruction(functionType);\r
320     int numParams = typeInst->getNumOperands() - 1;\r
321     for (int p = 0; p < numParams; ++p) {\r
322         Instruction* param = new Instruction(firstParamId + p, typeInst->getIdOperand(p + 1), OpFunctionParameter);\r
323         parent.mapInstruction(param);\r
324         parameterInstructions.push_back(param);\r
325     }\r
326 }\r
327 \r
328 __inline void Function::addLocalVariable(Instruction* inst)\r
329 {\r
330     blocks[0]->addLocalVariable(inst);\r
331     parent.mapInstruction(inst);\r
332 }\r
333 \r
334 __inline Block::Block(Id id, Function& parent) : parent(parent)\r
335 {\r
336     instructions.push_back(new Instruction(id, NoType, OpLabel));\r
337 }\r
338 \r
339 __inline void Block::addInstruction(Instruction* inst)\r
340 {\r
341     instructions.push_back(inst);\r
342     if (inst->getResultId())\r
343         parent.getParent().mapInstruction(inst);\r
344 }\r
345 \r
346 };  // end spv namespace\r
347 \r
348 #endif // spvIR_H\r