diff --git a/llvm/include/llvm/CodeGen/MachineFunction.h b/llvm/include/llvm/CodeGen/MachineFunction.h index 595872ad2d74..ec25bc13199b 100644 --- a/llvm/include/llvm/CodeGen/MachineFunction.h +++ b/llvm/include/llvm/CodeGen/MachineFunction.h @@ -114,9 +114,13 @@ class MachineFunction { /// unsigned FunctionNumber; - /// The alignment of the function. + /// Alignment - The alignment of the function. unsigned Alignment; + /// HasReturnsTwiceCall - Returns true if there's a call with a + /// "returns_twice" attribute, like setjmp. + bool HasReturnsTwiceCall; + MachineFunction(const MachineFunction &); // DO NOT IMPLEMENT void operator=(const MachineFunction&); // DO NOT IMPLEMENT public: @@ -181,6 +185,15 @@ public: void EnsureAlignment(unsigned A) { if (Alignment < A) Alignment = A; } + + /// hasReturnsTwiceCall - Returns true if there's a call with a + /// "returns_twice" attribute, like setjmp. + bool hasReturnsTwiceCall() const { + return HasReturnsTwiceCall; + } + void setReturnsTwiceCall(bool B) { + HasReturnsTwiceCall = B; + } /// getInfo - Keep track of various per-function pieces of information for /// backends that would like to do so. diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp index 6d789a674cf6..7e40cb9c6402 100644 --- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp @@ -25,6 +25,7 @@ #include "llvm/Intrinsics.h" #include "llvm/IntrinsicInst.h" #include "llvm/LLVMContext.h" +#include "llvm/Module.h" #include "llvm/CodeGen/FastISel.h" #include "llvm/CodeGen/GCStrategy.h" #include "llvm/CodeGen/GCMetadata.h" @@ -253,6 +254,39 @@ bool SelectionDAGISel::runOnMachineFunction(MachineFunction &mf) { done:; } + // Set a flag indicating if the machine function makes a call to setjmp / + // sigsetjmp (i.e., a function marked "returns_twice"). We'll use this to + // disable certain optimizations which cannot handle such control flows. + // + // FIXME: This goes beyond the setjmp/sigsetjmp functions. We should check for + // the GCC "returns twice" attribute. + const Module *M = Fn.getParent(); + const Function *SetJmp = M->getFunction("setjmp"); + const Function *SigSetJmp = M->getFunction("sigsetjmp"); + bool HasReturnsTwiceCall = false; + + if (SetJmp || SigSetJmp) { + if (SetJmp && !SetJmp->use_empty()) + for (Value::const_use_iterator + I = SetJmp->use_begin(), E = SetJmp->use_end(); I != E; ++I) + if (const CallInst *CI = dyn_cast(I)) + if (CI->getParent()->getParent() == &Fn) { + HasReturnsTwiceCall = true; + break; + } + + if (!HasReturnsTwiceCall && SigSetJmp && !SigSetJmp->use_empty()) + for (Value::const_use_iterator + I = SigSetJmp->use_begin(), E = SigSetJmp->use_end(); I != E; ++I) + if (const CallInst *CI = dyn_cast(I)) + if (CI->getParent()->getParent() == &Fn) { + HasReturnsTwiceCall = true; + break; + } + + mf.setReturnsTwiceCall(HasReturnsTwiceCall); + } + // Release function-specific state. SDB and CurDAG are already cleared // at this point. FuncInfo->clear(); diff --git a/llvm/lib/CodeGen/StackSlotColoring.cpp b/llvm/lib/CodeGen/StackSlotColoring.cpp index 804355634980..354878aa4260 100644 --- a/llvm/lib/CodeGen/StackSlotColoring.cpp +++ b/llvm/lib/CodeGen/StackSlotColoring.cpp @@ -118,7 +118,6 @@ namespace { private: void InitializeSlots(); - bool CheckForSetJmpCall(const MachineFunction &MF) const; void ScanForSpillSlotRefs(MachineFunction &MF); bool OverlapWithAssignments(LiveInterval *li, int Color) const; int ColorSlot(LiveInterval *li); @@ -162,34 +161,6 @@ namespace { }; } -/// CheckForSetJmpCall - Return true if there's a call to setjmp/sigsetjmp in -/// this function. -bool StackSlotColoring::CheckForSetJmpCall(const MachineFunction &MF) const { - const Function *F = MF.getFunction(); - const Module *M = F->getParent(); - const Function *SetJmp = M->getFunction("setjmp"); - const Function *SigSetJmp = M->getFunction("sigsetjmp"); - - if (!SetJmp && !SigSetJmp) - return false; - - if (SetJmp && !SetJmp->use_empty()) - for (Value::const_use_iterator - I = SetJmp->use_begin(), E = SetJmp->use_end(); I != E; ++I) - if (const CallInst *CI = dyn_cast(I)) - if (CI->getParent()->getParent() == F) - return true; - - if (SigSetJmp && !SigSetJmp->use_empty()) - for (Value::const_use_iterator - I = SigSetJmp->use_begin(), E = SigSetJmp->use_end(); I != E; ++I) - if (const CallInst *CI = dyn_cast(I)) - if (CI->getParent()->getParent() == F) - return true; - - return false; -} - /// ScanForSpillSlotRefs - Scan all the machine instructions for spill slot /// references and update spill slot weights. void StackSlotColoring::ScanForSpillSlotRefs(MachineFunction &MF) { @@ -753,14 +724,11 @@ bool StackSlotColoring::runOnMachineFunction(MachineFunction &MF) { return false; } - // If there are calls to setjmp or sigsetjmp, don't perform stack slot - // coloring. The stack could be modified before the longjmp is executed, - // resulting in the wrong value being used afterwards. (See - // .) - // - // FIXME: This goes beyond the setjmp/sigsetjmp functions. Ideally, we should - // check for the GCC "returns twice" attribute. - if (CheckForSetJmpCall(MF)) + // If there is a call to a function with the attribute "returns_twice" (like + // setjmp or sigsetjmp), don't perform stack slot coloring. The stack could be + // modified before the the second return, resulting in the wrong value being + // used afterwards. (See .) + if (MF.hasReturnsTwiceCall()) return false; // Gather spill slot references