summaryrefslogtreecommitdiffstats
path: root/gfx/angle/checkout/src/compiler/translator/tree_ops/SeparateDeclarations.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'gfx/angle/checkout/src/compiler/translator/tree_ops/SeparateDeclarations.cpp')
-rw-r--r--gfx/angle/checkout/src/compiler/translator/tree_ops/SeparateDeclarations.cpp199
1 files changed, 199 insertions, 0 deletions
diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/SeparateDeclarations.cpp b/gfx/angle/checkout/src/compiler/translator/tree_ops/SeparateDeclarations.cpp
new file mode 100644
index 0000000000..6d48449154
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/SeparateDeclarations.cpp
@@ -0,0 +1,199 @@
+//
+// Copyright 2002 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// The SeparateDeclarations function processes declarations, so that in the end each declaration
+// contains only one declarator.
+// This is useful as an intermediate step when initialization needs to be separated from
+// declaration, or when things need to be unfolded out of the initializer.
+// Example:
+// int a[1] = int[1](1), b[1] = int[1](2);
+// gets transformed when run through this class into the AST equivalent of:
+// int a[1] = int[1](1);
+// int b[1] = int[1](2);
+
+#include "compiler/translator/tree_ops/SeparateDeclarations.h"
+
+#include "compiler/translator/SymbolTable.h"
+#include "compiler/translator/tree_util/IntermTraverse.h"
+#include "compiler/translator/tree_util/ReplaceVariable.h"
+
+namespace sh
+{
+
+namespace
+{
+
+class SeparateDeclarationsTraverser : private TIntermTraverser
+{
+ public:
+ [[nodiscard]] static bool apply(TCompiler *compiler,
+ TIntermNode *root,
+ TSymbolTable *symbolTable);
+
+ private:
+ SeparateDeclarationsTraverser(TSymbolTable *symbolTable);
+ bool visitDeclaration(Visit, TIntermDeclaration *node) override;
+ void visitSymbol(TIntermSymbol *symbol) override;
+
+ void separateDeclarator(TIntermSequence *sequence,
+ size_t index,
+ TIntermSequence *replacementDeclarations,
+ const TStructure **replacementStructure);
+
+ VariableReplacementMap mVariableMap;
+};
+
+bool SeparateDeclarationsTraverser::apply(TCompiler *compiler,
+ TIntermNode *root,
+ TSymbolTable *symbolTable)
+{
+ SeparateDeclarationsTraverser separateDecl(symbolTable);
+ root->traverse(&separateDecl);
+ return separateDecl.updateTree(compiler, root);
+}
+
+SeparateDeclarationsTraverser::SeparateDeclarationsTraverser(TSymbolTable *symbolTable)
+ : TIntermTraverser(true, false, false, symbolTable)
+{}
+
+bool SeparateDeclarationsTraverser::visitDeclaration(Visit, TIntermDeclaration *node)
+{
+ TIntermSequence *sequence = node->getSequence();
+ if (sequence->size() <= 1)
+ {
+ return true;
+ }
+
+ TIntermBlock *parentBlock = getParentNode()->getAsBlock();
+ ASSERT(parentBlock != nullptr);
+
+ TIntermSequence replacementDeclarations;
+ const TStructure *replacementStructure = nullptr;
+ for (size_t ii = 0; ii < sequence->size(); ++ii)
+ {
+ separateDeclarator(sequence, ii, &replacementDeclarations, &replacementStructure);
+ }
+
+ mMultiReplacements.emplace_back(parentBlock, node, std::move(replacementDeclarations));
+ return false;
+}
+
+void SeparateDeclarationsTraverser::visitSymbol(TIntermSymbol *symbol)
+{
+ const TVariable *variable = &symbol->variable();
+ if (mVariableMap.count(variable) > 0)
+ {
+ queueAccessChainReplacement(mVariableMap[variable]->deepCopy());
+ }
+}
+
+void SeparateDeclarationsTraverser::separateDeclarator(TIntermSequence *sequence,
+ size_t index,
+ TIntermSequence *replacementDeclarations,
+ const TStructure **replacementStructure)
+{
+ TIntermTyped *declarator = sequence->at(index)->getAsTyped();
+ const TType &declaratorType = declarator->getType();
+
+ // If the declaration is not simultaneously declaring a struct, can use the same declarator.
+ // Otherwise, the first declarator is taken as-is if the struct has a name.
+ const TStructure *structure = declaratorType.getStruct();
+ const bool isStructSpecifier = declaratorType.isStructSpecifier();
+ if (!isStructSpecifier || (index == 0 && structure->symbolType() != SymbolType::Empty))
+ {
+ TIntermDeclaration *replacementDeclaration = new TIntermDeclaration;
+
+ // Make sure to update the declarator's initializers if any.
+ declarator->traverse(this);
+
+ replacementDeclaration->appendDeclarator(declarator);
+ replacementDeclaration->setLine(declarator->getLine());
+ replacementDeclarations->push_back(replacementDeclaration);
+ return;
+ }
+
+ // If the struct is nameless, split it out first.
+ if (structure->symbolType() == SymbolType::Empty)
+ {
+ if (*replacementStructure == nullptr)
+ {
+ TStructure *newStructure =
+ new TStructure(mSymbolTable, kEmptyImmutableString, &structure->fields(),
+ SymbolType::AngleInternal);
+ newStructure->setAtGlobalScope(structure->atGlobalScope());
+ *replacementStructure = structure = newStructure;
+
+ TType *namedType = new TType(structure, true);
+ namedType->setQualifier(EvqGlobal);
+
+ TVariable *structVariable =
+ new TVariable(mSymbolTable, kEmptyImmutableString, namedType, SymbolType::Empty);
+
+ TIntermDeclaration *structDeclaration = new TIntermDeclaration;
+ structDeclaration->appendDeclarator(new TIntermSymbol(structVariable));
+ structDeclaration->setLine(declarator->getLine());
+ replacementDeclarations->push_back(structDeclaration);
+ }
+ else
+ {
+ structure = *replacementStructure;
+ }
+ }
+
+ // Redeclare the declarator but not as a struct specifier.
+ TIntermSymbol *asSymbol = declarator->getAsSymbolNode();
+ TIntermTyped *initializer = nullptr;
+ if (asSymbol == nullptr)
+ {
+ TIntermBinary *asBinary = declarator->getAsBinaryNode();
+ ASSERT(asBinary->getOp() == EOpInitialize);
+ asSymbol = asBinary->getLeft()->getAsSymbolNode();
+ initializer = asBinary->getRight();
+
+ // Make sure the initializer itself has its variables replaced if necessary.
+ if (initializer->getAsSymbolNode())
+ {
+ const TVariable *initializerVariable = &initializer->getAsSymbolNode()->variable();
+ if (mVariableMap.count(initializerVariable) > 0)
+ {
+ initializer = mVariableMap[initializerVariable]->deepCopy();
+ }
+ }
+ else
+ {
+ initializer->traverse(this);
+ }
+ }
+
+ ASSERT(asSymbol && asSymbol->variable().symbolType() != SymbolType::Empty);
+
+ TType *newType = new TType(structure, false);
+ newType->setQualifier(asSymbol->getType().getQualifier());
+ newType->makeArrays(asSymbol->getType().getArraySizes());
+
+ TVariable *replacementVar = new TVariable(mSymbolTable, asSymbol->getName(), newType,
+ asSymbol->variable().symbolType());
+ TIntermSymbol *replacementSymbol = new TIntermSymbol(replacementVar);
+ TIntermTyped *replacement = replacementSymbol;
+ if (initializer)
+ {
+ replacement = new TIntermBinary(EOpInitialize, replacement, initializer);
+ }
+
+ TIntermDeclaration *replacementDeclaration = new TIntermDeclaration;
+ replacementDeclaration->appendDeclarator(replacement);
+ replacementDeclaration->setLine(declarator->getLine());
+ replacementDeclarations->push_back(replacementDeclaration);
+
+ mVariableMap[&asSymbol->variable()] = replacementSymbol;
+}
+} // namespace
+
+bool SeparateDeclarations(TCompiler *compiler, TIntermNode *root, TSymbolTable *symbolTable)
+{
+ return SeparateDeclarationsTraverser::apply(compiler, root, symbolTable);
+}
+
+} // namespace sh