Home | History | Annotate | Download | only in SPIRV
      1 //
      2 //Copyright (C) 2014-2015 LunarG, Inc.
      3 //Copyright (C) 2015-2016 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 //
     37 // "Builder" is an interface to fully build SPIR-V IR.   Allocate one of
     38 // these to build (a thread safe) internal SPIR-V representation (IR),
     39 // and then dump it as a binary stream according to the SPIR-V specification.
     40 //
     41 // A Builder has a 1:1 relationship with a SPIR-V module.
     42 //
     43 
     44 #pragma once
     45 #ifndef SpvBuilder_H
     46 #define SpvBuilder_H
     47 
     48 #include "Logger.h"
     49 #include "spirv.hpp"
     50 #include "spvIR.h"
     51 
     52 #include <algorithm>
     53 #include <map>
     54 #include <memory>
     55 #include <set>
     56 #include <sstream>
     57 #include <stack>
     58 
     59 namespace spv {
     60 
     61 class Builder {
     62 public:
     63     Builder(unsigned int userNumber, SpvBuildLogger* logger);
     64     virtual ~Builder();
     65 
     66     static const int maxMatrixSize = 4;
     67 
     68     void setSource(spv::SourceLanguage lang, int version)
     69     {
     70         source = lang;
     71         sourceVersion = version;
     72     }
     73     void addSourceExtension(const char* ext) { extensions.push_back(ext); }
     74     Id import(const char*);
     75     void setMemoryModel(spv::AddressingModel addr, spv::MemoryModel mem)
     76     {
     77         addressModel = addr;
     78         memoryModel = mem;
     79     }
     80 
     81     void addCapability(spv::Capability cap) { capabilities.insert(cap); }
     82 
     83     // To get a new <id> for anything needing a new one.
     84     Id getUniqueId() { return ++uniqueId; }
     85 
     86     // To get a set of new <id>s, e.g., for a set of function parameters
     87     Id getUniqueIds(int numIds)
     88     {
     89         Id id = uniqueId + 1;
     90         uniqueId += numIds;
     91         return id;
     92     }
     93 
     94     // For creating new types (will return old type if the requested one was already made).
     95     Id makeVoidType();
     96     Id makeBoolType();
     97     Id makePointer(StorageClass, Id type);
     98     Id makeIntegerType(int width, bool hasSign);   // generic
     99     Id makeIntType(int width) { return makeIntegerType(width, true); }
    100     Id makeUintType(int width) { return makeIntegerType(width, false); }
    101     Id makeFloatType(int width);
    102     Id makeStructType(const std::vector<Id>& members, const char*);
    103     Id makeStructResultType(Id type0, Id type1);
    104     Id makeVectorType(Id component, int size);
    105     Id makeMatrixType(Id component, int cols, int rows);
    106     Id makeArrayType(Id element, Id sizeId, int stride);  // 0 stride means no stride decoration
    107     Id makeRuntimeArray(Id element);
    108     Id makeFunctionType(Id returnType, const std::vector<Id>& paramTypes);
    109     Id makeImageType(Id sampledType, Dim, bool depth, bool arrayed, bool ms, unsigned sampled, ImageFormat format);
    110     Id makeSamplerType();
    111     Id makeSampledImageType(Id imageType);
    112 
    113     // For querying about types.
    114     Id getTypeId(Id resultId) const { return module.getTypeId(resultId); }
    115     Id getDerefTypeId(Id resultId) const;
    116     Op getOpCode(Id id) const { return module.getInstruction(id)->getOpCode(); }
    117     Op getTypeClass(Id typeId) const { return getOpCode(typeId); }
    118     Op getMostBasicTypeClass(Id typeId) const;
    119     int getNumComponents(Id resultId) const { return getNumTypeComponents(getTypeId(resultId)); }
    120     int getNumTypeConstituents(Id typeId) const;
    121     int getNumTypeComponents(Id typeId) const { return getNumTypeConstituents(typeId); }
    122     Id getScalarTypeId(Id typeId) const;
    123     Id getContainedTypeId(Id typeId) const;
    124     Id getContainedTypeId(Id typeId, int) const;
    125     StorageClass getTypeStorageClass(Id typeId) const { return module.getStorageClass(typeId); }
    126     ImageFormat getImageTypeFormat(Id typeId) const { return (ImageFormat)module.getInstruction(typeId)->getImmediateOperand(6); }
    127 
    128     bool isPointer(Id resultId)      const { return isPointerType(getTypeId(resultId)); }
    129     bool isScalar(Id resultId)       const { return isScalarType(getTypeId(resultId)); }
    130     bool isVector(Id resultId)       const { return isVectorType(getTypeId(resultId)); }
    131     bool isMatrix(Id resultId)       const { return isMatrixType(getTypeId(resultId)); }
    132     bool isAggregate(Id resultId)    const { return isAggregateType(getTypeId(resultId)); }
    133     bool isSampledImage(Id resultId) const { return isSampledImageType(getTypeId(resultId)); }
    134 
    135     bool isBoolType(Id typeId)         const { return groupedTypes[OpTypeBool].size() > 0 && typeId == groupedTypes[OpTypeBool].back()->getResultId(); }
    136     bool isPointerType(Id typeId)      const { return getTypeClass(typeId) == OpTypePointer; }
    137     bool isScalarType(Id typeId)       const { return getTypeClass(typeId) == OpTypeFloat  || getTypeClass(typeId) == OpTypeInt || getTypeClass(typeId) == OpTypeBool; }
    138     bool isVectorType(Id typeId)       const { return getTypeClass(typeId) == OpTypeVector; }
    139     bool isMatrixType(Id typeId)       const { return getTypeClass(typeId) == OpTypeMatrix; }
    140     bool isStructType(Id typeId)       const { return getTypeClass(typeId) == OpTypeStruct; }
    141     bool isArrayType(Id typeId)        const { return getTypeClass(typeId) == OpTypeArray; }
    142     bool isAggregateType(Id typeId)    const { return isArrayType(typeId) || isStructType(typeId); }
    143     bool isImageType(Id typeId)        const { return getTypeClass(typeId) == OpTypeImage; }
    144     bool isSamplerType(Id typeId)      const { return getTypeClass(typeId) == OpTypeSampler; }
    145     bool isSampledImageType(Id typeId) const { return getTypeClass(typeId) == OpTypeSampledImage; }
    146 
    147     bool isConstantOpCode(Op opcode) const;
    148     bool isSpecConstantOpCode(Op opcode) const;
    149     bool isConstant(Id resultId) const { return isConstantOpCode(getOpCode(resultId)); }
    150     bool isConstantScalar(Id resultId) const { return getOpCode(resultId) == OpConstant; }
    151     bool isSpecConstant(Id resultId) const { return isSpecConstantOpCode(getOpCode(resultId)); }
    152     unsigned int getConstantScalar(Id resultId) const { return module.getInstruction(resultId)->getImmediateOperand(0); }
    153     StorageClass getStorageClass(Id resultId) const { return getTypeStorageClass(getTypeId(resultId)); }
    154 
    155     int getTypeNumColumns(Id typeId) const
    156     {
    157         assert(isMatrixType(typeId));
    158         return getNumTypeConstituents(typeId);
    159     }
    160     int getNumColumns(Id resultId) const { return getTypeNumColumns(getTypeId(resultId)); }
    161     int getTypeNumRows(Id typeId) const
    162     {
    163         assert(isMatrixType(typeId));
    164         return getNumTypeComponents(getContainedTypeId(typeId));
    165     }
    166     int getNumRows(Id resultId) const { return getTypeNumRows(getTypeId(resultId)); }
    167 
    168     Dim getTypeDimensionality(Id typeId) const
    169     {
    170         assert(isImageType(typeId));
    171         return (Dim)module.getInstruction(typeId)->getImmediateOperand(1);
    172     }
    173     Id getImageType(Id resultId) const
    174     {
    175         Id typeId = getTypeId(resultId);
    176         assert(isImageType(typeId) || isSampledImageType(typeId));
    177         return isSampledImageType(typeId) ? module.getInstruction(typeId)->getIdOperand(0) : typeId;
    178     }
    179     bool isArrayedImageType(Id typeId) const
    180     {
    181         assert(isImageType(typeId));
    182         return module.getInstruction(typeId)->getImmediateOperand(3) != 0;
    183     }
    184 
    185     // For making new constants (will return old constant if the requested one was already made).
    186     Id makeBoolConstant(bool b, bool specConstant = false);
    187     Id makeIntConstant(int i, bool specConstant = false)         { return makeIntConstant(makeIntType(32),  (unsigned)i, specConstant); }
    188     Id makeUintConstant(unsigned u, bool specConstant = false)   { return makeIntConstant(makeUintType(32),           u, specConstant); }
    189     Id makeInt64Constant(long long i, bool specConstant = false)            { return makeInt64Constant(makeIntType(64),  (unsigned long long)i, specConstant); }
    190     Id makeUint64Constant(unsigned long long u, bool specConstant = false)  { return makeInt64Constant(makeUintType(64),                     u, specConstant); }
    191     Id makeFloatConstant(float f, bool specConstant = false);
    192     Id makeDoubleConstant(double d, bool specConstant = false);
    193 
    194     // Turn the array of constants into a proper spv constant of the requested type.
    195     Id makeCompositeConstant(Id type, std::vector<Id>& comps, bool specConst = false);
    196 
    197     // Methods for adding information outside the CFG.
    198     Instruction* addEntryPoint(ExecutionModel, Function*, const char* name);
    199     void addExecutionMode(Function*, ExecutionMode mode, int value1 = -1, int value2 = -1, int value3 = -1);
    200     void addName(Id, const char* name);
    201     void addMemberName(Id, int member, const char* name);
    202     void addLine(Id target, Id fileName, int line, int column);
    203     void addDecoration(Id, Decoration, int num = -1);
    204     void addMemberDecoration(Id, unsigned int member, Decoration, int num = -1);
    205 
    206     // At the end of what block do the next create*() instructions go?
    207     void setBuildPoint(Block* bp) { buildPoint = bp; }
    208     Block* getBuildPoint() const { return buildPoint; }
    209 
    210     // Make the entry-point function. The returned pointer is only valid
    211     // for the lifetime of this builder.
    212     Function* makeEntrypoint(const char*);
    213 
    214     // Make a shader-style function, and create its entry block if entry is non-zero.
    215     // Return the function, pass back the entry.
    216     // The returned pointer is only valid for the lifetime of this builder.
    217     Function* makeFunctionEntry(Decoration precision, Id returnType, const char* name, const std::vector<Id>& paramTypes,
    218                                 const std::vector<Decoration>& precisions, Block **entry = 0);
    219 
    220     // Create a return. An 'implicit' return is one not appearing in the source
    221     // code.  In the case of an implicit return, no post-return block is inserted.
    222     void makeReturn(bool implicit, Id retVal = 0);
    223 
    224     // Generate all the code needed to finish up a function.
    225     void leaveFunction();
    226 
    227     // Create a discard.
    228     void makeDiscard();
    229 
    230     // Create a global or function local or IO variable.
    231     Id createVariable(StorageClass, Id type, const char* name = 0);
    232 
    233     // Create an intermediate with an undefined value.
    234     Id createUndefined(Id type);
    235 
    236     // Store into an Id and return the l-value
    237     void createStore(Id rValue, Id lValue);
    238 
    239     // Load from an Id and return it
    240     Id createLoad(Id lValue);
    241 
    242     // Create an OpAccessChain instruction
    243     Id createAccessChain(StorageClass, Id base, std::vector<Id>& offsets);
    244 
    245     // Create an OpArrayLength instruction
    246     Id createArrayLength(Id base, unsigned int member);
    247 
    248     // Create an OpCompositeExtract instruction
    249     Id createCompositeExtract(Id composite, Id typeId, unsigned index);
    250     Id createCompositeExtract(Id composite, Id typeId, std::vector<unsigned>& indexes);
    251     Id createCompositeInsert(Id object, Id composite, Id typeId, unsigned index);
    252     Id createCompositeInsert(Id object, Id composite, Id typeId, std::vector<unsigned>& indexes);
    253 
    254     Id createVectorExtractDynamic(Id vector, Id typeId, Id componentIndex);
    255     Id createVectorInsertDynamic(Id vector, Id typeId, Id component, Id componentIndex);
    256 
    257     void createNoResultOp(Op);
    258     void createNoResultOp(Op, Id operand);
    259     void createNoResultOp(Op, const std::vector<Id>& operands);
    260     void createControlBarrier(Scope execution, Scope memory, MemorySemanticsMask);
    261     void createMemoryBarrier(unsigned executionScope, unsigned memorySemantics);
    262     Id createUnaryOp(Op, Id typeId, Id operand);
    263     Id createBinOp(Op, Id typeId, Id operand1, Id operand2);
    264     Id createTriOp(Op, Id typeId, Id operand1, Id operand2, Id operand3);
    265     Id createOp(Op, Id typeId, const std::vector<Id>& operands);
    266     Id createFunctionCall(spv::Function*, std::vector<spv::Id>&);
    267     Id createSpecConstantOp(Op, Id typeId, const std::vector<spv::Id>& operands, const std::vector<unsigned>& literals);
    268 
    269     // Take an rvalue (source) and a set of channels to extract from it to
    270     // make a new rvalue, which is returned.
    271     Id createRvalueSwizzle(Decoration precision, Id typeId, Id source, std::vector<unsigned>& channels);
    272 
    273     // Take a copy of an lvalue (target) and a source of components, and set the
    274     // source components into the lvalue where the 'channels' say to put them.
    275     // An updated version of the target is returned.
    276     // (No true lvalue or stores are used.)
    277     Id createLvalueSwizzle(Id typeId, Id target, Id source, std::vector<unsigned>& channels);
    278 
    279     // If both the id and precision are valid, the id
    280     // gets tagged with the requested precision.
    281     // The passed in id is always the returned id, to simplify use patterns.
    282     Id setPrecision(Id id, Decoration precision)
    283     {
    284         if (precision != NoPrecision && id != NoResult)
    285             addDecoration(id, precision);
    286 
    287         return id;
    288     }
    289 
    290     // Can smear a scalar to a vector for the following forms:
    291     //   - promoteScalar(scalar, vector)  // smear scalar to width of vector
    292     //   - promoteScalar(vector, scalar)  // smear scalar to width of vector
    293     //   - promoteScalar(pointer, scalar) // smear scalar to width of what pointer points to
    294     //   - promoteScalar(scalar, scalar)  // do nothing
    295     // Other forms are not allowed.
    296     //
    297     // Generally, the type of 'scalar' does not need to be the same type as the components in 'vector'.
    298     // The type of the created vector is a vector of components of the same type as the scalar.
    299     //
    300     // Note: One of the arguments will change, with the result coming back that way rather than
    301     // through the return value.
    302     void promoteScalar(Decoration precision, Id& left, Id& right);
    303 
    304     // Make a value by smearing the scalar to fill the type.
    305     // vectorType should be the correct type for making a vector of scalarVal.
    306     // (No conversions are done.)
    307     Id smearScalar(Decoration precision, Id scalarVal, Id vectorType);
    308 
    309     // Create a call to a built-in function.
    310     Id createBuiltinCall(Id resultType, Id builtins, int entryPoint, std::vector<Id>& args);
    311 
    312     // List of parameters used to create a texture operation
    313     struct TextureParameters {
    314         Id sampler;
    315         Id coords;
    316         Id bias;
    317         Id lod;
    318         Id Dref;
    319         Id offset;
    320         Id offsets;
    321         Id gradX;
    322         Id gradY;
    323         Id sample;
    324         Id component;
    325         Id texelOut;
    326         Id lodClamp;
    327     };
    328 
    329     // Select the correct texture operation based on all inputs, and emit the correct instruction
    330     Id createTextureCall(Decoration precision, Id resultType, bool sparse, bool fetch, bool proj, bool gather, bool noImplicit, const TextureParameters&);
    331 
    332     // Emit the OpTextureQuery* instruction that was passed in.
    333     // Figure out the right return value and type, and return it.
    334     Id createTextureQueryCall(Op, const TextureParameters&);
    335 
    336     Id createSamplePositionCall(Decoration precision, Id, Id);
    337 
    338     Id createBitFieldExtractCall(Decoration precision, Id, Id, Id, bool isSigned);
    339     Id createBitFieldInsertCall(Decoration precision, Id, Id, Id, Id);
    340 
    341     // Reduction comparison for composites:  For equal and not-equal resulting in a scalar.
    342     Id createCompositeCompare(Decoration precision, Id, Id, bool /* true if for equal, false if for not-equal */);
    343 
    344     // OpCompositeConstruct
    345     Id createCompositeConstruct(Id typeId, std::vector<Id>& constituents);
    346 
    347     // vector or scalar constructor
    348     Id createConstructor(Decoration precision, const std::vector<Id>& sources, Id resultTypeId);
    349 
    350     // matrix constructor
    351     Id createMatrixConstructor(Decoration precision, const std::vector<Id>& sources, Id constructee);
    352 
    353     // Helper to use for building nested control flow with if-then-else.
    354     class If {
    355     public:
    356         If(Id condition, Builder& builder);
    357         ~If() {}
    358 
    359         void makeBeginElse();
    360         void makeEndIf();
    361 
    362     private:
    363         If(const If&);
    364         If& operator=(If&);
    365 
    366         Builder& builder;
    367         Id condition;
    368         Function* function;
    369         Block* headerBlock;
    370         Block* thenBlock;
    371         Block* elseBlock;
    372         Block* mergeBlock;
    373     };
    374 
    375     // Make a switch statement.  A switch has 'numSegments' of pieces of code, not containing
    376     // any case/default labels, all separated by one or more case/default labels.  Each possible
    377     // case value v is a jump to the caseValues[v] segment.  The defaultSegment is also in this
    378     // number space.  How to compute the value is given by 'condition', as in switch(condition).
    379     //
    380     // The SPIR-V Builder will maintain the stack of post-switch merge blocks for nested switches.
    381     //
    382     // Use a defaultSegment < 0 if there is no default segment (to branch to post switch).
    383     //
    384     // Returns the right set of basic blocks to start each code segment with, so that the caller's
    385     // recursion stack can hold the memory for it.
    386     //
    387     void makeSwitch(Id condition, int numSegments, std::vector<int>& caseValues, std::vector<int>& valueToSegment, int defaultSegment,
    388                     std::vector<Block*>& segmentBB);  // return argument
    389 
    390     // Add a branch to the innermost switch's merge block.
    391     void addSwitchBreak();
    392 
    393     // Move to the next code segment, passing in the return argument in makeSwitch()
    394     void nextSwitchSegment(std::vector<Block*>& segmentBB, int segment);
    395 
    396     // Finish off the innermost switch.
    397     void endSwitch(std::vector<Block*>& segmentBB);
    398 
    399     struct LoopBlocks {
    400         LoopBlocks(Block& head, Block& body, Block& merge, Block& continue_target) :
    401             head(head), body(body), merge(merge), continue_target(continue_target) { }
    402         Block &head, &body, &merge, &continue_target;
    403     private:
    404         LoopBlocks();
    405         LoopBlocks& operator=(const LoopBlocks&);
    406     };
    407 
    408     // Start a new loop and prepare the builder to generate code for it.  Until
    409     // closeLoop() is called for this loop, createLoopContinue() and
    410     // createLoopExit() will target its corresponding blocks.
    411     LoopBlocks& makeNewLoop();
    412 
    413     // Create a new block in the function containing the build point.  Memory is
    414     // owned by the function object.
    415     Block& makeNewBlock();
    416 
    417     // Add a branch to the continue_target of the current (innermost) loop.
    418     void createLoopContinue();
    419 
    420     // Add an exit (e.g. "break") from the innermost loop that we're currently
    421     // in.
    422     void createLoopExit();
    423 
    424     // Close the innermost loop that you're in
    425     void closeLoop();
    426 
    427     //
    428     // Access chain design for an R-Value vs. L-Value:
    429     //
    430     // There is a single access chain the builder is building at
    431     // any particular time.  Such a chain can be used to either to a load or
    432     // a store, when desired.
    433     //
    434     // Expressions can be r-values, l-values, or both, or only r-values:
    435     //    a[b.c].d = ....  // l-value
    436     //    ... = a[b.c].d;  // r-value, that also looks like an l-value
    437     //    ++a[b.c].d;      // r-value and l-value
    438     //    (x + y)[2];      // r-value only, can't possibly be l-value
    439     //
    440     // Computing an r-value means generating code.  Hence,
    441     // r-values should only be computed when they are needed, not speculatively.
    442     //
    443     // Computing an l-value means saving away information for later use in the compiler,
    444     // no code is generated until the l-value is later dereferenced.  It is okay
    445     // to speculatively generate an l-value, just not okay to speculatively dereference it.
    446     //
    447     // The base of the access chain (the left-most variable or expression
    448     // from which everything is based) can be set either as an l-value
    449     // or as an r-value.  Most efficient would be to set an l-value if one
    450     // is available.  If an expression was evaluated, the resulting r-value
    451     // can be set as the chain base.
    452     //
    453     // The users of this single access chain can save and restore if they
    454     // want to nest or manage multiple chains.
    455     //
    456 
    457     struct AccessChain {
    458         Id base;                       // for l-values, pointer to the base object, for r-values, the base object
    459         std::vector<Id> indexChain;
    460         Id instr;                      // cache the instruction that generates this access chain
    461         std::vector<unsigned> swizzle; // each std::vector element selects the next GLSL component number
    462         Id component;                  // a dynamic component index, can coexist with a swizzle, done after the swizzle, NoResult if not present
    463         Id preSwizzleBaseType;         // dereferenced type, before swizzle or component is applied; NoType unless a swizzle or component is present
    464         bool isRValue;                 // true if 'base' is an r-value, otherwise, base is an l-value
    465     };
    466 
    467     //
    468     // the SPIR-V builder maintains a single active chain that
    469     // the following methods operated on
    470     //
    471 
    472     // for external save and restore
    473     AccessChain getAccessChain() { return accessChain; }
    474     void setAccessChain(AccessChain newChain) { accessChain = newChain; }
    475 
    476     // clear accessChain
    477     void clearAccessChain();
    478 
    479     // set new base as an l-value base
    480     void setAccessChainLValue(Id lValue)
    481     {
    482         assert(isPointer(lValue));
    483         accessChain.base = lValue;
    484     }
    485 
    486     // set new base value as an r-value
    487     void setAccessChainRValue(Id rValue)
    488     {
    489         accessChain.isRValue = true;
    490         accessChain.base = rValue;
    491     }
    492 
    493     // push offset onto the end of the chain
    494     void accessChainPush(Id offset)
    495     {
    496         accessChain.indexChain.push_back(offset);
    497     }
    498 
    499     // push new swizzle onto the end of any existing swizzle, merging into a single swizzle
    500     void accessChainPushSwizzle(std::vector<unsigned>& swizzle, Id preSwizzleBaseType);
    501 
    502     // push a variable component selection onto the access chain; supporting only one, so unsided
    503     void accessChainPushComponent(Id component, Id preSwizzleBaseType)
    504     {
    505         accessChain.component = component;
    506         if (accessChain.preSwizzleBaseType == NoType)
    507             accessChain.preSwizzleBaseType = preSwizzleBaseType;
    508     }
    509 
    510     // use accessChain and swizzle to store value
    511     void accessChainStore(Id rvalue);
    512 
    513     // use accessChain and swizzle to load an r-value
    514     Id accessChainLoad(Decoration precision, Id ResultType);
    515 
    516     // get the direct pointer for an l-value
    517     Id accessChainGetLValue();
    518 
    519     // Get the inferred SPIR-V type of the result of the current access chain,
    520     // based on the type of the base and the chain of dereferences.
    521     Id accessChainGetInferredType();
    522 
    523     // Remove OpDecorate instructions whose operands are defined in unreachable
    524     // blocks.
    525     void eliminateDeadDecorations();
    526     void dump(std::vector<unsigned int>&) const;
    527 
    528     void createBranch(Block* block);
    529     void createConditionalBranch(Id condition, Block* thenBlock, Block* elseBlock);
    530     void createLoopMerge(Block* mergeBlock, Block* continueBlock, unsigned int control);
    531 
    532     // Sets to generate opcode for specialization constants.
    533     void setToSpecConstCodeGenMode() { generatingOpCodeForSpecConst = true; }
    534     // Sets to generate opcode for non-specialization constants (normal mode).
    535     void setToNormalCodeGenMode() { generatingOpCodeForSpecConst = false; }
    536     // Check if the builder is generating code for spec constants.
    537     bool isInSpecConstCodeGenMode() { return generatingOpCodeForSpecConst; }
    538 
    539  protected:
    540     Id makeIntConstant(Id typeId, unsigned value, bool specConstant);
    541     Id makeInt64Constant(Id typeId, unsigned long long value, bool specConstant);
    542     Id findScalarConstant(Op typeClass, Op opcode, Id typeId, unsigned value) const;
    543     Id findScalarConstant(Op typeClass, Op opcode, Id typeId, unsigned v1, unsigned v2) const;
    544     Id findCompositeConstant(Op typeClass, std::vector<Id>& comps) const;
    545     Id collapseAccessChain();
    546     void transferAccessChainSwizzle(bool dynamic);
    547     void simplifyAccessChainSwizzle();
    548     void createAndSetNoPredecessorBlock(const char*);
    549     void createSelectionMerge(Block* mergeBlock, unsigned int control);
    550     void dumpInstructions(std::vector<unsigned int>&, const std::vector<std::unique_ptr<Instruction> >&) const;
    551 
    552     SourceLanguage source;
    553     int sourceVersion;
    554     std::vector<const char*> extensions;
    555     AddressingModel addressModel;
    556     MemoryModel memoryModel;
    557     std::set<spv::Capability> capabilities;
    558     int builderNumber;
    559     Module module;
    560     Block* buildPoint;
    561     Id uniqueId;
    562     Function* mainFunction;
    563     bool generatingOpCodeForSpecConst;
    564     AccessChain accessChain;
    565 
    566     // special blocks of instructions for output
    567     std::vector<std::unique_ptr<Instruction> > imports;
    568     std::vector<std::unique_ptr<Instruction> > entryPoints;
    569     std::vector<std::unique_ptr<Instruction> > executionModes;
    570     std::vector<std::unique_ptr<Instruction> > names;
    571     std::vector<std::unique_ptr<Instruction> > lines;
    572     std::vector<std::unique_ptr<Instruction> > decorations;
    573     std::vector<std::unique_ptr<Instruction> > constantsTypesGlobals;
    574     std::vector<std::unique_ptr<Instruction> > externals;
    575     std::vector<std::unique_ptr<Function> > functions;
    576 
    577      // not output, internally used for quick & dirty canonical (unique) creation
    578     std::vector<Instruction*> groupedConstants[OpConstant];  // all types appear before OpConstant
    579     std::vector<Instruction*> groupedTypes[OpConstant];
    580 
    581     // stack of switches
    582     std::stack<Block*> switchMerges;
    583 
    584     // Our loop stack.
    585     std::stack<LoopBlocks> loops;
    586 
    587     // The stream for outputing warnings and errors.
    588     SpvBuildLogger* logger;
    589 };  // end Builder class
    590 
    591 };  // end spv namespace
    592 
    593 #endif // SpvBuilder_H
    594