CFGUpdate.h 4.3 KB

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