must be followed by an ':ref:`indirectbr <i_indirectbr>`' instruction that
jumps to the result of the intrinsic call.
-``llvm.eh.unwindhelp``
-----------------------
-
-.. code-block:: llvm
-
- void @llvm.eh.unwindhelp(i8*)
-
-This intrinsic designates the provided static alloca as the unwind help object.
-This object is used by Windows native exception handling on non-x86 platforms
-where xdata unwind information is used. It is typically an 8 byte chunk of
-memory treated as two 32-bit integers.
-
SJLJ Intrinsics
---------------
/// on the stack. Returns an index with a negative value.
int CreateFixedSpillStackObject(uint64_t Size, int64_t SPOffset);
- /// Allocates memory at a fixed, target-specific offset from the frame
- /// pointer. Marks the function as having its frame address taken.
- int CreateFrameAllocation(uint64_t Size);
-
/// isFixedObjectIndex - Returns true if the specified index corresponds to a
/// fixed stack object.
bool isFixedObjectIndex(int ObjectIdx) const {
// Represents the list of actions to take when an exception is thrown.
def int_eh_actions : Intrinsic<[llvm_ptr_ty], [llvm_vararg_ty], []>;
-// Designates the provided static alloca as the unwind help object. Required
-// for WinEH.
-def int_eh_unwindhelp : Intrinsic<[], [llvm_ptr_ty], []>;
-
// __builtin_unwind_init is an undocumented GCC intrinsic that causes all
// callee-saved registers to be saved and restored (regardless of whether they
// are used) in the calling function. It is used by libgcc_eh.
case Intrinsic::eh_begincatch:
case Intrinsic::eh_endcatch:
llvm_unreachable("begin/end catch intrinsics not lowered in codegen");
- case Intrinsic::eh_unwindhelp: {
- AllocaInst *Slot =
- cast<AllocaInst>(I.getArgOperand(0)->stripPointerCasts());
- assert(FuncInfo.StaticAllocaMap.count(Slot) &&
- "can only use static allocas with llvm.eh.unwindhelp");
- int FI = FuncInfo.StaticAllocaMap[Slot];
- MachineFunction &MF = DAG.getMachineFunction();
- MachineModuleInfo &MMI = MF.getMMI();
- MMI.getWinEHFuncInfo(MF.getFunction()).UnwindHelpFrameIdx = FI;
- return nullptr;
- }
}
}
Builder.SetInsertPoint(&F.getEntryBlock().back());
Builder.CreateCall(FrameEscapeFn, AllocasToEscape);
- // Insert an alloca for the EH state in the entry block. On x86, we will also
- // insert stores to update the EH state, but on other ISAs, the runtime does
- // it for us.
- // FIXME: This record is different on x86.
- Type *UnwindHelpTy = Type::getInt64Ty(Context);
- AllocaInst *UnwindHelp =
- new AllocaInst(UnwindHelpTy, "unwindhelp", &F.getEntryBlock().front());
- Builder.CreateStore(llvm::ConstantInt::get(UnwindHelpTy, -2), UnwindHelp,
- /*isVolatile=*/true);
- Function *UnwindHelpFn =
- Intrinsic::getDeclaration(M, Intrinsic::eh_unwindhelp);
- Builder.CreateCall(UnwindHelpFn,
- Builder.CreateBitCast(UnwindHelp, Int8PtrType));
-
// Clean up the handler action maps we created for this function
DeleteContainerSeconds(CatchHandlerMap);
CatchHandlerMap.clear();
break;
}
- case Intrinsic::eh_unwindhelp: {
- auto *AI = dyn_cast<AllocaInst>(CI.getArgOperand(0)->stripPointerCasts());
- Assert(AI && AI->isStaticAlloca(),
- "llvm.eh.unwindhelp requires a static alloca", &CI);
- break;
- }
-
case Intrinsic::experimental_gc_statepoint:
Assert(!CI.isInlineAsm(),
"gc.statepoint support for inline assembly unimplemented", &CI);
return makeArrayRef(std::begin(XMMArgRegs64Bit), std::end(XMMArgRegs64Bit));
}
-static bool isOutlinedHandler(const MachineFunction &MF) {
- const MachineModuleInfo &MMI = MF.getMMI();
- const Function *F = MF.getFunction();
- return MMI.getWinEHParent(F) != F;
-}
-
SDValue
X86TargetLowering::LowerFormalArguments(SDValue Chain,
CallingConv::ID CallConv,
MFI->CreateFixedObject(1, StackSize, true));
}
+ MachineModuleInfo &MMI = MF.getMMI();
+ const Function *WinEHParent = nullptr;
+ if (IsWin64 && MMI.hasWinEHFuncInfo(Fn))
+ WinEHParent = MMI.getWinEHParent(Fn);
+ bool IsWinEHOutlined = WinEHParent && WinEHParent != Fn;
+ bool IsWinEHParent = WinEHParent && WinEHParent == Fn;
+
// Figure out if XMM registers are in use.
assert(!(MF.getTarget().Options.UseSoftFloat &&
Fn->hasFnAttribute(Attribute::NoImplicitFloat)) &&
if (!MemOps.empty())
Chain = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, MemOps);
- } else if (IsWin64 && isOutlinedHandler(MF)) {
+ } else if (IsWinEHOutlined) {
// Get to the caller-allocated home save location. Add 8 to account
// for the return address.
int HomeOffset = TFI.getOffsetOfLocalArea() + 8;
FuncInfo->setRegSaveFrameIndex(MFI->CreateFixedObject(
/*Size=*/1, /*SPOffset=*/HomeOffset + 8, /*Immutable=*/false));
- MachineModuleInfo &MMI = MF.getMMI();
MMI.getWinEHFuncInfo(Fn)
.CatchHandlerParentFrameObjIdx[const_cast<Function *>(Fn)] =
FuncInfo->getRegSaveFrameIndex();
FuncInfo->setArgumentStackSize(StackSize);
+ if (IsWinEHParent) {
+ int UnwindHelpFI = MFI->CreateStackObject(8, 8, /*isSS=*/false);
+ SDValue StackSlot = DAG.getFrameIndex(UnwindHelpFI, MVT::i64);
+ MMI.getWinEHFuncInfo(MF.getFunction()).UnwindHelpFrameIdx = UnwindHelpFI;
+ SDValue Neg2 = DAG.getConstant(-2, MVT::i64);
+ Chain = DAG.getStore(Chain, dl, Neg2, StackSlot,
+ MachinePointerInfo::getFixedStack(UnwindHelpFI),
+ /*isVolatile=*/true,
+ /*isNonTemporal=*/false, /*Alignment=*/0);
+ }
+
return Chain;
}
; CHECK-LABEL: define void @"\01?test@@YAXXZ"() #0 {
; CHECK: entry:
-; CHECK: [[UNWIND_HELP:\%.+]] = alloca i64
; CHECK: [[OBJ_PTR:\%.+]] = alloca %class.SomeClass
; CHECK: [[TMP0:\%.+]] = alloca i32, align 4
; CHECK: [[TMP1:\%.+]] = alloca i32, align 4
; CHECK: call void (...)* @llvm.frameescape(i32* [[TMP1]], %class.SomeClass* [[OBJ_PTR]], i32* [[TMP0]])
-; CHECK: [[UNWIND_HELP_i8:\%.+]] = bitcast i64* [[UNWIND_HELP]] to i8*
-; CHECK: call void @llvm.eh.unwindhelp(i8* [[UNWIND_HELP_i8]])
; CHECK: %call = invoke %class.SomeClass* @"\01??0SomeClass@@QEAA@XZ"(%class.SomeClass* %obj)
; CHECK: to label %invoke.cont unwind label %[[LPAD_LABEL:lpad[0-9]+]]
; CHECK: define void @"\01?test@@YAXXZ"() #0 {
; CHECK: entry:
-; CHECK: [[UNWINDHELP:\%.+]] = alloca i64
; CHECK: [[OBJ_PTR:\%.+]] = alloca %class.SomeClass*, align 8
; CHECK: [[LL_PTR:\%.+]] = alloca i64, align 8
; CHECK: [[I_PTR:\%.+]] = alloca i32, align 4
; CHECK: call void (...)* @llvm.frameescape(i32* [[I_PTR]], i64* [[LL_PTR]], %class.SomeClass** [[OBJ_PTR]])
-; CHECK: store volatile i64 -2, i64* [[UNWINDHELP]]
-; CHECK: [[TMP:\%.+]] = bitcast i64* [[UNWINDHELP]] to i8*
-; CHECK: call void @llvm.eh.unwindhelp(i8* [[TMP]])
; CHECK: invoke void @"\01?may_throw@@YAXXZ"()
; CHECK: to label %invoke.cont unwind label %[[LPAD_LABEL:lpad[0-9]+]]
define internal i8* @"\01?f@@YAXXZ.catch"(i8*, i8*) #4 {
entry:
%.i8 = call i8* @llvm.framerecover(i8* bitcast (void ()* @"\01?f@@YAXXZ" to i8*), i8* %1, i32 0)
- %2 = bitcast i8* %.i8 to i32**
- %3 = bitcast i32** %2 to i8*
+ %bc2 = bitcast i8* %.i8 to i32**
+ %bc3 = bitcast i32** %bc2 to i8*
invoke void @"\01?may_throw@@YAXXZ"()
to label %invoke.cont2 unwind label %lpad1
ret i8* blockaddress(@"\01?f@@YAXXZ", %try.cont)
lpad1: ; preds = %entry
- %4 = landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*)
+ %lp4 = landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*)
cleanup
catch %eh.CatchHandlerType* @llvm.eh.handlertype.N.0
%recover = call i8* (...)* @llvm.eh.actions(i32 1, i8* bitcast (%eh.CatchHandlerType* @llvm.eh.handlertype.N.0 to i8*), i32 1, i8* (i8*, i8*)* @"\01?f@@YAXXZ.catch1")
}
; CHECK-LABEL: "?f@@YAXXZ.catch":
-; CHECK: ".L?f@@YAXXZ.catch$parent_frame_offset" = 56
-; CHECK: movq %rdx, 56(%rsp)
; CHECK: .seh_handlerdata
; CHECK: .long ("$cppxdata$?f@@YAXXZ")@IMGREL
define void @"\01?f@@YAXXZ"() #0 {
entry:
- %unwindhelp = alloca i64
%exn.slot = alloca i8*
%ehselector.slot = alloca i32
%0 = alloca i32*, align 8
%1 = alloca double, align 8
call void (...)* @llvm.frameescape(i32** %0, double* %1)
- store volatile i64 -2, i64* %unwindhelp
- %2 = bitcast i64* %unwindhelp to i8*
- call void @llvm.eh.unwindhelp(i8* %2)
invoke void @"\01?may_throw@@YAXXZ"()
to label %invoke.cont unwind label %lpad2
br label %try.cont
lpad2: ; preds = %entry
- %3 = landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*)
+ %2 = landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*)
catch %eh.CatchHandlerType* @llvm.eh.handlertype.H.8
catch %eh.CatchHandlerType* @llvm.eh.handlertype.N.0
%recover = call i8* (...)* @llvm.eh.actions(i32 1, i8* bitcast (%eh.CatchHandlerType* @llvm.eh.handlertype.H.8 to i8*), i32 0, i8* (i8*, i8*)* @"\01?f@@YAXXZ.catch", i32 1, i8* bitcast (%eh.CatchHandlerType* @llvm.eh.handlertype.N.0 to i8*), i32 1, i8* (i8*, i8*)* @"\01?f@@YAXXZ.catch1")
to label %try.cont8 unwind label %lpad1
lpad1:
- %4 = landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*)
+ %3 = landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*)
catch %eh.CatchHandlerType* @llvm.eh.handlertype.N.0
%recover2 = call i8* (...)* @llvm.eh.actions(i32 1, i8* bitcast (%eh.CatchHandlerType* @llvm.eh.handlertype.N.0 to i8*), i32 1, i8* (i8*, i8*)* @"\01?f@@YAXXZ.catch1")
indirectbr i8* %recover2, [label %try.cont8]
; CHECK-NEXT: .long ("$tryMap$?f@@YAXXZ")@IMGREL
; CHECK-NEXT: .long 3
; CHECK-NEXT: .long ("$ip2state$?f@@YAXXZ")@IMGREL
-; CHECK-NEXT: .long 64
+; CHECK-NEXT: .long 32
; CHECK-NEXT: .long 0
; CHECK-NEXT: .long 1
; CHECK-NEXT:"$stateUnwindMap$?f@@YAXXZ":
; Function Attrs: nounwind readnone
declare i8* @llvm.framerecover(i8*, i8*, i32) #2
-; Function Attrs: nounwind
-declare void @llvm.eh.unwindhelp(i8*) #3
-
declare void @llvm.donothing(...)
attributes #0 = { "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-realign-stack" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" "wineh-parent"="\ 1?f@@YAXXZ" }
; CHECK-NEXT: .long 0
; CHECK-NEXT: .long 1
; CHECK-NEXT: .long ("$ip2state$?test1@@YAXXZ")@IMGREL
-; CHECK-NEXT: .long 64
+; CHECK-NEXT: .long 32
; CHECK-NEXT: .long 0
; CHECK-NEXT: .long 1
; CHECK-NEXT:"$stateUnwindMap$?test1@@YAXXZ":
; CHECK-NEXT: .long 0
; CHECK-NEXT: .long 4
; CHECK-NEXT: .long ("$ip2state$?test2@@YAX_N@Z")@IMGREL
-; CHECK-NEXT: .long 64
+; CHECK-NEXT: .long 40
; CHECK-NEXT: .long 0
; CHECK-NEXT: .long 1
; CHECK-NEXT:"$stateUnwindMap$?test2@@YAX_N@Z":
; CHECK-NEXT: .long 0
define void @"\01?test2@@YAX_N@Z"(i1 zeroext %b) #2 {
-entry:
- %unwindhelp = alloca i64
%b.addr = alloca i8, align 1
%s = alloca %struct.S, align 1
%exn.slot = alloca i8*
%s1 = alloca %struct.S, align 1
%frombool = zext i1 %b to i8
store i8 %frombool, i8* %b.addr, align 1
- %0 = bitcast i64* %unwindhelp to i8*
- store volatile i64 -2, i64* %unwindhelp
call void (...)* @llvm.frameescape(%struct.S* %s, %struct.S* %s1)
- call void @llvm.eh.unwindhelp(i8* %0)
call void @"\01?may_throw@@YAXXZ"()
invoke void @"\01?may_throw@@YAXXZ"()
to label %invoke.cont unwind label %lpad1