We want heuristics to be based on accurate data, but more importantly
we don't want llvm to behave randomly. A benign trunc inserted by an
upstream pass should not cause a wild swings in optimization
level. See PR11034. It's a general problem with threshold-based
heuristics, but we can make it less bad.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@140919
91177308-0d34-0410-b5e6-
96231b3b80d8
#include "llvm/ADT/DenseMap.h"
namespace llvm {
#include "llvm/ADT/DenseMap.h"
namespace llvm {
// CodeMetrics - Calculate size and a few similar metrics for a set of
// basic blocks.
struct CodeMetrics {
// CodeMetrics - Calculate size and a few similar metrics for a set of
// basic blocks.
struct CodeMetrics {
/// analyzeBasicBlock - Add information about the specified basic block
/// to the current structure.
/// analyzeBasicBlock - Add information about the specified basic block
/// to the current structure.
- void analyzeBasicBlock(const BasicBlock *BB);
+ void analyzeBasicBlock(const BasicBlock *BB, const TargetData *TD = 0);
/// analyzeFunction - Add information about the specified function
/// to the current structure.
/// analyzeFunction - Add information about the specified function
/// to the current structure.
- void analyzeFunction(Function *F);
+ void analyzeFunction(Function *F, const TargetData *TD = 0);
/// CountCodeReductionForConstant - Figure out an approximation for how
/// many instructions will be constant folded if the specified value is
/// CountCodeReductionForConstant - Figure out an approximation for how
/// many instructions will be constant folded if the specified value is
class CallSite;
template<class PtrType, unsigned SmallSize>
class SmallPtrSet;
class CallSite;
template<class PtrType, unsigned SmallSize>
class SmallPtrSet;
namespace InlineConstants {
// Various magic constants used to adjust heuristics.
namespace InlineConstants {
// Various magic constants used to adjust heuristics.
/// analyzeFunction - Add information about the specified function
/// to the current structure.
/// analyzeFunction - Add information about the specified function
/// to the current structure.
- void analyzeFunction(Function *F);
+ void analyzeFunction(Function *F, const TargetData *TD);
/// NeverInline - Returns true if the function should never be
/// inlined into any caller.
/// NeverInline - Returns true if the function should never be
/// inlined into any caller.
// the ValueMap will update itself when this happens.
ValueMap<const Function *, FunctionInfo> CachedFunctionInfo;
// 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:
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.
/// getInlineCost - The heuristic used to determine if we should inline the
/// function call or not.
#include "llvm/Support/CallSite.h"
#include "llvm/CallingConv.h"
#include "llvm/IntrinsicInst.h"
#include "llvm/Support/CallSite.h"
#include "llvm/CallingConv.h"
#include "llvm/IntrinsicInst.h"
+#include "llvm/Target/TargetData.h"
#include "llvm/ADT/SmallPtrSet.h"
using namespace llvm;
#include "llvm/ADT/SmallPtrSet.h"
using namespace llvm;
/// analyzeBasicBlock - Fill in the current structure with information gleaned
/// from the specified block.
/// analyzeBasicBlock - Fill in the current structure with information gleaned
/// from the specified block.
-void CodeMetrics::analyzeBasicBlock(const BasicBlock *BB) {
+void CodeMetrics::analyzeBasicBlock(const BasicBlock *BB,
+ const TargetData *TD) {
++NumBlocks;
unsigned NumInstsBeforeThisBB = NumInsts;
for (BasicBlock::const_iterator II = BB->begin(), E = BB->end();
++NumBlocks;
unsigned NumInstsBeforeThisBB = NumInsts;
for (BasicBlock::const_iterator II = BB->begin(), E = BB->end();
if (CI->isLosslessCast() || isa<IntToPtrInst>(CI) ||
isa<PtrToIntInst>(CI))
continue;
if (CI->isLosslessCast() || isa<IntToPtrInst>(CI) ||
isa<PtrToIntInst>(CI))
continue;
+ // trunc to a native type is free (assuming the target has compare and
+ // shift-right of the same width).
+ if (isa<TruncInst>(CI) && TD &&
+ TD->isLegalInteger(TD->getTypeSizeInBits(CI->getType())))
+ continue;
// Result of a cmp instruction is often extended (to be used by other
// cmp instructions, logical or return instructions). These are usually
// nop on most sane targets.
// Result of a cmp instruction is often extended (to be used by other
// cmp instructions, logical or return instructions). These are usually
// nop on most sane targets.
/// analyzeFunction - Fill in the current structure with information gleaned
/// from the specified function.
/// analyzeFunction - Fill in the current structure with information gleaned
/// from the specified function.
-void CodeMetrics::analyzeFunction(Function *F) {
+void CodeMetrics::analyzeFunction(Function *F, const TargetData *TD) {
// If this function contains a call to setjmp or _setjmp, never inline
// it. This is a hack because we depend on the user marking their local
// variables as volatile if they are live across a setjmp call, and they
// If this function contains a call to setjmp or _setjmp, never inline
// it. This is a hack because we depend on the user marking their local
// variables as volatile if they are live across a setjmp call, and they
// Look at the size of the callee.
for (Function::const_iterator BB = F->begin(), E = F->end(); BB != E; ++BB)
// Look at the size of the callee.
for (Function::const_iterator BB = F->begin(), E = F->end(); BB != E; ++BB)
- analyzeBasicBlock(&*BB);
+ analyzeBasicBlock(&*BB, TD);
}
/// analyzeFunction - Fill in the current structure with information gleaned
/// from the specified function.
}
/// analyzeFunction - Fill in the current structure with information gleaned
/// from the specified function.
-void InlineCostAnalyzer::FunctionInfo::analyzeFunction(Function *F) {
- Metrics.analyzeFunction(F);
+void InlineCostAnalyzer::FunctionInfo::analyzeFunction(Function *F,
+ const TargetData *TD) {
+ Metrics.analyzeFunction(F, TD);
// A function with exactly one return has it removed during the inlining
// process (see InlineFunction), so don't count it.
// A function with exactly one return has it removed during the inlining
// process (see InlineFunction), so don't count it.
// If we haven't calculated this information yet, do so now.
if (CalleeFI->Metrics.NumBlocks == 0)
// If we haven't calculated this information yet, do so now.
if (CalleeFI->Metrics.NumBlocks == 0)
- CalleeFI->analyzeFunction(Callee);
+ CalleeFI->analyzeFunction(Callee, TD);
unsigned ArgNo = 0;
unsigned i = 0;
unsigned ArgNo = 0;
unsigned i = 0;
// If we haven't calculated this information yet, do so now.
if (CalleeFI->Metrics.NumBlocks == 0)
// If we haven't calculated this information yet, do so now.
if (CalleeFI->Metrics.NumBlocks == 0)
- CalleeFI->analyzeFunction(Callee);
+ CalleeFI->analyzeFunction(Callee, TD);
// InlineCost - This value measures how good of an inline candidate this call
// site is to inline. A lower inline cost make is more likely for the call to
// InlineCost - This value measures how good of an inline candidate this call
// site is to inline. A lower inline cost make is more likely for the call to
// If we haven't calculated this information yet, do so now.
if (CalleeFI->Metrics.NumBlocks == 0)
// If we haven't calculated this information yet, do so now.
if (CalleeFI->Metrics.NumBlocks == 0)
- CalleeFI->analyzeFunction(Callee);
+ CalleeFI->analyzeFunction(Callee, TD);
bool isDirectCall = CS.getCalledFunction() == Callee;
Instruction *TheCall = CS.getInstruction();
bool isDirectCall = CS.getCalledFunction() == Callee;
Instruction *TheCall = CS.getInstruction();
// If we haven't calculated this information yet, do so now.
if (CalleeFI->Metrics.NumBlocks == 0)
// If we haven't calculated this information yet, do so now.
if (CalleeFI->Metrics.NumBlocks == 0)
- CalleeFI->analyzeFunction(Callee);
+ CalleeFI->analyzeFunction(Callee, TD);
// If we should never inline this, return a huge cost.
if (CalleeFI->NeverInline())
// If we should never inline this, return a huge cost.
if (CalleeFI->NeverInline())
// If we haven't calculated this information yet, do so now.
if (CallerFI.Metrics.NumBlocks == 0) {
// If we haven't calculated this information yet, do so now.
if (CallerFI.Metrics.NumBlocks == 0) {
- CallerFI.analyzeFunction(Caller);
+ CallerFI.analyzeFunction(Caller, TD);
// Recompute the CalleeFI pointer, getting Caller could have invalidated
// it.
// Recompute the CalleeFI pointer, getting Caller could have invalidated
// it.
// If we haven't calculated this information yet, do so now.
if (CalleeFI->Metrics.NumBlocks == 0)
// If we haven't calculated this information yet, do so now.
if (CalleeFI->Metrics.NumBlocks == 0)
- CalleeFI->analyzeFunction(Callee);
+ CalleeFI->analyzeFunction(Callee, TD);
// If we haven't calculated this information yet, do so now.
if (CalleeFI.Metrics.NumBlocks == 0)
// If we haven't calculated this information yet, do so now.
if (CalleeFI.Metrics.NumBlocks == 0)
- CalleeFI.analyzeFunction(Callee);
+ CalleeFI.analyzeFunction(Callee, TD);
float Factor = 1.0f;
// Single BB functions are often written to be inlined.
float Factor = 1.0f;
// Single BB functions are often written to be inlined.
#include "llvm/Support/CallSite.h"
#include "llvm/Transforms/IPO.h"
#include "llvm/Transforms/IPO/InlinerPass.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;
#include "llvm/ADT/SmallPtrSet.h"
using namespace llvm;
// doInitialization - Initializes the vector of functions that have not
// been annotated with the "always inline" attribute.
bool AlwaysInliner::doInitialization(CallGraph &CG) {
// doInitialization - Initializes the vector of functions that have not
// been annotated with the "always inline" attribute.
bool AlwaysInliner::doInitialization(CallGraph &CG) {
+ CA.setTargetData(getAnalysisIfAvailable<TargetData>());
+
Module &M = CG.getModule();
for (Module::iterator I = M.begin(), E = M.end();
Module &M = CG.getModule();
for (Module::iterator I = M.begin(), E = M.end();
#include "llvm/Support/CallSite.h"
#include "llvm/Transforms/IPO.h"
#include "llvm/Transforms/IPO/InlinerPass.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;
#include "llvm/ADT/SmallPtrSet.h"
using namespace llvm;
// doInitialization - Initializes the vector of functions that have been
// annotated with the noinline attribute.
bool SimpleInliner::doInitialization(CallGraph &CG) {
// doInitialization - Initializes the vector of functions that have been
// annotated with the noinline attribute.
bool SimpleInliner::doInitialization(CallGraph &CG) {
+ CA.setTargetData(getAnalysisIfAvailable<TargetData>());
Module &M = CG.getModule();
Module &M = CG.getModule();
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Transforms/Utils/UnrollLoop.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Transforms/Utils/UnrollLoop.h"
+#include "llvm/Target/TargetData.h"
#include <climits>
using namespace llvm;
#include <climits>
using namespace llvm;
}
/// ApproximateLoopSize - Approximate the size of the loop.
}
/// ApproximateLoopSize - Approximate the size of the loop.
-static unsigned ApproximateLoopSize(const Loop *L, unsigned &NumCalls) {
+static unsigned ApproximateLoopSize(const Loop *L, unsigned &NumCalls,
+ const TargetData *TD) {
CodeMetrics Metrics;
for (Loop::block_iterator I = L->block_begin(), E = L->block_end();
I != E; ++I)
CodeMetrics Metrics;
for (Loop::block_iterator I = L->block_begin(), E = L->block_end();
I != E; ++I)
- Metrics.analyzeBasicBlock(*I);
+ Metrics.analyzeBasicBlock(*I, TD);
NumCalls = Metrics.NumInlineCandidates;
unsigned LoopSize = Metrics.NumInsts;
NumCalls = Metrics.NumInlineCandidates;
unsigned LoopSize = Metrics.NumInsts;
// Enforce the threshold.
if (Threshold != NoThreshold) {
// Enforce the threshold.
if (Threshold != NoThreshold) {
+ const TargetData *TD = getAnalysisIfAvailable<TargetData>();
unsigned NumInlineCandidates;
unsigned NumInlineCandidates;
- unsigned LoopSize = ApproximateLoopSize(L, NumInlineCandidates);
+ unsigned LoopSize = ApproximateLoopSize(L, NumInlineCandidates, TD);
DEBUG(dbgs() << " Loop Size = " << LoopSize << "\n");
if (NumInlineCandidates != 0) {
DEBUG(dbgs() << " Not unrolling loop with inlinable calls.\n");
DEBUG(dbgs() << " Loop Size = " << LoopSize << "\n");
if (NumInlineCandidates != 0) {
DEBUG(dbgs() << " Not unrolling loop with inlinable calls.\n");