Skip to content

Commit 72029c6

Browse files
author
Andrew Kaylor
committedMar 3, 2015
Remap arguments and non-alloca values used by outlined C++ exception handlers.
Differential Revision: http://reviews.llvm.org/D7844 llvm-svn: 231042
1 parent 838752d commit 72029c6

File tree

3 files changed

+521
-40
lines changed

3 files changed

+521
-40
lines changed
 

‎llvm/lib/CodeGen/WinEHPrepare.cpp

+76-40
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ struct HandlerAllocas {
4646
// allocation block, and to remap the frame variable allocas (including
4747
// spill locations as needed) to GEPs that get the variable from the
4848
// frame allocation structure.
49-
typedef MapVector<AllocaInst *, HandlerAllocas> FrameVarInfoMap;
49+
typedef MapVector<Value *, HandlerAllocas> FrameVarInfoMap;
5050

5151
class WinEHPrepare : public FunctionPass {
5252
std::unique_ptr<FunctionPass> DwarfPrepare;
@@ -261,22 +261,31 @@ bool WinEHPrepare::prepareCPPEHHandlers(
261261
// all the entries in the HandlerData have been processed this isn't a
262262
// problem.
263263
for (auto &VarInfoEntry : FrameVarInfo) {
264-
AllocaInst *ParentAlloca = VarInfoEntry.first;
264+
Value *ParentVal = VarInfoEntry.first;
265265
HandlerAllocas &AllocaInfo = VarInfoEntry.second;
266266

267-
// If the instruction still has uses in the parent function or if it is
268-
// referenced by more than one handler, add it to the frame allocation
269-
// structure.
270-
if (ParentAlloca->getNumUses() != 0 || AllocaInfo.Allocas.size() > 1) {
271-
Type *VarTy = ParentAlloca->getAllocatedType();
267+
if (auto *ParentAlloca = dyn_cast<AllocaInst>(ParentVal)) {
268+
// If the instruction still has uses in the parent function or if it is
269+
// referenced by more than one handler, add it to the frame allocation
270+
// structure.
271+
if (ParentAlloca->getNumUses() != 0 || AllocaInfo.Allocas.size() > 1) {
272+
Type *VarTy = ParentAlloca->getAllocatedType();
273+
StructTys.push_back(VarTy);
274+
AllocaInfo.ParentFrameAllocationIndex = Idx++;
275+
} else {
276+
// If the variable is not used in the parent frame and it is only used
277+
// in one handler, the alloca can be removed from the parent frame
278+
// and the handler will keep its "temporary" alloca to define the value.
279+
// An element index of -1 is used to indicate this condition.
280+
AllocaInfo.ParentFrameAllocationIndex = -1;
281+
}
282+
} else {
283+
// FIXME: Sink non-alloca values into the handler if they have no other
284+
// uses in the parent function after outlining and are only used in
285+
// one handler.
286+
Type *VarTy = ParentVal->getType();
272287
StructTys.push_back(VarTy);
273288
AllocaInfo.ParentFrameAllocationIndex = Idx++;
274-
} else {
275-
// If the variable is not used in the parent frame and it is only used
276-
// in one handler, the alloca can be removed from the parent frame
277-
// and the handler will keep its "temporary" alloca to define the value.
278-
// An element index of -1 is used to indicate this condition.
279-
AllocaInfo.ParentFrameAllocationIndex = -1;
280289
}
281290
}
282291

@@ -331,11 +340,41 @@ bool WinEHPrepare::prepareCPPEHHandlers(
331340
// Finally, replace all of the temporary allocas for frame variables used in
332341
// the outlined handlers and the original frame allocas with GEP instructions
333342
// that get the equivalent pointer from the frame allocation struct.
343+
Instruction *FrameEHDataInst = cast<Instruction>(FrameEHData);
344+
BasicBlock::iterator II = FrameEHDataInst;
345+
++II;
346+
Instruction *AllocaInsertPt = II;
334347
for (auto &VarInfoEntry : FrameVarInfo) {
335-
AllocaInst *ParentAlloca = VarInfoEntry.first;
348+
Value *ParentVal = VarInfoEntry.first;
336349
HandlerAllocas &AllocaInfo = VarInfoEntry.second;
337350
int Idx = AllocaInfo.ParentFrameAllocationIndex;
338351

352+
// If the mapped value isn't already an alloca, we need to spill it if it
353+
// is a computed value or copy it if it is an argument.
354+
AllocaInst *ParentAlloca = dyn_cast<AllocaInst>(ParentVal);
355+
if (!ParentAlloca) {
356+
if (auto *Arg = dyn_cast<Argument>(ParentVal)) {
357+
// Lower this argument to a copy and then demote that to the stack.
358+
// We can't just use the argument location because the handler needs
359+
// it to be in the frame allocation block.
360+
// Use 'select i8 true, %arg, undef' to simulate a 'no-op' instruction.
361+
Value *TrueValue = ConstantInt::getTrue(Context);
362+
Value *UndefValue = UndefValue::get(Arg->getType());
363+
Instruction *SI =
364+
SelectInst::Create(TrueValue, Arg, UndefValue,
365+
Arg->getName() + ".tmp", AllocaInsertPt);
366+
Arg->replaceAllUsesWith(SI);
367+
// Reset the select operand, because it was clobbered by the RAUW above.
368+
SI->setOperand(1, Arg);
369+
ParentAlloca = DemoteRegToStack(*SI, true, SI);
370+
} else if (auto *PN = dyn_cast<PHINode>(ParentVal)) {
371+
ParentAlloca = DemotePHIToStack(PN, AllocaInsertPt);
372+
} else {
373+
Instruction *ParentInst = cast<Instruction>(ParentVal);
374+
ParentAlloca = DemoteRegToStack(*ParentInst, true, ParentInst);
375+
}
376+
}
377+
339378
// If we have an index of -1 for this instruction, it means it isn't used
340379
// outside of this handler. In that case, we just keep the "temporary"
341380
// alloca in the handler and erase the original alloca from the parent.
@@ -353,6 +392,8 @@ bool WinEHPrepare::prepareCPPEHHandlers(
353392
ParentAlloca->replaceAllUsesWith(ElementPtr);
354393
ParentAlloca->removeFromParent();
355394
ElementPtr->takeName(ParentAlloca);
395+
if (ParentAlloca == AllocaInsertPt)
396+
AllocaInsertPt = dyn_cast<Instruction>(ElementPtr);
356397
delete ParentAlloca;
357398

358399
// Next replace all outlined allocas that are mapped to it.
@@ -589,38 +630,33 @@ WinEHFrameVariableMaterializer::WinEHFrameVariableMaterializer(
589630
}
590631

591632
Value *WinEHFrameVariableMaterializer::materializeValueFor(Value *V) {
592-
// If we're asked to materialize an alloca variable, we temporarily
593-
// create a matching alloca in the outlined function. When all the
594-
// outlining is complete, we'll collect these into a structure and
595-
// replace these temporary allocas with GEPs referencing the frame
596-
// allocation block.
633+
// If we're asked to materialize a value that is an instruction, we
634+
// temporarily create an alloca in the outlined function and add this
635+
// to the FrameVarInfo map. When all the outlining is complete, we'll
636+
// collect these into a structure, spilling non-alloca values in the
637+
// parent frame as necessary, and replace these temporary allocas with
638+
// GEPs referencing the frame allocation block.
639+
640+
// If the value is an alloca, the mapping is direct.
597641
if (auto *AV = dyn_cast<AllocaInst>(V)) {
598-
AllocaInst *NewAlloca = Builder.CreateAlloca(
599-
AV->getAllocatedType(), AV->getArraySize(), AV->getName());
642+
AllocaInst *NewAlloca = dyn_cast<AllocaInst>(AV->clone());
643+
Builder.Insert(NewAlloca, AV->getName());
600644
FrameVarInfo[AV].Allocas.push_back(NewAlloca);
601645
return NewAlloca;
602646
}
603647

604-
// FIXME: Do PHI nodes need special handling?
605-
606-
// FIXME: Are there other cases we can handle better? GEP, ExtractValue, etc.
607-
608-
// FIXME: This doesn't work during cloning because it finds an instruction
609-
// in the use list that isn't yet part of a basic block.
610-
#if 0
611-
// If we're asked to remap some other instruction, we'll need to
612-
// spill it to an alloca variable in the parent function and add a
613-
// temporary alloca in the outlined function to be processed as
614-
// described above.
615-
Instruction *Inst = dyn_cast<Instruction>(V);
616-
if (Inst) {
617-
AllocaInst *Spill = DemoteRegToStack(*Inst, true);
618-
AllocaInst *NewAlloca = Builder.CreateAlloca(Spill->getAllocatedType(),
619-
Spill->getArraySize());
620-
FrameVarMap[AV] = NewAlloca;
621-
return NewAlloca;
648+
// For other types of instructions or arguments, we need an alloca based on
649+
// the value's type and a load of the alloca. The alloca will be replaced
650+
// by a GEP, but the load will stay. In the parent function, the value will
651+
// be spilled to a location in the frame allocation block.
652+
if (isa<Instruction>(V) || isa<Argument>(V)) {
653+
AllocaInst *NewAlloca =
654+
Builder.CreateAlloca(V->getType(), nullptr, "eh.temp.alloca");
655+
FrameVarInfo[V].Allocas.push_back(NewAlloca);
656+
LoadInst *NewLoad = Builder.CreateLoad(NewAlloca, V->getName() + ".reload");
657+
return NewLoad;
622658
}
623-
#endif
624659

660+
// Don't materialize other values.
625661
return nullptr;
626662
}
+181
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,181 @@
1+
; RUN: opt -mtriple=i386-pc-windows-msvc -winehprepare -S -o - < %s | FileCheck %s
2+
3+
; This test is built from the following code:
4+
; struct A {
5+
; A(int a);
6+
; A(const A &o);
7+
; ~A();
8+
; int a;
9+
; };
10+
;
11+
; void may_throw();
12+
;
13+
; int test(A a) {
14+
; try {
15+
; may_throw();
16+
; }
17+
; catch (int e) {
18+
; return a.a + e;
19+
; }
20+
; return 0;
21+
; }
22+
;
23+
; The test was built for a 32-bit Windows target and then the reference to
24+
; the inalloca instruction was manually sunk into the landingpad.
25+
26+
; ModuleID = 'cppeh-inalloca.cpp'
27+
target datalayout = "e-m:w-p:32:32-i64:64-f80:32-n8:16:32-S32"
28+
target triple = "i386-pc-windows-msvc"
29+
30+
%rtti.TypeDescriptor2 = type { i8**, i8*, [3 x i8] }
31+
%struct.A = type { i32 }
32+
33+
$"\01??_R0H@8" = comdat any
34+
35+
@"\01??_7type_info@@6B@" = external constant i8*
36+
@"\01??_R0H@8" = linkonce_odr global %rtti.TypeDescriptor2 { i8** @"\01??_7type_info@@6B@", i8* null, [3 x i8] c".H\00" }, comdat
37+
38+
; The function entry should be rewritten like this.
39+
; CHECK: define i32 @"\01?test@@YAHUA@@@Z"(<{ %struct.A }>* inalloca) #0 {
40+
; CHECK: entry:
41+
; CHECK: %frame.alloc = call i8* @llvm.frameallocate(i32 24)
42+
; CHECK: %eh.data = bitcast i8* %frame.alloc to %"struct.\01?test@@YAHUA@@@Z.ehdata"*
43+
; CHECK: %.tmp.reg2mem = getelementptr inbounds %"struct.\01?test@@YAHUA@@@Z.ehdata"* %eh.data, i32 0, i32 3
44+
; CHECK: %.tmp = select i1 true, <{ %struct.A }>* %0, <{ %struct.A }>* undef
45+
; CHECK: store <{ %struct.A }>* %.tmp, <{ %struct.A }>** %.tmp.reg2mem
46+
; CHECK-NOT: %retval = alloca i32, align 4
47+
; CHECK: %retval = getelementptr inbounds %"struct.\01?test@@YAHUA@@@Z.ehdata"* %eh.data, i32 0, i32 4
48+
; CHECK: %exn.slot = alloca i8*
49+
; CHECK: %ehselector.slot = alloca i32
50+
; CHECK-NOT: %e = alloca i32, align 4
51+
; CHECK: %e = getelementptr inbounds %"struct.\01?test@@YAHUA@@@Z.ehdata"* %eh.data, i32 0, i32 2
52+
; CHECK: %cleanup.dest.slot = getelementptr inbounds %"struct.\01?test@@YAHUA@@@Z.ehdata"* %eh.data, i32 0, i32 5
53+
; CHECK: invoke void @"\01?may_throw@@YAXXZ"()
54+
; CHECK: to label %invoke.cont unwind label %lpad
55+
56+
define i32 @"\01?test@@YAHUA@@@Z"(<{ %struct.A }>* inalloca) #0 {
57+
entry:
58+
%retval = alloca i32, align 4
59+
%exn.slot = alloca i8*
60+
%ehselector.slot = alloca i32
61+
%e = alloca i32, align 4
62+
%cleanup.dest.slot = alloca i32
63+
invoke void @"\01?may_throw@@YAXXZ"()
64+
to label %invoke.cont unwind label %lpad
65+
66+
invoke.cont: ; preds = %entry
67+
br label %try.cont
68+
69+
lpad: ; preds = %entry
70+
%1 = landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*)
71+
cleanup
72+
catch i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0H@8" to i8*)
73+
%2 = extractvalue { i8*, i32 } %1, 0
74+
store i8* %2, i8** %exn.slot
75+
%3 = extractvalue { i8*, i32 } %1, 1
76+
store i32 %3, i32* %ehselector.slot
77+
br label %catch.dispatch
78+
79+
catch.dispatch: ; preds = %lpad
80+
%sel = load i32* %ehselector.slot
81+
%4 = call i32 @llvm.eh.typeid.for(i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0H@8" to i8*)) #3
82+
%matches = icmp eq i32 %sel, %4
83+
br i1 %matches, label %catch, label %ehcleanup
84+
85+
catch: ; preds = %catch.dispatch
86+
%exn = load i8** %exn.slot
87+
%5 = call i8* @llvm.eh.begincatch(i8* %exn) #3
88+
%6 = bitcast i8* %5 to i32*
89+
%7 = load i32* %6, align 4
90+
store i32 %7, i32* %e, align 4
91+
%a = getelementptr inbounds <{ %struct.A }>* %0, i32 0, i32 0
92+
%a1 = getelementptr inbounds %struct.A* %a, i32 0, i32 0
93+
%8 = load i32* %a1, align 4
94+
%9 = load i32* %e, align 4
95+
%add = add nsw i32 %8, %9
96+
store i32 %add, i32* %retval
97+
store i32 1, i32* %cleanup.dest.slot
98+
call void @llvm.eh.endcatch() #3
99+
br label %cleanup
100+
101+
try.cont: ; preds = %invoke.cont
102+
store i32 0, i32* %retval
103+
store i32 1, i32* %cleanup.dest.slot
104+
br label %cleanup
105+
106+
; The cleanup block should be re-written like this.
107+
; CHECK: cleanup: ; preds = %try.cont, %catch
108+
; CHECK-NOT: %a2 = getelementptr inbounds <{ %struct.A }>* %0, i32 0, i32 0
109+
; CHECK: %.tmp.reload1 = load volatile <{ %struct.A }>** %.tmp.reg2mem
110+
; CHECK: %a2 = getelementptr inbounds <{ %struct.A }>* %.tmp.reload1, i32 0, i32 0
111+
; CHECK: call x86_thiscallcc void @"\01??1A@@QAE@XZ"(%struct.A* %a2) #2
112+
; CHECK: %10 = load i32* %retval
113+
; CHECK: ret i32 %10
114+
115+
cleanup: ; preds = %try.cont, %catch
116+
%a2 = getelementptr inbounds <{ %struct.A }>* %0, i32 0, i32 0
117+
call x86_thiscallcc void @"\01??1A@@QAE@XZ"(%struct.A* %a2) #3
118+
%10 = load i32* %retval
119+
ret i32 %10
120+
121+
ehcleanup: ; preds = %catch.dispatch
122+
%a3 = getelementptr inbounds <{ %struct.A }>* %0, i32 0, i32 0
123+
call x86_thiscallcc void @"\01??1A@@QAE@XZ"(%struct.A* %a3) #3
124+
br label %eh.resume
125+
126+
eh.resume: ; preds = %ehcleanup
127+
%exn2 = load i8** %exn.slot
128+
%sel3 = load i32* %ehselector.slot
129+
%lpad.val = insertvalue { i8*, i32 } undef, i8* %exn2, 0
130+
%lpad.val4 = insertvalue { i8*, i32 } %lpad.val, i32 %sel3, 1
131+
resume { i8*, i32 } %lpad.val4
132+
}
133+
134+
; The following catch handler should be outlined.
135+
; CHECK: define i8* @"\01?test@@YAHUA@@@Z.catch"(i8*, i8*) {
136+
; CHECK: catch.entry:
137+
; CHECK: %eh.alloc = call i8* @llvm.framerecover(i8* bitcast (i32 (<{ %struct.A }>*)* @"\01?test@@YAHUA@@@Z" to i8*), i8* %1)
138+
; CHECK: %eh.data = bitcast i8* %eh.alloc to %"struct.\01?test@@YAHUA@@@Z.ehdata"*
139+
; CHECK: %eh.obj.ptr = getelementptr inbounds %"struct.\01?test@@YAHUA@@@Z.ehdata"* %eh.data, i32 0, i32 1
140+
; CHECK: %eh.obj = load i8** %eh.obj.ptr
141+
; CHECK: %e = getelementptr inbounds %"struct.\01?test@@YAHUA@@@Z.ehdata"* %eh.data, i32 0, i32 2
142+
; CHECK: %eh.temp.alloca = getelementptr inbounds %"struct.\01?test@@YAHUA@@@Z.ehdata"* %eh.data, i32 0, i32 3
143+
; CHECK: %.reload = load <{ %struct.A }>** %eh.temp.alloca
144+
; CHECK: %retval = getelementptr inbounds %"struct.\01?test@@YAHUA@@@Z.ehdata"* %eh.data, i32 0, i32 4
145+
; CHECK: %cleanup.dest.slot = getelementptr inbounds %"struct.\01?test@@YAHUA@@@Z.ehdata"* %eh.data, i32 0, i32 5
146+
; CHECK: %2 = bitcast i8* %eh.obj to i32*
147+
; CHECK: %3 = load i32* %2, align 4
148+
; CHECK: store i32 %3, i32* %e, align 4
149+
; CHECK: %a = getelementptr inbounds <{ %struct.A }>* %.reload, i32 0, i32 0
150+
; CHECK: %a1 = getelementptr inbounds %struct.A* %a, i32 0, i32 0
151+
; CHECK: %4 = load i32* %a1, align 4
152+
; CHECK: %5 = load i32* %e, align 4
153+
; CHECK: %add = add nsw i32 %4, %5
154+
; CHECK: store i32 %add, i32* %retval
155+
; CHECK: store i32 1, i32* %cleanup.dest.slot
156+
; CHECK: ret i8* blockaddress(@"\01?test@@YAHUA@@@Z", %cleanup)
157+
; CHECK: }
158+
159+
160+
declare void @"\01?may_throw@@YAXXZ"() #0
161+
162+
declare i32 @__CxxFrameHandler3(...)
163+
164+
; Function Attrs: nounwind readnone
165+
declare i32 @llvm.eh.typeid.for(i8*) #1
166+
167+
declare i8* @llvm.eh.begincatch(i8*)
168+
169+
declare void @llvm.eh.endcatch()
170+
171+
; Function Attrs: nounwind
172+
declare x86_thiscallcc void @"\01??1A@@QAE@XZ"(%struct.A*) #2
173+
174+
attributes #0 = { "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
175+
attributes #1 = { nounwind readnone }
176+
attributes #2 = { nounwind "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
177+
attributes #3 = { nounwind }
178+
179+
!llvm.ident = !{!0}
180+
181+
!0 = !{!"clang version 3.7.0 (trunk 228868)"}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,264 @@
1+
; RUN: opt -mtriple=x86_64-pc-windows-msvc -winehprepare -S -o - < %s | FileCheck %s
2+
3+
; This test is based on the following code:
4+
;
5+
; struct SomeData {
6+
; int a;
7+
; int b;
8+
; };
9+
;
10+
; void may_throw();
11+
; void does_not_throw(int i);
12+
; void dump(int *, int, SomeData&);
13+
;
14+
; void test() {
15+
; int NumExceptions = 0;
16+
; int ExceptionVal[10];
17+
; SomeData Data = { 0, 0 };
18+
;
19+
; for (int i = 0; i < 10; ++i) {
20+
; try {
21+
; may_throw();
22+
; Data.a += i;
23+
; }
24+
; catch (int e) {
25+
; ExceptionVal[NumExceptions] = e;
26+
; ++NumExceptions;
27+
; if (e == i)
28+
; Data.b += e;
29+
; else
30+
; Data.a += e;
31+
; }
32+
; does_not_throw(NumExceptions);
33+
; }
34+
; dump(ExceptionVal, NumExceptions, Data);
35+
; }
36+
;
37+
; Unlike the cppeh-frame-vars.ll test, this test was generated using -O2
38+
; optimization, which results in non-alloca values being used in the
39+
; catch handler.
40+
41+
; ModuleID = 'cppeh-frame-vars.cpp'
42+
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
43+
target triple = "x86_64-pc-windows-msvc"
44+
45+
%rtti.TypeDescriptor2 = type { i8**, i8*, [3 x i8] }
46+
%struct.SomeData = type { i32, i32 }
47+
48+
$"\01??_R0H@8" = comdat any
49+
50+
@"\01??_7type_info@@6B@" = external constant i8*
51+
@"\01??_R0H@8" = linkonce_odr global %rtti.TypeDescriptor2 { i8** @"\01??_7type_info@@6B@", i8* null, [3 x i8] c".H\00" }, comdat
52+
53+
; This structure should be declared for the frame allocation block.
54+
; CHECK: %"struct.\01?test@@YAXXZ.ehdata" = type { i32, i8*, i32, [10 x i32], i32, i32*, i32* }
55+
56+
; The function entry should be rewritten like this.
57+
; CHECK: define void @"\01?test@@YAXXZ"() #0 {
58+
; CHECK: entry:
59+
; CHECK: %frame.alloc = call i8* @llvm.frameallocate(i32 80)
60+
; CHECK: %eh.data = bitcast i8* %frame.alloc to %"struct.\01?test@@YAXXZ.ehdata"*
61+
; CHECK-NOT: %ExceptionVal = alloca [10 x i32], align 16
62+
; CHECK: %NumExceptions.020.reg2mem = getelementptr inbounds %"struct.\01?test@@YAXXZ.ehdata"* %eh.data, i32 0, i32 2
63+
; CHECK: %i.019.reg2mem = getelementptr inbounds %"struct.\01?test@@YAXXZ.ehdata"* %eh.data, i32 0, i32 4
64+
; CHECK: %ExceptionVal = getelementptr inbounds %"struct.\01?test@@YAXXZ.ehdata"* %eh.data, i32 0, i32 3
65+
; CHECK: %Data = alloca i64, align 8
66+
; CHECK: %tmpcast = bitcast i64* %Data to %struct.SomeData*
67+
; CHECK: %0 = bitcast [10 x i32]* %ExceptionVal to i8*
68+
; CHECK: call void @llvm.lifetime.start(i64 40, i8* %0) #1
69+
; CHECK: store i64 0, i64* %Data, align 8
70+
; CHECK: %a.reg2mem = getelementptr inbounds %"struct.\01?test@@YAXXZ.ehdata"* %eh.data, i32 0, i32 5
71+
; CHECK: %a = bitcast i64* %Data to i32*
72+
; CHECK: store i32* %a, i32** %a.reg2mem
73+
; CHECK: %b.reg2mem = getelementptr inbounds %"struct.\01?test@@YAXXZ.ehdata"* %eh.data, i32 0, i32 6
74+
; CHECK: %b = getelementptr inbounds %struct.SomeData* %tmpcast, i64 0, i32 1
75+
; CHECK: store i32* %b, i32** %b.reg2mem
76+
; CHECK: store i32 0, i32* %NumExceptions.020.reg2mem
77+
; CHECK: store i32 0, i32* %i.019.reg2mem
78+
; CHECK: br label %for.body
79+
80+
; Function Attrs: uwtable
81+
define void @"\01?test@@YAXXZ"() #0 {
82+
entry:
83+
%ExceptionVal = alloca [10 x i32], align 16
84+
%Data = alloca i64, align 8
85+
%tmpcast = bitcast i64* %Data to %struct.SomeData*
86+
%0 = bitcast [10 x i32]* %ExceptionVal to i8*
87+
call void @llvm.lifetime.start(i64 40, i8* %0) #1
88+
store i64 0, i64* %Data, align 8
89+
%a = bitcast i64* %Data to i32*
90+
%b = getelementptr inbounds %struct.SomeData* %tmpcast, i64 0, i32 1
91+
br label %for.body
92+
93+
; CHECK: for.body:
94+
; CHECK-NOT: %NumExceptions.020 = phi i32 [ 0, %entry ], [ %NumExceptions.1, %try.cont ]
95+
; CHECK-NOT: %i.019 = phi i32 [ 0, %entry ], [ %inc5, %try.cont ]
96+
; CHECK: %i.019.reload = load i32* %i.019.reg2mem
97+
; CHECK: %NumExceptions.020.reload = load i32* %NumExceptions.020.reg2mem
98+
for.body: ; preds = %entry, %try.cont
99+
%NumExceptions.020 = phi i32 [ 0, %entry ], [ %NumExceptions.1, %try.cont ]
100+
%i.019 = phi i32 [ 0, %entry ], [ %inc5, %try.cont ]
101+
invoke void @"\01?may_throw@@YAXXZ"()
102+
to label %invoke.cont unwind label %lpad
103+
104+
; CHECK: invoke.cont: ; preds = %for.body
105+
; CHECK-NOT: %1 = load i32* %a, align 8, !tbaa !2
106+
; CHECK-NOT: %add = add nsw i32 %1, %i.019
107+
; CHECK-NOT: store i32 %add, i32* %a, align 8, !tbaa !2
108+
; CHECK: %a.reload3 = load volatile i32** %a.reg2mem
109+
; CHECK: %1 = load i32* %a.reload3, align 8, !tbaa !2
110+
; CHECK: %add = add nsw i32 %1, %i.019.reload
111+
; CHECK: %a.reload2 = load volatile i32** %a.reg2mem
112+
; CHECK: store i32 %add, i32* %a.reload2, align 8, !tbaa !2
113+
; CHECK: br label %try.cont
114+
invoke.cont: ; preds = %for.body
115+
%1 = load i32* %a, align 8, !tbaa !2
116+
%add = add nsw i32 %1, %i.019
117+
store i32 %add, i32* %a, align 8, !tbaa !2
118+
br label %try.cont
119+
120+
lpad: ; preds = %for.body
121+
%2 = landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*)
122+
catch i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0H@8" to i8*)
123+
%3 = extractvalue { i8*, i32 } %2, 1
124+
%4 = tail call i32 @llvm.eh.typeid.for(i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0H@8" to i8*)) #1
125+
%matches = icmp eq i32 %3, %4
126+
br i1 %matches, label %catch, label %eh.resume
127+
128+
catch: ; preds = %lpad
129+
%5 = extractvalue { i8*, i32 } %2, 0
130+
%6 = tail call i8* @llvm.eh.begincatch(i8* %5) #1
131+
%7 = bitcast i8* %6 to i32*
132+
%8 = load i32* %7, align 4, !tbaa !7
133+
%idxprom = sext i32 %NumExceptions.020 to i64
134+
%arrayidx = getelementptr inbounds [10 x i32]* %ExceptionVal, i64 0, i64 %idxprom
135+
store i32 %8, i32* %arrayidx, align 4, !tbaa !7
136+
%inc = add nsw i32 %NumExceptions.020, 1
137+
%cmp1 = icmp eq i32 %8, %i.019
138+
br i1 %cmp1, label %if.then, label %if.else
139+
140+
if.then: ; preds = %catch
141+
%9 = load i32* %b, align 4, !tbaa !8
142+
%add2 = add nsw i32 %9, %i.019
143+
store i32 %add2, i32* %b, align 4, !tbaa !8
144+
br label %if.end
145+
146+
if.else: ; preds = %catch
147+
%10 = load i32* %a, align 8, !tbaa !2
148+
%add4 = add nsw i32 %10, %8
149+
store i32 %add4, i32* %a, align 8, !tbaa !2
150+
br label %if.end
151+
152+
if.end: ; preds = %if.else, %if.then
153+
tail call void @llvm.eh.endcatch() #1
154+
br label %try.cont
155+
156+
; CHECK: try.cont: ; preds = %if.end, %invoke.cont
157+
; CHECK-NOT: %NumExceptions.1 = phi i32 [ %NumExceptions.020, %invoke.cont ], [ %inc, %if.end ]
158+
; CHECK: %NumExceptions.1 = phi i32 [ %NumExceptions.020.reload, %invoke.cont ], [ %inc, %if.end ]
159+
; CHECK: tail call void @"\01?does_not_throw@@YAXH@Z"(i32 %NumExceptions.1)
160+
; CHECK-NOT: %inc5 = add nuw nsw i32 %i.019, 1
161+
; CHECK: %inc5 = add nuw nsw i32 %i.019.reload, 1
162+
; CHECK: %cmp = icmp slt i32 %inc5, 10
163+
; CHECK: store i32 %NumExceptions.1, i32* %NumExceptions.020.reg2mem
164+
; CHECK: store i32 %inc5, i32* %i.019.reg2mem
165+
; CHECK: br i1 %cmp, label %for.body, label %for.end
166+
167+
try.cont: ; preds = %if.end, %invoke.cont
168+
%NumExceptions.1 = phi i32 [ %NumExceptions.020, %invoke.cont ], [ %inc, %if.end ]
169+
tail call void @"\01?does_not_throw@@YAXH@Z"(i32 %NumExceptions.1)
170+
%inc5 = add nuw nsw i32 %i.019, 1
171+
%cmp = icmp slt i32 %inc5, 10
172+
br i1 %cmp, label %for.body, label %for.end
173+
174+
for.end: ; preds = %try.cont
175+
%NumExceptions.1.lcssa = phi i32 [ %NumExceptions.1, %try.cont ]
176+
%arraydecay = getelementptr inbounds [10 x i32]* %ExceptionVal, i64 0, i64 0
177+
call void @"\01?dump@@YAXPEAHHAEAUSomeData@@@Z"(i32* %arraydecay, i32 %NumExceptions.1.lcssa, %struct.SomeData* dereferenceable(8) %tmpcast)
178+
call void @llvm.lifetime.end(i64 40, i8* %0) #1
179+
ret void
180+
181+
eh.resume: ; preds = %lpad
182+
%.lcssa = phi { i8*, i32 } [ %2, %lpad ]
183+
resume { i8*, i32 } %.lcssa
184+
}
185+
186+
; The following catch handler should be outlined.
187+
; CHECK: define i8* @"\01?test@@YAXXZ.catch"(i8*, i8*) {
188+
; CHECK: catch.entry:
189+
; CHECK: %eh.alloc = call i8* @llvm.framerecover(i8* bitcast (void ()* @"\01?test@@YAXXZ" to i8*), i8* %1)
190+
; CHECK: %eh.data = bitcast i8* %eh.alloc to %"struct.\01?test@@YAXXZ.ehdata"*
191+
; CHECK: %eh.obj.ptr = getelementptr inbounds %"struct.\01?test@@YAXXZ.ehdata"* %eh.data, i32 0, i32 1
192+
; CHECK: %eh.obj = load i8** %eh.obj.ptr
193+
; CHECK: %eh.temp.alloca = getelementptr inbounds %"struct.\01?test@@YAXXZ.ehdata"* %eh.data, i32 0, i32 2
194+
; CHECK: %NumExceptions.020.reload = load i32* %eh.temp.alloca
195+
; CHECK: %ExceptionVal = getelementptr inbounds %"struct.\01?test@@YAXXZ.ehdata"* %eh.data, i32 0, i32 3
196+
; CHECK: %eh.temp.alloca1 = getelementptr inbounds %"struct.\01?test@@YAXXZ.ehdata"* %eh.data, i32 0, i32 4
197+
; CHECK: %i.019.reload = load i32* %eh.temp.alloca1
198+
; CHECK: %eh.temp.alloca2 = getelementptr inbounds %"struct.\01?test@@YAXXZ.ehdata"* %eh.data, i32 0, i32 5
199+
; CHECK: %a.reload = load i32** %eh.temp.alloca2
200+
; CHECK: %eh.temp.alloca3 = getelementptr inbounds %"struct.\01?test@@YAXXZ.ehdata"* %eh.data, i32 0, i32 6
201+
; CHECK: %b.reload = load i32** %eh.temp.alloca3
202+
; CHECK: %2 = bitcast i8* %eh.obj to i32*
203+
; CHECK: %3 = load i32* %2, align 4, !tbaa !7
204+
; CHECK: %idxprom = sext i32 %NumExceptions.020.reload to i64
205+
; CHECK: %arrayidx = getelementptr inbounds [10 x i32]* %ExceptionVal, i64 0, i64 %idxprom
206+
; CHECK: store i32 %3, i32* %arrayidx, align 4, !tbaa !7
207+
; CHECK: %inc = add nsw i32 %NumExceptions.020.reload, 1
208+
; CHECK: %cmp1 = icmp eq i32 %3, %i.019.reload
209+
; CHECK: br i1 %cmp1, label %if.then, label %if.else
210+
;
211+
; CHECK: if.then: ; preds = %catch.entry
212+
; CHECK: %4 = load i32* %b.reload, align 4, !tbaa !8
213+
; CHECK: %add2 = add nsw i32 %4, %i.019.reload
214+
; CHECK: store i32 %add2, i32* %b.reload, align 4, !tbaa !8
215+
; CHECK: br label %if.end
216+
;
217+
; CHECK: if.else: ; preds = %catch.entry
218+
; CHECK: %5 = load i32* %a.reload, align 8, !tbaa !2
219+
; CHECK: %add4 = add nsw i32 %5, %3
220+
; CHECK: store i32 %add4, i32* %a.reload, align 8, !tbaa !2
221+
; CHECK: br label %if.end
222+
;
223+
; CHECK: if.end: ; preds = %if.else, %if.then
224+
; CHECK: ret i8* blockaddress(@"\01?test@@YAXXZ", %try.cont)
225+
; CHECK: }
226+
227+
; Function Attrs: nounwind
228+
declare void @llvm.lifetime.start(i64, i8* nocapture) #1
229+
230+
declare void @"\01?may_throw@@YAXXZ"() #2
231+
232+
declare i32 @__CxxFrameHandler3(...)
233+
234+
; Function Attrs: nounwind readnone
235+
declare i32 @llvm.eh.typeid.for(i8*) #3
236+
237+
declare i8* @llvm.eh.begincatch(i8*)
238+
239+
declare void @llvm.eh.endcatch()
240+
241+
declare void @"\01?does_not_throw@@YAXH@Z"(i32) #2
242+
243+
declare void @"\01?dump@@YAXPEAHHAEAUSomeData@@@Z"(i32*, i32, %struct.SomeData* dereferenceable(8)) #2
244+
245+
; Function Attrs: nounwind
246+
declare void @llvm.lifetime.end(i64, i8* nocapture) #1
247+
248+
attributes #0 = { 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" "unsafe-fp-math"="false" "use-soft-float"="false" }
249+
attributes #1 = { nounwind }
250+
attributes #2 = { "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
251+
attributes #3 = { nounwind readnone }
252+
253+
!llvm.module.flags = !{!0}
254+
!llvm.ident = !{!1}
255+
256+
!0 = !{i32 1, !"PIC Level", i32 2}
257+
!1 = !{!"clang version 3.7.0 (trunk 228868)"}
258+
!2 = !{!3, !4, i64 0}
259+
!3 = !{!"?AUSomeData@@", !4, i64 0, !4, i64 4}
260+
!4 = !{!"int", !5, i64 0}
261+
!5 = !{!"omnipotent char", !6, i64 0}
262+
!6 = !{!"Simple C/C++ TBAA"}
263+
!7 = !{!4, !4, i64 0}
264+
!8 = !{!3, !4, i64 4}

0 commit comments

Comments
 (0)
Please sign in to comment.