mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-24 03:33:20 +01:00
Don't do tail calls in a function that call setjmp. The stack might be
corrupted when setjmp returns again. llvm-svn: 131399
This commit is contained in:
parent
576f65b4b2
commit
113d944ce4
@ -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.
|
||||
|
@ -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.
|
||||
|
@ -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)) {
|
||||
|
@ -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
|
||||
|
16
test/Transforms/TailCallElim/setjmp.ll
Normal file
16
test/Transforms/TailCallElim/setjmp.ll
Normal 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()
|
Loading…
Reference in New Issue
Block a user