Edit

kc3-lang/angle/src/compiler/translator/SimplifyLoopConditions.cpp

Branch :

  • Show log

    Commit

  • Author : Jamie Madill
    Date : 2016-12-12 14:42:19
    Hash : d7b1ab58
    Message : Fix up translator style. Using git cl format. BUG=angleproject:650 Change-Id: I7d3f98d2b0dcfb0a8de6c35327db74e55c28d761 Reviewed-on: https://chromium-review.googlesource.com/419059 Reviewed-by: Jamie Madill <jmadill@chromium.org> Commit-Queue: Jamie Madill <jmadill@chromium.org>

  • src/compiler/translator/SimplifyLoopConditions.cpp
  • //
    // Copyright (c) 2016 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.
    //
    // SimplifyLoopConditions is an AST traverser that converts loop conditions and loop expressions
    // to regular statements inside the loop. This way further transformations that generate statements
    // from loop conditions and loop expressions work correctly.
    //
    
    #include "compiler/translator/SimplifyLoopConditions.h"
    
    #include "compiler/translator/IntermNode.h"
    #include "compiler/translator/IntermNodePatternMatcher.h"
    
    namespace sh
    {
    
    namespace
    {
    
    TIntermConstantUnion *CreateBoolConstantNode(bool value)
    {
        TConstantUnion *u = new TConstantUnion;
        u->setBConst(value);
        TIntermConstantUnion *node =
            new TIntermConstantUnion(u, TType(EbtBool, EbpUndefined, EvqConst, 1));
        return node;
    }
    
    class SimplifyLoopConditionsTraverser : public TLValueTrackingTraverser
    {
      public:
        SimplifyLoopConditionsTraverser(unsigned int conditionsToSimplifyMask,
                                        const TSymbolTable &symbolTable,
                                        int shaderVersion);
    
        void traverseLoop(TIntermLoop *node) override;
    
        bool visitBinary(Visit visit, TIntermBinary *node) override;
        bool visitAggregate(Visit visit, TIntermAggregate *node) override;
        bool visitTernary(Visit visit, TIntermTernary *node) override;
        bool visitDeclaration(Visit visit, TIntermDeclaration *node) override;
    
        void nextIteration();
        bool foundLoopToChange() const { return mFoundLoopToChange; }
    
      protected:
        // Marked to true once an operation that needs to be hoisted out of the expression has been
        // found. After that, no more AST updates are performed on that traversal.
        bool mFoundLoopToChange;
        bool mInsideLoopInitConditionOrExpression;
        IntermNodePatternMatcher mConditionsToSimplify;
    };
    
    SimplifyLoopConditionsTraverser::SimplifyLoopConditionsTraverser(
        unsigned int conditionsToSimplifyMask,
        const TSymbolTable &symbolTable,
        int shaderVersion)
        : TLValueTrackingTraverser(true, false, false, symbolTable, shaderVersion),
          mFoundLoopToChange(false),
          mInsideLoopInitConditionOrExpression(false),
          mConditionsToSimplify(conditionsToSimplifyMask)
    {
    }
    
    void SimplifyLoopConditionsTraverser::nextIteration()
    {
        mFoundLoopToChange                   = false;
        mInsideLoopInitConditionOrExpression = false;
        nextTemporaryIndex();
    }
    
    // The visit functions operate in three modes:
    // 1. If a matching expression has already been found, we return early since only one loop can
    //    be transformed on one traversal.
    // 2. We try to find loops. In case a node is not inside a loop and can not contain loops, we
    //    stop traversing the subtree.
    // 3. If we're inside a loop initialization, condition or expression, we check for expressions
    //    that should be moved out of the loop condition or expression. If one is found, the loop
    //    is processed.
    bool SimplifyLoopConditionsTraverser::visitBinary(Visit visit, TIntermBinary *node)
    {
    
        if (mFoundLoopToChange)
            return false;
    
        if (!mInsideLoopInitConditionOrExpression)
            return false;
    
        mFoundLoopToChange = mConditionsToSimplify.match(node, getParentNode(), isLValueRequiredHere());
        return !mFoundLoopToChange;
    }
    
    bool SimplifyLoopConditionsTraverser::visitAggregate(Visit visit, TIntermAggregate *node)
    {
        if (mFoundLoopToChange)
            return false;
    
        if (!mInsideLoopInitConditionOrExpression)
            return false;
    
        mFoundLoopToChange = mConditionsToSimplify.match(node, getParentNode());
        return !mFoundLoopToChange;
    }
    
    bool SimplifyLoopConditionsTraverser::visitTernary(Visit visit, TIntermTernary *node)
    {
        if (mFoundLoopToChange)
            return false;
    
        if (!mInsideLoopInitConditionOrExpression)
            return false;
    
        mFoundLoopToChange = mConditionsToSimplify.match(node);
        return !mFoundLoopToChange;
    }
    
    bool SimplifyLoopConditionsTraverser::visitDeclaration(Visit visit, TIntermDeclaration *node)
    {
        if (mFoundLoopToChange)
            return false;
    
        if (!mInsideLoopInitConditionOrExpression)
            return false;
    
        mFoundLoopToChange = mConditionsToSimplify.match(node);
        return !mFoundLoopToChange;
    }
    
    void SimplifyLoopConditionsTraverser::traverseLoop(TIntermLoop *node)
    {
        if (mFoundLoopToChange)
            return;
    
        // Mark that we're inside a loop condition or expression, and transform the loop if needed.
    
        incrementDepth(node);
    
        // Note: No need to traverse the loop init node.
    
        mInsideLoopInitConditionOrExpression = true;
        TLoopType loopType                   = node->getType();
    
        if (!mFoundLoopToChange && node->getInit())
        {
            node->getInit()->traverse(this);
        }
    
        if (!mFoundLoopToChange && node->getCondition())
        {
            node->getCondition()->traverse(this);
        }
    
        if (!mFoundLoopToChange && node->getExpression())
        {
            node->getExpression()->traverse(this);
        }
    
        if (mFoundLoopToChange)
        {
            // Replace the loop condition with a boolean variable that's updated on each iteration.
            if (loopType == ELoopWhile)
            {
                // Transform:
                //   while (expr) { body; }
                // into
                //   bool s0 = expr;
                //   while (s0) { { body; } s0 = expr; }
                TIntermSequence tempInitSeq;
                tempInitSeq.push_back(createTempInitDeclaration(node->getCondition()->deepCopy()));
                insertStatementsInParentBlock(tempInitSeq);
    
                TIntermBlock *newBody = new TIntermBlock();
                if (node->getBody())
                {
                    newBody->getSequence()->push_back(node->getBody());
                }
                newBody->getSequence()->push_back(
                    createTempAssignment(node->getCondition()->deepCopy()));
    
                // Can't use queueReplacement to replace old body, since it may have been nullptr.
                // It's safe to do the replacements in place here - this node won't be traversed
                // further.
                node->setBody(newBody);
                node->setCondition(createTempSymbol(node->getCondition()->getType()));
            }
            else if (loopType == ELoopDoWhile)
            {
                // Transform:
                //   do {
                //     body;
                //   } while (expr);
                // into
                //   bool s0 = true;
                //   do {
                //     { body; }
                //     s0 = expr;
                //   } while (s0);
                TIntermSequence tempInitSeq;
                tempInitSeq.push_back(createTempInitDeclaration(CreateBoolConstantNode(true)));
                insertStatementsInParentBlock(tempInitSeq);
    
                TIntermBlock *newBody = new TIntermBlock();
                if (node->getBody())
                {
                    newBody->getSequence()->push_back(node->getBody());
                }
                newBody->getSequence()->push_back(
                    createTempAssignment(node->getCondition()->deepCopy()));
    
                // Can't use queueReplacement to replace old body, since it may have been nullptr.
                // It's safe to do the replacements in place here - this node won't be traversed
                // further.
                node->setBody(newBody);
                node->setCondition(createTempSymbol(node->getCondition()->getType()));
            }
            else if (loopType == ELoopFor)
            {
                // Move the loop condition inside the loop.
                // Transform:
                //   for (init; expr; exprB) { body; }
                // into
                //   {
                //     init;
                //     bool s0 = expr;
                //     while (s0) {
                //       { body; }
                //       exprB;
                //       s0 = expr;
                //     }
                //   }
                TIntermBlock *loopScope            = new TIntermBlock();
                TIntermSequence *loopScopeSequence = loopScope->getSequence();
    
                // Insert "init;"
                if (node->getInit())
                {
                    loopScopeSequence->push_back(node->getInit());
                }
    
                // Insert "bool s0 = expr;" if applicable, "bool s0 = true;" otherwise
                TIntermTyped *conditionInitializer = nullptr;
                if (node->getCondition())
                {
                    conditionInitializer = node->getCondition()->deepCopy();
                }
                else
                {
                    conditionInitializer = TIntermTyped::CreateBool(true);
                }
                loopScopeSequence->push_back(createTempInitDeclaration(conditionInitializer));
    
                // Insert "{ body; }" in the while loop
                TIntermBlock *whileLoopBody = new TIntermBlock();
                if (node->getBody())
                {
                    whileLoopBody->getSequence()->push_back(node->getBody());
                }
                // Insert "exprB;" in the while loop
                if (node->getExpression())
                {
                    whileLoopBody->getSequence()->push_back(node->getExpression());
                }
                // Insert "s0 = expr;" in the while loop
                if (node->getCondition())
                {
                    whileLoopBody->getSequence()->push_back(
                        createTempAssignment(node->getCondition()->deepCopy()));
                }
    
                // Create "while(s0) { whileLoopBody }"
                TIntermLoop *whileLoop = new TIntermLoop(
                    ELoopWhile, nullptr, createTempSymbol(conditionInitializer->getType()), nullptr,
                    whileLoopBody);
                loopScope->getSequence()->push_back(whileLoop);
                queueReplacementWithParent(getAncestorNode(1), node, loopScope,
                                           OriginalNode::IS_DROPPED);
            }
        }
    
        mInsideLoopInitConditionOrExpression = false;
    
        if (!mFoundLoopToChange && node->getBody())
            node->getBody()->traverse(this);
    
        decrementDepth();
    }
    
    }  // namespace
    
    void SimplifyLoopConditions(TIntermNode *root,
                                unsigned int conditionsToSimplifyMask,
                                unsigned int *temporaryIndex,
                                const TSymbolTable &symbolTable,
                                int shaderVersion)
    {
        SimplifyLoopConditionsTraverser traverser(conditionsToSimplifyMask, symbolTable, shaderVersion);
        ASSERT(temporaryIndex != nullptr);
        traverser.useTemporaryIndex(temporaryIndex);
        // Process one loop at a time, and reset the traverser between iterations.
        do
        {
            traverser.nextIteration();
            root->traverse(&traverser);
            if (traverser.foundLoopToChange())
                traverser.updateTree();
        } while (traverser.foundLoopToChange());
    }
    
    }  // namespace sh