llvm.org GIT mirror llvm / 0ba86fa
[WinEH] Teach AsmPrinter about funclets Summary: Funclets have been turned into functions by the time they hit the object file. Make sure that they have decent names for the symbol table and CFI directives explaining how to reason about their prologues. Differential Revision: http://reviews.llvm.org/D13261 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@248824 91177308-0d34-0410-b5e6-96231b3b80d8 David Majnemer 4 years ago
18 changed file(s) with 320 addition(s) and 66 deletion(s). Raw diff Collapse all Expand all
112112
113113 /// Indicate that this basic block is the entry block of an EH funclet.
114114 bool IsEHFuncletEntry = false;
115
116 /// Indicate that this basic block is the entry block of a cleanup funclet.
117 bool IsCleanupFuncletEntry = false;
115118
116119 /// \brief since getSymbol is a relatively heavy-weight operation, the symbol
117120 /// is only computed once and is cached.
391394 /// Indicates if this is the entry block of an EH funclet.
392395 void setIsEHFuncletEntry(bool V = true) { IsEHFuncletEntry = V; }
393396
397 /// Returns true if this is the entry block of a cleanup funclet.
398 bool isCleanupFuncletEntry() const { return IsCleanupFuncletEntry; }
399
400 /// Indicates if this is the entry block of a cleanup funclet.
401 void setIsCleanupFuncletEntry(bool V = true) { IsCleanupFuncletEntry = V; }
402
394403 // Code Layout methods.
395404
396405 /// Move 'this' block before or after the specified block. This only moves
117117 // exceptions on Windows.
118118
119119 typedef PointerUnion MBBOrBasicBlock;
120 typedef PointerUnionMachineBasicBlock *> ValueOrMBB;
120 typedef PointerUnionconst MachineBasicBlock *> ValueOrMBB;
121121
122122 struct WinEHUnwindMapEntry {
123123 int ToState;
24582458 /// MachineBasicBlock, an alignment (if present) and a comment describing
24592459 /// it if appropriate.
24602460 void AsmPrinter::EmitBasicBlockStart(const MachineBasicBlock &MBB) const {
2461 // End the previous funclet and start a new one.
2462 if (MBB.isEHFuncletEntry()) {
2463 for (const HandlerInfo &HI : Handlers) {
2464 HI.Handler->endFunclet();
2465 HI.Handler->beginFunclet(MBB);
2466 }
2467 }
2468
24612469 // Emit an alignment directive for this block, if needed.
24622470 if (unsigned Align = MBB.getAlignment())
24632471 EmitAlignment(Align);
1818
1919 namespace llvm {
2020
21 class MachineBasicBlock;
2122 class MachineFunction;
2223 class MachineInstr;
2324 class MCSymbol;
4950 /// beginFunction at all.
5051 virtual void endFunction(const MachineFunction *MF) = 0;
5152
53 /// \brief Emit target-specific EH funclet machinery.
54 virtual void beginFunclet(const MachineBasicBlock &MBB,
55 MCSymbol *Sym = nullptr) {}
56 virtual void endFunclet() {}
57
5258 /// \brief Process beginning of an instruction.
5359 virtual void beginInstruction(const MachineInstr *MI) = 0;
5460
2929 #include "llvm/MC/MCStreamer.h"
3030 #include "llvm/MC/MCSymbol.h"
3131 #include "llvm/MC/MCWin64EH.h"
32 #include "llvm/Support/COFF.h"
3233 #include "llvm/Support/Dwarf.h"
3334 #include "llvm/Support/ErrorHandling.h"
3435 #include "llvm/Support/FormattedStream.h"
9798 return;
9899 }
99100
100 if (shouldEmitMoves || shouldEmitPersonality)
101 Asm->OutStreamer->EmitWinCFIStartProc(Asm->CurrentFnSym);
102
103 if (shouldEmitPersonality) {
104 const MCSymbol *PersHandlerSym =
105 TLOF.getCFIPersonalitySymbol(Per, *Asm->Mang, Asm->TM, MMI);
106 Asm->OutStreamer->EmitWinEHHandler(PersHandlerSym, true, true);
107 }
101 beginFunclet(MF->front(), Asm->CurrentFnSym);
108102 }
109103
110104 /// endFunction - Gather and emit post-function exception information.
124118 if (!isMSVCEHPersonality(Per))
125119 MMI->TidyLandingPads();
126120
121 endFunclet();
122
127123 if (shouldEmitPersonality || shouldEmitLSDA) {
128124 Asm->OutStreamer->PushSection();
129125
130 if (shouldEmitMoves || shouldEmitPersonality) {
131 // Emit an UNWIND_INFO struct describing the prologue.
132 Asm->OutStreamer->EmitWinEHHandlerData();
133 } else {
134 // Just switch sections to the right xdata section. This use of
135 // CurrentFnSym assumes that we only emit the LSDA when ending the parent
136 // function.
137 MCSection *XData = WinEH::UnwindEmitter::getXDataSection(
138 Asm->CurrentFnSym, Asm->OutContext);
139 Asm->OutStreamer->SwitchSection(XData);
140 }
126 // Just switch sections to the right xdata section. This use of CurrentFnSym
127 // assumes that we only emit the LSDA when ending the parent function.
128 MCSection *XData = WinEH::UnwindEmitter::getXDataSection(Asm->CurrentFnSym,
129 Asm->OutContext);
130 Asm->OutStreamer->SwitchSection(XData);
141131
142132 // Emit the tables appropriate to the personality function in use. If we
143133 // don't recognize the personality, assume it uses an Itanium-style LSDA.
152142
153143 Asm->OutStreamer->PopSection();
154144 }
155
145 }
146
147 /// Retreive the MCSymbol for a GlobalValue or MachineBasicBlock. GlobalValues
148 /// are used in the old WinEH scheme, and they will be removed eventually.
149 static MCSymbol *getMCSymbolForMBBOrGV(AsmPrinter *Asm, ValueOrMBB Handler) {
150 if (!Handler)
151 return nullptr;
152 if (Handler.is()) {
153 auto *MBB = Handler.get();
154 assert(MBB->isEHFuncletEntry());
155
156 // Give catches and cleanups a name based off of their parent function and
157 // their funclet entry block's number.
158 const MachineFunction *MF = MBB->getParent();
159 const Function *F = MF->getFunction();
160 StringRef FuncLinkageName = GlobalValue::getRealLinkageName(F->getName());
161 MCContext &Ctx = MF->getContext();
162 StringRef HandlerPrefix = MBB->isCleanupFuncletEntry() ? "dtor" : "catch";
163 return Ctx.getOrCreateSymbol("?" + HandlerPrefix + "$" +
164 Twine(MBB->getNumber()) + "@?0?" +
165 FuncLinkageName + "@4HA");
166 }
167 return Asm->getSymbol(cast(Handler.get()));
168 }
169
170 void WinException::beginFunclet(const MachineBasicBlock &MBB,
171 MCSymbol *Sym) {
172 CurrentFuncletEntry = &MBB;
173
174 const Function *F = Asm->MF->getFunction();
175 // If a symbol was not provided for the funclet, invent one.
176 if (!Sym) {
177 Sym = getMCSymbolForMBBOrGV(Asm, &MBB);
178
179 // Describe our funclet symbol as a function with internal linkage.
180 Asm->OutStreamer->BeginCOFFSymbolDef(Sym);
181 Asm->OutStreamer->EmitCOFFSymbolStorageClass(COFF::IMAGE_SYM_CLASS_STATIC);
182 Asm->OutStreamer->EmitCOFFSymbolType(COFF::IMAGE_SYM_DTYPE_FUNCTION
183 << COFF::SCT_COMPLEX_TYPE_SHIFT);
184 Asm->OutStreamer->EndCOFFSymbolDef();
185
186 // We want our funclet's entry point to be aligned such that no nops will be
187 // present after the label.
188 Asm->EmitAlignment(std::max(Asm->MF->getAlignment(), MBB.getAlignment()),
189 F);
190
191 // Now that we've emitted the alignment directive, point at our funclet.
192 Asm->OutStreamer->EmitLabel(Sym);
193 }
194
195 // Mark 'Sym' as starting our funclet.
156196 if (shouldEmitMoves || shouldEmitPersonality)
197 Asm->OutStreamer->EmitWinCFIStartProc(Sym);
198
199 if (shouldEmitPersonality) {
200 const TargetLoweringObjectFile &TLOF = Asm->getObjFileLowering();
201 const Function *PerFn = nullptr;
202
203 // Determine which personality routine we are using for this funclet.
204 if (F->hasPersonalityFn())
205 PerFn = dyn_cast(F->getPersonalityFn()->stripPointerCasts());
206 const MCSymbol *PersHandlerSym =
207 TLOF.getCFIPersonalitySymbol(PerFn, *Asm->Mang, Asm->TM, MMI);
208
209 // Classify the personality routine so that we may reason about it.
210 EHPersonality Per = EHPersonality::Unknown;
211 if (F->hasPersonalityFn())
212 Per = classifyEHPersonality(F->getPersonalityFn());
213
214 // Do not emit a .seh_handler directive if it is a C++ cleanup funclet.
215 if (Per != EHPersonality::MSVC_CXX ||
216 !CurrentFuncletEntry->isCleanupFuncletEntry())
217 Asm->OutStreamer->EmitWinEHHandler(PersHandlerSym, true, true);
218 }
219 }
220
221 void WinException::endFunclet() {
222 // No funclet to process? Great, we have nothing to do.
223 if (!CurrentFuncletEntry)
224 return;
225
226 if (shouldEmitMoves || shouldEmitPersonality) {
227 const Function *F = Asm->MF->getFunction();
228 EHPersonality Per = EHPersonality::Unknown;
229 if (F->hasPersonalityFn())
230 Per = classifyEHPersonality(F->getPersonalityFn());
231
232 // The .seh_handlerdata directive implicitly switches section, push the
233 // current section so that we may return to it.
234 Asm->OutStreamer->PushSection();
235
236 // Emit an UNWIND_INFO struct describing the prologue.
237 Asm->OutStreamer->EmitWinEHHandlerData();
238
239 // If this is a C++ catch funclet (or the parent function),
240 // emit a reference to the LSDA for the parent function.
241 if (Per == EHPersonality::MSVC_CXX && shouldEmitPersonality &&
242 !CurrentFuncletEntry->isCleanupFuncletEntry()) {
243 StringRef FuncLinkageName = GlobalValue::getRealLinkageName(F->getName());
244 MCSymbol *FuncInfoXData = Asm->OutContext.getOrCreateSymbol(
245 Twine("$cppxdata$", FuncLinkageName));
246 Asm->OutStreamer->EmitValue(create32bitRef(FuncInfoXData), 4);
247 }
248
249 // Switch back to the previous section now that we are done writing to
250 // .xdata.
251 Asm->OutStreamer->PopSection();
252
253 // Emit a .seh_endproc directive to mark the end of the function.
157254 Asm->OutStreamer->EmitWinCFIEndProc();
255 }
256
257 // Let's make sure we don't try to end the same funclet twice.
258 CurrentFuncletEntry = nullptr;
158259 }
159260
160261 const MCExpr *WinException::create32bitRef(const MCSymbol *Value) {
298399 }
299400 }
300401
301 /// Retreive the MCSymbol for a GlobalValue or MachineBasicBlock. GlobalValues
302 /// are used in the old WinEH scheme, and they will be removed eventually.
303 static MCSymbol *getMCSymbolForMBBOrGV(AsmPrinter *Asm, ValueOrMBB Handler) {
304 if (!Handler)
305 return nullptr;
306 if (Handler.is())
307 return Handler.get()->getSymbol();
308 return Asm->getSymbol(cast(Handler.get()));
309 }
310
311402 void WinException::emitCXXFrameHandler3Table(const MachineFunction *MF) {
312403 const Function *F = MF->getFunction();
313404 auto &OS = *Asm->OutStreamer;
322413 // IPs to state numbers.
323414 FuncInfoXData =
324415 Asm->OutContext.getOrCreateSymbol(Twine("$cppxdata$", FuncLinkageName));
325 OS.EmitValue(create32bitRef(FuncInfoXData), 4);
326416 computeIP2StateTable(MF, FuncInfo, IPToStateTable);
327417 } else {
328418 FuncInfoXData = Asm->OutContext.getOrCreateLSDASymbol(FuncLinkageName);
3434
3535 /// True if this is a 64-bit target and we should use image relative offsets.
3636 bool useImageRel32 = false;
37
38 /// Pointer to the current funclet entry BB.
39 const MachineBasicBlock *CurrentFuncletEntry = nullptr;
3740
3841 void emitCSpecificHandlerTable(const MachineFunction *MF);
3942
7578
7679 /// Gather and emit post-function exception information.
7780 void endFunction(const MachineFunction *) override;
81
82 /// \brief Emit target-specific EH funclet machinery.
83 void beginFunclet(const MachineBasicBlock &MBB, MCSymbol *Sym) override;
84 void endFunclet() override;
7885 };
7986 }
8087
11811181 // Don't emit any special code for the cleanuppad instruction. It just marks
11821182 // the start of a funclet.
11831183 FuncInfo.MBB->setIsEHFuncletEntry();
1184 FuncInfo.MBB->setIsCleanupFuncletEntry();
11841185 }
11851186
11861187 /// When an invoke or a cleanupret unwinds to the next EH pad, there are
712712 // Reset EBP / ESI to something good.
713713 MBBI = restoreWin32EHStackPointers(MBB, MBBI, DL);
714714 } else {
715 // FIXME: Add SEH directives.
716 NeedsWinCFI = false;
717715 // Immediately spill RDX into the home slot. The runtime cares about this.
718716 unsigned RDX = Uses64BitFramePtr ? X86::RDX : X86::EDX;
719717 // MOV64mr %rdx, 16(%rsp)
725723 // PUSH64r %rbp
726724 BuildMI(MBB, MBBI, DL, TII.get(X86::PUSH64r))
727725 .addReg(MachineFramePtr, RegState::Kill)
726 .setMIFlag(MachineInstr::FrameSetup);
727 BuildMI(MBB, MBBI, DL, TII.get(X86::SEH_PushReg))
728 .addImm(MachineFramePtr)
728729 .setMIFlag(MachineInstr::FrameSetup);
729730 // MOV64rr %rdx, %rbp
730731 unsigned MOVrr = Uses64BitFramePtr ? X86::MOV64rr : X86::MOV32rr;
3434 ; CHECK: .seh_handler __C_specific_handler
3535 ; CHECK-NOT: jmpq *
3636 ; CHECK: .seh_handlerdata
37 ; CHECK-NEXT: .text
38 ; CHECK: .seh_endproc
39 ; CHECK: .section .xdata,"dr"
3740 ; CHECK-NEXT: .long 1
3841 ; CHECK-NEXT: .long .Ltmp{{.*}}
3942 ; CHECK-NEXT: .long .Ltmp{{.*}}
1717 ; MINGW64: .seh_setframe 5, 32
1818 ; MINGW64: callq _Unwind_Resume
1919 ; MINGW64: .seh_handlerdata
20 ; MINGW64: .seh_endproc
2021 ; MINGW64: GCC_except_table0:
2122 ; MINGW64: Lexception0:
22 ; MINGW64: .seh_endproc
2323
2424 ; MINGW32: .cfi_startproc
2525 ; MINGW32: .cfi_personality 0, ___gxx_personality_v0
3737 ; CHECK: callq printf
3838
3939 ; CHECK: .seh_handlerdata
40 ; CHECK-NEXT: .text
41 ; CHECK-NEXT: .Ltmp{{[0-9]+}}
42 ; CHECK-NEXT: .seh_endproc
43 ; CHECK-NEXT: .section .xdata,"dr"
4044 ; CHECK-NEXT: .long 1
4145 ; CHECK-NEXT: .long .Ltmp{{[0-9]+}}@IMGREL
4246 ; CHECK-NEXT: .long .Ltmp{{[0-9]+}}@IMGREL+1
102102 ; CHECK: retq
103103 ;
104104 ; CHECK: .seh_handlerdata
105 ; CHECK-NEXT: .text
106 ; CHECK-NEXT: .Ltmp{{[0-9]+}}
107 ; CHECK-NEXT: .seh_endproc
108 ; CHECK-NEXT: .section .xdata,"dr"
105109 ; CHECK-NEXT: .long 3
106110 ; CHECK-NEXT: .long .Ltmp0@IMGREL
107111 ; CHECK-NEXT: .long .Ltmp1@IMGREL+1
3737 ; X64: retq
3838
3939 ; X64: .seh_handlerdata
40 ; X64-NEXT: .text
41 ; X64-NEXT: .Ltmp{{[0-9]+}}:
42 ; X64-NEXT: .seh_endproc
43 ; X64-NEXT: .section .xdata,"dr"
4044 ; X64-NEXT: .long 1
4145 ; X64-NEXT: .long .Ltmp0@IMGREL
4246 ; X64-NEXT: .long .Ltmp1@IMGREL
8989 ; CHECK: jmp [[cont_bb]]
9090
9191 ; CHECK: .seh_handlerdata
92 ; CHECK-NEXT: .text
93 ; CHECK-NEXT: .Ltmp{{[0-9]+}}
94 ; CHECK-NEXT: .seh_endproc
95 ; CHECK-NEXT: .section .xdata,"dr"
9296 ; CHECK-NEXT: .long 2
9397 ; CHECK-NEXT: .long .Ltmp0@IMGREL
9498 ; CHECK-NEXT: .long .Ltmp1@IMGREL+1
7070 ; X86: addl $12, %ebp
7171 ; X86: jmp [[contbb]]
7272
73 ; X86: [[catch1bb:LBB0_[0-9]+]]: # %catch{{$}}
73 ; X86: "?catch$[[catch1bb:[0-9]+]]@?0?try_catch_catch@4HA":
74 ; X86: LBB0_[[catch1bb]]: # %catch{{$}}
7475 ; X86: pushl %ebp
7576 ; X86-NOT: pushl
7677 ; X86: addl $12, %ebp
8889 ; X86: .long 0
8990 ; X86: .long "??_R0H@8"
9091 ; X86: .long 0
91 ; X86: .long [[catch1bb]]
92 ; X86: .long "?catch$[[catch1bb]]@?0?try_catch_catch@4HA"
9293
9394 ; X64-LABEL: try_catch_catch:
9495 ; X64: pushq %rbp
115116 ; X64: popq %rbp
116117 ; X64: retq
117118
118 ; X64: [[catch1bb:\.LBB0_[0-9]+]]: # %catch{{$}}
119 ; X64: "?catch$[[catch1bb:[0-9]+]]@?0?try_catch_catch@4HA":
120 ; X64: LBB0_[[catch1bb]]: # %catch{{$}}
119121 ; X64: movq %rdx, 16(%rsp)
120122 ; X64: pushq %rbp
121123 ; X64: movq %rdx, %rbp
131133 ; X64: .long 0
132134 ; X64: .long "??_R0H@8"@IMGREL
133135 ; X64: .long 0
134 ; X64: .long [[catch1bb]]@IMGREL
136 ; X64: .long "?catch$[[catch1bb]]@?0?try_catch_catch@4HA"@IMGREL
135137 ; X64: .long 56
7777 ; X86: addl $12, %ebp
7878 ; X86: jmp [[contbb]]
7979
80 ; X86: [[catch1bb:LBB0_[0-9]+]]: # %catch{{$}}
80 ; X86: "?catch$[[catch1bb:[0-9]+]]@?0?try_catch_catch@4HA":
81 ; X86: LBB0_[[catch1bb]]: # %catch{{$}}
8182 ; X86: pushl %ebp
8283 ; X86: addl $12, %ebp
8384 ; X86: subl $8, %esp
9293 ; X86-NEXT: movl $[[restorebb]], %eax
9394 ; X86-NEXT: retl
9495
95 ; X86: [[catch2bb:LBB0_[0-9]+]]: # %catch.2{{$}}
96 ; X86: "?catch$[[catch2bb:[0-9]+]]@?0?try_catch_catch@4HA":
97 ; X86: LBB0_[[catch2bb]]: # %catch.2{{$}}
9698 ; X86: pushl %ebp
9799 ; X86: addl $12, %ebp
98100 ; X86: subl $8, %esp
111113 ; X86-NEXT: .long 0
112114 ; X86-NEXT: .long "??_R0H@8"
113115 ; X86-NEXT: .long -20
114 ; X86-NEXT: .long [[catch1bb]]
116 ; X86-NEXT: .long "?catch$[[catch1bb]]@?0?try_catch_catch@4HA"
115117 ; X86-NEXT: .long 64
116118 ; X86-NEXT: .long 0
117119 ; X86-NEXT: .long 0
118 ; X86-NEXT: .long [[catch2bb]]
120 ; X86-NEXT: .long "?catch$[[catch2bb]]@?0?try_catch_catch@4HA"
119121
120122 ; X64-LABEL: try_catch_catch:
121123 ; X64: Lfunc_begin0:
134136 ; X64: popq %rbp
135137 ; X64: retq
136138
137 ; X64: [[catch1bb:\.LBB0_[0-9]+]]: # %catch{{$}}
139 ; X64: "?catch$[[catch1bb:[0-9]+]]@?0?try_catch_catch@4HA":
140 ; X64: LBB0_[[catch1bb]]: # %catch{{$}}
138141 ; X64: movq %rdx, 16(%rsp)
139142 ; X64: pushq %rbp
140143 ; X64: movq %rdx, %rbp
148151 ; X64-NEXT: leaq [[contbb]](%rip), %rax
149152 ; X64-NEXT: retq
150153
151 ; X64: [[catch2bb:\.LBB0_[0-9]+]]: # %catch.2{{$}}
154 ; X64: "?catch$[[catch2bb:[0-9]+]]@?0?try_catch_catch@4HA":
155 ; X64: LBB0_[[catch2bb]]: # %catch.2{{$}}
152156 ; X64: movq %rdx, 16(%rsp)
153157 ; X64: pushq %rbp
154158 ; X64: movq %rdx, %rbp
186190 ; X64-NEXT: .long "??_R0H@8"@IMGREL
187191 ; FIXME: This should probably be offset from rsp, not rbp.
188192 ; X64-NEXT: .long [[e_addr]]
189 ; X64-NEXT: .long [[catch1bb]]@IMGREL
193 ; X64-NEXT: .long "?catch$[[catch1bb]]@?0?try_catch_catch@4HA"@IMGREL
190194 ; X64-NEXT: .long 56
191195 ; X64-NEXT: .long 64
192196 ; X64-NEXT: .long 0
193197 ; X64-NEXT: .long 0
194 ; X64-NEXT: .long [[catch2bb]]@IMGREL
198 ; X64-NEXT: .long "?catch$[[catch2bb]]@?0?try_catch_catch@4HA"@IMGREL
195199 ; X64-NEXT: .long 56
196200
197201 ; X64: $ip2state$try_catch_catch:
6464 ; X86: movl $3, (%esp)
6565 ; X86: calll _f
6666
67 ; X86: LBB1_[[cleanup_inner:[0-9]+]]: # %cleanup.inner
67 ; X86: "?dtor$[[cleanup_inner:[0-9]+]]@?0?nested_cleanup@4HA":
68 ; X86: LBB1_[[cleanup_inner]]: # %cleanup.inner{{$}}
6869 ; X86: pushl %ebp
6970 ; X86: leal {{.*}}(%ebp), %ecx
7071 ; X86: calll "??1Dtor@@QAE@XZ"
7172 ; X86: popl %ebp
7273 ; X86: retl
7374
74 ; X86: LBB1_[[cleanup_outer:[0-9]+]]: # %cleanup.outer
75 ; X86: "?dtor$[[cleanup_outer:[0-9]+]]@?0?nested_cleanup@4HA":
76 ; X86: LBB1_[[cleanup_outer]]: # %cleanup.outer{{$}}
7577 ; X86: pushl %ebp
7678 ; X86: leal {{.*}}(%ebp), %ecx
7779 ; X86: calll "??1Dtor@@QAE@XZ"
9092 ; X86: .long 1
9193 ; X86: $stateUnwindMap$nested_cleanup:
9294 ; X86: .long -1
93 ; X86: .long LBB1_[[cleanup_outer]]
95 ; X86: .long "?dtor$[[cleanup_outer]]@?0?nested_cleanup@4HA"
9496 ; X86: .long 0
95 ; X86: .long LBB1_[[cleanup_inner]]
97 ; X86: .long "?dtor$[[cleanup_inner]]@?0?nested_cleanup@4HA"
9698
9799 ; X64-LABEL: nested_cleanup:
98100 ; X64: .Lfunc_begin1:
99 ; X64: .Ltmp8:
101 ; X64: .Ltmp14:
100102 ; X64: movl $1, %ecx
101103 ; X64: callq f
102 ; X64: .Ltmp10:
104 ; X64: .Ltmp16:
103105 ; X64: movl $2, %ecx
104106 ; X64: callq f
105 ; X64: .Ltmp11:
107 ; X64: .Ltmp17:
106108 ; X64: callq "??1Dtor@@QAE@XZ"
107 ; X64: .Ltmp12:
109 ; X64: .Ltmp18:
108110 ; X64: movl $3, %ecx
109111 ; X64: callq f
110 ; X64: .Ltmp13:
112 ; X64: .Ltmp19:
111113
112 ; X64: .LBB1_[[cleanup_inner:[0-9]+]]: # %cleanup.inner
114 ; X64: "?dtor$[[cleanup_inner:[0-9]+]]@?0?nested_cleanup@4HA":
115 ; X64: LBB1_[[cleanup_inner]]: # %cleanup.inner{{$}}
113116 ; X64: pushq %rbp
114117 ; X64: leaq {{.*}}(%rbp), %rcx
115118 ; X64: callq "??1Dtor@@QAE@XZ"
116119 ; X64: popq %rbp
117120 ; X64: retq
118121
119 ; X64: .LBB1_[[cleanup_outer:[0-9]+]]: # %cleanup.outer
122 ; X64: .seh_handlerdata
123 ; X64: .text
124 ; X64: .seh_endproc
125
126 ; X64: "?dtor$[[cleanup_outer:[0-9]+]]@?0?nested_cleanup@4HA":
127 ; X64: LBB1_[[cleanup_outer]]: # %cleanup.outer{{$}}
120128 ; X64: pushq %rbp
121129 ; X64: leaq {{.*}}(%rbp), %rcx
122130 ; X64: callq "??1Dtor@@QAE@XZ"
123131 ; X64: popq %rbp
124132 ; X64: retq
125133
126 ; X64: .seh_handlerdata
127 ; X64-NEXT: .long ($cppxdata$nested_cleanup)@IMGREL
134 ; X64: .section .xdata,"dr"
128135 ; X64-NEXT: .align 4
129136 ; X64: $cppxdata$nested_cleanup:
130137 ; X64-NEXT: .long 429065506
140147
141148 ; X64: $stateUnwindMap$nested_cleanup:
142149 ; X64-NEXT: .long -1
143 ; X64-NEXT: .long .LBB1_[[cleanup_outer]]@IMGREL
150 ; X64-NEXT: .long "?dtor$[[cleanup_outer]]@?0?nested_cleanup@4HA"@IMGREL
144151 ; X64-NEXT: .long 0
145 ; X64-NEXT: .long .LBB1_[[cleanup_inner]]@IMGREL
152 ; X64-NEXT: .long "?dtor$[[cleanup_inner]]@?0?nested_cleanup@4HA"@IMGREL
146153
147154 ; X64: $ip2state$nested_cleanup:
148155 ; X64-NEXT: .long .Lfunc_begin1@IMGREL
149156 ; X64-NEXT: .long -1
150 ; X64-NEXT: .long .Ltmp8@IMGREL
157 ; X64-NEXT: .long .Ltmp14@IMGREL
151158 ; X64-NEXT: .long 0
152 ; X64-NEXT: .long .Ltmp10@IMGREL
159 ; X64-NEXT: .long .Ltmp16@IMGREL
153160 ; X64-NEXT: .long 1
154 ; X64-NEXT: .long .Ltmp12@IMGREL
161 ; X64-NEXT: .long .Ltmp18@IMGREL
155162 ; X64-NEXT: .long 0
156 ; X64-NEXT: .long .Ltmp13@IMGREL+1
163 ; X64-NEXT: .long .Ltmp19@IMGREL+1
157164 ; X64-NEXT: .long -1
158165
159166 attributes #0 = { "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-realign-stack" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
0 ; RUN: llc -mtriple=x86_64-windows-msvc < %s | FileCheck %s
1
2 target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
3 target triple = "x86_64-pc-windows-msvc"
4
5 define void @"\01?f@@YAXXZ"(i1 %B) personality i32 (...)* @__CxxFrameHandler3 {
6 entry:
7 invoke void @g()
8 to label %unreachable unwind label %cleanupblock
9
10 cleanupblock:
11 %cleanp = cleanuppad []
12 call void @g()
13 cleanupret %cleanp unwind label %catch.dispatch
14
15 catch.dispatch:
16 %cp = catchpad [i8* null, i32 64, i8* null]
17 to label %catch unwind label %catchendblock
18
19 catch:
20 call void @g()
21 catchret %cp to label %try.cont
22
23 try.cont:
24 ret void
25
26 catchendblock:
27 catchendpad unwind to caller
28
29 unreachable:
30 unreachable
31 }
32
33
34 declare void @g()
35
36 declare i32 @__CxxFrameHandler3(...)
37
38 ; Destructors need CFI but they shouldn't use the .seh_handler directive.
39 ; CHECK: "?dtor$[[cleanup:[0-9]+]]@?0??f@@YAXXZ@4HA":
40 ; CHECK: .seh_proc "?dtor$[[cleanup]]@?0??f@@YAXXZ@4HA"
41 ; CHECK-NOT: .seh_handler __CxxFrameHandler3
42 ; CHECK: LBB0_[[cleanup]]: # %cleanupblock{{$}}
43
44 ; Emit CFI for pushing RBP.
45 ; CHECK: movq %rdx, 16(%rsp)
46 ; CHECK: pushq %rbp
47 ; CHECK: .seh_pushreg 5
48
49 ; Emit CFI for allocating from the stack pointer.
50 ; CHECK: subq $32, %rsp
51 ; CHECK: .seh_stackalloc 32
52
53 ; FIXME: This looks wrong...
54 ; CHECK: leaq 32(%rsp), %rbp
55 ; CHECK: .seh_setframe 5, 32
56
57 ; Prologue is done, emit the .seh_endprologue directive.
58 ; CHECK: .seh_endprologue
59
60 ; Make sure there is a nop after a call if the call precedes the epilogue.
61 ; CHECK: callq g
62 ; CHECK-NEXT: nop
63
64 ; Don't emit a reference to the LSDA.
65 ; CHECK: .seh_handlerdata
66 ; CHECK-NOT: .long ("$cppxdata$?f@@YAXXZ")@IMGREL
67 ; CHECK-NEXT: .text
68 ; CHECK: .seh_endproc
69
70 ; CHECK: "?catch$[[catch:[0-9]+]]@?0??f@@YAXXZ@4HA":
71 ; CHECK: .seh_proc "?catch$[[catch]]@?0??f@@YAXXZ@4HA"
72 ; CHECK-NEXT: .seh_handler __CxxFrameHandler3, @unwind, @except
73 ; CHECK: LBB0_[[catch]]: # %catch{{$}}
74
75 ; Emit CFI for pushing RBP.
76 ; CHECK: movq %rdx, 16(%rsp)
77 ; CHECK: pushq %rbp
78 ; CHECK: .seh_pushreg 5
79
80 ; Emit CFI for allocating from the stack pointer.
81 ; CHECK: subq $32, %rsp
82 ; CHECK: .seh_stackalloc 32
83
84 ; FIXME: This looks wrong...
85 ; CHECK: leaq 32(%rsp), %rbp
86 ; CHECK: .seh_setframe 5, 32
87
88 ; Prologue is done, emit the .seh_endprologue directive.
89 ; CHECK: .seh_endprologue
90
91 ; Make sure there is a nop after a call if the call precedes the epilogue.
92 ; CHECK: callq g
93 ; CHECK-NEXT: nop
94
95 ; Emit a reference to the LSDA.
96 ; CHECK: .seh_handlerdata
97 ; CHECK-NEXT: .long ("$cppxdata$?f@@YAXXZ")@IMGREL
98 ; CHECK-NEXT: .text
99 ; CHECK: .seh_endproc