[ModuleInliner] Factor out common code in InlineOrder.cpp (NFC)

This patch factors out common code in InlineOrder.cpp.

Without this patch, the model is to ask classes like SizePriority and
CostPriority to compare a pair of call sites:

  bool hasLowerPriority(const CallBase *L, const CallBase *R) const override {

while these priority classes have their own caches of priorities:

  DenseMap<const CallBase *, PriorityT> Priorities;

This model results in a lot of duplicate code like hasLowerPriority
and updateAndCheckDecreased.

This patch changes the model so that priority classes just have two
methods to compute a priority for a given call site and to compare two
previously computed priorities (as opposed to call sites).

Facilities like hasLowerPriority and updateAndCheckDecreased move to
PriorityInlineOrder along with the map from call sites to their
priorities.  PriorityInlineOrder becomes a template class so that it
can accommodate different priority classes.

Differential Revision: https://reviews.llvm.org/D134149
This commit is contained in:
Kazu Hirata 2022-09-21 08:50:30 -07:00
parent 8c1a9e3cf3
commit 0a0ccc85bb
1 changed files with 40 additions and 73 deletions

View File

@ -63,92 +63,61 @@ llvm::InlineCost getInlineCostWrapper(CallBase &CB,
GetBFI, PSI, RemarksEnabled ? &ORE : nullptr);
}
class InlinePriority {
class SizePriority {
public:
virtual ~InlinePriority() = default;
virtual bool hasLowerPriority(const CallBase *L, const CallBase *R) const = 0;
virtual void update(const CallBase *CB) = 0;
virtual bool updateAndCheckDecreased(const CallBase *CB) = 0;
};
class SizePriority : public InlinePriority {
using PriorityT = unsigned;
DenseMap<const CallBase *, PriorityT> Priorities;
PriorityT evaluate(const CallBase *CB) {
SizePriority() = default;
SizePriority(const CallBase *CB, FunctionAnalysisManager &,
const InlineParams &) {
Function *Callee = CB->getCalledFunction();
return Callee->getInstructionCount();
Size = Callee->getInstructionCount();
}
bool isMoreDesirable(const PriorityT &P1, const PriorityT &P2) const {
return P1 < P2;
static bool isMoreDesirable(const SizePriority &P1, const SizePriority &P2) {
return P1.Size < P2.Size;
}
public:
bool hasLowerPriority(const CallBase *L, const CallBase *R) const override {
const auto I1 = Priorities.find(L);
const auto I2 = Priorities.find(R);
assert(I1 != Priorities.end() && I2 != Priorities.end());
return isMoreDesirable(I2->second, I1->second);
}
// Update the priority associated with CB.
void update(const CallBase *CB) override { Priorities[CB] = evaluate(CB); };
bool updateAndCheckDecreased(const CallBase *CB) override {
auto It = Priorities.find(CB);
const auto OldPriority = It->second;
It->second = evaluate(CB);
const auto NewPriority = It->second;
return isMoreDesirable(OldPriority, NewPriority);
}
private:
unsigned Size;
};
class CostPriority : public InlinePriority {
using PriorityT = int;
DenseMap<const CallBase *, PriorityT> Priorities;
std::function<InlineCost(const CallBase *)> getInlineCost;
PriorityT evaluate(const CallBase *CB) {
auto IC = getInlineCost(CB);
int Cost = 0;
class CostPriority {
public:
CostPriority() = default;
CostPriority(const CallBase *CB, FunctionAnalysisManager &FAM,
const InlineParams &Params) {
auto IC = getInlineCostWrapper(const_cast<CallBase &>(*CB), FAM, Params);
if (IC.isVariable())
Cost = IC.getCost();
else
Cost = IC.isNever() ? INT_MAX : INT_MIN;
return Cost;
}
bool isMoreDesirable(const PriorityT &P1, const PriorityT &P2) const {
return P1 < P2;
static bool isMoreDesirable(const CostPriority &P1, const CostPriority &P2) {
return P1.Cost < P2.Cost;
}
public:
CostPriority() = delete;
CostPriority(std::function<InlineCost(const CallBase *)> getInlineCost)
: getInlineCost(getInlineCost){};
private:
int Cost;
};
bool hasLowerPriority(const CallBase *L, const CallBase *R) const override {
template <typename PriorityT>
class PriorityInlineOrder : public InlineOrder<std::pair<CallBase *, int>> {
using T = std::pair<CallBase *, int>;
bool hasLowerPriority(const CallBase *L, const CallBase *R) const {
const auto I1 = Priorities.find(L);
const auto I2 = Priorities.find(R);
assert(I1 != Priorities.end() && I2 != Priorities.end());
return isMoreDesirable(I2->second, I1->second);
return PriorityT::isMoreDesirable(I2->second, I1->second);
}
// Update the priority associated with CB.
void update(const CallBase *CB) override { Priorities[CB] = evaluate(CB); };
bool updateAndCheckDecreased(const CallBase *CB) override {
bool updateAndCheckDecreased(const CallBase *CB) {
auto It = Priorities.find(CB);
const auto OldPriority = It->second;
It->second = evaluate(CB);
It->second = PriorityT(CB, FAM, Params);
const auto NewPriority = It->second;
return isMoreDesirable(OldPriority, NewPriority);
return PriorityT::isMoreDesirable(OldPriority, NewPriority);
}
};
class PriorityInlineOrder : public InlineOrder<std::pair<CallBase *, int>> {
using T = std::pair<CallBase *, int>;
// 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
@ -158,17 +127,17 @@ class PriorityInlineOrder : public InlineOrder<std::pair<CallBase *, int>> {
// pushed right back into the heap. For simplicity, those cases where
// the desirability of a call site increases are ignored here.
void adjust() {
while (PriorityPtr->updateAndCheckDecreased(Heap.front())) {
while (updateAndCheckDecreased(Heap.front())) {
std::pop_heap(Heap.begin(), Heap.end(), isLess);
std::push_heap(Heap.begin(), Heap.end(), isLess);
}
}
public:
PriorityInlineOrder(std::unique_ptr<InlinePriority> PriorityPtr)
: PriorityPtr(std::move(PriorityPtr)) {
isLess = [this](const CallBase *L, const CallBase *R) {
return this->PriorityPtr->hasLowerPriority(L, R);
PriorityInlineOrder(FunctionAnalysisManager &FAM, const InlineParams &Params)
: FAM(FAM), Params(Params) {
isLess = [&](const CallBase *L, const CallBase *R) {
return hasLowerPriority(L, R);
};
}
@ -179,7 +148,7 @@ public:
const int InlineHistoryID = Elt.second;
Heap.push_back(CB);
PriorityPtr->update(CB);
Priorities[CB] = PriorityT(CB, FAM, Params);
std::push_heap(Heap.begin(), Heap.end(), isLess);
InlineHistoryMap[CB] = InlineHistoryID;
}
@ -208,7 +177,9 @@ private:
SmallVector<CallBase *, 16> Heap;
std::function<bool(const CallBase *L, const CallBase *R)> isLess;
DenseMap<CallBase *, int> InlineHistoryMap;
std::unique_ptr<InlinePriority> PriorityPtr;
DenseMap<const CallBase *, PriorityT> Priorities;
FunctionAnalysisManager &FAM;
const InlineParams &Params;
};
} // namespace
@ -218,15 +189,11 @@ llvm::getInlineOrder(FunctionAnalysisManager &FAM, const InlineParams &Params) {
switch (UseInlinePriority) {
case InlinePriorityMode::Size:
LLVM_DEBUG(dbgs() << " Current used priority: Size priority ---- \n");
return std::make_unique<PriorityInlineOrder>(
std::make_unique<SizePriority>());
return std::make_unique<PriorityInlineOrder<SizePriority>>(FAM, Params);
case InlinePriorityMode::Cost:
LLVM_DEBUG(dbgs() << " Current used priority: Cost priority ---- \n");
return std::make_unique<PriorityInlineOrder>(
std::make_unique<CostPriority>([&](const CallBase *CB) -> InlineCost {
return getInlineCostWrapper(const_cast<CallBase &>(*CB), FAM, Params);
}));
return std::make_unique<PriorityInlineOrder<CostPriority>>(FAM, Params);
default:
llvm_unreachable("Unsupported Inline Priority Mode");