CFGUpdate.h revision 343171
1//===- CFGUpdate.h - Encode a CFG Edge Update. ------------------*- C++ -*-===//
2//
3//                     The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This file defines a CFG Edge Update: Insert or Delete, and two Nodes as the
11// Edge ends.
12//
13//===----------------------------------------------------------------------===//
14
15#ifndef LLVM_SUPPORT_CFGUPDATE_H
16#define LLVM_SUPPORT_CFGUPDATE_H
17
18#include "llvm/ADT/APInt.h"
19#include "llvm/ADT/DenseMap.h"
20#include "llvm/ADT/PointerIntPair.h"
21#include "llvm/Support/Compiler.h"
22#include "llvm/Support/Debug.h"
23#include "llvm/Support/raw_ostream.h"
24
25namespace llvm {
26namespace cfg {
27enum class UpdateKind : unsigned char { Insert, Delete };
28
29template <typename NodePtr> class Update {
30  using NodeKindPair = PointerIntPair<NodePtr, 1, UpdateKind>;
31  NodePtr From;
32  NodeKindPair ToAndKind;
33
34public:
35  Update(UpdateKind Kind, NodePtr From, NodePtr To)
36      : From(From), ToAndKind(To, Kind) {}
37
38  UpdateKind getKind() const { return ToAndKind.getInt(); }
39  NodePtr getFrom() const { return From; }
40  NodePtr getTo() const { return ToAndKind.getPointer(); }
41  bool operator==(const Update &RHS) const {
42    return From == RHS.From && ToAndKind == RHS.ToAndKind;
43  }
44
45  void print(raw_ostream &OS) const {
46    OS << (getKind() == UpdateKind::Insert ? "Insert " : "Delete ");
47    getFrom()->printAsOperand(OS, false);
48    OS << " -> ";
49    getTo()->printAsOperand(OS, false);
50  }
51
52#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
53  LLVM_DUMP_METHOD void dump() const { print(dbgs()); }
54#endif
55};
56
57// LegalizeUpdates function simplifies updates assuming a graph structure.
58// This function serves double purpose:
59// a) It removes redundant updates, which makes it easier to reverse-apply
60//    them when traversing CFG.
61// b) It optimizes away updates that cancel each other out, as the end result
62//    is the same.
63template <typename NodePtr>
64void LegalizeUpdates(ArrayRef<Update<NodePtr>> AllUpdates,
65                     SmallVectorImpl<Update<NodePtr>> &Result,
66                     bool InverseGraph) {
67  // Count the total number of inserions of each edge.
68  // Each insertion adds 1 and deletion subtracts 1. The end number should be
69  // one of {-1 (deletion), 0 (NOP), +1 (insertion)}. Otherwise, the sequence
70  // of updates contains multiple updates of the same kind and we assert for
71  // that case.
72  SmallDenseMap<std::pair<NodePtr, NodePtr>, int, 4> Operations;
73  Operations.reserve(AllUpdates.size());
74
75  for (const auto &U : AllUpdates) {
76    NodePtr From = U.getFrom();
77    NodePtr To = U.getTo();
78    if (InverseGraph)
79      std::swap(From, To); // Reverse edge for postdominators.
80
81    Operations[{From, To}] += (U.getKind() == UpdateKind::Insert ? 1 : -1);
82  }
83
84  Result.clear();
85  Result.reserve(Operations.size());
86  for (auto &Op : Operations) {
87    const int NumInsertions = Op.second;
88    assert(std::abs(NumInsertions) <= 1 && "Unbalanced operations!");
89    if (NumInsertions == 0)
90      continue;
91    const UpdateKind UK =
92        NumInsertions > 0 ? UpdateKind::Insert : UpdateKind::Delete;
93    Result.push_back({UK, Op.first.first, Op.first.second});
94  }
95
96  // Make the order consistent by not relying on pointer values within the
97  // set. Reuse the old Operations map.
98  // In the future, we should sort by something else to minimize the amount
99  // of work needed to perform the series of updates.
100  for (size_t i = 0, e = AllUpdates.size(); i != e; ++i) {
101    const auto &U = AllUpdates[i];
102    if (!InverseGraph)
103      Operations[{U.getFrom(), U.getTo()}] = int(i);
104    else
105      Operations[{U.getTo(), U.getFrom()}] = int(i);
106  }
107
108  llvm::sort(Result,
109             [&Operations](const Update<NodePtr> &A, const Update<NodePtr> &B) {
110               return Operations[{A.getFrom(), A.getTo()}] >
111                      Operations[{B.getFrom(), B.getTo()}];
112             });
113}
114
115} // end namespace cfg
116} // end namespace llvm
117
118#endif // LLVM_SUPPORT_CFGUPDATE_H
119