#define DEBUG_TYPE "inline"
#include "llvm/CallingConv.h"
#include "llvm/Instructions.h"
#include "llvm/IntrinsicInst.h"
#include "llvm/Module.h"
#include "llvm/Type.h"
#include "llvm/Analysis/CallGraph.h"
#include "llvm/Analysis/InlineCost.h"
#include "llvm/Support/CallSite.h"
#include "llvm/Transforms/IPO.h"
#include "llvm/Transforms/IPO/InlinerPass.h"
#include "llvm/Target/TargetData.h"
#include "llvm/ADT/SmallPtrSet.h"
using namespace llvm;
namespace {
class AlwaysInliner : public Inliner {
public:
AlwaysInliner() : Inliner(ID, -2000000000, true) {
initializeAlwaysInlinerPass(*PassRegistry::getPassRegistry());
}
AlwaysInliner(bool InsertLifetime) : Inliner(ID, -2000000000,
InsertLifetime) {
initializeAlwaysInlinerPass(*PassRegistry::getPassRegistry());
}
static char ID; virtual InlineCost getInlineCost(CallSite CS);
virtual bool doFinalization(CallGraph &CG) {
return removeDeadFunctions(CG, true);
}
virtual bool doInitialization(CallGraph &CG);
};
}
char AlwaysInliner::ID = 0;
INITIALIZE_PASS_BEGIN(AlwaysInliner, "always-inline",
"Inliner for always_inline functions", false, false)
INITIALIZE_AG_DEPENDENCY(CallGraph)
INITIALIZE_PASS_END(AlwaysInliner, "always-inline",
"Inliner for always_inline functions", false, false)
Pass *llvm::createAlwaysInlinerPass() { return new AlwaysInliner(); }
Pass *llvm::createAlwaysInlinerPass(bool InsertLifetime) {
return new AlwaysInliner(InsertLifetime);
}
static bool isInlineViable(Function &F) {
bool ReturnsTwice = F.getFnAttributes().hasReturnsTwiceAttr();
for (Function::iterator BI = F.begin(), BE = F.end(); BI != BE; ++BI) {
if (isa<IndirectBrInst>(BI->getTerminator()))
return false;
for (BasicBlock::iterator II = BI->begin(), IE = BI->end(); II != IE;
++II) {
CallSite CS(II);
if (!CS)
continue;
if (&F == CS.getCalledFunction())
return false;
if (!ReturnsTwice && CS.isCall() &&
cast<CallInst>(CS.getInstruction())->canReturnTwice())
return false;
}
}
return true;
}
InlineCost AlwaysInliner::getInlineCost(CallSite CS) {
Function *Callee = CS.getCalledFunction();
if (!Callee) return InlineCost::getNever();
if (Callee->isDeclaration()) return InlineCost::getNever();
if (!Callee->getFnAttributes().hasAlwaysInlineAttr())
return InlineCost::getNever();
if (!isInlineViable(*Callee))
return InlineCost::getNever();
return InlineCost::getAlways();
}
bool AlwaysInliner::doInitialization(CallGraph &CG) {
return false;
}