diff options
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.cpp | 199 |
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 |