Front-end: Add specialization-constant subtrees for const variables/symbols.

This commit is contained in:
John Kessenich 2016-03-20 16:46:00 -06:00
parent 7cc0e2896e
commit a5845766e0
8 changed files with 61 additions and 23 deletions

View File

@ -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;
}
}

View File

@ -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
};

View File

@ -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);
}
//

View File

@ -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;
}
// 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");

View File

@ -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

View File

@ -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
};
//

View File

@ -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)

View File

@ -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);