summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/llvm/Analysis/CodeMetrics.h72
-rw-r--r--include/llvm/Analysis/InlineCost.h45
-rw-r--r--lib/Analysis/InlineCost.cpp27
-rw-r--r--lib/Transforms/Scalar/LoopUnswitch.cpp2
4 files changed, 98 insertions, 48 deletions
diff --git a/include/llvm/Analysis/CodeMetrics.h b/include/llvm/Analysis/CodeMetrics.h
new file mode 100644
index 0000000..58096f1
--- /dev/null
+++ b/include/llvm/Analysis/CodeMetrics.h
@@ -0,0 +1,72 @@
+//===- CodeMetrics.h - Measures the weight of a function---------*- 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 various weight measurements for a function, helping
+// the Inliner and PartialSpecialization decide whether to duplicate its
+// contents.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_ANALYSIS_CODEMETRICS_H
+#define LLVM_ANALYSIS_CODEMETRICS_H
+
+namespace llvm {
+ // CodeMetrics - Calculate size and a few similar metrics for a set of
+ // basic blocks.
+ struct CodeMetrics {
+ /// NeverInline - True if this callee should never be inlined into a
+ /// caller.
+ // bool NeverInline;
+
+ // True if this function contains a call to setjmp or _setjmp
+ bool callsSetJmp;
+
+ // True if this function calls itself
+ bool isRecursive;
+
+ // True if this function contains one or more indirect branches
+ bool containsIndirectBr;
+
+ /// usesDynamicAlloca - True if this function calls alloca (in the C sense).
+ bool usesDynamicAlloca;
+
+ /// NumInsts, NumBlocks - Keep track of how large each function is, which
+ /// is used to estimate the code size cost of inlining it.
+ unsigned NumInsts, NumBlocks;
+
+ /// NumBBInsts - Keeps track of basic block code size estimates.
+ DenseMap<const BasicBlock *, unsigned> NumBBInsts;
+
+ /// NumCalls - Keep track of the number of calls to 'big' functions.
+ unsigned NumCalls;
+
+ /// NumVectorInsts - Keep track of how many instructions produce vector
+ /// values. The inliner is being more aggressive with inlining vector
+ /// kernels.
+ unsigned NumVectorInsts;
+
+ /// NumRets - Keep track of how many Ret instructions the block contains.
+ unsigned NumRets;
+
+ CodeMetrics() : callsSetJmp(false), isRecursive(false),
+ containsIndirectBr(false), usesDynamicAlloca(false),
+ NumInsts(0), NumBlocks(0), NumCalls(0), NumVectorInsts(0),
+ NumRets(0) {}
+
+ /// analyzeBasicBlock - Add information about the specified basic block
+ /// to the current structure.
+ void analyzeBasicBlock(const BasicBlock *BB);
+
+ /// analyzeFunction - Add information about the specified function
+ /// to the current structure.
+ void analyzeFunction(Function *F);
+ };
+}
+
+#endif
diff --git a/include/llvm/Analysis/InlineCost.h b/include/llvm/Analysis/InlineCost.h
index cac7cfe..462bddd 100644
--- a/include/llvm/Analysis/InlineCost.h
+++ b/include/llvm/Analysis/InlineCost.h
@@ -19,6 +19,7 @@
#include <vector>
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/ValueMap.h"
+#include "llvm/Analysis/CodeMetrics.h"
namespace llvm {
@@ -29,46 +30,6 @@ namespace llvm {
template<class PtrType, unsigned SmallSize>
class SmallPtrSet;
- // CodeMetrics - Calculate size and a few similar metrics for a set of
- // basic blocks.
- struct CodeMetrics {
- /// NeverInline - True if this callee should never be inlined into a
- /// caller.
- bool NeverInline;
-
- /// usesDynamicAlloca - True if this function calls alloca (in the C sense).
- bool usesDynamicAlloca;
-
- /// NumInsts, NumBlocks - Keep track of how large each function is, which
- /// is used to estimate the code size cost of inlining it.
- unsigned NumInsts, NumBlocks;
-
- /// NumBBInsts - Keeps track of basic block code size estimates.
- DenseMap<const BasicBlock *, unsigned> NumBBInsts;
-
- /// NumCalls - Keep track of the number of calls to 'big' functions.
- unsigned NumCalls;
-
- /// NumVectorInsts - Keep track of how many instructions produce vector
- /// values. The inliner is being more aggressive with inlining vector
- /// kernels.
- unsigned NumVectorInsts;
-
- /// NumRets - Keep track of how many Ret instructions the block contains.
- unsigned NumRets;
-
- CodeMetrics() : NeverInline(false), usesDynamicAlloca(false), NumInsts(0),
- NumBlocks(0), NumCalls(0), NumVectorInsts(0), NumRets(0) {}
-
- /// analyzeBasicBlock - Add information about the specified basic block
- /// to the current structure.
- void analyzeBasicBlock(const BasicBlock *BB);
-
- /// analyzeFunction - Add information about the specified function
- /// to the current structure.
- void analyzeFunction(Function *F);
- };
-
namespace InlineConstants {
// Various magic constants used to adjust heuristics.
const int InstrCost = 5;
@@ -163,6 +124,10 @@ namespace llvm {
/// analyzeFunction - Add information about the specified function
/// to the current structure.
void analyzeFunction(Function *F);
+
+ /// 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);
diff --git a/lib/Analysis/InlineCost.cpp b/lib/Analysis/InlineCost.cpp
index 98dbb69..b1df517 100644
--- a/lib/Analysis/InlineCost.cpp
+++ b/lib/Analysis/InlineCost.cpp
@@ -162,14 +162,14 @@ void CodeMetrics::analyzeBasicBlock(const BasicBlock *BB) {
if (Function *F = CS.getCalledFunction()) {
if (F->isDeclaration() &&
(F->getName() == "setjmp" || F->getName() == "_setjmp"))
- NeverInline = true;
+ callsSetJmp = true;
// If this call is to function itself, then the function is recursive.
// Inlining it into other functions is a bad idea, because this is
// basically just a form of loop peeling, and our metrics aren't useful
// for that case.
if (F == BB->getParent())
- NeverInline = true;
+ isRecursive = true;
}
if (!isa<IntrinsicInst>(II) && !callIsSmall(CS.getCalledFunction())) {
@@ -220,7 +220,7 @@ void CodeMetrics::analyzeBasicBlock(const BasicBlock *BB) {
// jump would jump from the inlined copy of the function into the original
// function which is extremely undefined behavior.
if (isa<IndirectBrInst>(BB->getTerminator()))
- NeverInline = true;
+ containsIndirectBr = true;
// Remember NumInsts for this BB.
NumBBInsts[BB] = NumInsts - NumInstsBeforeThisBB;
@@ -247,7 +247,7 @@ void InlineCostAnalyzer::FunctionInfo::analyzeFunction(Function *F) {
// Don't bother calculating argument weights if we are never going to inline
// the function anyway.
- if (Metrics.NeverInline)
+ if (NeverInline())
return;
// Check out all of the arguments to the function, figuring out how much
@@ -258,6 +258,14 @@ void InlineCostAnalyzer::FunctionInfo::analyzeFunction(Function *F) {
CountCodeReductionForAlloca(I)));
}
+/// NeverInline - returns true if the function should never be inlined into
+/// any caller
+bool InlineCostAnalyzer::FunctionInfo::NeverInline()
+{
+ return (Metrics.callsSetJmp || Metrics.isRecursive ||
+ Metrics.containsIndirectBr);
+
+}
// getInlineCost - The heuristic used to determine if we should inline the
// function call or not.
//
@@ -315,7 +323,7 @@ InlineCost InlineCostAnalyzer::getInlineCost(CallSite CS,
CalleeFI->analyzeFunction(Callee);
// If we should never inline this, return a huge cost.
- if (CalleeFI->Metrics.NeverInline)
+ if (CalleeFI->NeverInline())
return InlineCost::getNever();
// FIXME: It would be nice to kill off CalleeFI->NeverInline. Then we
@@ -443,10 +451,15 @@ InlineCostAnalyzer::growCachedCostInfo(Function *Caller, Function *Callee) {
}
// Since CalleeMetrics were already calculated, we know that the CallerMetrics
- // reference isn't invalidated: both were in the DenseMap.
- CallerMetrics.NeverInline |= CalleeMetrics.NeverInline;
+ // reference isn't invalidated: both were in the DenseMap.
CallerMetrics.usesDynamicAlloca |= CalleeMetrics.usesDynamicAlloca;
+ // FIXME: If any of these three are true for the callee, the callee was
+ // not inlined into the caller, so I think they're redundant here.
+ CallerMetrics.callsSetJmp |= CalleeMetrics.callsSetJmp;
+ CallerMetrics.isRecursive |= CalleeMetrics.isRecursive;
+ CallerMetrics.containsIndirectBr |= CalleeMetrics.containsIndirectBr;
+
CallerMetrics.NumInsts += CalleeMetrics.NumInsts;
CallerMetrics.NumBlocks += CalleeMetrics.NumBlocks;
CallerMetrics.NumCalls += CalleeMetrics.NumCalls;
diff --git a/lib/Transforms/Scalar/LoopUnswitch.cpp b/lib/Transforms/Scalar/LoopUnswitch.cpp
index ae7bf40..9534ec3 100644
--- a/lib/Transforms/Scalar/LoopUnswitch.cpp
+++ b/lib/Transforms/Scalar/LoopUnswitch.cpp
@@ -445,7 +445,7 @@ bool LoopUnswitch::UnswitchIfProfitable(Value *LoopCond, Constant *Val) {
// This is a very ad-hoc heuristic.
if (Metrics.NumInsts > Threshold ||
Metrics.NumBlocks * 5 > Threshold ||
- Metrics.NeverInline) {
+ Metrics.containsIndirectBr || Metrics.isRecursive) {
DEBUG(dbgs() << "NOT unswitching loop %"
<< currentLoop->getHeader()->getName() << ", cost too high: "
<< currentLoop->getBlocks().size() << "\n");