Hash :
87c35883
Author :
Date :
2017-10-19T15:19:38
Prune no-op statements with a single traverser We put pruning literal statements and pruning empty declarations in the same traverser, as some of the required logic is the same. This pruning of no-ops is always done as one of the first processing steps after parsing, so further processing of the AST is simpler. Since we now prune pure literals before removing no-op cases from the end of switch statements, we also don't need any sort of special handling for switch statements in pruning pure literals. BUG=angleproject:2181 TEST=angle_unittests Change-Id: I2d86efaeb80baab63ac3cc803f3fd9e7ec02908a Reviewed-on: https://chromium-review.googlesource.com/727803 Reviewed-by: Jamie Madill <jmadill@chromium.org> Reviewed-by: Corentin Wallez <cwallez@chromium.org> Commit-Queue: Olli Etuaho <oetuaho@nvidia.com>
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116
//
// Copyright (c) 2017 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.
//
// RemoveNoOpCasesFromEndOfSwitchStatements.cpp: Clean up cases from the end of a switch statement
// that only contain no-ops.
#include "compiler/translator/RemoveNoOpCasesFromEndOfSwitchStatements.h"
#include "compiler/translator/IntermNode.h"
#include "compiler/translator/IntermNode_util.h"
#include "compiler/translator/IntermTraverse.h"
#include "compiler/translator/SymbolTable.h"
namespace sh
{
namespace
{
bool AreEmptyBlocks(TIntermSequence *statements, size_t i);
bool IsEmptyBlock(TIntermNode *node)
{
TIntermBlock *asBlock = node->getAsBlock();
if (asBlock)
{
if (asBlock->getSequence()->empty())
{
return true;
}
return AreEmptyBlocks(asBlock->getSequence(), 0u);
}
// Empty declarations should have already been pruned, otherwise they would need to be handled
// here. Note that declarations for struct types do contain a nameless child node.
ASSERT(node->getAsDeclarationNode() == nullptr ||
!node->getAsDeclarationNode()->getSequence()->empty());
// Pure literal statements should also already be pruned.
ASSERT(node->getAsConstantUnion() == nullptr);
return false;
}
// Return true if all statements in "statements" starting from index i consist only of empty blocks
// and no-op statements. Returns true also if there are no statements.
bool AreEmptyBlocks(TIntermSequence *statements, size_t i)
{
for (; i < statements->size(); ++i)
{
if (!IsEmptyBlock(statements->at(i)))
{
return false;
}
}
return true;
}
void RemoveNoOpCasesFromEndOfStatementList(TIntermBlock *statementList, TSymbolTable *symbolTable)
{
TIntermSequence *statements = statementList->getSequence();
bool foundDeadCase = false;
do
{
if (statements->empty())
{
return;
}
// Find the last case label.
size_t i = statements->size();
while (i > 0u && !(*statements)[i - 1]->getAsCaseNode())
{
--i;
}
// Now i is the index of the first statement following the last label inside the switch
// statement.
ASSERT(i > 0u);
foundDeadCase = AreEmptyBlocks(statements, i);
if (foundDeadCase)
{
statements->erase(statements->begin() + (i - 1u), statements->end());
}
} while (foundDeadCase);
}
class RemoveNoOpCasesFromEndOfSwitchTraverser : public TIntermTraverser
{
public:
RemoveNoOpCasesFromEndOfSwitchTraverser(TSymbolTable *symbolTable)
: TIntermTraverser(true, false, false, symbolTable)
{
}
bool visitSwitch(Visit visit, TIntermSwitch *node) override;
};
bool RemoveNoOpCasesFromEndOfSwitchTraverser::visitSwitch(Visit visit, TIntermSwitch *node)
{
// Here we may mutate the statement list, but it's safe since traversal has not yet reached
// there.
RemoveNoOpCasesFromEndOfStatementList(node->getStatementList(), mSymbolTable);
// Handle also nested switch statements.
return true;
}
} // anonymous namespace
void RemoveNoOpCasesFromEndOfSwitchStatements(TIntermBlock *root, TSymbolTable *symbolTable)
{
RemoveNoOpCasesFromEndOfSwitchTraverser traverser(symbolTable);
root->traverse(&traverser);
}
} // namespace sh