CFGUpdate.h 4.1 KB

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