Front-end: Add specialization-constant subtrees for const variables/symbols.
authorJohn Kessenich <cepheus@frii.com>
Sun, 20 Mar 2016 22:46:00 +0000 (16:46 -0600)
committerJohn Kessenich <cepheus@frii.com>
Sun, 20 Mar 2016 22:46:00 +0000 (16:46 -0600)
SPIRV/GlslangToSpv.cpp
glslang/Include/intermediate.h
glslang/MachineIndependent/Intermediate.cpp
glslang/MachineIndependent/ParseHelper.cpp
glslang/MachineIndependent/SymbolTable.cpp
glslang/MachineIndependent/SymbolTable.h
glslang/MachineIndependent/intermOut.cpp
glslang/MachineIndependent/localintermediate.h

index b837a25..6f5697e 100755 (executable)
@@ -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;
         }
     }
index ce5fb77..ab17701 100644 (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
 };
 
index 5f47491..bb4e14b 100644 (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);
 }
 
 //
index 9057b34..cd745a9 100644 (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;
         }
 
-        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");
index 9794a5d..75f5040 100644 (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
index ad73b3b..9877ab7 100644 (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
 };
 
 //
index 96b5c25..eb6c30c 100644 (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)
index f25c0f1..5e5a2e7 100644 (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);