Simplify DeferGlobalInitializers
It doesn't need to use a traverser, it's simpler to just iterate over
all statements in the global scope.
BUG=angleproject:1966
TEST=angle_unittests, WebGL conformance tests
Change-Id: I11200f72842db86be2bcdd11934262da183cc3b4
Reviewed-on: https://chromium-review.googlesource.com/504727
Commit-Queue: Olli Etuaho <oetuaho@nvidia.com>
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Reviewed-by: Jamie Madill <jmadill@chromium.org>
diff --git a/src/compiler/translator/DeferGlobalInitializers.cpp b/src/compiler/translator/DeferGlobalInitializers.cpp
index c1585a5..cdc8a37 100644
--- a/src/compiler/translator/DeferGlobalInitializers.cpp
+++ b/src/compiler/translator/DeferGlobalInitializers.cpp
@@ -22,105 +22,88 @@
namespace
{
-class DeferGlobalInitializersTraverser : public TIntermTraverser
+void GetDeferredInitializers(TIntermDeclaration *declaration,
+ TIntermSequence *deferredInitializersOut)
{
- public:
- DeferGlobalInitializersTraverser();
-
- bool visitBinary(Visit visit, TIntermBinary *node) override;
-
- void insertInitFunction(TIntermBlock *root);
-
- private:
- TIntermSequence mDeferredInitializers;
-};
-
-DeferGlobalInitializersTraverser::DeferGlobalInitializersTraverser()
- : TIntermTraverser(true, false, false)
-{
-}
-
-bool DeferGlobalInitializersTraverser::visitBinary(Visit visit, TIntermBinary *node)
-{
- if (node->getOp() == EOpInitialize)
+ // We iterate with an index instead of using an iterator since we're replacing the children of
+ // declaration inside the loop.
+ for (size_t i = 0; i < declaration->getSequence()->size(); ++i)
{
- TIntermSymbol *symbolNode = node->getLeft()->getAsSymbolNode();
- ASSERT(symbolNode);
- TIntermTyped *expression = node->getRight();
-
- if (mInGlobalScope && (expression->getQualifier() != EvqConst ||
- (expression->getAsConstantUnion() == nullptr &&
- !expression->isConstructorWithOnlyConstantUnionParameters())))
+ TIntermNode *declarator = declaration->getSequence()->at(i);
+ TIntermBinary *init = declarator->getAsBinaryNode();
+ if (init)
{
- // For variables which are not constant, defer their real initialization until
- // after we initialize uniforms.
- // Deferral is done also in any cases where the variable has not been constant folded,
- // since otherwise there's a chance that HLSL output will generate extra statements
- // from the initializer expression.
- TIntermBinary *deferredInit =
- new TIntermBinary(EOpAssign, symbolNode->deepCopy(), node->getRight());
- mDeferredInitializers.push_back(deferredInit);
+ TIntermSymbol *symbolNode = init->getLeft()->getAsSymbolNode();
+ ASSERT(symbolNode);
+ TIntermTyped *expression = init->getRight();
- // Change const global to a regular global if its initialization is deferred.
- // This can happen if ANGLE has not been able to fold the constant expression used
- // as an initializer.
- ASSERT(symbolNode->getQualifier() == EvqConst ||
- symbolNode->getQualifier() == EvqGlobal);
- if (symbolNode->getQualifier() == EvqConst)
+ if ((expression->getQualifier() != EvqConst ||
+ (expression->getAsConstantUnion() == nullptr &&
+ !expression->isConstructorWithOnlyConstantUnionParameters())))
{
- // All of the siblings in the same declaration need to have consistent qualifiers.
- auto *siblings = getParentNode()->getAsDeclarationNode()->getSequence();
- for (TIntermNode *siblingNode : *siblings)
+ // For variables which are not constant, defer their real initialization until
+ // after we initialize uniforms.
+ // Deferral is done also in any cases where the variable has not been constant
+ // folded, since otherwise there's a chance that HLSL output will generate extra
+ // statements from the initializer expression.
+ TIntermBinary *deferredInit =
+ new TIntermBinary(EOpAssign, symbolNode->deepCopy(), init->getRight());
+ deferredInitializersOut->push_back(deferredInit);
+
+ // Change const global to a regular global if its initialization is deferred.
+ // This can happen if ANGLE has not been able to fold the constant expression used
+ // as an initializer.
+ ASSERT(symbolNode->getQualifier() == EvqConst ||
+ symbolNode->getQualifier() == EvqGlobal);
+ if (symbolNode->getQualifier() == EvqConst)
{
- TIntermBinary *siblingBinary = siblingNode->getAsBinaryNode();
- if (siblingBinary)
+ // All of the siblings in the same declaration need to have consistent
+ // qualifiers.
+ auto *siblings = declaration->getSequence();
+ for (TIntermNode *siblingNode : *siblings)
{
- ASSERT(siblingBinary->getOp() == EOpInitialize);
- siblingBinary->getLeft()->getTypePointer()->setQualifier(EvqGlobal);
+ TIntermBinary *siblingBinary = siblingNode->getAsBinaryNode();
+ if (siblingBinary)
+ {
+ ASSERT(siblingBinary->getOp() == EOpInitialize);
+ siblingBinary->getLeft()->getTypePointer()->setQualifier(EvqGlobal);
+ }
+ siblingNode->getAsTyped()->getTypePointer()->setQualifier(EvqGlobal);
}
- siblingNode->getAsTyped()->getTypePointer()->setQualifier(EvqGlobal);
+ // This node is one of the siblings.
+ ASSERT(symbolNode->getQualifier() == EvqGlobal);
}
- // This node is one of the siblings.
- ASSERT(symbolNode->getQualifier() == EvqGlobal);
+ // Remove the initializer from the global scope and just declare the global instead.
+ declaration->replaceChildNode(init, symbolNode);
}
- // Remove the initializer from the global scope and just declare the global instead.
- queueReplacement(node, symbolNode, OriginalNode::IS_DROPPED);
}
}
- return false;
}
-void DeferGlobalInitializersTraverser::insertInitFunction(TIntermBlock *root)
+void InsertInitFunction(TIntermBlock *root, TIntermSequence *deferredInitializers)
{
- if (mDeferredInitializers.empty())
- {
- return;
- }
TSymbolUniqueId initFunctionId;
-
- const char *functionName = "initializeDeferredGlobals";
+ const char *functionName = "initializeGlobals";
// Add function prototype to the beginning of the shader
TIntermFunctionPrototype *functionPrototypeNode =
- CreateInternalFunctionPrototypeNode(TType(EbtVoid), functionName, initFunctionId);
+ TIntermTraverser::CreateInternalFunctionPrototypeNode(TType(EbtVoid), functionName,
+ initFunctionId);
root->getSequence()->insert(root->getSequence()->begin(), functionPrototypeNode);
// Add function definition to the end of the shader
TIntermBlock *functionBodyNode = new TIntermBlock();
- TIntermSequence *functionBody = functionBodyNode->getSequence();
- for (const auto &deferredInit : mDeferredInitializers)
- {
- functionBody->push_back(deferredInit);
- }
- TIntermFunctionDefinition *functionDefinition = CreateInternalFunctionDefinitionNode(
- TType(EbtVoid), functionName, functionBodyNode, initFunctionId);
+ functionBodyNode->getSequence()->swap(*deferredInitializers);
+ TIntermFunctionDefinition *functionDefinition =
+ TIntermTraverser::CreateInternalFunctionDefinitionNode(TType(EbtVoid), functionName,
+ functionBodyNode, initFunctionId);
root->getSequence()->push_back(functionDefinition);
// Insert call into main function
TIntermFunctionDefinition *main = FindMain(root);
ASSERT(main != nullptr);
- TIntermAggregate *functionCallNode =
- CreateInternalFunctionCallNode(TType(EbtVoid), functionName, initFunctionId, nullptr);
+ TIntermAggregate *functionCallNode = TIntermTraverser::CreateInternalFunctionCallNode(
+ TType(EbtVoid), functionName, initFunctionId, nullptr);
TIntermBlock *mainBody = main->getBody();
ASSERT(mainBody != nullptr);
@@ -131,14 +114,24 @@
void DeferGlobalInitializers(TIntermBlock *root)
{
- DeferGlobalInitializersTraverser traverser;
- root->traverse(&traverser);
+ TIntermSequence *deferredInitializers = new TIntermSequence();
- // Replace the initializers of the global variables.
- traverser.updateTree();
+ // Loop over all global statements and process the declarations. This is simpler than using a
+ // traverser.
+ for (TIntermNode *declaration : *root->getSequence())
+ {
+ TIntermDeclaration *asVariableDeclaration = declaration->getAsDeclarationNode();
+ if (asVariableDeclaration)
+ {
+ GetDeferredInitializers(asVariableDeclaration, deferredInitializers);
+ }
+ }
// Add the function with initialization and the call to that.
- traverser.insertInitFunction(root);
+ if (!deferredInitializers->empty())
+ {
+ InsertInitFunction(root, deferredInitializers);
+ }
}
} // namespace sh