InlineOrder.h 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. #pragma once
  2. #ifdef __GNUC__
  3. #pragma GCC diagnostic push
  4. #pragma GCC diagnostic ignored "-Wunused-parameter"
  5. #endif
  6. //===- InlineOrder.h - Inlining order abstraction -*- 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. #ifndef LLVM_ANALYSIS_INLINEORDER_H
  15. #define LLVM_ANALYSIS_INLINEORDER_H
  16. #include "llvm/ADT/DenseMap.h"
  17. #include "llvm/ADT/SmallVector.h"
  18. #include "llvm/IR/Function.h"
  19. #include "llvm/IR/Instruction.h"
  20. #include "llvm/IR/Instructions.h"
  21. #include <algorithm>
  22. #include <utility>
  23. namespace llvm {
  24. class CallBase;
  25. class Function;
  26. template <typename T> class InlineOrder {
  27. public:
  28. using reference = T &;
  29. using const_reference = const T &;
  30. virtual ~InlineOrder() = default;
  31. virtual size_t size() = 0;
  32. virtual void push(const T &Elt) = 0;
  33. virtual T pop() = 0;
  34. virtual const_reference front() = 0;
  35. virtual void erase_if(function_ref<bool(T)> Pred) = 0;
  36. bool empty() { return !size(); }
  37. };
  38. template <typename T, typename Container = SmallVector<T, 16>>
  39. class DefaultInlineOrder : public InlineOrder<T> {
  40. using reference = T &;
  41. using const_reference = const T &;
  42. public:
  43. size_t size() override { return Calls.size() - FirstIndex; }
  44. void push(const T &Elt) override { Calls.push_back(Elt); }
  45. T pop() override {
  46. assert(size() > 0);
  47. return Calls[FirstIndex++];
  48. }
  49. const_reference front() override {
  50. assert(size() > 0);
  51. return Calls[FirstIndex];
  52. }
  53. void erase_if(function_ref<bool(T)> Pred) override {
  54. Calls.erase(std::remove_if(Calls.begin() + FirstIndex, Calls.end(), Pred),
  55. Calls.end());
  56. }
  57. private:
  58. Container Calls;
  59. size_t FirstIndex = 0;
  60. };
  61. class InlineSizePriority {
  62. public:
  63. InlineSizePriority(int Size) : Size(Size) {}
  64. static bool isMoreDesirable(const InlineSizePriority &S1,
  65. const InlineSizePriority &S2) {
  66. return S1.Size < S2.Size;
  67. }
  68. static InlineSizePriority evaluate(CallBase *CB) {
  69. Function *Callee = CB->getCalledFunction();
  70. return InlineSizePriority(Callee->getInstructionCount());
  71. }
  72. int Size;
  73. };
  74. template <typename PriorityT>
  75. class PriorityInlineOrder : public InlineOrder<std::pair<CallBase *, int>> {
  76. using T = std::pair<CallBase *, int>;
  77. using HeapT = std::pair<CallBase *, PriorityT>;
  78. using reference = T &;
  79. using const_reference = const T &;
  80. static bool cmp(const HeapT &P1, const HeapT &P2) {
  81. return PriorityT::isMoreDesirable(P2.second, P1.second);
  82. }
  83. // A call site could become less desirable for inlining because of the size
  84. // growth from prior inlining into the callee. This method is used to lazily
  85. // update the desirability of a call site if it's decreasing. It is only
  86. // called on pop() or front(), not every time the desirability changes. When
  87. // the desirability of the front call site decreases, an updated one would be
  88. // pushed right back into the heap. For simplicity, those cases where
  89. // the desirability of a call site increases are ignored here.
  90. void adjust() {
  91. bool Changed = false;
  92. do {
  93. CallBase *CB = Heap.front().first;
  94. const PriorityT PreviousGoodness = Heap.front().second;
  95. const PriorityT CurrentGoodness = PriorityT::evaluate(CB);
  96. Changed = PriorityT::isMoreDesirable(PreviousGoodness, CurrentGoodness);
  97. if (Changed) {
  98. std::pop_heap(Heap.begin(), Heap.end(), cmp);
  99. Heap.pop_back();
  100. Heap.push_back({CB, CurrentGoodness});
  101. std::push_heap(Heap.begin(), Heap.end(), cmp);
  102. }
  103. } while (Changed);
  104. }
  105. public:
  106. size_t size() override { return Heap.size(); }
  107. void push(const T &Elt) override {
  108. CallBase *CB = Elt.first;
  109. const int InlineHistoryID = Elt.second;
  110. const PriorityT Goodness = PriorityT::evaluate(CB);
  111. Heap.push_back({CB, Goodness});
  112. std::push_heap(Heap.begin(), Heap.end(), cmp);
  113. InlineHistoryMap[CB] = InlineHistoryID;
  114. }
  115. T pop() override {
  116. assert(size() > 0);
  117. adjust();
  118. CallBase *CB = Heap.front().first;
  119. T Result = std::make_pair(CB, InlineHistoryMap[CB]);
  120. InlineHistoryMap.erase(CB);
  121. std::pop_heap(Heap.begin(), Heap.end(), cmp);
  122. Heap.pop_back();
  123. return Result;
  124. }
  125. const_reference front() override {
  126. assert(size() > 0);
  127. adjust();
  128. CallBase *CB = Heap.front().first;
  129. return *InlineHistoryMap.find(CB);
  130. }
  131. void erase_if(function_ref<bool(T)> Pred) override {
  132. auto PredWrapper = [=](HeapT P) -> bool {
  133. return Pred(std::make_pair(P.first, 0));
  134. };
  135. llvm::erase_if(Heap, PredWrapper);
  136. std::make_heap(Heap.begin(), Heap.end(), cmp);
  137. }
  138. private:
  139. SmallVector<HeapT, 16> Heap;
  140. DenseMap<CallBase *, int> InlineHistoryMap;
  141. };
  142. } // namespace llvm
  143. #endif // LLVM_ANALYSIS_INLINEORDER_H
  144. #ifdef __GNUC__
  145. #pragma GCC diagnostic pop
  146. #endif