Add anonymous members as a new symbol table type, so the infrastructure can handle blocks with no names.
Also, add more safety to the types involved regarding copy constructors, operator=, etc. git-svn-id: https://cvs.khronos.org/svn/repos/ogl/trunk/ecosystem/public/sdk/tools/glslang@21106 e7fa87d3-cd2b-0410-9028-fcbf551c1848
This commit is contained in:
parent
ed3197921e
commit
ba04210097
@ -5,7 +5,8 @@ layout(LocatioN = 3) in vec4 p;
|
||||
out vec4 pos;
|
||||
out vec3 color;
|
||||
|
||||
layout(shared, column_major, row_major) uniform mat4 m4; // default is now shared and row_major
|
||||
layout(shared, column_major, row_major) uniform mat4 badm4; // ERROR
|
||||
layout(shared, column_major, row_major) uniform; // default is now shared and row_major
|
||||
|
||||
layout(std140) uniform Transform { // layout of this block is std140
|
||||
mat4 M1; // row_major
|
||||
@ -13,18 +14,20 @@ layout(std140) uniform Transform { // layout of this block is std140
|
||||
mat3 N1; // row_major
|
||||
} tblock;
|
||||
|
||||
//uniform T2 { // layout of this block is shared
|
||||
//...
|
||||
//};
|
||||
//
|
||||
uniform T2 { // layout of this block is shared
|
||||
bool b;
|
||||
mat4 t2m;
|
||||
};
|
||||
|
||||
layout(column_major) uniform T3 { // shared and column_major
|
||||
mat4 M3; // column_major
|
||||
layout(row_major) mat4 m4; // row major
|
||||
layout(row_major) mat4 M4; // row major
|
||||
mat3 N2; // column_major
|
||||
int b; // ERROR, redefinition (needs to be last member of block for testing, following members are skipped)
|
||||
};
|
||||
|
||||
void main()
|
||||
{
|
||||
pos = p * (m4 + tblock.M1 + tblock.M2);
|
||||
pos = p * (tblock.M1 + tblock.M2 + M4 + M3 + t2m);
|
||||
color = c * tblock.N1;
|
||||
}
|
||||
|
||||
@ -68,16 +68,16 @@ layout(std140) uniform Transform2 { // layout of this block is std140
|
||||
};
|
||||
|
||||
layout(column_major) uniform T3 { // shared and column_major
|
||||
mat4 M3; // column_major
|
||||
layout(row_major) mat4 m4; // row major
|
||||
mat3 N2; // column_major
|
||||
mat4 M13; // column_major
|
||||
layout(row_major) mat4 m14; // row major
|
||||
mat3 N12; // column_major
|
||||
};
|
||||
|
||||
// in one compilation unit...
|
||||
layout(binding=3) uniform sampler2D s; // s bound to unit 3
|
||||
layout(binding=3) uniform sampler2D s17; // s bound to unit 3
|
||||
|
||||
// in another compilation unit...
|
||||
uniform sampler2D s; // okay, s still bound at 3
|
||||
uniform sampler2D s17; // okay, s still bound at 3
|
||||
|
||||
// in another compilation unit...
|
||||
//layout(binding=4) uniform sampler2D s; // ERROR: contradictory bindings
|
||||
|
||||
@ -398,7 +398,11 @@ public:
|
||||
TType() {}
|
||||
virtual ~TType() {}
|
||||
|
||||
TType(const TType& type) { *this = type; }
|
||||
// "dumb" copy, using built-in operator=(), not for use across pool pops.
|
||||
// It will also cause multiple copies of TType to point to the same information.
|
||||
// This only works if that information (like a structure's list of types) does not
|
||||
// change.
|
||||
explicit TType(const TType& type) { *this = type; }
|
||||
|
||||
void copyType(const TType& copyOf, const TStructureMap& remapper)
|
||||
{
|
||||
@ -680,7 +684,7 @@ protected:
|
||||
TArraySizes arraySizes;
|
||||
|
||||
TTypeList* structure; // 0 unless this is a struct
|
||||
mutable int structureSize;
|
||||
mutable int structureSize; // a cache, updated on first access
|
||||
int maxArraySize;
|
||||
TType* arrayInformationType;
|
||||
TString *fieldName; // for structure field names
|
||||
|
||||
@ -48,7 +48,7 @@ bool CompareStruct(const TType& leftNodeType, constUnion* rightUnionArray, const
|
||||
bool CompareStructure(const TType& leftNodeType, constUnion* rightUnionArray, constUnion* leftUnionArray)
|
||||
{
|
||||
if (leftNodeType.isArray()) {
|
||||
TType typeWithoutArrayness = leftNodeType;
|
||||
TType typeWithoutArrayness(leftNodeType);
|
||||
typeWithoutArrayness.dereference();
|
||||
|
||||
int arraySize = leftNodeType.getArraySize();
|
||||
@ -111,7 +111,7 @@ TIntermTyped* TIntermConstantUnion::fold(TOperator op, TIntermTyped* constantNod
|
||||
|
||||
// For most cases, the return type matches the argument type, so set that
|
||||
// up and just code to exceptions below.
|
||||
TType returnType = getType();
|
||||
TType returnType(getType());
|
||||
|
||||
//
|
||||
// A pair of nodes is to be folded together
|
||||
|
||||
@ -1183,7 +1183,7 @@ const TFunction* TParseContext::findFunction(int line, TFunction* call, bool *bu
|
||||
bool TParseContext::executeInitializer(TSourceLoc line, TString& identifier, TPublicType& pType,
|
||||
TIntermTyped* initializer, TIntermNode*& intermNode, TVariable* variable)
|
||||
{
|
||||
TType type = TType(pType);
|
||||
TType type(pType);
|
||||
|
||||
if (variable == 0) {
|
||||
if (reservedErrorCheck(line, identifier))
|
||||
@ -1286,7 +1286,7 @@ TIntermTyped* TParseContext::addConstructor(TIntermNode* node, const TType& type
|
||||
if (op == EOpConstructStruct)
|
||||
memberTypes = type.getStruct()->begin();
|
||||
|
||||
TType elementType = type;
|
||||
TType elementType(type);
|
||||
if (type.isArray())
|
||||
elementType.dereference();
|
||||
|
||||
@ -1496,8 +1496,8 @@ void TParseContext::addBlock(int line, TPublicType& qualifier, const TString& bl
|
||||
|
||||
// Build and add the interface block as a new type named blockName
|
||||
|
||||
TType* blockType = new TType(&typeList, blockName, qualifier.qualifier.storage);
|
||||
TVariable* userTypeDef = new TVariable(&blockName, *blockType, true);
|
||||
TType blockType(&typeList, blockName, qualifier.qualifier.storage);
|
||||
TVariable* userTypeDef = new TVariable(&blockName, blockType, true);
|
||||
if (! symbolTable.insert(*userTypeDef)) {
|
||||
error(line, "redefinition", blockName.c_str(), "block name");
|
||||
recover();
|
||||
@ -1516,11 +1516,12 @@ void TParseContext::addBlock(int line, TPublicType& qualifier, const TString& bl
|
||||
if (! instanceName)
|
||||
instanceName = new TString("");
|
||||
|
||||
TVariable* variable = new TVariable(instanceName, *blockType);
|
||||
|
||||
TVariable* variable = new TVariable(instanceName, blockType);
|
||||
if (! symbolTable.insert(*variable)) {
|
||||
error(line, "redefinition", variable->getName().c_str(), "");
|
||||
delete variable;
|
||||
if (*instanceName == "")
|
||||
error(line, "nameless block contains a member that already has a name at global scope", blockName.c_str(), "");
|
||||
else
|
||||
error(line, "block instance name redefinition", variable->getName().c_str(), "");
|
||||
recover();
|
||||
|
||||
return;
|
||||
@ -1616,7 +1617,7 @@ TIntermTyped* TParseContext::addConstArrayNode(int index, TIntermTyped* node, TS
|
||||
TIntermTyped* typedNode;
|
||||
TIntermConstantUnion* tempConstantNode = node->getAsConstantUnion();
|
||||
int arraySize = node->getType().getArraySize();
|
||||
TType arrayElementType = node->getType();
|
||||
TType arrayElementType(node->getType());
|
||||
arrayElementType.dereference();
|
||||
|
||||
if (index >= node->getType().getArraySize() || index < 0) {
|
||||
|
||||
@ -58,7 +58,7 @@ protected:
|
||||
// is guaranteed written. Not always possible to determine if
|
||||
// it is written conditionally.
|
||||
//
|
||||
// ?? It does not do this well yet, this is just a place holder
|
||||
// It does not do this well yet, this is just a place holder
|
||||
// that simply determines if it was reference at all, anywhere.
|
||||
//
|
||||
bool QualifierWritten(TIntermNode* node, TStorageQualifier qualifier)
|
||||
|
||||
@ -146,6 +146,11 @@ void TFunction::dump(TInfoSink &infoSink) const
|
||||
infoSink.debug << getName().c_str() << ": " << returnType.getCompleteTypeString() << " " << getMangledName().c_str() << "\n";
|
||||
}
|
||||
|
||||
void TAnonMember::dump(TInfoSink& TInfoSink) const
|
||||
{
|
||||
TInfoSink.debug << "anonymous member " << getMemberNumber() << " of " << getAnonContainer().getName().c_str() << "\n";
|
||||
}
|
||||
|
||||
void TSymbolTableLevel::dump(TInfoSink &infoSink) const
|
||||
{
|
||||
tLevel::const_iterator it;
|
||||
@ -250,9 +255,18 @@ TFunction* TFunction::clone(TStructureMap& remapper)
|
||||
return function;
|
||||
}
|
||||
|
||||
TAnonMember* TAnonMember::clone(TStructureMap& remapper)
|
||||
{
|
||||
// need to implement this once built-in symbols include interface blocks
|
||||
assert(0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
TSymbolTableLevel* TSymbolTableLevel::clone(TStructureMap& remapper)
|
||||
{
|
||||
TSymbolTableLevel *symTableLevel = new TSymbolTableLevel();
|
||||
symTableLevel->anonId = anonId;
|
||||
tLevel::iterator iter;
|
||||
for (iter = level.begin(); iter != level.end(); ++iter) {
|
||||
symTableLevel->insert(*iter->second->clone(remapper));
|
||||
|
||||
@ -42,6 +42,11 @@
|
||||
// effort of creating and loading with the large numbers of built-in
|
||||
// symbols.
|
||||
//
|
||||
// --> This requires a copy mechanism, so initial pools used to create
|
||||
// the shared information can be popped. So, care is taken with
|
||||
// copying pointers to point to new copies. Done through "clone"
|
||||
// methods.
|
||||
//
|
||||
// * Name mangling will be used to give each function a unique name
|
||||
// so that symbol table lookups are never ambiguous. This allows
|
||||
// a simpler symbol table structure.
|
||||
@ -67,24 +72,30 @@
|
||||
//
|
||||
class TVariable;
|
||||
class TFunction;
|
||||
class TAnonMember;
|
||||
class TSymbol {
|
||||
public:
|
||||
POOL_ALLOCATOR_NEW_DELETE(GlobalPoolAllocator)
|
||||
TSymbol(const TString *n) : name(n) { }
|
||||
virtual ~TSymbol() { /* don't delete name, it's from the pool */ }
|
||||
explicit TSymbol(const TString *n) : name(n) { }
|
||||
virtual TSymbol* clone(TStructureMap& remapper) = 0;
|
||||
virtual ~TSymbol() { }
|
||||
|
||||
const TString& getName() const { return *name; }
|
||||
void changeName(const char* buf) { name = new TString(buf); }
|
||||
virtual const TString& getMangledName() const { return getName(); }
|
||||
virtual TFunction* getAsFunction() { return 0; }
|
||||
virtual TVariable* getAsVariable() { return 0; }
|
||||
virtual TAnonMember* getAsAnonMember() { return 0; }
|
||||
void setUniqueId(int id) { uniqueId = id; }
|
||||
int getUniqueId() const { return uniqueId; }
|
||||
virtual void dump(TInfoSink &infoSink) const = 0;
|
||||
TSymbol(const TSymbol&);
|
||||
virtual TSymbol* clone(TStructureMap& remapper) = 0;
|
||||
|
||||
protected:
|
||||
explicit TSymbol(const TSymbol&);
|
||||
TSymbol& operator=(const TSymbol&);
|
||||
|
||||
const TString *name;
|
||||
unsigned int uniqueId; // For real comparing during code generation
|
||||
unsigned int uniqueId; // For cross-scope comparing during code generation
|
||||
};
|
||||
|
||||
//
|
||||
@ -100,7 +111,9 @@ protected:
|
||||
class TVariable : public TSymbol {
|
||||
public:
|
||||
TVariable(const TString *name, const TType& t, bool uT = false ) : TSymbol(name), type(t), userType(uT), unionArray(0), arrayInformationType(0) { }
|
||||
virtual TVariable* clone(TStructureMap& remapper);
|
||||
virtual ~TVariable() { }
|
||||
|
||||
virtual TVariable* getAsVariable() { return this; }
|
||||
TType& getType() { return type; }
|
||||
const TType& getType() const { return type; }
|
||||
@ -125,10 +138,12 @@ public:
|
||||
delete unionArray;
|
||||
unionArray = constArray;
|
||||
}
|
||||
TVariable(const TVariable&, TStructureMap& remapper); // copy constructor
|
||||
virtual TVariable* clone(TStructureMap& remapper);
|
||||
|
||||
protected:
|
||||
explicit TVariable(TVariable&);
|
||||
TVariable(const TVariable&, TStructureMap& remapper);
|
||||
TVariable& operator=(TVariable&);
|
||||
|
||||
TType type;
|
||||
bool userType;
|
||||
// we are assuming that Pool Allocator will free the memory allocated to unionArray
|
||||
@ -159,7 +174,7 @@ struct TParameter {
|
||||
//
|
||||
class TFunction : public TSymbol {
|
||||
public:
|
||||
TFunction(TOperator o) :
|
||||
explicit TFunction(TOperator o) :
|
||||
TSymbol(0),
|
||||
returnType(TType(EbtVoid)),
|
||||
op(o),
|
||||
@ -170,8 +185,9 @@ public:
|
||||
mangledName(*name + '('),
|
||||
op(tOp),
|
||||
defined(false) { }
|
||||
TFunction(const TFunction&, const TStructureMap& remapper);
|
||||
virtual TFunction* clone(TStructureMap& remapper);
|
||||
virtual ~TFunction();
|
||||
|
||||
virtual TFunction* getAsFunction() { return this; }
|
||||
|
||||
void addParameter(TParameter& p)
|
||||
@ -192,9 +208,12 @@ public:
|
||||
const TParameter& operator [](int i) const { return parameters[i]; }
|
||||
|
||||
virtual void dump(TInfoSink &infoSink) const;
|
||||
virtual TFunction* clone(TStructureMap& remapper);
|
||||
|
||||
protected:
|
||||
explicit TFunction(TFunction&);
|
||||
TFunction(const TFunction&, const TStructureMap& remapper);
|
||||
TFunction& operator=(TFunction&);
|
||||
|
||||
typedef TVector<TParameter> TParamList;
|
||||
TParamList parameters;
|
||||
TType returnType;
|
||||
@ -203,11 +222,29 @@ protected:
|
||||
bool defined;
|
||||
};
|
||||
|
||||
class TAnonMember : public TSymbol {
|
||||
public:
|
||||
TAnonMember(const TString* n, unsigned int m, TSymbol& a) : TSymbol(n), anonContainer(a), memberNumber(m) { }
|
||||
virtual TAnonMember* clone(TStructureMap& remapper);
|
||||
virtual ~TAnonMember() { }
|
||||
|
||||
TAnonMember* getAsAnonMember() { return this; }
|
||||
TSymbol& getAnonContainer() const { return anonContainer; }
|
||||
unsigned int getMemberNumber() const { return memberNumber; }
|
||||
virtual void dump(TInfoSink &infoSink) const;
|
||||
|
||||
protected:
|
||||
explicit TAnonMember(TAnonMember&);
|
||||
TAnonMember& operator=(TAnonMember&);
|
||||
|
||||
TSymbol& anonContainer;
|
||||
unsigned int memberNumber;
|
||||
};
|
||||
|
||||
class TSymbolTableLevel {
|
||||
public:
|
||||
POOL_ALLOCATOR_NEW_DELETE(GlobalPoolAllocator)
|
||||
TSymbolTableLevel() : defaultPrecision (0) { }
|
||||
TSymbolTableLevel() : defaultPrecision (0), anonId(0) { }
|
||||
~TSymbolTableLevel();
|
||||
|
||||
bool insert(TSymbol& symbol)
|
||||
@ -216,10 +253,29 @@ public:
|
||||
// returning true means symbol was added to the table
|
||||
//
|
||||
tInsertResult result;
|
||||
if (symbol.getName() == "") {
|
||||
// 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.
|
||||
char buf[20];
|
||||
snprintf(buf, 20, "__anon__%d", anonId++);
|
||||
symbol.changeName(buf);
|
||||
|
||||
bool isOkay = true;
|
||||
TTypeList& types = *symbol.getAsVariable()->getType().getStruct();
|
||||
for (unsigned int m = 0; m < types.size(); ++m) {
|
||||
TAnonMember* member = new TAnonMember(&types[m].type->getFieldName(), m, symbol);
|
||||
result = level.insert(tLevelPair(member->getMangledName(), member));
|
||||
if (! result.second)
|
||||
isOkay = false;
|
||||
}
|
||||
|
||||
return isOkay;
|
||||
} else {
|
||||
result = level.insert(tLevelPair(symbol.getMangledName(), &symbol));
|
||||
|
||||
return result.second;
|
||||
}
|
||||
}
|
||||
|
||||
TSymbol* find(const TString& name) const
|
||||
{
|
||||
@ -262,12 +318,16 @@ public:
|
||||
TSymbolTableLevel* clone(TStructureMap& remapper);
|
||||
|
||||
protected:
|
||||
explicit TSymbolTableLevel(TSymbolTableLevel&);
|
||||
TSymbolTableLevel& operator=(TSymbolTableLevel&);
|
||||
|
||||
typedef std::map<TString, TSymbol*, std::less<TString>, pool_allocator<std::pair<const TString, TSymbol*> > > tLevel;
|
||||
typedef const tLevel::value_type tLevelPair;
|
||||
typedef std::pair<tLevel::iterator, bool> tInsertResult;
|
||||
|
||||
tLevel level;
|
||||
tLevel level; // named mappings
|
||||
TPrecisionQualifier *defaultPrecision;
|
||||
int anonId;
|
||||
};
|
||||
|
||||
class TSymbolTable {
|
||||
@ -280,13 +340,11 @@ public:
|
||||
// that the symbol table has not been preloaded with built-ins.
|
||||
//
|
||||
}
|
||||
|
||||
TSymbolTable(TSymbolTable& symTable)
|
||||
explicit TSymbolTable(TSymbolTable& symTable)
|
||||
{
|
||||
table.push_back(symTable.table[0]);
|
||||
uniqueId = symTable.uniqueId;
|
||||
}
|
||||
|
||||
~TSymbolTable()
|
||||
{
|
||||
// level 0 is always built In symbols, so we never pop that out
|
||||
@ -347,6 +405,8 @@ public:
|
||||
void setPreviousDefaultPrecisions(TPrecisionQualifier *p) { table[currentLevel()]->setPreviousDefaultPrecisions(p); }
|
||||
|
||||
protected:
|
||||
TSymbolTable& operator=(TSymbolTableLevel&);
|
||||
|
||||
int currentLevel() const { return static_cast<int>(table.size()) - 1; }
|
||||
bool atDynamicBuiltInLevel() { return table.size() == 2; }
|
||||
|
||||
|
||||
@ -223,6 +223,20 @@ variable_identifier
|
||||
// if this is a new symbol, it won't find it, which is okay at this
|
||||
// point in the grammar.
|
||||
TSymbol* symbol = $1.symbol;
|
||||
TAnonMember* anon = symbol ? symbol->getAsAnonMember() : 0;
|
||||
if (anon) {
|
||||
// it was a member of an anonymous container, have to insert its dereference
|
||||
TVariable* variable = anon->getAnonContainer().getAsVariable();
|
||||
TIntermTyped* container = parseContext.intermediate.addSymbol(variable->getUniqueId(),
|
||||
variable->getName(),
|
||||
variable->getType(), $1.line);
|
||||
constUnion* unionArray = new constUnion[1];
|
||||
unionArray->setUConst(anon->getMemberNumber());
|
||||
TIntermTyped* constNode = parseContext.intermediate.addConstantUnion(unionArray, TType(EbtUint, EvqConst), $1.line);
|
||||
|
||||
$$ = parseContext.intermediate.addIndex(EOpIndexDirect, container, constNode, $1.line);
|
||||
$$->setType(*(*variable->getType().getStruct())[anon->getMemberNumber()].type);
|
||||
} else {
|
||||
const TVariable* variable = symbol ? symbol->getAsVariable() : 0;
|
||||
if (symbol && ! variable) {
|
||||
parseContext.error($1.line, "variable name expected", $1.string->c_str(), "");
|
||||
@ -244,6 +258,7 @@ variable_identifier
|
||||
variable->getName(),
|
||||
variable->getType(), $1.line);
|
||||
}
|
||||
}
|
||||
;
|
||||
|
||||
primary_expression
|
||||
@ -346,7 +361,7 @@ postfix_expression
|
||||
unionArray->setFConst(0.0f);
|
||||
$$ = parseContext.intermediate.addConstantUnion(unionArray, TType(EbtFloat, EvqConst), $2.line);
|
||||
} else {
|
||||
TType newType = $1->getType();
|
||||
TType newType($1->getType());
|
||||
newType.dereference();
|
||||
$$->setType(newType);
|
||||
// TODO: testing: write a set of dereference tests
|
||||
|
||||
@ -74,7 +74,7 @@ public:
|
||||
TIntermTyped* addMethod(TIntermTyped*, const TType&, const TString*, TSourceLoc);
|
||||
TIntermConstantUnion* addConstantUnion(constUnion*, const TType&, TSourceLoc);
|
||||
TIntermTyped* promoteConstantUnion(TBasicType, TIntermConstantUnion*) ;
|
||||
bool parseConstTree(TSourceLoc, TIntermNode*, constUnion*, TOperator, TType, bool singleConstantParam = false);
|
||||
bool parseConstTree(TSourceLoc, TIntermNode*, constUnion*, TOperator, const TType&, bool singleConstantParam = false);
|
||||
TIntermNode* addLoop(TIntermNode*, TIntermTyped*, TIntermTyped*, bool testFirst, TSourceLoc);
|
||||
TIntermBranch* addBranch(TOperator, TSourceLoc);
|
||||
TIntermBranch* addBranch(TOperator, TIntermTyped*, TSourceLoc);
|
||||
|
||||
@ -40,13 +40,13 @@
|
||||
//
|
||||
class TConstTraverser : public TIntermTraverser {
|
||||
public:
|
||||
TConstTraverser(constUnion* cUnion, bool singleConstParam, TOperator constructType, TInfoSink& sink, TType& t) : unionArray(cUnion), type(t),
|
||||
TConstTraverser(constUnion* cUnion, bool singleConstParam, TOperator constructType, TInfoSink& sink, const TType& t) : unionArray(cUnion), type(t),
|
||||
constructorType(constructType), singleConstantParam(singleConstParam), infoSink(sink), error(false), isMatrix(false),
|
||||
matrixCols(0), matrixRows(0) { index = 0; tOp = EOpNull;}
|
||||
int index ;
|
||||
constUnion *unionArray;
|
||||
TOperator tOp;
|
||||
TType type;
|
||||
const TType& type;
|
||||
TOperator constructorType;
|
||||
bool singleConstantParam;
|
||||
TInfoSink& infoSink;
|
||||
@ -255,7 +255,7 @@ bool ParseBranch(bool /* previsit*/, TIntermBranch* node, TIntermTraverser* it)
|
||||
// Individual functions can be initialized to 0 to skip processing of that
|
||||
// type of node. It's children will still be processed.
|
||||
//
|
||||
bool TIntermediate::parseConstTree(TSourceLoc line, TIntermNode* root, constUnion* unionArray, TOperator constructorType, TType t, bool singleConstantParam)
|
||||
bool TIntermediate::parseConstTree(TSourceLoc line, TIntermNode* root, constUnion* unionArray, TOperator constructorType, const TType& t, bool singleConstantParam)
|
||||
{
|
||||
if (root == 0)
|
||||
return false;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user