Restore r26192, r26240, r26241: All three about implicit-array sizing design and implementation. *Minus* test results.
r26192: Link-time sizing of implicitly-sized arrays and handling of anonymous blocks containing implicitly-sized members. Also changed "__anon" to "anon@" and encapsulated it.
r26240: Solidify the sharing of struct and array information between nodes and variables: A single copy now allows for simultaneously setting array size for all effected nodes and symbols of a given type. This allowed removal of ioArrayNodeResizeList and makes nodes of implicitly sized arrays know the final size.
r26241: Fix g++ issue with wanting non-const iterator.
git-svn-id: https://cvs.khronos.org/svn/repos/ogl/trunk/ecosystem/public/sdk/tools/glslang@26218 e7fa87d3-cd2b-0410-9028-fcbf551c1848
diff --git a/glslang/Include/Types.h b/glslang/Include/Types.h
index 0b3917c..e4c84dc 100644
--- a/glslang/Include/Types.h
+++ b/glslang/Include/Types.h
@@ -44,6 +44,12 @@
const int GlslangMaxTypeLength = 200; // TODO: need to print block/struct one member per line, so this can stay bounded
+const char* const AnonymousPrefix = "anon@"; // for something like a block whose members can be directly accessed
+inline bool IsAnonymous(const TString& name)
+{
+ return name.compare(0, 5, AnonymousPrefix) == 0;
+}
+
//
// Details within a sampler type
//
@@ -174,7 +180,7 @@
struct TArraySizes {
POOL_ALLOCATOR_NEW_DELETE(GetThreadPoolAllocator())
- TArraySizes() : implicitArraySize(0) { }
+ TArraySizes() : implicitArraySize(1) { }
int getSize() { return sizes.front(); } // TArraySizes only exists if there is at least one dimension
void setSize(int s) { sizes.push_back(s); }
bool isArrayOfArrays() { return sizes.size() > 1; }
@@ -701,14 +707,14 @@
sampler.clear();
qualifier = p.qualifier;
if (p.userDef) {
- structure = p.userDef->getStruct();
+ structure = p.userDef->getWritableStruct(); // public type is short-lived; there are no sharing issues
typeName = NewPoolTString(p.userDef->getTypeName().c_str());
}
}
// to efficiently make a dereferenced type
// without ever duplicating the outer structure that will be thrown away
// and using only shallow copy
- TType(const TType& type, int derefIndex)
+ TType(const TType& type, int derefIndex, bool rowMajor = false)
{
if (! type.isArray() && (type.basicType == EbtStruct || type.basicType == EbtBlock)) {
// do a structure dereference
@@ -718,7 +724,7 @@
} else {
// do an array/vector/matrix dereference
shallowCopy(type);
- dereference();
+ dereference(rowMajor);
}
}
// for making structures, ...
@@ -761,12 +767,12 @@
{
shallowCopy(copyOf);
- if (arraySizes) {
+ if (copyOf.arraySizes) {
arraySizes = new TArraySizes;
*arraySizes = *copyOf.arraySizes;
}
- if (structure) {
+ if (copyOf.structure) {
structure = new TTypeList;
TStructureMapIterator iter;
for (unsigned int i = 0; i < copyOf.structure->size(); ++i) {
@@ -778,9 +784,9 @@
}
}
- if (fieldName)
+ if (copyOf.fieldName)
fieldName = NewPoolTString(copyOf.fieldName->c_str());
- if (typeName)
+ if (copyOf.typeName)
typeName = NewPoolTString(copyOf.typeName->c_str());
}
@@ -793,47 +799,48 @@
}
// Merge type from parent, where a parentType is at the beginning of a declaration,
- // establishing some charastics for all subsequent names, while this type
+ // establishing some characteristics for all subsequent names, while this type
// is on the individual names.
void mergeType(const TPublicType& parentType)
{
// arrayness is currently the only child aspect that has to be preserved
- setElementType(parentType.basicType, parentType.vectorSize, parentType.matrixCols, parentType.matrixRows, parentType.userDef);
+ basicType = parentType.basicType;
+ vectorSize = parentType.vectorSize;
+ matrixCols = parentType.matrixCols;
+ matrixRows = parentType.matrixRows;
qualifier = parentType.qualifier;
sampler = parentType.sampler;
if (parentType.arraySizes)
setArraySizes(parentType.arraySizes);
- if (parentType.userDef)
+ if (parentType.userDef) {
+ structure = parentType.userDef->getWritableStruct();
setTypeName(parentType.userDef->getTypeName());
+ }
}
- virtual void dereference()
+ virtual void dereference(bool rowMajor = false)
{
if (arraySizes)
arraySizes = 0;
else if (matrixCols > 0) {
- vectorSize = matrixRows;
+ if (rowMajor)
+ vectorSize = matrixCols;
+ else
+ vectorSize = matrixRows;
matrixCols = 0;
matrixRows = 0;
} else if (vectorSize > 1)
vectorSize = 1;
}
- virtual void setElementType(TBasicType t, int s, int mc, int mr, const TType* userDef)
- {
- basicType = t;
- vectorSize = s;
- matrixCols = mc;
- matrixRows = mr;
- if (userDef)
- structure = userDef->getStruct();
- // leave array information intact.
- }
+ virtual void hideType() { basicType = EbtVoid; vectorSize = 1; }
+ virtual bool wasTypeHidden() const { return basicType == EbtVoid; }
+
virtual void setTypeName(const TString& n) { typeName = NewPoolTString(n.c_str()); }
virtual void setFieldName(const TString& n) { fieldName = NewPoolTString(n.c_str()); }
virtual const TString& getTypeName() const
{
- assert(typeName);
+ assert(typeName);
return *typeName;
}
@@ -845,17 +852,22 @@
virtual TBasicType getBasicType() const { return basicType; }
virtual const TSampler& getSampler() const { return sampler; }
- virtual TQualifier& getQualifier() { return qualifier; }
+
+ virtual TQualifier& getQualifier() { return qualifier; }
virtual const TQualifier& getQualifier() const { return qualifier; }
virtual int getVectorSize() const { return vectorSize; }
virtual int getMatrixCols() const { return matrixCols; }
virtual int getMatrixRows() const { return matrixRows; }
+ virtual int getArraySize() const { return arraySizes->sizes.front(); }
+ virtual int getImplicitArraySize () const { return arraySizes->implicitArraySize; }
virtual bool isScalar() const { return vectorSize == 1 && ! isStruct() && ! isArray(); }
virtual bool isVector() const { return vectorSize > 1; }
virtual bool isMatrix() const { return matrixCols ? true : false; }
virtual bool isArray() const { return arraySizes != 0; }
+ virtual bool isImplicitlySizedArray() const { return isArray() && ! getArraySize(); }
+ virtual bool isExplicitlySizedArray() const { return ! isImplicitlySizedArray(); }
virtual bool isStruct() const { return structure != 0; }
// Recursively checks if the type contains the given basic type
@@ -885,28 +897,58 @@
}
return false;
}
- int getArraySize() const { return arraySizes->sizes.front(); }
- void shareArraySizes(const TType& type)
+
+ // Recursively check the structure for any implicitly-sized arrays, needed for triggering a copyUp().
+ virtual bool containsImplicitlySizedArray() const
{
- // For when we are sharing existing array descriptors.
- // This allows all references to the same array
- // to be updated at once, by having all of them share the
- // array description.
+ if (isImplicitlySizedArray())
+ return true;
+ if (! structure)
+ return false;
+ for (unsigned int i = 0; i < structure->size(); ++i) {
+ if ((*structure)[i].type->containsImplicitlySizedArray())
+ return true;
+ }
+ return false;
+ }
+
+ // Array editing methods. Array descriptors can be shared across
+ // type instances. This allows all uses of the same array
+ // to be updated at once. E.g., all nodes can be explicitly sized
+ // by tracking and correcting one implicit size. Or, all nodes
+ // can get the explicit size on a redeclaration that gives size.
+ //
+ // N.B.: Don't share with the shared symbol tables (symbols are
+ // marked as isReadOnly(). Such symbols with arrays that will be
+ // edited need to copyUp() on first use, so that
+ // A) the edits don't effect the shared symbol table, and
+ // B) the edits are shared across all users.
+ void updateArraySizes(const TType& type)
+ {
+ // For when we may already be sharing existing array descriptors,
+ // keeping the pointers the same, just updating the contents.
*arraySizes = *type.arraySizes;
}
void setArraySizes(TArraySizes* s)
{
- // For when we don't want distinct types sharing the same descriptor.
+ // For setting a fresh new set of array sizes, not yet worrying about sharing.
arraySizes = new TArraySizes;
*arraySizes = *s;
}
void setArraySizes(const TType& type) { setArraySizes(type.arraySizes); }
-
void changeArraySize(int s) { arraySizes->sizes.front() = s; }
- bool isImplicitlySizedArray() const { return isArray() && ! getArraySize(); }
- bool isExplicitlySizedArray() const { return ! isImplicitlySizedArray(); }
void setImplicitArraySize (int s) { arraySizes->implicitArraySize = s; }
- int getImplicitArraySize () const { return arraySizes->implicitArraySize; }
+
+ // Recursively make the implicit array size the explicit array size, through the type tree.
+ void adoptImplicitArraySizes()
+ {
+ if (isImplicitlySizedArray())
+ changeArraySize(getImplicitArraySize());
+ if (isStruct()) {
+ for (int i = 0; i < (int)structure->size(); ++i)
+ (*structure)[i].type->adoptImplicitArraySizes();
+ }
+ }
const char* getBasicString() const
{
@@ -1044,15 +1086,15 @@
const char* getStorageQualifierString() const { return GetStorageQualifierString(qualifier.storage); }
const char* getPrecisionQualifierString() const { return GetPrecisionQualifierString(qualifier.precision); }
- TTypeList* getStruct() { return structure; }
- TTypeList* getStruct() const { return structure; }
+ const TTypeList* getStruct() const { return structure; }
+ TTypeList* getWritableStruct() const { return structure; } // This should only be used when known to not be sharing with other threads
int computeNumComponents() const
{
int components = 0;
if (getBasicType() == EbtStruct || getBasicType() == EbtBlock) {
- for (TTypeList::iterator tl = getStruct()->begin(); tl != getStruct()->end(); tl++)
+ for (TTypeList::const_iterator tl = getStruct()->begin(); tl != getStruct()->end(); tl++)
components += ((*tl).type)->computeNumComponents();
} else if (matrixCols)
components = matrixCols * matrixRows;
@@ -1158,9 +1200,8 @@
TSampler sampler;
TQualifier qualifier;
- TArraySizes* arraySizes;
-
- TTypeList* structure; // 0 unless this is a struct
+ TArraySizes* arraySizes; // 0 unless this is an array; can be shared across types
+ TTypeList* structure; // 0 unless this is a struct; can be shared across types
TString *fieldName; // for structure field names
TString *typeName; // for structure type name
};
diff --git a/glslang/MachineIndependent/Intermediate.cpp b/glslang/MachineIndependent/Intermediate.cpp
index 5195a0b..62ff0c5 100644
--- a/glslang/MachineIndependent/Intermediate.cpp
+++ b/glslang/MachineIndependent/Intermediate.cpp
@@ -866,10 +866,10 @@
// by the AST.
//
// Almost entirely, translation of symbols is driven by what's present
- // in the AST traversal, not by translating the symbol table.
+ // 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
+ // - 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.
diff --git a/glslang/MachineIndependent/ParseHelper.cpp b/glslang/MachineIndependent/ParseHelper.cpp
index 8b2be3c..3fcdbaf 100644
--- a/glslang/MachineIndependent/ParseHelper.cpp
+++ b/glslang/MachineIndependent/ParseHelper.cpp
@@ -371,59 +371,56 @@
TIntermTyped* TParseContext::handleVariable(TSourceLoc loc, TSymbol* symbol, TString* string)
{
TIntermTyped* node = 0;
- bool noteAccess = false;
// Error check for function requiring specific extensions present.
if (symbol && symbol->getNumExtensions())
requireExtensions(loc, symbol->getNumExtensions(), symbol->getExtensions(), symbol->getName().c_str());
+ if (symbol && symbol->isReadOnly()) {
+ // All shared things containing an implicitly sized array must be copied up
+ // on first use, so that all future references will share its array structure,
+ // so that editing the implicit size will effect all nodes consuming it,
+ // and so that editing the implicit size won't change the shared one.
+ if (symbol->getType().containsImplicitlySizedArray())
+ makeEditable(symbol);
+ }
+
+ const TVariable* variable;
const TAnonMember* anon = symbol ? symbol->getAsAnonMember() : 0;
if (anon) {
- // it was a member of an anonymous container
-
- // create a subtree for its dereference
- const TVariable* variable = anon->getAnonContainer().getAsVariable();
+ // It was a member of an anonymous container.
+
+ // Create a subtree for its dereference.
+ variable = anon->getAnonContainer().getAsVariable();
TIntermTyped* container = intermediate.addSymbol(*variable, loc);
TConstUnionArray unionArray(1);
unionArray[0].setUConst(anon->getMemberNumber());
TIntermTyped* constNode = intermediate.addConstantUnion(unionArray, TType(EbtUint, EvqConst), loc);
-
node = intermediate.addIndex(EOpIndexDirectStruct, container, constNode, loc);
- node->setType(*(*variable->getType().getStruct())[anon->getMemberNumber()].type);
- if (node->getBasicType() == EbtVoid)
- error(loc, "member of nameless block was not redeclared", string->c_str(), "");
- if (variable->getType().getQualifier().isIo())
- noteAccess = true;
- // TODO: does this create any accidental type sharing with the built-in level?
+ node->setType(*(*variable->getType().getStruct())[anon->getMemberNumber()].type);
+ if (node->getType().wasTypeHidden())
+ error(loc, "member of nameless block was not redeclared", string->c_str(), "");
} else {
- // The symbol table search was done in the lexical phase, but
- // if this is a new symbol, it wouldn't have found it.
- TVariable* variable = symbol ? symbol->getAsVariable() : 0;
+ // Not a member of an anonymous container.
+
+ // The symbol table search was done in the lexical phase.
+ // See if it was a variable.
+ variable = symbol ? symbol->getAsVariable() : 0;
if (symbol && ! variable)
error(loc, "variable name expected", string->c_str(), "");
+ // Recovery, if it wasn't found or was not a variable.
if (! variable)
variable = new TVariable(string, TType(EbtVoid));
if (variable->getType().getQualifier().storage == EvqConst)
node = intermediate.addConstantUnion(variable->getConstArray(), variable->getType(), loc);
- else {
- TType* type;
- if (variable->isReadOnly()) {
- type = new TType;
- // break type sharing with built-ins; only costs if there are arrays or structures
- type->deepCopy(variable->getType());
- } else
- type = &variable->getWritableType();
- // addSymbol will do a shallow copy of the type to the node, thus sharing array and struct information
- node = intermediate.addSymbol(variable->getUniqueId(), variable->getName(), *type, loc);
- if (type->getQualifier().isIo())
- noteAccess = true;
- }
+ else
+ node = intermediate.addSymbol(*variable, loc);
}
- if (noteAccess)
+ if (variable->getType().getQualifier().isIo())
intermediate.addIoAccessed(*string);
return node;
@@ -543,6 +540,22 @@
}
}
+// Make a shared symbol have a non-shared version that can be edited by the current
+// compile, such that editing its type will not change the shared version and will
+// effect all nodes sharing it.
+void TParseContext::makeEditable(TSymbol*& symbol)
+{
+ // copyUp() does a deep copy of the type.
+ symbol = symbolTable.copyUp(symbol);
+
+ // Also, see if it's tied to IO resizing
+ if (isIoResizeArray(symbol->getType()))
+ ioArraySymbolResizeList.push_back(symbol);
+
+ // Also, save it in the AST for linker use.
+ intermediate.addSymbolLinkageNode(linkage, *symbol);
+}
+
// Return true if this is a geometry shader input array or tessellation control output array.
bool TParseContext::isIoResizeArray(const TType& type) const
{
@@ -585,33 +598,20 @@
}
// Handle a dereference of a geometry shader input array or tessellation control output array.
-// See ioArrayNodeResizeList comment in ParseHelper.h.
+// See ioArraySymbolResizeList comment in ParseHelper.h.
//
void TParseContext::handleIoResizeArrayAccess(TSourceLoc loc, TIntermTyped* base)
{
- TIntermSymbol* symbol = base->getAsSymbolNode();
- assert(symbol);
- ioArrayNodeResizeList.push_back(symbol);
- if (symbol && builtInName(symbol->getName())) {
- // make sure we have a user-modifiable copy of this built-in input array
- TSymbol* arry = symbolTable.find(symbol->getName());
- if (arry->isReadOnly()) {
- arry = symbolTable.copyUp(arry);
+ TIntermSymbol* symbolNode = base->getAsSymbolNode();
+ assert(symbolNode);
+ if (! symbolNode)
+ return;
- // fix array size, if already implicitly size
- if (arry->getType().isImplicitlySizedArray()) {
- int newSize = getIoArrayImplicitSize();
- if (newSize) {
- arry->getWritableType().changeArraySize(newSize);
- symbol->getWritableType().changeArraySize(newSize);
- }
- }
-
- ioArraySymbolResizeList.push_back(arry);
-
- // Save it in the AST for linker use.
- intermediate.addSymbolLinkageNode(linkage, *arry);
- }
+ // fix array size, if it can be fixed and needs to be fixed (will allow variable indexing)
+ if (symbolNode->getType().isImplicitlySizedArray()) {
+ int newSize = getIoArrayImplicitSize();
+ if (newSize)
+ symbolNode->getWritableType().changeArraySize(newSize);
}
}
@@ -640,9 +640,6 @@
return;
}
- for (size_t i = 0; i < ioArrayNodeResizeList.size(); ++i)
- checkIoArrayConsistency(loc, requiredSize, feature, ioArrayNodeResizeList[i]->getWritableType(), ioArrayNodeResizeList[i]->getName());
-
for (size_t i = 0; i < ioArraySymbolResizeList.size(); ++i)
checkIoArrayConsistency(loc, requiredSize, feature, ioArraySymbolResizeList[i]->getWritableType(), ioArraySymbolResizeList[i]->getName());
}
@@ -732,7 +729,7 @@
} else if (base->isMatrix())
error(loc, "field selection not allowed on matrix", ".", "");
else if (base->getBasicType() == EbtStruct || base->getBasicType() == EbtBlock) {
- TTypeList* fields = base->getType().getStruct();
+ const TTypeList* fields = base->getType().getStruct();
bool fieldFound = false;
unsigned int member;
for (member = 0; member < fields->size(); ++member) {
@@ -2118,7 +2115,7 @@
return true;
if (type.getBasicType() == EbtStruct) {
- TTypeList& structure = *type.getStruct();
+ const TTypeList& structure = *type.getStruct();
for (unsigned int i = 0; i < structure.size(); ++i) {
if (containsSampler(*structure[i].type))
return true;
@@ -2204,7 +2201,7 @@
}
//
-// Do all the semantic checking for declaring an array, with and
+// Do all the semantic checking for declaring or redeclaring an array, with and
// without a size, and make the right changes to the symbol table.
//
// size == 0 means no specified size.
@@ -2249,27 +2246,28 @@
return;
}
- TType& newType = symbol->getWritableType();
+ // redeclareBuiltinVariable() should have already done the copyUp()
+ TType& existingType = symbol->getWritableType();
- if (! newType.isArray()) {
+ if (! existingType.isArray()) {
error(loc, "redeclaring non-array as array", identifier.c_str(), "");
return;
}
- if (newType.isExplicitlySizedArray()) {
+ if (existingType.isExplicitlySizedArray()) {
// be more leniant for input arrays to geometry shaders and tessellation control outputs, where the redeclaration is the same size
- if (! (isIoResizeArray(type) && newType.getArraySize() == type.getArraySize()))
+ if (! (isIoResizeArray(type) && existingType.getArraySize() == type.getArraySize()))
error(loc, "redeclaration of array with size", identifier.c_str(), "");
return;
}
- if (! newType.sameElementType(type)) {
+ if (! existingType.sameElementType(type)) {
error(loc, "redeclaration of array with a different type", identifier.c_str(), "");
return;
}
arrayLimitCheck(loc, identifier, type.getArraySize());
- newType.shareArraySizes(type);
+ existingType.updateArraySizes(type);
if (isIoResizeArray(type))
checkIoArraysConsistency(loc);
@@ -2284,13 +2282,29 @@
// something to do...
- // TODO: 1.50 linker: unsized block member array: 'node' could be an expression for a dereference
- TIntermSymbol* symbolNode = node->getAsSymbolNode();
- if (! symbolNode)
- return;
+ // Figure out what symbol to lookup, as we will use its type to edit for the size change,
+ // as that type will be shared through shallow copies for future references.
+ TSymbol* symbol = 0;
+ int blockIndex = -1;
+ const TString* lookupName;
+ if (node->getAsSymbolNode())
+ lookupName = &node->getAsSymbolNode()->getName();
+ else if (node->getAsBinaryNode()) {
+ const TIntermBinary* deref = node->getAsBinaryNode();
+ // This has to be the result of a block dereference, unless it's bad shader code
+ if (! deref->getLeft()->getAsSymbolNode() || deref->getLeft()->getBasicType() != EbtBlock ||
+ deref->getRight()->getAsConstantUnion() == 0)
+ return;
- TSymbol* symbol = symbolTable.find(symbolNode->getName());
- assert(symbol);
+ blockIndex = deref->getRight()->getAsConstantUnion()->getConstArray()[0].getIConst();
+
+ lookupName = &deref->getLeft()->getAsSymbolNode()->getName();
+ if (IsAnonymous(*lookupName))
+ lookupName = &(*deref->getLeft()->getType().getStruct())[blockIndex].type->getFieldName();
+ }
+
+ // Lookup the symbol, should only fail if shader code is incorrect
+ symbol = symbolTable.find(*lookupName);
if (symbol == 0)
return;
@@ -2299,18 +2313,6 @@
return;
}
- // For read-only built-ins, add a new variable for holding the maximum array size of an implicitly-sized shared array.
- // TODO: desktop linker: unsized arrays: is this new array type shared with the node?
- if (symbol->isReadOnly()) {
- symbol = symbolTable.copyUp(symbol);
-
- if (isIoResizeArray(symbol->getType()))
- ioArraySymbolResizeList.push_back(symbol);
-
- // Save it in the AST for linker use.
- intermediate.addSymbolLinkageNode(linkage, *symbol);
- }
-
symbol->getWritableType().setImplicitArraySize(index + 1);
}
@@ -2371,14 +2373,8 @@
// redeclaration. Otherwise, make the new one.
if (builtIn) {
// Copy the symbol up to make a writable version
+ makeEditable(symbol);
newDeclaration = true;
- symbol = symbolTable.copyUp(symbol);
-
- if (isIoResizeArray(symbol->getType()))
- ioArraySymbolResizeList.push_back(symbol);
-
- // Save it in the AST for linker use.
- intermediate.addSymbolLinkageNode(linkage, *symbol);
}
// Now, modify the type of the copy, as per the type of the current redeclaration.
@@ -2490,12 +2486,12 @@
// - remove unused members
// - ensure remaining qualifiers/types match
TType& type = block->getWritableType();
- TTypeList::iterator member = type.getStruct()->begin();
+ TTypeList::iterator member = type.getWritableStruct()->begin();
size_t numOriginalMembersFound = 0;
while (member != type.getStruct()->end()) {
// look for match
bool found = false;
- TTypeList::iterator newMember;
+ TTypeList::const_iterator newMember;
TSourceLoc memberLoc;
for (newMember = newTypeList.begin(); newMember != newTypeList.end(); ++newMember) {
if (member->type->getFieldName() == newMember->type->getFieldName()) {
@@ -2536,13 +2532,13 @@
// go to next member
++member;
} else {
- // Use EbtVoid to tag missing members of anonymous blocks that have been redeclared,
- // to hide the original (shared) declaration.
- // (Instance-named blocks can just have the member removed.)
+ // For missing members of anonymous blocks that have been redeclared,
+ // hide the original (shared) declaration.
+ // Instance-named blocks can just have the member removed.
if (instanceName)
- member = type.getStruct()->erase(member);
+ member = type.getWritableStruct()->erase(member);
else {
- member->type->setElementType(EbtVoid, 1, 0, 0, 0);
+ member->type->hideType();
++member;
}
}
@@ -2643,7 +2639,7 @@
void TParseContext::structTypeCheck(TSourceLoc loc, TPublicType& publicType)
{
- TTypeList& typeList = *publicType.userDef->getStruct();
+ const TTypeList& typeList = *publicType.userDef->getStruct();
// fix and check for member storage qualifiers and types that don't belong within a structure
for (unsigned int member = 0; member < typeList.size(); ++member) {
@@ -3797,7 +3793,7 @@
TIntermAggregate* aggrNode = node->getAsAggregate();
- TTypeList::iterator memberTypes;
+ TTypeList::const_iterator memberTypes;
if (op == EOpConstructStruct)
memberTypes = type.getStruct()->begin();
diff --git a/glslang/MachineIndependent/ShaderLang.cpp b/glslang/MachineIndependent/ShaderLang.cpp
index d781083..fc200a6 100644
--- a/glslang/MachineIndependent/ShaderLang.cpp
+++ b/glslang/MachineIndependent/ShaderLang.cpp
@@ -1064,7 +1064,7 @@
intermediate[stage]->finalCheck(*infoSink);
if (messages & EShMsgAST)
- intermediate[stage]->output(*infoSink, stages[stage].size() > 1);
+ intermediate[stage]->output(*infoSink, true);
return intermediate[stage]->getNumErrors() == 0;
}
diff --git a/glslang/MachineIndependent/linkValidate.cpp b/glslang/MachineIndependent/linkValidate.cpp
index 4a7d0bc..5c262bd 100644
--- a/glslang/MachineIndependent/linkValidate.cpp
+++ b/glslang/MachineIndependent/linkValidate.cpp
@@ -206,7 +206,10 @@
// Similarly for binding
if (! symbol->getQualifier().hasBinding() && unitSymbol->getQualifier().hasBinding())
symbol->getQualifier().layoutBinding = unitSymbol->getQualifier().layoutBinding;
-
+
+ // Update implicit array sizes
+ mergeImplicitArraySizes(symbol->getWritableType(), unitSymbol->getType());
+
// Check for consistent types/qualification/initializers etc.
mergeErrorCheck(infoSink, *symbol, *unitSymbol, false);
}
@@ -216,6 +219,25 @@
}
}
+// Recursively merge the implicit array sizes through the objects' respective type trees.
+void TIntermediate::mergeImplicitArraySizes(TType& type, const TType& unitType)
+{
+ if (type.isImplicitlySizedArray() && unitType.isArray()) {
+ int newImplicitArraySize = unitType.getArraySize();
+ if (newImplicitArraySize == 0)
+ newImplicitArraySize = unitType.getImplicitArraySize();
+ if (newImplicitArraySize > type.getImplicitArraySize ())
+ type.setImplicitArraySize(newImplicitArraySize);
+ }
+
+ // Type mismatches are caught and reported after this, just be careful for now.
+ if (! type.isStruct() || ! unitType.isStruct() || type.getStruct()->size() != unitType.getStruct()->size())
+ return;
+
+ for (int i = 0; i < (int)type.getStruct()->size(); ++i)
+ mergeImplicitArraySizes(*(*type.getStruct())[i].type, *(*unitType.getStruct())[i].type);
+}
+
//
// Compare two global objects from two compilation units and see if they match
// well enough. Rules can be different for intra- vs. cross-stage matching.
@@ -305,7 +327,7 @@
// Do final link-time error checking of a complete (merged) intermediate representation.
// (Much error checking was done during merging).
//
-// Also, lock in defaults of things not set.
+// Also, lock in defaults of things not set, including array sizes.
//
void TIntermediate::finalCheck(TInfoSink& infoSink)
{
@@ -392,6 +414,21 @@
case EShLangCompute:
break;
}
+
+ // Process the tree for any node-specific work.
+ class TFinalLinkTraverser : public TIntermTraverser {
+ public:
+ TFinalLinkTraverser() { }
+ virtual ~TFinalLinkTraverser() { }
+
+ virtual void visitSymbol(TIntermSymbol* symbol)
+ {
+ // Implicitly size arrays.
+ symbol->getWritableType().adoptImplicitArraySizes();
+ }
+ } finalLinkTraverser;
+
+ treeRoot->traverse(&finalLinkTraverser);
}
//
@@ -877,11 +914,8 @@
// rules 5 and 7
if (type.isMatrix()) {
- TType derefType(type, 0);
-
// rule 5: deref to row, not to column, meaning the size of vector is num columns instead of num rows
- if (type.getQualifier().layoutMatrix == ElmRowMajor)
- derefType.setElementType(derefType.getBasicType(), type.getMatrixCols(), 0, 0, 0);
+ TType derefType(type, 0, type.getQualifier().layoutMatrix == ElmRowMajor);
alignment = getBaseAlignment(derefType, size, std140);
if (std140)
diff --git a/glslang/MachineIndependent/localintermediate.h b/glslang/MachineIndependent/localintermediate.h
index 621772f..4ebbf2c 100644
--- a/glslang/MachineIndependent/localintermediate.h
+++ b/glslang/MachineIndependent/localintermediate.h
@@ -251,6 +251,7 @@
void error(TInfoSink& infoSink, const char*);
void mergeBodies(TInfoSink&, TIntermSequence& globals, const TIntermSequence& unitGlobals);
void mergeLinkerObjects(TInfoSink&, TIntermSequence& linkerObjects, const TIntermSequence& unitLinkerObjects);
+ void mergeImplicitArraySizes(TType&, const TType&);
void mergeErrorCheck(TInfoSink&, const TIntermSymbol&, const TIntermSymbol&, bool crossStage);
void checkCallGraphCycles(TInfoSink&);
void inOutLocationCheck(TInfoSink&);
diff --git a/glslang/MachineIndependent/reflection.cpp b/glslang/MachineIndependent/reflection.cpp
index 07bba31..ac9f3b6 100644
--- a/glslang/MachineIndependent/reflection.cpp
+++ b/glslang/MachineIndependent/reflection.cpp
@@ -283,7 +283,7 @@
bool block = base->getBasicType() == EbtBlock;
if (block) {
offset = 0;
- anonymous = base->getName().compare(0, 6, "__anon") == 0;
+ anonymous = IsAnonymous(base->getName());
if (base->getType().isArray()) {
assert(! anonymous);
for (int e = 0; e < base->getType().getArraySize(); ++e)