Hash :
a07b4213
Author :
Date :
2018-03-22T16:13:13
Move AST transformations to a subdirectory Move AST transformations to compiler/translator/tree_ops. BUG=angleproject:2409 TEST=angle_unittests Change-Id: I9c620e98707d22d005da6192fe7d1b4e8030aadd Reviewed-on: https://chromium-review.googlesource.com/975550 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 117 118 119 120 121 122 123 124 125 126
//
// 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.
//
// WrapSwitchStatementsInBlocks.cpp: Wrap switch statements in blocks and declare all switch-scoped
// variables there to make the AST compatible with HLSL output.
//
// switch (init)
// {
// case 0:
// float f;
// default:
// f = 1.0;
// }
//
// becomes
//
// {
// float f;
// switch (init)
// {
// case 0:
// default:
// f = 1.0;
// }
// }
#include "compiler/translator/tree_ops/WrapSwitchStatementsInBlocks.h"
#include "compiler/translator/IntermNode.h"
#include "compiler/translator/tree_util/IntermTraverse.h"
namespace sh
{
namespace
{
class WrapSwitchStatementsInBlocksTraverser : public TIntermTraverser
{
public:
WrapSwitchStatementsInBlocksTraverser() : TIntermTraverser(true, false, false) {}
bool visitSwitch(Visit visit, TIntermSwitch *node) override;
};
bool WrapSwitchStatementsInBlocksTraverser::visitSwitch(Visit, TIntermSwitch *node)
{
std::vector<TIntermDeclaration *> declarations;
TIntermSequence *statementList = node->getStatementList()->getSequence();
for (TIntermNode *statement : *statementList)
{
TIntermDeclaration *asDeclaration = statement->getAsDeclarationNode();
if (asDeclaration)
{
declarations.push_back(asDeclaration);
}
}
if (declarations.empty())
{
// We don't need to wrap the switch if it doesn't contain declarations as its direct
// descendants.
return true;
}
TIntermBlock *wrapperBlock = new TIntermBlock();
for (TIntermDeclaration *declaration : declarations)
{
// SeparateDeclarations should have already been run.
ASSERT(declaration->getSequence()->size() == 1);
TIntermDeclaration *declarationInBlock = new TIntermDeclaration();
TIntermSymbol *declaratorAsSymbol = declaration->getSequence()->at(0)->getAsSymbolNode();
if (declaratorAsSymbol)
{
// This is a simple declaration like: "float f;"
// Remove the declaration from inside the switch and put it in the wrapping block.
TIntermSequence emptyReplacement;
mMultiReplacements.push_back(NodeReplaceWithMultipleEntry(
node->getStatementList(), declaration, emptyReplacement));
declarationInBlock->appendDeclarator(declaratorAsSymbol->deepCopy());
// The declaration can't be the last statement inside the switch since unused variables
// should already have been pruned.
ASSERT(declaration != statementList->back());
}
else
{
// This is an init declaration like: "float f = 0.0;"
// Change the init declaration inside the switch into an assignment and put a plain
// declaration in the wrapping block.
TIntermBinary *declaratorAsBinary =
declaration->getSequence()->at(0)->getAsBinaryNode();
ASSERT(declaratorAsBinary);
TIntermBinary *initAssignment = new TIntermBinary(
EOpAssign, declaratorAsBinary->getLeft(), declaratorAsBinary->getRight());
queueReplacementWithParent(node->getStatementList(), declaration, initAssignment,
OriginalNode::IS_DROPPED);
declarationInBlock->appendDeclarator(declaratorAsBinary->getLeft()->deepCopy());
}
wrapperBlock->appendStatement(declarationInBlock);
}
wrapperBlock->appendStatement(node);
queueReplacement(wrapperBlock, OriginalNode::BECOMES_CHILD);
// Should be fine to process multiple switch statements, even nesting ones in the same
// traversal.
return true;
}
} // anonymous namespace
// Wrap switch statements in the AST into blocks when needed.
void WrapSwitchStatementsInBlocks(TIntermBlock *root)
{
WrapSwitchStatementsInBlocksTraverser traverser;
root->traverse(&traverser);
traverser.updateTree();
}
} // namespace sh