return builder.makeCompositeConstant(builder.makeVectorType(builder.makeUintType(32), 3), dimConstId, true);
} else {
spv::MissingFunctionality("specialization-constant expression trees");
+ exit(1);
return spv::NoResult;
}
}
// 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*);
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
};
// 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;
}
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);
}
//
// 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");
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
//
// 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
//
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() { }
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;
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
};
//
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)
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);