Whole stack: Fix stale types in the AST linker object nodes, fixing #557.

Rationalizes the entire tracking of the linker object nodes, effecting
GLSL, HLSL, and SPIR-V, to allow tracked objects to be fully edited before
their type snapshot for linker objects.

Should only effect things when the rest of the AST contained no reference to
the symbol, because normal AST nodes were not stale. Also will only effect such
objects when their types were edited.
This commit is contained in:
John Kessenich 2016-11-05 10:15:53 -06:00
parent e5e58cfee3
commit d3f1122a44
107 changed files with 630 additions and 560 deletions

View file

@ -221,16 +221,37 @@ void TParseContextBase::rValueErrorCheck(const TSourceLoc& loc, const char* op,
error(loc, "can't read from writeonly object: ", op, symNode->getName().c_str());
}
// Add a linkage symbol node for 'symbol', which
// must have its type fully edited, as this will snapshot the type.
// It is okay if symbol becomes invalid before finish().
void TParseContextBase::trackLinkage(TSymbol& symbol)
{
if (!parsingBuiltins)
intermediate.addSymbolLinkageNode(linkage, symbol);
}
// Add 'symbol' to the list of deferred linkage symbols, which
// are later processed in finish(), at which point the symbol
// must still be valid.
// It is okay if the symbol's type will be subsequently edited.
void TParseContextBase::trackLinkageDeferred(TSymbol& symbol)
{
if (!parsingBuiltins)
linkageSymbols.push_back(&symbol);
}
// 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.
// effect all nodes already sharing it (non-shallow type),
// or adopting its full type after being edited (shallow type).
void TParseContextBase::makeEditable(TSymbol*& symbol)
{
// copyUp() does a deep copy of the type.
symbol = symbolTable.copyUp(symbol);
// Save it in the AST for linker use.
intermediate.addSymbolLinkageNode(linkage, *symbol);
// Save it (deferred, so it can be edited first) in the AST for linker use.
if (symbol)
trackLinkageDeferred(*symbol);
}
// Return a writable version of the variable 'name'.
@ -242,7 +263,7 @@ TVariable* TParseContextBase::getEditableVariable(const char* name)
{
bool builtIn;
TSymbol* symbol = symbolTable.find(name, &builtIn);
assert(symbol != nullptr);
if (symbol == nullptr)
return nullptr;
@ -434,7 +455,7 @@ bool TParseContextBase::insertGlobalUniformBlock()
// This is the first request; we need a normal symbol table insert
inserted = symbolTable.insert(*globalUniformBlock);
if (inserted)
intermediate.addSymbolLinkageNode(linkage, *globalUniformBlock);
trackLinkageDeferred(*globalUniformBlock);
} else if (firstNewMember <= numMembers) {
// This is a follow-on request; we need to amend the first insert
inserted = symbolTable.amend(*globalUniformBlock, firstNewMember);
@ -448,4 +469,14 @@ bool TParseContextBase::insertGlobalUniformBlock()
return inserted;
}
void TParseContextBase::finish()
{
if (!parsingBuiltins) {
// Transfer te linkage symbols to AST nodes
for (auto i = linkageSymbols.begin(); i != linkageSymbols.end(); ++i)
intermediate.addSymbolLinkageNode(linkage, **i);
intermediate.addSymbolLinkageNodes(linkage, getLanguage(), symbolTable);
}
}
} // end namespace glslang

View file

