Edit

kc3-lang/angle/src/compiler/translator/RemoveSwitchFallThrough.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/RemoveSwitchFallThrough.cpp
  • //
    // Copyright (c) 2002-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.
    //
    
    #include "compiler/translator/RemoveSwitchFallThrough.h"
    
    namespace sh
    {
    
    TIntermBlock *RemoveSwitchFallThrough::removeFallThrough(TIntermBlock *statementList)
    {
        RemoveSwitchFallThrough rm(statementList);
        ASSERT(statementList);
        statementList->traverse(&rm);
        bool lastStatementWasBreak = rm.mLastStatementWasBreak;
        rm.mLastStatementWasBreak  = true;
        rm.handlePreviousCase();
        if (!lastStatementWasBreak)
        {
            TIntermBranch *finalBreak = new TIntermBranch(EOpBreak, nullptr);
            rm.mStatementListOut->getSequence()->push_back(finalBreak);
        }
        return rm.mStatementListOut;
    }
    
    RemoveSwitchFallThrough::RemoveSwitchFallThrough(TIntermBlock *statementList)
        : TIntermTraverser(true, false, false),
          mStatementList(statementList),
          mLastStatementWasBreak(false),
          mPreviousCase(nullptr)
    {
        mStatementListOut = new TIntermBlock();
    }
    
    void RemoveSwitchFallThrough::visitSymbol(TIntermSymbol *node)
    {
        // Note that this assumes that switch statements which don't begin by a case statement
        // have already been weeded out in validation.
        mPreviousCase->getSequence()->push_back(node);
        mLastStatementWasBreak = false;
    }
    
    void RemoveSwitchFallThrough::visitConstantUnion(TIntermConstantUnion *node)
    {
        // Conditions of case labels are not traversed, so this is some other constant
        // Could be just a statement like "0;"
        mPreviousCase->getSequence()->push_back(node);
        mLastStatementWasBreak = false;
    }
    
    bool RemoveSwitchFallThrough::visitBinary(Visit, TIntermBinary *node)
    {
        mPreviousCase->getSequence()->push_back(node);
        mLastStatementWasBreak = false;
        return false;
    }
    
    bool RemoveSwitchFallThrough::visitUnary(Visit, TIntermUnary *node)
    {
        mPreviousCase->getSequence()->push_back(node);
        mLastStatementWasBreak = false;
        return false;
    }
    
    bool RemoveSwitchFallThrough::visitTernary(Visit, TIntermTernary *node)
    {
        mPreviousCase->getSequence()->push_back(node);
        mLastStatementWasBreak = false;
        return false;
    }
    
    bool RemoveSwitchFallThrough::visitIfElse(Visit, TIntermIfElse *node)
    {
        mPreviousCase->getSequence()->push_back(node);
        mLastStatementWasBreak = false;
        return false;
    }
    
    bool RemoveSwitchFallThrough::visitSwitch(Visit, TIntermSwitch *node)
    {
        mPreviousCase->getSequence()->push_back(node);
        mLastStatementWasBreak = false;
        // Don't go into nested switch statements
        return false;
    }
    
    void RemoveSwitchFallThrough::outputSequence(TIntermSequence *sequence, size_t startIndex)
    {
        for (size_t i = startIndex; i < sequence->size(); ++i)
        {
            mStatementListOut->getSequence()->push_back(sequence->at(i));
        }
    }
    
    void RemoveSwitchFallThrough::handlePreviousCase()
    {
        if (mPreviousCase)
            mCasesSharingBreak.push_back(mPreviousCase);
        if (mLastStatementWasBreak)
        {
            bool labelsWithNoStatements = true;
            for (size_t i = 0; i < mCasesSharingBreak.size(); ++i)
            {
                if (mCasesSharingBreak.at(i)->getSequence()->size() > 1)
                {
                    labelsWithNoStatements = false;
                }
                if (labelsWithNoStatements)
                {
                    // Fall-through is allowed in case the label has no statements.
                    outputSequence(mCasesSharingBreak.at(i)->getSequence(), 0);
                }
                else
                {
                    // Include all the statements that this case can fall through under the same label.
                    for (size_t j = i; j < mCasesSharingBreak.size(); ++j)
                    {
                        size_t startIndex =
                            j > i ? 1 : 0;  // Add the label only from the first sequence.
                        outputSequence(mCasesSharingBreak.at(j)->getSequence(), startIndex);
                    }
                }
            }
            mCasesSharingBreak.clear();
        }
        mLastStatementWasBreak = false;
        mPreviousCase          = nullptr;
    }
    
    bool RemoveSwitchFallThrough::visitCase(Visit, TIntermCase *node)
    {
        handlePreviousCase();
        mPreviousCase = new TIntermBlock();
        mPreviousCase->getSequence()->push_back(node);
        // Don't traverse the condition of the case statement
        return false;
    }
    
    bool RemoveSwitchFallThrough::visitAggregate(Visit, TIntermAggregate *node)
    {
        mPreviousCase->getSequence()->push_back(node);
        mLastStatementWasBreak = false;
        return false;
    }
    
    bool RemoveSwitchFallThrough::visitBlock(Visit, TIntermBlock *node)
    {
        if (node != mStatementList)
        {
            mPreviousCase->getSequence()->push_back(node);
            mLastStatementWasBreak = false;
            return false;
        }
        return true;
    }
    
    bool RemoveSwitchFallThrough::visitLoop(Visit, TIntermLoop *node)
    {
        mPreviousCase->getSequence()->push_back(node);
        mLastStatementWasBreak = false;
        return false;
    }
    
    bool RemoveSwitchFallThrough::visitBranch(Visit, TIntermBranch *node)
    {
        mPreviousCase->getSequence()->push_back(node);
        // TODO: Verify that accepting return or continue statements here doesn't cause problems.
        mLastStatementWasBreak = true;
        return false;
    }
    
    }  // namespace sh