: Materializer(HandlerFn, VarInfo),
SelectorIDType(Type::getInt32Ty(HandlerFn->getContext())),
Int8PtrType(Type::getInt8PtrTy(HandlerFn->getContext())),
- LPadMap(LPadMap) {}
+ LPadMap(LPadMap) {
+ auto AI = HandlerFn->getArgumentList().begin();
+ ++AI;
+ EstablisherFrame = AI;
+ }
CloningAction handleInstruction(ValueToValueMapTy &VMap,
const Instruction *Inst,
Type *SelectorIDType;
Type *Int8PtrType;
LandingPadMap &LPadMap;
+
+ /// The value representing the parent frame pointer.
+ Value *EstablisherFrame;
};
class WinEHCatchDirector : public WinEHCloningDirectorBase {
Intrinsic::getDeclaration(M, Intrinsic::frameescape);
Function *RecoverFrameFn =
Intrinsic::getDeclaration(M, Intrinsic::framerecover);
+ SmallVector<Value *, 8> AllocasToEscape;
+
+ // Scan the entry block for an existing call to llvm.frameescape. We need to
+ // keep escaping those objects.
+ for (Instruction &I : F.front()) {
+ auto *II = dyn_cast<IntrinsicInst>(&I);
+ if (II && II->getIntrinsicID() == Intrinsic::frameescape) {
+ auto Args = II->arg_operands();
+ AllocasToEscape.append(Args.begin(), Args.end());
+ II->eraseFromParent();
+ break;
+ }
+ }
// Finally, replace all of the temporary allocas for frame variables used in
// the outlined handlers with calls to llvm.framerecover.
BasicBlock::iterator II = Entry->getFirstInsertionPt();
Instruction *AllocaInsertPt = II;
- SmallVector<Value *, 8> AllocasToEscape;
for (auto &VarInfoEntry : FrameVarInfo) {
Value *ParentVal = VarInfoEntry.first;
TinyPtrVector<AllocaInst *> &Allocas = VarInfoEntry.second;
VMap[Extract] = SelectorValue;
}
+static bool isFrameAddressCall(const Value *V) {
+ return match(const_cast<Value *>(V),
+ m_Intrinsic<Intrinsic::frameaddress>(m_SpecificInt(0)));
+}
+
CloningDirector::CloningAction WinEHCloningDirectorBase::handleInstruction(
ValueToValueMapTy &VMap, const Instruction *Inst, BasicBlock *NewBB) {
// If this is one of the boilerplate landing pad instructions, skip it.
if (match(Inst, m_Intrinsic<Intrinsic::eh_typeid_for>()))
return handleTypeIdFor(VMap, Inst, NewBB);
+ // When outlining llvm.frameaddress(i32 0), remap that to the second argument,
+ // which is the FP of the parent.
+ if (isFrameAddressCall(Inst)) {
+ VMap[Inst] = EstablisherFrame;
+ return CloningDirector::SkipInstruction;
+ }
+
// Continue with the default cloning behavior.
return CloningDirector::CloneInstruction;
}
<< Action->getStartBlock()->getName() << "\n");
}
-static bool isFrameAddressCall(Value *V) {
- return match(V, m_Intrinsic<Intrinsic::frameaddress>(m_SpecificInt(0)));
-}
-
static CallSite matchOutlinedFinallyCall(BasicBlock *BB,
Instruction *MaybeCall) {
// Look for finally blocks that Clang has already outlined for us.
target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-pc-windows-msvc"
+%struct._RTL_CRITICAL_SECTION = type { %struct._RTL_CRITICAL_SECTION_DEBUG*, i32, i32, i8*, i8*, i64 }
+%struct._RTL_CRITICAL_SECTION_DEBUG = type { i16, i16, %struct._RTL_CRITICAL_SECTION*, %struct._LIST_ENTRY, i32, i32, i32, i16, i16 }
+%struct._LIST_ENTRY = type { %struct._LIST_ENTRY*, %struct._LIST_ENTRY* }
+
declare i32 @puts(i8*)
declare void @may_crash()
declare i32 @__C_specific_handler(...)
+declare i8* @llvm.framerecover(i8*, i8*, i32) #1
+declare i8* @llvm.frameaddress(i32)
+declare void @llvm.frameescape(...)
+declare dllimport void @EnterCriticalSection(%struct._RTL_CRITICAL_SECTION*)
+declare dllimport void @LeaveCriticalSection(%struct._RTL_CRITICAL_SECTION*)
define void @use_finally() {
entry:
; CHECK-NEXT: cleanup
; CHECK-NEXT: call i8* (...) @llvm.eh.actions(i32 0, void (i8*, i8*)* @use_finally.cleanup)
; CHECK-NEXT: indirectbr i8* %recover, []
+
+; Function Attrs: nounwind uwtable
+define i32 @call_may_crash_locked() {
+entry:
+ %p = alloca %struct._RTL_CRITICAL_SECTION, align 8
+ call void (...) @llvm.frameescape(%struct._RTL_CRITICAL_SECTION* %p)
+ call void @EnterCriticalSection(%struct._RTL_CRITICAL_SECTION* %p)
+ invoke void @may_crash()
+ to label %invoke.cont unwind label %lpad
+
+invoke.cont: ; preds = %entry
+ %tmp2 = call i8* @llvm.frameaddress(i32 0)
+ %tmp3 = call i8* @llvm.framerecover(i8* bitcast (i32 ()* @call_may_crash_locked to i8*), i8* %tmp2, i32 0) #2
+ %tmp6 = bitcast i8* %tmp3 to %struct._RTL_CRITICAL_SECTION*
+ call void @LeaveCriticalSection(%struct._RTL_CRITICAL_SECTION* %tmp6)
+ ret i32 42
+
+lpad: ; preds = %entry
+ %tmp7 = landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__C_specific_handler to i8*)
+ cleanup
+ %tmp8 = call i8* @llvm.frameaddress(i32 0)
+ %tmp9 = call i8* @llvm.framerecover(i8* bitcast (i32 ()* @call_may_crash_locked to i8*), i8* %tmp8, i32 0)
+ %tmp12 = bitcast i8* %tmp9 to %struct._RTL_CRITICAL_SECTION*
+ call void @LeaveCriticalSection(%struct._RTL_CRITICAL_SECTION* %tmp12)
+ resume { i8*, i32 } %tmp7
+}
+
+; CHECK-LABEL: define i32 @call_may_crash_locked()
+; CHECK: invoke void @may_crash()
+;
+; CHECK: landingpad
+; CHECK-NEXT: cleanup
+; CHECK-NEXT: call i8* (...) @llvm.eh.actions(i32 0, void (i8*, i8*)* @call_may_crash_locked.cleanup)
+; CHECK-NEXT: indirectbr i8* %recover, []
+
+; CHECK-LABEL: define internal void @call_may_crash_locked.cleanup(i8*, i8*)
+; CHECK: %tmp9 = call i8* @llvm.framerecover(i8* bitcast (i32 ()* @call_may_crash_locked to i8*), i8* %1, i32 0)
+; CHECK: %tmp12 = bitcast i8* %tmp9 to %struct._RTL_CRITICAL_SECTION*
+; CHECK: call void @LeaveCriticalSection(%struct._RTL_CRITICAL_SECTION* %tmp12)