Front-end: Add specialization-constant subtrees for const variables/symbols.
This commit is contained in:
parent
7cc0e2896e
commit
a5845766e0
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@ -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
|
||||
};
|
||||
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
@ -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");
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
};
|
||||
|
||||
//
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user