llvm.org GIT mirror llvm / e04fe6c
[WinEH] Handle nested landing pads that return directly to the parent function. Differential Revision: http://reviews.llvm.org/D9684 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@237063 91177308-0d34-0410-b5e6-96231b3b80d8 Andrew Kaylor 5 years ago
6 changed file(s) with 325 addition(s) and 17 deletion(s). Raw diff Collapse all Expand all
9797 SetVector &EHReturnBlocks);
9898 void findCXXEHReturnPoints(Function &F,
9999 SetVector &EHReturnBlocks);
100 void getPossibleReturnTargets(Function *ParentF, Function *HandlerF,
101 SetVector &Targets);
100102 void completeNestedLandingPad(Function *ParentFn,
101103 LandingPadInst *OutlinedLPad,
102104 const LandingPadInst *OriginalLPad,
699701 F.getEntryBlock().getFirstInsertionPt());
700702 }
701703
704 // This container stores the llvm.eh.recover and IndirectBr instructions
705 // that make up the body of each landing pad after it has been outlined.
706 // We need to defer the population of the target list for the indirectbr
707 // until all landing pads have been outlined so that we can handle the
708 // case of blocks in the target that are reached only from nested
709 // landing pads.
710 SmallVector, 4> LPadImpls;
711
702712 for (LandingPadInst *LPad : LPads) {
703713 // Look for evidence that this landingpad has already been processed.
704714 bool LPadHasActionList = false;
818828 CallInst *Recover =
819829 CallInst::Create(ActionIntrin, ActionArgs, "recover", LPadBB);
820830
821 // Add an indirect branch listing possible successors of the catch handlers.
822 SetVector ReturnTargets;
823 for (ActionHandler *Action : Actions) {
824 if (auto *CatchAction = dyn_cast(Action)) {
825 const auto &CatchTargets = CatchAction->getReturnTargets();
826 ReturnTargets.insert(CatchTargets.begin(), CatchTargets.end());
827 }
828 }
829 IndirectBrInst *Branch =
830 IndirectBrInst::Create(Recover, ReturnTargets.size(), LPadBB);
831 for (BasicBlock *Target : ReturnTargets)
832 Branch->addDestination(Target);
831 if (isAsynchronousEHPersonality(Personality)) {
832 // SEH can create the target list directly, since catch handlers
833 // are not outlined.
834 SetVector ReturnTargets;
835 for (ActionHandler *Action : Actions) {
836 if (auto *CatchAction = dyn_cast(Action)) {
837 const auto &CatchTargets = CatchAction->getReturnTargets();
838 ReturnTargets.insert(CatchTargets.begin(), CatchTargets.end());
839 }
840 }
841 IndirectBrInst *Branch =
842 IndirectBrInst::Create(Recover, ReturnTargets.size(), LPadBB);
843 for (BasicBlock *Target : ReturnTargets)
844 Branch->addDestination(Target);
845 } else {
846 // C++ EH must defer populating the targets to handle the case of
847 // targets that are reached indirectly through nested landing pads.
848 IndirectBrInst *Branch =
849 IndirectBrInst::Create(Recover, 0, LPadBB);
850
851 LPadImpls.push_back(std::make_pair(Recover, Branch));
852 }
833853 } // End for each landingpad
834854
835855 // If nothing got outlined, there is no more processing to be done.
842862 for (auto &LPadPair : NestedLPtoOriginalLP)
843863 completeNestedLandingPad(&F, LPadPair.first, LPadPair.second, FrameVarInfo);
844864 NestedLPtoOriginalLP.clear();
865
866 // Populate the indirectbr instructions' target lists if we deferred
867 // doing so above.
868 SetVector CheckedTargets;
869 for (auto &LPadImplPair : LPadImpls) {
870 IntrinsicInst *Recover = cast(LPadImplPair.first);
871 IndirectBrInst *Branch = LPadImplPair.second;
872
873 // Get a list of handlers called by
874 SmallVector ActionList;
875 parseEHActions(Recover, ActionList);
876
877 // Add an indirect branch listing possible successors of the catch handlers.
878 SetVector ReturnTargets;
879 for (ActionHandler *Action : ActionList) {
880 if (auto *CA = dyn_cast(Action)) {
881 Function *Handler = cast(CA->getHandlerBlockOrFunc());
882 getPossibleReturnTargets(&F, Handler, ReturnTargets);
883 }
884 }
885 for (BasicBlock *Target : ReturnTargets) {
886 Branch->addDestination(Target);
887 // The target may be a block that we excepted to get pruned.
888 // If it is, it may contain a call to llvm.eh.endcatch.
889 if (CheckedTargets.insert(Target)) {
890 // Earlier preparations guarantee that all calls to llvm.eh.endcatch
891 // will be followed by an unconditional branch.
892 auto *Br = dyn_cast(Target->getTerminator());
893 if (Br && Br->isUnconditional() &&
894 Br != Target->getFirstNonPHIOrDbgOrLifetime()) {
895 Instruction *Prev = Br->getPrevNode();
896 if (match(cast(Prev), m_Intrinsic()))
897 Prev->eraseFromParent();
898 }
899 }
900 }
901 }
902 LPadImpls.clear();
845903
846904 F.addFnAttr("wineh-parent", F.getName());
847905
9731031 SmallVector Users(LPad->user_begin(), LPad->user_end());
9741032 for (auto *U : Users)
9751033 RecursivelyDeleteTriviallyDeadInstructions(U);
1034 }
1035
1036 void WinEHPrepare::getPossibleReturnTargets(Function *ParentF,
1037 Function *HandlerF,
1038 SetVector &Targets) {
1039 for (BasicBlock &BB : *HandlerF) {
1040 // If the handler contains landing pads, check for any
1041 // handlers that may return directly to a block in the
1042 // parent function.
1043 if (auto *LPI = BB.getLandingPadInst()) {
1044 IntrinsicInst *Recover = cast(LPI->getNextNode());
1045 SmallVector ActionList;
1046 parseEHActions(Recover, ActionList);
1047 for (auto *Action : ActionList) {
1048 if (auto *CH = dyn_cast(Action)) {
1049 Function *NestedF = cast(CH->getHandlerBlockOrFunc());
1050 getPossibleReturnTargets(ParentF, NestedF, Targets);
1051 }
1052 }
1053 }
1054
1055 auto *Ret = dyn_cast(BB.getTerminator());
1056 if (!Ret)
1057 continue;
1058
1059 // Handler functions must always return a block address.
1060 BlockAddress *BA = cast(Ret->getReturnValue());
1061
1062 // If this is the handler for a nested landing pad, the
1063 // return address may have been remapped to a block in the
1064 // parent handler. We're not interested in those.
1065 if (BA->getFunction() != ParentF)
1066 continue;
1067
1068 Targets.insert(BA->getBasicBlock());
1069 }
9761070 }
9771071
9781072 void WinEHPrepare::completeNestedLandingPad(Function *ParentFn,
9797 ; CHECK-NEXT: cleanup
9898 ; CHECK-NEXT: catch i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0H@8" to i8*)
9999 ; CHECK-NEXT: [[RECOVER3:\%.+]] = call i8* (...) @llvm.eh.actions(i32 1, i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0H@8" to i8*), i32 2, i8* (i8*, i8*)* @"\01?test@@YAXXZ.catch1", i32 0, void (i8*, i8*)* @"\01?test@@YAXXZ.cleanup")
100 ; CHECK-NEXT: indirectbr i8* [[RECOVER3]], [label %try.cont]
100 ; CHECK-NEXT: indirectbr i8* [[RECOVER3]], [label %try.cont, label %try.cont15]
101101
102102 lpad3: ; preds = %invoke.cont2
103103 %8 = landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*)
5555 ; CHECK: catch i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0H@8" to i8*)
5656 ; CHECK: catch i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0M@8" to i8*)
5757 ; CHECK: [[RECOVER:\%.+]] = call i8* (...) @llvm.eh.actions(i32 1, i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0H@8" to i8*), i32 0, i8* (i8*, i8*)* @"\01?test@@YAXXZ.catch", i32 1, i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0M@8" to i8*), i32 1, i8* (i8*, i8*)* @"\01?test@@YAXXZ.catch1")
58 ; CHECK: indirectbr i8* [[RECOVER]], [label %try.cont, label %try.cont10]
58 ; CHECK: indirectbr i8* [[RECOVER]], [label %try.cont10, label %try.cont]
5959
6060 lpad: ; preds = %entry
6161 %0 = landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*)
113113 ; CHECK-SAME: i32 1, i8* bitcast (i8** @_ZTIi to i8*), i32 1, i8* (i8*, i8*)* @_Z4testv.catch1,
114114 ; CHECK-SAME: i32 0, void (i8*, i8*)* @_Z4testv.cleanup,
115115 ; CHECK-SAME: i32 1, i8* bitcast (i8** @_ZTIf to i8*), i32 0, i8* (i8*, i8*)* @_Z4testv.catch)
116 ; CHECK-NEXT: indirectbr i8* [[RECOVER1]], [label %try.cont, label %try.cont19]
116 ; CHECK-NEXT: indirectbr i8* [[RECOVER1]], [label %try.cont19, label %try.cont]
117117
118118 lpad1: ; preds = %invoke.cont4, %invoke.cont
119119 %tmp3 = landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*)
136136 ; CHECK-SAME: i32 1, i8* bitcast (i8** @_ZTIi to i8*), i32 1, i8* (i8*, i8*)* @_Z4testv.catch1,
137137 ; CHECK-SAME: i32 0, void (i8*, i8*)* @_Z4testv.cleanup,
138138 ; CHECK-SAME: i32 1, i8* bitcast (i8** @_ZTIf to i8*), i32 0, i8* (i8*, i8*)* @_Z4testv.catch)
139 ; CHECK-NEXT: indirectbr i8* [[RECOVER3]], [label %try.cont, label %try.cont19]
139 ; CHECK-NEXT: indirectbr i8* [[RECOVER3]], [label %try.cont19, label %try.cont]
140140
141141 lpad3: ; preds = %invoke.cont2
142142 %tmp6 = landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*)
6363 ; CHECK: catch i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0H@8" to i8*)
6464 ; CHECK: catch i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0M@8" to i8*)
6565 ; CHECK: [[RECOVER:\%.+]] = call i8* (...) @llvm.eh.actions(i32 1, i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0H@8" to i8*), i32 0, i8* (i8*, i8*)* @"\01?test@@YAXXZ.catch", i32 1, i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0M@8" to i8*), i32 1, i8* (i8*, i8*)* @"\01?test@@YAXXZ.catch1")
66 ; CHECK: indirectbr i8* [[RECOVER]], [label %try.cont10, label %try.cont19]
66 ; CHECK: indirectbr i8* [[RECOVER]], [label %try.cont19, label %try.cont10]
6767
6868 lpad: ; preds = %entry
6969 %0 = landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*)
0 ; RUN: opt -mtriple=x86_64-pc-windows-msvc -winehprepare -S -o - < %s | FileCheck %s
1
2 ; This test was generated from the following code.
3 ;
4 ; void test1() {
5 ; try {
6 ; try {
7 ; throw 1;
8 ; } catch(...) { throw; }
9 ; } catch (...) { }
10 ; }
11 ; void test2() {
12 ; try {
13 ; throw 1;
14 ; } catch(...) {
15 ; try {
16 ; throw;
17 ; } catch (...) {}
18 ; }
19 ; }
20 ;
21 ; These two functions result in functionally equivalent code, but the last
22 ; catch block contains a call to llvm.eh.endcatch that tripped up processing
23 ; during development.
24 ;
25 ; The main purpose of this test is to verify that we can correctly
26 ; handle the case of nested landing pads that return directly to a block in
27 ; the parent function.
28
29 ; ModuleID = 'cppeh-nested-rethrow.cpp'
30 target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
31 target triple = "x86_64-pc-windows-msvc"
32
33 %rtti.TypeDescriptor2 = type { i8**, i8*, [3 x i8] }
34 %eh.CatchableType = type { i32, i32, i32, i32, i32, i32, i32 }
35 %eh.CatchableTypeArray.1 = type { i32, [1 x i32] }
36 %eh.ThrowInfo = type { i32, i32, i32, i32 }
37
38 $"\01??_R0H@8" = comdat any
39
40 $"_CT??_R0H@84" = comdat any
41
42 $_CTA1H = comdat any
43
44 $_TI1H = comdat any
45
46 @"\01??_7type_info@@6B@" = external constant i8*
47 @"\01??_R0H@8" = linkonce_odr global %rtti.TypeDescriptor2 { i8** @"\01??_7type_info@@6B@", i8* null, [3 x i8] c".H\00" }, comdat
48 @__ImageBase = external constant i8
49 @"_CT??_R0H@84" = linkonce_odr unnamed_addr constant %eh.CatchableType { i32 1, i32 trunc (i64 sub nuw nsw (i64 ptrtoint (%rtti.TypeDescriptor2* @"\01??_R0H@8" to i64), i64 ptrtoint (i8* @__ImageBase to i64)) to i32), i32 0, i32 -1, i32 0, i32 4, i32 0 }, section ".xdata", comdat
50 @_CTA1H = linkonce_odr unnamed_addr constant %eh.CatchableTypeArray.1 { i32 1, [1 x i32] [i32 trunc (i64 sub nuw nsw (i64 ptrtoint (%eh.CatchableType* @"_CT??_R0H@84" to i64), i64 ptrtoint (i8* @__ImageBase to i64)) to i32)] }, section ".xdata", comdat
51 @_TI1H = linkonce_odr unnamed_addr constant %eh.ThrowInfo { i32 0, i32 0, i32 0, i32 trunc (i64 sub nuw nsw (i64 ptrtoint (%eh.CatchableTypeArray.1* @_CTA1H to i64), i64 ptrtoint (i8* @__ImageBase to i64)) to i32) }, section ".xdata", comdat
52
53 ; CHECK-LABEL: define void @"\01?test1@@YAXXZ"()
54 ; CHECK: entry:
55 ; CHECK: call void (...) @llvm.frameescape
56
57 ; Function Attrs: nounwind uwtable
58 define void @"\01?test1@@YAXXZ"() #0 {
59 entry:
60 %tmp = alloca i32, align 4
61 %exn.slot = alloca i8*
62 %ehselector.slot = alloca i32
63 store i32 1, i32* %tmp
64 %0 = bitcast i32* %tmp to i8*
65 invoke void @_CxxThrowException(i8* %0, %eh.ThrowInfo* @_TI1H) #2
66 to label %unreachable unwind label %lpad
67
68 lpad: ; preds = %entry
69 %1 = landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*)
70 catch i8* null
71 %2 = extractvalue { i8*, i32 } %1, 0
72 store i8* %2, i8** %exn.slot
73 %3 = extractvalue { i8*, i32 } %1, 1
74 store i32 %3, i32* %ehselector.slot
75 br label %catch
76
77 catch: ; preds = %lpad
78 %exn = load i8*, i8** %exn.slot
79 call void @llvm.eh.begincatch(i8* %exn, i8* null) #1
80 invoke void @_CxxThrowException(i8* null, %eh.ThrowInfo* null) #2
81 to label %unreachable unwind label %lpad1
82
83 lpad1: ; preds = %catch
84 %4 = landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*)
85 catch i8* null
86 %5 = extractvalue { i8*, i32 } %4, 0
87 store i8* %5, i8** %exn.slot
88 %6 = extractvalue { i8*, i32 } %4, 1
89 store i32 %6, i32* %ehselector.slot
90 br label %catch2
91
92 catch2: ; preds = %lpad1
93 %exn3 = load i8*, i8** %exn.slot
94 call void @llvm.eh.begincatch(i8* %exn3, i8* null) #1
95 call void @llvm.eh.endcatch() #1
96 br label %try.cont4
97
98 ; This block should not be eliminated.
99 ; CHECK: try.cont4:
100 try.cont4: ; preds = %catch2, %try.cont
101 ret void
102
103 try.cont: ; No predecessors!
104 br label %try.cont4
105
106 unreachable: ; preds = %catch, %entry
107 unreachable
108 ; CHECK: }
109 }
110
111 declare void @_CxxThrowException(i8*, %eh.ThrowInfo*)
112
113 declare i32 @__CxxFrameHandler3(...)
114
115 ; Function Attrs: nounwind
116 declare void @llvm.eh.begincatch(i8* nocapture, i8* nocapture) #1
117
118 ; Function Attrs: nounwind
119 declare void @llvm.eh.endcatch() #1
120
121 ; CHECK-LABEL: define void @"\01?test2@@YAXXZ"()
122 ; CHECK: entry:
123 ; CHECK: call void (...) @llvm.frameescape
124
125 ; Function Attrs: nounwind uwtable
126 define void @"\01?test2@@YAXXZ"() #0 {
127 entry:
128 %tmp = alloca i32, align 4
129 %exn.slot = alloca i8*
130 %ehselector.slot = alloca i32
131 store i32 1, i32* %tmp
132 %0 = bitcast i32* %tmp to i8*
133 invoke void @_CxxThrowException(i8* %0, %eh.ThrowInfo* @_TI1H) #2
134 to label %unreachable unwind label %lpad
135
136 lpad: ; preds = %entry
137 %1 = landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*)
138 catch i8* null
139 %2 = extractvalue { i8*, i32 } %1, 0
140 store i8* %2, i8** %exn.slot
141 %3 = extractvalue { i8*, i32 } %1, 1
142 store i32 %3, i32* %ehselector.slot
143 br label %catch
144
145 catch: ; preds = %lpad
146 %exn = load i8*, i8** %exn.slot
147 call void @llvm.eh.begincatch(i8* %exn, i8* null) #1
148 invoke void @_CxxThrowException(i8* null, %eh.ThrowInfo* null) #2
149 to label %unreachable unwind label %lpad1
150
151 lpad1: ; preds = %catch
152 %4 = landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*)
153 catch i8* null
154 %5 = extractvalue { i8*, i32 } %4, 0
155 store i8* %5, i8** %exn.slot
156 %6 = extractvalue { i8*, i32 } %4, 1
157 store i32 %6, i32* %ehselector.slot
158 br label %catch2
159
160 catch2: ; preds = %lpad1
161 %exn3 = load i8*, i8** %exn.slot
162 call void @llvm.eh.begincatch(i8* %exn3, i8* null) #1
163 call void @llvm.eh.endcatch() #1
164 br label %try.cont
165
166 ; This block should not be eliminated.
167 ; CHECK: try.cont:
168 ; The endcatch call should be eliminated.
169 ; CHECK-NOT: call void @llvm.eh.endcatch()
170 try.cont: ; preds = %catch2
171 call void @llvm.eh.endcatch() #1
172 br label %try.cont4
173
174 try.cont4: ; preds = %try.cont
175 ret void
176
177 unreachable: ; preds = %catch, %entry
178 unreachable
179 ; CHECK: }
180 }
181
182 ; The outlined test1.catch handler should not contain a return instruction.
183 ; CHECK-LABEL: define internal i8* @"\01?test1@@YAXXZ.catch"(i8*, i8*)
184 ; CHECK-NOT: ret
185 ; CHECK: }
186
187 ; The outlined test1.catch1 handler should return to a valid block address.
188 ; CHECK-LABEL: define internal i8* @"\01?test1@@YAXXZ.catch1"(i8*, i8*)
189 ; WILL-CHECK: ret i8* inttoptr (
190 ; CHECK-NOT: ret i8* inttoptr (i32 1 to i8*)
191 ; CHECK: }
192
193 ; The outlined test2.catch handler should not contain a return instruction.
194 ; CHECK-LABEL: define internal i8* @"\01?test2@@YAXXZ.catch"(i8*, i8*)
195 ; CHECK-NOT: ret
196 ; CHECK: }
197
198 ; The outlined test2.catch1 handler should return to a valid block address.
199 ; CHECK-LABEL: define internal i8* @"\01?test2@@YAXXZ.catch2"(i8*, i8*)
200 ; WILL-CHECK: ret i8* inttoptr (
201 ; CHECK-NOT: ret i8* inttoptr (i32 1 to i8*)
202 ; CHECK: }
203
204
205 attributes #0 = { nounwind uwtable "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+sse,+sse2" "unsafe-fp-math"="false" "use-soft-float"="false" }
206 attributes #1 = { nounwind }
207 attributes #2 = { noreturn }
208
209 !llvm.module.flags = !{!0}
210 !llvm.ident = !{!1}
211
212 !0 = !{i32 1, !"PIC Level", i32 2}
213 !1 = !{!"clang version 3.7.0 (trunk 236059)"}