Allow inlining of functions with returns_twice calls, if they have the
authorJoerg Sonnenberger <joerg@bec.de>
Sun, 18 Dec 2011 20:35:43 +0000 (20:35 +0000)
committerJoerg Sonnenberger <joerg@bec.de>
Sun, 18 Dec 2011 20:35:43 +0000 (20:35 +0000)
attribute themselve.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@146851 91177308-0d34-0410-b5e6-96231b3b80d8

include/llvm/Analysis/CodeMetrics.h
include/llvm/CodeGen/MachineFunction.h
lib/Analysis/InlineCost.cpp
lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp
lib/CodeGen/StackSlotColoring.cpp
test/Transforms/Inline/inline_returns_twice.ll [new file with mode: 0644]

index 5f78021f3d212bea67528c3184c27284cf373514..c01507f0a927af8a697e29d380e0a62d3e31e4a0 100644 (file)
@@ -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),
index 3a4568a59dc33fad0d18951e226d1f3a6811a3f9..fd4cac8c12ebfbbff23793e2bceb3466fbd19056 100644 (file)
@@ -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
index 1f332e84e6e37078f03229b21a7e8c651166ab94..7f0b0cc3bf1bb32e661c4b1646498e7b7abdb4e7 100644 (file)
@@ -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;
 
index 3c950595b6d222b07e56c908c9d35c2f2b486529..aa6ef67357151c1f0fc5a2629864336780be75d8 100644 (file)
@@ -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.
index f8177a228ce76a6aea95020f431c228ca2b44d6a..ae3fa2acb794583fc42579e8e4ce111d80ac3732 100644 (file)
@@ -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 (file)
index 0000000..ab2e954
--- /dev/null
@@ -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
+}