llvm.org GIT mirror llvm / 8992ead
[WinEH] Correctly handle inlined __finally blocks with captures We should also teach the inliner to collapse framerecover of frameaddress of the current frame down to an alloca, but that can happen later. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@235459 91177308-0d34-0410-b5e6-96231b3b80d8 Reid Kleckner 5 years ago
2 changed file(s) with 81 addition(s) and 6 deletion(s). Raw diff Collapse all Expand all
174174 : Materializer(HandlerFn, VarInfo),
175175 SelectorIDType(Type::getInt32Ty(HandlerFn->getContext())),
176176 Int8PtrType(Type::getInt8PtrTy(HandlerFn->getContext())),
177 LPadMap(LPadMap) {}
177 LPadMap(LPadMap) {
178 auto AI = HandlerFn->getArgumentList().begin();
179 ++AI;
180 EstablisherFrame = AI;
181 }
178182
179183 CloningAction handleInstruction(ValueToValueMapTy &VMap,
180184 const Instruction *Inst,
209213 Type *SelectorIDType;
210214 Type *Int8PtrType;
211215 LandingPadMap &LPadMap;
216
217 /// The value representing the parent frame pointer.
218 Value *EstablisherFrame;
212219 };
213220
214221 class WinEHCatchDirector : public WinEHCloningDirectorBase {
519526 Intrinsic::getDeclaration(M, Intrinsic::frameescape);
520527 Function *RecoverFrameFn =
521528 Intrinsic::getDeclaration(M, Intrinsic::framerecover);
529 SmallVector AllocasToEscape;
530
531 // Scan the entry block for an existing call to llvm.frameescape. We need to
532 // keep escaping those objects.
533 for (Instruction &I : F.front()) {
534 auto *II = dyn_cast(&I);
535 if (II && II->getIntrinsicID() == Intrinsic::frameescape) {
536 auto Args = II->arg_operands();
537 AllocasToEscape.append(Args.begin(), Args.end());
538 II->eraseFromParent();
539 break;
540 }
541 }
522542
523543 // Finally, replace all of the temporary allocas for frame variables used in
524544 // the outlined handlers with calls to llvm.framerecover.
525545 BasicBlock::iterator II = Entry->getFirstInsertionPt();
526546 Instruction *AllocaInsertPt = II;
527 SmallVector AllocasToEscape;
528547 for (auto &VarInfoEntry : FrameVarInfo) {
529548 Value *ParentVal = VarInfoEntry.first;
530549 TinyPtrVector &Allocas = VarInfoEntry.second;
10501069 VMap[Extract] = SelectorValue;
10511070 }
10521071
1072 static bool isFrameAddressCall(const Value *V) {
1073 return match(const_cast(V),
1074 m_Intrinsic(m_SpecificInt(0)));
1075 }
1076
10531077 CloningDirector::CloningAction WinEHCloningDirectorBase::handleInstruction(
10541078 ValueToValueMapTy &VMap, const Instruction *Inst, BasicBlock *NewBB) {
10551079 // If this is one of the boilerplate landing pad instructions, skip it.
10811105 return handleEndCatch(VMap, Inst, NewBB);
10821106 if (match(Inst, m_Intrinsic()))
10831107 return handleTypeIdFor(VMap, Inst, NewBB);
1108
1109 // When outlining llvm.frameaddress(i32 0), remap that to the second argument,
1110 // which is the FP of the parent.
1111 if (isFrameAddressCall(Inst)) {
1112 VMap[Inst] = EstablisherFrame;
1113 return CloningDirector::SkipInstruction;
1114 }
10841115
10851116 // Continue with the default cloning behavior.
10861117 return CloningDirector::CloneInstruction;
15811612 Actions.insertCleanupHandler(Action);
15821613 DEBUG(dbgs() << " Found cleanup code in block "
15831614 << Action->getStartBlock()->getName() << "\n");
1584 }
1585
1586 static bool isFrameAddressCall(Value *V) {
1587 return match(V, m_Intrinsic(m_SpecificInt(0)));
15881615 }
15891616
15901617 static CallSite matchOutlinedFinallyCall(BasicBlock *BB,
55 target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
66 target triple = "x86_64-pc-windows-msvc"
77
8 %struct._RTL_CRITICAL_SECTION = type { %struct._RTL_CRITICAL_SECTION_DEBUG*, i32, i32, i8*, i8*, i64 }
9 %struct._RTL_CRITICAL_SECTION_DEBUG = type { i16, i16, %struct._RTL_CRITICAL_SECTION*, %struct._LIST_ENTRY, i32, i32, i32, i16, i16 }
10 %struct._LIST_ENTRY = type { %struct._LIST_ENTRY*, %struct._LIST_ENTRY* }
11
812 declare i32 @puts(i8*)
913 declare void @may_crash()
1014 declare i32 @__C_specific_handler(...)
15 declare i8* @llvm.framerecover(i8*, i8*, i32) #1
16 declare i8* @llvm.frameaddress(i32)
17 declare void @llvm.frameescape(...)
18 declare dllimport void @EnterCriticalSection(%struct._RTL_CRITICAL_SECTION*)
19 declare dllimport void @LeaveCriticalSection(%struct._RTL_CRITICAL_SECTION*)
1120
1221 define void @use_finally() {
1322 entry:
3241 ; CHECK-NEXT: cleanup
3342 ; CHECK-NEXT: call i8* (...) @llvm.eh.actions(i32 0, void (i8*, i8*)* @use_finally.cleanup)
3443 ; CHECK-NEXT: indirectbr i8* %recover, []
44
45 ; Function Attrs: nounwind uwtable
46 define i32 @call_may_crash_locked() {
47 entry:
48 %p = alloca %struct._RTL_CRITICAL_SECTION, align 8
49 call void (...) @llvm.frameescape(%struct._RTL_CRITICAL_SECTION* %p)
50 call void @EnterCriticalSection(%struct._RTL_CRITICAL_SECTION* %p)
51 invoke void @may_crash()
52 to label %invoke.cont unwind label %lpad
53
54 invoke.cont: ; preds = %entry
55 %tmp2 = call i8* @llvm.frameaddress(i32 0)
56 %tmp3 = call i8* @llvm.framerecover(i8* bitcast (i32 ()* @call_may_crash_locked to i8*), i8* %tmp2, i32 0) #2
57 %tmp6 = bitcast i8* %tmp3 to %struct._RTL_CRITICAL_SECTION*
58 call void @LeaveCriticalSection(%struct._RTL_CRITICAL_SECTION* %tmp6)
59 ret i32 42
60
61 lpad: ; preds = %entry
62 %tmp7 = landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__C_specific_handler to i8*)
63 cleanup
64 %tmp8 = call i8* @llvm.frameaddress(i32 0)
65 %tmp9 = call i8* @llvm.framerecover(i8* bitcast (i32 ()* @call_may_crash_locked to i8*), i8* %tmp8, i32 0)
66 %tmp12 = bitcast i8* %tmp9 to %struct._RTL_CRITICAL_SECTION*
67 call void @LeaveCriticalSection(%struct._RTL_CRITICAL_SECTION* %tmp12)
68 resume { i8*, i32 } %tmp7
69 }
70
71 ; CHECK-LABEL: define i32 @call_may_crash_locked()
72 ; CHECK: invoke void @may_crash()
73 ;
74 ; CHECK: landingpad
75 ; CHECK-NEXT: cleanup
76 ; CHECK-NEXT: call i8* (...) @llvm.eh.actions(i32 0, void (i8*, i8*)* @call_may_crash_locked.cleanup)
77 ; CHECK-NEXT: indirectbr i8* %recover, []
78
79 ; CHECK-LABEL: define internal void @call_may_crash_locked.cleanup(i8*, i8*)
80 ; CHECK: %tmp9 = call i8* @llvm.framerecover(i8* bitcast (i32 ()* @call_may_crash_locked to i8*), i8* %1, i32 0)
81 ; CHECK: %tmp12 = bitcast i8* %tmp9 to %struct._RTL_CRITICAL_SECTION*
82 ; CHECK: call void @LeaveCriticalSection(%struct._RTL_CRITICAL_SECTION* %tmp12)