Create linkage symbol nodes in the AST so a linker has access to all global objects that were declared, for error checking, etc. Use it now for all ins/outs/uniforms as well as gl_VertexID and gl_InstanceID.

Also fixed a confusing name and added more 'const'.


git-svn-id: https://cvs.khronos.org/svn/repos/ogl/trunk/ecosystem/public/sdk/tools/glslang@22142 e7fa87d3-cd2b-0410-9028-fcbf551c1848
This commit is contained in:
John Kessenich 2013-06-24 17:26:56 +00:00
parent b29ba33089
commit 06f8464fb5
10 changed files with 101 additions and 34 deletions

View File

@ -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));

View File

@ -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; }

View File

@ -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.
//

View File

@ -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 {
@ -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.

View File

@ -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

View File

@ -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);

View File

@ -442,6 +442,7 @@ public:
*builtIn = level < 2;
if (sameScope)
*sameScope = level == currentLevel();
return symbol;
}

View File

@ -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", "", "");

View File

@ -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;

View File

@ -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*);