[llvm] r339689 - Expose CFG Update struct. Define GraphTraits to get children given a snapshot CFG.

Alina Sbirlea via llvm-commits llvm-commits at lists.llvm.org
Tue Aug 14 09:44:28 PDT 2018


Author: asbirlea
Date: Tue Aug 14 09:44:28 2018
New Revision: 339689

URL: http://llvm.org/viewvc/llvm-project?rev=339689&view=rev
Log:
Expose CFG Update struct. Define GraphTraits to get children given a snapshot CFG.

Summary:
Certain passes or analysis need to view a CFG snapshot rather than the actual CFG. This patch provides GraphTraits to offer such a view.

The patch defines GraphTraits for BasicBlock* and Inverse<BasicBlock*> to provide CFG successors and predecessors based on a list of CFG updates.

An Update is defined as a triple {InsertOrDeleteKind, BlockStartOfEdge, BlockEndOfEdge}.
A GraphDiff is defined as a list of Updates that has been preprocessed to treat the CFG as a graph rather than a multi-graph. As such, there can only exist a single Update given two nodes. All duplicates will be filtered and Insert/Delete edges that cancel out will be ignored.
The methods GraphDiff exposes are:
- Determine if an existing child needs to be ignored, i.e. an Update exists in the correct direction to assume the removal of that edge.
- Return a list of new children to be considered, i.e. an Update exists in the correct direction for each child in the list to assume the insertion of that edge.

Reviewers: timshen, kuhar, chandlerc

Subscribers: sanjoy, jlebar, llvm-commits

Differential Revision: https://reviews.llvm.org/D50479

Added:
    llvm/trunk/include/llvm/IR/CFGDiff.h
    llvm/trunk/include/llvm/Support/CFGUpdate.h
Modified:
    llvm/trunk/include/llvm/ADT/iterator.h

Modified: llvm/trunk/include/llvm/ADT/iterator.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/ADT/iterator.h?rev=339689&r1=339688&r2=339689&view=diff
==============================================================================
--- llvm/trunk/include/llvm/ADT/iterator.h (original)
+++ llvm/trunk/include/llvm/ADT/iterator.h Tue Aug 14 09:44:28 2018
@@ -334,6 +334,34 @@ make_pointer_range(RangeT &&Range) {
                     PointerIteratorT(std::end(std::forward<RangeT>(Range))));
 }
 
