llvm.org GIT mirror llvm / 7577188
[WinEH] Add codegen support for cleanuppad and cleanupret All of the complexity is in cleanupret, and it mostly follows the same codepaths as catchret, except it doesn't take a return value in RAX. This small example now compiles and executes successfully on win32: extern "C" int printf(const char *, ...) noexcept; struct Dtor { ~Dtor() { printf("~Dtor\n"); } }; void has_cleanup() { Dtor o; throw 42; } int main() { try { has_cleanup(); } catch (int) { printf("caught it\n"); } } Don't try to put the cleanup in the same function as the catch, or Bad Things will happen. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@247219 91177308-0d34-0410-b5e6-96231b3b80d8 Reid Kleckner 4 years ago
13 changed file(s) with 131 addition(s) and 72 deletion(s). Raw diff Collapse all Expand all
590590 /// take a chain as input and return a chain.
591591 EH_LABEL,
592592
593 /// CATCHRET - Represents a return from a catch block funclet. Used for
594 /// MSVC compatible exception handling. Takes a chain operand and a
595 /// destination basic block operand.
593596 CATCHRET,
594597
598 /// CLEANUPRET - Represents a return from a cleanup block funclet. Used for
599 /// MSVC compatible exception handling. Takes only a chain operand.
595600 CLEANUPRET,
596601
597602 /// STACKSAVE - STACKSAVE has one operand, an input chain. It produces a
115115 // The following structs respresent the .xdata for functions using C++
116116 // exceptions on Windows.
117117
118 typedef PointerUnion MBBOrBasicBlock;
119 typedef PointerUnion ValueOrMBB;
120
118121 struct WinEHUnwindMapEntry {
119122 int ToState;
120 const Value *Cleanup;
123 ValueOrMBB Cleanup;
121124 };
122
123 typedef PointerUnion MBBOrBasicBlock;
124 typedef PointerUnion ValueOrMBB;
125125
126126 /// Similar to WinEHUnwindMapEntry, but supports SEH filters.
127127 struct SEHUnwindMapEntry {
315315 /// Retreive the MCSymbol for a GlobalValue or MachineBasicBlock. GlobalValues
316316 /// are used in the old WinEH scheme, and they will be removed eventually.
317317 static MCSymbol *getMCSymbolForMBBOrGV(AsmPrinter *Asm, ValueOrMBB Handler) {
318 if (!Handler)
319 return nullptr;
318320 if (Handler.is())
319321 return Handler.get()->getSymbol();
320 else
321 return Asm->getSymbol(cast(Handler.get()));
322 return Asm->getSymbol(cast(Handler.get()));
322323 }
323324
324325 void WinException::emitCXXFrameHandler3Table(const MachineFunction *MF) {
403404 if (UnwindMapXData) {
404405 OS.EmitLabel(UnwindMapXData);
405406 for (const WinEHUnwindMapEntry &UME : FuncInfo.UnwindMap) {
406 OS.EmitIntValue(UME.ToState, 4); // ToState
407 OS.EmitValue(create32bitRef(UME.Cleanup), 4); // Action
407 MCSymbol *CleanupSym = getMCSymbolForMBBOrGV(Asm, UME.Cleanup);
408 OS.EmitIntValue(UME.ToState, 4); // ToState
409 OS.EmitValue(create32bitRef(CleanupSym), 4); // Action
408410 }
409411 }
410412
222222 assert(&*BB->begin() == I &&
223223 "WinEHPrepare failed to remove PHIs from imaginary BBs");
224224 continue;
225 } else if (!isa(I)) {
226 llvm_unreachable("unhandled EH pad in MBB graph");
227225 }
228226 }
229227
268266 SmallVector LPads;
269267 for (BB = Fn->begin(); BB != EB; ++BB) {
270268 const Instruction *FNP = BB->getFirstNonPHI();
271 if (BB->isEHPad() && !isa(FNP) && !isa(FNP))
269 if (BB->isEHPad() && MBBMap.count(BB))
272270 MBBMap[BB]->setIsEHPad();
273271 if (const auto *LPI = dyn_cast(FNP))
274272 LPads.push_back(LPI);
288286
289287 // Calculate state numbers if we haven't already.
290288 WinEHFuncInfo &EHInfo = MMI.getWinEHFuncInfo(&fn);
291 if (Personality == EHPersonality::MSVC_CXX) {
292 const Function *WinEHParentFn = MMI.getWinEHParent(&fn);
289 const Function *WinEHParentFn = MMI.getWinEHParent(&fn);
290 if (Personality == EHPersonality::MSVC_CXX)
293291 calculateWinCXXEHStateNumbers(WinEHParentFn, EHInfo);
294 } else {
295 const Function *WinEHParentFn = MMI.getWinEHParent(&fn);
292 else
296293 calculateSEHStateNumbers(WinEHParentFn, EHInfo);
297 }
298
299 // Map all BB references in the EH data to MBBs.
300 for (WinEHTryBlockMapEntry &TBME : EHInfo.TryBlockMap)
301 for (WinEHHandlerType &H : TBME.HandlerArray)
302 if (const auto *BB =
303 dyn_cast(H.Handler.get()))
304 H.Handler = MBBMap[BB];
305 for (SEHUnwindMapEntry &UME : EHInfo.SEHUnwindMap) {
306 const BasicBlock *BB = UME.Handler.get();
307 UME.Handler = MBBMap[BB];
308 }
294
295 // Map all BB references in the WinEH data to MBBs.
296 for (WinEHTryBlockMapEntry &TBME : EHInfo.TryBlockMap)
297 for (WinEHHandlerType &H : TBME.HandlerArray)
298 if (const auto *BB =
299 dyn_cast(H.Handler.get()))
300 H.Handler = MBBMap[BB];
301 for (WinEHUnwindMapEntry &UME : EHInfo.UnwindMap)
302 if (UME.Cleanup)
303 if (const auto *BB = dyn_cast(UME.Cleanup.get()))
304 UME.Cleanup = MBBMap[BB];
305 for (SEHUnwindMapEntry &UME : EHInfo.SEHUnwindMap) {
306 const BasicBlock *BB = UME.Handler.get();
307 UME.Handler = MBBMap[BB];
308 }
309
309310 // If there's an explicit EH registration node on the stack, record its
310311 // frame index.
311312 if (EHInfo.EHRegNode && EHInfo.EHRegNode->getParent()->getParent() == Fn) {
11641164
11651165 void SelectionDAGBuilder::visitCatchRet(const CatchReturnInst &I) {
11661166 // Update machine-CFG edge.
1167 MachineBasicBlock *PadMBB = FuncInfo.MBB;
11681167 MachineBasicBlock *TargetMBB = FuncInfo.MBBMap[I.getSuccessor()];
1169 PadMBB->addSuccessor(TargetMBB);
1168 FuncInfo.MBB->addSuccessor(TargetMBB);
11701169
11711170 // Create the terminator node.
11721171 SDValue Ret = DAG.getNode(ISD::CATCHRET, getCurSDLoc(), MVT::Other,
11791178 }
11801179
11811180 void SelectionDAGBuilder::visitCleanupPad(const CleanupPadInst &CPI) {
1182 report_fatal_error("visitCleanupPad not yet implemented!");
1181 // Don't emit any special code for the cleanuppad instruction. It just marks
1182 // the start of a funclet.
1183 FuncInfo.MBB->setIsEHFuncletEntry();
1184 }
1185
1186 /// When an invoke or a cleanupret unwinds to the next EH pad, there are
1187 /// many places it could ultimately go. In the IR, we have a single unwind
1188 /// destination, but in the machine CFG, we enumerate all the possible blocks.
1189 /// This function skips over imaginary basic blocks that hold catchpad,
1190 /// terminatepad, or catchendpad instructions, and finds all the "real" machine
1191 /// basic block destinations.
1192 static void
1193 findUnwindDestinations(FunctionLoweringInfo &FuncInfo,
1194 const BasicBlock *EHPadBB,
1195 SmallVectorImpl &UnwindDests) {
1196 bool IsMSVCCXX = classifyEHPersonality(FuncInfo.Fn->getPersonalityFn()) ==
1197 EHPersonality::MSVC_CXX;
1198 while (EHPadBB) {
1199 const Instruction *Pad = EHPadBB->getFirstNonPHI();
1200 if (isa(Pad)) {
1201 // Stop on landingpads. They are not funclets.
1202 UnwindDests.push_back(FuncInfo.MBBMap[EHPadBB]);
1203 break;
1204 } else if (isa(Pad) || isa(Pad)) {
1205 // Stop on cleanup pads. Cleanups are always funclet entries for all known
1206 // personalities.
1207 UnwindDests.push_back(FuncInfo.MBBMap[EHPadBB]);
1208 UnwindDests.back()->setIsEHFuncletEntry();
1209 break;
1210 } else if (const auto *CPI = dyn_cast(Pad)) {
1211 // Add the catchpad handler to the possible destinations.
1212 UnwindDests.push_back(FuncInfo.MBBMap[CPI->getNormalDest()]);
1213 // In MSVC C++, catchblocks are funclets and need prologues.
1214 if (IsMSVCCXX)
1215 UnwindDests.back()->setIsEHFuncletEntry();
1216 EHPadBB = CPI->getUnwindDest();
1217 } else if (const auto *CEPI = dyn_cast(Pad)) {
1218 EHPadBB = CEPI->getUnwindDest();
1219 } else if (const auto *CEPI = dyn_cast(Pad)) {
1220 EHPadBB = CEPI->getUnwindDest();
1221 }
1222 }
11831223 }
11841224
11851225 void SelectionDAGBuilder::visitCleanupRet(const CleanupReturnInst &I) {
1186 report_fatal_error("visitCleanupRet not yet implemented!");
1226 // Update successor info.
1227 // FIXME: The weights for catchpads will be wrong.
1228 SmallVector UnwindDests;
1229 findUnwindDestinations(FuncInfo, I.getUnwindDest(), UnwindDests);
1230 for (MachineBasicBlock *UnwindDest : UnwindDests) {
1231 UnwindDest->setIsEHPad();
1232 addSuccessorWithWeight(FuncInfo.MBB, UnwindDest);
1233 }
1234
1235 // Create the terminator node.
1236 SDValue Ret =
1237 DAG.getNode(ISD::CLEANUPRET, getCurSDLoc(), MVT::Other, getControlRoot());
1238 DAG.setRoot(Ret);
11871239 }
11881240
11891241 void SelectionDAGBuilder::visitCleanupEndPad(const CleanupEndPadInst &I) {
20192071 CopyToExportRegsIfNeeded(&I);
20202072 }
20212073
2022 // Stop when we hit a pad that generates real code or we unwind to caller.
2023 // Catchpads are conditional branches that add real MBB destinations and
2024 // continue the loop. EH "end" pads are not real BBs and simply continue.
20252074 SmallVector UnwindDests;
2026 bool IsMSVCCXX = classifyEHPersonality(FuncInfo.Fn->getPersonalityFn()) ==
2027 EHPersonality::MSVC_CXX;
2028 while (EHPadBB) {
2029 const Instruction *Pad = EHPadBB->getFirstNonPHI();
2030 if (isa(Pad)) {
2031 // Stop on landingpads. They are not funclets.
2032 UnwindDests.push_back(FuncInfo.MBBMap[EHPadBB]);
2033 break;
2034 } else if (isa(Pad) || isa(Pad)) {
2035 // Stop on cleanup pads. Cleanups are always funclet entries for all known
2036 // personalities.
2037 UnwindDests.push_back(FuncInfo.MBBMap[EHPadBB]);
2038 UnwindDests.back()->setIsEHFuncletEntry();
2039 break;
2040 } else if (const auto *CPI = dyn_cast(Pad)) {
2041 // Add the catchpad handler to the possible destinations.
2042 UnwindDests.push_back(FuncInfo.MBBMap[CPI->getNormalDest()]);
2043 // In MSVC C++, catchblocks are funclets and need prologues.
2044 if (IsMSVCCXX)
2045 UnwindDests.back()->setIsEHFuncletEntry();
2046 EHPadBB = CPI->getUnwindDest();
2047 } else if (const auto *CEPI = dyn_cast(Pad)) {
2048 EHPadBB = CEPI->getUnwindDest();
2049 } else if (const auto *CEPI = dyn_cast(Pad)) {
2050 EHPadBB = CEPI->getUnwindDest();
2051 }
2052 }
2075 findUnwindDestinations(FuncInfo, EHPadBB, UnwindDests);
20532076
20542077 // Update successor info.
20552078 // FIXME: The weights for catchpads will be wrong.
30523052 }
30533053
30543054 static int addSEHHandler(WinEHFuncInfo &FuncInfo, int ParentState,
3055 const Function *Filter, const BasicBlock *Handler) {
3055 const Function *Filter, const BasicBlock *Handler) {
30563056 SEHUnwindMapEntry Entry;
30573057 Entry.ToState = ParentState;
30583058 Entry.Filter = Filter;
10291029 switch (MI->getOpcode()) {
10301030 case X86::CATCHRET:
10311031 case X86::CATCHRET64:
1032 case X86::CLEANUPRET:
1033 case X86::CLEANUPRET64:
10321034 return true;
10331035 default:
10341036 return false;
417417 }
418418 setOperationAction(ISD::EH_RETURN , MVT::Other, Custom);
419419 setOperationAction(ISD::CATCHRET , MVT::Other, Custom);
420 setOperationAction(ISD::CLEANUPRET , MVT::Other, Custom);
420421 // NOTE: EH_SJLJ_SETJMP/_LONGJMP supported here is NOT intended to support
421422 // SjLj exception handling but a light-weight setjmp/longjmp replacement to
422423 // support continuation, user-level threading, and etc.. As a result, no
1688816889 return DAG.getNode(ISD::BR, DL, MVT::Other, Chain, Dest);
1688916890 }
1689016891
16891
1689216892 unsigned ReturnReg = (PtrVT == MVT::i64 ? X86::RAX : X86::EAX);
1689316893
1689416894 // Load the address of the destination block.
16895 // FIXME: Do this without creating a BlockAddress.
1689516896 MachineBasicBlock *DestMBB = cast(Dest)->getBasicBlock();
16896 SDValue BlockPtr = DAG.getMCSymbol(DestMBB->getSymbol(), PtrVT);
16897 unsigned WrapperKind =
16898 Subtarget->isPICStyleRIPRel() ? X86ISD::WrapperRIP : X86ISD::Wrapper;
16899 SDValue WrappedPtr = DAG.getNode(WrapperKind, DL, PtrVT, BlockPtr);
16900 Chain = DAG.getCopyToReg(Chain, DL, ReturnReg, WrappedPtr);
16897 BlockAddress *BA =
16898 BlockAddress::get(const_cast(MF.getFunction()),
16899 const_cast(DestMBB->getBasicBlock()));
16900 DestMBB->setHasAddressTaken();
16901 SDValue BlockPtr = DAG.getBlockAddress(BA, PtrVT);
16902 Chain = DAG.getCopyToReg(Chain, DL, ReturnReg, BlockPtr);
1690116903 return DAG.getNode(X86ISD::CATCHRET, DL, MVT::Other, Chain,
1690216904 DAG.getRegister(ReturnReg, PtrVT));
16905 }
16906
16907 SDValue X86TargetLowering::LowerCLEANUPRET(SDValue Op, SelectionDAG &DAG) const {
16908 return DAG.getNode(X86ISD::CLEANUPRET, SDLoc(Op), MVT::Other,
16909 Op.getOperand(0));
1690316910 }
1690416911
1690516912 SDValue X86TargetLowering::lowerEH_SJLJ_SETJMP(SDValue Op,
1914119148 return LowerFRAME_TO_ARGS_OFFSET(Op, DAG);
1914219149 case ISD::DYNAMIC_STACKALLOC: return LowerDYNAMIC_STACKALLOC(Op, DAG);
1914319150 case ISD::EH_RETURN: return LowerEH_RETURN(Op, DAG);
19151 case ISD::CLEANUPRET: return LowerCLEANUPRET(Op, DAG);
1914419152 case ISD::CATCHRET: return LowerCATCHRET(Op, DAG);
1914519153 case ISD::EH_SJLJ_SETJMP: return lowerEH_SJLJ_SETJMP(Op, DAG);
1914619154 case ISD::EH_SJLJ_LONGJMP: return lowerEH_SJLJ_LONGJMP(Op, DAG);
1947919487 case X86ISD::EH_SJLJ_LONGJMP: return "X86ISD::EH_SJLJ_LONGJMP";
1948019488 case X86ISD::EH_RETURN: return "X86ISD::EH_RETURN";
1948119489 case X86ISD::CATCHRET: return "X86ISD::CATCHRET";
19490 case X86ISD::CLEANUPRET: return "X86ISD::CLEANUPRET";
1948219491 case X86ISD::TC_RETURN: return "X86ISD::TC_RETURN";
1948319492 case X86ISD::FNSTCW16m: return "X86ISD::FNSTCW16m";
1948419493 case X86ISD::FNSTSW16r: return "X86ISD::FNSTSW16r";
267267 // Exception Handling helpers.
268268 EH_RETURN,
269269
270 // CATCHRET - Represents a return from a catch block funclet. Used for
271 // MSVC compatible exception handling. Takes a chain operand and RAX.
270272 CATCHRET,
273
274 // CLEANUPRET - Represents a return from a cleanup block funclet. Used
275 // for MSVC compatible exception handling. Takes only a chain operand.
276 CLEANUPRET,
271277
272278 // SjLj exception handling setjmp.
273279 EH_SJLJ_SETJMP,
10081014 SDValue LowerFRAME_TO_ARGS_OFFSET(SDValue Op, SelectionDAG &DAG) const;
10091015 SDValue LowerEH_RETURN(SDValue Op, SelectionDAG &DAG) const;
10101016 SDValue LowerCATCHRET(SDValue Op, SelectionDAG &DAG) const;
1017 SDValue LowerCLEANUPRET(SDValue Op, SelectionDAG &DAG) const;
10111018 SDValue lowerEH_SJLJ_SETJMP(SDValue Op, SelectionDAG &DAG) const;
10121019 SDValue lowerEH_SJLJ_LONGJMP(SDValue Op, SelectionDAG &DAG) const;
10131020 SDValue LowerINIT_TRAMPOLINE(SDValue Op, SelectionDAG &DAG) const;
158158 def CATCHRET64 : I<0xC3, RawFrm, (outs), (ins GR64:$addr),
159159 "ret{q}\t# CATCHRET",
160160 [(X86catchret GR64:$addr)], IIC_RET>, Sched<[WriteJumpLd]>;
161 def CLEANUPRET : I<0xC3, RawFrm, (outs), (ins),
162 "ret{l}\t# CLEANUPRET",
163 [(X86cleanupret)], IIC_RET>, Sched<[WriteJumpLd]>,
164 Requires<[Not64BitMode]>;
165 def CLEANUPRET64 : I<0xC3, RawFrm, (outs), (ins),
166 "ret{q}\t# CLEANUPRET",
167 [(X86cleanupret)], IIC_RET>, Sched<[WriteJumpLd]>,
168 Requires<[In64BitMode]>;
161169 }
162170
163171 let hasSideEffects = 1, isBarrier = 1, isCodeGenOnly = 1,
205205 [SDNPHasChain]>;
206206
207207 def X86catchret : SDNode<"X86ISD::CATCHRET", SDT_X86EHRET, [SDNPHasChain]>;
208
209 def X86cleanupret : SDNode<"X86ISD::CLEANUPRET", SDTX86Void, [SDNPHasChain]>;
208210
209211 def X86eh_sjlj_setjmp : SDNode<"X86ISD::EH_SJLJ_SETJMP",
210212 SDTypeProfile<1, 1, [SDTCisInt<0>,
6262 ; X86: movl $0, -{{[0-9]+}}(%ebp)
6363 ; X86: movl $1, (%esp)
6464 ; X86: calll _f
65 ; X86: [[contbb:LBB0_[0-9]+]]:
65 ; X86: [[contbb:Ltmp[0-9]+]]: # Block address taken
6666 ; X86: movl -{{[0-9]+}}(%ebp), %esp
6767 ; X86: addl ${{[0-9]+}}, %esp
6868 ; X86: popl %esi
110110 ; X64: callq useints
111111 ; X64: movl $1, %ecx
112112 ; X64: callq f
113 ; X64: [[contbb:\.LBB0_[0-9]+]]:
113 ; X64: [[contbb:.Ltmp[0-9]+]]: # Block address taken
114114 ; X64: addq $40, %rsp
115115 ; X64: popq %rbp
116116 ; X64: retq
7070 ; X86-DAG: movl %[[addr_reg]], 4(%esp)
7171 ; X86-DAG: movl $1, (%esp)
7272 ; X86: calll _f
73 ; X86: [[contbb:LBB0_[0-9]+]]:
73 ; X86: [[contbb:Ltmp[0-9]+]]: # Block address taken
7474 ; X86: movl -{{[0-9]+}}(%ebp), %esp
7575 ; X86: retl
7676
119119 ; X64-DAG: leaq -[[local_offs:[0-9]+]](%rbp), %rdx
120120 ; X64-DAG: movl $1, %ecx
121121 ; X64: callq f
122 ; X64: [[contbb:\.LBB0_[0-9]+]]:
122 ; X64: [[contbb:.Ltmp[0-9]+]]: # Block address taken
123123 ; X64: addq $48, %rsp
124124 ; X64: popq %rbp
125125 ; X64: retq