Index: llvm/trunk/include/llvm/ADT/iterator.h =================================================================== --- llvm/trunk/include/llvm/ADT/iterator.h +++ llvm/trunk/include/llvm/ADT/iterator.h @@ -334,6 +334,34 @@ PointerIteratorT(std::end(std::forward(Range)))); } +// Wrapper iterator over iterator ItType, adding DataRef to the type of ItType, +// to create NodeRef = std::pair. +template +class WrappedPairNodeDataIterator + : public iterator_adaptor_base< + WrappedPairNodeDataIterator, ItType, + typename std::iterator_traits::iterator_category, NodeRef, + std::ptrdiff_t, NodeRef *, NodeRef &> { + using BaseT = iterator_adaptor_base< + WrappedPairNodeDataIterator, ItType, + typename std::iterator_traits::iterator_category, NodeRef, + std::ptrdiff_t, NodeRef *, NodeRef &>; + + const DataRef DR; + mutable NodeRef NR; + +public: + WrappedPairNodeDataIterator(ItType Begin, const DataRef DR) + : BaseT(Begin), DR(DR) { + NR.first = DR; + } + + NodeRef &operator*() const { + NR.second = *this->I; + return NR; + } +}; + } // end namespace llvm #endif // LLVM_ADT_ITERATOR_H Index: llvm/trunk/include/llvm/IR/CFGDiff.h =================================================================== --- llvm/trunk/include/llvm/IR/CFGDiff.h +++ llvm/trunk/include/llvm/IR/CFGDiff.h @@ -0,0 +1,286 @@ +//===- CFGDiff.h - Define a CFG snapshot. -----------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines specializations of GraphTraits that allows generic +// algorithms to see a different snapshot of a CFG. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_IR_CFGDIFF_H +#define LLVM_IR_CFGDIFF_H + +#include "llvm/ADT/GraphTraits.h" +#include "llvm/ADT/iterator.h" +#include "llvm/ADT/iterator_range.h" +#include "llvm/IR/BasicBlock.h" +#include "llvm/IR/CFG.h" +#include "llvm/Support/CFGUpdate.h" +#include "llvm/Support/type_traits.h" +#include +#include +#include + +// Two booleans are used to define orders in graphs: +// InverseGraph defines when we need to reverse the whole graph and is as such +// also equivalent to applying updates in reverse. +// InverseEdge defines whether we want to change the edges direction. E.g., for +// a non-inversed graph, the children are naturally the successors when +// InverseEdge is false and the predecessors when InverseEdge is true. + +// We define two base clases that call into GraphDiff, one for successors +// (CFGSuccessors), where InverseEdge is false, and one for predecessors +// (CFGPredecessors), where InverseEdge is true. +// FIXME: Further refactoring may merge the two base classes into a single one +// templated / parametrized on using succ_iterator/pred_iterator and false/true +// for the InverseEdge. + +// CFGViewSuccessors and CFGViewPredecessors, both can be parametrized to +// consider the graph inverted or not (i.e. InverseGraph). Successors +// implicitly has InverseEdge = false and Predecessors implicitly has +// InverseEdge = true (see calls to GraphDiff methods in there). The GraphTraits +// instantiations that follow define the value of InverseGraph. + +// GraphTraits instantiations: +// - GraphDiff is equivalent to InverseGraph = false +// - GraphDiff> is equivalent to InverseGraph = true +// - second pair item is BasicBlock *, then InverseEdge = false (so it inherits +// from CFGViewSuccessors). +// - second pair item is Inverse, then InverseEdge = true (so it +// inherits from CFGViewPredecessors). + +// The 4 GraphTraits are as follows: +// 1. std::pair *, BasicBlock *>> : +// CFGViewSuccessors +// Regular CFG, children means successors, InverseGraph = false, +// InverseEdge = false. +// 2. std::pair> *, BasicBlock *>> : +// CFGViewSuccessors +// Reverse the graph, get successors but reverse-apply updates, +// InverseGraph = true, InverseEdge = false. +// 3. std::pair *, Inverse>> : +// CFGViewPredecessors +// Regular CFG, reverse edges, so children mean predecessors, +// InverseGraph = false, InverseEdge = true. +// 4. std::pair> *, Inverse> +// : CFGViewPredecessors +// Reverse the graph and the edges, InverseGraph = true, InverseEdge = true. + +namespace llvm { + +// GraphDiff defines a CFG snapshot: given a set of Update, provide +// utilities to skip edges marked as deleted and return a set of edges marked as +// newly inserted. The current diff treats the CFG as a graph rather than a +// multigraph. Added edges are pruned to be unique, and deleted edges will +// remove all existing edges between two blocks. +template class GraphDiff { + using UpdateMapType = SmallDenseMap>; + UpdateMapType SuccInsert; + UpdateMapType SuccDelete; + UpdateMapType PredInsert; + UpdateMapType PredDelete; + // Using a singleton empty vector for all BasicBlock requests with no + // children. + SmallVector Empty; + + void printMap(raw_ostream &OS, const UpdateMapType &M) const { + for (auto Pair : M) + for (auto Child : Pair.second) { + OS << "("; + Pair.first->printAsOperand(OS, false); + OS << ", "; + Child->printAsOperand(OS, false); + OS << ") "; + } + OS << "\n"; + } + +public: + GraphDiff() {} + GraphDiff(ArrayRef> Updates, bool InverseGraph = false) { + SmallVector, 4> LegalizedUpdates; + cfg::LegalizeUpdates(Updates, LegalizedUpdates, InverseGraph); + for (auto U : LegalizedUpdates) { + if (U.getKind() == cfg::UpdateKind::Insert) { + SuccInsert[U.getFrom()].push_back(U.getTo()); + PredInsert[U.getTo()].push_back(U.getFrom()); + } else { + SuccDelete[U.getFrom()].push_back(U.getTo()); + PredDelete[U.getTo()].push_back(U.getFrom()); + } + } + } + + bool ignoreChild(const NodePtr BB, NodePtr EdgeEnd, bool InverseEdge, + bool InverseGraph) const { + auto &DeleteChildren = + (InverseEdge != InverseGraph) ? PredDelete : SuccDelete; + auto It = DeleteChildren.find(BB); + if (It == DeleteChildren.end()) + return false; + auto &EdgesForBB = It->second; + return llvm::find(EdgesForBB, EdgeEnd) != EdgesForBB.end(); + } + + iterator_range::const_iterator> + getAddedChildren(const NodePtr BB, bool InverseEdge, + bool InverseGraph) const { + auto &InsertChildren = + (InverseEdge != InverseGraph) ? PredInsert : SuccInsert; + auto It = InsertChildren.find(BB); + if (It == InsertChildren.end()) + return make_range(Empty.begin(), Empty.end()); + return make_range(It->second.begin(), It->second.end()); + } + + void print(raw_ostream &OS) const { + OS << "===== GraphDiff: CFG edge changes to create a CFG snapshot. \n" + "===== (Note: notion of children/inverse_children depends on " + "the direction of edges and the graph.)\n"; + OS << "Children to insert:\n\t"; + printMap(OS, SuccInsert); + OS << "Children to delete:\n\t"; + printMap(OS, SuccDelete); + OS << "Inverse_children to insert:\n\t"; + printMap(OS, PredInsert); + OS << "Inverse_children to delete:\n\t"; + printMap(OS, PredDelete); + OS << "\n"; + } + +#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) + LLVM_DUMP_METHOD void dump() const { print(dbgs()); } +#endif +}; + +template struct CFGViewSuccessors { + using DataRef = const GraphDiff *; + using NodeRef = std::pair; + + using ExistingChildIterator = + WrappedPairNodeDataIterator; + struct DeletedEdgesFilter { + BasicBlock *BB; + DeletedEdgesFilter(BasicBlock *BB) : BB(BB){}; + bool operator()(NodeRef N) const { + return !N.first->ignoreChild(BB, N.second, false, InverseGraph); + } + }; + using FilterExistingChildrenIterator = + filter_iterator; + + using vec_iterator = SmallVectorImpl::const_iterator; + using AddNewChildrenIterator = + WrappedPairNodeDataIterator; + using ChildIteratorType = + concat_iterator; + + static ChildIteratorType child_begin(NodeRef N) { + auto InsertVec = N.first->getAddedChildren(N.second, false, InverseGraph); + // filter iterator init: + auto firstit = make_filter_range( + make_range({succ_begin(N.second), N.first}, + {succ_end(N.second), N.first}), + DeletedEdgesFilter(N.second)); + // new inserts iterator init: + auto secondit = make_range( + {InsertVec.begin(), N.first}, {InsertVec.end(), N.first}); + + return concat_iterator(firstit, secondit); + } + + static ChildIteratorType child_end(NodeRef N) { + auto InsertVec = N.first->getAddedChildren(N.second, false, InverseGraph); + // filter iterator init: + auto firstit = make_filter_range( + make_range({succ_end(N.second), N.first}, + {succ_end(N.second), N.first}), + DeletedEdgesFilter(N.second)); + // new inserts iterator init: + auto secondit = make_range( + {InsertVec.end(), N.first}, {InsertVec.end(), N.first}); + + return concat_iterator(firstit, secondit); + } +}; + +template struct CFGViewPredecessors { + using DataRef = const GraphDiff *; + using NodeRef = std::pair; + + using ExistingChildIterator = + WrappedPairNodeDataIterator; + struct DeletedEdgesFilter { + BasicBlock *BB; + DeletedEdgesFilter(BasicBlock *BB) : BB(BB){}; + bool operator()(NodeRef N) const { + return !N.first->ignoreChild(BB, N.second, true, InverseGraph); + } + }; + using FilterExistingChildrenIterator = + filter_iterator; + + using vec_iterator = SmallVectorImpl::const_iterator; + using AddNewChildrenIterator = + WrappedPairNodeDataIterator; + using ChildIteratorType = + concat_iterator; + + static ChildIteratorType child_begin(NodeRef N) { + auto InsertVec = N.first->getAddedChildren(N.second, true, InverseGraph); + // filter iterator init: + auto firstit = make_filter_range( + make_range({pred_begin(N.second), N.first}, + {pred_end(N.second), N.first}), + DeletedEdgesFilter(N.second)); + // new inserts iterator init: + auto secondit = make_range( + {InsertVec.begin(), N.first}, {InsertVec.end(), N.first}); + + return concat_iterator(firstit, secondit); + } + + static ChildIteratorType child_end(NodeRef N) { + auto InsertVec = N.first->getAddedChildren(N.second, true, InverseGraph); + // filter iterator init: + auto firstit = make_filter_range( + make_range({pred_end(N.second), N.first}, + {pred_end(N.second), N.first}), + DeletedEdgesFilter(N.second)); + // new inserts iterator init: + auto secondit = make_range( + {InsertVec.end(), N.first}, {InsertVec.end(), N.first}); + + return concat_iterator(firstit, secondit); + } +}; + +template <> +struct GraphTraits *, BasicBlock *>> + : CFGViewSuccessors {}; +template <> +struct GraphTraits< + std::pair> *, BasicBlock *>> + : CFGViewSuccessors {}; +template <> +struct GraphTraits< + std::pair *, Inverse>> + : CFGViewPredecessors {}; +template <> +struct GraphTraits< + std::pair> *, Inverse>> + : CFGViewPredecessors {}; +} // end namespace llvm + +#endif // LLVM_IR_CFGDIFF_H Index: llvm/trunk/include/llvm/Support/CFGUpdate.h =================================================================== --- llvm/trunk/include/llvm/Support/CFGUpdate.h +++ llvm/trunk/include/llvm/Support/CFGUpdate.h @@ -0,0 +1,113 @@ +//===- CFGUpdate.h - Encode a CFG Edge Update. ------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines a CFG Edge Update: Insert or Delete, and two Nodes as the +// Edge ends. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SUPPORT_CFGUPDATE_H +#define LLVM_SUPPORT_CFGUPDATE_H + +#include "llvm/Support/Debug.h" + +namespace llvm { +namespace cfg { +enum class UpdateKind : unsigned char { Insert, Delete }; + +template class Update { + using NodeKindPair = PointerIntPair; + NodePtr From; + NodeKindPair ToAndKind; + +public: + Update(UpdateKind Kind, NodePtr From, NodePtr To) + : From(From), ToAndKind(To, Kind) {} + + UpdateKind getKind() const { return ToAndKind.getInt(); } + NodePtr getFrom() const { return From; } + NodePtr getTo() const { return ToAndKind.getPointer(); } + bool operator==(const Update &RHS) const { + return From == RHS.From && ToAndKind == RHS.ToAndKind; + } + + void print(raw_ostream &OS) const { + OS << (getKind() == UpdateKind::Insert ? "Insert " : "Delete "); + getFrom()->printAsOperand(OS, false); + OS << " -> "; + getTo()->printAsOperand(OS, false); + } + +#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) + LLVM_DUMP_METHOD void dump() const { print(dbgs()); } +#endif +}; + +// LegalizeUpdates function simplifies updates assuming a graph structure. +// This function serves double purpose: +// a) It removes redundant updates, which makes it easier to reverse-apply +// them when traversing CFG. +// b) It optimizes away updates that cancel each other out, as the end result +// is the same. +template +void LegalizeUpdates(ArrayRef> AllUpdates, + SmallVectorImpl> &Result, + bool InverseGraph) { + // Count the total number of inserions of each edge. + // Each insertion adds 1 and deletion subtracts 1. The end number should be + // one of {-1 (deletion), 0 (NOP), +1 (insertion)}. Otherwise, the sequence + // of updates contains multiple updates of the same kind and we assert for + // that case. + SmallDenseMap, int, 4> Operations; + Operations.reserve(AllUpdates.size()); + + for (const auto &U : AllUpdates) { + NodePtr From = U.getFrom(); + NodePtr To = U.getTo(); + if (InverseGraph) + std::swap(From, To); // Reverse edge for postdominators. + + Operations[{From, To}] += (U.getKind() == UpdateKind::Insert ? 1 : -1); + } + + Result.clear(); + Result.reserve(Operations.size()); + for (auto &Op : Operations) { + const int NumInsertions = Op.second; + assert(std::abs(NumInsertions) <= 1 && "Unbalanced operations!"); + if (NumInsertions == 0) + continue; + const UpdateKind UK = + NumInsertions > 0 ? UpdateKind::Insert : UpdateKind::Delete; + Result.push_back({UK, Op.first.first, Op.first.second}); + } + + // Make the order consistent by not relying on pointer values within the + // set. Reuse the old Operations map. + // In the future, we should sort by something else to minimize the amount + // of work needed to perform the series of updates. + for (size_t i = 0, e = AllUpdates.size(); i != e; ++i) { + const auto &U = AllUpdates[i]; + if (!InverseGraph) + Operations[{U.getFrom(), U.getTo()}] = int(i); + else + Operations[{U.getTo(), U.getFrom()}] = int(i); + } + + llvm::sort(Result.begin(), Result.end(), + [&Operations](const Update &A, const Update &B) { + return Operations[{A.getFrom(), A.getTo()}] > + Operations[{B.getFrom(), B.getTo()}]; + }); +} + +} // end namespace cfg +} // end namespace llvm + +#endif // LLVM_SUPPORT_CFGUPDATE_H