John Kessenich | 0df0cde | 2015-03-03 17:09:43 +0000 | [diff] [blame] | 1 | //
|
| 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 |
|
| 51 | #include "spirv.h"
|
| 52 | #include "spvIR.h"
|
| 53 |
|
| 54 | #include <algorithm>
|
| 55 | #include <stack>
|
| 56 | #include <map>
|
| 57 |
|
| 58 | namespace spv {
|
| 59 |
|
| 60 | class Builder {
|
| 61 | public:
|
| 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 |
|
| 80 | // To get a new <id> for anything needing a new one.
|
| 81 | Id getUniqueId() { return ++uniqueId; }
|
| 82 |
|
| 83 | // To get a set of new <id>s, e.g., for a set of function parameters
|
| 84 | Id getUniqueIds(int numIds)
|
| 85 | {
|
| 86 | Id id = uniqueId + 1;
|
| 87 | uniqueId += numIds;
|
| 88 | return id;
|
| 89 | }
|
| 90 |
|
| 91 | // For creating new types (will return old type if the requested one was already made).
|
| 92 | Id makeVoidType();
|
| 93 | Id makeBoolType();
|
| 94 | Id makePointer(StorageClass, Id type);
|
| 95 | Id makeIntegerType(int width, bool hasSign); // generic
|
| 96 | Id makeIntType(int width) { return makeIntegerType(width, true); }
|
| 97 | Id makeUintType(int width) { return makeIntegerType(width, false); }
|
| 98 | Id makeFloatType(int width);
|
| 99 | Id makeStructType(std::vector<Id>& members, const char*);
|
| 100 | Id makeVectorType(Id component, int size);
|
| 101 | Id makeMatrixType(Id component, int cols, int rows);
|
| 102 | Id makeArrayType(Id element, unsigned size);
|
| 103 | Id makeFunctionType(Id returnType, std::vector<Id>& paramTypes);
|
| 104 | enum samplerContent {
|
| 105 | samplerContentTexture,
|
| 106 | samplerContentImage,
|
| 107 | samplerContentTextureFilter
|
| 108 | };
|
John Kessenich | b40d6ac | 2015-03-30 17:41:16 +0000 | [diff] [blame] | 109 | Id makeSampler(Id sampledType, Dim, samplerContent, bool arrayed, bool shadow, bool ms);
|
John Kessenich | 0df0cde | 2015-03-03 17:09:43 +0000 | [diff] [blame] | 110 |
|
| 111 | // For querying about types.
|
| 112 | Id getTypeId(Id resultId) const { return module.getTypeId(resultId); }
|
| 113 | Id getDerefTypeId(Id resultId) const;
|
John Kessenich | b40d6ac | 2015-03-30 17:41:16 +0000 | [diff] [blame] | 114 | Op getOpCode(Id id) const { return module.getInstruction(id)->getOpCode(); }
|
| 115 | Op getTypeClass(Id typeId) const { return getOpCode(typeId); }
|
| 116 | Op getMostBasicTypeClass(Id typeId) const;
|
John Kessenich | 0df0cde | 2015-03-03 17:09:43 +0000 | [diff] [blame] | 117 | int getNumComponents(Id resultId) const { return getNumTypeComponents(getTypeId(resultId)); }
|
| 118 | int getNumTypeComponents(Id typeId) const;
|
| 119 | Id getScalarTypeId(Id typeId) const;
|
| 120 | Id getContainedTypeId(Id typeId) const;
|
| 121 | Id getContainedTypeId(Id typeId, int) const;
|
| 122 |
|
| 123 | bool isPointer(Id resultId) const { return isPointerType(getTypeId(resultId)); }
|
| 124 | bool isScalar(Id resultId) const { return isScalarType(getTypeId(resultId)); }
|
| 125 | bool isVector(Id resultId) const { return isVectorType(getTypeId(resultId)); }
|
| 126 | bool isMatrix(Id resultId) const { return isMatrixType(getTypeId(resultId)); }
|
| 127 | bool isAggregate(Id resultId) const { return isAggregateType(getTypeId(resultId)); }
|
| 128 |
|
| 129 | bool isPointerType(Id typeId) const { return getTypeClass(typeId) == OpTypePointer; }
|
| 130 | bool isScalarType(Id typeId) const { return getTypeClass(typeId) == OpTypeFloat || getTypeClass(typeId) == OpTypeInt || getTypeClass(typeId) == OpTypeBool; }
|
| 131 | bool isVectorType(Id typeId) const { return getTypeClass(typeId) == OpTypeVector; }
|
| 132 | bool isMatrixType(Id typeId) const { return getTypeClass(typeId) == OpTypeMatrix; }
|
| 133 | bool isStructType(Id typeId) const { return getTypeClass(typeId) == OpTypeStruct; }
|
| 134 | bool isArrayType(Id typeId) const { return getTypeClass(typeId) == OpTypeArray; }
|
| 135 | bool isAggregateType(Id typeId) const { return isArrayType(typeId) || isStructType(typeId); }
|
| 136 | bool isSamplerType(Id typeId) const { return getTypeClass(typeId) == OpTypeSampler; }
|
| 137 |
|
| 138 | bool isConstantScalar(Id resultId) const { return getOpCode(resultId) == OpConstant; }
|
| 139 | unsigned int getConstantScalar(Id resultId) const { return module.getInstruction(resultId)->getImmediateOperand(0); }
|
| 140 |
|
| 141 | int getTypeNumColumns(Id typeId) const
|
| 142 | {
|
| 143 | assert(isMatrixType(typeId));
|
| 144 | return getNumTypeComponents(typeId);
|
| 145 | }
|
| 146 | int getNumColumns(Id resultId) const { return getTypeNumColumns(getTypeId(resultId)); }
|
| 147 | int getTypeNumRows(Id typeId) const
|
| 148 | {
|
| 149 | assert(isMatrixType(typeId));
|
| 150 | return getNumTypeComponents(getContainedTypeId(typeId));
|
| 151 | }
|
| 152 | int getNumRows(Id resultId) const { return getTypeNumRows(getTypeId(resultId)); }
|
| 153 |
|
John Kessenich | b40d6ac | 2015-03-30 17:41:16 +0000 | [diff] [blame] | 154 | Dim getDimensionality(Id resultId) const
|
John Kessenich | 0df0cde | 2015-03-03 17:09:43 +0000 | [diff] [blame] | 155 | {
|
| 156 | assert(isSamplerType(getTypeId(resultId)));
|
John Kessenich | b40d6ac | 2015-03-30 17:41:16 +0000 | [diff] [blame] | 157 | return (Dim)module.getInstruction(getTypeId(resultId))->getImmediateOperand(1);
|
John Kessenich | 0df0cde | 2015-03-03 17:09:43 +0000 | [diff] [blame] | 158 | }
|
| 159 | bool isArrayedSampler(Id resultId) const
|
| 160 | {
|
| 161 | assert(isSamplerType(getTypeId(resultId)));
|
| 162 | return module.getInstruction(getTypeId(resultId))->getImmediateOperand(3) != 0;
|
| 163 | }
|
| 164 |
|
| 165 | // For making new constants (will return old constant if the requested one was already made).
|
| 166 | Id makeBoolConstant(bool b);
|
| 167 | Id makeIntConstant(Id typeId, unsigned value);
|
| 168 | Id makeIntConstant(int i) { return makeIntConstant(makeIntType(32), (unsigned)i); }
|
| 169 | Id makeUintConstant(unsigned u) { return makeIntConstant(makeUintType(32), u); }
|
| 170 | Id makeFloatConstant(float f);
|
| 171 | Id makeDoubleConstant(double d);
|
| 172 |
|
| 173 | // Turn the array of constants into a proper spv constant of the requested type.
|
| 174 | Id makeCompositeConstant(Id type, std::vector<Id>& comps);
|
| 175 |
|
| 176 | // Methods for adding information outside the CFG.
|
| 177 | void addEntryPoint(ExecutionModel, Function*);
|
| 178 | void addExecutionMode(Function*, ExecutionMode mode, int value = -1);
|
| 179 | void addName(Id, const char* name);
|
| 180 | void addMemberName(Id, int member, const char* name);
|
| 181 | void addLine(Id target, Id fileName, int line, int column);
|
| 182 | void addDecoration(Id, Decoration, int num = -1);
|
| 183 | void addMemberDecoration(Id, unsigned int member, Decoration, int num = -1);
|
| 184 |
|
| 185 | // At the end of what block do the next create*() instructions go?
|
| 186 | void setBuildPoint(Block* bp) { buildPoint = bp; }
|
| 187 | Block* getBuildPoint() const { return buildPoint; }
|
| 188 |
|
| 189 | // Make the main function.
|
| 190 | Function* makeMain();
|
| 191 |
|
| 192 | // Return from main. Implicit denotes a return at the very end of main.
|
| 193 | void makeMainReturn(bool implicit = false) { makeReturn(implicit, 0, true); }
|
| 194 |
|
| 195 | // Close the main function.
|
| 196 | void closeMain();
|
| 197 |
|
| 198 | // Make a shader-style function, and create its entry block if entry is non-zero.
|
| 199 | // Return the function, pass back the entry.
|
| 200 | Function* makeFunctionEntry(Id returnType, const char* name, std::vector<Id>& paramTypes, Block **entry = 0);
|
| 201 |
|
| 202 | // Create a return. Pass whether it is a return form main, and the return
|
| 203 | // value (if applicable). In the case of an implicit return, no post-return
|
| 204 | // block is inserted.
|
| 205 | void makeReturn(bool implicit = false, Id retVal = 0, bool isMain = false);
|
| 206 |
|
| 207 | // Generate all the code needed to finish up a function.
|
| 208 | void leaveFunction(bool main);
|
| 209 |
|
| 210 | // Create a discard.
|
| 211 | void makeDiscard();
|
| 212 |
|
| 213 | // Create a global or function local or IO variable.
|
| 214 | Id createVariable(StorageClass, Id type, const char* name = 0);
|
| 215 |
|
| 216 | // Store into an Id and return the l-value
|
| 217 | void createStore(Id rValue, Id lValue);
|
| 218 |
|
| 219 | // Load from an Id and return it
|
| 220 | Id createLoad(Id lValue);
|
| 221 |
|
| 222 | // Create an OpAccessChain instruction
|
| 223 | Id createAccessChain(StorageClass, Id base, std::vector<Id>& offsets);
|
| 224 |
|
| 225 | // Create an OpCompositeExtract instruction
|
| 226 | Id createCompositeExtract(Id composite, Id typeId, unsigned index);
|
| 227 | Id createCompositeExtract(Id composite, Id typeId, std::vector<unsigned>& indexes);
|
| 228 | Id createCompositeInsert(Id object, Id composite, Id typeId, unsigned index);
|
| 229 | Id createCompositeInsert(Id object, Id composite, Id typeId, std::vector<unsigned>& indexes);
|
| 230 |
|
John Kessenich | b40d6ac | 2015-03-30 17:41:16 +0000 | [diff] [blame] | 231 | void createNoResultOp(Op);
|
| 232 | void createNoResultOp(Op, Id operand);
|
John Kessenich | 0df0cde | 2015-03-03 17:09:43 +0000 | [diff] [blame] | 233 | void createControlBarrier(unsigned executionScope);
|
| 234 | void createMemoryBarrier(unsigned executionScope, unsigned memorySemantics);
|
John Kessenich | b40d6ac | 2015-03-30 17:41:16 +0000 | [diff] [blame] | 235 | Id createUnaryOp(Op, Id typeId, Id operand);
|
| 236 | Id createBinOp(Op, Id typeId, Id operand1, Id operand2);
|
| 237 | Id createTriOp(Op, Id typeId, Id operand1, Id operand2, Id operand3);
|
| 238 | Id createTernaryOp(Op, Id typeId, Id operand1, Id operand2, Id operand3);
|
John Kessenich | 0df0cde | 2015-03-03 17:09:43 +0000 | [diff] [blame] | 239 | Id createFunctionCall(spv::Function*, std::vector<spv::Id>&);
|
| 240 |
|
| 241 | // Take an rvalue (source) and a set of channels to extract from it to
|
| 242 | // make a new rvalue, which is returned.
|
| 243 | Id createRvalueSwizzle(Id typeId, Id source, std::vector<unsigned>& channels);
|
| 244 |
|
| 245 | // Take a copy of an lvalue (target) and a source of components, and set the
|
| 246 | // source components into the lvalue where the 'channels' say to put them.
|
| 247 | // An update version of the target is returned.
|
| 248 | // (No true lvalue or stores are used.)
|
| 249 | Id createLvalueSwizzle(Id typeId, Id target, Id source, std::vector<unsigned>& channels);
|
| 250 |
|
| 251 | // If the value passed in is an instruction and the precision is not EMpNone,
|
| 252 | // it gets tagged with the requested precision.
|
| 253 | void setPrecision(Id value, Decoration precision)
|
| 254 | {
|
| 255 | // TODO
|
| 256 | }
|
| 257 |
|
| 258 | // Can smear a scalar to a vector for the following forms:
|
| 259 | // - promoteScalar(scalar, vector) // smear scalar to width of vector
|
| 260 | // - promoteScalar(vector, scalar) // smear scalar to width of vector
|
| 261 | // - promoteScalar(pointer, scalar) // smear scalar to width of what pointer points to
|
| 262 | // - promoteScalar(scalar, scalar) // do nothing
|
| 263 | // Other forms are not allowed.
|
| 264 | //
|
| 265 | // Note: One of the arguments will change, with the result coming back that way rather than
|
| 266 | // through the return value.
|
| 267 | void promoteScalar(Decoration precision, Id& left, Id& right);
|
| 268 |
|
| 269 | // make a value by smearing the scalar to fill the type
|
| 270 | Id smearScalar(Decoration precision, Id scalarVal, Id);
|
| 271 |
|
| 272 | // Create a call to a built-in function.
|
| 273 | Id createBuiltinCall(Decoration precision, Id resultType, Id builtins, int entryPoint, std::vector<Id>& args);
|
| 274 |
|
| 275 | // List of parameters used to create a texture operation
|
| 276 | struct TextureParameters {
|
| 277 | Id sampler;
|
| 278 | Id coords;
|
| 279 | Id bias;
|
| 280 | Id lod;
|
| 281 | Id Dref;
|
| 282 | Id offset;
|
| 283 | Id gradX;
|
| 284 | Id gradY;
|
| 285 | };
|
| 286 |
|
| 287 | // Select the correct texture operation based on all inputs, and emit the correct instruction
|
| 288 | Id createTextureCall(Decoration precision, Id resultType, bool proj, const TextureParameters&);
|
| 289 |
|
| 290 | // Emit the OpTextureQuery* instruction that was passed in.
|
| 291 | // Figure out the right return value and type, and return it.
|
John Kessenich | b40d6ac | 2015-03-30 17:41:16 +0000 | [diff] [blame] | 292 | Id createTextureQueryCall(Op, const TextureParameters&);
|
John Kessenich | 0df0cde | 2015-03-03 17:09:43 +0000 | [diff] [blame] | 293 |
|
| 294 | Id createSamplePositionCall(Decoration precision, Id, Id);
|
| 295 |
|
| 296 | Id createBitFieldExtractCall(Decoration precision, Id, Id, Id, bool isSigned);
|
| 297 | Id createBitFieldInsertCall(Decoration precision, Id, Id, Id, Id);
|
| 298 |
|
| 299 | // Reduction comparision for composites: For equal and not-equal resulting in a scalar.
|
| 300 | Id createCompare(Decoration precision, Id, Id, bool /* true if for equal, fales if for not-equal */);
|
| 301 |
|
| 302 | // OpCompositeConstruct
|
| 303 | Id createCompositeConstruct(Id typeId, std::vector<Id>& constituents);
|
| 304 |
|
| 305 | // vector or scalar constructor
|
| 306 | Id createConstructor(Decoration precision, const std::vector<Id>& sources, Id resultTypeId);
|
| 307 |
|
| 308 | // matrix constructor
|
| 309 | Id createMatrixConstructor(Decoration precision, const std::vector<Id>& sources, Id constructee);
|
| 310 |
|
| 311 | // Helper to use for building nested control flow with if-then-else.
|
| 312 | class If {
|
| 313 | public:
|
| 314 | If(Id condition, Builder& builder);
|
| 315 | ~If() {}
|
| 316 |
|
| 317 | void makeBeginElse();
|
| 318 | void makeEndIf();
|
| 319 |
|
| 320 | private:
|
| 321 | Builder& builder;
|
| 322 | Id condition;
|
| 323 | Function* function;
|
| 324 | Block* headerBlock;
|
| 325 | Block* thenBlock;
|
| 326 | Block* elseBlock;
|
| 327 | Block* mergeBlock;
|
| 328 | };
|
| 329 |
|
| 330 | // Make a switch statement. A switch has 'numSegments' of pieces of code, not containing
|
| 331 | // any case/default labels, all separated by one or more case/default labels. Each possible
|
| 332 | // case value v is a jump to the caseValues[v] segment. The defaultSegment is also in this
|
| 333 | // number space. How to compute the value is given by 'condition', as in switch(condition).
|
| 334 | //
|
| 335 | // The SPIR-V Builder will maintain the stack of post-switch merge blocks for nested switches.
|
| 336 | //
|
| 337 | // Use a defaultSegment < 0 if there is no default segment (to branch to post switch).
|
| 338 | //
|
| 339 | // Returns the right set of basic blocks to start each code segment with, so that the caller's
|
| 340 | // recursion stack can hold the memory for it.
|
| 341 | //
|
| 342 | void makeSwitch(Id condition, int numSegments, std::vector<int>& caseValues, std::vector<int>& valueToSegment, int defaultSegment,
|
| 343 | std::vector<Block*>& segmentBB); // return argument
|
| 344 |
|
| 345 | // Add a branch to the innermost switch's merge block.
|
| 346 | void addSwitchBreak();
|
| 347 |
|
| 348 | // Move to the next code segment, passing in the return argument in makeSwitch()
|
| 349 | void nextSwitchSegment(std::vector<Block*>& segmentBB, int segment);
|
| 350 |
|
| 351 | // Finish off the innermost switch.
|
| 352 | void endSwitch(std::vector<Block*>& segmentBB);
|
| 353 |
|
| 354 | // Start the beginning of a new loop.
|
| 355 | void makeNewLoop();
|
| 356 |
|
| 357 | // Add the branch at the end of the loop header, and leave the build position
|
| 358 | // in the first block of the body.
|
| 359 | // 'condition' is true if should exit the loop
|
| 360 | void createLoopHeaderBranch(Id condition);
|
| 361 |
|
| 362 | // Add a back-edge (e.g "continue") for the innermost loop that you're in
|
| 363 | void createLoopBackEdge(bool implicit=false);
|
| 364 |
|
| 365 | // Add an exit (e.g. "break") for the innermost loop that you're in
|
| 366 | void createLoopExit();
|
| 367 |
|
| 368 | // Close the innermost loop that you're in
|
| 369 | void closeLoop();
|
| 370 |
|
| 371 | //
|
| 372 | // Access chain design for an R-Value vs. L-Value:
|
| 373 | //
|
| 374 | // There is a single access chain the builder is building at
|
| 375 | // any particular time. Such a chain can be used to either to a load or
|
| 376 | // a store, when desired.
|
| 377 | //
|
| 378 | // Expressions can be r-values, l-values, or both, or only r-values:
|
| 379 | // a[b.c].d = .... // l-value
|
| 380 | // ... = a[b.c].d; // r-value, that also looks like an l-value
|
| 381 | // ++a[b.c].d; // r-value and l-value
|
| 382 | // (x + y)[2]; // r-value only, can't possibly be l-value
|
| 383 | //
|
| 384 | // Computing an r-value means generating code. Hence,
|
| 385 | // r-values should only be computed when they are needed, not speculatively.
|
| 386 | //
|
| 387 | // Computing an l-value means saving away information for later use in the compiler,
|
| 388 | // no code is generated until the l-value is later dereferenced. It is okay
|
| 389 | // to speculatively generate an l-value, just not okay to speculatively dereference it.
|
| 390 | //
|
| 391 | // The base of the access chain (the left-most variable or expression
|
| 392 | // from which everything is based) can be set either as an l-value
|
| 393 | // or as an r-value. Most efficient would be to set an l-value if one
|
| 394 | // is available. If an expression was evaluated, the resulting r-value
|
| 395 | // can be set as the chain base.
|
| 396 | //
|
| 397 | // The users of this single access chain can save and restore if they
|
| 398 | // want to nest or manage multiple chains.
|
| 399 | //
|
| 400 |
|
| 401 | struct AccessChain {
|
| 402 | Id base; // for l-values, pointer to the base object, for r-values, the base object
|
| 403 | std::vector<Id> indexChain;
|
| 404 | Id instr; // the instruction that generates this access chain
|
| 405 | std::vector<unsigned> swizzle;
|
| 406 | Id component; // a dynamic component index
|
| 407 | int swizzleTargetWidth;
|
| 408 | Id resultType; // dereferenced type, to be inclusive of swizzles, which can't have a pointer
|
| 409 | bool isRValue;
|
| 410 | };
|
| 411 |
|
| 412 | //
|
| 413 | // the SPIR-V builder maintains a single active chain that
|
| 414 | // the following methods operated on
|
| 415 | //
|
| 416 |
|
| 417 | // for external save and restore
|
| 418 | AccessChain getAccessChain() { return accessChain; }
|
| 419 | void setAccessChain(AccessChain newChain) { accessChain = newChain; }
|
| 420 |
|
| 421 | // clear accessChain
|
| 422 | void clearAccessChain();
|
| 423 |
|
| 424 | // set new base as an l-value base
|
| 425 | void setAccessChainLValue(Id lValue)
|
| 426 | {
|
| 427 | assert(isPointer(lValue));
|
| 428 | accessChain.base = lValue;
|
| 429 | }
|
| 430 |
|
| 431 | // set new base value as an r-value
|
| 432 | void setAccessChainRValue(Id rValue)
|
| 433 | {
|
| 434 | accessChain.isRValue = true;
|
| 435 | accessChain.base = rValue;
|
| 436 | accessChain.resultType = getTypeId(rValue);
|
| 437 | }
|
| 438 |
|
| 439 | // push offset onto the end of the chain
|
| 440 | void accessChainPush(Id offset, Id newType)
|
| 441 | {
|
| 442 | accessChain.indexChain.push_back(offset);
|
| 443 | accessChain.resultType = newType;
|
| 444 | }
|
| 445 |
|
| 446 | // push new swizzle onto the end of any existing swizzle, merging into a single swizzle
|
| 447 | void accessChainPushSwizzle(std::vector<unsigned>& swizzle, int width, Id type);
|
| 448 |
|
| 449 | // push a variable component selection onto the access chain; supporting only one, so unsided
|
| 450 | void accessChainPushComponent(Id component) { accessChain.component = component; }
|
| 451 |
|
| 452 | // use accessChain and swizzle to store value
|
| 453 | void accessChainStore(Id rvalue);
|
| 454 |
|
| 455 | // use accessChain and swizzle to load an r-value
|
| 456 | Id accessChainLoad(Decoration precision);
|
| 457 |
|
| 458 | // get the direct pointer for an l-value
|
| 459 | Id accessChainGetLValue();
|
| 460 |
|
| 461 | void dump(std::vector<unsigned int>&) const;
|
| 462 |
|
| 463 | protected:
|
John Kessenich | b40d6ac | 2015-03-30 17:41:16 +0000 | [diff] [blame] | 464 | Id findScalarConstant(Op typeClass, Id typeId, unsigned value) const;
|
John Kessenich | edd1819 | 2015-04-17 21:47:07 +0000 | [diff] [blame^] | 465 | Id findScalarConstant(Op typeClass, Id typeId, unsigned v1, unsigned v2) const;
|
John Kessenich | b40d6ac | 2015-03-30 17:41:16 +0000 | [diff] [blame] | 466 | Id findCompositeConstant(Op typeClass, std::vector<Id>& comps) const;
|
John Kessenich | 0df0cde | 2015-03-03 17:09:43 +0000 | [diff] [blame] | 467 | Id collapseAccessChain();
|
| 468 | void simplifyAccessChainSwizzle();
|
| 469 | void createAndSetNoPredecessorBlock(const char*);
|
| 470 | void createBranch(Block* block);
|
John Kessenich | b40d6ac | 2015-03-30 17:41:16 +0000 | [diff] [blame] | 471 | void createMerge(Op, Block*, unsigned int control);
|
John Kessenich | 0df0cde | 2015-03-03 17:09:43 +0000 | [diff] [blame] | 472 | void createConditionalBranch(Id condition, Block* thenBlock, Block* elseBlock);
|
| 473 | void dumpInstructions(std::vector<unsigned int>&, const std::vector<Instruction*>&) const;
|
| 474 |
|
| 475 | SourceLanguage source;
|
| 476 | int sourceVersion;
|
| 477 | std::vector<const char*> extensions;
|
| 478 | AddressingModel addressModel;
|
| 479 | MemoryModel memoryModel;
|
| 480 | int builderNumber;
|
| 481 | Module module;
|
| 482 | Block* buildPoint;
|
| 483 | Id uniqueId;
|
| 484 | Function* mainFunction;
|
| 485 | Block* stageExit;
|
| 486 | AccessChain accessChain;
|
| 487 |
|
| 488 | // special blocks of instructions for output
|
| 489 | std::vector<Instruction*> imports;
|
| 490 | std::vector<Instruction*> entryPoints;
|
| 491 | std::vector<Instruction*> executionModes;
|
| 492 | std::vector<Instruction*> names;
|
| 493 | std::vector<Instruction*> lines;
|
| 494 | std::vector<Instruction*> decorations;
|
| 495 | std::vector<Instruction*> constantsTypesGlobals;
|
| 496 | std::vector<Instruction*> externals;
|
| 497 |
|
| 498 | // not output, internally used for quick & dirty canonical (unique) creation
|
| 499 | std::vector<Instruction*> groupedConstants[OpConstant]; // all types appear before OpConstant
|
| 500 | std::vector<Instruction*> groupedTypes[OpConstant];
|
| 501 |
|
| 502 | // stack of switches
|
| 503 | std::stack<Block*> switchMerges;
|
| 504 |
|
| 505 | // Data that needs to be kept in order to properly handle loops.
|
| 506 | struct Loop {
|
| 507 | Block* header;
|
| 508 | Block* merge;
|
| 509 | Function* function;
|
| 510 | };
|
| 511 |
|
| 512 | // Our loop stack.
|
| 513 | std::stack<Loop> loops;
|
| 514 | }; // end Builder class
|
| 515 |
|
| 516 | void MissingFunctionality(const char*);
|
| 517 | void ValidationError(const char* error);
|
| 518 |
|
| 519 | }; // end spv namespace
|
| 520 |
|
| 521 | #endif // SpvBuilder_H
|