Edit

kc3-lang/angle/src/compiler/translator/tree_ops/RemovePow.cpp

Branch :

  • Show log

    Commit

  • Author : Shahbaz Youssefi
    Date : 2021-01-19 12:38:46
    Hash : f0286e63
    Message : Translator: Stop allocating TIntermSequence The functions that take a TIntermSequence always copy out / Swap the contents away. This change makes all TIntermSequences live on the stack instead of being newed. Bug: angleproject:5535 Change-Id: I942f1c5e57b00199d5308183f71bd9e18b0608bd Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2636679 Reviewed-by: Jamie Madill <jmadill@chromium.org> Reviewed-by: Tim Van Patten <timvp@google.com> Commit-Queue: Shahbaz Youssefi <syoussefi@chromium.org>

  • src/compiler/translator/tree_ops/RemovePow.cpp
  • //
    // 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.
    //
    // RemovePow is an AST traverser to convert pow(x, y) built-in calls where y is a
    // constant to exp2(y * log2(x)). This works around an issue in NVIDIA 311 series
    // OpenGL drivers.
    //
    
    #include "compiler/translator/tree_ops/RemovePow.h"
    
    #include "compiler/translator/InfoSink.h"
    #include "compiler/translator/tree_util/IntermNode_util.h"
    #include "compiler/translator/tree_util/IntermTraverse.h"
    
    namespace sh
    {
    
    namespace
    {
    
    bool IsProblematicPow(TIntermTyped *node)
    {
        TIntermAggregate *agg = node->getAsAggregate();
        if (agg != nullptr && agg->getOp() == EOpPow)
        {
            ASSERT(agg->getSequence()->size() == 2);
            return agg->getSequence()->at(1)->getAsConstantUnion() != nullptr;
        }
        return false;
    }
    
    // Traverser that converts all pow operations simultaneously.
    class RemovePowTraverser : public TIntermTraverser
    {
      public:
        RemovePowTraverser(TSymbolTable *symbolTable);
    
        bool visitAggregate(Visit visit, TIntermAggregate *node) override;
    
        void nextIteration() { mNeedAnotherIteration = false; }
        bool needAnotherIteration() const { return mNeedAnotherIteration; }
    
      protected:
        bool mNeedAnotherIteration;
    };
    
    RemovePowTraverser::RemovePowTraverser(TSymbolTable *symbolTable)
        : TIntermTraverser(true, false, false, symbolTable), mNeedAnotherIteration(false)
    {}
    
    bool RemovePowTraverser::visitAggregate(Visit visit, TIntermAggregate *node)
    {
        if (IsProblematicPow(node))
        {
            TIntermTyped *x = node->getSequence()->at(0)->getAsTyped();
            TIntermTyped *y = node->getSequence()->at(1)->getAsTyped();
    
            TIntermSequence logArgs;
            logArgs.push_back(x);
            TIntermTyped *log = CreateBuiltInFunctionCallNode("log2", &logArgs, *mSymbolTable, 100);
            log->setLine(node->getLine());
    
            TOperator op       = TIntermBinary::GetMulOpBasedOnOperands(y->getType(), log->getType());
            TIntermBinary *mul = new TIntermBinary(op, y, log);
            mul->setLine(node->getLine());
    
            TIntermSequence expArgs;
            expArgs.push_back(mul);
            TIntermTyped *exp = CreateBuiltInFunctionCallNode("exp2", &expArgs, *mSymbolTable, 100);
            exp->setLine(node->getLine());
    
            queueReplacement(exp, OriginalNode::IS_DROPPED);
    
            // If the x parameter also needs to be replaced, we need to do that in another traversal,
            // since it's parent node will change in a way that's not handled correctly by updateTree().
            if (IsProblematicPow(x))
            {
                mNeedAnotherIteration = true;
                return false;
            }
        }
        return true;
    }
    
    }  // namespace
    
    bool RemovePow(TCompiler *compiler, TIntermNode *root, TSymbolTable *symbolTable)
    {
        RemovePowTraverser traverser(symbolTable);
        // Iterate as necessary, and reset the traverser between iterations.
        do
        {
            traverser.nextIteration();
            root->traverse(&traverser);
            if (!traverser.updateTree(compiler, root))
            {
                return false;
            }
        } while (traverser.needAnotherIteration());
    
        return true;
    }
    
    }  // namespace sh