Index: llvm/trunk/lib/CodeGen/SelectionDAG/FunctionLoweringInfo.cpp =================================================================== --- llvm/trunk/lib/CodeGen/SelectionDAG/FunctionLoweringInfo.cpp +++ llvm/trunk/lib/CodeGen/SelectionDAG/FunctionLoweringInfo.cpp @@ -216,14 +216,17 @@ // 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); Index: llvm/trunk/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp =================================================================== --- llvm/trunk/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp +++ llvm/trunk/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp @@ -1160,7 +1160,35 @@ } 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 @@ 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 @@ 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(); Index: llvm/trunk/lib/CodeGen/WinEHPrepare.cpp =================================================================== --- llvm/trunk/lib/CodeGen/WinEHPrepare.cpp +++ llvm/trunk/lib/CodeGen/WinEHPrepare.cpp @@ -2612,7 +2612,7 @@ 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 @@ 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; Index: llvm/trunk/test/CodeGen/X86/funclet-layout.ll =================================================================== --- llvm/trunk/test/CodeGen/X86/funclet-layout.ll +++ llvm/trunk/test/CodeGen/X86/funclet-layout.ll @@ -93,13 +93,14 @@ ; 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 @@ ; 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 Index: llvm/trunk/test/CodeGen/X86/seh-catchpad.ll =================================================================== --- llvm/trunk/test/CodeGen/X86/seh-catchpad.ll +++ llvm/trunk/test/CodeGen/X86/seh-catchpad.ll @@ -112,7 +112,7 @@ ; 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 @@ ; 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]] Index: llvm/trunk/test/CodeGen/X86/win-catchpad-csrs.ll =================================================================== --- llvm/trunk/test/CodeGen/X86/win-catchpad-csrs.ll +++ llvm/trunk/test/CodeGen/X86/win-catchpad-csrs.ll @@ -72,7 +72,7 @@ ; 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 @@ ; 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 Index: llvm/trunk/test/CodeGen/X86/win-catchpad.ll =================================================================== --- llvm/trunk/test/CodeGen/X86/win-catchpad.ll +++ llvm/trunk/test/CodeGen/X86/win-catchpad.ll @@ -25,6 +25,7 @@ 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 @@ ; 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 @@ ; 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 @@ ; 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 @@ ; 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 @@ ; 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 Index: llvm/trunk/test/CodeGen/X86/win-funclet-cfi.ll =================================================================== --- llvm/trunk/test/CodeGen/X86/win-funclet-cfi.ll +++ llvm/trunk/test/CodeGen/X86/win-funclet-cfi.ll @@ -70,7 +70,7 @@ ; 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) Index: llvm/trunk/test/CodeGen/X86/win32-seh-catchpad.ll =================================================================== --- llvm/trunk/test/CodeGen/X86/win32-seh-catchpad.ll +++ llvm/trunk/test/CodeGen/X86/win32-seh-catchpad.ll @@ -197,6 +197,35 @@ 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