Generalize the symbol hierarchy to transparently handle anonymous-block members better.

git-svn-id: https://cvs.khronos.org/svn/repos/ogl/trunk/ecosystem/public/sdk/tools/glslang@23469 e7fa87d3-cd2b-0410-9028-fcbf551c1848
This commit is contained in:
John Kessenich 2013-10-11 17:29:19 +00:00
parent 4c70685382
commit 9d30218fb6
8 changed files with 217 additions and 155 deletions

View File

@ -24,6 +24,7 @@ Link Validation
+ Non ES: value checking of global const initializers + Non ES: value checking of global const initializers
+ Non ES: value checking of uniform initializers + Non ES: value checking of uniform initializers
+ Non ES: location match + Non ES: location match
- gl_TexCoord can only have a max array size of up to gl_MaxTextureCoords
- location aliasing/overlap (except desktop vertex shader inputs) - location aliasing/overlap (except desktop vertex shader inputs)
- 1.0: count the number of uniforms and varyings, compare against limits - 1.0: count the number of uniforms and varyings, compare against limits
+ recursion for functions + recursion for functions

View File

@ -885,6 +885,11 @@ void TIntermediate::addSymbolLinkageNodes(TIntermAggregate*& linkage, EShLanguag
treeRoot = growAggregate(treeRoot, linkage); treeRoot = growAggregate(treeRoot, linkage);
} }
//
// Add the given name or symbol to the list of nodes at the end of the tree used
// for link-time checking and external linkage.
//
void TIntermediate::addSymbolLinkageNode(TIntermAggregate*& linkage, TSymbolTable& symbolTable, const TString& name) void TIntermediate::addSymbolLinkageNode(TIntermAggregate*& linkage, TSymbolTable& symbolTable, const TString& name)
{ {
TSymbol* symbol = symbolTable.find(name); TSymbol* symbol = symbolTable.find(name);
@ -892,10 +897,16 @@ void TIntermediate::addSymbolLinkageNode(TIntermAggregate*& linkage, TSymbolTabl
addSymbolLinkageNode(linkage, *symbol->getAsVariable()); addSymbolLinkageNode(linkage, *symbol->getAsVariable());
} }
void TIntermediate::addSymbolLinkageNode(TIntermAggregate*& linkage, const TVariable& variable) void TIntermediate::addSymbolLinkageNode(TIntermAggregate*& linkage, const TSymbol& symbol)
{ {
TIntermSymbol* node = new TIntermSymbol(variable.getUniqueId(), variable.getName(), variable.getType()); const TVariable* variable = symbol.getAsVariable();
node->setConstArray(variable.getConstArray()); if (! variable) {
// This must be a member of an anonymous block, and we need to add the whole block
const TAnonMember* anon = symbol.getAsAnonMember();
variable = &anon->getAnonContainer();
}
TIntermSymbol* node = new TIntermSymbol(variable->getUniqueId(), variable->getName(), variable->getType());
node->setConstArray(variable->getConstArray());
linkage = growAggregate(linkage, node); linkage = growAggregate(linkage, node);
} }

View File

@ -473,11 +473,10 @@ TIntermTyped* TParseContext::handleBracketDereference(TSourceLoc loc, TIntermTyp
(base->isMatrix() && base->getType().getMatrixCols() <= indexValue))) (base->isMatrix() && base->getType().getMatrixCols() <= indexValue)))
error(loc, "", "[", "index out of range '%d'", index->getAsConstantUnion()->getConstArray()[0].getIConst()); error(loc, "", "[", "index out of range '%d'", index->getAsConstantUnion()->getConstArray()[0].getIConst());
if (base->isArray()) { if (base->isArray()) {
if (base->getType().getArraySize() == 0) { if (base->getType().getArraySize() == 0)
if (base->getType().getMaxArraySize() <= index->getAsConstantUnion()->getConstArray()[0].getIConst()) updateMaxArraySize(loc, base, index->getAsConstantUnion()->getConstArray()[0].getIConst());
arraySetMaxSize(loc, base->getAsSymbolNode(), index->getAsConstantUnion()->getConstArray()[0].getIConst() + 1); else if (index->getAsConstantUnion()->getConstArray()[0].getIConst() >= base->getType().getArraySize() ||
} else if ( index->getAsConstantUnion()->getConstArray()[0].getIConst() >= base->getType().getArraySize() || index->getAsConstantUnion()->getConstArray()[0].getIConst() < 0)
index->getAsConstantUnion()->getConstArray()[0].getIConst() < 0)
error(loc, "", "[", "array index out of range '%d'", index->getAsConstantUnion()->getConstArray()[0].getIConst()); error(loc, "", "[", "array index out of range '%d'", index->getAsConstantUnion()->getConstArray()[0].getIConst());
} }
result = intermediate.addIndex(EOpIndexDirect, base, index, loc); result = intermediate.addIndex(EOpIndexDirect, base, index, loc);
@ -627,8 +626,8 @@ TFunction* TParseContext::handleFunctionDeclarator(TSourceLoc loc, TFunction& fu
requireNotRemoved(loc, EEsProfile, 300, "redeclaration of built-in function"); requireNotRemoved(loc, EEsProfile, 300, "redeclaration of built-in function");
const TFunction* prevDec = symbol ? symbol->getAsFunction() : 0; const TFunction* prevDec = symbol ? symbol->getAsFunction() : 0;
if (prevDec) { if (prevDec) {
if (prevDec->getReturnType() != function.getReturnType()) { if (prevDec->getType() != function.getType()) {
error(loc, "overloaded functions must have the same return type", function.getReturnType().getCompleteTypeString().c_str(), ""); error(loc, "overloaded functions must have the same return type", function.getType().getCompleteTypeString().c_str(), "");
} }
for (int i = 0; i < prevDec->getParamCount(); ++i) { for (int i = 0; i < prevDec->getParamCount(); ++i) {
if ((*prevDec)[i].type->getQualifier().storage != function[i].type->getQualifier().storage) if ((*prevDec)[i].type->getQualifier().storage != function[i].type->getQualifier().storage)
@ -679,7 +678,7 @@ TIntermAggregate* TParseContext::handleFunctionPrototype(TSourceLoc loc, TFuncti
// //
// Remember the return type for later checking for RETURN statements. // Remember the return type for later checking for RETURN statements.
// //
currentFunctionType = &(prevDec->getReturnType()); currentFunctionType = &(prevDec->getType());
} else } else
currentFunctionType = new TType(EbtVoid); currentFunctionType = new TType(EbtVoid);
functionReturnsValue = false; functionReturnsValue = false;
@ -690,8 +689,8 @@ TIntermAggregate* TParseContext::handleFunctionPrototype(TSourceLoc loc, TFuncti
if (function.getName() == "main") { if (function.getName() == "main") {
if (function.getParamCount() > 0) if (function.getParamCount() > 0)
error(loc, "function cannot take any parameter(s)", function.getName().c_str(), ""); error(loc, "function cannot take any parameter(s)", function.getName().c_str(), "");
if (function.getReturnType().getBasicType() != EbtVoid) if (function.getType().getBasicType() != EbtVoid)
error(loc, "", function.getReturnType().getCompleteTypeString().c_str(), "main function cannot return a value"); error(loc, "", function.getType().getCompleteTypeString().c_str(), "main function cannot return a value");
intermediate.addMainCount(); intermediate.addMainCount();
} }
@ -798,7 +797,7 @@ TIntermTyped* TParseContext::handleFunctionCall(TSourceLoc loc, TFunction* fnCal
op = fnCandidate->getBuiltInOp(); op = fnCandidate->getBuiltInOp();
if (builtIn && op != EOpNull) { if (builtIn && op != EOpNull) {
// A function call mapped to a built-in operation. // A function call mapped to a built-in operation.
result = intermediate.addBuiltInFunctionCall(loc, op, fnCandidate->getParamCount() == 1, intermNode, fnCandidate->getReturnType()); result = intermediate.addBuiltInFunctionCall(loc, op, fnCandidate->getParamCount() == 1, intermNode, fnCandidate->getType());
if (result == 0) { if (result == 0) {
error(intermNode->getLoc(), " wrong operand type", "Internal Error", error(intermNode->getLoc(), " wrong operand type", "Internal Error",
"built in unary operator function. Type: %s", "built in unary operator function. Type: %s",
@ -807,7 +806,7 @@ TIntermTyped* TParseContext::handleFunctionCall(TSourceLoc loc, TFunction* fnCal
} }
} else { } else {
// This is a function call not mapped to built-in operation // This is a function call not mapped to built-in operation
result = intermediate.setAggregateOperator(intermAggregate, EOpFunctionCall, fnCandidate->getReturnType(), loc); result = intermediate.setAggregateOperator(intermAggregate, EOpFunctionCall, fnCandidate->getType(), loc);
result->getAsAggregate()->setName(fnCandidate->getMangledName()); result->getAsAggregate()->setName(fnCandidate->getMangledName());
// this is how we know whether the given function is a built-in function or a user-defined function // this is how we know whether the given function is a built-in function or a user-defined function
@ -830,7 +829,7 @@ TIntermTyped* TParseContext::handleFunctionCall(TSourceLoc loc, TFunction* fnCal
} }
// built-in texturing functions get their return value precision from the precision of the sampler // built-in texturing functions get their return value precision from the precision of the sampler
if (builtIn && fnCandidate->getReturnType().getQualifier().precision == EpqNone && if (builtIn && fnCandidate->getType().getQualifier().precision == EpqNone &&
fnCandidate->getParamCount() > 0 && (*fnCandidate)[0].type->getBasicType() == EbtSampler) fnCandidate->getParamCount() > 0 && (*fnCandidate)[0].type->getBasicType() == EbtSampler)
result->getQualifier().precision = result->getAsAggregate()->getSequence()[0]->getAsTyped()->getQualifier().precision; result->getQualifier().precision = result->getAsAggregate()->getSequence()[0]->getAsTyped()->getQualifier().precision;
} }
@ -1228,7 +1227,7 @@ bool TParseContext::reservedErrorCheck(TSourceLoc loc, const TString& identifier
// //
bool TParseContext::constructorError(TSourceLoc loc, TIntermNode* node, TFunction& function, TOperator op, TType& type) bool TParseContext::constructorError(TSourceLoc loc, TIntermNode* node, TFunction& function, TOperator op, TType& type)
{ {
type.shallowCopy(function.getReturnType()); type.shallowCopy(function.getType());
bool constructingMatrix = false; bool constructingMatrix = false;
switch(op) { switch(op) {
@ -1713,89 +1712,86 @@ void TParseContext::arrayDimCheck(TSourceLoc loc, const TType* type, TArraySizes
// //
// size == 0 means no specified size. // size == 0 means no specified size.
// //
void TParseContext::declareArray(TSourceLoc loc, TString& identifier, const TType& type, TVariable*& variable, bool& newDeclaration) void TParseContext::declareArray(TSourceLoc loc, TString& identifier, const TType& type, TSymbol*& symbol, bool& newDeclaration)
{ {
// if (! symbol) {
// Don't check for reserved word use until after we know it's not in the symbol table,
// because reserved arrays can be redeclared.
//
// However, reserved arrays cannot be modified in a shared symbol table, so add a new
// one at a non-shared level in the table.
//
// Redeclarations have to take place at the same scope; otherwise they are hiding declarations
//
if (! variable) {
bool currentScope; bool currentScope;
TSymbol* symbol = symbolTable.find(identifier, 0, &currentScope); symbol = symbolTable.find(identifier, 0, &currentScope);
if (symbol == 0 || ! currentScope) { if (symbol == 0 || ! currentScope) {
variable = new TVariable(&identifier, type); //
symbolTable.insert(*variable); // Successfully process a new definition.
// (Redeclarations have to take place at the same scope; otherwise they are hiding declarations)
//
symbol = new TVariable(&identifier, type);
symbolTable.insert(*symbol);
newDeclaration = true; newDeclaration = true;
return; return;
} }
variable = symbol->getAsVariable(); if (symbol->getAsAnonMember()) {
error(loc, "cannot redeclare a user-block member array", identifier.c_str(), "");
return;
}
} }
if (! variable) { //
// Process a redeclaration.
//
if (! symbol) {
error(loc, "array variable name expected", identifier.c_str(), ""); error(loc, "array variable name expected", identifier.c_str(), "");
return; return;
} }
if (! variable->getType().isArray()) { TType& newType = symbol->getWritableType();
if (! newType.isArray()) {
error(loc, "redeclaring non-array as array", identifier.c_str(), ""); error(loc, "redeclaring non-array as array", identifier.c_str(), "");
return; return;
} }
if (variable->getType().getArraySize() > 0) { if (newType.getArraySize() > 0) {
error(loc, "redeclaration of array with size", identifier.c_str(), ""); error(loc, "redeclaration of array with size", identifier.c_str(), "");
return; return;
} }
if (! variable->getType().sameElementType(type)) { if (! newType.sameElementType(type)) {
error(loc, "redeclaration of array with a different type", identifier.c_str(), ""); error(loc, "redeclaration of array with a different newType", identifier.c_str(), "");
return; return;
} }
variable->getWritableType().shareArraySizes(type); newType.shareArraySizes(type);
} }
bool TParseContext::arraySetMaxSize(TSourceLoc loc, TIntermSymbol *node, int size) void TParseContext::updateMaxArraySize(TSourceLoc loc, TIntermNode *node, int index)
{ {
TSymbol* symbol = symbolTable.find(node->getName()); TIntermSymbol* symbolNode = node->getAsSymbolNode();
if (symbol == 0) { if (! symbolNode) {
error(loc, " undeclared identifier", node->getName().c_str(), ""); // TODO: functionality: unsized arrays: handle members of blocks
return true; return;
} }
TVariable* variable = symbol->getAsVariable(); // maybe there is nothing to do...
if (! variable) { // TODO: functionality: unsized arrays: is the node sharing the array type with the symbol table?
error(loc, "array variable name expected", node->getName().c_str(), ""); if (symbolNode->getType().getMaxArraySize() > index)
return true; return;
// something to do...
TSymbol* symbol = symbolTable.find(symbolNode->getName());
assert(symbol);
if (symbol == 0)
return;
if (symbol->getAsFunction()) {
error(loc, "array variable name expected", symbolNode->getName().c_str(), "");
return;
} }
// TODO: desktop linker: make this a link-time check (note if it's here, an explicit declaration skips it)
//if (node->getName() == "gl_TexCoord") {
// TSymbol* texCoord = symbolTable.find("gl_MaxTextureCoords");
// if (! texCoord || ! texCoord->getAsVariable()) {
// infoSink.info.message(EPrefixInternalError, "gl_MaxTextureCoords not defined", loc);
// return true;
// }
// int texCoordValue = texCoord->getAsVariable()->getConstArray()[0].getIConst();
// if (texCoordValue <= size) {
// error(loc, "", "[", "gl_TexCoord can only have a max array size of up to gl_MaxTextureCoords", "");
// return true;
// }
//}
// For read-only built-ins, add a new variable for holding the maximum array size of an implicitly-sized shared array. // For read-only built-ins, add a new variable for holding the maximum array size of an implicitly-sized shared array.
if (variable->isReadOnly()) // TODO: functionality: unsized arrays: is this new array type shared with the node?
variable = symbolTable.copyUp(variable); if (symbol->isReadOnly())
symbol = symbolTable.copyUp(symbol);
variable->getWritableType().setMaxArraySize(size); symbol->getWritableType().setMaxArraySize(index + 1);
return false;
} }
// //
@ -1822,9 +1818,7 @@ void TParseContext::nonInitConstCheck(TSourceLoc loc, TString& identifier, TType
// //
// Returns a redeclared and type-modified variable if a redeclarated occurred. // Returns a redeclared and type-modified variable if a redeclarated occurred.
// //
// Will emit TSymbol* TParseContext::redeclareBuiltin(TSourceLoc loc, const TString& identifier, bool& newDeclaration)
//
TVariable* TParseContext::redeclareBuiltin(TSourceLoc loc, const TString& identifier, bool& newDeclaration)
{ {
if (profile == EEsProfile || identifier.compare(0, 3, "gl_") != 0 || symbolTable.atBuiltInLevel()) if (profile == EEsProfile || identifier.compare(0, 3, "gl_") != 0 || symbolTable.atBuiltInLevel())
return 0; return 0;
@ -1853,21 +1847,19 @@ TVariable* TParseContext::redeclareBuiltin(TSourceLoc loc, const TString& identi
if (! symbol) if (! symbol)
return 0; return 0;
TVariable* variable = symbol->getAsVariable();
// If it wasn't at a built-in level, then it's already been redeclared; // If it wasn't at a built-in level, then it's already been redeclared;
// that is, this is a redeclaration of a redeclaration, reuse that initial // that is, this is a redeclaration of a redeclaration, reuse that initial
// redeclaration. Otherwise, make the new one. // redeclaration. Otherwise, make the new one.
if (builtIn) { if (builtIn) {
// Copy the symbol up to make a writable version // Copy the symbol up to make a writable version
newDeclaration = true; newDeclaration = true;
variable = symbolTable.copyUp(variable); symbol = symbolTable.copyUp(symbol)->getAsVariable();
} }
// Now, modify the type of the copy, as per the type of the current redeclaration. // Now, modify the type of the copy, as per the type of the current redeclaration.
// TODO: functionality: verify type change is allowed and make the change in type // TODO: functionality: verify type change is allowed and make the change in type
return variable; return symbol;
} }
return 0; return 0;
@ -2029,8 +2021,8 @@ TIntermNode* TParseContext::declareVariable(TSourceLoc loc, TString& identifier,
// Check for redeclaration of built-ins and/or attempting to declare a reserved name // Check for redeclaration of built-ins and/or attempting to declare a reserved name
bool newDeclaration = false; // true if a new entry gets added to the symbol table bool newDeclaration = false; // true if a new entry gets added to the symbol table
TVariable* variable = redeclareBuiltin(loc, identifier, newDeclaration); TSymbol* symbol = redeclareBuiltin(loc, identifier, newDeclaration);
if (! variable) if (! symbol)
reservedErrorCheck(loc, identifier); reservedErrorCheck(loc, identifier);
// Declare the variable // Declare the variable
@ -2042,7 +2034,7 @@ TIntermNode* TParseContext::declareVariable(TSourceLoc loc, TString& identifier,
arrayDimCheck(loc, &type, arraySizes); arrayDimCheck(loc, &type, arraySizes);
if (! arrayQualifierError(loc, type.getQualifier())) { if (! arrayQualifierError(loc, type.getQualifier())) {
type.setArraySizes(arraySizes); type.setArraySizes(arraySizes);
declareArray(loc, identifier, type, variable, newDeclaration); declareArray(loc, identifier, type, symbol, newDeclaration);
} }
if (initializer) { if (initializer) {
@ -2051,18 +2043,24 @@ TIntermNode* TParseContext::declareVariable(TSourceLoc loc, TString& identifier,
} }
} else { } else {
// non-array case // non-array case
if (! variable) if (! symbol)
variable = declareNonArray(loc, identifier, type, newDeclaration); symbol = declareNonArray(loc, identifier, type, newDeclaration);
} }
// Deal with initializer // Deal with initializer
TIntermNode* initNode = 0; TIntermNode* initNode = 0;
if (variable && initializer) if (symbol && initializer) {
TVariable* variable = symbol->getAsVariable();
if (! variable) {
error(loc, "initializer requires a variable, not a member", identifier.c_str(), "");
return 0;
}
initNode = executeInitializer(loc, identifier, initializer, variable); initNode = executeInitializer(loc, identifier, initializer, variable);
}
// see if it's a linker-level object to track // see if it's a linker-level object to track
if (newDeclaration && symbolTable.atGlobalLevel()) if (symbol && newDeclaration && symbolTable.atGlobalLevel())
intermediate.addSymbolLinkageNode(linkage, *variable); intermediate.addSymbolLinkageNode(linkage, *symbol);
return initNode; return initNode;
} }
@ -2435,11 +2433,13 @@ void TParseContext::addBlock(TSourceLoc loc, TTypeList& typeList, const TString*
// For an identifier that is already declared, add more qualification to it. // For an identifier that is already declared, add more qualification to it.
void TParseContext::addQualifierToExisting(TSourceLoc loc, TQualifier qualifier, const TString& identifier) void TParseContext::addQualifierToExisting(TSourceLoc loc, TQualifier qualifier, const TString& identifier)
{ {
TSymbol* existing = symbolTable.find(identifier); TSymbol* symbol = symbolTable.find(identifier);
TVariable* variable = existing ? existing->getAsVariable() : 0; if (! symbol) {
if (! variable) {
error(loc, "identifier not previously declared", identifier.c_str(), ""); error(loc, "identifier not previously declared", identifier.c_str(), "");
return;
}
if (symbol->getAsFunction()) {
error(loc, "cannot re-qualify a function name", identifier.c_str(), "");
return; return;
} }
@ -2453,12 +2453,13 @@ void TParseContext::addQualifierToExisting(TSourceLoc loc, TQualifier qualifier,
return; return;
} }
// For read-only built-ins, add a new variable for holding the modified qualifier. // For read-only built-ins, add a new symbol for holding the modified qualifier.
if (variable->isReadOnly()) // This will bring up an entire block, if a block type has to be modified (e.g., gl_Position inside a block)
variable = symbolTable.copyUp(variable); if (symbol->isReadOnly())
symbol = symbolTable.copyUp(symbol);
if (qualifier.invariant) if (qualifier.invariant)
variable->getWritableType().getQualifier().invariant = true; symbol->getWritableType().getQualifier().invariant = true;
} }
void TParseContext::addQualifierToExisting(TSourceLoc loc, TQualifier qualifier, TIdentifierList& identifiers) void TParseContext::addQualifierToExisting(TSourceLoc loc, TQualifier qualifier, TIdentifierList& identifiers)

View File

@ -111,7 +111,7 @@ public:
void precisionQualifierCheck(TSourceLoc, TPublicType&); void precisionQualifierCheck(TSourceLoc, TPublicType&);
void parameterSamplerCheck(TSourceLoc, TStorageQualifier qualifier, const TType& type); void parameterSamplerCheck(TSourceLoc, TStorageQualifier qualifier, const TType& type);
bool containsSampler(const TType& type); bool containsSampler(const TType& type);
TVariable* redeclareBuiltin(TSourceLoc, const TString&, bool& newDeclaration); TSymbol* redeclareBuiltin(TSourceLoc, const TString&, bool& newDeclaration);
void paramCheck(TSourceLoc, TStorageQualifier qualifier, TType* type); void paramCheck(TSourceLoc, TStorageQualifier qualifier, TType* type);
void nestedBlockCheck(TSourceLoc); void nestedBlockCheck(TSourceLoc);
void nestedStructCheck(TSourceLoc); void nestedStructCheck(TSourceLoc);
@ -139,7 +139,7 @@ public:
TIntermTyped* addConstArrayNode(int index, TIntermTyped* node, TSourceLoc); TIntermTyped* addConstArrayNode(int index, TIntermTyped* node, TSourceLoc);
TIntermTyped* addConstStruct(TString& , TIntermTyped*, TSourceLoc); TIntermTyped* addConstStruct(TString& , TIntermTyped*, TSourceLoc);
bool arraySetMaxSize(TSourceLoc, TIntermSymbol*, int); void updateMaxArraySize(TSourceLoc, TIntermNode*, int index);
void setScanContext(TScanContext* c) { scanContext = c; } void setScanContext(TScanContext* c) { scanContext = c; }
TScanContext* getScanContext() const { return scanContext; } TScanContext* getScanContext() const { return scanContext; }
@ -164,7 +164,7 @@ protected:
const char* getPreamble(); const char* getPreamble();
void nonInitConstCheck(TSourceLoc, TString& identifier, TType& type); void nonInitConstCheck(TSourceLoc, TString& identifier, TType& type);
TVariable* declareNonArray(TSourceLoc, TString& identifier, TType&, bool& newDeclaration); TVariable* declareNonArray(TSourceLoc, TString& identifier, TType&, bool& newDeclaration);
void declareArray(TSourceLoc, TString& identifier, const TType&, TVariable*&, bool& newDeclaration); void declareArray(TSourceLoc, TString& identifier, const TType&, TSymbol*&, bool& newDeclaration);
TIntermNode* executeInitializer(TSourceLoc, TString& identifier, TIntermTyped* initializer, TVariable* variable); TIntermNode* executeInitializer(TSourceLoc, TString& identifier, TIntermTyped* initializer, TVariable* variable);
TOperator mapTypeToConstructorOp(const TType&); TOperator mapTypeToConstructorOp(const TType&);

View File

@ -240,7 +240,7 @@ TVariable::TVariable(const TVariable& copyOf) : TSymbol(copyOf)
} }
} }
TVariable* TVariable::clone() TVariable* TVariable::clone() const
{ {
TVariable *variable = new TVariable(*this); TVariable *variable = new TVariable(*this);
@ -261,28 +261,45 @@ TFunction::TFunction(const TFunction& copyOf) : TSymbol(copyOf)
defined = copyOf.defined; defined = copyOf.defined;
} }
TFunction* TFunction::clone() TFunction* TFunction::clone() const
{ {
TFunction *function = new TFunction(*this); TFunction *function = new TFunction(*this);
return function; return function;
} }
TAnonMember* TAnonMember::clone() TAnonMember* TAnonMember::clone() const
{ {
// need to implement this once built-in symbols include interface blocks // Anonymous members of a given block should be cloned at a higher level,
// where they can all be assured to still end up pointing to a single
// copy of the original container.
assert(0); assert(0);
return 0; return 0;
} }
TSymbolTableLevel* TSymbolTableLevel::clone() TSymbolTableLevel* TSymbolTableLevel::clone() const
{ {
TSymbolTableLevel *symTableLevel = new TSymbolTableLevel(); TSymbolTableLevel *symTableLevel = new TSymbolTableLevel();
symTableLevel->anonId = anonId; symTableLevel->anonId = anonId;
tLevel::iterator iter; std::vector<bool> containerCopied(anonId, false);
for (iter = level.begin(); iter != level.end(); ++iter) tLevel::const_iterator iter;
symTableLevel->insert(*iter->second->clone()); for (iter = level.begin(); iter != level.end(); ++iter) {
const TAnonMember* anon = iter->second->getAsAnonMember();
if (anon) {
// Insert all the anonymous members of this same container at once,
// avoid inserting the other members in the future, once this has been done,
// allowing them to all be part of the same new container.
if (! containerCopied[anon->getAnonId()]) {
TVariable* container = anon->getAnonContainer().clone();
container->changeName(NewPoolTString(""));
// insert the whole container
symTableLevel->insert(*container);
containerCopied[anon->getAnonId()] = true;
}
} else
symTableLevel->insert(*iter->second->clone());
}
return symTableLevel; return symTableLevel;
} }

View File

@ -45,8 +45,7 @@
// symbols. // symbols.
// //
// --> This requires a copy mechanism, so initial pools used to create // --> This requires a copy mechanism, so initial pools used to create
// the shared information can be popped. So, care is taken with // the shared information can be popped. Done through "clone"
// copying pointers to point to new copies. Done through "clone"
// methods. // methods.
// //
// * Name mangling will be used to give each function a unique name // * Name mangling will be used to give each function a unique name
@ -74,30 +73,34 @@ namespace glslang {
// //
// Symbol base class. (Can build functions or variables out of these...) // Symbol base class. (Can build functions or variables out of these...)
// //
class TVariable; class TVariable;
class TFunction; class TFunction;
class TAnonMember; class TAnonMember;
class TSymbol { class TSymbol {
public: public:
POOL_ALLOCATOR_NEW_DELETE(GetThreadPoolAllocator()) POOL_ALLOCATOR_NEW_DELETE(GetThreadPoolAllocator())
explicit TSymbol(const TString *n) : name(n), writable(true) { } explicit TSymbol(const TString *n) : name(n), writable(true) { }
virtual TSymbol* clone() = 0; virtual TSymbol* clone() const = 0;
virtual ~TSymbol() { } virtual ~TSymbol() { }
const TString& getName() const { return *name; } virtual const TString& getName() const { return *name; }
void changeName(const TString* newName) { name = newName; } virtual void changeName(const TString* newName) { name = newName; }
virtual const TString& getMangledName() const { return getName(); } virtual const TString& getMangledName() const { return getName(); }
virtual TFunction* getAsFunction() { return 0; } virtual TFunction* getAsFunction() { return 0; }
virtual const TFunction* getAsFunction() const { return 0; } virtual const TFunction* getAsFunction() const { return 0; }
virtual TVariable* getAsVariable() { return 0; } virtual TVariable* getAsVariable() { return 0; }
virtual const TVariable* getAsVariable() const { return 0; } virtual const TVariable* getAsVariable() const { return 0; }
virtual const TAnonMember* getAsAnonMember() const { return 0; } virtual const TAnonMember* getAsAnonMember() const { return 0; }
void setUniqueId(int id) { uniqueId = id; } virtual const TType& getType() const = 0;
int getUniqueId() const { return uniqueId; } virtual TType& getWritableType() = 0;
virtual void setUniqueId(int id) { uniqueId = id; }
virtual int getUniqueId() const { return uniqueId; }
virtual void dump(TInfoSink &infoSink) const = 0; virtual void dump(TInfoSink &infoSink) const = 0;
bool isReadOnly() { return ! writable; } virtual bool isReadOnly() { return ! writable; }
void makeReadOnly() { writable = false; } virtual void makeReadOnly() { writable = false; }
protected: protected:
explicit TSymbol(const TSymbol&); explicit TSymbol(const TSymbol&);
@ -126,20 +129,19 @@ 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) { type.shallowCopy(t); }
virtual TVariable* clone(); virtual TVariable* clone() const;
virtual ~TVariable() { } virtual ~TVariable() { }
virtual TVariable* getAsVariable() { return this; } virtual TVariable* getAsVariable() { return this; }
virtual const TVariable* getAsVariable() const { return this; } virtual const TVariable* getAsVariable() const { return this; }
TType& getWritableType() { assert(writable); return type; } virtual const TType& getType() const { return type; }
const TType& getType() const { return type; } virtual TType& getWritableType() { assert(writable); return type; }
bool isUserType() const { return userType; } virtual bool isUserType() const { return userType; }
virtual const TConstUnionArray& getConstArray() const { return unionArray; }
virtual void setConstArray(const TConstUnionArray& constArray) { unionArray = constArray; }
virtual void dump(TInfoSink &infoSink) const; virtual void dump(TInfoSink &infoSink) const;
const TConstUnionArray& getConstArray() const { return unionArray; }
void setConstArray(const TConstUnionArray& constArray) { unionArray = constArray; }
protected: protected:
explicit TVariable(const TVariable&); explicit TVariable(const TVariable&);
TVariable& operator=(const TVariable&); TVariable& operator=(const TVariable&);
@ -182,35 +184,36 @@ public:
mangledName(*name + '('), mangledName(*name + '('),
op(tOp), op(tOp),
defined(false) { returnType.shallowCopy(retType); } defined(false) { returnType.shallowCopy(retType); }
virtual TFunction* clone(); virtual TFunction* clone() const;
virtual ~TFunction(); virtual ~TFunction();
virtual TFunction* getAsFunction() { return this; } virtual TFunction* getAsFunction() { return this; }
virtual const TFunction* getAsFunction() const { return this; } virtual const TFunction* getAsFunction() const { return this; }
void addParameter(TParameter& p) virtual void addParameter(TParameter& p)
{ {
assert(writable); assert(writable);
parameters.push_back(p); parameters.push_back(p);
p.type->appendMangledName(mangledName); p.type->appendMangledName(mangledName);
} }
const TString& getMangledName() const { return mangledName; } virtual const TString& getMangledName() const { return mangledName; }
const TType& getReturnType() const { return returnType; } virtual const TType& getType() const { return returnType; }
void relateToOperator(TOperator o) { assert(writable); op = o; } virtual TType& getWritableType() { return returnType; }
TOperator getBuiltInOp() const { return op; } virtual void relateToOperator(TOperator o) { assert(writable); op = o; }
void setDefined() { assert(writable); defined = true; } virtual TOperator getBuiltInOp() const { return op; }
bool isDefined() const { return defined; } virtual void setDefined() { assert(writable); defined = true; }
virtual bool isDefined() const { return defined; }
int getParamCount() const { return static_cast<int>(parameters.size()); } virtual int getParamCount() const { return static_cast<int>(parameters.size()); }
TParameter& operator [](int i) { assert(writable); return parameters[i]; } virtual TParameter& operator[](int i) { assert(writable); return parameters[i]; }
const TParameter& operator [](int i) const { return parameters[i]; } virtual const TParameter& operator[](int i) const { return parameters[i]; }
virtual void dump(TInfoSink &infoSink) const; virtual void dump(TInfoSink &infoSink) const;
protected: protected:
explicit TFunction(const TFunction&); explicit TFunction(const TFunction&);
TFunction& operator=(TFunction&); TFunction& operator=(const TFunction&);
typedef TVector<TParameter> TParamList; typedef TVector<TParameter> TParamList;
TParamList parameters; TParamList parameters;
@ -222,21 +225,37 @@ protected:
class TAnonMember : public TSymbol { class TAnonMember : public TSymbol {
public: public:
TAnonMember(const TString* n, unsigned int m, TSymbol& a) : TSymbol(n), anonContainer(a), memberNumber(m) { } TAnonMember(const TString* n, unsigned int m, const TVariable& a, int an) : TSymbol(n), anonContainer(a), memberNumber(m), anonId(an) { }
virtual TAnonMember* clone(); virtual TAnonMember* clone() const;
virtual ~TAnonMember() { } virtual ~TAnonMember() { }
const TAnonMember* getAsAnonMember() const { return this; } virtual const TAnonMember* getAsAnonMember() const { return this; }
TSymbol& getAnonContainer() const { return anonContainer; } virtual const TVariable& getAnonContainer() const { return anonContainer; }
unsigned int getMemberNumber() const { return memberNumber; } virtual unsigned int getMemberNumber() const { return memberNumber; }
virtual const TType& getType() const
{
TTypeList& types = *anonContainer.getType().getStruct();
return *types[memberNumber].type;
}
virtual TType& getWritableType()
{
assert(writable);
TTypeList& types = *anonContainer.getType().getStruct();
return *types[memberNumber].type;
}
virtual int getAnonId() const { return anonId; }
virtual void dump(TInfoSink &infoSink) const; virtual void dump(TInfoSink &infoSink) const;
protected: protected:
explicit TAnonMember(TAnonMember&); explicit TAnonMember(const TAnonMember&);
TAnonMember& operator=(TAnonMember&); TAnonMember& operator=(const TAnonMember&);
TSymbol& anonContainer; const TVariable& anonContainer;
unsigned int memberNumber; unsigned int memberNumber;
int anonId;
}; };
class TSymbolTableLevel { class TSymbolTableLevel {
@ -256,18 +275,20 @@ public:
// An empty name means an anonymous container, exposing its members to the external scope. // An empty name means an anonymous container, exposing its members to the external scope.
// Give it a name and insert its members in the symbol table, pointing to the container. // Give it a name and insert its members in the symbol table, pointing to the container.
char buf[20]; char buf[20];
snprintf(buf, 20, "__anon__%d", anonId++); snprintf(buf, 20, "__anon__%d", anonId);
symbol.changeName(NewPoolTString(buf)); symbol.changeName(NewPoolTString(buf));
bool isOkay = true; bool isOkay = true;
const TTypeList& types = *symbol.getAsVariable()->getType().getStruct(); const TTypeList& types = *symbol.getAsVariable()->getType().getStruct();
for (unsigned int m = 0; m < types.size(); ++m) { for (unsigned int m = 0; m < types.size(); ++m) {
TAnonMember* member = new TAnonMember(&types[m].type->getFieldName(), m, symbol); TAnonMember* member = new TAnonMember(&types[m].type->getFieldName(), m, *symbol.getAsVariable(), anonId);
result = level.insert(tLevelPair(member->getMangledName(), member)); result = level.insert(tLevelPair(member->getMangledName(), member));
if (! result.second) if (! result.second)
isOkay = false; isOkay = false;
} }
++anonId;
return isOkay; return isOkay;
} else { } else {
// Check for redefinition errors: // Check for redefinition errors:
@ -344,7 +365,7 @@ public:
void relateToOperator(const char* name, TOperator op); void relateToOperator(const char* name, TOperator op);
void dump(TInfoSink &infoSink) const; void dump(TInfoSink &infoSink) const;
TSymbolTableLevel* clone(); TSymbolTableLevel* clone() const;
void readOnly(); void readOnly();
protected: protected:
@ -422,7 +443,7 @@ public:
{ {
symbol.setUniqueId(++uniqueId); symbol.setUniqueId(++uniqueId);
if (symbol.getAsVariable()) { if (! symbol.getAsFunction()) {
// make sure there isn't a function of this name // make sure there isn't a function of this name
if (table[currentLevel()]->hasFunctionName(symbol.getName())) if (table[currentLevel()]->hasFunctionName(symbol.getName()))
return false; return false;
@ -438,16 +459,27 @@ public:
} }
// //
// To copy a variable from a shared level up to the current level, so it can be // Copy a variable or anonymous member's structure from a shared level up
// modified without impacting other users of the shared table. // to the current level, so it can be modified without impacting other users
// of the shared table.
// //
TVariable* copyUp(TVariable* shared) TSymbol* copyUp(TSymbol* shared)
{ {
TVariable* variable = shared->clone(); TSymbol* copy;
variable->setUniqueId(shared->getUniqueId()); if (shared->getAsVariable()) {
table[currentLevel()]->insert(*variable); copy = shared->clone();
copy->setUniqueId(shared->getUniqueId());
return variable; table[currentLevel()]->insert(*copy);
return copy;
} else {
const TAnonMember* anon = shared->getAsAnonMember();
assert(anon);
TVariable* container = anon->getAnonContainer().clone();
container->changeName(NewPoolTString(""));
container->setUniqueId(anon->getAnonContainer().getUniqueId());
table[currentLevel()]->insert(*container);
return table[currentLevel()]->find(shared->getName());
}
} }
TSymbol* find(const TString& name, bool* builtIn = 0, bool *currentScope = 0) TSymbol* find(const TString& name, bool* builtIn = 0, bool *currentScope = 0)

View File

@ -2378,7 +2378,7 @@ function_definition
parseContext.error($1.loc, "function does not return a value:", "", $1.function->getName().c_str()); parseContext.error($1.loc, "function does not return a value:", "", $1.function->getName().c_str());
parseContext.symbolTable.pop(&parseContext.defaultPrecision[0]); parseContext.symbolTable.pop(&parseContext.defaultPrecision[0]);
$$ = parseContext.intermediate.growAggregate($1.intermAggregate, $3); $$ = parseContext.intermediate.growAggregate($1.intermAggregate, $3);
parseContext.intermediate.setAggregateOperator($$, EOpFunction, $1.function->getReturnType(), $1.loc); parseContext.intermediate.setAggregateOperator($$, EOpFunction, $1.function->getType(), $1.loc);
$$->getAsAggregate()->setName($1.function->getMangledName().c_str()); $$->getAsAggregate()->setName($1.function->getMangledName().c_str());
// store the pragma information for debug and optimize and other vendor specific // store the pragma information for debug and optimize and other vendor specific

View File

@ -49,7 +49,7 @@ struct TVectorFields {
}; };
class TSymbolTable; class TSymbolTable;
class TVariable; class TSymbol;
// //
// Set of helper functions to help parse and build the tree. // Set of helper functions to help parse and build the tree.
@ -97,7 +97,7 @@ public:
bool postProcess(TIntermNode*, EShLanguage); bool postProcess(TIntermNode*, EShLanguage);
void addSymbolLinkageNodes(TIntermAggregate*& linkage, EShLanguage, TSymbolTable&); void addSymbolLinkageNodes(TIntermAggregate*& linkage, EShLanguage, TSymbolTable&);
void addSymbolLinkageNode(TIntermAggregate*& linkage, TSymbolTable&, const TString&); void addSymbolLinkageNode(TIntermAggregate*& linkage, TSymbolTable&, const TString&);
void addSymbolLinkageNode(TIntermAggregate*& linkage, const TVariable&); void addSymbolLinkageNode(TIntermAggregate*& linkage, const TSymbol&);
void addToCallGraph(TInfoSink&, const TString& caller, const TString& callee); void addToCallGraph(TInfoSink&, const TString& caller, const TString& callee);
void merge(TInfoSink&, TIntermediate&); void merge(TInfoSink&, TIntermediate&);