diff --git a/Test/300block.frag b/Test/300block.frag index c6d9fcc8c50f2b16b26b2747b728e4188e88f0a9..25aab8ad18c0f26c3a09e23a55e44a75b348538a 100644 --- a/Test/300block.frag +++ b/Test/300block.frag @@ -34,6 +34,11 @@ uniform barBlockArray { int ni; } insts[4]; +uniform unreferenced { + float f; + uint u; +}; + void main() { texture(s.sampler, vec3(inst.ni, bv.y, insts[2].nbv.z)); diff --git a/glslang/Include/intermediate.h b/glslang/Include/intermediate.h index f5a1d4445d93594dd66e6abf7c53e6c48ed741ec..ec11f617124b77094693447369a31c94270910ea 100644 --- a/glslang/Include/intermediate.h +++ b/glslang/Include/intermediate.h @@ -56,6 +56,7 @@ enum TOperator { EOpNull, // if in a node, should only mean a node is still being built EOpSequence, // denotes a list of statements, or parameters, etc. + EOpLinkerObjects, // for aggregate node of objects the linker may need, if not reference by the rest of the AST EOpFunctionCall, EOpFunction, // For function definition EOpParameters, // an aggregate listing the parameters to a function @@ -353,6 +354,7 @@ public: virtual TBasicType getBasicType() const { return type.getBasicType(); } virtual TQualifier& getQualifier() { return type.getQualifier(); } + virtual const TQualifier& getQualifier() const { return type.getQualifier(); } virtual void propagatePrecision(TPrecisionQualifier); virtual int getVectorSize() const { return type.getVectorSize(); } virtual int getMatrixCols() const { return type.getMatrixCols(); } @@ -431,15 +433,15 @@ public: // if symbol is initialized as symbol(sym), the memory comes from the poolallocator of sym. If sym comes from // per process globalpoolallocator, then it causes increased memory usage per compile // it is essential to use "symbol = sym" to assign to symbol - TIntermSymbol(int i, const TString& sym, const TType& t) : - TIntermTyped(t), id(i) { symbol = sym;} + TIntermSymbol(int i, const TString& n, const TType& t) : + TIntermTyped(t), id(i) { name = n;} virtual int getId() const { return id; } - virtual const TString& getSymbol() const { return symbol; } + virtual const TString& getName() const { return name; } virtual void traverse(TIntermTraverser*); virtual TIntermSymbol* getAsSymbolNode() { return this; } protected: int id; - TString symbol; + TString name; }; class TIntermConstantUnion : public TIntermTyped { @@ -519,12 +521,14 @@ public: virtual TIntermAggregate* getAsAggregate() { return this; } virtual void setOperator(TOperator o) { op = o; } virtual TIntermSequence& getSequence() { return sequence; } + virtual const TIntermSequence& getSequence() const { return sequence; } virtual void setName(const TString& n) { name = n; } virtual const TString& getName() const { return name; } virtual void traverse(TIntermTraverser*); virtual void setUserDefined() { userDefined = true; } virtual bool isUserDefined() { return userDefined; } virtual TQualifierList& getQualifierList() { return qualifier; } + virtual const TQualifierList& getQualifierList() const { return qualifier; } void setOptimize(bool o) { optimize = o; } void setDebug(bool d) { debug = d; } bool getOptimize() { return optimize; } diff --git a/glslang/MachineIndependent/Intermediate.cpp b/glslang/MachineIndependent/Intermediate.cpp index 771bb17cc688150fb279a206e3618930b0cd27e2..df807e8d941a956ca44e2df3e8bfbe980a9576af 100644 --- a/glslang/MachineIndependent/Intermediate.cpp +++ b/glslang/MachineIndependent/Intermediate.cpp @@ -835,7 +835,7 @@ TIntermBranch* TIntermediate::addBranch(TOperator branchOp, TIntermTyped* expres } // -// This is to be executed once the final root is put on top by the parsing +// This is to be executed after the final root is put on top by the parsing // process. // bool TIntermediate::postProcess(TIntermNode* root, EShLanguage language) @@ -843,9 +843,7 @@ bool TIntermediate::postProcess(TIntermNode* root, EShLanguage language) if (root == 0) return true; - // - // First, finish off the top level sequence, if any - // + // Finish off the top-level sequence TIntermAggregate* aggRoot = root->getAsAggregate(); if (aggRoot && aggRoot->getOp() == EOpNull) aggRoot->setOperator(EOpSequence); @@ -853,6 +851,58 @@ bool TIntermediate::postProcess(TIntermNode* root, EShLanguage language) return true; } +void TIntermediate::addSymbolLinkageNodes(TIntermNode* root, TIntermAggregate*& linkage, EShLanguage language, TSymbolTable& symbolTable) +{ + // Add top-level nodes for declarations that must be checked cross + // compilation unit by a linker, yet might not have been referenced + // by the AST. + // + // Almost entirely, translation of symbols is driven by what's present + // in the AST traversal, not by translating the symbol table. + // + // However, there are some special cases: + // - From the specification: "Special built-in inputs gl_VertexID and + // gl_InstanceID are also considered active vertex attributes." + // - Linker-based type mismatch error reporting needs to see all + // uniforms/ins/outs variables and blocks. + // - ftransform() can make gl_Vertex and gl_ModelViewProjectionMatrix active. + // + + //if (ftransformUsed) { + // TODO: desktop: track ftransform() usage + // addSymbolLinkageNode(root, symbolTable, "gl_Vertex"); + // addSymbolLinkageNode(root, symbolTable, "gl_ModelViewProjectionMatrix"); + //} + + if (language == EShLangVertex) { + // the names won't be found in the symbol table unless the versions are right, + // so version logic does not need to be repeated here + addSymbolLinkageNode(linkage, symbolTable, "gl_VertexID"); + addSymbolLinkageNode(linkage, symbolTable, "gl_InstanceID"); + } + + if (linkage) { + // Finish off linkage sequence + linkage->setOperator(EOpLinkerObjects); + + // Add a child to the root node for the linker objects + growAggregate(root, linkage, 0); + } +} + +void TIntermediate::addSymbolLinkageNode(TIntermAggregate*& linkage, TSymbolTable& symbolTable, const TString& name) +{ + TSymbol* symbol = symbolTable.find(name); + if (symbol) + addSymbolLinkageNode(linkage, *symbol->getAsVariable()); +} + +void TIntermediate::addSymbolLinkageNode(TIntermAggregate*& linkage, const TVariable& variable) +{ + TIntermSymbol* node = new TIntermSymbol(variable.getUniqueId(), variable.getName(), variable.getType()); + linkage = growAggregate(linkage, node, 0); +} + // // This deletes the tree. // diff --git a/glslang/MachineIndependent/ParseHelper.cpp b/glslang/MachineIndependent/ParseHelper.cpp index a9040e95708819deec067f5ebc565be4d9701179..bf11314d83be470cdd0351ba65d6d726f546e93b 100644 --- a/glslang/MachineIndependent/ParseHelper.cpp +++ b/glslang/MachineIndependent/ParseHelper.cpp @@ -42,7 +42,7 @@ TParseContext::TParseContext(TSymbolTable& symt, TIntermediate& interm, int v, EProfile p, EShLanguage L, TInfoSink& is, bool fc, EShMessages m) : - intermediate(interm), symbolTable(symt), infoSink(is), language(L), treeRoot(0), + intermediate(interm), symbolTable(symt), infoSink(is), language(L), treeRoot(0), linkage(0), numErrors(0), lexAfterType(false), loopNestingLevel(0), structNestingLevel(0), inTypeParen(false), version(v), profile(p), forwardCompatible(fc), messages(m), @@ -331,11 +331,11 @@ void TParseContext::variableCheck(TIntermTyped*& nodePtr) return; if (symbol->getType().getBasicType() == EbtVoid) { - error(symbol->getLine(), "undeclared identifier", symbol->getSymbol().c_str(), ""); + error(symbol->getLine(), "undeclared identifier", symbol->getName().c_str(), ""); // Add to symbol table to prevent future error messages on the same name - TVariable* fakeVariable = new TVariable(&symbol->getSymbol(), TType(EbtFloat)); + TVariable* fakeVariable = new TVariable(&symbol->getName(), TType(EbtFloat)); symbolTable.insert(*fakeVariable); // substitute a symbol node for this new variable @@ -403,7 +403,7 @@ bool TParseContext::lValueErrorCheck(int line, const char* op, TIntermTyped* nod const char* symbol = 0; if (symNode != 0) - symbol = symNode->getSymbol().c_str(); + symbol = symNode->getName().c_str(); const char* message = 0; switch (node->getQualifier().storage) { @@ -1038,15 +1038,15 @@ void TParseContext::arrayCheck(int line, TString& identifier, const TPublicType& bool TParseContext::arraySetMaxSize(TIntermSymbol *node, TType* type, int size, bool updateFlag, TSourceLoc line) { - TSymbol* symbol = symbolTable.find(node->getSymbol()); + TSymbol* symbol = symbolTable.find(node->getName()); if (symbol == 0) { - error(line, " undeclared identifier", node->getSymbol().c_str(), ""); + error(line, " undeclared identifier", node->getName().c_str(), ""); return true; } TVariable* variable = symbol->getAsVariable(); if (! variable) { - error(0, "array variable name expected", node->getSymbol().c_str(), ""); + error(0, "array variable name expected", node->getName().c_str(), ""); return true; } @@ -1055,7 +1055,7 @@ bool TParseContext::arraySetMaxSize(TIntermSymbol *node, TType* type, int size, // special casing to test index value of gl_TexCoord. If the accessed index is >= gl_MaxTextureCoords // its an error - if (node->getSymbol() == "gl_TexCoord") { + if (node->getName() == "gl_TexCoord") { TSymbol* texCoord = symbolTable.find("gl_MaxTextureCoords"); if (! texCoord || ! texCoord->getAsVariable()) { infoSink.info.message(EPrefixInternalError, "gl_MaxTextureCoords not defined", line); @@ -1111,11 +1111,15 @@ void TParseContext::nonInitCheck(int line, TString& identifier, TPublicType& typ TVariable* variable = new TVariable(&identifier, TType(type)); - if (! symbolTable.insert(*variable)) { + if (! symbolTable.insert(*variable)) error(line, "redefinition", variable->getName().c_str(), ""); - delete variable; - } else + else { voidErrorCheck(line, identifier, type); + + // see if it's a linker-level object to track + if (type.qualifier.isUniform() || type.qualifier.isPipeInput() || type.qualifier.isPipeOutput()) + intermediate.addSymbolLinkageNode(linkage, *variable); + } } void TParseContext::paramCheck(int line, TStorageQualifier qualifier, TType* type) @@ -1311,12 +1315,12 @@ bool TParseContext::executeInitializerError(TSourceLoc line, TString& identifier variable->shareConstPointer(initializer->getAsConstantUnion()->getUnionArrayPointer()); } } else if (initializer->getAsSymbolNode()) { - TSymbol* symbol = symbolTable.find(initializer->getAsSymbolNode()->getSymbol()); + TSymbol* symbol = symbolTable.find(initializer->getAsSymbolNode()->getName()); if (TVariable* tVar = symbol->getAsVariable()) { constUnion* constArray = tVar->getConstUnionPointer(); variable->shareConstPointer(constArray); } else { - error(line, "expected variable", initializer->getAsSymbolNode()->getSymbol().c_str(), ""); + error(line, "expected variable", initializer->getAsSymbolNode()->getName().c_str(), ""); return true; } } else { @@ -1575,7 +1579,7 @@ void TParseContext::addBlock(int line, TTypeList& typeList, const TString* insta case EvqOut: defaultQualification = globalOutputDefaults; break; default: defaultQualification.clear(); break; } - + mergeLayoutQualifiers(line, defaultQualification, currentBlockDefaults); for (unsigned int member = 0; member < typeList.size(); ++member) { TQualifier memberQualification = defaultQualification; @@ -1611,6 +1615,9 @@ void TParseContext::addBlock(int line, TTypeList& typeList, const TString* insta return; } + + // save it in case there are no references in the AST, so the linker can error test against it + intermediate.addSymbolLinkageNode(linkage, *variable); } // For an identifier that is already declared, add more qualification to it. diff --git a/glslang/MachineIndependent/ParseHelper.h b/glslang/MachineIndependent/ParseHelper.h index 43ec8fe54c9a0d4f46053fdb3a1987e376a31469..4d29186ead2e517caaff4c0cc1d413948900b8f8 100644 --- a/glslang/MachineIndependent/ParseHelper.h +++ b/glslang/MachineIndependent/ParseHelper.h @@ -41,13 +41,6 @@ #include "SymbolTable.h" #include "localintermediate.h" -struct TMatrixFields { - bool wholeRow; - bool wholeCol; - int row; - int col; -}; - typedef enum { EBhRequire, EBhEnable, @@ -62,6 +55,8 @@ struct TPragma { TPragmaTable pragmaTable; }; + + // // The following are extra variables needed during parsing, grouped together so // they can be passed to the parser without needing a global. @@ -74,6 +69,7 @@ struct TParseContext { TInfoSink& infoSink; EShLanguage language; // vertex or fragment language TIntermNode* treeRoot; // root of parse tree being created + TIntermAggregate *linkage; // aggregate node of objects the linker may need, if not reference by the rest of the AST int numErrors; // number of compile-time errors encountered bool lexAfterType; // true if we've recognized a type, so can only be looking for an identifier int loopNestingLevel; // 0 if outside all loops diff --git a/glslang/MachineIndependent/ShaderLang.cpp b/glslang/MachineIndependent/ShaderLang.cpp index fe3ff88a2bb6883da7fc187497ea2ca422d95e3d..f2dbfd68a8517909f1413b84da442d108b49a591 100644 --- a/glslang/MachineIndependent/ShaderLang.cpp +++ b/glslang/MachineIndependent/ShaderLang.cpp @@ -556,6 +556,7 @@ int ShCompile( int ret = PaParseStrings(const_cast<char**>(shaderStrings), 0, numStrings, parseContext, parseContext.getPreamble()); if (ret) success = false; + intermediate.addSymbolLinkageNodes(parseContext.treeRoot, parseContext.linkage, parseContext.language, symbolTable); if (success && parseContext.treeRoot) { if (optLevel == EShOptNoGeneration) @@ -564,7 +565,6 @@ int ShCompile( success = intermediate.postProcess(parseContext.treeRoot, parseContext.language); if (success) { - if (debugOptions & EDebugOpIntermediate) intermediate.outputTree(parseContext.treeRoot); diff --git a/glslang/MachineIndependent/SymbolTable.h b/glslang/MachineIndependent/SymbolTable.h index 10ffaa08e7271b0cd5581744cfc315d41cbc05a8..7932539353d4845fe0372cfdf72fc95eeb298d6f 100644 --- a/glslang/MachineIndependent/SymbolTable.h +++ b/glslang/MachineIndependent/SymbolTable.h @@ -442,6 +442,7 @@ public: *builtIn = level < 2; if (sameScope) *sameScope = level == currentLevel(); + return symbol; } diff --git a/glslang/MachineIndependent/glslang.y b/glslang/MachineIndependent/glslang.y index 39003818cbea372d04ac9838161ddab59329a980..a5fa9072c79aa6f28ecc5c160922f87228d880c8 100644 --- a/glslang/MachineIndependent/glslang.y +++ b/glslang/MachineIndependent/glslang.y @@ -270,7 +270,7 @@ postfix_expression parseContext.variableCheck($1); if (!$1->isArray() && !$1->isMatrix() && !$1->isVector()) { if ($1->getAsSymbolNode()) - parseContext.error($2.line, " left of '[' is not of type array, matrix, or vector ", $1->getAsSymbolNode()->getSymbol().c_str(), ""); + parseContext.error($2.line, " left of '[' is not of type array, matrix, or vector ", $1->getAsSymbolNode()->getName().c_str(), ""); else parseContext.error($2.line, " left of '[' is not of type array, matrix, or vector ", "expression", ""); } @@ -746,8 +746,8 @@ function_identifier } else { TIntermSymbol* symbol = $1->getAsSymbolNode(); if (symbol) { - parseContext.reservedErrorCheck(symbol->getLine(), symbol->getSymbol()); - TFunction *function = new TFunction(&symbol->getSymbol(), TType(EbtVoid)); + parseContext.reservedErrorCheck(symbol->getLine(), symbol->getName()); + TFunction *function = new TFunction(&symbol->getName(), TType(EbtVoid)); $$.function = function; } else parseContext.error($1->getLine(), "function call, method or subroutine call expected", "", ""); diff --git a/glslang/MachineIndependent/intermOut.cpp b/glslang/MachineIndependent/intermOut.cpp index 944dedd854353e2cd95f082004ec7c7f54d434d6..fe0f233d8ea0ec618fe2200f548be30a93d7e788 100644 --- a/glslang/MachineIndependent/intermOut.cpp +++ b/glslang/MachineIndependent/intermOut.cpp @@ -87,7 +87,7 @@ void OutputSymbol(TIntermSymbol* node, TIntermTraverser* it) const int maxSize = GlslangMaxTypeLength + GlslangMaxTokenLength; char buf[maxSize]; snprintf(buf, maxSize, "'%s' (%s)\n", - node->getSymbol().c_str(), + node->getName().c_str(), node->getCompleteString().c_str()); oit->infoSink.debug << buf; @@ -274,6 +274,7 @@ bool OutputAggregate(bool /* preVisit */, TIntermAggregate* node, TIntermTravers switch (node->getOp()) { case EOpSequence: out.debug << "Sequence\n"; return true; + case EOpLinkerObjects: out.debug << "Linker Objects\n"; return true; case EOpComma: out.debug << "Comma"; break; case EOpFunction: out.debug << "Function Definition: " << node->getName(); break; case EOpFunctionCall: out.debug << "Function Call: " << node->getName(); break; diff --git a/glslang/MachineIndependent/localintermediate.h b/glslang/MachineIndependent/localintermediate.h index ab0c0db5ba97fb74c8a09caba4d62eca1160db15..4332d821b84ebb8c5d1b0e7d2c8509d2822e0700 100644 --- a/glslang/MachineIndependent/localintermediate.h +++ b/glslang/MachineIndependent/localintermediate.h @@ -80,6 +80,9 @@ public: TIntermBranch* addBranch(TOperator, TIntermTyped*, TSourceLoc); TIntermTyped* addSwizzle(TVectorFields&, TSourceLoc); bool postProcess(TIntermNode*, EShLanguage); + void addSymbolLinkageNodes(TIntermNode* root, TIntermAggregate*& linkage, EShLanguage, TSymbolTable&); + void addSymbolLinkageNode(TIntermAggregate*& linkage, TSymbolTable&, const TString&); + void addSymbolLinkageNode(TIntermAggregate*& linkage, const TVariable&); void remove(TIntermNode*); void outputTree(TIntermNode*);