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);
|
return builder.makeCompositeConstant(builder.makeVectorType(builder.makeUintType(32), 3), dimConstId, true);
|
||||||
} else {
|
} else {
|
||||||
spv::MissingFunctionality("specialization-constant expression trees");
|
spv::MissingFunctionality("specialization-constant expression trees");
|
||||||
|
exit(1);
|
||||||
return spv::NoResult;
|
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
|
// 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
|
// per process threadPoolAllocator, then it causes increased memory usage per compile
|
||||||
// it is essential to use "symbol = sym" to assign to symbol
|
// it is essential to use "symbol = sym" to assign to symbol
|
||||||
TIntermSymbol(int i, const TString& n, const TType& t) :
|
TIntermSymbol(int i, const TString& n, const TType& t)
|
||||||
TIntermTyped(t), id(i) { name = n;}
|
: TIntermTyped(t), id(i), constSubtree(nullptr)
|
||||||
|
{ name = n; }
|
||||||
virtual int getId() const { return id; }
|
virtual int getId() const { return id; }
|
||||||
virtual const TString& getName() const { return name; }
|
virtual const TString& getName() const { return name; }
|
||||||
virtual void traverse(TIntermTraverser*);
|
virtual void traverse(TIntermTraverser*);
|
||||||
virtual TIntermSymbol* getAsSymbolNode() { return this; }
|
virtual TIntermSymbol* getAsSymbolNode() { return this; }
|
||||||
virtual const TIntermSymbol* getAsSymbolNode() const { return this; }
|
virtual const TIntermSymbol* getAsSymbolNode() const { return this; }
|
||||||
void setConstArray(const TConstUnionArray& c) { unionArray = c; }
|
void setConstArray(const TConstUnionArray& c) { constArray = c; }
|
||||||
const TConstUnionArray& getConstArray() const { return unionArray; }
|
const TConstUnionArray& getConstArray() const { return constArray; }
|
||||||
|
void setConstSubtree(TIntermTyped* subtree) { constSubtree = subtree; }
|
||||||
|
TIntermTyped* getConstSubtree() const { return constSubtree; }
|
||||||
protected:
|
protected:
|
||||||
int id; // the unique id of the symbol this node represents
|
int id; // the unique id of the symbol this node represents
|
||||||
TString name; // the name 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 {
|
class TIntermConstantUnion : public TIntermTyped {
|
||||||
public:
|
public:
|
||||||
TIntermConstantUnion(const TConstUnionArray& ua, const TType& t) : TIntermTyped(t), unionArray(ua), literal(false) { }
|
TIntermConstantUnion(const TConstUnionArray& ua, const TType& t) : TIntermTyped(t), constArray(ua), literal(false) { }
|
||||||
const TConstUnionArray& getConstArray() const { return unionArray; }
|
const TConstUnionArray& getConstArray() const { return constArray; }
|
||||||
virtual TIntermConstantUnion* getAsConstantUnion() { return this; }
|
virtual TIntermConstantUnion* getAsConstantUnion() { return this; }
|
||||||
virtual const TIntermConstantUnion* getAsConstantUnion() const { return this; }
|
virtual const TIntermConstantUnion* getAsConstantUnion() const { return this; }
|
||||||
virtual void traverse(TIntermTraverser*);
|
virtual void traverse(TIntermTraverser*);
|
||||||
@ -640,7 +644,7 @@ public:
|
|||||||
void setExpression() { literal = false; }
|
void setExpression() { literal = false; }
|
||||||
bool isLiteral() const { return literal; }
|
bool isLiteral() const { return literal; }
|
||||||
protected:
|
protected:
|
||||||
const TConstUnionArray unionArray;
|
const TConstUnionArray constArray;
|
||||||
bool literal; // true if node represents a literal in the source code
|
bool literal; // true if node represents a literal in the source code
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -61,11 +61,13 @@ namespace glslang {
|
|||||||
// Returns the added node.
|
// 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);
|
TIntermSymbol* node = new TIntermSymbol(id, name, type);
|
||||||
node->setLoc(loc);
|
node->setLoc(loc);
|
||||||
node->setConstArray(constArray);
|
node->setConstArray(constArray);
|
||||||
|
node->setConstSubtree(constSubtree);
|
||||||
|
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
@ -80,14 +82,14 @@ TIntermSymbol* TIntermediate::addSymbol(const TVariable& variable)
|
|||||||
|
|
||||||
TIntermSymbol* TIntermediate::addSymbol(const TVariable& variable, const TSourceLoc& loc)
|
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)
|
TIntermSymbol* TIntermediate::addSymbol(const TType& type, const TSourceLoc& loc)
|
||||||
{
|
{
|
||||||
TConstUnionArray unionArray; // just a null constant
|
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...
|
// Compile-time tagging of the variable with its constant value...
|
||||||
|
|
||||||
initializer = intermediate.addConversion(EOpAssign, variable->getType(), initializer);
|
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",
|
error(loc, "non-matching or non-convertible constant type for const initializer",
|
||||||
variable->getType().getStorageQualifierString(), "");
|
variable->getType().getStorageQualifierString(), "");
|
||||||
variable->getWritableType().getQualifier().makeTemporary();
|
variable->getWritableType().getQualifier().makeTemporary();
|
||||||
return nullptr;
|
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());
|
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 {
|
} else {
|
||||||
// normal assigning of a value to a variable...
|
// normal assigning of a value to a variable...
|
||||||
specializationCheck(loc, initializer->getType(), "initializer");
|
specializationCheck(loc, initializer->getType(), "initializer");
|
||||||
|
|||||||
@ -252,11 +252,14 @@ TVariable::TVariable(const TVariable& copyOf) : TSymbol(copyOf)
|
|||||||
if (copyOf.numExtensions != 0)
|
if (copyOf.numExtensions != 0)
|
||||||
setExtensions(copyOf.numExtensions, copyOf.extensions);
|
setExtensions(copyOf.numExtensions, copyOf.extensions);
|
||||||
|
|
||||||
if (! copyOf.unionArray.empty()) {
|
if (! copyOf.constArray.empty()) {
|
||||||
assert(! copyOf.type.isStruct());
|
assert(! copyOf.type.isStruct());
|
||||||
TConstUnionArray newArray(copyOf.unionArray, 0, copyOf.unionArray.size());
|
TConstUnionArray newArray(copyOf.constArray, 0, copyOf.constArray.size());
|
||||||
unionArray = newArray;
|
constArray = newArray;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// don't support specialization-constant subtrees in cloned tables
|
||||||
|
constSubtree = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
TVariable* TVariable::clone() const
|
TVariable* TVariable::clone() const
|
||||||
|
|||||||
@ -135,7 +135,7 @@ protected:
|
|||||||
//
|
//
|
||||||
// Variable class, meaning a symbol that's not a function.
|
// 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
|
// 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
|
// 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
|
// seem worth having separate classes, and "getConst" can't simply return
|
||||||
@ -144,7 +144,10 @@ protected:
|
|||||||
//
|
//
|
||||||
class TVariable : public TSymbol {
|
class TVariable : public TSymbol {
|
||||||
public:
|
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* clone() const;
|
||||||
virtual ~TVariable() { }
|
virtual ~TVariable() { }
|
||||||
|
|
||||||
@ -153,9 +156,11 @@ public:
|
|||||||
virtual const TType& getType() const { return type; }
|
virtual const TType& getType() const { return type; }
|
||||||
virtual TType& getWritableType() { assert(writable); return type; }
|
virtual TType& getWritableType() { assert(writable); return type; }
|
||||||
virtual bool isUserType() const { return userType; }
|
virtual bool isUserType() const { return userType; }
|
||||||
virtual const TConstUnionArray& getConstArray() const { return unionArray; }
|
virtual const TConstUnionArray& getConstArray() const { return constArray; }
|
||||||
virtual TConstUnionArray& getWritableConstArray() { assert(writable); return unionArray; }
|
virtual TConstUnionArray& getWritableConstArray() { assert(writable); return constArray; }
|
||||||
virtual void setConstArray(const TConstUnionArray& constArray) { unionArray = 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;
|
virtual void dump(TInfoSink &infoSink) const;
|
||||||
|
|
||||||
@ -167,7 +172,12 @@ protected:
|
|||||||
bool userType;
|
bool userType;
|
||||||
// we are assuming that Pool Allocator will free the memory allocated to unionArray
|
// we are assuming that Pool Allocator will free the memory allocated to unionArray
|
||||||
// when this object is destroyed
|
// 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())
|
if (! node->getConstArray().empty())
|
||||||
OutputConstantUnion(infoSink, node, node->getConstArray(), depth + 1);
|
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)
|
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);
|
static int getBaseAlignment(const TType&, int& size, int& stride, bool std140, bool rowMajor);
|
||||||
|
|
||||||
protected:
|
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 error(TInfoSink& infoSink, const char*);
|
||||||
void mergeBodies(TInfoSink&, TIntermSequence& globals, const TIntermSequence& unitGlobals);
|
void mergeBodies(TInfoSink&, TIntermSequence& globals, const TIntermSequence& unitGlobals);
|
||||||
void mergeLinkerObjects(TInfoSink&, TIntermSequence& linkerObjects, const TIntermSequence& unitLinkerObjects);
|
void mergeLinkerObjects(TInfoSink&, TIntermSequence& linkerObjects, const TIntermSequence& unitLinkerObjects);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user