@ -50,15 +50,12 @@ namespace glslang {
TParseContext::TParseContext(TSymbolTable& symbolTable, TIntermediate& interm, bool parsingBuiltins,
int version, EProfile profile, const SpvVersion& spvVersion, EShLanguage language,
TInfoSink& infoSink, bool forwardCompatible, EShMessages messages) :
TParseContextBase(symbolTable, interm, version, profile, spvVersion, language, infoSink, forwardCompatible, messages),
TParseContextBase(symbolTable, interm, parsingBuiltins, version, profile, spvVersion, language, infoSink, forwardCompatible, messages),
contextPragma(true, false), loopNestingLevel(0), structNestingLevel(0), controlFlowNestingLevel(0), statementNestingLevel(0),
inMain(false), postMainReturn(false), currentFunctionType(nullptr), blockName(nullptr),
limits(resources.limits), parsingBuiltins(parsingBuiltins),
limits(resources.limits),
atomicUintOffsets(nullptr), anyIndexLimits(false)
{
// ensure we always have a linkage node, even if empty, to simplify tree topology algorithms
linkage = new TIntermAggregate;
// decide whether precision qualifiers should be ignored or respected
if (profile == EEsProfile || spvVersion.vulkan > 0) {
precisionManager.respectPrecisionQualifiers();
@ -184,8 +181,8 @@ bool TParseContext::parseShaderStrings(TPpContext& ppContext, TInputScanner& inp
currentScanner = &input;
ppContext.setInput(input, versionWillBeError);
yyparse(this);
if (! parsingBuiltins)
finalErrorCheck();
finish();
return numErrors == 0;
}
@ -3093,7 +3090,7 @@ void TParseContext::arrayDimMerge(TType& type, const TArraySizes* sizes)
// 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.
//
void TParseContext::declareArray(const TSourceLoc& loc, TString& identifier, const TType& type, TSymbol*& symbol, bool& newDeclaration)
void TParseContext::declareArray(const TSourceLoc& loc, TString& identifier, const TType& type, TSymbol*& symbol)
{
if (symbol == nullptr) {
bool currentScope;
@ -3111,7 +3108,8 @@ void TParseContext::declareArray(const TSourceLoc& loc, TString& identifier, con
//
symbol = new TVariable(&identifier, type);
symbolTable.insert(*symbol);
newDeclaration = true;
if (symbolTable.atGlobalLevel())
trackLinkageDeferred(*symbol);
if (! symbolTable.atBuiltInLevel()) {
if (isIoResizeArray(type)) {
@ -3271,7 +3269,8 @@ void TParseContext::nonInitConstCheck(const TSourceLoc& loc, TString& identifier
//
// Returns a redeclared and type-modified variable if a redeclarated occurred.
//
TSymbol* TParseContext::redeclareBuiltinVariable(const TSourceLoc& loc, const TString& identifier, const TQualifier& qualifier, const TShaderQualifiers& publicType, bool& newDeclaration)
TSymbol* TParseContext::redeclareBuiltinVariable(const TSourceLoc& loc, const TString& identifier,
const TQualifier& qualifier, const TShaderQualifiers& publicType)
{
if (! builtInName(identifier) || symbolTable.atBuiltInLevel() || ! symbolTable.atGlobalLevel())
return nullptr;
@ -3318,11 +3317,8 @@ TSymbol* TParseContext::redeclareBuiltinVariable(const TSourceLoc& loc, const TS
// 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
// redeclaration. Otherwise, make the new one.
if (builtIn) {
// Copy the symbol up to make a writable version
if (builtIn)
makeEditable(symbol);
newDeclaration = true;
}
// Now, modify the type of the copy, as per the type of the current redeclaration.
@ -3540,7 +3536,7 @@ void TParseContext::redeclareBuiltinBlock(const TSourceLoc& loc, TTypeList& newT
fixIoArraySize(loc, block->getWritableType());
// Save it in the AST for linker use.
intermediate.addSymbolLinkageNode(linkage, *block);
trackLinkageDeferred(*block);
}
void TParseContext::paramCheckFix(const TSourceLoc& loc, const TStorageQualifier& qualifier, TType& type)
@ -3794,8 +3790,13 @@ void TParseContext::limitCheck(const TSourceLoc& loc, int value, const char* lim
//
// Do any additional error checking, etc., once we know the parsing is done.
//
void TParseContext::finalErrorCheck()
void TParseContext::finish()
{
TParseContextBase::finish();
if (parsingBuiltins)
return;
// Check on array indexes for ES 2.0 (version 100) limitations.
for (size_t i = 0; i < needsIndexLimitationChecking.size(); ++i)
constantIndexExpressionCheck(needsIndexLimitationChecking[i]);
@ -4971,8 +4972,7 @@ TIntermNode* TParseContext::declareVariable(const TSourceLoc& loc, TString& iden
error(loc, "can only apply depth layout to gl_FragDepth", "layout qualifier", "");
// 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
TSymbol* symbol = redeclareBuiltinVariable(loc, identifier, type.getQualifier(), publicType.shaderQualifiers, newDeclaration);
TSymbol* symbol = redeclareBuiltinVariable(loc, identifier, type.getQualifier(), publicType.shaderQualifiers);
if (symbol == nullptr)
reservedErrorCheck(loc, identifier);
@ -4990,7 +4990,7 @@ TIntermNode* TParseContext::declareVariable(const TSourceLoc& loc, TString& iden
arrayUnsizedCheck(loc, type.getQualifier(), &type.getArraySizes(), initializer != nullptr, false);
if (! arrayQualifierError(loc, type.getQualifier()) && ! arrayError(loc, type))
declareArray(loc, identifier, type, symbol, newDeclaration);
declareArray(loc, identifier, type, symbol);
if (initializer) {
profileRequires(loc, ENoProfile, 120, E_GL_3DL_array_objects, "initializer");
@ -4999,7 +4999,7 @@ TIntermNode* TParseContext::declareVariable(const TSourceLoc& loc, TString& iden
} else {
// non-array case
if (symbol == nullptr)
symbol = declareNonArray(loc, identifier, type, newDeclaration);
symbol = declareNonArray(loc, identifier, type);
else if (type != symbol->getType())
error(loc, "cannot change the type of", "redeclaration", symbol->getName().c_str());
}
@ -5022,10 +5022,6 @@ TIntermNode* TParseContext::declareVariable(const TSourceLoc& loc, TString& iden
layoutObjectCheck(loc, *symbol);
fixOffset(loc, *symbol);
// see if it's a linker-level object to track
if (newDeclaration && symbolTable.atGlobalLevel())
intermediate.addSymbolLinkageNode(linkage, *symbol);
return initNode;
}
@ -5061,20 +5057,22 @@ TVariable* TParseContext::makeInternalVariable(const char* name, const TType& ty
//
// Return the successfully declared variable.
//
TVariable* TParseContext::declareNonArray(const TSourceLoc& loc, TString& identifier, TType& type, bool& newDeclaration)
TVariable* TParseContext::declareNonArray(const TSourceLoc& loc, TString& identifier, TType& type)
{
// make a new variable
TVariable* variable = new TVariable(&identifier, type);
ioArrayCheck(loc, type, identifier);
// add variable to symbol table
if (! symbolTable.insert(*variable)) {
error(loc, "redefinition", variable->getName().c_str(), "");
return nullptr;
} else {
newDeclaration = true;
if (symbolTable.insert(*variable)) {
if (symbolTable.atGlobalLevel())
trackLinkageDeferred(*variable);
return variable;
}
error(loc, "redefinition", variable->getName().c_str(), "");
return nullptr;
}
//
@ -5731,7 +5729,7 @@ void TParseContext::declareBlock(const TSourceLoc& loc, TTypeList& typeList, con
fixIoArraySize(loc, variable.getWritableType());
// Save it in the AST for linker use.
intermediate.addSymbolLinkageNode(linkage, variable);
trackLinkageDeferred(variable);
}
// Do all block-declaration checking regarding the combination of in/out/uniform/buffer

View file

@ -73,13 +73,16 @@ typedef std::set<int> TIdSetType;
//
class TParseContextBase : public TParseVersions {
public:
TParseContextBase(TSymbolTable& symbolTable, TIntermediate& interm, int version,
TParseContextBase(TSymbolTable& symbolTable, TIntermediate& interm, bool parsingBuiltins, int version,
EProfile profile, const SpvVersion& spvVersion, EShLanguage language,
TInfoSink& infoSink, bool forwardCompatible, EShMessages messages)
: TParseVersions(interm, version, profile, spvVersion, language, infoSink, forwardCompatible, messages),
symbolTable(symbolTable),
linkage(nullptr), scanContext(nullptr), ppContext(nullptr),
globalUniformBlock(nullptr) { }
parsingBuiltins(parsingBuiltins), scanContext(nullptr), ppContext(nullptr),
globalUniformBlock(nullptr)
{
linkage = new TIntermAggregate;
}
virtual ~TParseContextBase() { }
virtual void C_DECL error(const TSourceLoc&, const char* szReason, const char* szToken,
@ -94,7 +97,6 @@ public:
virtual void setLimits(const TBuiltInResource&) = 0;
EShLanguage getLanguage() const { return language; }
TIntermAggregate*& getLinkage() { return linkage; }
void setScanContext(TScanContext* c) { scanContext = c; }
TScanContext* getScanContext() const { return scanContext; }
void setPpContext(TPpContext* c) { ppContext = c; }
@ -150,7 +152,8 @@ protected:
TParseContextBase(TParseContextBase&);
TParseContextBase& operator=(TParseContextBase&);
TIntermAggregate* linkage; // aggregate node of objects the linker may need, if not referenced by the rest of the AST
const bool parsingBuiltins; // true if parsing built-in symbols/functions
TVector<TSymbol*> linkageSymbols; // these need to be transferred to 'linkage', after all editing is done
TScanContext* scanContext;
TPpContext* ppContext;
@ -177,8 +180,14 @@ protected:
virtual void outputMessage(const TSourceLoc&, const char* szReason, const char* szToken,
const char* szExtraInfoFormat, TPrefixType prefix,
va_list args);
virtual void trackLinkage(TSymbol& symbol);
virtual void trackLinkageDeferred(TSymbol& symbol);
virtual void makeEditable(TSymbol*&);
virtual TVariable* getEditableVariable(const char* name);
virtual void finish();
private:
TIntermAggregate* linkage;
};
//
@ -314,7 +323,7 @@ public:
void precisionQualifierCheck(const TSourceLoc&, TBasicType, TQualifier&);
void parameterTypeCheck(const TSourceLoc&, TStorageQualifier qualifier, const TType& type);
bool containsFieldWithBasicType(const TType& type ,TBasicType basicType);
TSymbol* redeclareBuiltinVariable(const TSourceLoc&, const TString&, const TQualifier&, const TShaderQualifiers&, bool& newDeclaration);
TSymbol* redeclareBuiltinVariable(const TSourceLoc&, const TString&, const TQualifier&, const TShaderQualifiers&);
void redeclareBuiltinBlock(const TSourceLoc&, TTypeList& typeList, const TString& blockName, const TString* instanceName, TArraySizes* arraySizes);
void paramCheckFix(const TSourceLoc&, const TStorageQualifier&, TType& type);
void paramCheckFix(const TSourceLoc&, const TQualifier&, TType& type);
@ -368,11 +377,11 @@ protected:
void nonInitConstCheck(const TSourceLoc&, TString& identifier, TType& type);
void inheritGlobalDefaults(TQualifier& dst) const;
TVariable* makeInternalVariable(const char* name, const TType&) const;
TVariable* declareNonArray(const TSourceLoc&, TString& identifier, TType&, bool& newDeclaration);
void declareArray(const TSourceLoc&, TString& identifier, const TType&, TSymbol*&, bool& newDeclaration);
TVariable* declareNonArray(const TSourceLoc&, TString& identifier, TType&);
void declareArray(const TSourceLoc&, TString& identifier, const TType&, TSymbol*&);
TIntermNode* executeInitializer(const TSourceLoc&, TIntermTyped* initializer, TVariable* variable);
TIntermTyped* convertInitializerList(const TSourceLoc&, const TType&, TIntermTyped* initializer);
void finalErrorCheck();
void finish() override;
public:
//
@ -401,7 +410,6 @@ protected:
TParseContext(TParseContext&);
TParseContext& operator=(TParseContext&);
const bool parsingBuiltins; // true if parsing built-in symbols/functions
static const int maxSamplerIndex = EsdNumDims * (EbtNumTypes * (2 * 2 * 2 * 2 * 2)); // see computeSamplerTypeIndex()
TPrecisionQualifier defaultSamplerPrecision[maxSamplerIndex];
TPrecisionManager precisionManager;

View file

@ -947,7 +947,6 @@ struct DoFullParse{
// Parse the full shader.
if (! parseContext.parseShaderStrings(ppContext, fullInput, versionWillBeError))
success = false;
intermediate.addSymbolLinkageNodes(parseContext.getLinkage(), parseContext.getLanguage(), symbolTable);
if (success && intermediate.getTreeRoot()) {
if (optLevel == EShOptNoGeneration)

View file

@ -260,7 +260,6 @@ public:
// Linkage related
void addSymbolLinkageNodes(TIntermAggregate*& linkage, EShLanguage, TSymbolTable&);
void addSymbolLinkageNode(TIntermAggregate*& linkage, TSymbolTable&, const TString&);
void addSymbolLinkageNode(TIntermAggregate*& linkage, const TSymbol&);
bool setInvocations(int i)
@ -396,6 +395,7 @@ protected:
bool promote(TIntermOperator*);
bool promoteUnary(TIntermUnary&);
bool promoteBinary(TIntermBinary&);
void addSymbolLinkageNode(TIntermAggregate*& linkage, TSymbolTable&, const TString&);
const EShLanguage language; // stage, known at construction time
EShSource source; // source language, known a bit later