diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 00:47:55 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 00:47:55 +0000 |
commit | 26a029d407be480d791972afb5975cf62c9360a6 (patch) | |
tree | f435a8308119effd964b339f76abb83a57c29483 /gfx/angle/checkout/src/compiler/translator/tree_util/ReplaceShadowingVariables.cpp | |
parent | Initial commit. (diff) | |
download | firefox-26a029d407be480d791972afb5975cf62c9360a6.tar.xz firefox-26a029d407be480d791972afb5975cf62c9360a6.zip |
Adding upstream version 124.0.1.upstream/124.0.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'gfx/angle/checkout/src/compiler/translator/tree_util/ReplaceShadowingVariables.cpp')
-rw-r--r-- | gfx/angle/checkout/src/compiler/translator/tree_util/ReplaceShadowingVariables.cpp | 142 |
1 files changed, 142 insertions, 0 deletions
diff --git a/gfx/angle/checkout/src/compiler/translator/tree_util/ReplaceShadowingVariables.cpp b/gfx/angle/checkout/src/compiler/translator/tree_util/ReplaceShadowingVariables.cpp new file mode 100644 index 0000000000..47842eaade --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/tree_util/ReplaceShadowingVariables.cpp @@ -0,0 +1,142 @@ +// +// Copyright 2019 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. +// +// ReplaceShadowingVariables.cpp: Replace all references to any variable in the AST that is +// a redefinition of a variable in a nested scope. This is a useful for ESSL 1.00 shaders +// where the spec section "4.2.3. Redeclaring Variables" states "However, a nested scope can +// override an outer scope's declaration of a particular variable name." This is changed in +// later spec versions, such as ESSL 3.20 spec which states "If [a variable] is declared as +// a parameter in a function definition, it is scoped until the end of that function +// definition. A function's parameter declarations and body together form a single scope." +// +// So this class is useful when translating from ESSL 1.00 shaders, where function body var +// redefinition is allowed, to later shader versions where it's not allowed. +// + +#include "compiler/translator/tree_util/ReplaceShadowingVariables.h" +#include "compiler/translator/tree_util/ReplaceVariable.h" + +#include "compiler/translator/Compiler.h" +#include "compiler/translator/IntermNode.h" +#include "compiler/translator/Symbol.h" +#include "compiler/translator/SymbolTable.h" +#include "compiler/translator/tree_util/IntermNode_util.h" +#include "compiler/translator/tree_util/IntermTraverse.h" + +#include <unordered_set> + +namespace sh +{ + +namespace +{ + +// Custom struct to queue up any replacements until after AST traversal +struct DeferredReplacementBlock +{ + const TVariable *originalVariable; // variable to be replaced + TVariable *replacementVariable; // variable to replace originalVar with + TIntermBlock *functionBody; // function body where replacement occurs +}; + +class ReplaceShadowingVariablesTraverser : public TIntermTraverser +{ + public: + ReplaceShadowingVariablesTraverser(TSymbolTable *symbolTable) + : TIntermTraverser(true, true, true, symbolTable), mParameterNames{}, mFunctionBody(nullptr) + {} + + bool visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node) override + { + // In pre-visit of function, record params + if (visit == PreVisit) + { + ASSERT(mParameterNames.size() == 0); + const TFunction *func = node->getFunctionPrototype()->getFunction(); + // Grab all of the parameter names from the function prototype + size_t paramCount = func->getParamCount(); + for (size_t i = 0; i < paramCount; ++i) + { + mParameterNames.emplace(std::string(func->getParam(i)->name().data())); + } + if (mParameterNames.size() > 0) + mFunctionBody = node->getBody(); + } + else if (visit == PostVisit) + { + // Clear data saved from function definition + mParameterNames.clear(); + mFunctionBody = nullptr; + } + return true; + } + bool visitDeclaration(Visit visit, TIntermDeclaration *node) override + { + if (visit == PreVisit && mParameterNames.size() != 0) + { + TIntermSequence *decls = node->getSequence(); + for (auto &declVector : *decls) + { + // no init case + TIntermSymbol *symNode = declVector->getAsSymbolNode(); + if (symNode == nullptr) + { + // init case + TIntermBinary *binaryNode = declVector->getAsBinaryNode(); + ASSERT(binaryNode->getOp() == EOpInitialize); + symNode = binaryNode->getLeft()->getAsSymbolNode(); + } + ASSERT(symNode != nullptr); + std::string varName = std::string(symNode->variable().name().data()); + if (mParameterNames.count(varName) > 0) + { + // We found a redefined var so queue replacement + mReplacements.emplace_back(DeferredReplacementBlock{ + &symNode->variable(), + CreateTempVariable(mSymbolTable, &symNode->variable().getType()), + mFunctionBody}); + } + } + } + return true; + } + // Perform replacement of vars for any deferred replacements that were identified + [[nodiscard]] bool executeReplacements(TCompiler *compiler) + { + for (DeferredReplacementBlock &replace : mReplacements) + { + if (!ReplaceVariable(compiler, replace.functionBody, replace.originalVariable, + replace.replacementVariable)) + { + return false; + } + } + mReplacements.clear(); + return true; + } + + private: + std::unordered_set<std::string> mParameterNames; + TIntermBlock *mFunctionBody; + std::vector<DeferredReplacementBlock> mReplacements; +}; + +} // anonymous namespace + +// Replaces every occurrence of a variable with another variable. +[[nodiscard]] bool ReplaceShadowingVariables(TCompiler *compiler, + TIntermBlock *root, + TSymbolTable *symbolTable) +{ + ReplaceShadowingVariablesTraverser traverser(symbolTable); + root->traverse(&traverser); + if (!traverser.executeReplacements(compiler)) + { + return false; + } + return traverser.updateTree(compiler, root); +} + +} // namespace sh |