llvm-6502/include/llvm/Analysis/InlineCost.h
Chandler Carruth f91f5af802 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

201 lines
7.4 KiB
C++

//===- InlineCost.h - Cost analysis for inliner -----------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements heuristics for inlining decisions.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_ANALYSIS_INLINECOST_H
#define LLVM_ANALYSIS_INLINECOST_H
#include "llvm/Function.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/ValueMap.h"
#include "llvm/Analysis/CodeMetrics.h"
#include <cassert>
#include <climits>
#include <vector>
namespace llvm {
class CallSite;
template<class PtrType, unsigned SmallSize>
class SmallPtrSet;
class TargetData;
namespace InlineConstants {
// Various magic constants used to adjust heuristics.
const int InstrCost = 5;
const int IndirectCallBonus = -100;
const int CallPenalty = 25;
const int LastCallToStaticBonus = -15000;
const int ColdccPenalty = 2000;
const int NoreturnPenalty = 10000;
}
/// InlineCost - Represent the cost of inlining a function. This
/// supports special values for functions which should "always" or
/// "never" be inlined. Otherwise, the cost represents a unitless
/// amount; smaller values increase the likelihood of the function
/// being inlined.
class InlineCost {
enum Kind {
Value,
Always,
Never
};
// This is a do-it-yourself implementation of
// int Cost : 30;
// unsigned Type : 2;
// We used to use bitfields, but they were sometimes miscompiled (PR3822).
enum { TYPE_BITS = 2 };
enum { COST_BITS = unsigned(sizeof(unsigned)) * CHAR_BIT - TYPE_BITS };
unsigned TypedCost; // int Cost : COST_BITS; unsigned Type : TYPE_BITS;
Kind getType() const {
return Kind(TypedCost >> COST_BITS);
}
int getCost() const {
// Sign-extend the bottom COST_BITS bits.
return (int(TypedCost << TYPE_BITS)) >> TYPE_BITS;
}
InlineCost(int C, int T) {
TypedCost = (unsigned(C << TYPE_BITS) >> TYPE_BITS) | (T << COST_BITS);
assert(getCost() == C && "Cost exceeds InlineCost precision");
}
public:
static InlineCost get(int Cost) { return InlineCost(Cost, Value); }
static InlineCost getAlways() { return InlineCost(0, Always); }
static InlineCost getNever() { return InlineCost(0, Never); }
bool isVariable() const { return getType() == Value; }
bool isAlways() const { return getType() == Always; }
bool isNever() const { return getType() == Never; }
/// getValue() - Return a "variable" inline cost's amount. It is
/// an error to call this on an "always" or "never" InlineCost.
int getValue() const {
assert(getType() == Value && "Invalid access of InlineCost");
return getCost();
}
};
/// InlineCostAnalyzer - Cost analyzer used by inliner.
class InlineCostAnalyzer {
struct ArgInfo {
public:
unsigned ConstantWeight;
unsigned AllocaWeight;
ArgInfo(unsigned CWeight, unsigned AWeight)
: ConstantWeight(CWeight), AllocaWeight(AWeight)
{}
};
struct FunctionInfo {
CodeMetrics Metrics;
/// ArgumentWeights - Each formal argument of the function is inspected to
/// see if it is used in any contexts where making it a constant or alloca
/// would reduce the code size. If so, we add some value to the argument
/// entry here.
std::vector<ArgInfo> ArgumentWeights;
/// PointerArgPairWeights - Weights to use when giving an inline bonus to
/// a call site due to correlated pairs of pointers.
DenseMap<std::pair<unsigned, unsigned>, unsigned> PointerArgPairWeights;
/// countCodeReductionForConstant - Figure out an approximation for how
/// many instructions will be constant folded if the specified value is
/// constant.
unsigned countCodeReductionForConstant(const CodeMetrics &Metrics,
Value *V);
/// countCodeReductionForAlloca - Figure out an approximation of how much
/// smaller the function will be if it is inlined into a context where an
/// argument becomes an alloca.
unsigned countCodeReductionForAlloca(const CodeMetrics &Metrics,
Value *V);
/// countCodeReductionForPointerPair - Count the bonus to apply to an
/// inline call site where a pair of arguments are pointers and one
/// argument is a constant offset from the other. The idea is to
/// recognize a common C++ idiom where a begin and end iterator are
/// actually pointers, and many operations on the pair of them will be
/// constants if the function is called with arguments that have
/// a constant offset.
void countCodeReductionForPointerPair(
const CodeMetrics &Metrics,
DenseMap<Value *, unsigned> &PointerArgs,
Value *V, unsigned ArgIdx);
/// analyzeFunction - Add information about the specified function
/// to the current structure.
void analyzeFunction(Function *F, const TargetData *TD);
/// NeverInline - Returns true if the function should never be
/// inlined into any caller.
bool NeverInline();
};
// The Function* for a function can be changed (by ArgumentPromotion);
// the ValueMap will update itself when this happens.
ValueMap<const Function *, FunctionInfo> CachedFunctionInfo;
// TargetData if available, or null.
const TargetData *TD;
int CountBonusForConstant(Value *V, Constant *C = NULL);
int ConstantFunctionBonus(CallSite CS, Constant *C);
int getInlineSize(CallSite CS, Function *Callee);
int getInlineBonuses(CallSite CS, Function *Callee);
public:
InlineCostAnalyzer(): TD(0) {}
void setTargetData(const TargetData *TData) { TD = TData; }
/// getInlineCost - The heuristic used to determine if we should inline the
/// function call or not.
///
InlineCost getInlineCost(CallSite CS);
/// getCalledFunction - The heuristic used to determine if we should inline
/// the function call or not. The callee is explicitly specified, to allow
/// you to calculate the cost of inlining a function via a pointer. The
/// result assumes that the inlined version will always be used. You should
/// weight it yourself in cases where this callee will not always be called.
InlineCost getInlineCost(CallSite CS, Function *Callee);
/// getInlineFudgeFactor - Return a > 1.0 factor if the inliner should use a
/// higher threshold to determine if the function call should be inlined.
float getInlineFudgeFactor(CallSite CS);
/// resetCachedFunctionInfo - erase any cached cost info for this function.
void resetCachedCostInfo(Function* Caller) {
CachedFunctionInfo[Caller] = FunctionInfo();
}
/// growCachedCostInfo - update the cached cost info for Caller after Callee
/// has been inlined. If Callee is NULL it means a dead call has been
/// eliminated.
void growCachedCostInfo(Function* Caller, Function* Callee);
/// clear - empty the cache of inline costs
void clear();
};
/// callIsSmall - If a call is likely to lower to a single target instruction,
/// or is otherwise deemed small return true.
bool callIsSmall(const Function *Callee);
}
#endif