123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182 |
- #pragma once
- #ifdef __GNUC__
- #pragma GCC diagnostic push
- #pragma GCC diagnostic ignored "-Wunused-parameter"
- #endif
- //===- InlineOrder.h - Inlining order abstraction -*- C++ ---*-------------===//
- //
- // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
- // See https://llvm.org/LICENSE.txt for license information.
- // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
- //
- //===----------------------------------------------------------------------===//
- //
- #ifndef LLVM_ANALYSIS_INLINEORDER_H
- #define LLVM_ANALYSIS_INLINEORDER_H
- #include "llvm/ADT/DenseMap.h"
- #include "llvm/ADT/SmallVector.h"
- #include "llvm/IR/Function.h"
- #include "llvm/IR/Instruction.h"
- #include "llvm/IR/Instructions.h"
- #include <algorithm>
- #include <utility>
- namespace llvm {
- class CallBase;
- class Function;
- template <typename T> class InlineOrder {
- public:
- using reference = T &;
- using const_reference = const T &;
- virtual ~InlineOrder() = default;
- virtual size_t size() = 0;
- virtual void push(const T &Elt) = 0;
- virtual T pop() = 0;
- virtual const_reference front() = 0;
- virtual void erase_if(function_ref<bool(T)> Pred) = 0;
- bool empty() { return !size(); }
- };
- template <typename T, typename Container = SmallVector<T, 16>>
- class DefaultInlineOrder : public InlineOrder<T> {
- using reference = T &;
- using const_reference = const T &;
- public:
- size_t size() override { return Calls.size() - FirstIndex; }
- void push(const T &Elt) override { Calls.push_back(Elt); }
- T pop() override {
- assert(size() > 0);
- return Calls[FirstIndex++];
- }
- const_reference front() override {
- assert(size() > 0);
- return Calls[FirstIndex];
- }
- void erase_if(function_ref<bool(T)> Pred) override {
- Calls.erase(std::remove_if(Calls.begin() + FirstIndex, Calls.end(), Pred),
- Calls.end());
- }
- private:
- Container Calls;
- size_t FirstIndex = 0;
- };
- class InlineSizePriority {
- public:
- InlineSizePriority(int Size) : Size(Size) {}
- static bool isMoreDesirable(const InlineSizePriority &S1,
- const InlineSizePriority &S2) {
- return S1.Size < S2.Size;
- }
- static InlineSizePriority evaluate(CallBase *CB) {
- Function *Callee = CB->getCalledFunction();
- return InlineSizePriority(Callee->getInstructionCount());
- }
- int Size;
- };
- template <typename PriorityT>
- class PriorityInlineOrder : public InlineOrder<std::pair<CallBase *, int>> {
- using T = std::pair<CallBase *, int>;
- using HeapT = std::pair<CallBase *, PriorityT>;
- using reference = T &;
- using const_reference = const T &;
- static bool cmp(const HeapT &P1, const HeapT &P2) {
- return PriorityT::isMoreDesirable(P2.second, P1.second);
- }
- // A call site could become less desirable for inlining because of the size
- // growth from prior inlining into the callee. This method is used to lazily
- // update the desirability of a call site if it's decreasing. It is only
- // called on pop() or front(), not every time the desirability changes. When
- // the desirability of the front call site decreases, an updated one would be
- // pushed right back into the heap. For simplicity, those cases where
- // the desirability of a call site increases are ignored here.
- void adjust() {
- bool Changed = false;
- do {
- CallBase *CB = Heap.front().first;
- const PriorityT PreviousGoodness = Heap.front().second;
- const PriorityT CurrentGoodness = PriorityT::evaluate(CB);
- Changed = PriorityT::isMoreDesirable(PreviousGoodness, CurrentGoodness);
- if (Changed) {
- std::pop_heap(Heap.begin(), Heap.end(), cmp);
- Heap.pop_back();
- Heap.push_back({CB, CurrentGoodness});
- std::push_heap(Heap.begin(), Heap.end(), cmp);
- }
- } while (Changed);
- }
- public:
- size_t size() override { return Heap.size(); }
- void push(const T &Elt) override {
- CallBase *CB = Elt.first;
- const int InlineHistoryID = Elt.second;
- const PriorityT Goodness = PriorityT::evaluate(CB);
- Heap.push_back({CB, Goodness});
- std::push_heap(Heap.begin(), Heap.end(), cmp);
- InlineHistoryMap[CB] = InlineHistoryID;
- }
- T pop() override {
- assert(size() > 0);
- adjust();
- CallBase *CB = Heap.front().first;
- T Result = std::make_pair(CB, InlineHistoryMap[CB]);
- InlineHistoryMap.erase(CB);
- std::pop_heap(Heap.begin(), Heap.end(), cmp);
- Heap.pop_back();
- return Result;
- }
- const_reference front() override {
- assert(size() > 0);
- adjust();
- CallBase *CB = Heap.front().first;
- return *InlineHistoryMap.find(CB);
- }
- void erase_if(function_ref<bool(T)> Pred) override {
- auto PredWrapper = [=](HeapT P) -> bool {
- return Pred(std::make_pair(P.first, 0));
- };
- llvm::erase_if(Heap, PredWrapper);
- std::make_heap(Heap.begin(), Heap.end(), cmp);
- }
- private:
- SmallVector<HeapT, 16> Heap;
- DenseMap<CallBase *, int> InlineHistoryMap;
- };
- } // namespace llvm
- #endif // LLVM_ANALYSIS_INLINEORDER_H
- #ifdef __GNUC__
- #pragma GCC diagnostic pop
- #endif
|