summaryrefslogtreecommitdiffstatshomepage
path: root/3rdparty/bgfx/3rdparty/glslang/SPIRV/SpvBuilder.h
diff options
context:
space:
mode:
Diffstat (limited to '3rdparty/bgfx/3rdparty/glslang/SPIRV/SpvBuilder.h')
-rw-r--r--3rdparty/bgfx/3rdparty/glslang/SPIRV/SpvBuilder.h598
1 files changed, 598 insertions, 0 deletions
diff --git a/3rdparty/bgfx/3rdparty/glslang/SPIRV/SpvBuilder.h b/3rdparty/bgfx/3rdparty/glslang/SPIRV/SpvBuilder.h
new file mode 100644
index 00000000000..e8524b2b1b7
--- /dev/null
+++ b/3rdparty/bgfx/3rdparty/glslang/SPIRV/SpvBuilder.h
@@ -0,0 +1,598 @@
+//
+//Copyright (C) 2014-2015 LunarG, Inc.
+//Copyright (C) 2015-2016 Google, Inc.
+//
+//All rights reserved.
+//
+//Redistribution and use in source and binary forms, with or without
+//modification, are permitted provided that the following conditions
+//are met:
+//
+// Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//
+// Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+//
+// Neither the name of 3Dlabs Inc. Ltd. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+//POSSIBILITY OF SUCH DAMAGE.
+
+//
+// "Builder" is an interface to fully build SPIR-V IR. Allocate one of
+// these to build (a thread safe) internal SPIR-V representation (IR),
+// and then dump it as a binary stream according to the SPIR-V specification.
+//
+// A Builder has a 1:1 relationship with a SPIR-V module.
+//
+
+#pragma once
+#ifndef SpvBuilder_H
+#define SpvBuilder_H
+
+#include "Logger.h"
+#include "spirv.hpp"
+#include "spvIR.h"
+
+#include <algorithm>
+#include <map>
+#include <memory>
+#include <set>
+#include <sstream>
+#include <stack>
+
+namespace spv {
+
+class Builder {
+public:
+ Builder(unsigned int userNumber, SpvBuildLogger* logger);
+ virtual ~Builder();
+
+ static const int maxMatrixSize = 4;
+
+ void setSource(spv::SourceLanguage lang, int version)
+ {
+ source = lang;
+ sourceVersion = version;
+ }
+ void addSourceExtension(const char* ext) { sourceExtensions.push_back(ext); }
+ void addExtension(const char* ext) { extensions.insert(ext); }
+ Id import(const char*);
+ void setMemoryModel(spv::AddressingModel addr, spv::MemoryModel mem)
+ {
+ addressModel = addr;
+ memoryModel = mem;
+ }
+
+ void addCapability(spv::Capability cap) { capabilities.insert(cap); }
+
+ // To get a new <id> for anything needing a new one.
+ Id getUniqueId() { return ++uniqueId; }
+
+ // To get a set of new <id>s, e.g., for a set of function parameters
+ Id getUniqueIds(int numIds)
+ {
+ Id id = uniqueId + 1;
+ uniqueId += numIds;
+ return id;
+ }
+
+ // For creating new types (will return old type if the requested one was already made).
+ Id makeVoidType();
+ Id makeBoolType();
+ Id makePointer(StorageClass, Id type);
+ Id makeIntegerType(int width, bool hasSign); // generic
+ Id makeIntType(int width) { return makeIntegerType(width, true); }
+ Id makeUintType(int width) { return makeIntegerType(width, false); }
+ Id makeFloatType(int width);
+ Id makeStructType(const std::vector<Id>& members, const char*);
+ Id makeStructResultType(Id type0, Id type1);
+ Id makeVectorType(Id component, int size);
+ Id makeMatrixType(Id component, int cols, int rows);
+ Id makeArrayType(Id element, Id sizeId, int stride); // 0 stride means no stride decoration
+ Id makeRuntimeArray(Id element);
+ Id makeFunctionType(Id returnType, const std::vector<Id>& paramTypes);
+ Id makeImageType(Id sampledType, Dim, bool depth, bool arrayed, bool ms, unsigned sampled, ImageFormat format);
+ Id makeSamplerType();
+ Id makeSampledImageType(Id imageType);
+
+ // For querying about types.
+ Id getTypeId(Id resultId) const { return module.getTypeId(resultId); }
+ Id getDerefTypeId(Id resultId) const;
+ Op getOpCode(Id id) const { return module.getInstruction(id)->getOpCode(); }
+ Op getTypeClass(Id typeId) const { return getOpCode(typeId); }
+ Op getMostBasicTypeClass(Id typeId) const;
+ int getNumComponents(Id resultId) const { return getNumTypeComponents(getTypeId(resultId)); }
+ int getNumTypeConstituents(Id typeId) const;
+ int getNumTypeComponents(Id typeId) const { return getNumTypeConstituents(typeId); }
+ Id getScalarTypeId(Id typeId) const;
+ Id getContainedTypeId(Id typeId) const;
+ Id getContainedTypeId(Id typeId, int) const;
+ StorageClass getTypeStorageClass(Id typeId) const { return module.getStorageClass(typeId); }
+ ImageFormat getImageTypeFormat(Id typeId) const { return (ImageFormat)module.getInstruction(typeId)->getImmediateOperand(6); }
+
+ bool isPointer(Id resultId) const { return isPointerType(getTypeId(resultId)); }
+ bool isScalar(Id resultId) const { return isScalarType(getTypeId(resultId)); }
+ bool isVector(Id resultId) const { return isVectorType(getTypeId(resultId)); }
+ bool isMatrix(Id resultId) const { return isMatrixType(getTypeId(resultId)); }
+ bool isAggregate(Id resultId) const { return isAggregateType(getTypeId(resultId)); }
+ bool isSampledImage(Id resultId) const { return isSampledImageType(getTypeId(resultId)); }
+
+ bool isBoolType(Id typeId) const { return groupedTypes[OpTypeBool].size() > 0 && typeId == groupedTypes[OpTypeBool].back()->getResultId(); }
+ bool isPointerType(Id typeId) const { return getTypeClass(typeId) == OpTypePointer; }
+ bool isScalarType(Id typeId) const { return getTypeClass(typeId) == OpTypeFloat || getTypeClass(typeId) == OpTypeInt || getTypeClass(typeId) == OpTypeBool; }
+ bool isVectorType(Id typeId) const { return getTypeClass(typeId) == OpTypeVector; }
+ bool isMatrixType(Id typeId) const { return getTypeClass(typeId) == OpTypeMatrix; }
+ bool isStructType(Id typeId) const { return getTypeClass(typeId) == OpTypeStruct; }
+ bool isArrayType(Id typeId) const { return getTypeClass(typeId) == OpTypeArray; }
+ bool isAggregateType(Id typeId) const { return isArrayType(typeId) || isStructType(typeId); }
+ bool isImageType(Id typeId) const { return getTypeClass(typeId) == OpTypeImage; }
+ bool isSamplerType(Id typeId) const { return getTypeClass(typeId) == OpTypeSampler; }
+ bool isSampledImageType(Id typeId) const { return getTypeClass(typeId) == OpTypeSampledImage; }
+
+ bool isConstantOpCode(Op opcode) const;
+ bool isSpecConstantOpCode(Op opcode) const;
+ bool isConstant(Id resultId) const { return isConstantOpCode(getOpCode(resultId)); }
+ bool isConstantScalar(Id resultId) const { return getOpCode(resultId) == OpConstant; }
+ bool isSpecConstant(Id resultId) const { return isSpecConstantOpCode(getOpCode(resultId)); }
+ unsigned int getConstantScalar(Id resultId) const { return module.getInstruction(resultId)->getImmediateOperand(0); }
+ StorageClass getStorageClass(Id resultId) const { return getTypeStorageClass(getTypeId(resultId)); }
+
+ int getTypeNumColumns(Id typeId) const
+ {
+ assert(isMatrixType(typeId));
+ return getNumTypeConstituents(typeId);
+ }
+ int getNumColumns(Id resultId) const { return getTypeNumColumns(getTypeId(resultId)); }
+ int getTypeNumRows(Id typeId) const
+ {
+ assert(isMatrixType(typeId));
+ return getNumTypeComponents(getContainedTypeId(typeId));
+ }
+ int getNumRows(Id resultId) const { return getTypeNumRows(getTypeId(resultId)); }
+
+ Dim getTypeDimensionality(Id typeId) const
+ {
+ assert(isImageType(typeId));
+ return (Dim)module.getInstruction(typeId)->getImmediateOperand(1);
+ }
+ Id getImageType(Id resultId) const
+ {
+ Id typeId = getTypeId(resultId);
+ assert(isImageType(typeId) || isSampledImageType(typeId));
+ return isSampledImageType(typeId) ? module.getInstruction(typeId)->getIdOperand(0) : typeId;
+ }
+ bool isArrayedImageType(Id typeId) const
+ {
+ assert(isImageType(typeId));
+ return module.getInstruction(typeId)->getImmediateOperand(3) != 0;
+ }
+
+ // For making new constants (will return old constant if the requested one was already made).
+ Id makeBoolConstant(bool b, bool specConstant = false);
+ Id makeIntConstant(int i, bool specConstant = false) { return makeIntConstant(makeIntType(32), (unsigned)i, specConstant); }
+ Id makeUintConstant(unsigned u, bool specConstant = false) { return makeIntConstant(makeUintType(32), u, specConstant); }
+ Id makeInt64Constant(long long i, bool specConstant = false) { return makeInt64Constant(makeIntType(64), (unsigned long long)i, specConstant); }
+ Id makeUint64Constant(unsigned long long u, bool specConstant = false) { return makeInt64Constant(makeUintType(64), u, specConstant); }
+ Id makeFloatConstant(float f, bool specConstant = false);
+ Id makeDoubleConstant(double d, bool specConstant = false);
+#ifdef AMD_EXTENSIONS
+ Id makeFloat16Constant(float f16, bool specConstant = false);
+#endif
+
+ // Turn the array of constants into a proper spv constant of the requested type.
+ Id makeCompositeConstant(Id type, std::vector<Id>& comps, bool specConst = false);
+
+ // Methods for adding information outside the CFG.
+ Instruction* addEntryPoint(ExecutionModel, Function*, const char* name);
+ void addExecutionMode(Function*, ExecutionMode mode, int value1 = -1, int value2 = -1, int value3 = -1);
+ void addName(Id, const char* name);
+ void addMemberName(Id, int member, const char* name);
+ void addLine(Id target, Id fileName, int line, int column);
+ void addDecoration(Id, Decoration, int num = -1);
+ void addMemberDecoration(Id, unsigned int member, Decoration, int num = -1);
+
+ // At the end of what block do the next create*() instructions go?
+ void setBuildPoint(Block* bp) { buildPoint = bp; }
+ Block* getBuildPoint() const { return buildPoint; }
+
+ // Make the entry-point function. The returned pointer is only valid
+ // for the lifetime of this builder.
+ Function* makeEntryPoint(const char*);
+
+ // Make a shader-style function, and create its entry block if entry is non-zero.
+ // Return the function, pass back the entry.
+ // The returned pointer is only valid for the lifetime of this builder.
+ Function* makeFunctionEntry(Decoration precision, Id returnType, const char* name, const std::vector<Id>& paramTypes,
+ const std::vector<Decoration>& precisions, Block **entry = 0);
+
+ // Create a return. An 'implicit' return is one not appearing in the source
+ // code. In the case of an implicit return, no post-return block is inserted.
+ void makeReturn(bool implicit, Id retVal = 0);
+
+ // Generate all the code needed to finish up a function.
+ void leaveFunction();
+
+ // Create a discard.
+ void makeDiscard();
+
+ // Create a global or function local or IO variable.
+ Id createVariable(StorageClass, Id type, const char* name = 0);
+
+ // Create an intermediate with an undefined value.
+ Id createUndefined(Id type);
+
+ // Store into an Id and return the l-value
+ void createStore(Id rValue, Id lValue);
+
+ // Load from an Id and return it
+ Id createLoad(Id lValue);
+
+ // Create an OpAccessChain instruction
+ Id createAccessChain(StorageClass, Id base, std::vector<Id>& offsets);
+
+ // Create an OpArrayLength instruction
+ Id createArrayLength(Id base, unsigned int member);
+
+ // Create an OpCompositeExtract instruction
+ Id createCompositeExtract(Id composite, Id typeId, unsigned index);
+ Id createCompositeExtract(Id composite, Id typeId, std::vector<unsigned>& indexes);
+ Id createCompositeInsert(Id object, Id composite, Id typeId, unsigned index);
+ Id createCompositeInsert(Id object, Id composite, Id typeId, std::vector<unsigned>& indexes);
+
+ Id createVectorExtractDynamic(Id vector, Id typeId, Id componentIndex);
+ Id createVectorInsertDynamic(Id vector, Id typeId, Id component, Id componentIndex);
+
+ void createNoResultOp(Op);
+ void createNoResultOp(Op, Id operand);
+ void createNoResultOp(Op, const std::vector<Id>& operands);
+ void createControlBarrier(Scope execution, Scope memory, MemorySemanticsMask);
+ void createMemoryBarrier(unsigned executionScope, unsigned memorySemantics);
+ Id createUnaryOp(Op, Id typeId, Id operand);
+ Id createBinOp(Op, Id typeId, Id operand1, Id operand2);
+ Id createTriOp(Op, Id typeId, Id operand1, Id operand2, Id operand3);
+ Id createOp(Op, Id typeId, const std::vector<Id>& operands);
+ Id createFunctionCall(spv::Function*, std::vector<spv::Id>&);
+ Id createSpecConstantOp(Op, Id typeId, const std::vector<spv::Id>& operands, const std::vector<unsigned>& literals);
+
+ // Take an rvalue (source) and a set of channels to extract from it to
+ // make a new rvalue, which is returned.
+ Id createRvalueSwizzle(Decoration precision, Id typeId, Id source, std::vector<unsigned>& channels);
+
+ // Take a copy of an lvalue (target) and a source of components, and set the
+ // source components into the lvalue where the 'channels' say to put them.
+ // An updated version of the target is returned.
+ // (No true lvalue or stores are used.)
+ Id createLvalueSwizzle(Id typeId, Id target, Id source, std::vector<unsigned>& channels);
+
+ // If both the id and precision are valid, the id
+ // gets tagged with the requested precision.
+ // The passed in id is always the returned id, to simplify use patterns.
+ Id setPrecision(Id id, Decoration precision)
+ {
+ if (precision != NoPrecision && id != NoResult)
+ addDecoration(id, precision);
+
+ return id;
+ }
+
+ // Can smear a scalar to a vector for the following forms:
+ // - promoteScalar(scalar, vector) // smear scalar to width of vector
+ // - promoteScalar(vector, scalar) // smear scalar to width of vector
+ // - promoteScalar(pointer, scalar) // smear scalar to width of what pointer points to
+ // - promoteScalar(scalar, scalar) // do nothing
+ // Other forms are not allowed.
+ //
+ // Generally, the type of 'scalar' does not need to be the same type as the components in 'vector'.
+ // The type of the created vector is a vector of components of the same type as the scalar.
+ //
+ // Note: One of the arguments will change, with the result coming back that way rather than
+ // through the return value.
+ void promoteScalar(Decoration precision, Id& left, Id& right);
+
+ // Make a value by smearing the scalar to fill the type.
+ // vectorType should be the correct type for making a vector of scalarVal.
+ // (No conversions are done.)
+ Id smearScalar(Decoration precision, Id scalarVal, Id vectorType);
+
+ // Create a call to a built-in function.
+ Id createBuiltinCall(Id resultType, Id builtins, int entryPoint, std::vector<Id>& args);
+
+ // List of parameters used to create a texture operation
+ struct TextureParameters {
+ Id sampler;
+ Id coords;
+ Id bias;
+ Id lod;
+ Id Dref;
+ Id offset;
+ Id offsets;
+ Id gradX;
+ Id gradY;
+ Id sample;
+ Id component;
+ Id texelOut;
+ Id lodClamp;
+ };
+
+ // Select the correct texture operation based on all inputs, and emit the correct instruction
+ Id createTextureCall(Decoration precision, Id resultType, bool sparse, bool fetch, bool proj, bool gather, bool noImplicit, const TextureParameters&);
+
+ // Emit the OpTextureQuery* instruction that was passed in.
+ // Figure out the right return value and type, and return it.
+ Id createTextureQueryCall(Op, const TextureParameters&);
+
+ Id createSamplePositionCall(Decoration precision, Id, Id);
+
+ Id createBitFieldExtractCall(Decoration precision, Id, Id, Id, bool isSigned);
+ Id createBitFieldInsertCall(Decoration precision, Id, Id, Id, Id);
+
+ // Reduction comparison for composites: For equal and not-equal resulting in a scalar.
+ Id createCompositeCompare(Decoration precision, Id, Id, bool /* true if for equal, false if for not-equal */);
+
+ // OpCompositeConstruct
+ Id createCompositeConstruct(Id typeId, std::vector<Id>& constituents);
+
+ // vector or scalar constructor
+ Id createConstructor(Decoration precision, const std::vector<Id>& sources, Id resultTypeId);
+
+ // matrix constructor
+ Id createMatrixConstructor(Decoration precision, const std::vector<Id>& sources, Id constructee);
+
+ // Helper to use for building nested control flow with if-then-else.
+ class If {
+ public:
+ If(Id condition, Builder& builder);
+ ~If() {}
+
+ void makeBeginElse();
+ void makeEndIf();
+
+ private:
+ If(const If&);
+ If& operator=(If&);
+
+ Builder& builder;
+ Id condition;
+ Function* function;
+ Block* headerBlock;
+ Block* thenBlock;
+ Block* elseBlock;
+ Block* mergeBlock;
+ };
+
+ // Make a switch statement. A switch has 'numSegments' of pieces of code, not containing
+ // any case/default labels, all separated by one or more case/default labels. Each possible
+ // case value v is a jump to the caseValues[v] segment. The defaultSegment is also in this
+ // number space. How to compute the value is given by 'condition', as in switch(condition).
+ //
+ // The SPIR-V Builder will maintain the stack of post-switch merge blocks for nested switches.
+ //
+ // Use a defaultSegment < 0 if there is no default segment (to branch to post switch).
+ //
+ // Returns the right set of basic blocks to start each code segment with, so that the caller's
+ // recursion stack can hold the memory for it.
+ //
+ void makeSwitch(Id condition, int numSegments, std::vector<int>& caseValues, std::vector<int>& valueToSegment, int defaultSegment,
+ std::vector<Block*>& segmentBB); // return argument
+
+ // Add a branch to the innermost switch's merge block.
+ void addSwitchBreak();
+
+ // Move to the next code segment, passing in the return argument in makeSwitch()
+ void nextSwitchSegment(std::vector<Block*>& segmentBB, int segment);
+
+ // Finish off the innermost switch.
+ void endSwitch(std::vector<Block*>& segmentBB);
+
+ struct LoopBlocks {
+ LoopBlocks(Block& head, Block& body, Block& merge, Block& continue_target) :
+ head(head), body(body), merge(merge), continue_target(continue_target) { }
+ Block &head, &body, &merge, &continue_target;
+ private:
+ LoopBlocks();
+ LoopBlocks& operator=(const LoopBlocks&);
+ };
+
+ // Start a new loop and prepare the builder to generate code for it. Until
+ // closeLoop() is called for this loop, createLoopContinue() and
+ // createLoopExit() will target its corresponding blocks.
+ LoopBlocks& makeNewLoop();
+
+ // Create a new block in the function containing the build point. Memory is
+ // owned by the function object.
+ Block& makeNewBlock();
+
+ // Add a branch to the continue_target of the current (innermost) loop.
+ void createLoopContinue();
+
+ // Add an exit (e.g. "break") from the innermost loop that we're currently
+ // in.
+ void createLoopExit();
+
+ // Close the innermost loop that you're in
+ void closeLoop();
+
+ //
+ // Access chain design for an R-Value vs. L-Value:
+ //
+ // There is a single access chain the builder is building at
+ // any particular time. Such a chain can be used to either to a load or
+ // a store, when desired.
+ //
+ // Expressions can be r-values, l-values, or both, or only r-values:
+ // a[b.c].d = .... // l-value
+ // ... = a[b.c].d; // r-value, that also looks like an l-value
+ // ++a[b.c].d; // r-value and l-value
+ // (x + y)[2]; // r-value only, can't possibly be l-value
+ //
+ // Computing an r-value means generating code. Hence,
+ // r-values should only be computed when they are needed, not speculatively.
+ //
+ // Computing an l-value means saving away information for later use in the compiler,
+ // no code is generated until the l-value is later dereferenced. It is okay
+ // to speculatively generate an l-value, just not okay to speculatively dereference it.
+ //
+ // The base of the access chain (the left-most variable or expression
+ // from which everything is based) can be set either as an l-value
+ // or as an r-value. Most efficient would be to set an l-value if one
+ // is available. If an expression was evaluated, the resulting r-value
+ // can be set as the chain base.
+ //
+ // The users of this single access chain can save and restore if they
+ // want to nest or manage multiple chains.
+ //
+
+ struct AccessChain {
+ Id base; // for l-values, pointer to the base object, for r-values, the base object
+ std::vector<Id> indexChain;
+ Id instr; // cache the instruction that generates this access chain
+ std::vector<unsigned> swizzle; // each std::vector element selects the next GLSL component number
+ Id component; // a dynamic component index, can coexist with a swizzle, done after the swizzle, NoResult if not present
+ Id preSwizzleBaseType; // dereferenced type, before swizzle or component is applied; NoType unless a swizzle or component is present
+ bool isRValue; // true if 'base' is an r-value, otherwise, base is an l-value
+ };
+
+ //
+ // the SPIR-V builder maintains a single active chain that
+ // the following methods operate on
+ //
+
+ // for external save and restore
+ AccessChain getAccessChain() { return accessChain; }
+ void setAccessChain(AccessChain newChain) { accessChain = newChain; }
+
+ // clear accessChain
+ void clearAccessChain();
+
+ // set new base as an l-value base
+ void setAccessChainLValue(Id lValue)
+ {
+ assert(isPointer(lValue));
+ accessChain.base = lValue;
+ }
+
+ // set new base value as an r-value
+ void setAccessChainRValue(Id rValue)
+ {
+ accessChain.isRValue = true;
+ accessChain.base = rValue;
+ }
+
+ // push offset onto the end of the chain
+ void accessChainPush(Id offset)
+ {
+ accessChain.indexChain.push_back(offset);
+ }
+
+ // push new swizzle onto the end of any existing swizzle, merging into a single swizzle
+ void accessChainPushSwizzle(std::vector<unsigned>& swizzle, Id preSwizzleBaseType);
+
+ // push a variable component selection onto the access chain; supporting only one, so unsided
+ void accessChainPushComponent(Id component, Id preSwizzleBaseType)
+ {
+ accessChain.component = component;
+ if (accessChain.preSwizzleBaseType == NoType)
+ accessChain.preSwizzleBaseType = preSwizzleBaseType;
+ }
+
+ // use accessChain and swizzle to store value
+ void accessChainStore(Id rvalue);
+
+ // use accessChain and swizzle to load an r-value
+ Id accessChainLoad(Decoration precision, Id ResultType);
+
+ // get the direct pointer for an l-value
+ Id accessChainGetLValue();
+
+ // Get the inferred SPIR-V type of the result of the current access chain,
+ // based on the type of the base and the chain of dereferences.
+ Id accessChainGetInferredType();
+
+ // Remove OpDecorate instructions whose operands are defined in unreachable
+ // blocks.
+ void eliminateDeadDecorations();
+ void dump(std::vector<unsigned int>&) const;
+
+ void createBranch(Block* block);
+ void createConditionalBranch(Id condition, Block* thenBlock, Block* elseBlock);
+ void createLoopMerge(Block* mergeBlock, Block* continueBlock, unsigned int control);
+
+ // Sets to generate opcode for specialization constants.
+ void setToSpecConstCodeGenMode() { generatingOpCodeForSpecConst = true; }
+ // Sets to generate opcode for non-specialization constants (normal mode).
+ void setToNormalCodeGenMode() { generatingOpCodeForSpecConst = false; }
+ // Check if the builder is generating code for spec constants.
+ bool isInSpecConstCodeGenMode() { return generatingOpCodeForSpecConst; }
+
+ protected:
+ Id makeIntConstant(Id typeId, unsigned value, bool specConstant);
+ Id makeInt64Constant(Id typeId, unsigned long long value, bool specConstant);
+ Id findScalarConstant(Op typeClass, Op opcode, Id typeId, unsigned value) const;
+ Id findScalarConstant(Op typeClass, Op opcode, Id typeId, unsigned v1, unsigned v2) const;
+ Id findCompositeConstant(Op typeClass, std::vector<Id>& comps) const;
+ Id collapseAccessChain();
+ void transferAccessChainSwizzle(bool dynamic);
+ void simplifyAccessChainSwizzle();
+ void createAndSetNoPredecessorBlock(const char*);
+ void createSelectionMerge(Block* mergeBlock, unsigned int control);
+ void dumpInstructions(std::vector<unsigned int>&, const std::vector<std::unique_ptr<Instruction> >&) const;
+
+ SourceLanguage source;
+ int sourceVersion;
+ std::set<const char*> extensions;
+ std::vector<const char*> sourceExtensions;
+ AddressingModel addressModel;
+ MemoryModel memoryModel;
+ std::set<spv::Capability> capabilities;
+ int builderNumber;
+ Module module;
+ Block* buildPoint;
+ Id uniqueId;
+ Function* entryPointFunction;
+ bool generatingOpCodeForSpecConst;
+ AccessChain accessChain;
+
+ // special blocks of instructions for output
+ std::vector<std::unique_ptr<Instruction> > imports;
+ std::vector<std::unique_ptr<Instruction> > entryPoints;
+ std::vector<std::unique_ptr<Instruction> > executionModes;
+ std::vector<std::unique_ptr<Instruction> > names;
+ std::vector<std::unique_ptr<Instruction> > lines;
+ std::vector<std::unique_ptr<Instruction> > decorations;
+ std::vector<std::unique_ptr<Instruction> > constantsTypesGlobals;
+ std::vector<std::unique_ptr<Instruction> > externals;
+ std::vector<std::unique_ptr<Function> > functions;
+
+ // not output, internally used for quick & dirty canonical (unique) creation
+ std::vector<Instruction*> groupedConstants[OpConstant]; // all types appear before OpConstant
+ std::vector<Instruction*> groupedTypes[OpConstant];
+
+ // stack of switches
+ std::stack<Block*> switchMerges;
+
+ // Our loop stack.
+ std::stack<LoopBlocks> loops;
+
+ // The stream for outputing warnings and errors.
+ SpvBuildLogger* logger;
+}; // end Builder class
+
+}; // end spv namespace
+
+#endif // SpvBuilder_H