Allow inlining of functions with returns_twice calls, if they have the

attribute themselve.

llvm-svn: 146851
This commit is contained in:
Joerg Sonnenberger 2011-12-18 20:35:43 +00:00
parent e16533eded
commit 8cf8d64d19
6 changed files with 70 additions and 22 deletions

View File

@ -31,8 +31,9 @@ namespace llvm {
/// caller. /// caller.
// bool NeverInline; // bool NeverInline;
// True if this function contains a call to setjmp or _setjmp // True if this function contains a call to setjmp or other functions
bool callsSetJmp; // with attribute "returns twice" without having the attribute by itself.
bool exposesReturnsTwice;
// True if this function calls itself // True if this function calls itself
bool isRecursive; bool isRecursive;
@ -66,7 +67,7 @@ namespace llvm {
/// NumRets - Keep track of how many Ret instructions the block contains. /// NumRets - Keep track of how many Ret instructions the block contains.
unsigned NumRets; unsigned NumRets;
CodeMetrics() : callsSetJmp(false), isRecursive(false), CodeMetrics() : exposesReturnsTwice(false), isRecursive(false),
containsIndirectBr(false), usesDynamicAlloca(false), containsIndirectBr(false), usesDynamicAlloca(false),
NumInsts(0), NumBlocks(0), NumCalls(0), NumInsts(0), NumBlocks(0), NumCalls(0),
NumInlineCandidates(0), NumVectorInsts(0), NumInlineCandidates(0), NumVectorInsts(0),

View File

@ -120,10 +120,12 @@ class MachineFunction {
/// Alignment - The alignment of the function. /// Alignment - The alignment of the function.
unsigned Alignment; unsigned Alignment;
/// CallsSetJmp - True if the function calls setjmp or sigsetjmp. This is used /// ExposesReturnsTwice - True if the function calls setjmp or related
/// to limit optimizations which cannot reason about the control flow of /// functions with attribute "returns twice", but doesn't have
/// setjmp. /// the attribute itself.
bool CallsSetJmp; /// This is used to limit optimizations which cannot reason
/// about the control flow of such functions.
bool ExposesReturnsTwice;
MachineFunction(const MachineFunction &); // DO NOT IMPLEMENT MachineFunction(const MachineFunction &); // DO NOT IMPLEMENT
void operator=(const MachineFunction&); // DO NOT IMPLEMENT void operator=(const MachineFunction&); // DO NOT IMPLEMENT
@ -192,15 +194,17 @@ public:
if (Alignment < A) Alignment = A; if (Alignment < A) Alignment = A;
} }
/// callsSetJmp - Returns true if the function calls setjmp or sigsetjmp. /// exposesReturnsTwice - Returns true if the function calls setjmp or
bool callsSetJmp() const { /// any other similar functions with attribute "returns twice" without
return CallsSetJmp; /// having the attribute itself.
bool exposesReturnsTwice() const {
return ExposesReturnsTwice;
} }
/// setCallsSetJmp - Set a flag that indicates if there's a call to setjmp or /// setCallsSetJmp - Set a flag that indicates if there's a call to
/// sigsetjmp. /// a "returns twice" function.
void setCallsSetJmp(bool B) { void setExposesReturnsTwice(bool B) {
CallsSetJmp = B; ExposesReturnsTwice = B;
} }
/// getInfo - Keep track of various per-function pieces of information for /// getInfo - Keep track of various per-function pieces of information for

View File

@ -232,10 +232,12 @@ unsigned CodeMetrics::CountCodeReductionForAlloca(Value *V) {
/// from the specified function. /// from the specified function.
void CodeMetrics::analyzeFunction(Function *F, const TargetData *TD) { void CodeMetrics::analyzeFunction(Function *F, const TargetData *TD) {
// If this function contains a call that "returns twice" (e.g., setjmp or // If this function contains a call that "returns twice" (e.g., setjmp or
// _setjmp), never inline it. This is a hack because we depend on the user // _setjmp) and it isn't marked with "returns twice" itself, never inline it.
// marking their local variables as volatile if they are live across a setjmp // This is a hack because we depend on the user marking their local variables
// call, and they probably won't do this in callers. // as volatile if they are live across a setjmp call, and they probably
callsSetJmp = F->callsFunctionThatReturnsTwice(); // won't do this in callers.
exposesReturnsTwice = F->callsFunctionThatReturnsTwice() &&
!F->hasFnAttr(Attribute::ReturnsTwice);
// 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)
@ -265,7 +267,7 @@ void InlineCostAnalyzer::FunctionInfo::analyzeFunction(Function *F,
/// NeverInline - returns true if the function should never be inlined into /// NeverInline - returns true if the function should never be inlined into
/// any caller /// any caller
bool InlineCostAnalyzer::FunctionInfo::NeverInline() { bool InlineCostAnalyzer::FunctionInfo::NeverInline() {
return (Metrics.callsSetJmp || Metrics.isRecursive || return (Metrics.exposesReturnsTwice || Metrics.isRecursive ||
Metrics.containsIndirectBr); Metrics.containsIndirectBr);
} }
// getSpecializationBonus - The heuristic used to determine the per-call // getSpecializationBonus - The heuristic used to determine the per-call
@ -634,7 +636,7 @@ InlineCostAnalyzer::growCachedCostInfo(Function *Caller, Function *Callee) {
// FIXME: If any of these three are true for the callee, the callee was // 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. // not inlined into the caller, so I think they're redundant here.
CallerMetrics.callsSetJmp |= CalleeMetrics.callsSetJmp; CallerMetrics.exposesReturnsTwice |= CalleeMetrics.exposesReturnsTwice;
CallerMetrics.isRecursive |= CalleeMetrics.isRecursive; CallerMetrics.isRecursive |= CalleeMetrics.isRecursive;
CallerMetrics.containsIndirectBr |= CalleeMetrics.containsIndirectBr; CallerMetrics.containsIndirectBr |= CalleeMetrics.containsIndirectBr;

View File

@ -452,7 +452,7 @@ bool SelectionDAGISel::runOnMachineFunction(MachineFunction &mf) {
} }
// Determine if there is a call to setjmp in the machine function. // Determine if there is a call to setjmp in the machine function.
MF->setCallsSetJmp(Fn.callsFunctionThatReturnsTwice()); MF->setExposesReturnsTwice(Fn.callsFunctionThatReturnsTwice());
// Replace forward-declared registers with the registers containing // Replace forward-declared registers with the registers containing
// the desired value. // the desired value.

View File

@ -426,7 +426,7 @@ bool StackSlotColoring::runOnMachineFunction(MachineFunction &MF) {
// coloring. The stack could be modified before the longjmp is executed, // coloring. The stack could be modified before the longjmp is executed,
// resulting in the wrong value being used afterwards. (See // resulting in the wrong value being used afterwards. (See
// <rdar://problem/8007500>.) // <rdar://problem/8007500>.)
if (MF.callsSetJmp()) if (MF.exposesReturnsTwice())
return false; return false;
// Gather spill slot references // Gather spill slot references

View File

@ -0,0 +1,41 @@
; RUN: opt < %s -inline -S | FileCheck %s
; Check that functions with "returns_twice" calls are only inlined,
; if they are themselve marked as such.
declare i32 @a() returns_twice
declare i32 @b() returns_twice
define i32 @f() {
entry:
%call = call i32 @a() returns_twice
%add = add nsw i32 1, %call
ret i32 %add
}
define i32 @g() {
entry:
; CHECK: define i32 @g
; CHECK: call i32 @f()
; CHECK-NOT: call i32 @a()
%call = call i32 @f()
%add = add nsw i32 1, %call
ret i32 %add
}
define i32 @h() returns_twice {
entry:
%call = call i32 @b() returns_twice
%add = add nsw i32 1, %call
ret i32 %add
}
define i32 @i() {
entry:
; CHECK: define i32 @i
; CHECK: call i32 @b()
; CHECK-NOT: call i32 @h()
%call = call i32 @h() returns_twice
%add = add nsw i32 1, %call
ret i32 %add
}