Edit

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

Branch :

  • Show log

    Commit

  • Author : Jamie Madill
    Date : 2016-11-07 13:58:48
    Hash : 45bcc784
    Message : translator: Scope all classes with "sh". I was seeing an odd problem with our PoolAlloc conflicting with the glslang/Vulkan TIntermNode, so the fix was to move everything to a separate namespace. The bison grammars are also regenerated. No functional changes. BUG=angleproject:1576 Change-Id: I959c7afe4c092f0d458432c07b4dcee4d39513f3 Reviewed-on: https://chromium-review.googlesource.com/408267 Reviewed-by: Yuly Novikov <ynovikov@chromium.org> Commit-Queue: Jamie Madill <jmadill@chromium.org>

  • src/compiler/translator/RewriteDoWhile.cpp
  • //
    // Copyright (c) 2015 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.
    //
    
    // RewriteDoWhile.cpp: rewrites do-while loops using another equivalent
    // construct.
    
    #include "compiler/translator/RewriteDoWhile.h"
    
    #include "compiler/translator/IntermNode.h"
    
    namespace sh
    {
    
    namespace
    {
    
    // An AST traverser that rewrites loops of the form
    //   do {
    //     CODE;
    //   } while (CONDITION)
    //
    // to loops of the form
    //   bool temp = false;
    //   while (true) {
    //     if (temp) {
    //       if (!CONDITION) {
    //         break;
    //       }
    //     }
    //     temp = true;
    //     CODE;
    //   }
    //
    // The reason we don't use a simpler form, with for example just (temp && !CONDITION) in the
    // while condition, is that short-circuit is often badly supported by driver shader compiler.
    // The double if has the same effect, but forces shader compilers to behave.
    //
    // TODO(cwallez) when UnfoldShortCircuitIntoIf handles loops correctly, revisit this as we might
    // be able to use while (temp || CONDITION) with temp initially set to true then run
    // UnfoldShortCircuitIntoIf
    class DoWhileRewriter : public TIntermTraverser
    {
      public:
        DoWhileRewriter() : TIntermTraverser(true, false, false) {}
    
        bool visitBlock(Visit, TIntermBlock *node) override
        {
            // A well-formed AST can only have do-while inside TIntermBlock. By doing a prefix traversal
            // we are able to replace the do-while in the sequence directly as the content of the
            // do-while will be traversed later.
    
            TIntermSequence *statements = node->getSequence();
    
            // The statements vector will have new statements inserted when we encounter a do-while,
            // which prevents us from using a range-based for loop. Using the usual i++ works, as
            // the (two) new statements inserted replace the statement at the current position.
            for (size_t i = 0; i < statements->size(); i++)
            {
                TIntermNode *statement = (*statements)[i];
                TIntermLoop *loop      = statement->getAsLoopNode();
    
                if (loop == nullptr || loop->getType() != ELoopDoWhile)
                {
                    continue;
                }
    
                TType boolType = TType(EbtBool);
    
                // bool temp = false;
                TIntermDeclaration *tempDeclaration = nullptr;
                {
                    TConstantUnion *falseConstant = new TConstantUnion();
                    falseConstant->setBConst(false);
                    TIntermTyped *falseValue = new TIntermConstantUnion(falseConstant, boolType);
    
                    tempDeclaration = createTempInitDeclaration(falseValue);
                }
    
                // temp = true;
                TIntermBinary *assignTrue = nullptr;
                {
                    TConstantUnion *trueConstant = new TConstantUnion();
                    trueConstant->setBConst(true);
                    TIntermTyped *trueValue = new TIntermConstantUnion(trueConstant, boolType);
    
                    assignTrue = createTempAssignment(trueValue);
                }
    
                // if (temp) {
                //   if (!CONDITION) {
                //     break;
                //   }
                // }
                TIntermIfElse *breakIf = nullptr;
                {
                    TIntermBranch *breakStatement = new TIntermBranch(EOpBreak, nullptr);
    
                    TIntermBlock *breakBlock = new TIntermBlock();
                    breakBlock->getSequence()->push_back(breakStatement);
    
                    TIntermUnary *negatedCondition =
                        new TIntermUnary(EOpLogicalNot, loop->getCondition());
    
                    TIntermIfElse *innerIf = new TIntermIfElse(negatedCondition, breakBlock, nullptr);
    
                    TIntermBlock *innerIfBlock = new TIntermBlock();
                    innerIfBlock->getSequence()->push_back(innerIf);
    
                    breakIf = new TIntermIfElse(createTempSymbol(boolType), innerIfBlock, nullptr);
                }
    
                // Assemble the replacement loops, reusing the do-while loop's body and inserting our
                // statements at the front.
                TIntermLoop *newLoop = nullptr;
                {
                    TConstantUnion *trueConstant = new TConstantUnion();
                    trueConstant->setBConst(true);
                    TIntermTyped *trueValue = new TIntermConstantUnion(trueConstant, boolType);
    
                    TIntermBlock *body = loop->getBody();
                    if (body == nullptr)
                    {
                        body = new TIntermBlock();
                    }
                    auto sequence = body->getSequence();
                    sequence->insert(sequence->begin(), assignTrue);
                    sequence->insert(sequence->begin(), breakIf);
    
                    newLoop = new TIntermLoop(ELoopWhile, nullptr, trueValue, nullptr, body);
                }
    
                TIntermSequence replacement;
                replacement.push_back(tempDeclaration);
                replacement.push_back(newLoop);
    
                node->replaceChildNodeWithMultiple(loop, replacement);
    
                nextTemporaryIndex();
            }
            return true;
        }
    };
    
    }  // anonymous namespace
    
    void RewriteDoWhile(TIntermNode *root, unsigned int *temporaryIndex)
    {
        ASSERT(temporaryIndex != 0);
    
        DoWhileRewriter rewriter;
        rewriter.useTemporaryIndex(temporaryIndex);
    
        root->traverse(&rewriter);
    }
    
    }  // namespace sh