Don't do tail calls in a function that call setjmp. The stack might be

corrupted when setjmp returns again.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@131399 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Rafael Espindola 2011-05-16 03:05:33 +00:00
parent baaa320168
commit 0e00c6c561
5 changed files with 59 additions and 37 deletions

View File

@ -414,6 +414,10 @@ public:
///
bool hasAddressTaken(const User** = 0) const;
/// callsFunctionThatReturnsTwice - Return true if the function has a call to
/// setjmp or other function that gcc recognizes as "returning twice".
bool callsFunctionThatReturnsTwice() const;
private:
// Shadow Value::setValueSubclassData with a private forwarding method so that
// subclasses cannot accidentally use it.

View File

@ -208,38 +208,6 @@ void SelectionDAGISel::getAnalysisUsage(AnalysisUsage &AU) const {
MachineFunctionPass::getAnalysisUsage(AU);
}
/// FunctionCallsSetJmp - Return true if the function has a call to setjmp or
/// other function that gcc recognizes as "returning twice". This is used to
/// limit code-gen optimizations on the machine function.
///
/// FIXME: Remove after <rdar://problem/8031714> is fixed.
static bool FunctionCallsSetJmp(const Function *F) {
const Module *M = F->getParent();
static const char *ReturnsTwiceFns[] = {
"_setjmp",
"setjmp",
"sigsetjmp",
"setjmp_syscall",
"savectx",
"qsetjmp",
"vfork",
"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() == F)
return true;
}
return false;
}
/// SplitCriticalSideEffectEdges - Look for critical edges with a PHI value that
/// may trap on it. In this case we have to split the edge so that the path
/// through the predecessor block that doesn't go to the phi block doesn't
@ -390,7 +358,7 @@ bool SelectionDAGISel::runOnMachineFunction(MachineFunction &mf) {
}
// Determine if there is a call to setjmp in the machine function.
MF->setCallsSetJmp(FunctionCallsSetJmp(&Fn));
MF->setCallsSetJmp(Fn.callsFunctionThatReturnsTwice());
// Replace forward-declared registers with the registers containing
// the desired value.

View File

@ -59,6 +59,7 @@
#include "llvm/Function.h"
#include "llvm/Instructions.h"
#include "llvm/IntrinsicInst.h"
#include "llvm/Module.h"
#include "llvm/Pass.h"
#include "llvm/Analysis/CaptureTracking.h"
#include "llvm/Analysis/InlineCost.h"
@ -209,10 +210,10 @@ bool TailCallElim::runOnFunction(Function &F) {
}
}
// Finally, if this function contains no non-escaping allocas, mark all calls
// in the function as eligible for tail calls (there is no stack memory for
// them to access).
if (!FunctionContainsEscapingAllocas)
// Finally, if this function contains no non-escaping allocas, or calls
// setjmp, mark all calls in the function as eligible for tail calls
//(there is no stack memory for them to access).
if (!FunctionContainsEscapingAllocas && !F.callsFunctionThatReturnsTwice())
for (Function::iterator BB = F.begin(), E = F.end(); BB != E; ++BB)
for (BasicBlock::iterator I = BB->begin(), E = BB->end(); I != E; ++I)
if (CallInst *CI = dyn_cast<CallInst>(I)) {

View File

@ -24,6 +24,7 @@
#include "llvm/Support/Threading.h"
#include "SymbolTableListTraitsImpl.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringExtras.h"
using namespace llvm;
@ -406,4 +407,36 @@ bool Function::hasAddressTaken(const User* *PutOffender) const {
return false;
}
/// callsFunctionThatReturnsTwice - Return true if the function has a call to
/// setjmp or other function that gcc recognizes as "returning twice".
///
/// FIXME: Remove after <rdar://problem/8031714> is fixed.
/// FIXME: Is the obove FIXME valid?
bool Function::callsFunctionThatReturnsTwice() const {
const Module *M = this->getParent();
static const char *ReturnsTwiceFns[] = {
"_setjmp",
"setjmp",
"sigsetjmp",
"setjmp_syscall",
"savectx",
"qsetjmp",
"vfork",
"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;
}
return false;
}
// vim: sw=2 ai

View File

@ -0,0 +1,16 @@
; RUN: opt < %s -tailcallelim -S | FileCheck %s
; Test that we don't tail call in a functions that calls setjmp.
; CHECK-NOT: tail call void @bar()
define void @foo(i32* %x) {
bb:
%tmp75 = tail call i32 @setjmp(i32* %x)
call void @bar()
ret void
}
declare i32 @setjmp(i32*)
declare void @bar()