Long live the exception handling!
This patch fills the last necessary bits to enable exceptions
handling in LLVM. Currently only on x86-32/linux.
In fact, this patch adds necessary intrinsics (and their lowering) which
represent really weird target-specific gcc builtins used inside unwinder.
After corresponding llvm-gcc patch will land (easy) exceptions should be
more or less workable. However, exceptions handling support should not be
thought as 'finished': I expect many small and not so small glitches
everywhere.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@39855 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/include/llvm/CodeGen/MachineModuleInfo.h b/include/llvm/CodeGen/MachineModuleInfo.h
index 1f9decf..778b75c 100644
--- a/include/llvm/CodeGen/MachineModuleInfo.h
+++ b/include/llvm/CodeGen/MachineModuleInfo.h
@@ -1030,6 +1030,9 @@
// Personalities - Vector of all personality functions ever seen. Used to emit
// common EH frames.
std::vector<Function *> Personalities;
+
+ bool CallsEHReturn;
+ bool CallsUnwindInit;
public:
static char ID; // Pass identification, replacement for typeid
@@ -1072,6 +1075,12 @@
/// needsFrameInfo - Returns true if we need to gather callee-saved register
/// move info for the frame.
bool needsFrameInfo() const;
+
+ bool callsEHReturn() const { return CallsEHReturn; }
+ void setCallsEHReturn(bool b) { CallsEHReturn = b; }
+
+ bool callsUnwindInit() const { return CallsUnwindInit; }
+ void setCallsUnwindInit(bool b) { CallsUnwindInit = b; }
/// NextLabelID - Return the next unique label id.
///
diff --git a/include/llvm/CodeGen/SelectionDAGNodes.h b/include/llvm/CodeGen/SelectionDAGNodes.h
index 316b02a..c96d516 100644
--- a/include/llvm/CodeGen/SelectionDAGNodes.h
+++ b/include/llvm/CodeGen/SelectionDAGNodes.h
@@ -110,6 +110,11 @@
// to the current function's frame or return address, an index of one to the
// parent's frame or return address, and so on.
FRAMEADDR, RETURNADDR,
+
+ // FRAME_TO_ARGS_OFFSET - This node represents offset from frame pointer to
+ // first (possible) on-stack argument. This is needed for correct stack
+ // adjustment during unwind.
+ FRAME_TO_ARGS_OFFSET,
// RESULT, OUTCHAIN = EXCEPTIONADDR(INCHAIN) - This node represents the
// address of the exception block on entry to an landing pad block.
@@ -119,6 +124,12 @@
// the selection index of the exception thrown.
EHSELECTION,
+ // OUTCHAIN = EH_RETURN(INCHAIN, OFFSET, HANDLER) - This node represents
+ // 'eh_return' gcc dwarf builtin, which is used to return from
+ // exception. The general meaning is: adjust stack by OFFSET and pass
+ // execution to HANDLER. Many platform-related details also :)
+ EH_RETURN,
+
// TargetConstant* - Like Constant*, but the DAG does not do any folding or
// simplification of the constant.
TargetConstant,
diff --git a/include/llvm/Intrinsics.td b/include/llvm/Intrinsics.td
index df3afde..e5bb2f6 100644
--- a/include/llvm/Intrinsics.td
+++ b/include/llvm/Intrinsics.td
@@ -233,6 +233,14 @@
llvm_vararg_ty]>;
def int_eh_typeid_for : Intrinsic<[llvm_i32_ty, llvm_ptr_ty]>;
+def int_eh_return : Intrinsic<[llvm_void_ty, llvm_i32_ty, llvm_ptr_ty]>,
+ GCCBuiltin<"__builtin_eh_return">;
+
+def int_eh_unwind_init: Intrinsic<[llvm_void_ty]>,
+ GCCBuiltin<"__builtin_unwind_init">;
+
+def int_eh_dwarf_cfa : Intrinsic<[llvm_ptr_ty, llvm_i32_ty]>;
+
//===---------------- Generic Variable Attribute Intrinsics----------------===//
//
def int_var_annotation : Intrinsic<[llvm_void_ty, llvm_ptr_ty, llvm_ptr_ty,
diff --git a/include/llvm/Target/MRegisterInfo.h b/include/llvm/Target/MRegisterInfo.h
index ecfe1ec..d2b76b8 100644
--- a/include/llvm/Target/MRegisterInfo.h
+++ b/include/llvm/Target/MRegisterInfo.h
@@ -396,12 +396,14 @@
/// callee saved registers on this target. The register should be in the
/// order of desired callee-save stack frame offset. The first register is
/// closed to the incoming stack pointer if stack grows down, and vice versa.
- virtual const unsigned* getCalleeSavedRegs() const = 0;
+ virtual const unsigned* getCalleeSavedRegs(const MachineFunction *MF = 0)
+ const = 0;
/// getCalleeSavedRegClasses - Return a null-terminated list of the preferred
/// register classes to spill each callee saved register with. The order and
/// length of this list match the getCalleeSaveRegs() list.
- virtual const TargetRegisterClass* const *getCalleeSavedRegClasses() const =0;
+ virtual const TargetRegisterClass* const *getCalleeSavedRegClasses(
+ const MachineFunction *MF) const =0;
/// getReservedRegs - Returns a bitset indexed by physical register number
/// indicating if a register is a special register that has particular uses and
diff --git a/lib/CodeGen/MachineModuleInfo.cpp b/lib/CodeGen/MachineModuleInfo.cpp
index 88d8507..77fb643 100644
--- a/lib/CodeGen/MachineModuleInfo.cpp
+++ b/lib/CodeGen/MachineModuleInfo.cpp
@@ -1476,6 +1476,8 @@
, FrameMoves()
, LandingPads()
, Personalities()
+, CallsEHReturn(0)
+, CallsUnwindInit(0)
{
// Always emit "no personality" info
Personalities.push_back(NULL);
@@ -1523,6 +1525,8 @@
TypeInfos.clear();
FilterIds.clear();
FilterEnds.clear();
+ CallsEHReturn = 0;
+ CallsUnwindInit = 0;
}
/// getDescFor - Convert a Value to a debug information descriptor.
diff --git a/lib/CodeGen/PrologEpilogInserter.cpp b/lib/CodeGen/PrologEpilogInserter.cpp
index 0658ad2..882c6a7 100644
--- a/lib/CodeGen/PrologEpilogInserter.cpp
+++ b/lib/CodeGen/PrologEpilogInserter.cpp
@@ -121,7 +121,7 @@
const TargetFrameInfo *TFI = Fn.getTarget().getFrameInfo();
// Get the callee saved register list...
- const unsigned *CSRegs = RegInfo->getCalleeSavedRegs();
+ const unsigned *CSRegs = RegInfo->getCalleeSavedRegs(&Fn);
// Get the function call frame set-up and tear-down instruction opcode
int FrameSetupOpcode = RegInfo->getCallFrameSetupOpcode();
@@ -170,7 +170,7 @@
// function, thus needing to be saved and restored in the prolog/epilog.
//
const TargetRegisterClass* const *CSRegClasses =
- RegInfo->getCalleeSavedRegClasses();
+ RegInfo->getCalleeSavedRegClasses(&Fn);
std::vector<CalleeSavedInfo> CSI;
for (unsigned i = 0; CSRegs[i]; ++i) {
unsigned Reg = CSRegs[i];
diff --git a/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp b/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp
index a5146bd..8b82b62 100644
--- a/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp
+++ b/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp
@@ -640,6 +640,7 @@
break;
case ISD::FRAMEADDR:
case ISD::RETURNADDR:
+ case ISD::FRAME_TO_ARGS_OFFSET:
// The only option for these nodes is to custom lower them. If the target
// does not custom lower them, then return zero.
Tmp1 = TLI.LowerOperation(Op, DAG);
@@ -695,6 +696,21 @@
}
}
break;
+ case ISD::EH_RETURN:
+ MVT::ValueType VT = Node->getValueType(0);
+ // The only "good" option for this node is to custom lower it.
+ switch (TLI.getOperationAction(Node->getOpcode(), VT)) {
+ default: assert(0 && "This action is not supported at all!");
+ case TargetLowering::Custom:
+ Result = TLI.LowerOperation(Op, DAG);
+ if (Result.Val) break;
+ // Fall Thru
+ case TargetLowering::Legal:
+ // Target does not know, how to lower this, lower to noop
+ Result = LegalizeOp(Node->getOperand(0));
+ break;
+ }
+ break;
case ISD::AssertSext:
case ISD::AssertZext:
Tmp1 = LegalizeOp(Node->getOperand(0));
diff --git a/lib/CodeGen/SelectionDAG/SelectionDAG.cpp b/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
index dc23151..9803ab8 100644
--- a/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
+++ b/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
@@ -3369,8 +3369,10 @@
case ISD::GLOBAL_OFFSET_TABLE: return "GLOBAL_OFFSET_TABLE";
case ISD::RETURNADDR: return "RETURNADDR";
case ISD::FRAMEADDR: return "FRAMEADDR";
+ case ISD::FRAME_TO_ARGS_OFFSET: return "FRAME_TO_ARGS_OFFSET";
case ISD::EXCEPTIONADDR: return "EXCEPTIONADDR";
case ISD::EHSELECTION: return "EHSELECTION";
+ case ISD::EH_RETURN: return "EH_RETURN";
case ISD::ConstantPool: return "ConstantPool";
case ISD::ExternalSymbol: return "ExternalSymbol";
case ISD::INTRINSIC_WO_CHAIN: {
diff --git a/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp b/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp
index 87bf249..8a2f7b1 100644
--- a/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp
+++ b/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp
@@ -2721,6 +2721,53 @@
return 0;
}
+ case Intrinsic::eh_return: {
+ MachineModuleInfo *MMI = DAG.getMachineModuleInfo();
+
+ if (MMI && ExceptionHandling) {
+ MMI->setCallsEHReturn(true);
+ DAG.setRoot(DAG.getNode(ISD::EH_RETURN,
+ MVT::Other,
+ getRoot(),
+ getValue(I.getOperand(1)),
+ getValue(I.getOperand(2))));
+ } else {
+ setValue(&I, DAG.getConstant(0, TLI.getPointerTy()));
+ }
+
+ return 0;
+ }
+
+ case Intrinsic::eh_unwind_init: {
+ if (MachineModuleInfo *MMI = DAG.getMachineModuleInfo()) {
+ MMI->setCallsUnwindInit(true);
+ }
+
+ return 0;
+ }
+
+ case Intrinsic::eh_dwarf_cfa: {
+ if (ExceptionHandling) {
+ MVT::ValueType VT = getValue(I.getOperand(1)).getValueType();
+ SDOperand Offset = DAG.getNode(ISD::ADD,
+ TLI.getPointerTy(),
+ DAG.getNode(ISD::FRAME_TO_ARGS_OFFSET,
+ VT),
+ getValue(I.getOperand(1)));
+ setValue(&I, DAG.getNode(ISD::ADD,
+ TLI.getPointerTy(),
+ DAG.getNode(ISD::FRAMEADDR,
+ TLI.getPointerTy(),
+ DAG.getConstant(0,
+ TLI.getPointerTy())),
+ Offset));
+ } else {
+ setValue(&I, DAG.getConstant(0, TLI.getPointerTy()));
+ }
+
+ return 0;
+ }
+
case Intrinsic::sqrt_f32:
case Intrinsic::sqrt_f64:
setValue(&I, DAG.getNode(ISD::FSQRT,
diff --git a/lib/Target/ARM/ARMRegisterInfo.cpp b/lib/Target/ARM/ARMRegisterInfo.cpp
index 05458e5..f8e10de 100644
--- a/lib/Target/ARM/ARMRegisterInfo.cpp
+++ b/lib/Target/ARM/ARMRegisterInfo.cpp
@@ -327,7 +327,8 @@
return NewMI;
}
-const unsigned* ARMRegisterInfo::getCalleeSavedRegs() const {
+const unsigned* ARMRegisterInfo::getCalleeSavedRegs(const MachineFunction *MF)
+ const {
static const unsigned CalleeSavedRegs[] = {
ARM::LR, ARM::R11, ARM::R10, ARM::R9, ARM::R8,
ARM::R7, ARM::R6, ARM::R5, ARM::R4,
@@ -349,7 +350,7 @@
}
const TargetRegisterClass* const *
-ARMRegisterInfo::getCalleeSavedRegClasses() const {
+ARMRegisterInfo::getCalleeSavedRegClasses(const MachineFunction *MF) const {
static const TargetRegisterClass * const CalleeSavedRegClasses[] = {
&ARM::GPRRegClass, &ARM::GPRRegClass, &ARM::GPRRegClass,
&ARM::GPRRegClass, &ARM::GPRRegClass, &ARM::GPRRegClass,
diff --git a/lib/Target/ARM/ARMRegisterInfo.h b/lib/Target/ARM/ARMRegisterInfo.h
index 261cc88..3db1d89 100644
--- a/lib/Target/ARM/ARMRegisterInfo.h
+++ b/lib/Target/ARM/ARMRegisterInfo.h
@@ -66,9 +66,10 @@
MachineInstr* foldMemoryOperand(MachineInstr* MI, unsigned OpNum,
int FrameIndex) const;
- const unsigned *getCalleeSavedRegs() const;
+ const unsigned *getCalleeSavedRegs(const MachineFunction *MF = 0) const;
- const TargetRegisterClass* const* getCalleeSavedRegClasses() const;
+ const TargetRegisterClass* const* getCalleeSavedRegClasses(
+ const MachineFunction *MF = 0) const;
BitVector getReservedRegs(const MachineFunction &MF) const;
diff --git a/lib/Target/Alpha/AlphaRegisterInfo.cpp b/lib/Target/Alpha/AlphaRegisterInfo.cpp
index 72a8407..59d3e81 100644
--- a/lib/Target/Alpha/AlphaRegisterInfo.cpp
+++ b/lib/Target/Alpha/AlphaRegisterInfo.cpp
@@ -164,7 +164,8 @@
MBB.insert(I, MI);
}
-const unsigned* AlphaRegisterInfo::getCalleeSavedRegs() const {
+const unsigned* AlphaRegisterInfo::getCalleeSavedRegs(const MachineFunction *MF)
+ const {
static const unsigned CalleeSavedRegs[] = {
Alpha::R9, Alpha::R10,
Alpha::R11, Alpha::R12,
@@ -178,7 +179,7 @@
}
const TargetRegisterClass* const*
-AlphaRegisterInfo::getCalleeSavedRegClasses() const {
+AlphaRegisterInfo::getCalleeSavedRegClasses(const MachineFunction *MF) const {
static const TargetRegisterClass * const CalleeSavedRegClasses[] = {
&Alpha::GPRCRegClass, &Alpha::GPRCRegClass,
&Alpha::GPRCRegClass, &Alpha::GPRCRegClass,
diff --git a/lib/Target/Alpha/AlphaRegisterInfo.h b/lib/Target/Alpha/AlphaRegisterInfo.h
index 07fea9e..2872e59 100644
--- a/lib/Target/Alpha/AlphaRegisterInfo.h
+++ b/lib/Target/Alpha/AlphaRegisterInfo.h
@@ -48,9 +48,10 @@
void reMaterialize(MachineBasicBlock &MBB, MachineBasicBlock::iterator MI,
unsigned DestReg, const MachineInstr *Orig) const;
- const unsigned *getCalleeSavedRegs() const;
+ const unsigned *getCalleeSavedRegs(const MachineFunction *MF = 0) const;
- const TargetRegisterClass* const* getCalleeSavedRegClasses() const;
+ const TargetRegisterClass* const* getCalleeSavedRegClasses(
+ const MachineFunction *MF = 0) const;
BitVector getReservedRegs(const MachineFunction &MF) const;
diff --git a/lib/Target/IA64/IA64RegisterInfo.cpp b/lib/Target/IA64/IA64RegisterInfo.cpp
index 41a15fd..08327f2 100644
--- a/lib/Target/IA64/IA64RegisterInfo.cpp
+++ b/lib/Target/IA64/IA64RegisterInfo.cpp
@@ -102,7 +102,8 @@
MBB.insert(I, MI);
}
-const unsigned* IA64RegisterInfo::getCalleeSavedRegs() const {
+const unsigned* IA64RegisterInfo::getCalleeSavedRegs(const MachineFunction *MF)
+ const {
static const unsigned CalleeSavedRegs[] = {
IA64::r5, 0
};
@@ -110,7 +111,7 @@
}
const TargetRegisterClass* const*
-IA64RegisterInfo::getCalleeSavedRegClasses() const {
+IA64RegisterInfo::getCalleeSavedRegClasses(const MachineFunction *MF) const {
static const TargetRegisterClass * const CalleeSavedRegClasses[] = {
&IA64::GRRegClass, 0
};
diff --git a/lib/Target/IA64/IA64RegisterInfo.h b/lib/Target/IA64/IA64RegisterInfo.h
index d90f321..162ad5a 100644
--- a/lib/Target/IA64/IA64RegisterInfo.h
+++ b/lib/Target/IA64/IA64RegisterInfo.h
@@ -47,9 +47,10 @@
void reMaterialize(MachineBasicBlock &MBB, MachineBasicBlock::iterator MI,
unsigned DestReg, const MachineInstr *Orig) const;
- const unsigned *getCalleeSavedRegs() const;
+ const unsigned *getCalleeSavedRegs(const MachineFunction *MF = 0) const;
- const TargetRegisterClass* const* getCalleeSavedRegClasses() const;
+ const TargetRegisterClass* const* getCalleeSavedRegClasses(
+ const MachineFunction *MF = 0) const;
BitVector getReservedRegs(const MachineFunction &MF) const;
diff --git a/lib/Target/PowerPC/PPCRegisterInfo.cpp b/lib/Target/PowerPC/PPCRegisterInfo.cpp
index a788a75..19780a8 100644
--- a/lib/Target/PowerPC/PPCRegisterInfo.cpp
+++ b/lib/Target/PowerPC/PPCRegisterInfo.cpp
@@ -248,7 +248,8 @@
MBB.insert(I, MI);
}
-const unsigned* PPCRegisterInfo::getCalleeSavedRegs() const {
+const unsigned* PPCRegisterInfo::getCalleeSavedRegs(const MachineFunction *MF)
+ const {
// 32-bit Darwin calling convention.
static const unsigned Macho32_CalleeSavedRegs[] = {
PPC::R13, PPC::R14, PPC::R15,
@@ -324,7 +325,7 @@
}
const TargetRegisterClass* const*
-PPCRegisterInfo::getCalleeSavedRegClasses() const {
+PPCRegisterInfo::getCalleeSavedRegClasses(const MachineFunction *MF) const {
// 32-bit Macho calling convention.
static const TargetRegisterClass * const Macho32_CalleeSavedRegClasses[] = {
&PPC::GPRCRegClass,&PPC::GPRCRegClass,&PPC::GPRCRegClass,
diff --git a/lib/Target/PowerPC/PPCRegisterInfo.h b/lib/Target/PowerPC/PPCRegisterInfo.h
index 0caf106..4112034 100644
--- a/lib/Target/PowerPC/PPCRegisterInfo.h
+++ b/lib/Target/PowerPC/PPCRegisterInfo.h
@@ -57,9 +57,10 @@
virtual MachineInstr* foldMemoryOperand(MachineInstr* MI, unsigned OpNum,
int FrameIndex) const;
- const unsigned *getCalleeSavedRegs() const;
+ const unsigned *getCalleeSavedRegs(const MachineFunction* MF = 0) const;
- const TargetRegisterClass* const* getCalleeSavedRegClasses() const;
+ const TargetRegisterClass* const* getCalleeSavedRegClasses(
+ const MachineFunction *MF = 0) const;
BitVector getReservedRegs(const MachineFunction &MF) const;
diff --git a/lib/Target/Sparc/SparcRegisterInfo.cpp b/lib/Target/Sparc/SparcRegisterInfo.cpp
index ded1bcd..1981b4f 100644
--- a/lib/Target/Sparc/SparcRegisterInfo.cpp
+++ b/lib/Target/Sparc/SparcRegisterInfo.cpp
@@ -121,7 +121,8 @@
return NewMI;
}
-const unsigned* SparcRegisterInfo::getCalleeSavedRegs() const {
+const unsigned* SparcRegisterInfo::getCalleeSavedRegs(const MachineFunction *MF)
+ const {
static const unsigned CalleeSavedRegs[] = { 0 };
return CalleeSavedRegs;
}
@@ -143,7 +144,7 @@
const TargetRegisterClass* const*
-SparcRegisterInfo::getCalleeSavedRegClasses() const {
+SparcRegisterInfo::getCalleeSavedRegClasses(const MachineFunction *MF) const {
static const TargetRegisterClass * const CalleeSavedRegClasses[] = { 0 };
return CalleeSavedRegClasses;
}
diff --git a/lib/Target/Sparc/SparcRegisterInfo.h b/lib/Target/Sparc/SparcRegisterInfo.h
index b7ea4d6..451964b 100644
--- a/lib/Target/Sparc/SparcRegisterInfo.h
+++ b/lib/Target/Sparc/SparcRegisterInfo.h
@@ -51,9 +51,10 @@
unsigned OpNum,
int FrameIndex) const;
- const unsigned *getCalleeSavedRegs() const;
+ const unsigned *getCalleeSavedRegs(const MachineFunction *MF = 0) const;
- const TargetRegisterClass* const* getCalleeSavedRegClasses() const;
+ const TargetRegisterClass* const* getCalleeSavedRegClasses(
+ const MachineFunction *MF = 0) const;
BitVector getReservedRegs(const MachineFunction &MF) const;
diff --git a/lib/Target/X86/X86ISelLowering.cpp b/lib/Target/X86/X86ISelLowering.cpp
index 3bf2b9f..37dea79 100644
--- a/lib/Target/X86/X86ISelLowering.cpp
+++ b/lib/Target/X86/X86ISelLowering.cpp
@@ -42,6 +42,8 @@
X86ScalarSSE = Subtarget->hasSSE2();
X86StackPtr = Subtarget->is64Bit() ? X86::RSP : X86::ESP;
+ RegInfo = TM.getRegisterInfo();
+
// Set up the TargetLowering object.
// X86 is weird, it always uses i8 for shift amounts and setcc results.
@@ -197,6 +199,9 @@
}
// X86 ret instruction may pop stack.
setOperationAction(ISD::RET , MVT::Other, Custom);
+ if (!Subtarget->is64Bit())
+ setOperationAction(ISD::EH_RETURN , MVT::Other, Custom);
+
// Darwin ABI issue.
setOperationAction(ISD::ConstantPool , MVT::i32 , Custom);
setOperationAction(ISD::JumpTable , MVT::i32 , Custom);
@@ -4226,6 +4231,39 @@
DAG.getConstant(4, getPointerTy()));
}
+SDOperand X86TargetLowering::LowerFRAME_TO_ARGS_OFFSET(SDOperand Op,
+ SelectionDAG &DAG) {
+ // Is not yet supported on x86-64
+ if (Subtarget->is64Bit())
+ return SDOperand();
+
+ return DAG.getConstant(8, getPointerTy());
+}
+
+SDOperand X86TargetLowering::LowerEH_RETURN(SDOperand Op, SelectionDAG &DAG)
+{
+ assert(!Subtarget->is64Bit() &&
+ "Lowering of eh_return builtin is not supported yet on x86-64");
+
+ MachineFunction &MF = DAG.getMachineFunction();
+ SDOperand Chain = Op.getOperand(0);
+ SDOperand Offset = Op.getOperand(1);
+ SDOperand Handler = Op.getOperand(2);
+
+ SDOperand Frame = DAG.getRegister(RegInfo->getFrameRegister(MF),
+ getPointerTy());
+
+ SDOperand StoreAddr = DAG.getNode(ISD::SUB, getPointerTy(), Frame,
+ DAG.getConstant(-4UL, getPointerTy()));
+ StoreAddr = DAG.getNode(ISD::ADD, getPointerTy(), StoreAddr, Offset);
+ Chain = DAG.getStore(Chain, Handler, StoreAddr, NULL, 0);
+ Chain = DAG.getCopyToReg(Chain, X86::ECX, StoreAddr);
+ MF.addLiveOut(X86::ECX);
+
+ return DAG.getNode(X86ISD::EH_RETURN, MVT::Other,
+ Chain, DAG.getRegister(X86::ECX, getPointerTy()));
+}
+
/// LowerOperation - Provide custom lowering hooks for some operations.
///
SDOperand X86TargetLowering::LowerOperation(SDOperand Op, SelectionDAG &DAG) {
@@ -4263,7 +4301,10 @@
case ISD::INTRINSIC_WO_CHAIN: return LowerINTRINSIC_WO_CHAIN(Op, DAG);
case ISD::RETURNADDR: return LowerRETURNADDR(Op, DAG);
case ISD::FRAMEADDR: return LowerFRAMEADDR(Op, DAG);
+ case ISD::FRAME_TO_ARGS_OFFSET:
+ return LowerFRAME_TO_ARGS_OFFSET(Op, DAG);
case ISD::DYNAMIC_STACKALLOC: return LowerDYNAMIC_STACKALLOC(Op, DAG);
+ case ISD::EH_RETURN: return LowerEH_RETURN(Op, DAG);
}
return SDOperand();
}
@@ -4311,6 +4352,7 @@
case X86ISD::FRCP: return "X86ISD::FRCP";
case X86ISD::TLSADDR: return "X86ISD::TLSADDR";
case X86ISD::THREAD_POINTER: return "X86ISD::THREAD_POINTER";
+ case X86ISD::EH_RETURN: return "X86ISD::EH_RETURN";
}
}
diff --git a/lib/Target/X86/X86ISelLowering.h b/lib/Target/X86/X86ISelLowering.h
index b9aaefa..07a96d3 100644
--- a/lib/Target/X86/X86ISelLowering.h
+++ b/lib/Target/X86/X86ISelLowering.h
@@ -16,6 +16,7 @@
#define X86ISELLOWERING_H
#include "X86Subtarget.h"
+#include "X86RegisterInfo.h"
#include "llvm/Target/TargetLowering.h"
#include "llvm/CodeGen/SelectionDAG.h"
@@ -184,7 +185,10 @@
FRSQRT, FRCP,
// Thread Local Storage
- TLSADDR, THREAD_POINTER
+ TLSADDR, THREAD_POINTER,
+
+ // Exception Handling helpers
+ EH_RETURN
};
}
@@ -370,6 +374,7 @@
/// Subtarget - Keep a pointer to the X86Subtarget around so that we can
/// make the right decision when generating code for different targets.
const X86Subtarget *Subtarget;
+ const MRegisterInfo *RegInfo;
/// X86StackPtr - X86 physical register used as stack ptr.
unsigned X86StackPtr;
@@ -424,6 +429,8 @@
SDOperand LowerINTRINSIC_WO_CHAIN(SDOperand Op, SelectionDAG &DAG);
SDOperand LowerRETURNADDR(SDOperand Op, SelectionDAG &DAG);
SDOperand LowerFRAMEADDR(SDOperand Op, SelectionDAG &DAG);
+ SDOperand LowerFRAME_TO_ARGS_OFFSET(SDOperand Op, SelectionDAG &DAG);
+ SDOperand LowerEH_RETURN(SDOperand Op, SelectionDAG &DAG);
};
}
diff --git a/lib/Target/X86/X86InstrInfo.td b/lib/Target/X86/X86InstrInfo.td
index f8eac7e..b24f644 100644
--- a/lib/Target/X86/X86InstrInfo.td
+++ b/lib/Target/X86/X86InstrInfo.td
@@ -51,6 +51,8 @@
def SDT_X86TLSTP : SDTypeProfile<1, 0, [SDTCisPtrTy<0>]>;
+def SDT_X86EHRET : SDTypeProfile<0, 1, [SDTCisInt<0>]>;
+
def X86shld : SDNode<"X86ISD::SHLD", SDTIntShiftDOp>;
def X86shrd : SDNode<"X86ISD::SHRD", SDTIntShiftDOp>;
@@ -95,6 +97,9 @@
[SDNPHasChain, SDNPInFlag, SDNPOutFlag]>;
def X86TLStp : SDNode<"X86ISD::THREAD_POINTER", SDT_X86TLSTP, []>;
+def X86ehret : SDNode<"X86ISD::EH_RETURN", SDT_X86EHRET,
+ [SDNPHasChain]>;
+
//===----------------------------------------------------------------------===//
// X86 Operand Definitions.
@@ -2492,6 +2497,17 @@
(i32 imm:$file))]>;
//===----------------------------------------------------------------------===//
+// EH Pseudo Instructions
+//
+let isTerminator = 1, isReturn = 1, isBarrier = 1,
+ hasCtrlDep = 1, noResults = 1 in {
+def EH_RETURN : I<0xC3, RawFrm, (ops GR32:$addr),
+ "ret #eh_return, addr: $addr",
+ [(X86ehret GR32:$addr)]>;
+
+}
+
+//===----------------------------------------------------------------------===//
// Non-Instruction Patterns
//===----------------------------------------------------------------------===//
diff --git a/lib/Target/X86/X86RegisterInfo.cpp b/lib/Target/X86/X86RegisterInfo.cpp
index 3ea437f..9dc3dd1 100644
--- a/lib/Target/X86/X86RegisterInfo.cpp
+++ b/lib/Target/X86/X86RegisterInfo.cpp
@@ -903,30 +903,62 @@
}
-const unsigned *X86RegisterInfo::getCalleeSavedRegs() const {
+const unsigned *X86RegisterInfo::getCalleeSavedRegs(const MachineFunction *MF)
+ const {
static const unsigned CalleeSavedRegs32Bit[] = {
X86::ESI, X86::EDI, X86::EBX, X86::EBP, 0
};
+
+ static const unsigned CalleeSavedRegs32EHRet[] = {
+ X86::EAX, X86::EDX, X86::ESI, X86::EDI, X86::EBX, X86::EBP, 0
+ };
+
static const unsigned CalleeSavedRegs64Bit[] = {
X86::RBX, X86::R12, X86::R13, X86::R14, X86::R15, X86::RBP, 0
};
- return Is64Bit ? CalleeSavedRegs64Bit : CalleeSavedRegs32Bit;
+ if (Is64Bit)
+ return CalleeSavedRegs64Bit;
+ else {
+ if (MF) {
+ MachineFrameInfo *MFI = MF->getFrameInfo();
+ MachineModuleInfo *MMI = MFI->getMachineModuleInfo();
+ if (MMI && MMI->callsEHReturn())
+ return CalleeSavedRegs32EHRet;
+ }
+ return CalleeSavedRegs32Bit;
+ }
}
const TargetRegisterClass* const*
-X86RegisterInfo::getCalleeSavedRegClasses() const {
+X86RegisterInfo::getCalleeSavedRegClasses(const MachineFunction *MF) const {
static const TargetRegisterClass * const CalleeSavedRegClasses32Bit[] = {
&X86::GR32RegClass, &X86::GR32RegClass,
&X86::GR32RegClass, &X86::GR32RegClass, 0
};
+ static const TargetRegisterClass * const CalleeSavedRegClasses32EHRet[] = {
+ &X86::GR32RegClass, &X86::GR32RegClass,
+ &X86::GR32RegClass, &X86::GR32RegClass,
+ &X86::GR32RegClass, &X86::GR32RegClass, 0
+ };
static const TargetRegisterClass * const CalleeSavedRegClasses64Bit[] = {
&X86::GR64RegClass, &X86::GR64RegClass,
&X86::GR64RegClass, &X86::GR64RegClass,
&X86::GR64RegClass, &X86::GR64RegClass, 0
};
- return Is64Bit ? CalleeSavedRegClasses64Bit : CalleeSavedRegClasses32Bit;
+ if (Is64Bit)
+ return CalleeSavedRegClasses64Bit;
+ else {
+ if (MF) {
+ MachineFrameInfo *MFI = MF->getFrameInfo();
+ MachineModuleInfo *MMI = MFI->getMachineModuleInfo();
+ if (MMI && MMI->callsEHReturn())
+ return CalleeSavedRegClasses32EHRet;
+ }
+ return CalleeSavedRegClasses32Bit;
+ }
+
}
BitVector X86RegisterInfo::getReservedRegs(const MachineFunction &MF) const {
@@ -953,9 +985,13 @@
// if frame pointer elimination is disabled.
//
bool X86RegisterInfo::hasFP(const MachineFunction &MF) const {
+ MachineFrameInfo *MFI = MF.getFrameInfo();
+ MachineModuleInfo *MMI = MFI->getMachineModuleInfo();
+
return (NoFramePointerElim ||
MF.getFrameInfo()->hasVarSizedObjects() ||
- MF.getInfo<X86MachineFunctionInfo>()->getForceFramePointer());
+ MF.getInfo<X86MachineFunctionInfo>()->getForceFramePointer() ||
+ (MMI && MMI->callsUnwindInit()));
}
void X86RegisterInfo::
@@ -1243,10 +1279,12 @@
MachineBasicBlock &MBB) const {
const MachineFrameInfo *MFI = MF.getFrameInfo();
MachineBasicBlock::iterator MBBI = prior(MBB.end());
+ unsigned RetOpcode = MBBI->getOpcode();
- switch (MBBI->getOpcode()) {
+ switch (RetOpcode) {
case X86::RET:
case X86::RETI:
+ case X86::EH_RETURN:
case X86::TAILJMPd:
case X86::TAILJMPr:
case X86::TAILJMPm: break; // These are ok
@@ -1288,6 +1326,14 @@
emitSPUpdate(MBB, MBBI, StackPtr, NumBytes, Is64Bit, TII);
}
}
+
+ // We're returning from function via eh_return.
+ if (RetOpcode == X86::EH_RETURN) {
+ MachineOperand &DestAddr = MBBI->getOperand(0);
+ assert(DestAddr.isReg() && "Offset should be in register!");
+ BuildMI(MBB, MBBI, TII.get(Is64Bit ? X86::MOV64rr : X86::MOV32rr),StackPtr).
+ addReg(DestAddr.getReg());
+ }
}
unsigned X86RegisterInfo::getRARegister() const {
diff --git a/lib/Target/X86/X86RegisterInfo.h b/lib/Target/X86/X86RegisterInfo.h
index cf83f99..7f18b56 100644
--- a/lib/Target/X86/X86RegisterInfo.h
+++ b/lib/Target/X86/X86RegisterInfo.h
@@ -74,12 +74,13 @@
/// getCalleeSavedRegs - Return a null-terminated list of all of the
/// callee-save registers on this target.
- const unsigned *getCalleeSavedRegs() const;
+ const unsigned *getCalleeSavedRegs(const MachineFunction* MF = 0) const;
/// getCalleeSavedRegClasses - Return a null-terminated list of the preferred
/// register classes to spill each callee-saved register with. The order and
/// length of this list match the getCalleeSavedRegs() list.
- const TargetRegisterClass* const* getCalleeSavedRegClasses() const;
+ const TargetRegisterClass* const* getCalleeSavedRegClasses(
+ const MachineFunction *MF = 0) const;
/// getReservedRegs - Returns a bitset indexed by physical register number
/// indicating if a register is a special register that has particular uses and
diff --git a/lib/Target/X86/X86TargetAsmInfo.cpp b/lib/Target/X86/X86TargetAsmInfo.cpp
index dbf202c..4bb854e 100644
--- a/lib/Target/X86/X86TargetAsmInfo.cpp
+++ b/lib/Target/X86/X86TargetAsmInfo.cpp
@@ -124,8 +124,9 @@
DwarfARangesSection = "\t.section\t.debug_aranges,\"\",@progbits";
DwarfRangesSection = "\t.section\t.debug_ranges,\"\",@progbits";
DwarfMacInfoSection = "\t.section\t.debug_macinfo,\"\",@progbits";
-
- SupportsExceptionHandling = true;
+
+ if (!Subtarget->is64Bit())
+ SupportsExceptionHandling = true;
DwarfEHFrameSection = "\t.section\t.eh_frame,\"aw\",@progbits";
DwarfExceptionSection = "\t.section\t.gcc_except_table,\"a\",@progbits";
break;