blob: d3e7ad987d3296350f246a9f80214157809f1bf5 [file] [log] [blame]
John Kessenich140f3df2015-06-26 16:58:36 -06001//
2//Copyright (C) 2014 LunarG, Inc.
3//
4//All rights reserved.
5//
6//Redistribution and use in source and binary forms, with or without
7//modification, are permitted provided that the following conditions
8//are met:
9//
10// Redistributions of source code must retain the above copyright
11// notice, this list of conditions and the following disclaimer.
12//
13// Redistributions in binary form must reproduce the above
14// copyright notice, this list of conditions and the following
15// disclaimer in the documentation and/or other materials provided
16// with the distribution.
17//
18// Neither the name of 3Dlabs Inc. Ltd. nor the names of its
19// contributors may be used to endorse or promote products derived
20// from this software without specific prior written permission.
21//
22//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
25//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
26//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
27//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
28//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
30//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
32//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33//POSSIBILITY OF SUCH DAMAGE.
34
35//
36// Author: John Kessenich, LunarG
37//
38
39//
40// "Builder" is an interface to fully build SPIR-V IR. Allocate one of
41// these to build (a thread safe) internal SPIR-V representation (IR),
42// and then dump it as a binary stream according to the SPIR-V specification.
43//
44// A Builder has a 1:1 relationship with a SPIR-V module.
45//
46
47#pragma once
48#ifndef SpvBuilder_H
49#define SpvBuilder_H
50
John Kessenich5e4b1242015-08-06 22:53:06 -060051#include "spirv.hpp"
John Kessenich140f3df2015-06-26 16:58:36 -060052#include "spvIR.h"
53
54#include <algorithm>
55#include <stack>
56#include <map>
57
58namespace spv {
59
60class Builder {
61public:
62 Builder(unsigned int userNumber);
63 virtual ~Builder();
64
65 static const int maxMatrixSize = 4;
66
67 void setSource(spv::SourceLanguage lang, int version)
68 {
69 source = lang;
70 sourceVersion = version;
71 }
72 void addSourceExtension(const char* ext) { extensions.push_back(ext); }
73 Id import(const char*);
74 void setMemoryModel(spv::AddressingModel addr, spv::MemoryModel mem)
75 {
76 addressModel = addr;
77 memoryModel = mem;
78 }
79
John Kessenich5e4b1242015-08-06 22:53:06 -060080 void addCapability(spv::Capability cap) { capabilities.push_back(cap); }
81
John Kessenich140f3df2015-06-26 16:58:36 -060082 // To get a new <id> for anything needing a new one.
83 Id getUniqueId() { return ++uniqueId; }
84
85 // To get a set of new <id>s, e.g., for a set of function parameters
86 Id getUniqueIds(int numIds)
87 {
88 Id id = uniqueId + 1;
89 uniqueId += numIds;
90 return id;
91 }
92
93 // For creating new types (will return old type if the requested one was already made).
94 Id makeVoidType();
95 Id makeBoolType();
96 Id makePointer(StorageClass, Id type);
97 Id makeIntegerType(int width, bool hasSign); // generic
98 Id makeIntType(int width) { return makeIntegerType(width, true); }
99 Id makeUintType(int width) { return makeIntegerType(width, false); }
100 Id makeFloatType(int width);
101 Id makeStructType(std::vector<Id>& members, const char*);
John Kessenich55e7d112015-11-15 21:33:39 -0700102 Id makeStructResultType(Id type0, Id type1);
John Kessenich140f3df2015-06-26 16:58:36 -0600103 Id makeVectorType(Id component, int size);
104 Id makeMatrixType(Id component, int cols, int rows);
105 Id makeArrayType(Id element, unsigned size);
John Kessenichc9a80832015-09-12 12:17:44 -0600106 Id makeRuntimeArray(Id element);
John Kessenich140f3df2015-06-26 16:58:36 -0600107 Id makeFunctionType(Id returnType, std::vector<Id>& paramTypes);
John Kessenich5e4b1242015-08-06 22:53:06 -0600108 Id makeImageType(Id sampledType, Dim, bool depth, bool arrayed, bool ms, unsigned sampled, ImageFormat format);
John Kessenich55e7d112015-11-15 21:33:39 -0700109 Id makeSamplerType();
John Kessenich5e4b1242015-08-06 22:53:06 -0600110 Id makeSampledImageType(Id imageType);
John Kessenich140f3df2015-06-26 16:58:36 -0600111
112 // For querying about types.
113 Id getTypeId(Id resultId) const { return module.getTypeId(resultId); }
114 Id getDerefTypeId(Id resultId) const;
115 Op getOpCode(Id id) const { return module.getInstruction(id)->getOpCode(); }
116 Op getTypeClass(Id typeId) const { return getOpCode(typeId); }
117 Op getMostBasicTypeClass(Id typeId) const;
118 int getNumComponents(Id resultId) const { return getNumTypeComponents(getTypeId(resultId)); }
119 int getNumTypeComponents(Id typeId) const;
120 Id getScalarTypeId(Id typeId) const;
121 Id getContainedTypeId(Id typeId) const;
122 Id getContainedTypeId(Id typeId, int) const;
John Kessenich55e7d112015-11-15 21:33:39 -0700123 StorageClass getTypeStorageClass(Id typeId) const { return module.getStorageClass(typeId); }
John Kessenich140f3df2015-06-26 16:58:36 -0600124
125 bool isPointer(Id resultId) const { return isPointerType(getTypeId(resultId)); }
126 bool isScalar(Id resultId) const { return isScalarType(getTypeId(resultId)); }
127 bool isVector(Id resultId) const { return isVectorType(getTypeId(resultId)); }
128 bool isMatrix(Id resultId) const { return isMatrixType(getTypeId(resultId)); }
129 bool isAggregate(Id resultId) const { return isAggregateType(getTypeId(resultId)); }
John Kessenich55e7d112015-11-15 21:33:39 -0700130 bool isBoolType(Id typeId) const { return groupedTypes[OpTypeBool].size() > 0 && typeId == groupedTypes[OpTypeBool].back()->getResultId(); }
John Kessenich140f3df2015-06-26 16:58:36 -0600131
132 bool isPointerType(Id typeId) const { return getTypeClass(typeId) == OpTypePointer; }
133 bool isScalarType(Id typeId) const { return getTypeClass(typeId) == OpTypeFloat || getTypeClass(typeId) == OpTypeInt || getTypeClass(typeId) == OpTypeBool; }
134 bool isVectorType(Id typeId) const { return getTypeClass(typeId) == OpTypeVector; }
135 bool isMatrixType(Id typeId) const { return getTypeClass(typeId) == OpTypeMatrix; }
136 bool isStructType(Id typeId) const { return getTypeClass(typeId) == OpTypeStruct; }
137 bool isArrayType(Id typeId) const { return getTypeClass(typeId) == OpTypeArray; }
138 bool isAggregateType(Id typeId) const { return isArrayType(typeId) || isStructType(typeId); }
John Kessenich5e4b1242015-08-06 22:53:06 -0600139 bool isImageType(Id typeId) const { return getTypeClass(typeId) == OpTypeImage; }
John Kessenich140f3df2015-06-26 16:58:36 -0600140 bool isSamplerType(Id typeId) const { return getTypeClass(typeId) == OpTypeSampler; }
John Kessenich5e4b1242015-08-06 22:53:06 -0600141 bool isSampledImageType(Id typeId) const { return getTypeClass(typeId) == OpTypeSampledImage; }
John Kessenich140f3df2015-06-26 16:58:36 -0600142
John Kessenich71631272015-10-13 10:39:19 -0600143 bool isConstantOpCode(Op opcode) const;
144 bool isConstant(Id resultId) const { return isConstantOpCode(getOpCode(resultId)); }
John Kessenich140f3df2015-06-26 16:58:36 -0600145 bool isConstantScalar(Id resultId) const { return getOpCode(resultId) == OpConstant; }
146 unsigned int getConstantScalar(Id resultId) const { return module.getInstruction(resultId)->getImmediateOperand(0); }
John Kessenich55e7d112015-11-15 21:33:39 -0700147 StorageClass getStorageClass(Id resultId) const { return getTypeStorageClass(getTypeId(resultId)); }
John Kessenich140f3df2015-06-26 16:58:36 -0600148
149 int getTypeNumColumns(Id typeId) const
150 {
151 assert(isMatrixType(typeId));
152 return getNumTypeComponents(typeId);
153 }
154 int getNumColumns(Id resultId) const { return getTypeNumColumns(getTypeId(resultId)); }
155 int getTypeNumRows(Id typeId) const
156 {
157 assert(isMatrixType(typeId));
158 return getNumTypeComponents(getContainedTypeId(typeId));
159 }
160 int getNumRows(Id resultId) const { return getTypeNumRows(getTypeId(resultId)); }
161
John Kessenich5e4b1242015-08-06 22:53:06 -0600162 Dim getTypeDimensionality(Id typeId) const
John Kessenich140f3df2015-06-26 16:58:36 -0600163 {
John Kessenich5e4b1242015-08-06 22:53:06 -0600164 assert(isImageType(typeId));
165 return (Dim)module.getInstruction(typeId)->getImmediateOperand(1);
John Kessenich140f3df2015-06-26 16:58:36 -0600166 }
John Kessenich5e4b1242015-08-06 22:53:06 -0600167 Id getImageType(Id resultId) const
John Kessenich140f3df2015-06-26 16:58:36 -0600168 {
Rex Xu6b86d492015-09-16 17:48:22 +0800169 Id typeId = getTypeId(resultId);
170 assert(isImageType(typeId) || isSampledImageType(typeId));
171 return isSampledImageType(typeId) ? module.getInstruction(typeId)->getIdOperand(0) : typeId;
John Kessenich5e4b1242015-08-06 22:53:06 -0600172 }
173 bool isArrayedImageType(Id typeId) const
174 {
175 assert(isImageType(typeId));
176 return module.getInstruction(typeId)->getImmediateOperand(3) != 0;
John Kessenich140f3df2015-06-26 16:58:36 -0600177 }
178
179 // For making new constants (will return old constant if the requested one was already made).
John Kessenich55e7d112015-11-15 21:33:39 -0700180 Id makeBoolConstant(bool b, bool specConstant = false);
181 Id makeIntConstant(int i, bool specConstant = false) { return makeIntConstant(makeIntType(32), (unsigned)i, specConstant); }
182 Id makeUintConstant(unsigned u, bool specConstant = false) { return makeIntConstant(makeUintType(32), u, specConstant); }
183 Id makeFloatConstant(float f, bool specConstant = false);
184 Id makeDoubleConstant(double d, bool specConstant = false);
John Kessenich140f3df2015-06-26 16:58:36 -0600185
186 // Turn the array of constants into a proper spv constant of the requested type.
187 Id makeCompositeConstant(Id type, std::vector<Id>& comps);
188
189 // Methods for adding information outside the CFG.
John Kessenich55e7d112015-11-15 21:33:39 -0700190 Instruction* addEntryPoint(ExecutionModel, Function*, const char* name);
John Kessenichb56a26a2015-09-16 16:04:05 -0600191 void addExecutionMode(Function*, ExecutionMode mode, int value1 = -1, int value2 = -1, int value3 = -1);
John Kessenich140f3df2015-06-26 16:58:36 -0600192 void addName(Id, const char* name);
193 void addMemberName(Id, int member, const char* name);
194 void addLine(Id target, Id fileName, int line, int column);
195 void addDecoration(Id, Decoration, int num = -1);
196 void addMemberDecoration(Id, unsigned int member, Decoration, int num = -1);
197
198 // At the end of what block do the next create*() instructions go?
199 void setBuildPoint(Block* bp) { buildPoint = bp; }
200 Block* getBuildPoint() const { return buildPoint; }
201
202 // Make the main function.
203 Function* makeMain();
204
John Kessenich140f3df2015-06-26 16:58:36 -0600205 // Make a shader-style function, and create its entry block if entry is non-zero.
206 // Return the function, pass back the entry.
207 Function* makeFunctionEntry(Id returnType, const char* name, std::vector<Id>& paramTypes, Block **entry = 0);
208
John Kesseniche770b3e2015-09-14 20:58:02 -0600209 // Create a return. An 'implicit' return is one not appearing in the source
210 // code. In the case of an implicit return, no post-return block is inserted.
211 void makeReturn(bool implicit, Id retVal = 0);
John Kessenich140f3df2015-06-26 16:58:36 -0600212
213 // Generate all the code needed to finish up a function.
John Kesseniche770b3e2015-09-14 20:58:02 -0600214 void leaveFunction();
John Kessenich140f3df2015-06-26 16:58:36 -0600215
216 // Create a discard.
217 void makeDiscard();
218
219 // Create a global or function local or IO variable.
220 Id createVariable(StorageClass, Id type, const char* name = 0);
221
Miro Knejp28f9b1c2015-08-11 02:45:24 +0200222 // Create an imtermediate with an undefined value.
223 Id createUndefined(Id type);
224
John Kessenich140f3df2015-06-26 16:58:36 -0600225 // Store into an Id and return the l-value
226 void createStore(Id rValue, Id lValue);
227
228 // Load from an Id and return it
229 Id createLoad(Id lValue);
230
231 // Create an OpAccessChain instruction
232 Id createAccessChain(StorageClass, Id base, std::vector<Id>& offsets);
233
John Kessenichee21fc92015-09-21 21:50:29 -0600234 // Create an OpArrayLength instruction
235 Id createArrayLength(Id base, unsigned int member);
236
John Kessenich140f3df2015-06-26 16:58:36 -0600237 // Create an OpCompositeExtract instruction
238 Id createCompositeExtract(Id composite, Id typeId, unsigned index);
239 Id createCompositeExtract(Id composite, Id typeId, std::vector<unsigned>& indexes);
240 Id createCompositeInsert(Id object, Id composite, Id typeId, unsigned index);
241 Id createCompositeInsert(Id object, Id composite, Id typeId, std::vector<unsigned>& indexes);
242
243 Id createVectorExtractDynamic(Id vector, Id typeId, Id componentIndex);
244 Id createVectorInsertDynamic(Id vector, Id typeId, Id component, Id componentIndex);
245
246 void createNoResultOp(Op);
247 void createNoResultOp(Op, Id operand);
Rex Xufc618912015-09-09 16:42:49 +0800248 void createNoResultOp(Op, const std::vector<Id>& operands);
John Kessenich5e4b1242015-08-06 22:53:06 -0600249 void createControlBarrier(Scope execution, Scope memory, MemorySemanticsMask);
John Kessenich140f3df2015-06-26 16:58:36 -0600250 void createMemoryBarrier(unsigned executionScope, unsigned memorySemantics);
251 Id createUnaryOp(Op, Id typeId, Id operand);
252 Id createBinOp(Op, Id typeId, Id operand1, Id operand2);
253 Id createTriOp(Op, Id typeId, Id operand1, Id operand2, Id operand3);
John Kessenich5e4b1242015-08-06 22:53:06 -0600254 Id createOp(Op, Id typeId, const std::vector<Id>& operands);
John Kessenich140f3df2015-06-26 16:58:36 -0600255 Id createFunctionCall(spv::Function*, std::vector<spv::Id>&);
256
257 // Take an rvalue (source) and a set of channels to extract from it to
258 // make a new rvalue, which is returned.
259 Id createRvalueSwizzle(Id typeId, Id source, std::vector<unsigned>& channels);
260
261 // Take a copy of an lvalue (target) and a source of components, and set the
262 // source components into the lvalue where the 'channels' say to put them.
263 // An updated version of the target is returned.
264 // (No true lvalue or stores are used.)
265 Id createLvalueSwizzle(Id typeId, Id target, Id source, std::vector<unsigned>& channels);
266
267 // If the value passed in is an instruction and the precision is not EMpNone,
268 // it gets tagged with the requested precision.
269 void setPrecision(Id /* value */, Decoration /* precision */)
270 {
271 // TODO
272 }
273
274 // Can smear a scalar to a vector for the following forms:
275 // - promoteScalar(scalar, vector) // smear scalar to width of vector
276 // - promoteScalar(vector, scalar) // smear scalar to width of vector
277 // - promoteScalar(pointer, scalar) // smear scalar to width of what pointer points to
278 // - promoteScalar(scalar, scalar) // do nothing
279 // Other forms are not allowed.
280 //
281 // Note: One of the arguments will change, with the result coming back that way rather than
282 // through the return value.
283 void promoteScalar(Decoration precision, Id& left, Id& right);
284
285 // make a value by smearing the scalar to fill the type
286 Id smearScalar(Decoration precision, Id scalarVal, Id);
287
288 // Create a call to a built-in function.
289 Id createBuiltinCall(Decoration precision, Id resultType, Id builtins, int entryPoint, std::vector<Id>& args);
290
291 // List of parameters used to create a texture operation
292 struct TextureParameters {
293 Id sampler;
294 Id coords;
295 Id bias;
296 Id lod;
297 Id Dref;
298 Id offset;
John Kessenich5e4b1242015-08-06 22:53:06 -0600299 Id offsets;
John Kessenich140f3df2015-06-26 16:58:36 -0600300 Id gradX;
301 Id gradY;
John Kessenich5e4b1242015-08-06 22:53:06 -0600302 Id sample;
John Kessenich55e7d112015-11-15 21:33:39 -0700303 Id comp;
John Kessenich140f3df2015-06-26 16:58:36 -0600304 };
305
306 // Select the correct texture operation based on all inputs, and emit the correct instruction
John Kessenich55e7d112015-11-15 21:33:39 -0700307 Id createTextureCall(Decoration precision, Id resultType, bool fetch, bool proj, bool gather, const TextureParameters&);
John Kessenich140f3df2015-06-26 16:58:36 -0600308
309 // Emit the OpTextureQuery* instruction that was passed in.
310 // Figure out the right return value and type, and return it.
311 Id createTextureQueryCall(Op, const TextureParameters&);
312
313 Id createSamplePositionCall(Decoration precision, Id, Id);
314
315 Id createBitFieldExtractCall(Decoration precision, Id, Id, Id, bool isSigned);
316 Id createBitFieldInsertCall(Decoration precision, Id, Id, Id, Id);
317
318 // Reduction comparision for composites: For equal and not-equal resulting in a scalar.
319 Id createCompare(Decoration precision, Id, Id, bool /* true if for equal, fales if for not-equal */);
320
321 // OpCompositeConstruct
322 Id createCompositeConstruct(Id typeId, std::vector<Id>& constituents);
323
324 // vector or scalar constructor
325 Id createConstructor(Decoration precision, const std::vector<Id>& sources, Id resultTypeId);
326
327 // matrix constructor
328 Id createMatrixConstructor(Decoration precision, const std::vector<Id>& sources, Id constructee);
329
330 // Helper to use for building nested control flow with if-then-else.
331 class If {
332 public:
333 If(Id condition, Builder& builder);
334 ~If() {}
335
336 void makeBeginElse();
337 void makeEndIf();
338
339 private:
340 If(const If&);
341 If& operator=(If&);
342
343 Builder& builder;
344 Id condition;
345 Function* function;
346 Block* headerBlock;
347 Block* thenBlock;
348 Block* elseBlock;
349 Block* mergeBlock;
350 };
351
352 // Make a switch statement. A switch has 'numSegments' of pieces of code, not containing
353 // any case/default labels, all separated by one or more case/default labels. Each possible
354 // case value v is a jump to the caseValues[v] segment. The defaultSegment is also in this
355 // number space. How to compute the value is given by 'condition', as in switch(condition).
356 //
357 // The SPIR-V Builder will maintain the stack of post-switch merge blocks for nested switches.
358 //
359 // Use a defaultSegment < 0 if there is no default segment (to branch to post switch).
360 //
361 // Returns the right set of basic blocks to start each code segment with, so that the caller's
362 // recursion stack can hold the memory for it.
363 //
364 void makeSwitch(Id condition, int numSegments, std::vector<int>& caseValues, std::vector<int>& valueToSegment, int defaultSegment,
365 std::vector<Block*>& segmentBB); // return argument
366
367 // Add a branch to the innermost switch's merge block.
368 void addSwitchBreak();
369
370 // Move to the next code segment, passing in the return argument in makeSwitch()
371 void nextSwitchSegment(std::vector<Block*>& segmentBB, int segment);
372
373 // Finish off the innermost switch.
374 void endSwitch(std::vector<Block*>& segmentBB);
375
David Netoc22f37c2015-07-15 16:21:26 -0400376 // Start the beginning of a new loop, and prepare the builder to
377 // generate code for the loop test.
378 // The loopTestFirst parameter is true when the loop test executes before
379 // the body. (It is false for do-while loops.)
380 void makeNewLoop(bool loopTestFirst);
Dejan Mircevski9c6734c2016-01-10 12:15:13 -0500381 struct LoopBlocks {
382 Block &body, &merge, &continue_target;
383 };
384 LoopBlocks makeNewLoop();
385
386 // Create a new block in the function containing the build point.
387 Block& makeNewBlock();
John Kessenich140f3df2015-06-26 16:58:36 -0600388
389 // Add the branch for the loop test, based on the given condition.
David Netoc22f37c2015-07-15 16:21:26 -0400390 // The true branch goes to the first block in the loop body, and
391 // the false branch goes to the loop's merge block. The builder insertion
392 // point will be placed at the start of the body.
John Kessenich140f3df2015-06-26 16:58:36 -0600393 void createLoopTestBranch(Id condition);
394
David Netoc22f37c2015-07-15 16:21:26 -0400395 // Generate an unconditional branch to the loop body. The builder insertion
396 // point will be placed at the start of the body. Use this when there is
397 // no loop test.
398 void createBranchToBody();
John Kessenich140f3df2015-06-26 16:58:36 -0600399
400 // Add a branch to the test of the current (innermost) loop.
David Netoc22f37c2015-07-15 16:21:26 -0400401 // The way we generate code, that's also the loop header.
John Kessenich140f3df2015-06-26 16:58:36 -0600402 void createLoopContinue();
403
404 // Add an exit (e.g. "break") for the innermost loop that you're in
405 void createLoopExit();
406
407 // Close the innermost loop that you're in
408 void closeLoop();
409
410 //
411 // Access chain design for an R-Value vs. L-Value:
412 //
413 // There is a single access chain the builder is building at
414 // any particular time. Such a chain can be used to either to a load or
415 // a store, when desired.
416 //
417 // Expressions can be r-values, l-values, or both, or only r-values:
418 // a[b.c].d = .... // l-value
419 // ... = a[b.c].d; // r-value, that also looks like an l-value
420 // ++a[b.c].d; // r-value and l-value
421 // (x + y)[2]; // r-value only, can't possibly be l-value
422 //
423 // Computing an r-value means generating code. Hence,
424 // r-values should only be computed when they are needed, not speculatively.
425 //
426 // Computing an l-value means saving away information for later use in the compiler,
427 // no code is generated until the l-value is later dereferenced. It is okay
428 // to speculatively generate an l-value, just not okay to speculatively dereference it.
429 //
430 // The base of the access chain (the left-most variable or expression
431 // from which everything is based) can be set either as an l-value
432 // or as an r-value. Most efficient would be to set an l-value if one
433 // is available. If an expression was evaluated, the resulting r-value
434 // can be set as the chain base.
435 //
436 // The users of this single access chain can save and restore if they
437 // want to nest or manage multiple chains.
438 //
439
440 struct AccessChain {
John Kessenich55e7d112015-11-15 21:33:39 -0700441 Id base; // for l-values, pointer to the base object, for r-values, the base object
John Kessenich140f3df2015-06-26 16:58:36 -0600442 std::vector<Id> indexChain;
John Kessenich55e7d112015-11-15 21:33:39 -0700443 Id instr; // cache the instruction that generates this access chain
444 std::vector<unsigned> swizzle; // each std::vector element selects the next GLSL component number
445 Id component; // a dynamic component index, can coexist with a swizzle, done after the swizzle, NoResult if not present
446 Id preSwizzleBaseType; // dereferenced type, before swizzle or component is applied; NoType unless a swizzle or component is present
447 bool isRValue; // true if 'base' is an r-value, otherwise, base is an l-value
John Kessenich140f3df2015-06-26 16:58:36 -0600448 };
449
450 //
451 // the SPIR-V builder maintains a single active chain that
452 // the following methods operated on
453 //
454
455 // for external save and restore
456 AccessChain getAccessChain() { return accessChain; }
457 void setAccessChain(AccessChain newChain) { accessChain = newChain; }
458
459 // clear accessChain
460 void clearAccessChain();
461
462 // set new base as an l-value base
463 void setAccessChainLValue(Id lValue)
464 {
465 assert(isPointer(lValue));
466 accessChain.base = lValue;
John Kessenich140f3df2015-06-26 16:58:36 -0600467 }
468
469 // set new base value as an r-value
470 void setAccessChainRValue(Id rValue)
471 {
472 accessChain.isRValue = true;
473 accessChain.base = rValue;
John Kessenich140f3df2015-06-26 16:58:36 -0600474 }
475
476 // push offset onto the end of the chain
John Kessenichfa668da2015-09-13 14:46:30 -0600477 void accessChainPush(Id offset)
John Kessenich140f3df2015-06-26 16:58:36 -0600478 {
479 accessChain.indexChain.push_back(offset);
John Kessenich140f3df2015-06-26 16:58:36 -0600480 }
481
482 // push new swizzle onto the end of any existing swizzle, merging into a single swizzle
John Kessenichfa668da2015-09-13 14:46:30 -0600483 void accessChainPushSwizzle(std::vector<unsigned>& swizzle, Id preSwizzleBaseType);
John Kessenich140f3df2015-06-26 16:58:36 -0600484
485 // push a variable component selection onto the access chain; supporting only one, so unsided
John Kessenichfa668da2015-09-13 14:46:30 -0600486 void accessChainPushComponent(Id component, Id preSwizzleBaseType)
487 {
488 accessChain.component = component;
489 if (accessChain.preSwizzleBaseType == NoType)
490 accessChain.preSwizzleBaseType = preSwizzleBaseType;
491 }
John Kessenich140f3df2015-06-26 16:58:36 -0600492
493 // use accessChain and swizzle to store value
494 void accessChainStore(Id rvalue);
495
496 // use accessChain and swizzle to load an r-value
John Kessenichfa668da2015-09-13 14:46:30 -0600497 Id accessChainLoad(Id ResultType);
John Kessenich140f3df2015-06-26 16:58:36 -0600498
499 // get the direct pointer for an l-value
500 Id accessChainGetLValue();
501
502 void dump(std::vector<unsigned int>&) const;
503
Dejan Mircevski9c6734c2016-01-10 12:15:13 -0500504 void createBranch(Block* block);
505 void createConditionalBranch(Id condition, Block* thenBlock, Block* elseBlock);
506 void createLoopMerge(Block* mergeBlock, Block* continueBlock, unsigned int control);
507
508 protected:
John Kessenich55e7d112015-11-15 21:33:39 -0700509 Id makeIntConstant(Id typeId, unsigned value, bool specConstant);
510 Id findScalarConstant(Op typeClass, Op opcode, Id typeId, unsigned value) const;
511 Id findScalarConstant(Op typeClass, Op opcode, Id typeId, unsigned v1, unsigned v2) const;
John Kessenich140f3df2015-06-26 16:58:36 -0600512 Id findCompositeConstant(Op typeClass, std::vector<Id>& comps) const;
513 Id collapseAccessChain();
John Kessenich55e7d112015-11-15 21:33:39 -0700514 void transferAccessChainSwizzle(bool dynamic);
John Kessenich140f3df2015-06-26 16:58:36 -0600515 void simplifyAccessChainSwizzle();
John Kessenich140f3df2015-06-26 16:58:36 -0600516 void createAndSetNoPredecessorBlock(const char*);
John Kessenich55e7d112015-11-15 21:33:39 -0700517 void createSelectionMerge(Block* mergeBlock, unsigned int control);
John Kessenich140f3df2015-06-26 16:58:36 -0600518 void dumpInstructions(std::vector<unsigned int>&, const std::vector<Instruction*>&) const;
519
David Netoc22f37c2015-07-15 16:21:26 -0400520 struct Loop; // Defined below.
521 void createBranchToLoopHeaderFromInside(const Loop& loop);
522
John Kessenich140f3df2015-06-26 16:58:36 -0600523 SourceLanguage source;
524 int sourceVersion;
525 std::vector<const char*> extensions;
526 AddressingModel addressModel;
527 MemoryModel memoryModel;
John Kessenich5e4b1242015-08-06 22:53:06 -0600528 std::vector<spv::Capability> capabilities;
John Kessenich140f3df2015-06-26 16:58:36 -0600529 int builderNumber;
530 Module module;
531 Block* buildPoint;
532 Id uniqueId;
533 Function* mainFunction;
John Kessenich140f3df2015-06-26 16:58:36 -0600534 AccessChain accessChain;
535
536 // special blocks of instructions for output
537 std::vector<Instruction*> imports;
538 std::vector<Instruction*> entryPoints;
539 std::vector<Instruction*> executionModes;
540 std::vector<Instruction*> names;
541 std::vector<Instruction*> lines;
542 std::vector<Instruction*> decorations;
543 std::vector<Instruction*> constantsTypesGlobals;
544 std::vector<Instruction*> externals;
545
546 // not output, internally used for quick & dirty canonical (unique) creation
547 std::vector<Instruction*> groupedConstants[OpConstant]; // all types appear before OpConstant
548 std::vector<Instruction*> groupedTypes[OpConstant];
549
550 // stack of switches
551 std::stack<Block*> switchMerges;
552
553 // Data that needs to be kept in order to properly handle loops.
554 struct Loop {
David Neto3e6a33c2015-07-17 17:11:22 -0400555 // Constructs a default Loop structure containing new header, merge, and
556 // body blocks for the current function.
557 // The testFirst argument indicates whether the loop test executes at
558 // the top of the loop rather than at the bottom. In the latter case,
559 // also create a phi instruction whose value indicates whether we're on
560 // the first iteration of the loop. The phi instruction is initialized
561 // with no values or predecessor operands.
562 Loop(Builder& builder, bool testFirst);
David Neto3e6a33c2015-07-17 17:11:22 -0400563
564 // The function containing the loop.
565 Function* const function;
John Kessenich140f3df2015-06-26 16:58:36 -0600566 // The header is the first block generated for the loop.
567 // It dominates all the blocks in the loop, i.e. it is always
568 // executed before any others.
569 // If the loop test is executed before the body (as in "while" and
570 // "for" loops), then the header begins with the test code.
571 // Otherwise, the loop is a "do-while" loop and the header contains the
572 // start of the body of the loop (if the body exists).
David Neto3e6a33c2015-07-17 17:11:22 -0400573 Block* const header;
John Kessenich140f3df2015-06-26 16:58:36 -0600574 // The merge block marks the end of the loop. Control is transferred
575 // to the merge block when either the loop test fails, or when a
576 // nested "break" is encountered.
David Neto3e6a33c2015-07-17 17:11:22 -0400577 Block* const merge;
David Netoc22f37c2015-07-15 16:21:26 -0400578 // The body block is the first basic block in the body of the loop, i.e.
579 // the code that is to be repeatedly executed, aside from loop control.
580 // This member is null until we generate code that references the loop
581 // body block.
David Neto3e6a33c2015-07-17 17:11:22 -0400582 Block* const body;
David Netoc22f37c2015-07-15 16:21:26 -0400583 // True when the loop test executes before the body.
David Neto3e6a33c2015-07-17 17:11:22 -0400584 const bool testFirst;
David Netoc22f37c2015-07-15 16:21:26 -0400585 // When the test executes after the body, this is defined as the phi
586 // instruction that tells us whether we are on the first iteration of
Andrew Woloszyn2d83ab22015-09-18 16:12:03 -0400587 // the loop. Otherwise this is null. This is non-const because
588 // it has to be initialized outside of the initializer-list.
589 Instruction* isFirstIteration;
John Kessenich140f3df2015-06-26 16:58:36 -0600590 };
591
592 // Our loop stack.
593 std::stack<Loop> loops;
594}; // end Builder class
595
John Kessenich426394d2015-07-23 10:22:48 -0600596// Use for non-fatal notes about what's not complete
597void TbdFunctionality(const char*);
598
599// Use for fatal missing functionality
John Kessenich140f3df2015-06-26 16:58:36 -0600600void MissingFunctionality(const char*);
John Kessenich140f3df2015-06-26 16:58:36 -0600601
602}; // end spv namespace
603
604#endif // SpvBuilder_H