tor-browser

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

RewriteDoWhile.cpp (5115B)


      1 //
      2 // Copyright 2015 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 
      7 // RewriteDoWhile.cpp: rewrites do-while loops using another equivalent
      8 // construct.
      9 
     10 #include "compiler/translator/tree_ops/apple/RewriteDoWhile.h"
     11 
     12 #include "compiler/translator/Compiler.h"
     13 #include "compiler/translator/StaticType.h"
     14 #include "compiler/translator/tree_util/IntermNode_util.h"
     15 #include "compiler/translator/tree_util/IntermTraverse.h"
     16 
     17 namespace sh
     18 {
     19 
     20 namespace
     21 {
     22 
     23 // An AST traverser that rewrites loops of the form
     24 //   do {
     25 //     CODE;
     26 //   } while (CONDITION)
     27 //
     28 // to loops of the form
     29 //   bool temp = false;
     30 //   while (true) {
     31 //     if (temp) {
     32 //       if (!CONDITION) {
     33 //         break;
     34 //       }
     35 //     }
     36 //     temp = true;
     37 //     CODE;
     38 //   }
     39 //
     40 // The reason we don't use a simpler form, with for example just (temp && !CONDITION) in the
     41 // while condition, is that short-circuit is often badly supported by driver shader compiler.
     42 // The double if has the same effect, but forces shader compilers to behave.
     43 //
     44 // TODO(cwallez) when UnfoldShortCircuitIntoIf handles loops correctly, revisit this as we might
     45 // be able to use while (temp || CONDITION) with temp initially set to true then run
     46 // UnfoldShortCircuitIntoIf
     47 class DoWhileRewriter : public TIntermTraverser
     48 {
     49  public:
     50    DoWhileRewriter(TSymbolTable *symbolTable) : TIntermTraverser(true, false, false, symbolTable)
     51    {}
     52 
     53    bool visitBlock(Visit, TIntermBlock *node) override
     54    {
     55        // A well-formed AST can only have do-while inside TIntermBlock. By doing a prefix traversal
     56        // we are able to replace the do-while in the sequence directly as the content of the
     57        // do-while will be traversed later.
     58 
     59        TIntermSequence *statements = node->getSequence();
     60 
     61        // The statements vector will have new statements inserted when we encounter a do-while,
     62        // which prevents us from using a range-based for loop. Using the usual i++ works, as
     63        // the (two) new statements inserted replace the statement at the current position.
     64        for (size_t i = 0; i < statements->size(); i++)
     65        {
     66            TIntermNode *statement = (*statements)[i];
     67            TIntermLoop *loop      = statement->getAsLoopNode();
     68 
     69            if (loop == nullptr || loop->getType() != ELoopDoWhile)
     70            {
     71                continue;
     72            }
     73 
     74            // Found a loop to change.
     75            const TType *boolType = StaticType::Get<EbtBool, EbpUndefined, EvqTemporary, 1, 1>();
     76            TVariable *conditionVariable = CreateTempVariable(mSymbolTable, boolType);
     77 
     78            // bool temp = false;
     79            TIntermDeclaration *tempDeclaration =
     80                CreateTempInitDeclarationNode(conditionVariable, CreateBoolNode(false));
     81 
     82            // temp = true;
     83            TIntermBinary *assignTrue =
     84                CreateTempAssignmentNode(conditionVariable, CreateBoolNode(true));
     85 
     86            // if (temp) {
     87            //   if (!CONDITION) {
     88            //     break;
     89            //   }
     90            // }
     91            TIntermIfElse *breakIf = nullptr;
     92            {
     93                TIntermBranch *breakStatement = new TIntermBranch(EOpBreak, nullptr);
     94 
     95                TIntermBlock *breakBlock = new TIntermBlock();
     96                breakBlock->getSequence()->push_back(breakStatement);
     97 
     98                TIntermUnary *negatedCondition =
     99                    new TIntermUnary(EOpLogicalNot, loop->getCondition(), nullptr);
    100 
    101                TIntermIfElse *innerIf = new TIntermIfElse(negatedCondition, breakBlock, nullptr);
    102 
    103                TIntermBlock *innerIfBlock = new TIntermBlock();
    104                innerIfBlock->getSequence()->push_back(innerIf);
    105 
    106                breakIf = new TIntermIfElse(CreateTempSymbolNode(conditionVariable), innerIfBlock,
    107                                            nullptr);
    108            }
    109 
    110            // Assemble the replacement loops, reusing the do-while loop's body and inserting our
    111            // statements at the front.
    112            TIntermLoop *newLoop = nullptr;
    113            {
    114                TIntermBlock *body = loop->getBody();
    115                if (body == nullptr)
    116                {
    117                    body = new TIntermBlock();
    118                }
    119                auto sequence = body->getSequence();
    120                sequence->insert(sequence->begin(), assignTrue);
    121                sequence->insert(sequence->begin(), breakIf);
    122 
    123                newLoop = new TIntermLoop(ELoopWhile, nullptr, CreateBoolNode(true), nullptr, body);
    124            }
    125 
    126            TIntermSequence replacement;
    127            replacement.push_back(tempDeclaration);
    128            replacement.push_back(newLoop);
    129 
    130            node->replaceChildNodeWithMultiple(loop, replacement);
    131        }
    132        return true;
    133    }
    134 };
    135 
    136 }  // anonymous namespace
    137 
    138 bool RewriteDoWhile(TCompiler *compiler, TIntermNode *root, TSymbolTable *symbolTable)
    139 {
    140    DoWhileRewriter rewriter(symbolTable);
    141 
    142    root->traverse(&rewriter);
    143 
    144    return compiler->validateAST(root);
    145 }
    146 
    147 }  // namespace sh