llvm-project/llvm/lib/Transforms/Utils/BasicInliner.cpp

171 lines
5.6 KiB
C++

//===- BasicInliner.cpp - Basic function level inliner --------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file was developed by Devang Patel and is distributed under
// the University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines a simple function based inliner that does not use
// call graph information.
//
//===----------------------------------------------------------------------===//
#define DEBUG_TYPE "basicinliner"
#include "llvm/Module.h"
#include "llvm/Function.h"
#include "llvm/Transforms/Utils/BasicInliner.h"
#include "llvm/Transforms/Utils/Cloning.h"
#include "llvm/Support/CallSite.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h"
#include "llvm/ADT/SmallPtrSet.h"
#include <vector>
using namespace llvm;
namespace {
cl::opt<unsigned>
BasicInlineThreshold("inline-threshold", cl::Hidden, cl::init(200),
cl::desc("Control the amount of basic inlining to perform (default = 200)"));
}
namespace llvm {
/// BasicInlinerImpl - BasicInliner implemantation class. This hides
/// container info, used by basic inliner, from public interface.
struct VISIBILITY_HIDDEN BasicInlinerImpl {
BasicInlinerImpl(const BasicInlinerImpl&); // DO NOT IMPLEMENT
void operator=(const BasicInlinerImpl&); // DO NO IMPLEMENT
public:
BasicInlinerImpl(TargetData *T) : TD(T) {}
/// addFunction - Add function into the list of functions to process.
/// All functions must be inserted using this interface before invoking
/// inlineFunctions().
void addFunction(Function *F) {
Functions.push_back(F);
}
/// neverInlineFunction - Sometimes a function is never to be inlined
/// because of one or other reason.
void neverInlineFunction(Function *F) {
NeverInline.insert(F);
}
/// inlineFuctions - Walk all call sites in all functions supplied by
/// client. Inline as many call sites as possible. Delete completely
/// inlined functions.
void inlineFunctions();
private:
TargetData *TD;
std::vector<Function *> Functions;
SmallPtrSet<const Function *, 16> NeverInline;
SmallPtrSet<Function *, 8> DeadFunctions;
InlineCostAnalyzer CA;
};
/// inlineFuctions - Walk all call sites in all functions supplied by
/// client. Inline as many call sites as possible. Delete completely
/// inlined functions.
void BasicInlinerImpl::inlineFunctions() {
// Scan through and identify all call sites ahead of time so that we only
// inline call sites in the original functions, not call sites that result
// from inlining other functions.
std::vector<CallSite> CallSites;
for (std::vector<Function *>::iterator FI = Functions.begin(),
FE = Functions.end(); FI != FE; ++FI) {
Function *F = *FI;
for (Function::iterator BB = F->begin(), E = F->end(); BB != E; ++BB)
for (BasicBlock::iterator I = BB->begin(); I != BB->end(); ++I) {
CallSite CS = CallSite::get(I);
if (CS.getInstruction() && CS.getCalledFunction()
&& !CS.getCalledFunction()->isDeclaration())
CallSites.push_back(CS);
}
}
DOUT << ": " << CallSites.size() << " call sites.\n";
// Inline call sites.
bool Changed = false;
do {
Changed = false;
for (unsigned index = 0; index != CallSites.size() && !CallSites.empty(); ++index) {
CallSite CS = CallSites[index];
if (Function *Callee = CS.getCalledFunction()) {
// Eliminate calls taht are never inlinable.
if (Callee->isDeclaration() ||
CS.getInstruction()->getParent()->getParent() == Callee) {
CallSites.erase(CallSites.begin() + index);
--index;
continue;
}
int InlineCost = CA.getInlineCost(CS, NeverInline);
if (InlineCost >= (int) BasicInlineThreshold) {
DOUT << " NOT Inlining: cost = " << InlineCost
<< ", call: " << *CS.getInstruction();
continue;
}
DOUT << " Inlining: cost=" << InlineCost
<<", call: " << *CS.getInstruction();
// Inline
if (InlineFunction(CS, NULL, TD)) {
if (Callee->use_empty() && Callee->hasInternalLinkage())
DeadFunctions.insert(Callee);
Changed = true;
CallSites.erase(CallSites.begin() + index);
--index;
}
}
}
} while (Changed);
// Remove completely inlined functions from module.
for(SmallPtrSet<Function *, 8>::iterator I = DeadFunctions.begin(),
E = DeadFunctions.end(); I != E; ++I) {
Function *D = *I;
Module *M = D->getParent();
M->getFunctionList().remove(D);
}
}
BasicInliner::BasicInliner(TargetData *TD) {
Impl = new BasicInlinerImpl(TD);
}
BasicInliner::~BasicInliner() {
delete Impl;
}
/// addFunction - Add function into the list of functions to process.
/// All functions must be inserted using this interface before invoking
/// inlineFunctions().
void BasicInliner::addFunction(Function *F) {
Impl->addFunction(F);
}
/// neverInlineFunction - Sometimes a function is never to be inlined because
/// of one or other reason.
void BasicInliner::neverInlineFunction(Function *F) {
Impl->neverInlineFunction(F);
}
/// inlineFuctions - Walk all call sites in all functions supplied by
/// client. Inline as many call sites as possible. Delete completely
/// inlined functions.
void BasicInliner::inlineFunctions() {
Impl->inlineFunctions();
}
}