mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2025-07-29 10:25:12 +00:00
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:
@@ -414,6 +414,10 @@ public:
|
|||||||
///
|
///
|
||||||
bool hasAddressTaken(const User** = 0) const;
|
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:
|
private:
|
||||||
// Shadow Value::setValueSubclassData with a private forwarding method so that
|
// Shadow Value::setValueSubclassData with a private forwarding method so that
|
||||||
// subclasses cannot accidentally use it.
|
// subclasses cannot accidentally use it.
|
||||||
|
@@ -208,38 +208,6 @@ void SelectionDAGISel::getAnalysisUsage(AnalysisUsage &AU) const {
|
|||||||
MachineFunctionPass::getAnalysisUsage(AU);
|
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
|
/// 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
|
/// 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
|
/// 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.
|
// 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
|
// Replace forward-declared registers with the registers containing
|
||||||
// the desired value.
|
// the desired value.
|
||||||
|
@@ -59,6 +59,7 @@
|
|||||||
#include "llvm/Function.h"
|
#include "llvm/Function.h"
|
||||||
#include "llvm/Instructions.h"
|
#include "llvm/Instructions.h"
|
||||||
#include "llvm/IntrinsicInst.h"
|
#include "llvm/IntrinsicInst.h"
|
||||||
|
#include "llvm/Module.h"
|
||||||
#include "llvm/Pass.h"
|
#include "llvm/Pass.h"
|
||||||
#include "llvm/Analysis/CaptureTracking.h"
|
#include "llvm/Analysis/CaptureTracking.h"
|
||||||
#include "llvm/Analysis/InlineCost.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
|
// Finally, if this function contains no non-escaping allocas, or calls
|
||||||
// in the function as eligible for tail calls (there is no stack memory for
|
// setjmp, mark all calls in the function as eligible for tail calls
|
||||||
// them to access).
|
//(there is no stack memory for them to access).
|
||||||
if (!FunctionContainsEscapingAllocas)
|
if (!FunctionContainsEscapingAllocas && !F.callsFunctionThatReturnsTwice())
|
||||||
for (Function::iterator BB = F.begin(), E = F.end(); BB != E; ++BB)
|
for (Function::iterator BB = F.begin(), E = F.end(); BB != E; ++BB)
|
||||||
for (BasicBlock::iterator I = BB->begin(), E = BB->end(); I != E; ++I)
|
for (BasicBlock::iterator I = BB->begin(), E = BB->end(); I != E; ++I)
|
||||||
if (CallInst *CI = dyn_cast<CallInst>(I)) {
|
if (CallInst *CI = dyn_cast<CallInst>(I)) {
|
||||||
|
@@ -24,6 +24,7 @@
|
|||||||
#include "llvm/Support/Threading.h"
|
#include "llvm/Support/Threading.h"
|
||||||
#include "SymbolTableListTraitsImpl.h"
|
#include "SymbolTableListTraitsImpl.h"
|
||||||
#include "llvm/ADT/DenseMap.h"
|
#include "llvm/ADT/DenseMap.h"
|
||||||
|
#include "llvm/ADT/STLExtras.h"
|
||||||
#include "llvm/ADT/StringExtras.h"
|
#include "llvm/ADT/StringExtras.h"
|
||||||
using namespace llvm;
|
using namespace llvm;
|
||||||
|
|
||||||
@@ -406,4 +407,36 @@ bool Function::hasAddressTaken(const User* *PutOffender) const {
|
|||||||
return false;
|
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
|
// 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()
|
Reference in New Issue
Block a user