// 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<LandingPadInst>(I))
MMI.setHasEHFunclets(true);
- if (isa<CatchPadInst>(I) || isa<CatchEndPadInst>(I) ||
- isa<CleanupEndPadInst>(I)) {
+ if (isa<CatchEndPadInst>(I) || isa<CleanupEndPadInst>(I)) {
assert(&*BB->begin() == I &&
"WinEHPrepare failed to remove PHIs from imaginary BBs");
continue;
}
+ if (isa<CatchPadInst>(I) || isa<CleanupPadInst>(I))
+ assert(&*BB->begin() == I && "WinEHPrepare failed to demote PHIs");
}
MachineBasicBlock *MBB = mf.CreateMachineBasicBlock(BB);
}
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) {
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.
break;
} else if (const auto *CPI = dyn_cast<CatchPadInst>(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();
else
HT.TypeDescriptor = cast<GlobalVariable>(TypeInfo->stripPointerCasts());
HT.Adjectives = cast<ConstantInt>(CPI->getArgOperand(1))->getZExtValue();
- HT.Handler = CPI->getNormalDest();
+ HT.Handler = CPI->getParent();
HT.CatchObjRecoverIdx = -2;
if (isa<ConstantPointerNull>(CPI->getArgOperand(2)))
HT.CatchObj.Alloca = nullptr;
const Function *Filter = dyn_cast<Function>(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;
; 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
; 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
; 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
; 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]]
; 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
; 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
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*) {
; 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
; 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
; 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
; 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
; 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
; 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)
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