Commit 1dd07a64 by Olli Etuaho Committed by Commit Bot

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: 's avatarCorentin Wallez <cwallez@chromium.org> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org>
parent 231c7f56
...@@ -22,105 +22,88 @@ namespace sh ...@@ -22,105 +22,88 @@ namespace sh
namespace namespace
{ {
class DeferGlobalInitializersTraverser : public TIntermTraverser void GetDeferredInitializers(TIntermDeclaration *declaration,
TIntermSequence *deferredInitializersOut)
{ {
public: // We iterate with an index instead of using an iterator since we're replacing the children of
DeferGlobalInitializersTraverser(); // declaration inside the loop.
for (size_t i = 0; i < declaration->getSequence()->size(); ++i)
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)
{ {
TIntermSymbol *symbolNode = node->getLeft()->getAsSymbolNode(); TIntermNode *declarator = declaration->getSequence()->at(i);
ASSERT(symbolNode); TIntermBinary *init = declarator->getAsBinaryNode();
TIntermTyped *expression = node->getRight(); if (init)
if (mInGlobalScope && (expression->getQualifier() != EvqConst ||
(expression->getAsConstantUnion() == nullptr &&
!expression->isConstructorWithOnlyConstantUnionParameters())))
{ {
// For variables which are not constant, defer their real initialization until TIntermSymbol *symbolNode = init->getLeft()->getAsSymbolNode();
// after we initialize uniforms. ASSERT(symbolNode);
// Deferral is done also in any cases where the variable has not been constant folded, TIntermTyped *expression = init->getRight();
// since otherwise there's a chance that HLSL output will generate extra statements
// from the initializer expression. if ((expression->getQualifier() != EvqConst ||
TIntermBinary *deferredInit = (expression->getAsConstantUnion() == nullptr &&
new TIntermBinary(EOpAssign, symbolNode->deepCopy(), node->getRight()); !expression->isConstructorWithOnlyConstantUnionParameters())))
mDeferredInitializers.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)
{ {
// All of the siblings in the same declaration need to have consistent qualifiers. // For variables which are not constant, defer their real initialization until
auto *siblings = getParentNode()->getAsDeclarationNode()->getSequence(); // after we initialize uniforms.
for (TIntermNode *siblingNode : *siblings) // 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(); // All of the siblings in the same declaration need to have consistent
if (siblingBinary) // qualifiers.
auto *siblings = declaration->getSequence();
for (TIntermNode *siblingNode : *siblings)
{ {
ASSERT(siblingBinary->getOp() == EOpInitialize); TIntermBinary *siblingBinary = siblingNode->getAsBinaryNode();
siblingBinary->getLeft()->getTypePointer()->setQualifier(EvqGlobal); 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. // Remove the initializer from the global scope and just declare the global instead.
ASSERT(symbolNode->getQualifier() == EvqGlobal); 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; TSymbolUniqueId initFunctionId;
const char *functionName = "initializeGlobals";
const char *functionName = "initializeDeferredGlobals";
// Add function prototype to the beginning of the shader // Add function prototype to the beginning of the shader
TIntermFunctionPrototype *functionPrototypeNode = TIntermFunctionPrototype *functionPrototypeNode =
CreateInternalFunctionPrototypeNode(TType(EbtVoid), functionName, initFunctionId); TIntermTraverser::CreateInternalFunctionPrototypeNode(TType(EbtVoid), functionName,
initFunctionId);
root->getSequence()->insert(root->getSequence()->begin(), functionPrototypeNode); root->getSequence()->insert(root->getSequence()->begin(), functionPrototypeNode);
// Add function definition to the end of the shader // Add function definition to the end of the shader
TIntermBlock *functionBodyNode = new TIntermBlock(); TIntermBlock *functionBodyNode = new TIntermBlock();
TIntermSequence *functionBody = functionBodyNode->getSequence(); functionBodyNode->getSequence()->swap(*deferredInitializers);
for (const auto &deferredInit : mDeferredInitializers) TIntermFunctionDefinition *functionDefinition =
{ TIntermTraverser::CreateInternalFunctionDefinitionNode(TType(EbtVoid), functionName,
functionBody->push_back(deferredInit); functionBodyNode, initFunctionId);
}
TIntermFunctionDefinition *functionDefinition = CreateInternalFunctionDefinitionNode(
TType(EbtVoid), functionName, functionBodyNode, initFunctionId);
root->getSequence()->push_back(functionDefinition); root->getSequence()->push_back(functionDefinition);
// Insert call into main function // Insert call into main function
TIntermFunctionDefinition *main = FindMain(root); TIntermFunctionDefinition *main = FindMain(root);
ASSERT(main != nullptr); ASSERT(main != nullptr);
TIntermAggregate *functionCallNode = TIntermAggregate *functionCallNode = TIntermTraverser::CreateInternalFunctionCallNode(
CreateInternalFunctionCallNode(TType(EbtVoid), functionName, initFunctionId, nullptr); TType(EbtVoid), functionName, initFunctionId, nullptr);
TIntermBlock *mainBody = main->getBody(); TIntermBlock *mainBody = main->getBody();
ASSERT(mainBody != nullptr); ASSERT(mainBody != nullptr);
...@@ -131,14 +114,24 @@ void DeferGlobalInitializersTraverser::insertInitFunction(TIntermBlock *root) ...@@ -131,14 +114,24 @@ void DeferGlobalInitializersTraverser::insertInitFunction(TIntermBlock *root)
void DeferGlobalInitializers(TIntermBlock *root) void DeferGlobalInitializers(TIntermBlock *root)
{ {
DeferGlobalInitializersTraverser traverser; TIntermSequence *deferredInitializers = new TIntermSequence();
root->traverse(&traverser);
// Replace the initializers of the global variables. // Loop over all global statements and process the declarations. This is simpler than using a
traverser.updateTree(); // 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. // Add the function with initialization and the call to that.
traverser.insertInitFunction(root); if (!deferredInitializers->empty())
{
InsertInitFunction(root, deferredInitializers);
}
} }
} // namespace sh } // namespace sh
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment