summaryrefslogtreecommitdiffstats
path: root/src/3rdparty/angle/src/compiler/translator/InitializeVariables.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/3rdparty/angle/src/compiler/translator/InitializeVariables.cpp')
-rw-r--r--src/3rdparty/angle/src/compiler/translator/InitializeVariables.cpp325
1 files changed, 249 insertions, 76 deletions
diff --git a/src/3rdparty/angle/src/compiler/translator/InitializeVariables.cpp b/src/3rdparty/angle/src/compiler/translator/InitializeVariables.cpp
index 86d3e6bc83..aa1a042fac 100644
--- a/src/3rdparty/angle/src/compiler/translator/InitializeVariables.cpp
+++ b/src/3rdparty/angle/src/compiler/translator/InitializeVariables.cpp
@@ -6,112 +6,285 @@
#include "compiler/translator/InitializeVariables.h"
+#include "angle_gl.h"
#include "common/debug.h"
+#include "compiler/translator/FindMain.h"
+#include "compiler/translator/IntermNode_util.h"
+#include "compiler/translator/IntermTraverse.h"
+#include "compiler/translator/SymbolTable.h"
+#include "compiler/translator/util.h"
+
+namespace sh
+{
namespace
{
-TIntermConstantUnion *constructFloatConstUnionNode(const TType &type)
+void AddArrayZeroInitSequence(const TIntermTyped *initializedNode,
+ bool canUseLoopsToInitialize,
+ TIntermSequence *initSequenceOut,
+ TSymbolTable *symbolTable);
+
+void AddStructZeroInitSequence(const TIntermTyped *initializedNode,
+ bool canUseLoopsToInitialize,
+ TIntermSequence *initSequenceOut,
+ TSymbolTable *symbolTable);
+
+TIntermBinary *CreateZeroInitAssignment(const TIntermTyped *initializedNode)
{
- TType myType = type;
- unsigned char size = static_cast<unsigned char>(myType.getNominalSize());
- if (myType.isMatrix())
- size *= size;
- TConstantUnion *u = new TConstantUnion[size];
- for (int ii = 0; ii < size; ++ii)
- u[ii].setFConst(0.0f);
-
- myType.clearArrayness();
- myType.setQualifier(EvqConst);
- TIntermConstantUnion *node = new TIntermConstantUnion(u, myType);
- return node;
+ TIntermTyped *zero = CreateZeroNode(initializedNode->getType());
+ return new TIntermBinary(EOpAssign, initializedNode->deepCopy(), zero);
}
-TIntermConstantUnion *constructIndexNode(int index)
+void AddZeroInitSequence(const TIntermTyped *initializedNode,
+ bool canUseLoopsToInitialize,
+ TIntermSequence *initSequenceOut,
+ TSymbolTable *symbolTable)
{
- TConstantUnion *u = new TConstantUnion[1];
- u[0].setIConst(index);
+ if (initializedNode->isArray())
+ {
+ AddArrayZeroInitSequence(initializedNode, canUseLoopsToInitialize, initSequenceOut,
+ symbolTable);
+ }
+ else if (initializedNode->getType().isStructureContainingArrays() ||
+ initializedNode->getType().isNamelessStruct())
+ {
+ AddStructZeroInitSequence(initializedNode, canUseLoopsToInitialize, initSequenceOut,
+ symbolTable);
+ }
+ else
+ {
+ initSequenceOut->push_back(CreateZeroInitAssignment(initializedNode));
+ }
+}
- TType type(EbtInt, EbpUndefined, EvqConst, 1);
- TIntermConstantUnion *node = new TIntermConstantUnion(u, type);
- return node;
+void AddStructZeroInitSequence(const TIntermTyped *initializedNode,
+ bool canUseLoopsToInitialize,
+ TIntermSequence *initSequenceOut,
+ TSymbolTable *symbolTable)
+{
+ ASSERT(initializedNode->getBasicType() == EbtStruct);
+ const TStructure *structType = initializedNode->getType().getStruct();
+ for (int i = 0; i < static_cast<int>(structType->fields().size()); ++i)
+ {
+ TIntermBinary *element = new TIntermBinary(EOpIndexDirectStruct,
+ initializedNode->deepCopy(), CreateIndexNode(i));
+ // Structs can't be defined inside structs, so the type of a struct field can't be a
+ // nameless struct.
+ ASSERT(!element->getType().isNamelessStruct());
+ AddZeroInitSequence(element, canUseLoopsToInitialize, initSequenceOut, symbolTable);
+ }
}
-} // namespace anonymous
+void AddArrayZeroInitStatementList(const TIntermTyped *initializedNode,
+ bool canUseLoopsToInitialize,
+ TIntermSequence *initSequenceOut,
+ TSymbolTable *symbolTable)
+{
+ for (unsigned int i = 0; i < initializedNode->getOutermostArraySize(); ++i)
+ {
+ TIntermBinary *element =
+ new TIntermBinary(EOpIndexDirect, initializedNode->deepCopy(), CreateIndexNode(i));
+ AddZeroInitSequence(element, canUseLoopsToInitialize, initSequenceOut, symbolTable);
+ }
+}
-bool InitializeVariables::visitAggregate(Visit visit, TIntermAggregate *node)
+void AddArrayZeroInitForLoop(const TIntermTyped *initializedNode,
+ TIntermSequence *initSequenceOut,
+ TSymbolTable *symbolTable)
{
- bool visitChildren = !mCodeInserted;
- switch (node->getOp())
+ ASSERT(initializedNode->isArray());
+ TSymbolUniqueId indexSymbol(symbolTable);
+
+ TIntermSymbol *indexSymbolNode = CreateTempSymbolNode(indexSymbol, TType(EbtInt), EvqTemporary);
+ TIntermDeclaration *indexInit =
+ CreateTempInitDeclarationNode(indexSymbol, CreateZeroNode(TType(EbtInt)), EvqTemporary);
+ TIntermConstantUnion *arraySizeNode = CreateIndexNode(initializedNode->getOutermostArraySize());
+ TIntermBinary *indexSmallerThanSize =
+ new TIntermBinary(EOpLessThan, indexSymbolNode->deepCopy(), arraySizeNode);
+ TIntermUnary *indexIncrement = new TIntermUnary(EOpPreIncrement, indexSymbolNode->deepCopy());
+
+ TIntermBlock *forLoopBody = new TIntermBlock();
+ TIntermSequence *forLoopBodySeq = forLoopBody->getSequence();
+
+ TIntermBinary *element = new TIntermBinary(EOpIndexIndirect, initializedNode->deepCopy(),
+ indexSymbolNode->deepCopy());
+ AddZeroInitSequence(element, true, forLoopBodySeq, symbolTable);
+
+ TIntermLoop *forLoop =
+ new TIntermLoop(ELoopFor, indexInit, indexSmallerThanSize, indexIncrement, forLoopBody);
+ initSequenceOut->push_back(forLoop);
+}
+
+void AddArrayZeroInitSequence(const TIntermTyped *initializedNode,
+ bool canUseLoopsToInitialize,
+ TIntermSequence *initSequenceOut,
+ TSymbolTable *symbolTable)
+{
+ // The array elements are assigned one by one to keep the AST compatible with ESSL 1.00 which
+ // doesn't have array assignment. We'll do this either with a for loop or just a list of
+ // statements assigning to each array index. Note that it is important to have the array init in
+ // the right order to workaround http://crbug.com/709317
+ bool isSmallArray = initializedNode->getOutermostArraySize() <= 1u ||
+ (initializedNode->getBasicType() != EbtStruct &&
+ !initializedNode->getType().isArrayOfArrays() &&
+ initializedNode->getOutermostArraySize() <= 3u);
+ if (initializedNode->getQualifier() == EvqFragData ||
+ initializedNode->getQualifier() == EvqFragmentOut || isSmallArray ||
+ !canUseLoopsToInitialize)
+ {
+ // Fragment outputs should not be indexed by non-constant indices.
+ // Also it doesn't make sense to use loops to initialize very small arrays.
+ AddArrayZeroInitStatementList(initializedNode, canUseLoopsToInitialize, initSequenceOut,
+ symbolTable);
+ }
+ else
{
- case EOpSequence:
- break;
- case EOpFunction:
- {
- // Function definition.
- ASSERT(visit == PreVisit);
- if (node->getName() == "main(")
+ AddArrayZeroInitForLoop(initializedNode, initSequenceOut, symbolTable);
+ }
+}
+
+void InsertInitCode(TIntermSequence *mainBody,
+ const InitVariableList &variables,
+ TSymbolTable *symbolTable,
+ int shaderVersion,
+ const TExtensionBehavior &extensionBehavior,
+ bool canUseLoopsToInitialize)
+{
+ for (const auto &var : variables)
+ {
+ TString name = TString(var.name.c_str());
+ size_t pos = name.find_last_of('[');
+ if (pos != TString::npos)
{
- TIntermSequence *sequence = node->getSequence();
- ASSERT((sequence->size() == 1) || (sequence->size() == 2));
- TIntermAggregate *body = NULL;
- if (sequence->size() == 1)
- {
- body = new TIntermAggregate(EOpSequence);
- sequence->push_back(body);
- }
- else
+ name = name.substr(0, pos);
+ }
+
+ TIntermTyped *initializedSymbol = nullptr;
+ if (var.isBuiltIn())
+ {
+ initializedSymbol = ReferenceBuiltInVariable(name, *symbolTable, shaderVersion);
+ if (initializedSymbol->getQualifier() == EvqFragData &&
+ !IsExtensionEnabled(extensionBehavior, TExtension::EXT_draw_buffers))
{
- body = (*sequence)[1]->getAsAggregate();
+ // If GL_EXT_draw_buffers is disabled, only the 0th index of gl_FragData can be
+ // written to.
+ // TODO(oetuaho): This is a bit hacky and would be better to remove, if we came up
+ // with a good way to do it. Right now "gl_FragData" in symbol table is initialized
+ // to have the array size of MaxDrawBuffers, and the initialization happens before
+ // the shader sets the extensions it is using.
+ initializedSymbol =
+ new TIntermBinary(EOpIndexDirect, initializedSymbol, CreateIndexNode(0));
}
- ASSERT(body);
- insertInitCode(body->getSequence());
- mCodeInserted = true;
}
- break;
- }
- default:
- visitChildren = false;
- break;
+ else
+ {
+ initializedSymbol = ReferenceGlobalVariable(name, *symbolTable);
+ }
+ ASSERT(initializedSymbol != nullptr);
+
+ TIntermSequence *initCode =
+ CreateInitCode(initializedSymbol, canUseLoopsToInitialize, symbolTable);
+ mainBody->insert(mainBody->begin(), initCode->begin(), initCode->end());
}
- return visitChildren;
}
-void InitializeVariables::insertInitCode(TIntermSequence *sequence)
+class InitializeLocalsTraverser : public TIntermTraverser
{
- for (size_t ii = 0; ii < mVariables.size(); ++ii)
+ public:
+ InitializeLocalsTraverser(int shaderVersion,
+ TSymbolTable *symbolTable,
+ bool canUseLoopsToInitialize)
+ : TIntermTraverser(true, false, false, symbolTable),
+ mShaderVersion(shaderVersion),
+ mCanUseLoopsToInitialize(canUseLoopsToInitialize)
{
- const InitVariableInfo &varInfo = mVariables[ii];
+ }
- if (varInfo.type.isArray())
+ protected:
+ bool visitDeclaration(Visit visit, TIntermDeclaration *node) override
+ {
+ for (TIntermNode *declarator : *node->getSequence())
{
- for (int index = varInfo.type.getArraySize() - 1; index >= 0; --index)
+ if (!mInGlobalScope && !declarator->getAsBinaryNode())
{
- TIntermBinary *assign = new TIntermBinary(EOpAssign);
- sequence->insert(sequence->begin(), assign);
-
- TIntermBinary *indexDirect = new TIntermBinary(EOpIndexDirect);
- TIntermSymbol *symbol = new TIntermSymbol(0, varInfo.name, varInfo.type);
- indexDirect->setLeft(symbol);
- TIntermConstantUnion *indexNode = constructIndexNode(index);
- indexDirect->setRight(indexNode);
-
- assign->setLeft(indexDirect);
+ TIntermSymbol *symbol = declarator->getAsSymbolNode();
+ ASSERT(symbol);
+ if (symbol->getSymbol() == "")
+ {
+ continue;
+ }
- TIntermConstantUnion *zeroConst = constructFloatConstUnionNode(varInfo.type);
- assign->setRight(zeroConst);
+ // Arrays may need to be initialized one element at a time, since ESSL 1.00 does not
+ // support array constructors or assigning arrays.
+ bool arrayConstructorUnavailable =
+ (symbol->isArray() || symbol->getType().isStructureContainingArrays()) &&
+ mShaderVersion == 100;
+ // Nameless struct constructors can't be referred to, so they also need to be
+ // initialized one element at a time.
+ // TODO(oetuaho): Check if it makes sense to initialize using a loop, even if we
+ // could use an initializer. It could at least reduce code size for very large
+ // arrays, but could hurt runtime performance.
+ if (arrayConstructorUnavailable || symbol->getType().isNamelessStruct())
+ {
+ // SimplifyLoopConditions should have been run so the parent node of this node
+ // should not be a loop.
+ ASSERT(getParentNode()->getAsLoopNode() == nullptr);
+ // SeparateDeclarations should have already been run, so we don't need to worry
+ // about further declarators in this declaration depending on the effects of
+ // this declarator.
+ ASSERT(node->getSequence()->size() == 1);
+ insertStatementsInParentBlock(
+ TIntermSequence(),
+ *CreateInitCode(symbol, mCanUseLoopsToInitialize, mSymbolTable));
+ }
+ else
+ {
+ TIntermBinary *init =
+ new TIntermBinary(EOpInitialize, symbol, CreateZeroNode(symbol->getType()));
+ queueReplacementWithParent(node, symbol, init, OriginalNode::BECOMES_CHILD);
+ }
}
}
- else
- {
- TIntermBinary *assign = new TIntermBinary(EOpAssign);
- sequence->insert(sequence->begin(), assign);
- TIntermSymbol *symbol = new TIntermSymbol(0, varInfo.name, varInfo.type);
- assign->setLeft(symbol);
- TIntermConstantUnion *zeroConst = constructFloatConstUnionNode(varInfo.type);
- assign->setRight(zeroConst);
- }
-
+ return false;
}
+
+ private:
+ int mShaderVersion;
+ bool mCanUseLoopsToInitialize;
+};
+
+} // namespace anonymous
+
+TIntermSequence *CreateInitCode(const TIntermTyped *initializedSymbol,
+ bool canUseLoopsToInitialize,
+ TSymbolTable *symbolTable)
+{
+ TIntermSequence *initCode = new TIntermSequence();
+ AddZeroInitSequence(initializedSymbol, canUseLoopsToInitialize, initCode, symbolTable);
+ return initCode;
+}
+
+void InitializeUninitializedLocals(TIntermBlock *root,
+ int shaderVersion,
+ bool canUseLoopsToInitialize,
+ TSymbolTable *symbolTable)
+{
+ InitializeLocalsTraverser traverser(shaderVersion, symbolTable, canUseLoopsToInitialize);
+ root->traverse(&traverser);
+ traverser.updateTree();
+}
+
+void InitializeVariables(TIntermBlock *root,
+ const InitVariableList &vars,
+ TSymbolTable *symbolTable,
+ int shaderVersion,
+ const TExtensionBehavior &extensionBehavior,
+ bool canUseLoopsToInitialize)
+{
+ TIntermBlock *body = FindMainBody(root);
+ InsertInitCode(body->getSequence(), vars, symbolTable, shaderVersion, extensionBehavior,
+ canUseLoopsToInitialize);
}
+} // namespace sh