tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

ReplaceShadowingVariables.cpp (5492B)


      1 //
      2 // Copyright 2019 The ANGLE Project Authors. All rights reserved.
      3 // Use of this source code is governed by a BSD-style license that can be
      4 // found in the LICENSE file.
      5 //
      6 // ReplaceShadowingVariables.cpp: Replace all references to any variable in the AST that is
      7 // a redefinition of a variable in a nested scope. This is a useful for ESSL 1.00 shaders
      8 // where the spec section "4.2.3. Redeclaring Variables" states "However, a nested scope can
      9 // override an outer scope's declaration of a particular variable name." This is changed in
     10 // later spec versions, such as ESSL 3.20 spec which states "If [a variable] is declared as
     11 // a parameter in a function definition, it is scoped until the end of that function
     12 // definition. A function's parameter declarations and body together form a single scope."
     13 //
     14 // So this class is useful when translating from ESSL 1.00 shaders, where function body var
     15 // redefinition is allowed, to later shader versions where it's not allowed.
     16 //
     17 
     18 #include "compiler/translator/tree_util/ReplaceShadowingVariables.h"
     19 #include "compiler/translator/tree_util/ReplaceVariable.h"
     20 
     21 #include "compiler/translator/Compiler.h"
     22 #include "compiler/translator/IntermNode.h"
     23 #include "compiler/translator/Symbol.h"
     24 #include "compiler/translator/SymbolTable.h"
     25 #include "compiler/translator/tree_util/IntermNode_util.h"
     26 #include "compiler/translator/tree_util/IntermTraverse.h"
     27 
     28 #include <unordered_set>
     29 
     30 namespace sh
     31 {
     32 
     33 namespace
     34 {
     35 
     36 // Custom struct to queue up any replacements until after AST traversal
     37 struct DeferredReplacementBlock
     38 {
     39    const TVariable *originalVariable;  // variable to be replaced
     40    TVariable *replacementVariable;     // variable to replace originalVar with
     41    TIntermBlock *functionBody;         // function body where replacement occurs
     42 };
     43 
     44 class ReplaceShadowingVariablesTraverser : public TIntermTraverser
     45 {
     46  public:
     47    ReplaceShadowingVariablesTraverser(TSymbolTable *symbolTable)
     48        : TIntermTraverser(true, true, true, symbolTable), mParameterNames{}, mFunctionBody(nullptr)
     49    {}
     50 
     51    bool visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node) override
     52    {
     53        // In pre-visit of function, record params
     54        if (visit == PreVisit)
     55        {
     56            ASSERT(mParameterNames.size() == 0);
     57            const TFunction *func = node->getFunctionPrototype()->getFunction();
     58            // Grab all of the parameter names from the function prototype
     59            size_t paramCount = func->getParamCount();
     60            for (size_t i = 0; i < paramCount; ++i)
     61            {
     62                mParameterNames.emplace(std::string(func->getParam(i)->name().data()));
     63            }
     64            if (mParameterNames.size() > 0)
     65                mFunctionBody = node->getBody();
     66        }
     67        else if (visit == PostVisit)
     68        {
     69            // Clear data saved from function definition
     70            mParameterNames.clear();
     71            mFunctionBody = nullptr;
     72        }
     73        return true;
     74    }
     75    bool visitDeclaration(Visit visit, TIntermDeclaration *node) override
     76    {
     77        if (visit == PreVisit && mParameterNames.size() != 0)
     78        {
     79            TIntermSequence *decls = node->getSequence();
     80            for (auto &declVector : *decls)
     81            {
     82                // no init case
     83                TIntermSymbol *symNode = declVector->getAsSymbolNode();
     84                if (symNode == nullptr)
     85                {
     86                    // init case
     87                    TIntermBinary *binaryNode = declVector->getAsBinaryNode();
     88                    ASSERT(binaryNode->getOp() == EOpInitialize);
     89                    symNode = binaryNode->getLeft()->getAsSymbolNode();
     90                }
     91                ASSERT(symNode != nullptr);
     92                std::string varName = std::string(symNode->variable().name().data());
     93                if (mParameterNames.count(varName) > 0)
     94                {
     95                    // We found a redefined var so queue replacement
     96                    mReplacements.emplace_back(DeferredReplacementBlock{
     97                        &symNode->variable(),
     98                        CreateTempVariable(mSymbolTable, &symNode->variable().getType()),
     99                        mFunctionBody});
    100                }
    101            }
    102        }
    103        return true;
    104    }
    105    // Perform replacement of vars for any deferred replacements that were identified
    106    [[nodiscard]] bool executeReplacements(TCompiler *compiler)
    107    {
    108        for (DeferredReplacementBlock &replace : mReplacements)
    109        {
    110            if (!ReplaceVariable(compiler, replace.functionBody, replace.originalVariable,
    111                                 replace.replacementVariable))
    112            {
    113                return false;
    114            }
    115        }
    116        mReplacements.clear();
    117        return true;
    118    }
    119 
    120  private:
    121    std::unordered_set<std::string> mParameterNames;
    122    TIntermBlock *mFunctionBody;
    123    std::vector<DeferredReplacementBlock> mReplacements;
    124 };
    125 
    126 }  // anonymous namespace
    127 
    128 // Replaces every occurrence of a variable with another variable.
    129 [[nodiscard]] bool ReplaceShadowingVariables(TCompiler *compiler,
    130                                             TIntermBlock *root,
    131                                             TSymbolTable *symbolTable)
    132 {
    133    ReplaceShadowingVariablesTraverser traverser(symbolTable);
    134    root->traverse(&traverser);
    135    if (!traverser.executeReplacements(compiler))
    136    {
    137        return false;
    138    }
    139    return traverser.updateTree(compiler, root);
    140 }
    141 
    142 }  // namespace sh