Licensing. Fixes #958. Add licenes file and update copyrights.
[platform/upstream/glslang.git] / SPIRV / spvIR.h
1 //
2 // Copyright (C) 2014 LunarG, Inc.
3 // Copyright (C) 2015-2018 Google, Inc.
4 //
5 // All rights reserved.
6 //
7 // Redistribution and use in source and binary forms, with or without
8 // modification, are permitted provided that the following conditions
9 // are met:
10 //
11 //    Redistributions of source code must retain the above copyright
12 //    notice, this list of conditions and the following disclaimer.
13 //
14 //    Redistributions in binary form must reproduce the above
15 //    copyright notice, this list of conditions and the following
16 //    disclaimer in the documentation and/or other materials provided
17 //    with the distribution.
18 //
19 //    Neither the name of 3Dlabs Inc. Ltd. nor the names of its
20 //    contributors may be used to endorse or promote products derived
21 //    from this software without specific prior written permission.
22 //
23 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
26 // FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
27 // COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
28 // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
29 // BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
30 // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
31 // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
33 // ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
34 // POSSIBILITY OF SUCH DAMAGE.
35
36 // SPIRV-IR
37 //
38 // Simple in-memory representation (IR) of SPIRV.  Just for holding
39 // Each function's CFG of blocks.  Has this hierarchy:
40 //  - Module, which is a list of
41 //    - Function, which is a list of
42 //      - Block, which is a list of
43 //        - Instruction
44 //
45
46 #pragma once
47 #ifndef spvIR_H
48 #define spvIR_H
49
50 #include "spirv.hpp"
51
52 #include <algorithm>
53 #include <cassert>
54 #include <functional>
55 #include <iostream>
56 #include <memory>
57 #include <vector>
58
59 namespace spv {
60
61 class Block;
62 class Function;
63 class Module;
64
65 const Id NoResult = 0;
66 const Id NoType = 0;
67
68 const Decoration NoPrecision = DecorationMax;
69
70 #ifdef __GNUC__
71 #   define POTENTIALLY_UNUSED __attribute__((unused))
72 #else
73 #   define POTENTIALLY_UNUSED
74 #endif
75
76 POTENTIALLY_UNUSED
77 const MemorySemanticsMask MemorySemanticsAllMemory =
78                 (MemorySemanticsMask)(MemorySemanticsUniformMemoryMask |
79                                       MemorySemanticsWorkgroupMemoryMask |
80                                       MemorySemanticsAtomicCounterMemoryMask |
81                                       MemorySemanticsImageMemoryMask);
82
83 struct IdImmediate {
84     bool isId;      // true if word is an Id, false if word is an immediate
85     unsigned word;
86 };
87
88 //
89 // SPIR-V IR instruction.
90 //
91
92 class Instruction {
93 public:
94     Instruction(Id resultId, Id typeId, Op opCode) : resultId(resultId), typeId(typeId), opCode(opCode), block(nullptr) { }
95     explicit Instruction(Op opCode) : resultId(NoResult), typeId(NoType), opCode(opCode), block(nullptr) { }
96     virtual ~Instruction() {}
97     void addIdOperand(Id id) {
98         operands.push_back(id);
99         idOperand.push_back(true);
100     }
101     void addImmediateOperand(unsigned int immediate) {
102         operands.push_back(immediate);
103         idOperand.push_back(false);
104     }
105     void addStringOperand(const char* str)
106     {
107         unsigned int word;
108         char* wordString = (char*)&word;
109         char* wordPtr = wordString;
110         int charCount = 0;
111         char c;
112         do {
113             c = *(str++);
114             *(wordPtr++) = c;
115             ++charCount;
116             if (charCount == 4) {
117                 addImmediateOperand(word);
118                 wordPtr = wordString;
119                 charCount = 0;
120             }
121         } while (c != 0);
122
123         // deal with partial last word
124         if (charCount > 0) {
125             // pad with 0s
126             for (; charCount < 4; ++charCount)
127                 *(wordPtr++) = 0;
128             addImmediateOperand(word);
129         }
130     }
131     bool isIdOperand(int op) const { return idOperand[op]; }
132     void setBlock(Block* b) { block = b; }
133     Block* getBlock() const { return block; }
134     Op getOpCode() const { return opCode; }
135     int getNumOperands() const
136     {
137         assert(operands.size() == idOperand.size());
138         return (int)operands.size();
139     }
140     Id getResultId() const { return resultId; }
141     Id getTypeId() const { return typeId; }
142     Id getIdOperand(int op) const {
143         assert(idOperand[op]);
144         return operands[op];
145     }
146     unsigned int getImmediateOperand(int op) const {
147         assert(!idOperand[op]);
148         return operands[op];
149     }
150
151     // Write out the binary form.
152     void dump(std::vector<unsigned int>& out) const
153     {
154         // Compute the wordCount
155         unsigned int wordCount = 1;
156         if (typeId)
157             ++wordCount;
158         if (resultId)
159             ++wordCount;
160         wordCount += (unsigned int)operands.size();
161
162         // Write out the beginning of the instruction
163         out.push_back(((wordCount) << WordCountShift) | opCode);
164         if (typeId)
165             out.push_back(typeId);
166         if (resultId)
167             out.push_back(resultId);
168
169         // Write out the operands
170         for (int op = 0; op < (int)operands.size(); ++op)
171             out.push_back(operands[op]);
172     }
173
174 protected:
175     Instruction(const Instruction&);
176     Id resultId;
177     Id typeId;
178     Op opCode;
179     std::vector<Id> operands;     // operands, both <id> and immediates (both are unsigned int)
180     std::vector<bool> idOperand;  // true for operands that are <id>, false for immediates
181     Block* block;
182 };
183
184 //
185 // SPIR-V IR block.
186 //
187
188 class Block {
189 public:
190     Block(Id id, Function& parent);
191     virtual ~Block()
192     {
193     }
194
195     Id getId() { return instructions.front()->getResultId(); }
196
197     Function& getParent() const { return parent; }
198     void addInstruction(std::unique_ptr<Instruction> inst);
199     void addPredecessor(Block* pred) { predecessors.push_back(pred); pred->successors.push_back(this);}
200     void addLocalVariable(std::unique_ptr<Instruction> inst) { localVariables.push_back(std::move(inst)); }
201     const std::vector<Block*>& getPredecessors() const { return predecessors; }
202     const std::vector<Block*>& getSuccessors() const { return successors; }
203     const std::vector<std::unique_ptr<Instruction> >& getInstructions() const {
204         return instructions;
205     }
206     void setUnreachable() { unreachable = true; }
207     bool isUnreachable() const { return unreachable; }
208     // Returns the block's merge instruction, if one exists (otherwise null).
209     const Instruction* getMergeInstruction() const {
210         if (instructions.size() < 2) return nullptr;
211         const Instruction* nextToLast = (instructions.cend() - 2)->get();
212         switch (nextToLast->getOpCode()) {
213             case OpSelectionMerge:
214             case OpLoopMerge:
215                 return nextToLast;
216             default:
217                 return nullptr;
218         }
219         return nullptr;
220     }
221
222     bool isTerminated() const
223     {
224         switch (instructions.back()->getOpCode()) {
225         case OpBranch:
226         case OpBranchConditional:
227         case OpSwitch:
228         case OpKill:
229         case OpReturn:
230         case OpReturnValue:
231             return true;
232         default:
233             return false;
234         }
235     }
236
237     void dump(std::vector<unsigned int>& out) const
238     {
239         instructions[0]->dump(out);
240         for (int i = 0; i < (int)localVariables.size(); ++i)
241             localVariables[i]->dump(out);
242         for (int i = 1; i < (int)instructions.size(); ++i)
243             instructions[i]->dump(out);
244     }
245
246 protected:
247     Block(const Block&);
248     Block& operator=(Block&);
249
250     // To enforce keeping parent and ownership in sync:
251     friend Function;
252
253     std::vector<std::unique_ptr<Instruction> > instructions;
254     std::vector<Block*> predecessors, successors;
255     std::vector<std::unique_ptr<Instruction> > localVariables;
256     Function& parent;
257
258     // track whether this block is known to be uncreachable (not necessarily
259     // true for all unreachable blocks, but should be set at least
260     // for the extraneous ones introduced by the builder).
261     bool unreachable;
262 };
263
264 // Traverses the control-flow graph rooted at root in an order suited for
265 // readable code generation.  Invokes callback at every node in the traversal
266 // order.
267 void inReadableOrder(Block* root, std::function<void(Block*)> callback);
268
269 //
270 // SPIR-V IR Function.
271 //
272
273 class Function {
274 public:
275     Function(Id id, Id resultType, Id functionType, Id firstParam, Module& parent);
276     virtual ~Function()
277     {
278         for (int i = 0; i < (int)parameterInstructions.size(); ++i)
279             delete parameterInstructions[i];
280
281         for (int i = 0; i < (int)blocks.size(); ++i)
282             delete blocks[i];
283     }
284     Id getId() const { return functionInstruction.getResultId(); }
285     Id getParamId(int p) const { return parameterInstructions[p]->getResultId(); }
286     Id getParamType(int p) const { return parameterInstructions[p]->getTypeId(); }
287
288     void addBlock(Block* block) { blocks.push_back(block); }
289     void removeBlock(Block* block)
290     {
291         auto found = find(blocks.begin(), blocks.end(), block);
292         assert(found != blocks.end());
293         blocks.erase(found);
294         delete block;
295     }
296
297     Module& getParent() const { return parent; }
298     Block* getEntryBlock() const { return blocks.front(); }
299     Block* getLastBlock() const { return blocks.back(); }
300     const std::vector<Block*>& getBlocks() const { return blocks; }
301     void addLocalVariable(std::unique_ptr<Instruction> inst);
302     Id getReturnType() const { return functionInstruction.getTypeId(); }
303
304     void setImplicitThis() { implicitThis = true; }
305     bool hasImplicitThis() const { return implicitThis; }
306
307     void dump(std::vector<unsigned int>& out) const
308     {
309         // OpFunction
310         functionInstruction.dump(out);
311
312         // OpFunctionParameter
313         for (int p = 0; p < (int)parameterInstructions.size(); ++p)
314             parameterInstructions[p]->dump(out);
315
316         // Blocks
317         inReadableOrder(blocks[0], [&out](const Block* b) { b->dump(out); });
318         Instruction end(0, 0, OpFunctionEnd);
319         end.dump(out);
320     }
321
322 protected:
323     Function(const Function&);
324     Function& operator=(Function&);
325
326     Module& parent;
327     Instruction functionInstruction;
328     std::vector<Instruction*> parameterInstructions;
329     std::vector<Block*> blocks;
330     bool implicitThis;  // true if this is a member function expecting to be passed a 'this' as the first argument
331 };
332
333 //
334 // SPIR-V IR Module.
335 //
336
337 class Module {
338 public:
339     Module() {}
340     virtual ~Module()
341     {
342         // TODO delete things
343     }
344
345     void addFunction(Function *fun) { functions.push_back(fun); }
346
347     void mapInstruction(Instruction *instruction)
348     {
349         spv::Id resultId = instruction->getResultId();
350         // map the instruction's result id
351         if (resultId >= idToInstruction.size())
352             idToInstruction.resize(resultId + 16);
353         idToInstruction[resultId] = instruction;
354     }
355
356     Instruction* getInstruction(Id id) const { return idToInstruction[id]; }
357     const std::vector<Function*>& getFunctions() const { return functions; }
358     spv::Id getTypeId(Id resultId) const {
359         return idToInstruction[resultId] == nullptr ? NoType : idToInstruction[resultId]->getTypeId();
360     }
361     StorageClass getStorageClass(Id typeId) const
362     {
363         assert(idToInstruction[typeId]->getOpCode() == spv::OpTypePointer);
364         return (StorageClass)idToInstruction[typeId]->getImmediateOperand(0);
365     }
366
367     void dump(std::vector<unsigned int>& out) const
368     {
369         for (int f = 0; f < (int)functions.size(); ++f)
370             functions[f]->dump(out);
371     }
372
373 protected:
374     Module(const Module&);
375     std::vector<Function*> functions;
376
377     // map from result id to instruction having that result id
378     std::vector<Instruction*> idToInstruction;
379
380     // map from a result id to its type id
381 };
382
383 //
384 // Implementation (it's here due to circular type definitions).
385 //
386
387 // Add both
388 // - the OpFunction instruction
389 // - all the OpFunctionParameter instructions
390 __inline Function::Function(Id id, Id resultType, Id functionType, Id firstParamId, Module& parent)
391     : parent(parent), functionInstruction(id, resultType, OpFunction), implicitThis(false)
392 {
393     // OpFunction
394     functionInstruction.addImmediateOperand(FunctionControlMaskNone);
395     functionInstruction.addIdOperand(functionType);
396     parent.mapInstruction(&functionInstruction);
397     parent.addFunction(this);
398
399     // OpFunctionParameter
400     Instruction* typeInst = parent.getInstruction(functionType);
401     int numParams = typeInst->getNumOperands() - 1;
402     for (int p = 0; p < numParams; ++p) {
403         Instruction* param = new Instruction(firstParamId + p, typeInst->getIdOperand(p + 1), OpFunctionParameter);
404         parent.mapInstruction(param);
405         parameterInstructions.push_back(param);
406     }
407 }
408
409 __inline void Function::addLocalVariable(std::unique_ptr<Instruction> inst)
410 {
411     Instruction* raw_instruction = inst.get();
412     blocks[0]->addLocalVariable(std::move(inst));
413     parent.mapInstruction(raw_instruction);
414 }
415
416 __inline Block::Block(Id id, Function& parent) : parent(parent), unreachable(false)
417 {
418     instructions.push_back(std::unique_ptr<Instruction>(new Instruction(id, NoType, OpLabel)));
419     instructions.back()->setBlock(this);
420     parent.getParent().mapInstruction(instructions.back().get());
421 }
422
423 __inline void Block::addInstruction(std::unique_ptr<Instruction> inst)
424 {
425     Instruction* raw_instruction = inst.get();
426     instructions.push_back(std::move(inst));
427     raw_instruction->setBlock(this);
428     if (raw_instruction->getResultId())
429         parent.getParent().mapInstruction(raw_instruction);
430 }
431
432 };  // end spv namespace
433
434 #endif // spvIR_H