llvm.org GIT mirror llvm / 504fa89
CodeGen support for x86_64 SEH catch handlers in LLVM This adds handling for ExceptionHandling::MSVC, used by the x86_64-pc-windows-msvc triple. It assumes that filter functions have already been outlined in either the frontend or the backend. Filter functions are used in place of the landingpad catch clause type info operands. In catch clause order, the first filter to return true will catch the exception. The C specific handler table expects the landing pad to be split into one block per handler, but LLVM IR uses a single landing pad for all possible unwind actions. This patch papers over the mismatch by synthesizing single instruction BBs for every catch clause to fill in the EH selector that the landing pad block expects. Missing functionality: - Accessing data in the parent frame from outlined filters - Cleanups (from __finally) are unsupported, as they will require outlining and parent frame access - Filter clauses are unsupported, as there's no clear analogue in SEH In other words, this is the minimal set of changes needed to write IR to catch arbitrary exceptions and resume normal execution. Reviewers: majnemer Differential Revision: http://reviews.llvm.org/D6300 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@225904 91177308-0d34-0410-b5e6-96231b3b80d8 Reid Kleckner 5 years ago
12 changed file(s) with 653 addition(s) and 18 deletion(s). Raw diff Collapse all Expand all
6565 MachineBasicBlock *LandingPadBlock; // Landing pad block.
6666 SmallVector BeginLabels; // Labels prior to invoke.
6767 SmallVector EndLabels; // Labels after invoke.
68 SmallVector ClauseLabels; // Labels for each clause.
6869 MCSymbol *LandingPadLabel; // Label at beginning of landing pad.
6970 const Function *Personality; // Personality function.
7071 std::vector TypeIds; // List of type ids (filters negative)
329330 ///
330331 void addCleanup(MachineBasicBlock *LandingPad);
331332
333 /// Add a clause for a landing pad. Returns a new label for the clause. This
334 /// is used by EH schemes that have more than one landing pad. In this case,
335 /// each clause gets its own basic block.
336 MCSymbol *addClauseForLandingPad(MachineBasicBlock *LandingPad);
337
332338 /// getTypeIDFor - Return the type id for the specified typeinfo. This is
333339 /// function wide.
334340 unsigned getTypeIDFor(const GlobalValue *TI);
120120 for (unsigned J = NumShared, M = TypeIds.size(); J != M; ++J) {
121121 int TypeID = TypeIds[J];
122122 assert(-1 - TypeID < (int)FilterOffsets.size() && "Unknown filter id!");
123 int ValueForTypeID = TypeID < 0 ? FilterOffsets[-1 - TypeID] : TypeID;
123 int ValueForTypeID =
124 isFilterEHSelector(TypeID) ? FilterOffsets[-1 - TypeID] : TypeID;
124125 unsigned SizeTypeID = getSLEB128Size(ValueForTypeID);
125126
126127 int NextAction = SizeAction ? -(SizeAction + SizeTypeID) : 0;
268269 CallSiteEntry Site = {
269270 BeginLabel,
270271 LastLabel,
271 LandingPad->LandingPadLabel,
272 LandingPad,
272273 FirstActions[P.PadIndex]
273274 };
274275
275276 // Try to merge with the previous call-site. SJLJ doesn't do this
276277 if (PreviousIsInvoke && !IsSJLJ) {
277278 CallSiteEntry &Prev = CallSites.back();
278 if (Site.PadLabel == Prev.PadLabel && Site.Action == Prev.Action) {
279 if (Site.LPad == Prev.LPad && Site.Action == Prev.Action) {
279280 // Extend the range of the previous entry.
280281 Prev.EndLabel = Site.EndLabel;
281282 continue;
575576
576577 // Offset of the landing pad, counted in 16-byte bundles relative to the
577578 // @LPStart address.
578 if (!S.PadLabel) {
579 if (!S.LPad) {
579580 if (VerboseAsm)
580581 Asm->OutStreamer.AddComment(" has no landing pad");
581582 Asm->OutStreamer.EmitIntValue(0, 4/*size*/);
582583 } else {
583584 if (VerboseAsm)
584585 Asm->OutStreamer.AddComment(Twine(" jumps to ") +
585 S.PadLabel->getName());
586 Asm->EmitLabelDifference(S.PadLabel, EHFuncBeginSym, 4);
586 S.LPad->LandingPadLabel->getName());
587 Asm->EmitLabelDifference(S.LPad->LandingPadLabel, EHFuncBeginSym, 4);
587588 }
588589
589590 // Offset of the first associated action record, relative to the start of
680681 unsigned TypeID = *I;
681682 if (VerboseAsm) {
682683 --Entry;
683 if (TypeID != 0)
684 if (isFilterEHSelector(TypeID))
684685 Asm->OutStreamer.AddComment("FilterInfo " + Twine(Entry));
685686 }
686687
2222 class MachineInstr;
2323 class MachineFunction;
2424 class AsmPrinter;
25 class MCSymbol;
26 class MCSymbolRefExpr;
2527
2628 template
2729 class SmallVectorImpl;
5961 /// Structure describing an entry in the call-site table.
6062 struct CallSiteEntry {
6163 // The 'try-range' is BeginLabel .. EndLabel.
62 MCSymbol *BeginLabel; // zero indicates the start of the function.
63 MCSymbol *EndLabel; // zero indicates the end of the function.
64 MCSymbol *BeginLabel; // Null indicates the start of the function.
65 MCSymbol *EndLabel; // Null indicates the end of the function.
6466
65 // The landing pad starts at PadLabel.
66 MCSymbol *PadLabel; // zero indicates that there is no landing pad.
67 // LPad contains the landing pad start labels.
68 const LandingPadInfo *LPad; // Null indicates that there is no landing pad.
6769 unsigned Action;
6870 };
6971
111113
112114 virtual void emitTypeInfos(unsigned TTypeEncoding);
113115
116 // Helpers for for identifying what kind of clause an EH typeid or selector
117 // corresponds to. Negative selectors are for filter clauses, the zero
118 // selector is for cleanups, and positive selectors are for catch clauses.
119 static bool isFilterEHSelector(int Selector) { return Selector < 0; }
120 static bool isCleanupEHSelector(int Selector) { return Selector == 0; }
121 static bool isCatchEHSelector(int Selector) { return Selector > 0; }
122
114123 public:
115124 EHStreamer(AsmPrinter *A);
116125 virtual ~EHStreamer();
9898
9999 if (shouldEmitPersonality) {
100100 Asm->OutStreamer.PushSection();
101
102 // Emit an UNWIND_INFO struct describing the prologue.
101103 Asm->OutStreamer.EmitWinEHHandlerData();
102 emitExceptionTable();
104
105 // Emit either MSVC-compatible tables or the usual Itanium-style LSDA after
106 // the UNWIND_INFO struct.
107 if (Asm->MAI->getExceptionHandlingType() == ExceptionHandling::MSVC) {
108 const Function *Per = MMI->getPersonalities()[MMI->getPersonalityIndex()];
109 if (Per->getName() == "__C_specific_handler")
110 emitCSpecificHandlerTable();
111 else
112 report_fatal_error(Twine("unexpected personality function: ") +
113 Per->getName());
114 } else {
115 emitExceptionTable();
116 }
117
103118 Asm->OutStreamer.PopSection();
104119 }
105120 Asm->OutStreamer.EmitWinCFIEndProc();
106121 }
122
123 const MCSymbolRefExpr *Win64Exception::createImageRel32(const MCSymbol *Value) {
124 return MCSymbolRefExpr::Create(Value, MCSymbolRefExpr::VK_COFF_IMGREL32,
125 Asm->OutContext);
126 }
127
128 /// Emit the language-specific data that __C_specific_handler expects. This
129 /// handler lives in the x64 Microsoft C runtime and allows catching or cleaning
130 /// up after faults with __try, __except, and __finally. The typeinfo values
131 /// are not really RTTI data, but pointers to filter functions that return an
132 /// integer (1, 0, or -1) indicating how to handle the exception. For __finally
133 /// blocks and other cleanups, the landing pad label is zero, and the filter
134 /// function is actually a cleanup handler with the same prototype. A catch-all
135 /// entry is modeled with a null filter function field and a non-zero landing
136 /// pad label.
137 ///
138 /// Possible filter function return values:
139 /// EXCEPTION_EXECUTE_HANDLER (1):
140 /// Jump to the landing pad label after cleanups.
141 /// EXCEPTION_CONTINUE_SEARCH (0):
142 /// Continue searching this table or continue unwinding.
143 /// EXCEPTION_CONTINUE_EXECUTION (-1):
144 /// Resume execution at the trapping PC.
145 ///
146 /// Inferred table structure:
147 /// struct Table {
148 /// int NumEntries;
149 /// struct Entry {
150 /// imagerel32 LabelStart;
151 /// imagerel32 LabelEnd;
152 /// imagerel32 FilterOrFinally; // Zero means catch-all.
153 /// imagerel32 LabelLPad; // Zero means __finally.
154 /// } Entries[NumEntries];
155 /// };
156 void Win64Exception::emitCSpecificHandlerTable() {
157 const std::vector &PadInfos = MMI->getLandingPads();
158
159 // Simplifying assumptions for first implementation:
160 // - Cleanups are not implemented.
161 // - Filters are not implemented.
162
163 // The Itanium LSDA table sorts similar landing pads together to simplify the
164 // actions table, but we don't need that.
165 SmallVector LandingPads;
166 LandingPads.reserve(PadInfos.size());
167 for (const auto &LP : PadInfos)
168 LandingPads.push_back(&LP);
169
170 // Compute label ranges for call sites as we would for the Itanium LSDA, but
171 // use an all zero action table because we aren't using these actions.
172 SmallVector FirstActions;
173 FirstActions.resize(LandingPads.size());
174 SmallVector CallSites;
175 computeCallSiteTable(CallSites, LandingPads, FirstActions);
176
177 MCSymbol *EHFuncBeginSym =
178 Asm->GetTempSymbol("eh_func_begin", Asm->getFunctionNumber());
179 MCSymbol *EHFuncEndSym =
180 Asm->GetTempSymbol("eh_func_end", Asm->getFunctionNumber());
181
182 // Emit the number of table entries.
183 unsigned NumEntries = 0;
184 for (const CallSiteEntry &CSE : CallSites) {
185 if (!CSE.LPad)
186 continue; // Ignore gaps.
187 for (int Selector : CSE.LPad->TypeIds) {
188 // Ignore C++ filter clauses in SEH.
189 // FIXME: Implement cleanup clauses.
190 if (isCatchEHSelector(Selector))
191 ++NumEntries;
192 }
193 }
194 Asm->OutStreamer.EmitIntValue(NumEntries, 4);
195
196 // Emit the four-label records for each call site entry. The table has to be
197 // sorted in layout order, and the call sites should already be sorted.
198 for (const CallSiteEntry &CSE : CallSites) {
199 // Ignore gaps. Unlike the Itanium model, unwinding through a frame without
200 // an EH table entry will propagate the exception rather than terminating
201 // the program.
202 if (!CSE.LPad)
203 continue;
204 const LandingPadInfo *LPad = CSE.LPad;
205
206 // Compute the label range. We may reuse the function begin and end labels
207 // rather than forming new ones.
208 const MCExpr *Begin =
209 createImageRel32(CSE.BeginLabel ? CSE.BeginLabel : EHFuncBeginSym);
210 const MCExpr *End;
211 if (CSE.EndLabel) {
212 // The interval is half-open, so we have to add one to include the return
213 // address of the last invoke in the range.
214 End = MCBinaryExpr::CreateAdd(createImageRel32(CSE.EndLabel),
215 MCConstantExpr::Create(1, Asm->OutContext),
216 Asm->OutContext);
217 } else {
218 End = createImageRel32(EHFuncEndSym);
219 }
220
221 // These aren't really type info globals, they are actually pointers to
222 // filter functions ordered by selector. The zero selector is used for
223 // cleanups, so slot zero corresponds to selector 1.
224 const std::vector &SelectorToFilter = MMI->getTypeInfos();
225
226 // Do a parallel iteration across typeids and clause labels, skipping filter
227 // clauses.
228 assert(LPad->TypeIds.size() == LPad->ClauseLabels.size());
229 for (size_t I = 0, E = LPad->TypeIds.size(); I < E; ++I) {
230 // AddLandingPadInfo stores the clauses in reverse, but there is a FIXME
231 // to change that.
232 int Selector = LPad->TypeIds[E - I - 1];
233 MCSymbol *ClauseLabel = LPad->ClauseLabels[I];
234
235 // Ignore C++ filter clauses in SEH.
236 // FIXME: Implement cleanup clauses.
237 if (!isCatchEHSelector(Selector))
238 continue;
239
240 Asm->OutStreamer.EmitValue(Begin, 4);
241 Asm->OutStreamer.EmitValue(End, 4);
242 if (isCatchEHSelector(Selector)) {
243 assert(unsigned(Selector - 1) < SelectorToFilter.size());
244 const GlobalValue *TI = SelectorToFilter[Selector - 1];
245 if (TI) // Emit the filter function pointer.
246 Asm->OutStreamer.EmitValue(createImageRel32(Asm->getSymbol(TI)), 4);
247 else // Otherwise, this is a "catch i8* null", or catch all.
248 Asm->OutStreamer.EmitIntValue(0, 4);
249 }
250 Asm->OutStreamer.EmitValue(createImageRel32(ClauseLabel), 4);
251 }
252 }
253 }
2828 /// Per-function flag to indicate if frame moves info should be emitted.
2929 bool shouldEmitMoves;
3030
31 void emitCSpecificHandlerTable();
32
33 const MCSymbolRefExpr *createImageRel32(const MCSymbol *Value);
34
3135 public:
3236 //===--------------------------------------------------------------------===//
3337 // Main entry points.
451451 LP.TypeIds.push_back(0);
452452 }
453453
454 MCSymbol *
455 MachineModuleInfo::addClauseForLandingPad(MachineBasicBlock *LandingPad) {
456 MCSymbol *ClauseLabel = Context.CreateTempSymbol();
457 LandingPadInfo &LP = getOrCreateLandingPadInfo(LandingPad);
458 LP.ClauseLabels.push_back(ClauseLabel);
459 return ClauseLabel;
460 }
461
454462 /// TidyLandingPads - Remap landing pad labels and remove any deleted landing
455463 /// pads.
456464 void MachineModuleInfo::TidyLandingPads(DenseMap *LPMap) {
448448 case ExceptionHandling::DwarfCFI:
449449 case ExceptionHandling::ARM:
450450 case ExceptionHandling::ItaniumWinEH:
451 case ExceptionHandling::MSVC: // FIXME: Needs preparation.
451452 addPass(createDwarfEHPass(TM));
452453 break;
453 case ExceptionHandling::MSVC: // FIXME: Add preparation.
454454 case ExceptionHandling::None:
455455 addPass(createLowerInvokePass());
456456
20702070 // Get the two live-in registers as SDValues. The physregs have already been
20712071 // copied into virtual registers.
20722072 SDValue Ops[2];
2073 Ops[0] = DAG.getZExtOrTrunc(
2074 DAG.getCopyFromReg(DAG.getEntryNode(), getCurSDLoc(),
2075 FuncInfo.ExceptionPointerVirtReg, TLI.getPointerTy()),
2076 getCurSDLoc(), ValueVTs[0]);
2073 if (FuncInfo.ExceptionPointerVirtReg) {
2074 Ops[0] = DAG.getZExtOrTrunc(
2075 DAG.getCopyFromReg(DAG.getEntryNode(), getCurSDLoc(),
2076 FuncInfo.ExceptionPointerVirtReg, TLI.getPointerTy()),
2077 getCurSDLoc(), ValueVTs[0]);
2078 } else {
2079 Ops[0] = DAG.getConstant(0, TLI.getPointerTy());
2080 }
20772081 Ops[1] = DAG.getZExtOrTrunc(
20782082 DAG.getCopyFromReg(DAG.getEntryNode(), getCurSDLoc(),
20792083 FuncInfo.ExceptionSelectorVirtReg, TLI.getPointerTy()),
20832087 SDValue Res = DAG.getNode(ISD::MERGE_VALUES, getCurSDLoc(),
20842088 DAG.getVTList(ValueVTs), Ops);
20852089 setValue(&LP, Res);
2090 }
2091
2092 unsigned
2093 SelectionDAGBuilder::visitLandingPadClauseBB(GlobalValue *ClauseGV,
2094 MachineBasicBlock *LPadBB) {
2095 SDValue Chain = getControlRoot();
2096
2097 // Get the typeid that we will dispatch on later.
2098 const TargetLowering &TLI = DAG.getTargetLoweringInfo();
2099 const TargetRegisterClass *RC = TLI.getRegClassFor(TLI.getPointerTy());
2100 unsigned VReg = FuncInfo.MF->getRegInfo().createVirtualRegister(RC);
2101 unsigned TypeID = DAG.getMachineFunction().getMMI().getTypeIDFor(ClauseGV);
2102 SDValue Sel = DAG.getConstant(TypeID, TLI.getPointerTy());
2103 Chain = DAG.getCopyToReg(Chain, getCurSDLoc(), VReg, Sel);
2104
2105 // Branch to the main landing pad block.
2106 MachineBasicBlock *ClauseMBB = FuncInfo.MBB;
2107 ClauseMBB->addSuccessor(LPadBB);
2108 DAG.setRoot(DAG.getNode(ISD::BR, getCurSDLoc(), MVT::Other, Chain,
2109 DAG.getBasicBlock(LPadBB)));
2110 return VReg;
20862111 }
20872112
20882113 /// handleSmallSwitchCaseRange - Emit a series of specific tests (suitable for
712712 void visitJumpTable(JumpTable &JT);
713713 void visitJumpTableHeader(JumpTable &JT, JumpTableHeader &JTH,
714714 MachineBasicBlock *SwitchBB);
715 unsigned visitLandingPadClauseBB(GlobalValue *ClauseGV,
716 MachineBasicBlock *LPadMBB);
715717
716718 private:
717719 // These all get lowered before this pass.
1818 #include "llvm/Analysis/AliasAnalysis.h"
1919 #include "llvm/Analysis/BranchProbabilityInfo.h"
2020 #include "llvm/Analysis/CFG.h"
21 #include "llvm/CodeGen/Analysis.h"
2122 #include "llvm/CodeGen/FastISel.h"
2223 #include "llvm/CodeGen/FunctionLoweringInfo.h"
2324 #include "llvm/CodeGen/GCMetadata.h"
3940 #include "llvm/IR/Intrinsics.h"
4041 #include "llvm/IR/LLVMContext.h"
4142 #include "llvm/IR/Module.h"
43 #include "llvm/MC/MCAsmInfo.h"
4244 #include "llvm/Support/Compiler.h"
4345 #include "llvm/Support/Debug.h"
4446 #include "llvm/Support/ErrorHandling.h"
891893 void SelectionDAGISel::PrepareEHLandingPad() {
892894 MachineBasicBlock *MBB = FuncInfo->MBB;
893895
896 const TargetRegisterClass *PtrRC = TLI->getRegClassFor(TLI->getPointerTy());
897
894898 // Add a label to mark the beginning of the landing pad. Deletion of the
895899 // landing pad can thus be detected via the MachineModuleInfo.
896900 MCSymbol *Label = MF->getMMI().addLandingPad(MBB);
902906 BuildMI(*MBB, FuncInfo->InsertPt, SDB->getCurDebugLoc(), II)
903907 .addSym(Label);
904908
909 if (TM.getMCAsmInfo()->getExceptionHandlingType() ==
910 ExceptionHandling::MSVC) {
911 // Make virtual registers and a series of labels that fill in values for the
912 // clauses.
913 auto &RI = MF->getRegInfo();
914 FuncInfo->ExceptionSelectorVirtReg = RI.createVirtualRegister(PtrRC);
915
916 // Get all invoke BBs that will unwind into the clause BBs.
917 SmallVector InvokeBBs(MBB->pred_begin(),
918 MBB->pred_end());
919
920 // Emit separate machine basic blocks with separate labels for each clause
921 // before the main landing pad block.
922 const BasicBlock *LLVMBB = MBB->getBasicBlock();
923 const LandingPadInst *LPadInst = LLVMBB->getLandingPadInst();
924 MachineInstrBuilder SelectorPHI = BuildMI(
925 *MBB, MBB->begin(), SDB->getCurDebugLoc(), TII->get(TargetOpcode::PHI),
926 FuncInfo->ExceptionSelectorVirtReg);
927 for (unsigned I = 0, E = LPadInst->getNumClauses(); I != E; ++I) {
928 MachineBasicBlock *ClauseBB = MF->CreateMachineBasicBlock(LLVMBB);
929 MF->insert(MBB, ClauseBB);
930
931 // Add the edge from the invoke to the clause.
932 for (MachineBasicBlock *InvokeBB : InvokeBBs)
933 InvokeBB->addSuccessor(ClauseBB);
934
935 // Mark the clause as a landing pad or MI passes will delete it.
936 ClauseBB->setIsLandingPad();
937
938 GlobalValue *ClauseGV = ExtractTypeInfo(LPadInst->getClause(I));
939
940 // Start the BB with a label.
941 MCSymbol *ClauseLabel = MF->getMMI().addClauseForLandingPad(MBB);
942 BuildMI(*ClauseBB, ClauseBB->begin(), SDB->getCurDebugLoc(), II)
943 .addSym(ClauseLabel);
944
945 // Construct a simple BB that defines a register with the typeid constant.
946 FuncInfo->MBB = ClauseBB;
947 FuncInfo->InsertPt = ClauseBB->end();
948 unsigned VReg = SDB->visitLandingPadClauseBB(ClauseGV, MBB);
949 CurDAG->setRoot(SDB->getRoot());
950 SDB->clear();
951 CodeGenAndEmitDAG();
952
953 // Add the typeid virtual register to the phi in the main landing pad.
954 SelectorPHI.addReg(VReg).addMBB(ClauseBB);
955 }
956
957 // Remove the edge from the invoke to the lpad.
958 for (MachineBasicBlock *InvokeBB : InvokeBBs)
959 InvokeBB->removeSuccessor(MBB);
960
961 // Restore FuncInfo back to its previous state and select the main landing
962 // pad block.
963 FuncInfo->MBB = MBB;
964 FuncInfo->InsertPt = MBB->end();
965 return;
966 }
967
905968 // Mark exception register as live in.
906 const TargetRegisterClass *PtrRC = TLI->getRegClassFor(TLI->getPointerTy());
907969 if (unsigned Reg = TLI->getExceptionPointerRegister())
908970 FuncInfo->ExceptionPointerVirtReg = MBB->addLiveIn(Reg, PtrRC);
909971
0 ; RUN: llc -mtriple x86_64-pc-windows-msvc < %s | FileCheck %s
1
2 define void @two_invoke_merged() {
3 entry:
4 invoke void @try_body()
5 to label %again unwind label %lpad
6
7 again:
8 invoke void @try_body()
9 to label %done unwind label %lpad
10
11 done:
12 ret void
13
14 lpad:
15 %vals = landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__C_specific_handler to i8*)
16 catch i8* bitcast (i32 (i8*, i8*)* @filt0 to i8*)
17 catch i8* bitcast (i32 (i8*, i8*)* @filt1 to i8*)
18 %sel = extractvalue { i8*, i32 } %vals, 1
19 call void @use_selector(i32 %sel)
20 ret void
21 }
22
23 ; Normal path code
24
25 ; CHECK-LABEL: {{^}}two_invoke_merged:
26 ; CHECK: .seh_proc two_invoke_merged
27 ; CHECK: .seh_handler __C_specific_handler, @unwind, @except
28 ; CHECK: .Ltmp0:
29 ; CHECK: callq try_body
30 ; CHECK-NEXT: .Ltmp1:
31 ; CHECK: .Ltmp2:
32 ; CHECK: callq try_body
33 ; CHECK-NEXT: .Ltmp3:
34 ; CHECK: retq
35
36 ; Landing pad code
37
38 ; CHECK: .Ltmp5:
39 ; CHECK: movl $1, %ecx
40 ; CHECK: jmp
41 ; CHECK: .Ltmp6:
42 ; CHECK: movl $2, %ecx
43 ; CHECK: callq use_selector
44
45 ; CHECK: .seh_handlerdata
46 ; CHECK-NEXT: .long 2
47 ; CHECK-NEXT: .long .Ltmp0@IMGREL
48 ; CHECK-NEXT: .long .Ltmp3@IMGREL+1
49 ; CHECK-NEXT: .long filt0@IMGREL
50 ; CHECK-NEXT: .long .Ltmp5@IMGREL
51 ; CHECK-NEXT: .long .Ltmp0@IMGREL
52 ; CHECK-NEXT: .long .Ltmp3@IMGREL+1
53 ; CHECK-NEXT: .long filt1@IMGREL
54 ; CHECK-NEXT: .long .Ltmp6@IMGREL
55 ; CHECK: .text
56 ; CHECK: .seh_endproc
57
58 define void @two_invoke_gap() {
59 entry:
60 invoke void @try_body()
61 to label %again unwind label %lpad
62
63 again:
64 call void @do_nothing_on_unwind()
65 invoke void @try_body()
66 to label %done unwind label %lpad
67
68 done:
69 ret void
70
71 lpad:
72 %vals = landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__C_specific_handler to i8*)
73 catch i8* bitcast (i32 (i8*, i8*)* @filt0 to i8*)
74 %sel = extractvalue { i8*, i32 } %vals, 1
75 call void @use_selector(i32 %sel)
76 ret void
77 }
78
79 ; Normal path code
80
81 ; CHECK-LABEL: {{^}}two_invoke_gap:
82 ; CHECK: .seh_proc two_invoke_gap
83 ; CHECK: .seh_handler __C_specific_handler, @unwind, @except
84 ; CHECK: .Ltmp11:
85 ; CHECK: callq try_body
86 ; CHECK-NEXT: .Ltmp12:
87 ; CHECK: callq do_nothing_on_unwind
88 ; CHECK: .Ltmp13:
89 ; CHECK: callq try_body
90 ; CHECK-NEXT: .Ltmp14:
91 ; CHECK: retq
92
93 ; Landing pad code
94
95 ; CHECK: .Ltmp16:
96 ; CHECK: movl $1, %ecx
97 ; CHECK: callq use_selector
98
99 ; CHECK: .seh_handlerdata
100 ; CHECK-NEXT: .long 2
101 ; CHECK-NEXT: .long .Ltmp11@IMGREL
102 ; CHECK-NEXT: .long .Ltmp12@IMGREL+1
103 ; CHECK-NEXT: .long filt0@IMGREL
104 ; CHECK-NEXT: .long .Ltmp16@IMGREL
105 ; CHECK-NEXT: .long .Ltmp13@IMGREL
106 ; CHECK-NEXT: .long .Ltmp14@IMGREL+1
107 ; CHECK-NEXT: .long filt0@IMGREL
108 ; CHECK-NEXT: .long .Ltmp16@IMGREL
109 ; CHECK: .text
110 ; CHECK: .seh_endproc
111
112 define void @two_invoke_nounwind_gap() {
113 entry:
114 invoke void @try_body()
115 to label %again unwind label %lpad
116
117 again:
118 call void @cannot_unwind()
119 invoke void @try_body()
120 to label %done unwind label %lpad
121
122 done:
123 ret void
124
125 lpad:
126 %vals = landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__C_specific_handler to i8*)
127 catch i8* bitcast (i32 (i8*, i8*)* @filt0 to i8*)
128 %sel = extractvalue { i8*, i32 } %vals, 1
129 call void @use_selector(i32 %sel)
130 ret void
131 }
132
133 ; Normal path code
134
135 ; CHECK-LABEL: {{^}}two_invoke_nounwind_gap:
136 ; CHECK: .seh_proc two_invoke_nounwind_gap
137 ; CHECK: .seh_handler __C_specific_handler, @unwind, @except
138 ; CHECK: .Ltmp21:
139 ; CHECK: callq try_body
140 ; CHECK-NEXT: .Ltmp22:
141 ; CHECK: callq cannot_unwind
142 ; CHECK: .Ltmp23:
143 ; CHECK: callq try_body
144 ; CHECK-NEXT: .Ltmp24:
145 ; CHECK: retq
146
147 ; Landing pad code
148
149 ; CHECK: .Ltmp26:
150 ; CHECK: movl $1, %ecx
151 ; CHECK: callq use_selector
152
153 ; CHECK: .seh_handlerdata
154 ; CHECK-NEXT: .long 1
155 ; CHECK-NEXT: .long .Ltmp21@IMGREL
156 ; CHECK-NEXT: .long .Ltmp24@IMGREL+1
157 ; CHECK-NEXT: .long filt0@IMGREL
158 ; CHECK-NEXT: .long .Ltmp26@IMGREL
159 ; CHECK: .text
160 ; CHECK: .seh_endproc
161
162 declare void @try_body()
163 declare void @do_nothing_on_unwind()
164 declare void @cannot_unwind() nounwind
165 declare void @use_selector(i32)
166
167 declare i32 @filt0(i8* %eh_info, i8* %rsp)
168 declare i32 @filt1(i8* %eh_info, i8* %rsp)
169
170 declare void @handler0()
171 declare void @handler1()
172
173 declare i32 @__C_specific_handler(...)
174 declare i32 @llvm.eh.typeid.for(i8*) readnone nounwind
0 ; RUN: llc -mtriple x86_64-pc-windows-msvc < %s | FileCheck %s
1
2 ; This test case is also intended to be run manually as a complete functional
3 ; test. It should link, print something, and exit zero rather than crashing.
4 ; It is the hypothetical lowering of a C source program that looks like:
5 ;
6 ; int safe_div(int *n, int *d) {
7 ; int r;
8 ; __try {
9 ; __try {
10 ; r = *n / *d;
11 ; } __except(GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION) {
12 ; puts("EXCEPTION_ACCESS_VIOLATION");
13 ; r = -1;
14 ; }
15 ; } __except(GetExceptionCode() == EXCEPTION_INT_DIVIDE_BY_ZERO) {
16 ; puts("EXCEPTION_INT_DIVIDE_BY_ZERO");
17 ; r = -2;
18 ; }
19 ; return r;
20 ; }
21
22 @str1 = internal constant [27 x i8] c"EXCEPTION_ACCESS_VIOLATION\00"
23 @str2 = internal constant [29 x i8] c"EXCEPTION_INT_DIVIDE_BY_ZERO\00"
24
25 define i32 @safe_div(i32* %n, i32* %d) {
26 entry:
27 %r = alloca i32, align 4
28 invoke void @try_body(i32* %r, i32* %n, i32* %d)
29 to label %__try.cont unwind label %lpad
30
31 lpad:
32 %vals = landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__C_specific_handler to i8*)
33 catch i8* bitcast (i32 (i8*, i8*)* @safe_div_filt0 to i8*)
34 catch i8* bitcast (i32 (i8*, i8*)* @safe_div_filt1 to i8*)
35 %ehptr = extractvalue { i8*, i32 } %vals, 0
36 %sel = extractvalue { i8*, i32 } %vals, 1
37 %filt0_val = call i32 @llvm.eh.typeid.for(i8* bitcast (i32 (i8*, i8*)* @safe_div_filt0 to i8*))
38 %is_filt0 = icmp eq i32 %sel, %filt0_val
39 br i1 %is_filt0, label %handler0, label %eh.dispatch1
40
41 eh.dispatch1:
42 %filt1_val = call i32 @llvm.eh.typeid.for(i8* bitcast (i32 (i8*, i8*)* @safe_div_filt1 to i8*))
43 %is_filt1 = icmp eq i32 %sel, %filt1_val
44 br i1 %is_filt1, label %handler1, label %eh.resume
45
46 handler0:
47 call void @puts(i8* getelementptr ([27 x i8]* @str1, i32 0, i32 0))
48 store i32 -1, i32* %r, align 4
49 br label %__try.cont
50
51 handler1:
52 call void @puts(i8* getelementptr ([29 x i8]* @str2, i32 0, i32 0))
53 store i32 -2, i32* %r, align 4
54 br label %__try.cont
55
56 eh.resume:
57 resume { i8*, i32 } %vals
58
59 __try.cont:
60 %safe_ret = load i32* %r, align 4
61 ret i32 %safe_ret
62 }
63
64 ; Normal path code
65
66 ; CHECK: {{^}}safe_div:
67 ; CHECK: .seh_proc safe_div
68 ; CHECK: .seh_handler __C_specific_handler, @unwind, @except
69 ; CHECK: .Ltmp0:
70 ; CHECK: leaq [[rloc:.*\(%rsp\)]], %rcx
71 ; CHECK: callq try_body
72 ; CHECK-NEXT: .Ltmp1
73 ; CHECK: .LBB0_7:
74 ; CHECK: movl [[rloc]], %eax
75 ; CHECK: retq
76
77 ; Landing pad code
78
79 ; CHECK: .Ltmp3:
80 ; CHECK: movl $1, %[[sel:[a-z]+]]
81 ; CHECK: .Ltmp4
82 ; CHECK: movl $2, %[[sel]]
83 ; CHECK: .L{{.*}}:
84 ; CHECK: cmpl $1, %[[sel]]
85
86 ; CHECK: # %handler0
87 ; CHECK: callq puts
88 ; CHECK: movl $-1, [[rloc]]
89 ; CHECK: jmp .LBB0_7
90
91 ; CHECK: cmpl $2, %[[sel]]
92
93 ; CHECK: # %handler1
94 ; CHECK: callq puts
95 ; CHECK: movl $-2, [[rloc]]
96 ; CHECK: jmp .LBB0_7
97
98 ; FIXME: EH preparation should not call _Unwind_Resume.
99 ; CHECK: callq _Unwind_Resume
100 ; CHECK: ud2
101
102 ; CHECK: .seh_handlerdata
103 ; CHECK: .long 2
104 ; CHECK: .long .Ltmp0@IMGREL
105 ; CHECK: .long .Ltmp1@IMGREL+1
106 ; CHECK: .long safe_div_filt0@IMGREL
107 ; CHECK: .long .Ltmp3@IMGREL
108 ; CHECK: .long .Ltmp0@IMGREL
109 ; CHECK: .long .Ltmp1@IMGREL+1
110 ; CHECK: .long safe_div_filt1@IMGREL
111 ; CHECK: .long .Ltmp4@IMGREL
112 ; CHECK: .text
113 ; CHECK: .seh_endproc
114
115
116 define void @try_body(i32* %r, i32* %n, i32* %d) {
117 entry:
118 %0 = load i32* %n, align 4
119 %1 = load i32* %d, align 4
120 %div = sdiv i32 %0, %1
121 store i32 %div, i32* %r, align 4
122 ret void
123 }
124
125 ; The prototype of these filter functions is:
126 ; int filter(EXCEPTION_POINTERS *eh_ptrs, void *rbp);
127
128 ; The definition of EXCEPTION_POINTERS is:
129 ; typedef struct _EXCEPTION_POINTERS {
130 ; EXCEPTION_RECORD *ExceptionRecord;
131 ; CONTEXT *ContextRecord;
132 ; } EXCEPTION_POINTERS;
133
134 ; The definition of EXCEPTION_RECORD is:
135 ; typedef struct _EXCEPTION_RECORD {
136 ; DWORD ExceptionCode;
137 ; ...
138 ; } EXCEPTION_RECORD;
139
140 ; The exception code can be retreived with two loads, one for the record
141 ; pointer and one for the code. The values of local variables can be
142 ; accessed via rbp, but that would require additional not yet implemented LLVM
143 ; support.
144
145 define i32 @safe_div_filt0(i8* %eh_ptrs, i8* %rbp) {
146 %eh_ptrs_c = bitcast i8* %eh_ptrs to i32**
147 %eh_rec = load i32** %eh_ptrs_c
148 %eh_code = load i32* %eh_rec
149 ; EXCEPTION_ACCESS_VIOLATION = 0xC0000005
150 %cmp = icmp eq i32 %eh_code, 3221225477
151 %filt.res = zext i1 %cmp to i32
152 ret i32 %filt.res
153 }
154
155 define i32 @safe_div_filt1(i8* %eh_ptrs, i8* %rbp) {
156 %eh_ptrs_c = bitcast i8* %eh_ptrs to i32**
157 %eh_rec = load i32** %eh_ptrs_c
158 %eh_code = load i32* %eh_rec
159 ; EXCEPTION_INT_DIVIDE_BY_ZERO = 0xC0000094
160 %cmp = icmp eq i32 %eh_code, 3221225620
161 %filt.res = zext i1 %cmp to i32
162 ret i32 %filt.res
163 }
164
165 @str_result = internal constant [21 x i8] c"safe_div result: %d\0A\00"
166
167 define i32 @main() {
168 %d.addr = alloca i32, align 4
169 %n.addr = alloca i32, align 4
170
171 store i32 10, i32* %n.addr, align 4
172 store i32 2, i32* %d.addr, align 4
173 %r1 = call i32 @safe_div(i32* %n.addr, i32* %d.addr)
174 call void (i8*, ...)* @printf(i8* getelementptr ([21 x i8]* @str_result, i32 0, i32 0), i32 %r1)
175
176 store i32 10, i32* %n.addr, align 4
177 store i32 0, i32* %d.addr, align 4
178 %r2 = call i32 @safe_div(i32* %n.addr, i32* %d.addr)
179 call void (i8*, ...)* @printf(i8* getelementptr ([21 x i8]* @str_result, i32 0, i32 0), i32 %r2)
180
181 %r3 = call i32 @safe_div(i32* %n.addr, i32* null)
182 call void (i8*, ...)* @printf(i8* getelementptr ([21 x i8]* @str_result, i32 0, i32 0), i32 %r3)
183 ret i32 0
184 }
185
186 define void @_Unwind_Resume() {
187 call void @abort()
188 unreachable
189 }
190
191 declare i32 @__C_specific_handler(...)
192 declare i32 @llvm.eh.typeid.for(i8*) readnone nounwind
193 declare void @puts(i8*)
194 declare void @printf(i8*, ...)
195 declare void @abort()