summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/llvm/Analysis/CodeMetrics.h7
-rw-r--r--include/llvm/CodeGen/MachineFunction.h26
-rw-r--r--lib/Analysis/InlineCost.cpp14
-rw-r--r--lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp2
-rw-r--r--lib/CodeGen/StackSlotColoring.cpp2
-rw-r--r--test/Transforms/Inline/inline_returns_twice.ll41
6 files changed, 70 insertions, 22 deletions
diff --git a/include/llvm/Analysis/CodeMetrics.h b/include/llvm/Analysis/CodeMetrics.h
index 5f78021f3d..c01507f0a9 100644
--- a/include/llvm/Analysis/CodeMetrics.h
+++ b/include/llvm/Analysis/CodeMetrics.h
@@ -31,8 +31,9 @@ namespace llvm {
/// caller.
// bool NeverInline;
- // True if this function contains a call to setjmp or _setjmp
- bool callsSetJmp;
+ // True if this function contains a call to setjmp or other functions
+ // with attribute "returns twice" without having the attribute by itself.
+ bool exposesReturnsTwice;
// True if this function calls itself
bool isRecursive;
@@ -66,7 +67,7 @@ namespace llvm {
/// NumRets - Keep track of how many Ret instructions the block contains.
unsigned NumRets;
- CodeMetrics() : callsSetJmp(false), isRecursive(false),
+ CodeMetrics() : exposesReturnsTwice(false), isRecursive(false),
containsIndirectBr(false), usesDynamicAlloca(false),
NumInsts(0), NumBlocks(0), NumCalls(0),
NumInlineCandidates(0), NumVectorInsts(0),
diff --git a/include/llvm/CodeGen/MachineFunction.h b/include/llvm/CodeGen/MachineFunction.h
index 3a4568a59d..fd4cac8c12 100644
--- a/include/llvm/CodeGen/MachineFunction.h
+++ b/include/llvm/CodeGen/MachineFunction.h
@@ -120,10 +120,12 @@ class MachineFunction {
/// Alignment - The alignment of the function.
unsigned Alignment;
- /// CallsSetJmp - True if the function calls setjmp or sigsetjmp. This is used
- /// to limit optimizations which cannot reason about the control flow of
- /// setjmp.
- bool CallsSetJmp;
+ /// ExposesReturnsTwice - True if the function calls setjmp or related
+ /// functions with attribute "returns twice", but doesn't have
+ /// the attribute itself.
+ /// This is used to limit optimizations which cannot reason
+ /// about the control flow of such functions.
+ bool ExposesReturnsTwice;
MachineFunction(const MachineFunction &); // DO NOT IMPLEMENT
void operator=(const MachineFunction&); // DO NOT IMPLEMENT
@@ -192,15 +194,17 @@ public:
if (Alignment < A) Alignment = A;
}
- /// callsSetJmp - Returns true if the function calls setjmp or sigsetjmp.
- bool callsSetJmp() const {
- return CallsSetJmp;
+ /// exposesReturnsTwice - Returns true if the function calls setjmp or
+ /// any other similar functions with attribute "returns twice" without
+ /// having the attribute itself.
+ bool exposesReturnsTwice() const {
+ return ExposesReturnsTwice;
}
- /// setCallsSetJmp - Set a flag that indicates if there's a call to setjmp or
- /// sigsetjmp.
- void setCallsSetJmp(bool B) {
- CallsSetJmp = B;
+ /// setCallsSetJmp - Set a flag that indicates if there's a call to
+ /// a "returns twice" function.
+ void setExposesReturnsTwice(bool B) {
+ ExposesReturnsTwice = B;
}
/// getInfo - Keep track of various per-function pieces of information for
diff --git a/lib/Analysis/InlineCost.cpp b/lib/Analysis/InlineCost.cpp
index 1f332e84e6..7f0b0cc3bf 100644
--- a/lib/Analysis/InlineCost.cpp
+++ b/lib/Analysis/InlineCost.cpp
@@ -232,10 +232,12 @@ unsigned CodeMetrics::CountCodeReductionForAlloca(Value *V) {
/// from the specified function.
void CodeMetrics::analyzeFunction(Function *F, const TargetData *TD) {
// 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
- // marking their local variables as volatile if they are live across a setjmp
- // call, and they probably won't do this in callers.
- callsSetJmp = F->callsFunctionThatReturnsTwice();
+ // _setjmp) and it isn't marked with "returns twice" itself, 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 probably
+ // won't do this in callers.
+ exposesReturnsTwice = F->callsFunctionThatReturnsTwice() &&
+ !F->hasFnAttr(Attribute::ReturnsTwice);
// Look at the size of the callee.
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
/// any caller
bool InlineCostAnalyzer::FunctionInfo::NeverInline() {
- return (Metrics.callsSetJmp || Metrics.isRecursive ||
+ return (Metrics.exposesReturnsTwice || Metrics.isRecursive ||
Metrics.containsIndirectBr);
}
// 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
// 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.containsIndirectBr |= CalleeMetrics.containsIndirectBr;
diff --git a/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp b/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp
index 3c950595b6..aa6ef67357 100644
--- a/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp
+++ b/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp
@@ -452,7 +452,7 @@ bool SelectionDAGISel::runOnMachineFunction(MachineFunction &mf) {
}
// 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
// the desired value.
diff --git a/lib/CodeGen/StackSlotColoring.cpp b/lib/CodeGen/StackSlotColoring.cpp
index f8177a228c..ae3fa2acb7 100644
--- a/lib/CodeGen/StackSlotColoring.cpp
+++ b/lib/CodeGen/StackSlotColoring.cpp
@@ -426,7 +426,7 @@ bool StackSlotColoring::runOnMachineFunction(MachineFunction &MF) {
// coloring. The stack could be modified before the longjmp is executed,
// resulting in the wrong value being used afterwards. (See
// <rdar://problem/8007500>.)
- if (MF.callsSetJmp())
+ if (MF.exposesReturnsTwice())
return false;
// Gather spill slot references
diff --git a/test/Transforms/Inline/inline_returns_twice.ll b/test/Transforms/Inline/inline_returns_twice.ll
new file mode 100644
index 0000000000..ab2e954af1
--- /dev/null
+++ b/test/Transforms/Inline/inline_returns_twice.ll
@@ -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
+}