From: Kenneth Uildriks Date: Wed, 9 Jun 2010 15:11:37 +0000 (+0000) Subject: Pulled CodeMetrics out of InlineCost.h and made it a bit more general, so it can... X-Git-Url: http://plrg.eecs.uci.edu/git/?p=oota-llvm.git;a=commitdiff_plain;h=42c7d23c6d56e0743169d94025264eaf17eb799d Pulled CodeMetrics out of InlineCost.h and made it a bit more general, so it can be reused from PartialSpecializationCost git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@105725 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/llvm/Analysis/CodeMetrics.h b/include/llvm/Analysis/CodeMetrics.h new file mode 100644 index 00000000000..58096f1f15b --- /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 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 cac7cfe2455..462bddd5330 100644 --- a/include/llvm/Analysis/InlineCost.h +++ b/include/llvm/Analysis/InlineCost.h @@ -19,6 +19,7 @@ #include #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 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 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 98dbb69fe6a..b1df517c2a9 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(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(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 ae7bf40e0e1..9534ec3e0f3 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");