/// take a chain as input and return a chain.
EH_LABEL,
+ /// CATCHRET - Represents a return from a catch block funclet. Used for
+ /// MSVC compatible exception handling. Takes a chain operand and a
+ /// destination basic block operand.
CATCHRET,
+ /// CLEANUPRET - Represents a return from a cleanup block funclet. Used for
+ /// MSVC compatible exception handling. Takes only a chain operand.
CLEANUPRET,
/// STACKSAVE - STACKSAVE has one operand, an input chain. It produces a
// The following structs respresent the .xdata for functions using C++
// exceptions on Windows.
+typedef PointerUnion<const BasicBlock *, MachineBasicBlock *> MBBOrBasicBlock;
+typedef PointerUnion<const Value *, MachineBasicBlock *> ValueOrMBB;
+
struct WinEHUnwindMapEntry {
int ToState;
- const Value *Cleanup;
+ ValueOrMBB Cleanup;
};
-typedef PointerUnion<const BasicBlock *, MachineBasicBlock *> MBBOrBasicBlock;
-typedef PointerUnion<const Value *, MachineBasicBlock *> ValueOrMBB;
-
/// Similar to WinEHUnwindMapEntry, but supports SEH filters.
struct SEHUnwindMapEntry {
/// If unwinding continues through this handler, transition to the handler at
/// Retreive the MCSymbol for a GlobalValue or MachineBasicBlock. GlobalValues
/// are used in the old WinEH scheme, and they will be removed eventually.
static MCSymbol *getMCSymbolForMBBOrGV(AsmPrinter *Asm, ValueOrMBB Handler) {
+ if (!Handler)
+ return nullptr;
if (Handler.is<MachineBasicBlock *>())
return Handler.get<MachineBasicBlock *>()->getSymbol();
- else
- return Asm->getSymbol(cast<GlobalValue>(Handler.get<const Value *>()));
+ return Asm->getSymbol(cast<GlobalValue>(Handler.get<const Value *>()));
}
void WinException::emitCXXFrameHandler3Table(const MachineFunction *MF) {
if (UnwindMapXData) {
OS.EmitLabel(UnwindMapXData);
for (const WinEHUnwindMapEntry &UME : FuncInfo.UnwindMap) {
- OS.EmitIntValue(UME.ToState, 4); // ToState
- OS.EmitValue(create32bitRef(UME.Cleanup), 4); // Action
+ MCSymbol *CleanupSym = getMCSymbolForMBBOrGV(Asm, UME.Cleanup);
+ OS.EmitIntValue(UME.ToState, 4); // ToState
+ OS.EmitValue(create32bitRef(CleanupSym), 4); // Action
}
}
assert(&*BB->begin() == I &&
"WinEHPrepare failed to remove PHIs from imaginary BBs");
continue;
- } else if (!isa<LandingPadInst>(I)) {
- llvm_unreachable("unhandled EH pad in MBB graph");
}
}
SmallVector<const LandingPadInst *, 4> LPads;
for (BB = Fn->begin(); BB != EB; ++BB) {
const Instruction *FNP = BB->getFirstNonPHI();
- if (BB->isEHPad() && !isa<CatchPadInst>(FNP) && !isa<CatchEndPadInst>(FNP))
+ if (BB->isEHPad() && MBBMap.count(BB))
MBBMap[BB]->setIsEHPad();
if (const auto *LPI = dyn_cast<LandingPadInst>(FNP))
LPads.push_back(LPI);
// Calculate state numbers if we haven't already.
WinEHFuncInfo &EHInfo = MMI.getWinEHFuncInfo(&fn);
- if (Personality == EHPersonality::MSVC_CXX) {
- const Function *WinEHParentFn = MMI.getWinEHParent(&fn);
+ const Function *WinEHParentFn = MMI.getWinEHParent(&fn);
+ if (Personality == EHPersonality::MSVC_CXX)
calculateWinCXXEHStateNumbers(WinEHParentFn, EHInfo);
- } else {
- const Function *WinEHParentFn = MMI.getWinEHParent(&fn);
+ else
calculateSEHStateNumbers(WinEHParentFn, EHInfo);
+
+ // Map all BB references in the WinEH data to MBBs.
+ for (WinEHTryBlockMapEntry &TBME : EHInfo.TryBlockMap)
+ for (WinEHHandlerType &H : TBME.HandlerArray)
+ if (const auto *BB =
+ dyn_cast<BasicBlock>(H.Handler.get<const Value *>()))
+ H.Handler = MBBMap[BB];
+ for (WinEHUnwindMapEntry &UME : EHInfo.UnwindMap)
+ if (UME.Cleanup)
+ if (const auto *BB = dyn_cast<BasicBlock>(UME.Cleanup.get<const Value *>()))
+ UME.Cleanup = MBBMap[BB];
+ for (SEHUnwindMapEntry &UME : EHInfo.SEHUnwindMap) {
+ const BasicBlock *BB = UME.Handler.get<const BasicBlock *>();
+ UME.Handler = MBBMap[BB];
}
- // Map all BB references in the EH data to MBBs.
- for (WinEHTryBlockMapEntry &TBME : EHInfo.TryBlockMap)
- for (WinEHHandlerType &H : TBME.HandlerArray)
- if (const auto *BB =
- dyn_cast<BasicBlock>(H.Handler.get<const Value *>()))
- H.Handler = MBBMap[BB];
- for (SEHUnwindMapEntry &UME : EHInfo.SEHUnwindMap) {
- const BasicBlock *BB = UME.Handler.get<const BasicBlock *>();
- UME.Handler = MBBMap[BB];
- }
// If there's an explicit EH registration node on the stack, record its
// frame index.
if (EHInfo.EHRegNode && EHInfo.EHRegNode->getParent()->getParent() == Fn) {
void SelectionDAGBuilder::visitCatchRet(const CatchReturnInst &I) {
// Update machine-CFG edge.
- MachineBasicBlock *PadMBB = FuncInfo.MBB;
MachineBasicBlock *TargetMBB = FuncInfo.MBBMap[I.getSuccessor()];
- PadMBB->addSuccessor(TargetMBB);
+ FuncInfo.MBB->addSuccessor(TargetMBB);
// Create the terminator node.
SDValue Ret = DAG.getNode(ISD::CATCHRET, getCurSDLoc(), MVT::Other,
}
void SelectionDAGBuilder::visitCleanupPad(const CleanupPadInst &CPI) {
- report_fatal_error("visitCleanupPad not yet implemented!");
+ // Don't emit any special code for the cleanuppad instruction. It just marks
+ // the start of a funclet.
+ FuncInfo.MBB->setIsEHFuncletEntry();
+}
+
+/// When an invoke or a cleanupret unwinds to the next EH pad, there are
+/// many places it could ultimately go. In the IR, we have a single unwind
+/// destination, but in the machine CFG, we enumerate all the possible blocks.
+/// This function skips over imaginary basic blocks that hold catchpad,
+/// terminatepad, or catchendpad instructions, and finds all the "real" machine
+/// basic block destinations.
+static void
+findUnwindDestinations(FunctionLoweringInfo &FuncInfo,
+ const BasicBlock *EHPadBB,
+ SmallVectorImpl<MachineBasicBlock *> &UnwindDests) {
+ bool IsMSVCCXX = classifyEHPersonality(FuncInfo.Fn->getPersonalityFn()) ==
+ EHPersonality::MSVC_CXX;
+ while (EHPadBB) {
+ const Instruction *Pad = EHPadBB->getFirstNonPHI();
+ if (isa<LandingPadInst>(Pad)) {
+ // Stop on landingpads. They are not funclets.
+ UnwindDests.push_back(FuncInfo.MBBMap[EHPadBB]);
+ break;
+ } else if (isa<CleanupPadInst>(Pad) || isa<LandingPadInst>(Pad)) {
+ // Stop on cleanup pads. Cleanups are always funclet entries for all known
+ // personalities.
+ UnwindDests.push_back(FuncInfo.MBBMap[EHPadBB]);
+ UnwindDests.back()->setIsEHFuncletEntry();
+ break;
+ } else if (const auto *CPI = dyn_cast<CatchPadInst>(Pad)) {
+ // Add the catchpad handler to the possible destinations.
+ UnwindDests.push_back(FuncInfo.MBBMap[CPI->getNormalDest()]);
+ // In MSVC C++, catchblocks are funclets and need prologues.
+ if (IsMSVCCXX)
+ UnwindDests.back()->setIsEHFuncletEntry();
+ EHPadBB = CPI->getUnwindDest();
+ } else if (const auto *CEPI = dyn_cast<CatchEndPadInst>(Pad)) {
+ EHPadBB = CEPI->getUnwindDest();
+ } else if (const auto *CEPI = dyn_cast<CleanupEndPadInst>(Pad)) {
+ EHPadBB = CEPI->getUnwindDest();
+ }
+ }
}
void SelectionDAGBuilder::visitCleanupRet(const CleanupReturnInst &I) {
- report_fatal_error("visitCleanupRet not yet implemented!");
+ // Update successor info.
+ // FIXME: The weights for catchpads will be wrong.
+ SmallVector<MachineBasicBlock *, 1> UnwindDests;
+ findUnwindDestinations(FuncInfo, I.getUnwindDest(), UnwindDests);
+ for (MachineBasicBlock *UnwindDest : UnwindDests) {
+ UnwindDest->setIsEHPad();
+ addSuccessorWithWeight(FuncInfo.MBB, UnwindDest);
+ }
+
+ // Create the terminator node.
+ SDValue Ret =
+ DAG.getNode(ISD::CLEANUPRET, getCurSDLoc(), MVT::Other, getControlRoot());
+ DAG.setRoot(Ret);
}
void SelectionDAGBuilder::visitCleanupEndPad(const CleanupEndPadInst &I) {
CopyToExportRegsIfNeeded(&I);
}
- // Stop when we hit a pad that generates real code or we unwind to caller.
- // Catchpads are conditional branches that add real MBB destinations and
- // continue the loop. EH "end" pads are not real BBs and simply continue.
SmallVector<MachineBasicBlock *, 1> UnwindDests;
- bool IsMSVCCXX = classifyEHPersonality(FuncInfo.Fn->getPersonalityFn()) ==
- EHPersonality::MSVC_CXX;
- while (EHPadBB) {
- const Instruction *Pad = EHPadBB->getFirstNonPHI();
- if (isa<LandingPadInst>(Pad)) {
- // Stop on landingpads. They are not funclets.
- UnwindDests.push_back(FuncInfo.MBBMap[EHPadBB]);
- break;
- } else if (isa<CleanupPadInst>(Pad) || isa<LandingPadInst>(Pad)) {
- // Stop on cleanup pads. Cleanups are always funclet entries for all known
- // personalities.
- UnwindDests.push_back(FuncInfo.MBBMap[EHPadBB]);
- UnwindDests.back()->setIsEHFuncletEntry();
- break;
- } else if (const auto *CPI = dyn_cast<CatchPadInst>(Pad)) {
- // Add the catchpad handler to the possible destinations.
- UnwindDests.push_back(FuncInfo.MBBMap[CPI->getNormalDest()]);
- // In MSVC C++, catchblocks are funclets and need prologues.
- if (IsMSVCCXX)
- UnwindDests.back()->setIsEHFuncletEntry();
- EHPadBB = CPI->getUnwindDest();
- } else if (const auto *CEPI = dyn_cast<CatchEndPadInst>(Pad)) {
- EHPadBB = CEPI->getUnwindDest();
- } else if (const auto *CEPI = dyn_cast<CleanupEndPadInst>(Pad)) {
- EHPadBB = CEPI->getUnwindDest();
- }
- }
+ findUnwindDestinations(FuncInfo, EHPadBB, UnwindDests);
// Update successor info.
// FIXME: The weights for catchpads will be wrong.
}
static int addSEHHandler(WinEHFuncInfo &FuncInfo, int ParentState,
- const Function *Filter, const BasicBlock *Handler) {
+ const Function *Filter, const BasicBlock *Handler) {
SEHUnwindMapEntry Entry;
Entry.ToState = ParentState;
Entry.Filter = Filter;
switch (MI->getOpcode()) {
case X86::CATCHRET:
case X86::CATCHRET64:
+ case X86::CLEANUPRET:
+ case X86::CLEANUPRET64:
return true;
default:
return false;
}
setOperationAction(ISD::EH_RETURN , MVT::Other, Custom);
setOperationAction(ISD::CATCHRET , MVT::Other, Custom);
+ setOperationAction(ISD::CLEANUPRET , MVT::Other, Custom);
// NOTE: EH_SJLJ_SETJMP/_LONGJMP supported here is NOT intended to support
// SjLj exception handling but a light-weight setjmp/longjmp replacement to
// support continuation, user-level threading, and etc.. As a result, no
return DAG.getNode(ISD::BR, DL, MVT::Other, Chain, Dest);
}
-
unsigned ReturnReg = (PtrVT == MVT::i64 ? X86::RAX : X86::EAX);
// Load the address of the destination block.
+ // FIXME: Do this without creating a BlockAddress.
MachineBasicBlock *DestMBB = cast<BasicBlockSDNode>(Dest)->getBasicBlock();
- SDValue BlockPtr = DAG.getMCSymbol(DestMBB->getSymbol(), PtrVT);
- unsigned WrapperKind =
- Subtarget->isPICStyleRIPRel() ? X86ISD::WrapperRIP : X86ISD::Wrapper;
- SDValue WrappedPtr = DAG.getNode(WrapperKind, DL, PtrVT, BlockPtr);
- Chain = DAG.getCopyToReg(Chain, DL, ReturnReg, WrappedPtr);
+ BlockAddress *BA =
+ BlockAddress::get(const_cast<Function *>(MF.getFunction()),
+ const_cast<BasicBlock *>(DestMBB->getBasicBlock()));
+ DestMBB->setHasAddressTaken();
+ SDValue BlockPtr = DAG.getBlockAddress(BA, PtrVT);
+ Chain = DAG.getCopyToReg(Chain, DL, ReturnReg, BlockPtr);
return DAG.getNode(X86ISD::CATCHRET, DL, MVT::Other, Chain,
DAG.getRegister(ReturnReg, PtrVT));
}
+SDValue X86TargetLowering::LowerCLEANUPRET(SDValue Op, SelectionDAG &DAG) const {
+ return DAG.getNode(X86ISD::CLEANUPRET, SDLoc(Op), MVT::Other,
+ Op.getOperand(0));
+}
+
SDValue X86TargetLowering::lowerEH_SJLJ_SETJMP(SDValue Op,
SelectionDAG &DAG) const {
SDLoc DL(Op);
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);
+ case ISD::CLEANUPRET: return LowerCLEANUPRET(Op, DAG);
case ISD::CATCHRET: return LowerCATCHRET(Op, DAG);
case ISD::EH_SJLJ_SETJMP: return lowerEH_SJLJ_SETJMP(Op, DAG);
case ISD::EH_SJLJ_LONGJMP: return lowerEH_SJLJ_LONGJMP(Op, DAG);
case X86ISD::EH_SJLJ_LONGJMP: return "X86ISD::EH_SJLJ_LONGJMP";
case X86ISD::EH_RETURN: return "X86ISD::EH_RETURN";
case X86ISD::CATCHRET: return "X86ISD::CATCHRET";
+ case X86ISD::CLEANUPRET: return "X86ISD::CLEANUPRET";
case X86ISD::TC_RETURN: return "X86ISD::TC_RETURN";
case X86ISD::FNSTCW16m: return "X86ISD::FNSTCW16m";
case X86ISD::FNSTSW16r: return "X86ISD::FNSTSW16r";
// Exception Handling helpers.
EH_RETURN,
+ // CATCHRET - Represents a return from a catch block funclet. Used for
+ // MSVC compatible exception handling. Takes a chain operand and RAX.
CATCHRET,
+ // CLEANUPRET - Represents a return from a cleanup block funclet. Used
+ // for MSVC compatible exception handling. Takes only a chain operand.
+ CLEANUPRET,
+
// SjLj exception handling setjmp.
EH_SJLJ_SETJMP,
SDValue LowerFRAME_TO_ARGS_OFFSET(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerEH_RETURN(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerCATCHRET(SDValue Op, SelectionDAG &DAG) const;
+ SDValue LowerCLEANUPRET(SDValue Op, SelectionDAG &DAG) const;
SDValue lowerEH_SJLJ_SETJMP(SDValue Op, SelectionDAG &DAG) const;
SDValue lowerEH_SJLJ_LONGJMP(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerINIT_TRAMPOLINE(SDValue Op, SelectionDAG &DAG) const;
def CATCHRET64 : I<0xC3, RawFrm, (outs), (ins GR64:$addr),
"ret{q}\t# CATCHRET",
[(X86catchret GR64:$addr)], IIC_RET>, Sched<[WriteJumpLd]>;
+def CLEANUPRET : I<0xC3, RawFrm, (outs), (ins),
+ "ret{l}\t# CLEANUPRET",
+ [(X86cleanupret)], IIC_RET>, Sched<[WriteJumpLd]>,
+ Requires<[Not64BitMode]>;
+def CLEANUPRET64 : I<0xC3, RawFrm, (outs), (ins),
+ "ret{q}\t# CLEANUPRET",
+ [(X86cleanupret)], IIC_RET>, Sched<[WriteJumpLd]>,
+ Requires<[In64BitMode]>;
}
let hasSideEffects = 1, isBarrier = 1, isCodeGenOnly = 1,
def X86catchret : SDNode<"X86ISD::CATCHRET", SDT_X86EHRET, [SDNPHasChain]>;
+def X86cleanupret : SDNode<"X86ISD::CLEANUPRET", SDTX86Void, [SDNPHasChain]>;
+
def X86eh_sjlj_setjmp : SDNode<"X86ISD::EH_SJLJ_SETJMP",
SDTypeProfile<1, 1, [SDTCisInt<0>,
SDTCisPtrTy<1>]>,
; X86: movl $0, -{{[0-9]+}}(%ebp)
; X86: movl $1, (%esp)
; X86: calll _f
-; X86: [[contbb:LBB0_[0-9]+]]:
+; X86: [[contbb:Ltmp[0-9]+]]: # Block address taken
; X86: movl -{{[0-9]+}}(%ebp), %esp
; X86: addl ${{[0-9]+}}, %esp
; X86: popl %esi
; X64: callq useints
; X64: movl $1, %ecx
; X64: callq f
-; X64: [[contbb:\.LBB0_[0-9]+]]:
+; X64: [[contbb:.Ltmp[0-9]+]]: # Block address taken
; X64: addq $40, %rsp
; X64: popq %rbp
; X64: retq
; X86-DAG: movl %[[addr_reg]], 4(%esp)
; X86-DAG: movl $1, (%esp)
; X86: calll _f
-; X86: [[contbb:LBB0_[0-9]+]]:
+; X86: [[contbb:Ltmp[0-9]+]]: # Block address taken
; X86: movl -{{[0-9]+}}(%ebp), %esp
; X86: retl
; X64-DAG: leaq -[[local_offs:[0-9]+]](%rbp), %rdx
; X64-DAG: movl $1, %ecx
; X64: callq f
-; X64: [[contbb:\.LBB0_[0-9]+]]:
+; X64: [[contbb:.Ltmp[0-9]+]]: # Block address taken
; X64: addq $48, %rsp
; X64: popq %rbp
; X64: retq