mirror of
				https://github.com/c64scene-ar/llvm-6502.git
				synced 2025-10-30 16:17:05 +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