llvm.org GIT mirror llvm / 3e16bd3
[WinEH] Create an llvm.x86.seh.exceptioninfo intrinsic This intrinsic is like framerecover plus a load. It recovers the EH registration stack allocation from the parent frame and loads the exception information field out of it, giving back a pointer to an EXCEPTION_POINTERS struct. It's designed for clang to use in SEH filter expressions instead of accessing the EXCEPTION_POINTERS parameter that is available on x64. This required a minor change to MC to allow defining a label variable to another absolute framerecover label variable. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@239567 91177308-0d34-0410-b5e6-96231b3b80d8 Reid Kleckner 5 years ago
10 changed file(s) with 177 addition(s) and 106 deletion(s). Raw diff Collapse all Expand all
143143 SmallVector UnwindMap;
144144 SmallVector TryBlockMap;
145145 SmallVector, 4> IPToStateList;
146 int UnwindHelpFrameIdx;
147 int UnwindHelpFrameOffset;
146 int UnwindHelpFrameIdx = INT_MAX;
147 int UnwindHelpFrameOffset = -1;
148 unsigned NumIPToStateFuncsVisited = 0;
148149
149 unsigned NumIPToStateFuncsVisited;
150 /// frameescape index of the 32-bit EH registration node. Set by
151 /// WinEHStatePass and used indirectly by SEH filter functions of the parent.
152 int EHRegNodeEscapeIndex = INT_MAX;
150153
151 WinEHFuncInfo()
152 : UnwindHelpFrameIdx(INT_MAX), UnwindHelpFrameOffset(-1),
153 NumIPToStateFuncsVisited(0) {}
154 WinEHFuncInfo() {}
154155 };
155156
156157 /// Analyze the IR in ParentFn and it's handlers to build WinEHFuncInfo, which
428428 def int_eh_actions : Intrinsic<[llvm_ptr_ty], [llvm_vararg_ty], []>;
429429
430430 def int_eh_exceptioncode : Intrinsic<[llvm_i32_ty], [], [IntrReadMem]>;
431 def int_eh_exceptioninfo : Intrinsic<[llvm_ptr_ty], [], [IntrReadMem]>;
432431
433432 // __builtin_unwind_init is an undocumented GCC intrinsic that causes all
434433 // callee-saved registers to be saved and restored (regardless of whether they
1717 }
1818
1919 //===----------------------------------------------------------------------===//
20 // SEH LSDA for Windows
20 // SEH intrinsics for Windows
2121 let TargetPrefix = "x86" in {
2222 def int_x86_seh_lsda : Intrinsic<[llvm_ptr_ty], [llvm_ptr_ty], [IntrNoMem]>;
23 def int_x86_seh_exceptioninfo : Intrinsic<[llvm_ptr_ty],
24 [llvm_ptr_ty, llvm_ptr_ty],
25 [IntrReadMem]>;
2326 }
2427
2528 //===----------------------------------------------------------------------===//
448448 Asm->OutContext.getOrCreateParentFrameOffsetSymbol(
449449 GlobalValue::getRealLinkageName(HT.Handler->getName()));
450450 const MCSymbolRefExpr *ParentFrameOffsetRef = MCSymbolRefExpr::create(
451 ParentFrameOffset, MCSymbolRefExpr::VK_None, Asm->OutContext);
451 ParentFrameOffset, Asm->OutContext);
452452 OS.EmitValue(ParentFrameOffsetRef, 4); // ParentFrameOffset
453453 }
454454 }
550550 /// functionally equivalent to the __C_specific_handler table, except it is
551551 /// indexed by state number instead of IP.
552552 void WinException::emitExceptHandlerTable(const MachineFunction *MF) {
553 auto &OS = *Asm->OutStreamer;
553 MCStreamer &OS = *Asm->OutStreamer;
554
555 // Define the EH registration node offset label in terms of its frameescape
556 // label. The WinEHStatePass ensures that the registration node is passed to
557 // frameescape. This allows SEH filter functions to access the
558 // EXCEPTION_POINTERS field, which is filled in by the _except_handlerN.
559 const Function *F = MF->getFunction();
560 WinEHFuncInfo &FuncInfo = MMI->getWinEHFuncInfo(F);
561 assert(FuncInfo.EHRegNodeEscapeIndex != INT_MAX &&
562 "no EH reg node frameescape index");
563 StringRef FLinkageName = GlobalValue::getRealLinkageName(F->getName());
564 MCSymbol *ParentFrameOffset =
565 Asm->OutContext.getOrCreateParentFrameOffsetSymbol(FLinkageName);
566 MCSymbol *FrameAllocSym = Asm->OutContext.getOrCreateFrameAllocSymbol(
567 FLinkageName, FuncInfo.EHRegNodeEscapeIndex);
568 const MCSymbolRefExpr *FrameAllocSymRef =
569 MCSymbolRefExpr::create(FrameAllocSym, Asm->OutContext);
570 OS.EmitAssignment(ParentFrameOffset, FrameAllocSymRef);
554571
555572 // Emit the __ehtable label that we use for llvm.x86.seh.lsda.
556 const Function *F = MF->getFunction();
557 StringRef FLinkageName = GlobalValue::getRealLinkageName(F->getName());
558573 MCSymbol *LSDALabel = Asm->OutContext.getOrCreateLSDASymbol(FLinkageName);
559574 OS.EmitLabel(LSDALabel);
560575
525525 if (!Symbol.isTemporary())
526526 return true;
527527
528 // Temporary variable symbols are invisible.
529 if (Symbol.isVariable())
530 return false;
531
528532 // Absolute temporary labels are never visible.
529 if (!Symbol.isInSection())
530 return false;
531
532 // For now, all non-variable symbols are exported,
533 // the linker will sort the rest out for us.
534 return !Symbol.isVariable();
533 return !Symbol.isAbsolute();
535534 }
536535
537536 bool WinCOFFObjectWriter::IsPhysicalSection(COFFSection *S) {
1550515505 DAG.getTargetExternalSymbol(Name.data(), VT, X86II::MO_NOPREFIX);
1550615506 return DAG.getNode(X86ISD::Wrapper, dl, VT, Result);
1550715507 }
15508
15509 case Intrinsic::eh_exceptioninfo: {
15510 // Compute the symbol for the LSDA. We know it'll get emitted later.
15511 MachineFunction &MF = DAG.getMachineFunction();
15512 SDValue Op1 = Op.getOperand(1);
15513 auto *Fn = cast(cast(Op1)->getGlobal());
15514 MCSymbol *LSDASym = MF.getMMI().getContext().getOrCreateLSDASymbol(
15515 GlobalValue::getRealLinkageName(Fn->getName()));
15516 StringRef Name = LSDASym->getName();
15517 assert(Name.data()[Name.size()] == '\0' && "not null terminated");
15518
15519 // Generate a simple absolute symbol reference. This intrinsic is only
15520 // supported on 32-bit Windows, which isn't PIC.
15521 SDValue Result =
15522 DAG.getTargetExternalSymbol(Name.data(), VT, X86II::MO_NOPREFIX);
15523 return DAG.getNode(X86ISD::Wrapper, dl, VT, Result);
15524 }
1552515508 }
1552615509 }
1552715510
1570615689 return DAG.getMergeValues(Results, DL);
1570715690 }
1570815691
15692 static SDValue LowerEXCEPTIONINFO(SDValue Op, const X86Subtarget *Subtarget,
15693 SelectionDAG &DAG) {
15694 MachineFunction &MF = DAG.getMachineFunction();
15695 SDLoc dl(Op);
15696 SDValue FnOp = Op.getOperand(2);
15697 SDValue FPOp = Op.getOperand(3);
15698
15699 // Compute the symbol for the parent EH registration. We know it'll get
15700 // emitted later.
15701 auto *Fn = cast(cast(FnOp)->getGlobal());
15702 MCSymbol *ParentFrameSym =
15703 MF.getMMI().getContext().getOrCreateParentFrameOffsetSymbol(
15704 GlobalValue::getRealLinkageName(Fn->getName()));
15705 StringRef Name = ParentFrameSym->getName();
15706 assert(Name.data()[Name.size()] == '\0' && "not null terminated");
15707
15708 // Create a TargetExternalSymbol for the label to avoid any target lowering
15709 // that would make this PC relative.
15710 MVT PtrVT = Op.getSimpleValueType();
15711 SDValue OffsetSym = DAG.getTargetExternalSymbol(Name.data(), PtrVT);
15712 SDValue OffsetVal =
15713 DAG.getNode(ISD::FRAME_ALLOC_RECOVER, dl, PtrVT, OffsetSym);
15714
15715 // Add the offset to the FP.
15716 SDValue Add = DAG.getNode(ISD::ADD, dl, PtrVT, FPOp, OffsetVal);
15717
15718 // Load the second field of the struct, which is 4 bytes in. See
15719 // WinEHStatePass for more info.
15720 Add = DAG.getNode(ISD::ADD, dl, PtrVT, Add, DAG.getConstant(4, dl, PtrVT));
15721 return DAG.getLoad(PtrVT, dl, DAG.getEntryNode(), Add, MachinePointerInfo(),
15722 false, false, false, 0);
15723 }
1570915724
1571015725 static SDValue LowerINTRINSIC_W_CHAIN(SDValue Op, const X86Subtarget *Subtarget,
1571115726 SelectionDAG &DAG) {
1571215727 unsigned IntNo = cast(Op.getOperand(1))->getZExtValue();
1571315728
1571415729 const IntrinsicData* IntrData = getIntrinsicWithChain(IntNo);
15715 if (!IntrData)
15730 if (!IntrData) {
15731 if (IntNo == Intrinsic::x86_seh_exceptioninfo)
15732 return LowerEXCEPTIONINFO(Op, Subtarget, DAG);
1571615733 return SDValue();
15734 }
1571715735
1571815736 SDLoc dl(Op);
1571915737 switch(IntrData->Type) {
6666 void addCXXStateStoresToFunclet(Value *ParentRegNode, WinEHFuncInfo &FuncInfo,
6767 Function &F, int BaseState);
6868 void insertStateNumberStore(Value *ParentRegNode, Instruction *IP, int State);
69 iplist::iterator
70 rewriteExceptionInfoIntrinsics(IntrinsicInst *Intrin);
7169
7270 Value *emitEHLSDA(IRBuilder<> &Builder, Function *F);
7371
486484 void WinEHStatePass::addSEHStateStores(Function &F, MachineModuleInfo &MMI) {
487485 WinEHFuncInfo &FuncInfo = MMI.getWinEHFuncInfo(&F);
488486
487 // Remember and return the index that we used. We save it in WinEHFuncInfo so
488 // that we can lower llvm.x86.seh.exceptioninfo later in filter functions
489 // without too much trouble.
490 int RegNodeEscapeIndex = escapeRegNode(F);
491 FuncInfo.EHRegNodeEscapeIndex = RegNodeEscapeIndex;
492
489493 // Iterate all the instructions and emit state number stores.
490494 int CurState = 0;
491495 SmallPtrSet ExceptBlocks;
494498 if (auto *CI = dyn_cast(I)) {
495499 auto *Intrin = dyn_cast(CI);
496500 if (Intrin) {
497 I = rewriteExceptionInfoIntrinsics(Intrin);
498501 // Calls that "don't throw" are considered to be able to throw asynch
499502 // exceptions, but intrinsics cannot.
500503 continue;
541544 }
542545 }
543546
544 /// Rewrite llvm.eh.exceptioncode and llvm.eh.exceptioninfo to memory loads in
545 /// IR.
546 iplist::iterator
547 WinEHStatePass::rewriteExceptionInfoIntrinsics(IntrinsicInst *Intrin) {
548 Intrinsic::ID ID = Intrin->getIntrinsicID();
549 if (ID != Intrinsic::eh_exceptioncode && ID != Intrinsic::eh_exceptioninfo)
550 return Intrin;
551
552 // RegNode->ExceptionPointers
553 IRBuilder<> Builder(Intrin);
554 Value *Ptrs =
555 Builder.CreateLoad(Builder.CreateStructGEP(RegNodeTy, RegNode, 1));
556 Value *Res;
557 if (ID == Intrinsic::eh_exceptioncode) {
558 // Ptrs->ExceptionRecord->Code
559 Ptrs = Builder.CreateBitCast(
560 Ptrs, Builder.getInt32Ty()->getPointerTo()->getPointerTo());
561 Value *Rec = Builder.CreateLoad(Ptrs);
562 Res = Builder.CreateLoad(Rec);
563 } else {
564 Res = Ptrs;
565 }
566 Intrin->replaceAllUsesWith(Res);
567 return Intrin->eraseFromParent();
568 }
569
570547 void WinEHStatePass::insertStateNumberStore(Value *ParentRegNode,
571548 Instruction *IP, int State) {
572549 IRBuilder<> Builder(IP);
0 ; RUN: llc -mtriple=i686-windows-msvc < %s | FileCheck %s
1
2 ; 32-bit catch-all has to use a filter function because that's how it saves the
3 ; exception code.
4
5 @str = linkonce_odr unnamed_addr constant [27 x i8] c"GetExceptionCode(): 0x%lx\0A\00", align 1
6
7 declare i32 @_except_handler3(...)
8 declare void @crash()
9 declare i32 @printf(i8* nocapture readonly, ...) nounwind
10 declare i32 @llvm.eh.typeid.for(i8*)
11 declare i8* @llvm.frameaddress(i32)
12 declare i8* @llvm.framerecover(i8*, i8*, i32)
13 declare void @llvm.frameescape(...)
14 declare i8* @llvm.x86.seh.exceptioninfo(i8*, i8*)
15
16 define i32 @main() {
17 entry:
18 %__exceptioncode = alloca i32, align 4
19 call void (...) @llvm.frameescape(i32* %__exceptioncode)
20 invoke void @crash() #5
21 to label %__try.cont unwind label %lpad
22
23 lpad: ; preds = %entry
24 %0 = landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @_except_handler3 to i8*)
25 catch i8* bitcast (i32 ()* @"filt$main" to i8*)
26 %1 = extractvalue { i8*, i32 } %0, 1
27 %2 = call i32 @llvm.eh.typeid.for(i8* bitcast (i32 ()* @"filt$main" to i8*)) #4
28 %matches = icmp eq i32 %1, %2
29 br i1 %matches, label %__except, label %eh.resume
30
31 __except: ; preds = %lpad
32 %3 = load i32, i32* %__exceptioncode, align 4
33 %call = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([27 x i8], [27 x i8]* @str, i32 0, i32 0), i32 %3) #4
34 br label %__try.cont
35
36 __try.cont: ; preds = %entry, %__except
37 ret i32 0
38
39 eh.resume: ; preds = %lpad
40 resume { i8*, i32 } %0
41 }
42
43 define internal i32 @"filt$main"() {
44 entry:
45 %0 = tail call i8* @llvm.frameaddress(i32 1)
46 %1 = tail call i8* @llvm.framerecover(i8* bitcast (i32 ()* @main to i8*), i8* %0, i32 0)
47 %__exceptioncode = bitcast i8* %1 to i32*
48 %2 = tail call i8* @llvm.x86.seh.exceptioninfo(i8* bitcast (i32 ()* @main to i8*), i8* %0)
49 %3 = bitcast i8* %2 to i32**
50 %4 = load i32*, i32** %3, align 4
51 %5 = load i32, i32* %4, align 4
52 store i32 %5, i32* %__exceptioncode, align 4
53 ret i32 1
54 }
55
56 ; Check that we can get the exception code from eax to the printf.
57
58 ; CHECK-LABEL: _main:
59 ; CHECK: Lmain$frame_escape_0 = [[code_offs:[-0-9]+]]
60 ; CHECK: Lmain$frame_escape_1 = [[reg_offs:[-0-9]+]]
61 ; CHECK: movl %esp, [[reg_offs]](%ebp)
62 ; CHECK: movl $L__ehtable$main,
63 ; EH state 0
64 ; CHECK: movl $0, -4(%ebp)
65 ; CHECK: calll _crash
66 ; CHECK: retl
67 ; CHECK: # Block address taken
68 ; stackrestore
69 ; CHECK: movl [[reg_offs]](%ebp), %esp
70 ; EH state -1
71 ; CHECK: movl [[code_offs]](%ebp), %[[code:[a-z]+]]
72 ; CHECK: movl $-1, -4(%ebp)
73 ; CHECK-DAG: movl %[[code]], 4(%esp)
74 ; CHECK-DAG: movl $_str, (%esp)
75 ; CHECK: calll _printf
76
77 ; CHECK: .section .xdata,"dr"
78 ; CHECK: L__ehtable$main
79 ; CHECK-NEXT: .long -1
80 ; CHECK-NEXT: .long _filt$main
81 ; CHECK-NEXT: .long Ltmp{{[0-9]+}}
82
83 ; CHECK-LABEL: _filt$main:
84 ; CHECK: movl
None ; RUN: llc -mtriple=x86_64-windows-msvc < %s | FileCheck %s --check-prefix=X64
1 ; RUN: sed -e 's/__C_specific_handler/_except_handler3/' %s | \
2 ; RUN: llc -mtriple=i686-windows-msvc | FileCheck %s --check-prefix=X86
0 ; RUN: llc -mtriple=x86_64-windows-msvc < %s | FileCheck %s
31
42 @str = linkonce_odr unnamed_addr constant [27 x i8] c"GetExceptionCode(): 0x%lx\0A\00", align 1
53
3028
3129 ; Check that we can get the exception code from eax to the printf.
3230
33 ; X64-LABEL: main:
34 ; X64: callq crash
35 ; X64: retq
36 ; X64: # Block address taken
37 ; X64: leaq str(%rip), %rcx
38 ; X64: movl %eax, %edx
39 ; X64: callq printf
31 ; CHECK-LABEL: main:
32 ; CHECK: callq crash
33 ; CHECK: retq
34 ; CHECK: # Block address taken
35 ; CHECK: leaq str(%rip), %rcx
36 ; CHECK: movl %eax, %edx
37 ; CHECK: callq printf
4038
41 ; X64: .seh_handlerdata
42 ; X64-NEXT: .long 1
43 ; X64-NEXT: .long .Ltmp{{[0-9]+}}@IMGREL
44 ; X64-NEXT: .long .Ltmp{{[0-9]+}}@IMGREL+1
45 ; X64-NEXT: .long 1
46 ; X64-NEXT: .long .Ltmp{{[0-9]+}}@IMGREL
47
48 ; X86-LABEL: _main:
49 ; The EH code load should be this offset +4.
50 ; X86: movl %esp, -24(%ebp)
51 ; X86: movl $L__ehtable$main,
52 ; EH state 0
53 ; X86: movl $0, -4(%ebp)
54 ; X86: calll _crash
55 ; X86: retl
56 ; X86: # Block address taken
57 ; X86: movl -20(%ebp), %[[ptrs:[^ ,]*]]
58 ; X86: movl (%[[ptrs]]), %[[rec:[^ ,]*]]
59 ; X86: movl (%[[rec]]), %[[code:[^ ,]*]]
60 ; EH state -1
61 ; X86: movl $-1, -4(%ebp)
62 ; X86-DAG: movl %[[code]], 4(%esp)
63 ; X86-DAG: movl $_str, (%esp)
64 ; X86: calll _printf
65
66 ; X86: .section .xdata,"dr"
67 ; X86-NEXT: L__ehtable$main
68 ; X86-NEXT: .long -1
69 ; X86-NEXT: .long 0
70 ; X86-NEXT: .long Ltmp{{[0-9]+}}
39 ; CHECK: .seh_handlerdata
40 ; CHECK-NEXT: .long 1
41 ; CHECK-NEXT: .long .Ltmp{{[0-9]+}}@IMGREL
42 ; CHECK-NEXT: .long .Ltmp{{[0-9]+}}@IMGREL+1
43 ; CHECK-NEXT: .long 1
44 ; CHECK-NEXT: .long .Ltmp{{[0-9]+}}@IMGREL
8989 ; CHECK: jmp [[cont_bb]]
9090
9191 ; CHECK: .section .xdata,"dr"
92 ; CHECK-NEXT: L__ehtable$safe_div:
92 ; CHECK: L__ehtable$safe_div:
9393 ; CHECK-NEXT: .long -1
9494 ; CHECK-NEXT: .long _safe_div_filt0
9595 ; CHECK-NEXT: .long [[handler0]]