+// Wrapper iterator over iterator ItType, adding DataRef to the type of ItType,
+// to create NodeRef = std::pair<InnerTypeOfItType, DataRef>.
+template <typename ItType, typename NodeRef, typename DataRef>
+class WrappedPairNodeDataIterator
+    : public iterator_adaptor_base<
+          WrappedPairNodeDataIterator<ItType, NodeRef, DataRef>, ItType,
+          typename std::iterator_traits<ItType>::iterator_category, NodeRef,
+          std::ptrdiff_t, NodeRef *, NodeRef &> {
+  using BaseT = iterator_adaptor_base<
+      WrappedPairNodeDataIterator, ItType,
+      typename std::iterator_traits<ItType>::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

Added: llvm/trunk/include/llvm/IR/CFGDiff.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/IR/CFGDiff.h?rev=339689&view=auto
==============================================================================
--- llvm/trunk/include/llvm/IR/CFGDiff.h (added)
+++ llvm/trunk/include/llvm/IR/CFGDiff.h Tue Aug 14 09:44:28 2018
@@ -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 <cassert>
+#include <cstddef>
+#include <iterator>
+
+// 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<BasicBlock *> is equivalent to InverseGraph = false
+// - GraphDiff<Inverse<BasicBlock *>> is equivalent to InverseGraph = true
+// - second pair item is BasicBlock *, then InverseEdge = false (so it inherits
+// from CFGViewSuccessors).
+// - second pair item is Inverse<BasicBlock *>, then InverseEdge = true (so it
+// inherits from CFGViewPredecessors).
+
+// The 4 GraphTraits are as follows:
+// 1. std::pair<const GraphDiff<BasicBlock *> *, BasicBlock *>> :
+//        CFGViewSuccessors<false>
+// Regular CFG, children means successors, InverseGraph = false,
+// InverseEdge = false.
+// 2. std::pair<const GraphDiff<Inverse<BasicBlock *>> *, BasicBlock *>> :
+//        CFGViewSuccessors<true>
+// Reverse the graph, get successors but reverse-apply updates,
+// InverseGraph = true, InverseEdge = false.
+// 3. std::pair<const GraphDiff<BasicBlock *> *, Inverse<BasicBlock *>>> :
+//        CFGViewPredecessors<false>
+// Regular CFG, reverse edges, so children mean predecessors,
+// InverseGraph = false, InverseEdge = true.
+// 4. std::pair<const GraphDiff<Inverse<BasicBlock *>> *, Inverse<BasicBlock *>>
+//        : CFGViewPredecessors<true>
+// Reverse the graph and the edges, InverseGraph = true, InverseEdge = true.
+
+namespace llvm {
+
+// GraphDiff defines a CFG snapshot: given a set of Update<NodePtr>, 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 <typename NodePtr> class GraphDiff {
+  using UpdateMapType = SmallDenseMap<NodePtr, SmallVector<NodePtr, 2>>;
+  UpdateMapType SuccInsert;
+  UpdateMapType SuccDelete;
+  UpdateMapType PredInsert;
+  UpdateMapType PredDelete;
+  // Using a singleton empty vector for all BasicBlock requests with no
+  // children.
+  SmallVector<NodePtr, 1> 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<cfg::Update<NodePtr>> Updates, bool InverseGraph = false) {
+    SmallVector<cfg::Update<NodePtr>, 4> LegalizedUpdates;
+    cfg::LegalizeUpdates<NodePtr>(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<typename SmallVectorImpl<NodePtr>::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 <bool InverseGraph = false> struct CFGViewSuccessors {
+  using DataRef = const GraphDiff<BasicBlock *> *;
+  using NodeRef = std::pair<DataRef, BasicBlock *>;
+
+  using ExistingChildIterator =
+      WrappedPairNodeDataIterator<succ_iterator, NodeRef, DataRef>;
+  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<ExistingChildIterator, DeletedEdgesFilter>;
+
+  using vec_iterator = SmallVectorImpl<BasicBlock *>::const_iterator;
+  using AddNewChildrenIterator =
+      WrappedPairNodeDataIterator<vec_iterator, NodeRef, DataRef>;
+  using ChildIteratorType =
+      concat_iterator<NodeRef, FilterExistingChildrenIterator,
+                      AddNewChildrenIterator>;
+
+  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<ExistingChildIterator>({succ_begin(N.second), N.first},
+                                          {succ_end(N.second), N.first}),
+        DeletedEdgesFilter(N.second));
+    // new inserts iterator init:
+    auto secondit = make_range<AddNewChildrenIterator>(
+        {InsertVec.begin(), N.first}, {InsertVec.end(), N.first});
+
+    return concat_iterator<NodeRef, FilterExistingChildrenIterator,
+                           AddNewChildrenIterator>(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<ExistingChildIterator>({succ_end(N.second), N.first},
+                                          {succ_end(N.second), N.first}),
+        DeletedEdgesFilter(N.second));
+    // new inserts iterator init:
+    auto secondit = make_range<AddNewChildrenIterator>(
+        {InsertVec.end(), N.first}, {InsertVec.end(), N.first});
+
+    return concat_iterator<NodeRef, FilterExistingChildrenIterator,
+                           AddNewChildrenIterator>(firstit, secondit);
+  }
+};
+
+template <bool InverseGraph = false> struct CFGViewPredecessors {
+  using DataRef = const GraphDiff<BasicBlock *> *;
+  using NodeRef = std::pair<DataRef, BasicBlock *>;
+
+  using ExistingChildIterator =
+      WrappedPairNodeDataIterator<pred_iterator, NodeRef, DataRef>;
+  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<ExistingChildIterator, DeletedEdgesFilter>;
+
+  using vec_iterator = SmallVectorImpl<BasicBlock *>::const_iterator;
+  using AddNewChildrenIterator =
+      WrappedPairNodeDataIterator<vec_iterator, NodeRef, DataRef>;
+  using ChildIteratorType =
+      concat_iterator<NodeRef, FilterExistingChildrenIterator,
+                      AddNewChildrenIterator>;
+
+  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<ExistingChildIterator>({pred_begin(N.second), N.first},
+                                          {pred_end(N.second), N.first}),
+        DeletedEdgesFilter(N.second));
+    // new inserts iterator init:
+    auto secondit = make_range<AddNewChildrenIterator>(
+        {InsertVec.begin(), N.first}, {InsertVec.end(), N.first});
+
+    return concat_iterator<NodeRef, FilterExistingChildrenIterator,
+                           AddNewChildrenIterator>(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<ExistingChildIterator>({pred_end(N.second), N.first},
+                                          {pred_end(N.second), N.first}),
+        DeletedEdgesFilter(N.second));
+    // new inserts iterator init:
+    auto secondit = make_range<AddNewChildrenIterator>(
+        {InsertVec.end(), N.first}, {InsertVec.end(), N.first});
+
+    return concat_iterator<NodeRef, FilterExistingChildrenIterator,
+                           AddNewChildrenIterator>(firstit, secondit);
+  }
+};
+
+template <>
+struct GraphTraits<std::pair<const GraphDiff<BasicBlock *> *, BasicBlock *>>
+    : CFGViewSuccessors<false> {};
+template <>
+struct GraphTraits<
+    std::pair<const GraphDiff<Inverse<BasicBlock *>> *, BasicBlock *>>
+    : CFGViewSuccessors<true> {};
+template <>
+struct GraphTraits<
+    std::pair<const GraphDiff<BasicBlock *> *, Inverse<BasicBlock *>>>
+    : CFGViewPredecessors<false> {};
+template <>
+struct GraphTraits<
+    std::pair<const GraphDiff<Inverse<BasicBlock *>> *, Inverse<BasicBlock *>>>
+    : CFGViewPredecessors<true> {};
+} // end namespace llvm
+
+#endif // LLVM_IR_CFGDIFF_H

Added: llvm/trunk/include/llvm/Support/CFGUpdate.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Support/CFGUpdate.h?rev=339689&view=auto
==============================================================================
--- llvm/trunk/include/llvm/Support/CFGUpdate.h (added)
+++ llvm/trunk/include/llvm/Support/CFGUpdate.h Tue Aug 14 09:44:28 2018
@@ -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 <typename NodePtr> class Update {
+  using NodeKindPair = PointerIntPair<NodePtr, 1, UpdateKind>;
+  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 <typename NodePtr>
+void LegalizeUpdates(ArrayRef<Update<NodePtr>> AllUpdates,
+                     SmallVectorImpl<Update<NodePtr>> &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<std::pair<NodePtr, NodePtr>, 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<NodePtr> &A, const Update<NodePtr> &B) {
+               return Operations[{A.getFrom(), A.getTo()}] >
+                      Operations[{B.getFrom(), B.getTo()}];
+             });
+}
+
+} // end namespace cfg
+} // end namespace llvm
+
+#endif // LLVM_SUPPORT_CFGUPDATE_H




More information about the llvm-commits mailing list