Check for the returns_twice attribute in callsFunctionThatReturnsTwice. This
authorRafael Espindola <rafael.espindola@gmail.com>
Wed, 5 Oct 2011 20:05:13 +0000 (20:05 +0000)
committerRafael Espindola <rafael.espindola@gmail.com>
Wed, 5 Oct 2011 20:05:13 +0000 (20:05 +0000)
fixes PR11038, but there are still some cleanups to be done.

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

include/llvm/Instructions.h
lib/VMCore/Function.cpp
test/Transforms/TailCallElim/setjmp.ll

index 2f879a18617ccf43af2a012f7baac8d3019fbb82..23e3e7e0f7b6884c8189c024bebc2e1dd718615d 100644 (file)
@@ -1267,6 +1267,15 @@ public:
     else removeAttribute(~0, Attribute::NoInline);
   }
 
+  /// @brief Return true if the call can return twice
+  bool canReturnTwice() const {
+    return paramHasAttr(~0, Attribute::ReturnsTwice);
+  }
+  void setCanReturnTwice(bool Value = true) {
+    if (Value) addAttribute(~0, Attribute::ReturnsTwice);
+    else removeAttribute(~0, Attribute::ReturnsTwice);
+  }
+
   /// @brief Determine if the call does not access memory.
   bool doesNotAccessMemory() const {
     return paramHasAttr(~0, Attribute::ReadNone);
index 1f59bf9716708d876a586cf07a5eee6806cf023b..ef0827b110e41f807d0ce5fe0fb229d24a3ce1f1 100644 (file)
@@ -17,6 +17,7 @@
 #include "llvm/LLVMContext.h"
 #include "llvm/CodeGen/ValueTypes.h"
 #include "llvm/Support/CallSite.h"
+#include "llvm/Support/InstIterator.h"
 #include "llvm/Support/LeakDetector.h"
 #include "llvm/Support/ManagedStatic.h"
 #include "llvm/Support/StringPool.h"
@@ -416,7 +417,6 @@ bool Function::hasAddressTaken(const User* *PutOffender) const {
 /// FIXME: Remove after <rdar://problem/8031714> is fixed.
 /// FIXME: Is the above FIXME valid?
 bool Function::callsFunctionThatReturnsTwice() const {
-  const Module *M = this->getParent();
   static const char *ReturnsTwiceFns[] = {
     "_setjmp",
     "setjmp",
@@ -428,16 +428,25 @@ bool Function::callsFunctionThatReturnsTwice() const {
     "getcontext"
   };
 
-  for (unsigned I = 0; I < array_lengthof(ReturnsTwiceFns); ++I)
-    if (const Function *Callee = M->getFunction(ReturnsTwiceFns[I])) {
-      if (!Callee->use_empty())
-        for (Value::const_use_iterator
-               I = Callee->use_begin(), E = Callee->use_end();
-             I != E; ++I)
-          if (const CallInst *CI = dyn_cast<CallInst>(*I))
-            if (CI->getParent()->getParent() == this)
-              return true;
+  for (const_inst_iterator I = inst_begin(this), E = inst_end(this); I != E;
+       ++I) {
+    const CallInst* callInst = dyn_cast<CallInst>(&*I);
+    if (!callInst)
+      continue;
+    if (callInst->canReturnTwice())
+      return true;
+
+    // check for known function names.
+    // FIXME: move this to clang.
+    Function *F = callInst->getCalledFunction();
+    if (!F)
+      continue;
+    StringRef Name = F->getName();
+    for (unsigned J = 0; J < array_lengthof(ReturnsTwiceFns); ++J) {
+      if (Name == ReturnsTwiceFns[J])
+        return true;
     }
+  }
 
   return false;
 }
index 35bb75dddb30ea55633ee0dfd4774fcd64202d97..7ef9cb360f53ce9c23af26070ebc39efa09f1b77 100644 (file)
@@ -1,16 +1,29 @@
 ; RUN: opt < %s -tailcallelim -S | FileCheck %s
 
-; Test that we don't tail call in a functions that calls setjmp.
+; Test that we don't tail call in a functions that calls returns_twice
+; functions.
 
+declare void @bar()
+
+; CHECK: foo1
 ; CHECK-NOT: tail call void @bar()
 
-define void @foo(i32* %x) {
+define void @foo1(i32* %x) {
 bb:
   %tmp75 = tail call i32 @setjmp(i32* %x)
   call void @bar()
   ret void
 }
 
-declare i32 @setjmp(i32*) returns_twice
+declare i32 @setjmp(i32*)
 
-declare void @bar()
+; CHECK: foo2
+; CHECK-NOT: tail call void @bar()
+
+define void @foo2(i32* %x) {
+bb:
+  %tmp75 = tail call i32 @zed2(i32* %x)
+  call void @bar()
+  ret void
+}
+declare i32 @zed2(i32*) returns_twice