2008-09-03 19:52:17 +00:00
|
|
|
//===- InlineAlways.cpp - Code to inline always_inline functions ----------===//
|
2008-09-03 18:50:53 +00:00
|
|
|
//
|
|
|
|
// The LLVM Compiler Infrastructure
|
|
|
|
//
|
|
|
|
// This file is distributed under the University of Illinois Open Source
|
|
|
|
// License. See LICENSE.TXT for details.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
2008-09-03 19:52:17 +00:00
|
|
|
// This file implements a custom inliner that handles only functions that
|
2008-09-03 20:25:40 +00:00
|
|
|
// are marked as "always inline".
|
2008-09-03 18:50:53 +00:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
#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"
|
2009-10-13 18:30:07 +00:00
|
|
|
#include "llvm/Analysis/InlineCost.h"
|
2008-09-03 18:50:53 +00:00
|
|
|
#include "llvm/Support/CallSite.h"
|
|
|
|
#include "llvm/Transforms/IPO.h"
|
|
|
|
#include "llvm/Transforms/IPO/InlinerPass.h"
|
2011-10-01 01:39:05 +00:00
|
|
|
#include "llvm/Target/TargetData.h"
|
2008-09-03 18:50:53 +00:00
|
|
|
#include "llvm/ADT/SmallPtrSet.h"
|
|
|
|
|
|
|
|
using namespace llvm;
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
|
|
|
// AlwaysInliner only inlines functions that are mark as "always inline".
|
2009-10-25 06:33:48 +00:00
|
|
|
class AlwaysInliner : public Inliner {
|
2008-09-03 18:50:53 +00:00
|
|
|
public:
|
2011-10-01 01:27:56 +00:00
|
|
|
// Use extremely low threshold.
|
2012-02-25 03:07:57 +00:00
|
|
|
AlwaysInliner() : Inliner(ID, -2000000000, /*InsertLifetime*/true) {
|
2012-02-25 02:56:01 +00:00
|
|
|
initializeAlwaysInlinerPass(*PassRegistry::getPassRegistry());
|
|
|
|
}
|
|
|
|
AlwaysInliner(bool InsertLifetime) : Inliner(ID, -2000000000,
|
|
|
|
InsertLifetime) {
|
2010-10-19 17:21:58 +00:00
|
|
|
initializeAlwaysInlinerPass(*PassRegistry::getPassRegistry());
|
|
|
|
}
|
2008-09-03 18:50:53 +00:00
|
|
|
static char ID; // Pass identification, replacement for typeid
|
2012-03-31 13:17:18 +00:00
|
|
|
virtual InlineCost getInlineCost(CallSite CS);
|
2011-10-01 01:27:56 +00:00
|
|
|
virtual bool doFinalization(CallGraph &CG) {
|
Start removing the use of an ad-hoc 'never inline' set and instead
directly query the function information which this set was representing.
This simplifies the interface of the inline cost analysis, and makes the
always-inline pass significantly more efficient.
Previously, always-inline would first make a single set of every
function in the module *except* those marked with the always-inline
attribute. It would then query this set at every call site to see if the
function was a member of the set, and if so, refuse to inline it. This
is quite wasteful. Instead, simply check the function attribute directly
when looking at the callsite.
The normal inliner also had similar redundancy. It added every function
in the module with the noinline attribute to its set to ignore, even
though inside the cost analysis function we *already tested* the
noinline attribute and produced the same result.
The only tricky part of removing this is that we have to be able to
correctly remove only the functions inlined by the always-inline pass
when finalizing, which requires a bit of a hack. Still, much less of
a hack than the set of all non-always-inline functions was. While I was
touching this function, I switched a heavy-weight set to a vector with
sort+unique. The algorithm already had a two-phase insert and removal
pattern, we were just needlessly paying the uniquing cost on every
insert.
This probably speeds up some compiles by a small amount (-O0 compiles
with lots of always-inline, so potentially heavy libc++ users), but I've
not tried to measure it.
I believe there is no functional change here, but yell if you spot one.
None are intended.
Finally, the direction this is going in is to greatly simplify the
inline cost query interface so that we can replace its implementation
with a much more clever one. Along the way, all the APIs get simplified,
so it seems incrementally good.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@152903 91177308-0d34-0410-b5e6-96231b3b80d8
2012-03-16 06:10:13 +00:00
|
|
|
return removeDeadFunctions(CG, /*AlwaysInlineOnly=*/true);
|
2008-11-05 01:39:16 +00:00
|
|
|
}
|
2008-09-03 18:50:53 +00:00
|
|
|
virtual bool doInitialization(CallGraph &CG);
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
char AlwaysInliner::ID = 0;
|
2010-10-19 17:21:58 +00:00
|
|
|
INITIALIZE_PASS_BEGIN(AlwaysInliner, "always-inline",
|
|
|
|
"Inliner for always_inline functions", false, false)
|
|
|
|
INITIALIZE_AG_DEPENDENCY(CallGraph)
|
|
|
|
INITIALIZE_PASS_END(AlwaysInliner, "always-inline",
|
2010-10-07 22:25:06 +00:00
|
|
|
"Inliner for always_inline functions", false, false)
|
2008-09-03 18:50:53 +00:00
|
|
|
|
|
|
|
Pass *llvm::createAlwaysInlinerPass() { return new AlwaysInliner(); }
|
|
|
|
|
2012-02-25 02:56:01 +00:00
|
|
|
Pass *llvm::createAlwaysInlinerPass(bool InsertLifetime) {
|
|
|
|
return new AlwaysInliner(InsertLifetime);
|
|
|
|
}
|
|
|
|
|
2012-03-31 13:17:18 +00:00
|
|
|
/// \brief Minimal filter to detect invalid constructs for inlining.
|
|
|
|
static bool isInlineViable(Function &F) {
|
|
|
|
bool ReturnsTwice = F.hasFnAttr(Attribute::ReturnsTwice);
|
|
|
|
for (Function::iterator BI = F.begin(), BE = F.end(); BI != BE; ++BI) {
|
|
|
|
// Disallow inlining of functions which contain an indirect branch.
|
|
|
|
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;
|
|
|
|
|
|
|
|
// Disallow recursive calls.
|
|
|
|
if (&F == CS.getCalledFunction())
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// Disallow calls which expose returns-twice to a function not previously
|
|
|
|
// attributed as such.
|
2012-04-01 10:21:05 +00:00
|
|
|
if (!ReturnsTwice && CS.isCall() &&
|
2012-03-31 13:17:18 +00:00
|
|
|
cast<CallInst>(CS.getInstruction())->canReturnTwice())
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// \brief Get the inline cost for the always-inliner.
|
|
|
|
///
|
|
|
|
/// The always inliner *only* handles functions which are marked with the
|
|
|
|
/// attribute to force inlining. As such, it is dramatically simpler and avoids
|
|
|
|
/// using the powerful (but expensive) inline cost analysis. Instead it uses
|
|
|
|
/// a very simple and boring direct walk of the instructions looking for
|
|
|
|
/// impossible-to-inline constructs.
|
|
|
|
///
|
|
|
|
/// Note, it would be possible to go to some lengths to cache the information
|
|
|
|
/// computed here, but as we only expect to do this for relatively few and
|
|
|
|
/// small functions which have the explicit attribute to force inlining, it is
|
|
|
|
/// likely not worth it in practice.
|
|
|
|
InlineCost AlwaysInliner::getInlineCost(CallSite CS) {
|
|
|
|
Function *Callee = CS.getCalledFunction();
|
|
|
|
// We assume indirect calls aren't calling an always-inline function.
|
|
|
|
if (!Callee) return InlineCost::getNever();
|
|
|
|
|
|
|
|
// We can't inline calls to external functions.
|
|
|
|
// FIXME: We shouldn't even get here.
|
|
|
|
if (Callee->isDeclaration()) return InlineCost::getNever();
|
|
|
|
|
|
|
|
// Return never for anything not marked as always inline.
|
|
|
|
if (!Callee->hasFnAttr(Attribute::AlwaysInline))
|
|
|
|
return InlineCost::getNever();
|
|
|
|
|
|
|
|
// Do some minimal analysis to preclude non-viable functions.
|
|
|
|
if (!isInlineViable(*Callee))
|
|
|
|
return InlineCost::getNever();
|
|
|
|
|
|
|
|
// Otherwise, force inlining.
|
|
|
|
return InlineCost::getAlways();
|
|
|
|
}
|
|
|
|
|
2011-10-01 01:27:56 +00:00
|
|
|
// doInitialization - Initializes the vector of functions that have not
|
2008-09-03 18:50:53 +00:00
|
|
|
// been annotated with the "always inline" attribute.
|
|
|
|
bool AlwaysInliner::doInitialization(CallGraph &CG) {
|
|
|
|
return false;
|
|
|
|
}
|