From 4d2c1b67133b43093a822290ca43b9ceb488c1e7 Mon Sep 17 00:00:00 2001 From: David Majnemer Date: Tue, 6 Oct 2015 23:31:59 +0000 Subject: [PATCH] [WinEH] Create a separate MBB for funclet prologues Our current emission strategy is to emit the funclet prologue in the CatchPad's normal destination. This is problematic because intra-funclet control flow to the normal destination is not erroneous and results in us reevaluating the prologue if said control flow is taken. Instead, use the CatchPad's location for the funclet prologue. This correctly models our desire to have unwind edges evaluate the prologue but edges to the normal destination result in typical control flow. Differential Revision: http://reviews.llvm.org/D13424 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@249483 91177308-0d34-0410-b5e6-96231b3b80d8 --- .../SelectionDAG/FunctionLoweringInfo.cpp | 7 +- .../SelectionDAG/SelectionDAGBuilder.cpp | 46 +++++- lib/CodeGen/WinEHPrepare.cpp | 5 +- test/CodeGen/X86/funclet-layout.ll | 21 +-- test/CodeGen/X86/seh-catchpad.ll | 6 +- test/CodeGen/X86/win-catchpad-csrs.ll | 4 +- test/CodeGen/X86/win-catchpad.ll | 152 +++++++++++++++++- test/CodeGen/X86/win-funclet-cfi.ll | 2 +- test/CodeGen/X86/win32-seh-catchpad.ll | 29 ++++ 9 files changed, 241 insertions(+), 31 deletions(-) diff --git a/lib/CodeGen/SelectionDAG/FunctionLoweringInfo.cpp b/lib/CodeGen/SelectionDAG/FunctionLoweringInfo.cpp index d718ede35cd..a7f5ba1269e 100644 --- a/lib/CodeGen/SelectionDAG/FunctionLoweringInfo.cpp +++ b/lib/CodeGen/SelectionDAG/FunctionLoweringInfo.cpp @@ -216,14 +216,17 @@ void FunctionLoweringInfo::set(const Function &fn, MachineFunction &mf, // are really data, and no instructions can live here. if (BB->isEHPad()) { const Instruction *I = BB->getFirstNonPHI(); + // FIXME: Don't mark SEH functions without __finally blocks as having + // funclets. if (!isa(I)) MMI.setHasEHFunclets(true); - if (isa(I) || isa(I) || - isa(I)) { + if (isa(I) || isa(I)) { assert(&*BB->begin() == I && "WinEHPrepare failed to remove PHIs from imaginary BBs"); continue; } + if (isa(I) || isa(I)) + assert(&*BB->begin() == I && "WinEHPrepare failed to demote PHIs"); } MachineBasicBlock *MBB = mf.CreateMachineBasicBlock(BB); diff --git a/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp b/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp index fc140f65571..22809aa0b3e 100644 --- a/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp +++ b/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp @@ -1160,7 +1160,35 @@ SDValue SelectionDAGBuilder::getValueImpl(const Value *V) { } void SelectionDAGBuilder::visitCatchPad(const CatchPadInst &I) { - llvm_unreachable("should never codegen catchpads"); + auto Pers = classifyEHPersonality(FuncInfo.Fn->getPersonalityFn()); + bool IsMSVCCXX = Pers == EHPersonality::MSVC_CXX; + bool IsSEH = isAsynchronousEHPersonality(Pers); + MachineBasicBlock *CatchPadMBB = FuncInfo.MBB; + // In MSVC C++, catchblocks are funclets and need prologues. + if (IsMSVCCXX) + CatchPadMBB->setIsEHFuncletEntry(); + + MachineBasicBlock *NormalDestMBB = FuncInfo.MBBMap[I.getNormalDest()]; + + // Update machine-CFG edge. + FuncInfo.MBB->addSuccessor(NormalDestMBB); + + // CatchPads in SEH are not funclets, they are merely markers which indicate + // where to insert register restoration code. + if (IsSEH) { + DAG.setRoot(DAG.getNode(ISD::CATCHRET, getCurSDLoc(), MVT::Other, + getControlRoot(), DAG.getBasicBlock(NormalDestMBB), + DAG.getBasicBlock(FuncInfo.MF->begin()))); + return; + } + + // If this is not a fall-through branch or optimizations are switched off, + // emit the branch. + if (NormalDestMBB != NextBlock(CatchPadMBB) || + TM.getOptLevel() == CodeGenOpt::None) + DAG.setRoot(DAG.getNode(ISD::BR, getCurSDLoc(), MVT::Other, + getControlRoot(), + DAG.getBasicBlock(NormalDestMBB))); } void SelectionDAGBuilder::visitCatchRet(const CatchReturnInst &I) { @@ -1168,6 +1196,18 @@ void SelectionDAGBuilder::visitCatchRet(const CatchReturnInst &I) { MachineBasicBlock *TargetMBB = FuncInfo.MBBMap[I.getSuccessor()]; FuncInfo.MBB->addSuccessor(TargetMBB); + auto Pers = classifyEHPersonality(FuncInfo.Fn->getPersonalityFn()); + bool IsSEH = isAsynchronousEHPersonality(Pers); + if (IsSEH) { + // If this is not a fall-through branch or optimizations are switched off, + // emit the branch. + if (TargetMBB != NextBlock(FuncInfo.MBB) || + TM.getOptLevel() == CodeGenOpt::None) + DAG.setRoot(DAG.getNode(ISD::BR, getCurSDLoc(), MVT::Other, + getControlRoot(), DAG.getBasicBlock(TargetMBB))); + return; + } + // Figure out the funclet membership for the catchret's successor. // This will be used by the FuncletLayout pass to determine how to order the // BB's. @@ -1225,8 +1265,8 @@ findUnwindDestinations(FunctionLoweringInfo &FuncInfo, break; } else if (const auto *CPI = dyn_cast(Pad)) { // Add the catchpad handler to the possible destinations. - UnwindDests.push_back(FuncInfo.MBBMap[CPI->getNormalDest()]); - // In MSVC C++ and CoreCLR, catchblocks are funclets and need prologues. + UnwindDests.push_back(FuncInfo.MBBMap[EHPadBB]); + // In MSVC C++, catchblocks are funclets and need prologues. if (IsMSVCCXX || IsCoreCLR) UnwindDests.back()->setIsEHFuncletEntry(); EHPadBB = CPI->getUnwindDest(); diff --git a/lib/CodeGen/WinEHPrepare.cpp b/lib/CodeGen/WinEHPrepare.cpp index cd813e6f9bc..a9fec812071 100644 --- a/lib/CodeGen/WinEHPrepare.cpp +++ b/lib/CodeGen/WinEHPrepare.cpp @@ -2612,7 +2612,7 @@ static void addTryBlockMapEntry(WinEHFuncInfo &FuncInfo, int TryLow, else HT.TypeDescriptor = cast(TypeInfo->stripPointerCasts()); HT.Adjectives = cast(CPI->getArgOperand(1))->getZExtValue(); - HT.Handler = CPI->getNormalDest(); + HT.Handler = CPI->getParent(); HT.CatchObjRecoverIdx = -2; if (isa(CPI->getArgOperand(2))) HT.CatchObj.Alloca = nullptr; @@ -2770,8 +2770,7 @@ static void calculateExplicitSEHStateNumbers(WinEHFuncInfo &FuncInfo, const Function *Filter = dyn_cast(FilterOrNull); assert((Filter || FilterOrNull->isNullValue()) && "unexpected filter value"); - int TryState = - addSEHExcept(FuncInfo, ParentState, Filter, CPI->getNormalDest()); + int TryState = addSEHExcept(FuncInfo, ParentState, Filter, CatchPadBB); // Everything in the __try block uses TryState as its parent state. FuncInfo.EHPadStateMap[CPI] = TryState; diff --git a/test/CodeGen/X86/funclet-layout.ll b/test/CodeGen/X86/funclet-layout.ll index ffd4b49b688..053d484889b 100644 --- a/test/CodeGen/X86/funclet-layout.ll +++ b/test/CodeGen/X86/funclet-layout.ll @@ -93,13 +93,14 @@ unreachable: ; preds = %catch, %entry ; CHECK: # %try.cont.5 ; CHECK: retq -; The inner catch funclet contains %catch.3 -; CHECK: # %catch.3 -; CHECK: retq +; The outer catch funclet contains %catch.dispatch +; CHECK: # %catch.dispatch{{$}} +; CHECK: callq _CxxThrowException +; CHECK: # %unreachable +; CHECK: ud2 -; The outer catch funclet contains %catch and %try.cont -; CHECK: # %catch{{$}} -; CHECK: # %try.cont{{$}} +; The inner catch funclet contains %catch.dispatch.1 +; CHECK: # %catch.dispatch.1 ; CHECK: retq @@ -149,13 +150,13 @@ exit_two: ; CHECK-NOT: # exit_two ; CHECK: ud2 -; The catch(int) funclet contains %catch.2 -; CHECK: # %catch.2 +; The catch(...) funclet contains %catch.dispatch +; CHECK: # %catch.dispatch{{$}} ; CHECK: callq exit ; CHECK: ud2 -; The catch(...) funclet contains %catch -; CHECK: # %catch{{$}} +; The catch(int) funclet contains %catch.dispatch.1 +; CHECK: # %catch.dispatch.1 ; CHECK: callq exit ; CHECK: ud2 diff --git a/test/CodeGen/X86/seh-catchpad.ll b/test/CodeGen/X86/seh-catchpad.ll index e70ea793c79..fc8e721c63d 100644 --- a/test/CodeGen/X86/seh-catchpad.ll +++ b/test/CodeGen/X86/seh-catchpad.ll @@ -112,7 +112,7 @@ ehcleanup.end: ; preds = %ehcleanup ; CHECK: addq $48, %rsp ; CHECK: popq %rbp ; CHECK: retq -; CHECK: .LBB1_[[except1bb:[0-9]+]]: # %__except +; CHECK: .LBB1_[[except1bb:[0-9]+]]: # %catch.dispatch ; CHECK: .Ltmp2: ; CHECK: movl $1, %ecx ; CHECK: xorl %edx, %edx @@ -120,7 +120,9 @@ ehcleanup.end: ; preds = %ehcleanup ; CHECK: .Ltmp3: ; CHECK: callq "?fin$0@0@main@@" ; CHECK: jmp .LBB1_[[epilogue]] -; CHECK: .LBB1_[[except2bb:[0-9]+]]: # %__except.ret +; CHECK: .LBB1_[[except2bb:[0-9]+]]: # %catch.dispatch.7 +; CHECK: jmp .LBB1_7 +; CHECK: # %__except.9 ; CHECK: leaq "??_C@_06IBDBCMGJ@caught?$AA@"(%rip), %rcx ; CHECK: callq puts ; CHECK: jmp .LBB1_[[epilogue]] diff --git a/test/CodeGen/X86/win-catchpad-csrs.ll b/test/CodeGen/X86/win-catchpad-csrs.ll index b9f99e61669..05a59ac9b62 100644 --- a/test/CodeGen/X86/win-catchpad-csrs.ll +++ b/test/CodeGen/X86/win-catchpad-csrs.ll @@ -72,7 +72,7 @@ catchendblock: ; preds = %catch, ; X86: jmp [[contbb]] ; X86: "?catch$[[catch1bb:[0-9]+]]@?0?try_catch_catch@4HA": -; X86: LBB0_[[catch1bb]]: # %catch{{$}} +; X86: LBB0_[[catch1bb]]: # %catch.dispatch{{$}} ; X86: pushl %ebp ; X86-NOT: pushl ; X86: subl $16, %esp @@ -119,7 +119,7 @@ catchendblock: ; preds = %catch, ; X64: retq ; X64: "?catch$[[catch1bb:[0-9]+]]@?0?try_catch_catch@4HA": -; X64: LBB0_[[catch1bb]]: # %catch{{$}} +; X64: LBB0_[[catch1bb]]: # %catch.dispatch{{$}} ; X64: movq %rdx, 16(%rsp) ; X64: pushq %rbp ; X64: .seh_pushreg 5 diff --git a/test/CodeGen/X86/win-catchpad.ll b/test/CodeGen/X86/win-catchpad.ll index 2c05fbe22f1..45d1085f3ad 100644 --- a/test/CodeGen/X86/win-catchpad.ll +++ b/test/CodeGen/X86/win-catchpad.ll @@ -25,6 +25,7 @@ $"\01??_R0H@8" = comdat any declare void @f(i32 %p, i32* %l) +declare i1 @getbool() declare i32 @__CxxFrameHandler3(...) define i32 @try_catch_catch() personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) { @@ -74,24 +75,24 @@ catchendblock: ; preds = %catch, %catch.2, %c ; X86: retl ; FIXME: These should be de-duplicated. -; X86: [[restorebb1:LBB0_[0-9]+]]: # %invoke.cont.2 +; X86: [[restorebb2:LBB0_[0-9]+]]: # %invoke.cont.3 ; X86: movl -16(%ebp), %esp ; X86: addl $12, %ebp ; X86: jmp [[contbb]] -; X86: [[restorebb2:LBB0_[0-9]+]]: # %invoke.cont.3 +; X86: [[restorebb1:LBB0_[0-9]+]]: # %invoke.cont.2 ; X86: movl -16(%ebp), %esp ; X86: addl $12, %ebp ; X86: jmp [[contbb]] ; X86: "?catch$[[catch1bb:[0-9]+]]@?0?try_catch_catch@4HA": -; X86: LBB0_[[catch1bb]]: # %catch{{$}} +; X86: LBB0_[[catch1bb]]: # %catch.dispatch{{$}} ; X86: pushl %ebp ; X86: subl $8, %esp ; X86: addl $12, %ebp +; X86: leal -[[local_offs]](%ebp), %[[addr_reg:[a-z]+]] ; X86: movl -32(%ebp), %[[e_reg:[a-z]+]] ; X86: movl $1, -{{[0-9]+}}(%ebp) -; X86: leal -[[local_offs]](%ebp), %[[addr_reg:[a-z]+]] ; X86-DAG: movl %[[addr_reg]], 4(%esp) ; X86-DAG: movl %[[e_reg]], (%esp) ; X86: calll _f @@ -101,12 +102,12 @@ catchendblock: ; preds = %catch, %catch.2, %c ; X86-NEXT: retl ; X86: "?catch$[[catch2bb:[0-9]+]]@?0?try_catch_catch@4HA": -; X86: LBB0_[[catch2bb]]: # %catch.2{{$}} +; X86: LBB0_[[catch2bb]]: # %catch.dispatch.2{{$}} ; X86: pushl %ebp ; X86: subl $8, %esp ; X86: addl $12, %ebp -; X86: movl $1, -{{[0-9]+}}(%ebp) ; X86: leal -[[local_offs]](%ebp), %[[addr_reg:[a-z]+]] +; X86: movl $1, -{{[0-9]+}}(%ebp) ; X86-DAG: movl %[[addr_reg]], 4(%esp) ; X86-DAG: movl $3, (%esp) ; X86: calll _f @@ -145,7 +146,7 @@ catchendblock: ; preds = %catch, %catch.2, %c ; X64: retq ; X64: "?catch$[[catch1bb:[0-9]+]]@?0?try_catch_catch@4HA": -; X64: LBB0_[[catch1bb]]: # %catch{{$}} +; X64: LBB0_[[catch1bb]]: # %catch.dispatch{{$}} ; X64: movq %rdx, 16(%rsp) ; X64: pushq %rbp ; X64: .seh_pushreg 5 @@ -163,7 +164,7 @@ catchendblock: ; preds = %catch, %catch.2, %c ; X64-NEXT: retq ; X64: "?catch$[[catch2bb:[0-9]+]]@?0?try_catch_catch@4HA": -; X64: LBB0_[[catch2bb]]: # %catch.2{{$}} +; X64: LBB0_[[catch2bb]]: # %catch.dispatch.2{{$}} ; X64: movq %rdx, 16(%rsp) ; X64: pushq %rbp ; X64: .seh_pushreg 5 @@ -221,3 +222,138 @@ catchendblock: ; preds = %catch, %catch.2, %c ; X64-NEXT: .long 1 ; X64-NEXT: .long .Ltmp3@IMGREL+1 ; X64-NEXT: .long -1 + + +define i32 @branch_to_normal_dest() personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) { +entry: + invoke void @f(i32 1, i32* null) + to label %try.cont unwind label %catch.dispatch + +catch.dispatch: + %0 = catchpad [i8* null, i32 64, i8* null] + to label %catch unwind label %catchendblock + +catch: + %V = call i1 @getbool() + br i1 %V, label %catch, label %catch.done + +catch.done: + catchret %0 to label %try.cont + +try.cont: + ret i32 0 + +catchendblock: + catchendpad unwind to caller +} + +; X86-LABEL: _branch_to_normal_dest: +; X86: calll _f + +; X86: [[contbb:LBB1_[0-9]+]]: # %try.cont +; X86: retl + +; X86: [[restorebb:LBB1_[0-9]+]]: # %catch.done +; X86: movl -16(%ebp), %esp +; X86: addl $12, %ebp +; X86: jmp [[contbb]] + +; X86: "?catch$[[catchdispbb:[0-9]+]]@?0?branch_to_normal_dest@4HA": +; X86: LBB1_[[catchdispbb]]: # %catch.dispatch{{$}} +; X86: pushl %ebp +; X86: subl $8, %esp +; X86: addl $12, %ebp + +; X86: LBB1_[[catchbb:[0-9]+]]: # %catch +; X86: movl $-1, -16(%ebp) +; X86: calll _getbool +; X86: testb $1, %al +; X86: jne LBB1_[[catchbb]] +; X86: # %catch.done +; X86-NEXT: movl $[[restorebb]], %eax +; X86-NEXT: addl $8, %esp +; X86-NEXT: popl %ebp +; X86-NEXT: retl + +; X86: L__ehtable$branch_to_normal_dest: +; X86: $handlerMap$0$branch_to_normal_dest: +; X86-NEXT: .long 64 +; X86-NEXT: .long 0 +; X86-NEXT: .long 0 +; X86-NEXT: .long "?catch$[[catchdispbb]]@?0?branch_to_normal_dest@4HA" + +; X64-LABEL: branch_to_normal_dest: +; X64: # %entry +; X64: pushq %rbp +; X64: .seh_pushreg 5 +; X64: subq $48, %rsp +; X64: .seh_stackalloc 48 +; X64: leaq 48(%rsp), %rbp +; X64: .seh_setframe 5, 48 +; X64: .seh_endprologue +; X64: .Ltmp[[before_call:[0-9]+]]: +; X64: callq f +; X64: .Ltmp[[after_call:[0-9]+]]: +; X64: [[contbb:\.LBB1_[0-9]+]]: # %try.cont +; X64: addq $48, %rsp +; X64: popq %rbp +; X64: retq + +; X64: "?catch$[[catchbb:[0-9]+]]@?0?branch_to_normal_dest@4HA": +; X64: LBB1_[[catchbb]]: # %catch.dispatch{{$}} +; X64: movq %rdx, 16(%rsp) +; X64: pushq %rbp +; X64: .seh_pushreg 5 +; X64: subq $32, %rsp +; X64: .seh_stackalloc 32 +; X64: leaq 48(%rdx), %rbp +; X64: .seh_endprologue +; X64: .LBB1_[[normal_dest_bb:[0-9]+]]: # %catch +; X64: callq getbool +; X64: testb $1, %al +; X64: jne .LBB1_[[normal_dest_bb]] +; X64: # %catch.done +; X64: leaq [[contbb]](%rip), %rax +; X64-NEXT: addq $32, %rsp +; X64-NEXT: popq %rbp +; X64-NEXT: retq + +; X64-LABEL: $cppxdata$branch_to_normal_dest: +; X64-NEXT: .long 429065506 +; X64-NEXT: .long 2 +; X64-NEXT: .long ($stateUnwindMap$branch_to_normal_dest)@IMGREL +; X64-NEXT: .long 1 +; X64-NEXT: .long ($tryMap$branch_to_normal_dest)@IMGREL +; X64-NEXT: .long 3 +; X64-NEXT: .long ($ip2state$branch_to_normal_dest)@IMGREL +; X64-NEXT: .long 40 +; X64-NEXT: .long 0 +; X64-NEXT: .long 1 + +; X64-LABEL: $stateUnwindMap$branch_to_normal_dest: +; X64-NEXT: .long -1 +; X64-NEXT: .long 0 +; X64-NEXT: .long -1 +; X64-NEXT: .long 0 + +; X64-LABEL: $tryMap$branch_to_normal_dest: +; X64-NEXT: .long 0 +; X64-NEXT: .long 0 +; X64-NEXT: .long 1 +; X64-NEXT: .long 1 +; X64-NEXT: .long ($handlerMap$0$branch_to_normal_dest)@IMGREL + +; X64-LABEL: $handlerMap$0$branch_to_normal_dest: +; X64-NEXT: .long 64 +; X64-NEXT: .long 0 +; X64-NEXT: .long 0 +; X64-NEXT: .long "?catch$[[catchbb]]@?0?branch_to_normal_dest@4HA"@IMGREL +; X64-NEXT: .long 56 + +; X64-LABEL: $ip2state$branch_to_normal_dest: +; X64-NEXT: .long .Lfunc_begin1@IMGREL +; X64-NEXT: .long -1 +; X64-NEXT: .long .Ltmp[[before_call]]@IMGREL +; X64-NEXT: .long 0 +; X64-NEXT: .long .Ltmp[[after_call]]@IMGREL+1 +; X64-NEXT: .long -1 diff --git a/test/CodeGen/X86/win-funclet-cfi.ll b/test/CodeGen/X86/win-funclet-cfi.ll index 63be4f26afa..52589ee1918 100644 --- a/test/CodeGen/X86/win-funclet-cfi.ll +++ b/test/CodeGen/X86/win-funclet-cfi.ll @@ -70,7 +70,7 @@ declare i32 @__CxxFrameHandler3(...) ; CHECK: "?catch$[[catch:[0-9]+]]@?0??f@@YAXXZ@4HA": ; CHECK: .seh_proc "?catch$[[catch]]@?0??f@@YAXXZ@4HA" ; CHECK-NEXT: .seh_handler __CxxFrameHandler3, @unwind, @except -; CHECK: LBB0_[[catch]]: # %catch{{$}} +; CHECK: LBB0_[[catch]]: # %catch.dispatch{{$}} ; Emit CFI for pushing RBP. ; CHECK: movq %rdx, 16(%rsp) diff --git a/test/CodeGen/X86/win32-seh-catchpad.ll b/test/CodeGen/X86/win32-seh-catchpad.ll index 1d635dc5711..dd14f2df689 100644 --- a/test/CodeGen/X86/win32-seh-catchpad.ll +++ b/test/CodeGen/X86/win32-seh-catchpad.ll @@ -197,6 +197,35 @@ entry: ret i32 1 } +define void @code_in_catchpad() #0 personality i8* bitcast (i32 (...)* @_except_handler3 to i8*) { +entry: + invoke void @f(i32 1) #3 + to label %__except unwind label %catch.dispatch + +catch.dispatch: ; preds = %entry + %0 = catchpad [i8* bitcast (i32 ()* @try_except_filter_catchall to i8*)] to label %__except.ret unwind label %catchendblock + +__except.ret: ; preds = %catch.dispatch + call void @f(i32 2) + catchret %0 to label %__except + +__except: + ret void + +catchendblock: ; preds = %catch.dispatch + catchendpad unwind to caller +} + +; CHECK-LABEL: _code_in_catchpad: +; CHECK: # %catch.dispatch +; CHECK-NEXT: movl -24(%ebp), %esp +; CHECK-NEXT: addl $12, %ebp +; CHECK: # %__except.ret +; CHECK-NEXT: movl $-1, -16(%ebp) +; CHECK-NEXT: movl $2, (%esp) +; CHECK-NEXT: calll _f + + ; Function Attrs: nounwind readnone declare i8* @llvm.frameaddress(i32) #1 -- 2.34.1