From a5845766e0d89aa0b7aa597fe74a93296f4aeb0d Mon Sep 17 00:00:00 2001 From: John Kessenich Date: Sun, 20 Mar 2016 16:46:00 -0600 Subject: [PATCH] Front-end: Add specialization-constant subtrees for const variables/symbols. --- SPIRV/GlslangToSpv.cpp | 1 + glslang/Include/intermediate.h | 20 ++++++++++++-------- glslang/MachineIndependent/Intermediate.cpp | 8 +++++--- glslang/MachineIndependent/ParseHelper.cpp | 17 +++++++++++++++-- glslang/MachineIndependent/SymbolTable.cpp | 9 ++++++--- glslang/MachineIndependent/SymbolTable.h | 22 ++++++++++++++++------ glslang/MachineIndependent/intermOut.cpp | 5 +++++ glslang/MachineIndependent/localintermediate.h | 2 +- 8 files changed, 61 insertions(+), 23 deletions(-) diff --git a/SPIRV/GlslangToSpv.cpp b/SPIRV/GlslangToSpv.cpp index b837a25..6f5697e 100755 --- a/SPIRV/GlslangToSpv.cpp +++ b/SPIRV/GlslangToSpv.cpp @@ -3763,6 +3763,7 @@ spv::Id TGlslangToSpvTraverser::createSpvSpecConstant(const glslang::TIntermType return builder.makeCompositeConstant(builder.makeVectorType(builder.makeUintType(32), 3), dimConstId, true); } else { spv::MissingFunctionality("specialization-constant expression trees"); + exit(1); return spv::NoResult; } } diff --git a/glslang/Include/intermediate.h b/glslang/Include/intermediate.h index ce5fb77..ab17701 100644 --- a/glslang/Include/intermediate.h +++ b/glslang/Include/intermediate.h @@ -612,25 +612,29 @@ public: // if symbol is initialized as symbol(sym), the memory comes from the pool allocator of sym. If sym comes from // per process threadPoolAllocator, then it causes increased memory usage per compile // it is essential to use "symbol = sym" to assign to symbol - TIntermSymbol(int i, const TString& n, const TType& t) : - TIntermTyped(t), id(i) { name = n;} + TIntermSymbol(int i, const TString& n, const TType& t) + : TIntermTyped(t), id(i), constSubtree(nullptr) + { name = n; } virtual int getId() const { return id; } virtual const TString& getName() const { return name; } virtual void traverse(TIntermTraverser*); virtual TIntermSymbol* getAsSymbolNode() { return this; } virtual const TIntermSymbol* getAsSymbolNode() const { return this; } - void setConstArray(const TConstUnionArray& c) { unionArray = c; } - const TConstUnionArray& getConstArray() const { return unionArray; } + void setConstArray(const TConstUnionArray& c) { constArray = c; } + const TConstUnionArray& getConstArray() const { return constArray; } + void setConstSubtree(TIntermTyped* subtree) { constSubtree = subtree; } + TIntermTyped* getConstSubtree() const { return constSubtree; } protected: int id; // the unique id of the symbol this node represents TString name; // the name of the symbol this node represents - TConstUnionArray unionArray; // if the symbol is a front-end compile-time constant, this is its value + TConstUnionArray constArray; // if the symbol is a front-end compile-time constant, this is its value + TIntermTyped* constSubtree; }; class TIntermConstantUnion : public TIntermTyped { public: - TIntermConstantUnion(const TConstUnionArray& ua, const TType& t) : TIntermTyped(t), unionArray(ua), literal(false) { } - const TConstUnionArray& getConstArray() const { return unionArray; } + TIntermConstantUnion(const TConstUnionArray& ua, const TType& t) : TIntermTyped(t), constArray(ua), literal(false) { } + const TConstUnionArray& getConstArray() const { return constArray; } virtual TIntermConstantUnion* getAsConstantUnion() { return this; } virtual const TIntermConstantUnion* getAsConstantUnion() const { return this; } virtual void traverse(TIntermTraverser*); @@ -640,7 +644,7 @@ public: void setExpression() { literal = false; } bool isLiteral() const { return literal; } protected: - const TConstUnionArray unionArray; + const TConstUnionArray constArray; bool literal; // true if node represents a literal in the source code }; diff --git a/glslang/MachineIndependent/Intermediate.cpp b/glslang/MachineIndependent/Intermediate.cpp index 5f47491..bb4e14b 100644 --- a/glslang/MachineIndependent/Intermediate.cpp +++ b/glslang/MachineIndependent/Intermediate.cpp @@ -61,11 +61,13 @@ namespace glslang { // Returns the added node. // -TIntermSymbol* TIntermediate::addSymbol(int id, const TString& name, const TType& type, const TConstUnionArray& constArray, const TSourceLoc& loc) +TIntermSymbol* TIntermediate::addSymbol(int id, const TString& name, const TType& type, const TConstUnionArray& constArray, + TIntermTyped* constSubtree, const TSourceLoc& loc) { TIntermSymbol* node = new TIntermSymbol(id, name, type); node->setLoc(loc); node->setConstArray(constArray); + node->setConstSubtree(constSubtree); return node; } @@ -80,14 +82,14 @@ TIntermSymbol* TIntermediate::addSymbol(const TVariable& variable) TIntermSymbol* TIntermediate::addSymbol(const TVariable& variable, const TSourceLoc& loc) { - return addSymbol(variable.getUniqueId(), variable.getName(), variable.getType(), variable.getConstArray(), loc); + return addSymbol(variable.getUniqueId(), variable.getName(), variable.getType(), variable.getConstArray(), variable.getConstSubtree(), loc); } TIntermSymbol* TIntermediate::addSymbol(const TType& type, const TSourceLoc& loc) { TConstUnionArray unionArray; // just a null constant - return addSymbol(0, "", type, unionArray, loc); + return addSymbol(0, "", type, unionArray, nullptr, loc); } // diff --git a/glslang/MachineIndependent/ParseHelper.cpp b/glslang/MachineIndependent/ParseHelper.cpp index 9057b34..cd745a9 100644 --- a/glslang/MachineIndependent/ParseHelper.cpp +++ b/glslang/MachineIndependent/ParseHelper.cpp @@ -4914,14 +4914,27 @@ TIntermNode* TParseContext::executeInitializer(const TSourceLoc& loc, TIntermTyp // Compile-time tagging of the variable with its constant value... initializer = intermediate.addConversion(EOpAssign, variable->getType(), initializer); - if (! initializer || ! initializer->getAsConstantUnion() || variable->getType() != initializer->getType()) { + if (! initializer || ! initializer->getType().getQualifier().isConstant() || variable->getType() != initializer->getType()) { error(loc, "non-matching or non-convertible constant type for const initializer", variable->getType().getStorageQualifierString(), ""); variable->getWritableType().getQualifier().makeTemporary(); return nullptr; } - variable->setConstArray(initializer->getAsConstantUnion()->getConstArray()); + // We either have a folded constant in getAsConstantUnion, or we have to use + // the initializer's subtree in the AST to represent the computation of a + // specialization constant. + assert(initializer->getAsConstantUnion() || initializer->getType().getQualifier().isSpecConstant()); + if (initializer->getAsConstantUnion()) + variable->setConstArray(initializer->getAsConstantUnion()->getConstArray()); + else { + // It's a specialization constant. + variable->getWritableType().getQualifier().makeSpecConstant(); + + // Keep the subtree that computes the specialization constant with the variable. + // Later, a symbol node will adopt the subtree from the variable. + variable->setConstSubtree(initializer); + } } else { // normal assigning of a value to a variable... specializationCheck(loc, initializer->getType(), "initializer"); diff --git a/glslang/MachineIndependent/SymbolTable.cpp b/glslang/MachineIndependent/SymbolTable.cpp index 9794a5d..75f5040 100644 --- a/glslang/MachineIndependent/SymbolTable.cpp +++ b/glslang/MachineIndependent/SymbolTable.cpp @@ -252,11 +252,14 @@ TVariable::TVariable(const TVariable& copyOf) : TSymbol(copyOf) if (copyOf.numExtensions != 0) setExtensions(copyOf.numExtensions, copyOf.extensions); - if (! copyOf.unionArray.empty()) { + if (! copyOf.constArray.empty()) { assert(! copyOf.type.isStruct()); - TConstUnionArray newArray(copyOf.unionArray, 0, copyOf.unionArray.size()); - unionArray = newArray; + TConstUnionArray newArray(copyOf.constArray, 0, copyOf.constArray.size()); + constArray = newArray; } + + // don't support specialization-constant subtrees in cloned tables + constSubtree = nullptr; } TVariable* TVariable::clone() const diff --git a/glslang/MachineIndependent/SymbolTable.h b/glslang/MachineIndependent/SymbolTable.h index ad73b3b..9877ab7 100644 --- a/glslang/MachineIndependent/SymbolTable.h +++ b/glslang/MachineIndependent/SymbolTable.h @@ -135,7 +135,7 @@ protected: // // Variable class, meaning a symbol that's not a function. // -// There could be a separate class heirarchy for Constant variables; +// There could be a separate class hierarchy for Constant variables; // Only one of int, bool, or float, (or none) is correct for // any particular use, but it's easy to do this way, and doesn't // seem worth having separate classes, and "getConst" can't simply return @@ -144,7 +144,10 @@ protected: // class TVariable : public TSymbol { public: - TVariable(const TString *name, const TType& t, bool uT = false ) : TSymbol(name), userType(uT) { type.shallowCopy(t); } + TVariable(const TString *name, const TType& t, bool uT = false ) + : TSymbol(name), + userType(uT), + constSubtree(nullptr) { type.shallowCopy(t); } virtual TVariable* clone() const; virtual ~TVariable() { } @@ -153,9 +156,11 @@ public: virtual const TType& getType() const { return type; } virtual TType& getWritableType() { assert(writable); return type; } virtual bool isUserType() const { return userType; } - virtual const TConstUnionArray& getConstArray() const { return unionArray; } - virtual TConstUnionArray& getWritableConstArray() { assert(writable); return unionArray; } - virtual void setConstArray(const TConstUnionArray& constArray) { unionArray = constArray; } + virtual const TConstUnionArray& getConstArray() const { return constArray; } + virtual TConstUnionArray& getWritableConstArray() { assert(writable); return constArray; } + virtual void setConstArray(const TConstUnionArray& array) { constArray = array; } + virtual void setConstSubtree(TIntermTyped* subtree) { constSubtree = subtree; } + virtual TIntermTyped* getConstSubtree() const { return constSubtree; } virtual void dump(TInfoSink &infoSink) const; @@ -167,7 +172,12 @@ protected: bool userType; // we are assuming that Pool Allocator will free the memory allocated to unionArray // when this object is destroyed - TConstUnionArray unionArray; + + // TODO: these two should be a union + // A variable could be a compile-time constant, or a specialization + // constant, or neither, but never both. + TConstUnionArray constArray; // for compile-time constant value + TIntermTyped* constSubtree; // for specialization constant computation }; // diff --git a/glslang/MachineIndependent/intermOut.cpp b/glslang/MachineIndependent/intermOut.cpp index 96b5c25..eb6c30c 100644 --- a/glslang/MachineIndependent/intermOut.cpp +++ b/glslang/MachineIndependent/intermOut.cpp @@ -605,6 +605,11 @@ void TOutputTraverser::visitSymbol(TIntermSymbol* node) if (! node->getConstArray().empty()) OutputConstantUnion(infoSink, node, node->getConstArray(), depth + 1); + else if (node->getConstSubtree()) { + incrementDepth(node); + node->getConstSubtree()->traverse(this); + decrementDepth(); + } } bool TOutputTraverser::visitLoop(TVisit /* visit */, TIntermLoop* node) diff --git a/glslang/MachineIndependent/localintermediate.h b/glslang/MachineIndependent/localintermediate.h index f25c0f1..5e5a2e7 100644 --- a/glslang/MachineIndependent/localintermediate.h +++ b/glslang/MachineIndependent/localintermediate.h @@ -326,7 +326,7 @@ public: static int getBaseAlignment(const TType&, int& size, int& stride, bool std140, bool rowMajor); protected: - TIntermSymbol* addSymbol(int Id, const TString&, const TType&, const TConstUnionArray&, const TSourceLoc&); + TIntermSymbol* addSymbol(int Id, const TString&, const TType&, const TConstUnionArray&, TIntermTyped* subtree, const TSourceLoc&); void error(TInfoSink& infoSink, const char*); void mergeBodies(TInfoSink&, TIntermSequence& globals, const TIntermSequence& unitGlobals); void mergeLinkerObjects(TInfoSink&, TIntermSequence& linkerObjects, const TIntermSequence& unitLinkerObjects); -- 2.7.4