forked from OSchip/llvm-project
Inlining and unrolling heuristics should be aware of free truncs.
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. llvm-svn: 140919
This commit is contained in:
parent
cfebbcfedd
commit
f7656015fc
|
@ -18,6 +18,9 @@
|
||||||
#include "llvm/ADT/DenseMap.h"
|
#include "llvm/ADT/DenseMap.h"
|
||||||
|
|
||||||
namespace llvm {
|
namespace llvm {
|
||||||
|
|
||||||
|
class TargetData;
|
||||||
|
|
||||||
// CodeMetrics - Calculate size and a few similar metrics for a set of
|
// CodeMetrics - Calculate size and a few similar metrics for a set of
|
||||||
// basic blocks.
|
// basic blocks.
|
||||||
struct CodeMetrics {
|
struct CodeMetrics {
|
||||||
|
@ -68,11 +71,11 @@ namespace llvm {
|
||||||
|
|
||||||
/// analyzeBasicBlock - Add information about the specified basic block
|
/// analyzeBasicBlock - Add information about the specified basic block
|
||||||
/// to the current structure.
|
/// 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
|
/// analyzeFunction - Add information about the specified function
|
||||||
/// to the current structure.
|
/// to the current structure.
|
||||||
void analyzeFunction(Function *F);
|
void analyzeFunction(Function *F, const TargetData *TD = 0);
|
||||||
|
|
||||||
/// CountCodeReductionForConstant - Figure out an approximation for how
|
/// CountCodeReductionForConstant - Figure out an approximation for how
|
||||||
/// many instructions will be constant folded if the specified value is
|
/// many instructions will be constant folded if the specified value is
|
||||||
|
|
|
@ -29,6 +29,7 @@ namespace llvm {
|
||||||
class CallSite;
|
class CallSite;
|
||||||
template<class PtrType, unsigned SmallSize>
|
template<class PtrType, unsigned SmallSize>
|
||||||
class SmallPtrSet;
|
class SmallPtrSet;
|
||||||
|
class TargetData;
|
||||||
|
|
||||||
namespace InlineConstants {
|
namespace InlineConstants {
|
||||||
// Various magic constants used to adjust heuristics.
|
// Various magic constants used to adjust heuristics.
|
||||||
|
@ -113,7 +114,7 @@ namespace llvm {
|
||||||
|
|
||||||
/// analyzeFunction - Add information about the specified function
|
/// analyzeFunction - Add information about the specified function
|
||||||
/// to the current structure.
|
/// to the current structure.
|
||||||
void analyzeFunction(Function *F);
|
void analyzeFunction(Function *F, const TargetData *TD);
|
||||||
|
|
||||||
/// NeverInline - Returns true if the function should never be
|
/// NeverInline - Returns true if the function should never be
|
||||||
/// inlined into any caller.
|
/// inlined into any caller.
|
||||||
|
@ -124,11 +125,17 @@ namespace llvm {
|
||||||
// the ValueMap will update itself when this happens.
|
// the ValueMap will update itself when this happens.
|
||||||
ValueMap<const Function *, FunctionInfo> CachedFunctionInfo;
|
ValueMap<const Function *, FunctionInfo> CachedFunctionInfo;
|
||||||
|
|
||||||
|
// TargetData if available, or null.
|
||||||
|
const TargetData *TD;
|
||||||
|
|
||||||
int CountBonusForConstant(Value *V, Constant *C = NULL);
|
int CountBonusForConstant(Value *V, Constant *C = NULL);
|
||||||
int ConstantFunctionBonus(CallSite CS, Constant *C);
|
int ConstantFunctionBonus(CallSite CS, Constant *C);
|
||||||
int getInlineSize(CallSite CS, Function *Callee);
|
int getInlineSize(CallSite CS, Function *Callee);
|
||||||
int getInlineBonuses(CallSite CS, Function *Callee);
|
int getInlineBonuses(CallSite CS, Function *Callee);
|
||||||
public:
|
public:
|
||||||
|
InlineCostAnalyzer(): TD(0) {}
|
||||||
|
|
||||||
|
void setTargetData(const TargetData *TData) { TD = TData; }
|
||||||
|
|
||||||
/// getInlineCost - The heuristic used to determine if we should inline the
|
/// getInlineCost - The heuristic used to determine if we should inline the
|
||||||
/// function call or not.
|
/// function call or not.
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
#include "llvm/Support/CallSite.h"
|
#include "llvm/Support/CallSite.h"
|
||||||
#include "llvm/CallingConv.h"
|
#include "llvm/CallingConv.h"
|
||||||
#include "llvm/IntrinsicInst.h"
|
#include "llvm/IntrinsicInst.h"
|
||||||
|
#include "llvm/Target/TargetData.h"
|
||||||
#include "llvm/ADT/SmallPtrSet.h"
|
#include "llvm/ADT/SmallPtrSet.h"
|
||||||
|
|
||||||
using namespace llvm;
|
using namespace llvm;
|
||||||
|
@ -52,7 +53,8 @@ bool llvm::callIsSmall(const Function *F) {
|
||||||
|
|
||||||
/// analyzeBasicBlock - Fill in the current structure with information gleaned
|
/// analyzeBasicBlock - Fill in the current structure with information gleaned
|
||||||
/// from the specified block.
|
/// from the specified block.
|
||||||
void CodeMetrics::analyzeBasicBlock(const BasicBlock *BB) {
|
void CodeMetrics::analyzeBasicBlock(const BasicBlock *BB,
|
||||||
|
const TargetData *TD) {
|
||||||
++NumBlocks;
|
++NumBlocks;
|
||||||
unsigned NumInstsBeforeThisBB = NumInsts;
|
unsigned NumInstsBeforeThisBB = NumInsts;
|
||||||
for (BasicBlock::const_iterator II = BB->begin(), E = BB->end();
|
for (BasicBlock::const_iterator II = BB->begin(), E = BB->end();
|
||||||
|
@ -105,6 +107,11 @@ void CodeMetrics::analyzeBasicBlock(const BasicBlock *BB) {
|
||||||
if (CI->isLosslessCast() || isa<IntToPtrInst>(CI) ||
|
if (CI->isLosslessCast() || isa<IntToPtrInst>(CI) ||
|
||||||
isa<PtrToIntInst>(CI))
|
isa<PtrToIntInst>(CI))
|
||||||
continue;
|
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
|
// Result of a cmp instruction is often extended (to be used by other
|
||||||
// cmp instructions, logical or return instructions). These are usually
|
// cmp instructions, logical or return instructions). These are usually
|
||||||
// nop on most sane targets.
|
// nop on most sane targets.
|
||||||
|
@ -217,7 +224,7 @@ unsigned CodeMetrics::CountCodeReductionForAlloca(Value *V) {
|
||||||
|
|
||||||
/// analyzeFunction - Fill in the current structure with information gleaned
|
/// analyzeFunction - Fill in the current structure with information gleaned
|
||||||
/// from the specified function.
|
/// 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
|
// 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
|
// 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
|
// variables as volatile if they are live across a setjmp call, and they
|
||||||
|
@ -227,13 +234,14 @@ void CodeMetrics::analyzeFunction(Function *F) {
|
||||||
|
|
||||||
// Look at the size of the callee.
|
// Look at the size of the callee.
|
||||||
for (Function::const_iterator BB = F->begin(), E = F->end(); BB != E; ++BB)
|
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
|
/// analyzeFunction - Fill in the current structure with information gleaned
|
||||||
/// from the specified function.
|
/// from the specified function.
|
||||||
void InlineCostAnalyzer::FunctionInfo::analyzeFunction(Function *F) {
|
void InlineCostAnalyzer::FunctionInfo::analyzeFunction(Function *F,
|
||||||
Metrics.analyzeFunction(F);
|
const TargetData *TD) {
|
||||||
|
Metrics.analyzeFunction(F, TD);
|
||||||
|
|
||||||
// A function with exactly one return has it removed during the inlining
|
// A function with exactly one return has it removed during the inlining
|
||||||
// process (see InlineFunction), so don't count it.
|
// process (see InlineFunction), so don't count it.
|
||||||
|
@ -275,7 +283,7 @@ int InlineCostAnalyzer::getSpecializationBonus(Function *Callee,
|
||||||
|
|
||||||
// If we haven't calculated this information yet, do so now.
|
// If we haven't calculated this information yet, do so now.
|
||||||
if (CalleeFI->Metrics.NumBlocks == 0)
|
if (CalleeFI->Metrics.NumBlocks == 0)
|
||||||
CalleeFI->analyzeFunction(Callee);
|
CalleeFI->analyzeFunction(Callee, TD);
|
||||||
|
|
||||||
unsigned ArgNo = 0;
|
unsigned ArgNo = 0;
|
||||||
unsigned i = 0;
|
unsigned i = 0;
|
||||||
|
@ -365,7 +373,7 @@ int InlineCostAnalyzer::getInlineSize(CallSite CS, Function *Callee) {
|
||||||
|
|
||||||
// If we haven't calculated this information yet, do so now.
|
// If we haven't calculated this information yet, do so now.
|
||||||
if (CalleeFI->Metrics.NumBlocks == 0)
|
if (CalleeFI->Metrics.NumBlocks == 0)
|
||||||
CalleeFI->analyzeFunction(Callee);
|
CalleeFI->analyzeFunction(Callee, TD);
|
||||||
|
|
||||||
// InlineCost - This value measures how good of an inline candidate this call
|
// 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
|
// site is to inline. A lower inline cost make is more likely for the call to
|
||||||
|
@ -418,7 +426,7 @@ int InlineCostAnalyzer::getInlineBonuses(CallSite CS, Function *Callee) {
|
||||||
|
|
||||||
// If we haven't calculated this information yet, do so now.
|
// If we haven't calculated this information yet, do so now.
|
||||||
if (CalleeFI->Metrics.NumBlocks == 0)
|
if (CalleeFI->Metrics.NumBlocks == 0)
|
||||||
CalleeFI->analyzeFunction(Callee);
|
CalleeFI->analyzeFunction(Callee, TD);
|
||||||
|
|
||||||
bool isDirectCall = CS.getCalledFunction() == Callee;
|
bool isDirectCall = CS.getCalledFunction() == Callee;
|
||||||
Instruction *TheCall = CS.getInstruction();
|
Instruction *TheCall = CS.getInstruction();
|
||||||
|
@ -486,7 +494,7 @@ InlineCost InlineCostAnalyzer::getInlineCost(CallSite CS,
|
||||||
|
|
||||||
// If we haven't calculated this information yet, do so now.
|
// If we haven't calculated this information yet, do so now.
|
||||||
if (CalleeFI->Metrics.NumBlocks == 0)
|
if (CalleeFI->Metrics.NumBlocks == 0)
|
||||||
CalleeFI->analyzeFunction(Callee);
|
CalleeFI->analyzeFunction(Callee, TD);
|
||||||
|
|
||||||
// If we should never inline this, return a huge cost.
|
// If we should never inline this, return a huge cost.
|
||||||
if (CalleeFI->NeverInline())
|
if (CalleeFI->NeverInline())
|
||||||
|
@ -505,7 +513,7 @@ InlineCost InlineCostAnalyzer::getInlineCost(CallSite CS,
|
||||||
|
|
||||||
// If we haven't calculated this information yet, do so now.
|
// If we haven't calculated this information yet, do so now.
|
||||||
if (CallerFI.Metrics.NumBlocks == 0) {
|
if (CallerFI.Metrics.NumBlocks == 0) {
|
||||||
CallerFI.analyzeFunction(Caller);
|
CallerFI.analyzeFunction(Caller, TD);
|
||||||
|
|
||||||
// Recompute the CalleeFI pointer, getting Caller could have invalidated
|
// Recompute the CalleeFI pointer, getting Caller could have invalidated
|
||||||
// it.
|
// it.
|
||||||
|
@ -544,7 +552,7 @@ InlineCost InlineCostAnalyzer::getSpecializationCost(Function *Callee,
|
||||||
|
|
||||||
// If we haven't calculated this information yet, do so now.
|
// If we haven't calculated this information yet, do so now.
|
||||||
if (CalleeFI->Metrics.NumBlocks == 0)
|
if (CalleeFI->Metrics.NumBlocks == 0)
|
||||||
CalleeFI->analyzeFunction(Callee);
|
CalleeFI->analyzeFunction(Callee, TD);
|
||||||
|
|
||||||
int Cost = 0;
|
int Cost = 0;
|
||||||
|
|
||||||
|
@ -570,7 +578,7 @@ float InlineCostAnalyzer::getInlineFudgeFactor(CallSite CS) {
|
||||||
|
|
||||||
// If we haven't calculated this information yet, do so now.
|
// If we haven't calculated this information yet, do so now.
|
||||||
if (CalleeFI.Metrics.NumBlocks == 0)
|
if (CalleeFI.Metrics.NumBlocks == 0)
|
||||||
CalleeFI.analyzeFunction(Callee);
|
CalleeFI.analyzeFunction(Callee, TD);
|
||||||
|
|
||||||
float Factor = 1.0f;
|
float Factor = 1.0f;
|
||||||
// Single BB functions are often written to be inlined.
|
// Single BB functions are often written to be inlined.
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
#include "llvm/Support/CallSite.h"
|
#include "llvm/Support/CallSite.h"
|
||||||
#include "llvm/Transforms/IPO.h"
|
#include "llvm/Transforms/IPO.h"
|
||||||
#include "llvm/Transforms/IPO/InlinerPass.h"
|
#include "llvm/Transforms/IPO/InlinerPass.h"
|
||||||
|
#include "llvm/Target/TargetData.h"
|
||||||
#include "llvm/ADT/SmallPtrSet.h"
|
#include "llvm/ADT/SmallPtrSet.h"
|
||||||
|
|
||||||
using namespace llvm;
|
using namespace llvm;
|
||||||
|
@ -74,6 +75,8 @@ Pass *llvm::createAlwaysInlinerPass() { return new AlwaysInliner(); }
|
||||||
// doInitialization - Initializes the vector of functions that have not
|
// doInitialization - Initializes the vector of functions that have not
|
||||||
// been annotated with the "always inline" attribute.
|
// been annotated with the "always inline" attribute.
|
||||||
bool AlwaysInliner::doInitialization(CallGraph &CG) {
|
bool AlwaysInliner::doInitialization(CallGraph &CG) {
|
||||||
|
CA.setTargetData(getAnalysisIfAvailable<TargetData>());
|
||||||
|
|
||||||
Module &M = CG.getModule();
|
Module &M = CG.getModule();
|
||||||
|
|
||||||
for (Module::iterator I = M.begin(), E = M.end();
|
for (Module::iterator I = M.begin(), E = M.end();
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
#include "llvm/Support/CallSite.h"
|
#include "llvm/Support/CallSite.h"
|
||||||
#include "llvm/Transforms/IPO.h"
|
#include "llvm/Transforms/IPO.h"
|
||||||
#include "llvm/Transforms/IPO/InlinerPass.h"
|
#include "llvm/Transforms/IPO/InlinerPass.h"
|
||||||
|
#include "llvm/Target/TargetData.h"
|
||||||
#include "llvm/ADT/SmallPtrSet.h"
|
#include "llvm/ADT/SmallPtrSet.h"
|
||||||
|
|
||||||
using namespace llvm;
|
using namespace llvm;
|
||||||
|
@ -75,6 +76,7 @@ Pass *llvm::createFunctionInliningPass(int Threshold) {
|
||||||
// doInitialization - Initializes the vector of functions that have been
|
// doInitialization - Initializes the vector of functions that have been
|
||||||
// annotated with the noinline attribute.
|
// annotated with the noinline attribute.
|
||||||
bool SimpleInliner::doInitialization(CallGraph &CG) {
|
bool SimpleInliner::doInitialization(CallGraph &CG) {
|
||||||
|
CA.setTargetData(getAnalysisIfAvailable<TargetData>());
|
||||||
|
|
||||||
Module &M = CG.getModule();
|
Module &M = CG.getModule();
|
||||||
|
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
#include "llvm/Support/Debug.h"
|
#include "llvm/Support/Debug.h"
|
||||||
#include "llvm/Support/raw_ostream.h"
|
#include "llvm/Support/raw_ostream.h"
|
||||||
#include "llvm/Transforms/Utils/UnrollLoop.h"
|
#include "llvm/Transforms/Utils/UnrollLoop.h"
|
||||||
|
#include "llvm/Target/TargetData.h"
|
||||||
#include <climits>
|
#include <climits>
|
||||||
|
|
||||||
using namespace llvm;
|
using namespace llvm;
|
||||||
|
@ -107,11 +108,12 @@ Pass *llvm::createLoopUnrollPass(int Threshold, int Count, int AllowPartial) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 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;
|
CodeMetrics Metrics;
|
||||||
for (Loop::block_iterator I = L->block_begin(), E = L->block_end();
|
for (Loop::block_iterator I = L->block_begin(), E = L->block_end();
|
||||||
I != E; ++I)
|
I != E; ++I)
|
||||||
Metrics.analyzeBasicBlock(*I);
|
Metrics.analyzeBasicBlock(*I, TD);
|
||||||
NumCalls = Metrics.NumInlineCandidates;
|
NumCalls = Metrics.NumInlineCandidates;
|
||||||
|
|
||||||
unsigned LoopSize = Metrics.NumInsts;
|
unsigned LoopSize = Metrics.NumInsts;
|
||||||
|
@ -174,8 +176,9 @@ bool LoopUnroll::runOnLoop(Loop *L, LPPassManager &LPM) {
|
||||||
|
|
||||||
// Enforce the threshold.
|
// Enforce the threshold.
|
||||||
if (Threshold != NoThreshold) {
|
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");
|
DEBUG(dbgs() << " Loop Size = " << LoopSize << "\n");
|
||||||
if (NumInlineCandidates != 0) {
|
if (NumInlineCandidates != 0) {
|
||||||
DEBUG(dbgs() << " Not unrolling loop with inlinable calls.\n");
|
DEBUG(dbgs() << " Not unrolling loop with inlinable calls.\n");
|
||||||
|
|
Loading…
Reference in New Issue