Files
revng-revng/lib/RestructureCFGPass/Flattening.cpp
T
2019-02-25 12:29:15 +01:00

96 lines
3.4 KiB
C++

/// \file Flattening.cpp
/// \brief Helper functions for flattening the RegionCFGTree after combing
//
// This file is distributed under the MIT License. See LICENSE.md for details.
//
// LLVM includes
#include <llvm/ADT/SmallVector.h>
// revng libraries includes
#include "revng/Support/Debug.h"
// local libraries includes
#include "revng-c/RestructureCFGPass/RegionCFGTree.h"
#include "revng-c/RestructureCFGPass/Utils.h"
// local includes
#include "Flattening.h"
Logger<> FlattenLog("flattening");
void flattenRegionCFGTree(RegionCFG &Root) {
std::set<BasicBlockNode *> CollapsedNodes;
std::set<BasicBlockNode *> NodesToRemove;
for (BasicBlockNode *CollapsedNode : Root)
if (CollapsedNode->isCollapsed())
CollapsedNodes.insert(CollapsedNode);
while (CollapsedNodes.size()) {
for (BasicBlockNode *CollapsedNode : CollapsedNodes) {
revng_assert(CollapsedNode->successor_size() <= 1);
RegionCFG *CollapsedRegion = CollapsedNode->getCollapsedCFG();
BasicBlockNode *OldEntry = &CollapsedRegion->getEntryNode();
// move nodes to root RegionCFG
RegionCFG::BBNodeMap SubstitutionMap{};
using IterT = RegionCFG::links_container::iterator;
using MovedIterRange = llvm::iterator_range<IterT>;
MovedIterRange MovedRange = Root.copyNodesAndEdgesFrom(CollapsedRegion,
SubstitutionMap);
// Obtain a reference to the root AST node.
ASTTree &RootAST = Root.getAST();
ASTNode *ASTEntry = RootAST.copyASTNodesFrom(CollapsedRegion->getAST(),
SubstitutionMap);
// Fix body field of predecessor AST nodes
ASTNode *SCSNode = RootAST.findASTNode(CollapsedNode);
revng_assert((SCSNode != nullptr) and (llvm::isa<ScsNode>(SCSNode)));
ScsNode *SCS = llvm::cast<ScsNode>(SCSNode);
SCS->setBody(ASTEntry);
using EdgeDescriptor = std::pair<BasicBlockNode *, BasicBlockNode *>;
llvm::SmallVector<EdgeDescriptor, 4> ToMove;
// Fix predecessors
BasicBlockNode *Entry = SubstitutionMap.at(OldEntry);
for (BasicBlockNode *Pred : CollapsedNode->predecessors())
ToMove.push_back({ Pred, CollapsedNode });
for (EdgeDescriptor &Edge : ToMove)
moveEdgeTarget(Edge, Entry);
// Fix successors and loops
BasicBlockNode *Succ = *CollapsedNode->successors().begin();
for (std::unique_ptr<BasicBlockNode> &UniqueBBNode : MovedRange) {
if (UniqueBBNode->isBreak() or UniqueBBNode->isContinue()) {
BasicBlockNode *NewTarget = UniqueBBNode->isBreak() ? Succ : Entry;
ToMove.clear();
for (BasicBlockNode *Pred : UniqueBBNode->predecessors())
ToMove.push_back({ Pred, UniqueBBNode.get() });
for (EdgeDescriptor &Edge : ToMove)
moveEdgeTarget(Edge, NewTarget);
// breaks and continues need to be removed
NodesToRemove.insert(UniqueBBNode.get());
}
}
// also collapsed nodes need to be removed
NodesToRemove.insert(CollapsedNode);
}
// remove superfluous nodes
for (BasicBlockNode *BBNode : NodesToRemove)
Root.removeNode(BBNode);
NodesToRemove.clear();
// check if there are remaining collapsed nodes
CollapsedNodes.clear();
for (BasicBlockNode *CollapsedNode : Root)
if (CollapsedNode->isCollapsed())
CollapsedNodes.insert(CollapsedNode);
}
}