diff --git a/llvm/lib/Target/X86/X86IndirectBranchTracking.cpp b/llvm/lib/Target/X86/X86IndirectBranchTracking.cpp --- a/llvm/lib/Target/X86/X86IndirectBranchTracking.cpp +++ b/llvm/lib/Target/X86/X86IndirectBranchTracking.cpp @@ -138,17 +138,38 @@ if (MBB.hasAddressTaken()) Changed |= addENDBR(MBB, MBB.begin()); - // Exception handle may indirectly jump to catch pad, So we should add - // ENDBR before catch pad instructions. - bool EHPadIBTNeeded = MBB.isEHPad(); - for (MachineBasicBlock::iterator I = MBB.begin(); I != MBB.end(); ++I) { if (I->isCall() && IsCallReturnTwice(I->getOperand(0))) Changed |= addENDBR(MBB, std::next(I)); + } - if (EHPadIBTNeeded && I->isEHLabel()) { + // Exception handle may indirectly jump to catch pad, So we should add + // ENDBR before catch pad instructions. For SjLj exception model, it will + // create a new BB(new landingpad) indirectly jump to the old landingpad. + if (TM->Options.ExceptionModel == ExceptionHandling::SjLj) { + for (MachineBasicBlock::iterator I = MBB.begin(); I != MBB.end(); ++I) { + // New Landingpad BB without EHLabel. + if (MBB.isEHPad()) { + if (I->isDebugInstr()) + continue; + Changed |= addENDBR(MBB, I); + break; + } else if (I->isEHLabel()) { + // Old Landingpad BB (is not Landingpad now) with + // the the old "callee" EHLabel. + MCSymbol *Sym = I->getOperand(0).getMCSymbol(); + if (!MF.hasCallSiteLandingPad(Sym)) + continue; + Changed |= addENDBR(MBB, std::next(I)); + break; + } + } + } else if (MBB.isEHPad()){ + for (MachineBasicBlock::iterator I = MBB.begin(); I != MBB.end(); ++I) { + if (!I->isEHLabel()) + continue; Changed |= addENDBR(MBB, std::next(I)); - EHPadIBTNeeded = false; + break; } } } diff --git a/llvm/test/CodeGen/X86/indirect-branch-tracking-eh.ll b/llvm/test/CodeGen/X86/indirect-branch-tracking-eh.ll --- a/llvm/test/CodeGen/X86/indirect-branch-tracking-eh.ll +++ b/llvm/test/CodeGen/X86/indirect-branch-tracking-eh.ll @@ -1,15 +1,78 @@ -; RUN: llc -mtriple=x86_64-unknown-unknown < %s | FileCheck %s -; RUN: llc -mtriple=i386-unknown-unknown < %s | FileCheck %s +; RUN: llc -mtriple=x86_64-unknown-unknown < %s | FileCheck %s --check-prefix=X86_64 +; RUN: llc -mtriple=i386-unknown-unknown < %s | FileCheck %s --check-prefix=X86 +; RUN: llc -mtriple i386-windows-gnu -exception-model sjlj -verify-machineinstrs=0 < %s | FileCheck %s --check-prefix=SJLJ +; RUN: llc -mtriple i386-windows-gnu -exception-model sjlj -verify-machineinstrs=0 < %s | FileCheck %s --check-prefix=NUM + +; X86_64: test_eh: # @test_eh +; X86_64-NEXT: .Lfunc_begin0: +; X86_64: # %bb.0: # %entry +; X86_64-NEXT: endbr64 +; X86_64-NEXT: pushq %rax +; X86_64: .Ltmp0: +; X86_64-NEXT: callq _Z20function_that_throwsv +; X86_64-NEXT: .Ltmp1: +; X86_64-NEXT: # %bb.1: # %try.cont +; X86_64: retq +; X86_64-NEXT: .LBB0_2: # %lpad +; X86_64-NEXT: .cfi_def_cfa_offset 16 +; X86_64-NEXT: .Ltmp2: +; X86_64-NEXT: endbr64 +; X86_64: callq __cxa_begin_catch + + +; X86: test_eh: # @test_eh +; X86-NEXT: .Lfunc_begin0: +; X86: # %bb.0: # %entry +; X86-NEXT: endbr32 +; X86-NEXT: .Ltmp0: +; X86: calll _Z20function_that_throwsv +; X86-NEXT: .Ltmp1: +; X86-NEXT: # %bb.1: # %try.cont +; X86-NEXT: retl +; X86-NEXT: .LBB0_2: # %lpad +; X86-NEXT: .Ltmp2: +; X86-NEXT: endbr32 +; X86: calll __cxa_begin_catch + +; NUM-COUNT-3: endbr32 + +; SJLJ: test_eh: +; SJLJ-NEXT: Lfunc_begin0: +; SJLJ-NEXT: # %bb.0: # %entry +; SJLJ-NEXT: endbr32 +; SJLJ: calll __Unwind_SjLj_Register +; SJLJ: Ltmp0: +; SJLJ: calll __Z20function_that_throwsv +; SJLJ: LBB0_2: # %try.cont +; SJLJ: calll __Unwind_SjLj_Unregister +; SJLJ: retl + +; SJLJ: LBB0_3: +; SJLJ-NEXT: endbr32 +; SJLJ-NEXT: leal +; SJLJ-NEXT: movl +; SJLJ-NEXT: cmpl +; SJLJ-NEXT: jb LBB0_4 + +; SJLJ: LBB0_4: +; SJLJ-NEXT: jmpl *LJTI0_0(,%eax,4) + +; SJLJ: LBB0_6: # %lpad +; SJLJ-NEXT: Ltmp2: +; SJLJ-NEXT: endbr32 +; SJLJ: calll ___cxa_begin_catch +; SJLJ: jmp LBB0_2 +; SJLJ: LJTI0_0: +; SJLJ-NEXT: .long LBB0_6 + -;There should be 2 endbr* instruction at entry and catch pad. -;CHECK-COUNT-2: endbr declare void @_Z20function_that_throwsv() declare i32 @__gxx_personality_sj0(...) declare i8* @__cxa_begin_catch(i8*) declare void @__cxa_end_catch() -define void @test8() personality i8* bitcast (i32 (...)* @__gxx_personality_sj0 to i8*) { +define void @test_eh() personality i8* bitcast (i32 (...)* @__gxx_personality_sj0 to i8*) { entry: invoke void @_Z20function_that_throwsv() to label %try.cont unwind label %lpad diff --git a/llvm/test/CodeGen/X86/indirect-branch-tracking-eh2.ll b/llvm/test/CodeGen/X86/indirect-branch-tracking-eh2.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/X86/indirect-branch-tracking-eh2.ll @@ -0,0 +1,149 @@ +; RUN: llc -mtriple x86_64-unknown-unknown -exception-model sjlj -verify-machineinstrs=0 < %s | FileCheck %s --check-prefix=NUM +; RUN: llc -mtriple x86_64-unknown-unknown -exception-model sjlj -verify-machineinstrs=0 < %s | FileCheck %s --check-prefix=SJLJ + +; NUM-COUNT-3: endbr64 + +;SJLJ: main: # @main +;SJLJ-NEXT: .Lmain$local: +;SJLJ-NEXT: .Lfunc_begin0: +;SJLJ-NEXT: # %bb.0: # %entry +;SJLJ-NEXT: endbr64 +;SJLJ-NEXT: pushq %rbp +;SJLJ: callq _Unwind_SjLj_Register +;SJLJ-NEXT: .Ltmp0: +;SJLJ-NEXT: callq _Z3foov +;SJLJ-NEXT: .Ltmp1: +;SJLJ-NEXT: # %bb.1: # %invoke.cont +;SJLJ-NEXT: movl +;SJLJ-NEXT: .LBB0_7: # %return +;SJLJ: callq _Unwind_SjLj_Unregister +;SJLJ: retq +;SJLJ-NEXT: .LBB0_9: +;SJLJ-NEXT: endbr64 +;SJLJ-NEXT: movl +;SJLJ-NEXT: cmpl +;SJLJ-NEXT: jb .LBB0_10 +;SJLJ-NEXT: # %bb.11: +;SJLJ-NEXT: ud2 +;SJLJ-NEXT: .LBB0_10: +;SJLJ-NEXT: leaq .LJTI0_0(%rip), %rcx +;SJLJ-NEXT: jmpq *(%rcx,%rax,8) +;SJLJ-NEXT: .LBB0_2: # %lpad +;SJLJ-NEXT: .Ltmp2: +;SJLJ-NEXT: endbr64 +;SJLJ: jne .LBB0_4 +;SJLJ-NEXT: # %bb.3: # %catch3 +;SJLJ: callq __cxa_begin_catch +;SJLJ: jmp .LBB0_6 +;SJLJ-NEXT: .LBB0_4: # %catch.fallthrough +;SJLJ-NEXT: cmpl +;SJLJ-NEXT: jne .LBB0_8 +;SJLJ-NEXT: # %bb.5: # %catch +;SJLJ: callq __cxa_begin_catch +;SJLJ: cmpb +;SJLJ-NEXT: .LBB0_6: # %return +;SJLJ: callq __cxa_end_catch +;SJLJ-NEXT: jmp .LBB0_7 +;SJLJ-NEXT: .LBB0_8: # %eh.resume +;SJLJ-NEXT: movl +;SJLJ-NEXT: .Lfunc_end0: +;SJLJ: .LJTI0_0: +;SJLJ-NEXT: .quad .LBB0_2 + +@_ZTIi = external dso_local constant i8* +@_ZTIc = external dso_local constant i8* + +; Function Attrs: noinline norecurse optnone uwtable +define dso_local i32 @main() #0 personality i8* bitcast (i32 (...)* @__gxx_personality_sj0 to i8*) { +entry: + %retval = alloca i32, align 4 + %exn.slot = alloca i8* + %ehselector.slot = alloca i32 + %x = alloca i8, align 1 + %x4 = alloca i32, align 4 + store i32 0, i32* %retval, align 4 + invoke void @_Z3foov() + to label %invoke.cont unwind label %lpad + +invoke.cont: ; preds = %entry + br label %try.cont + +lpad: ; preds = %entry + %0 = landingpad { i8*, i32 } + catch i8* bitcast (i8** @_ZTIi to i8*) + catch i8* bitcast (i8** @_ZTIc to i8*) + %1 = extractvalue { i8*, i32 } %0, 0 + store i8* %1, i8** %exn.slot, align 8 + %2 = extractvalue { i8*, i32 } %0, 1 + store i32 %2, i32* %ehselector.slot, align 4 + br label %catch.dispatch + +catch.dispatch: ; preds = %lpad + %sel = load i32, i32* %ehselector.slot, align 4 + %3 = call i32 @llvm.eh.typeid.for(i8* bitcast (i8** @_ZTIi to i8*)) #3 + %matches = icmp eq i32 %sel, %3 + br i1 %matches, label %catch3, label %catch.fallthrough + +catch3: ; preds = %catch.dispatch + %exn5 = load i8*, i8** %exn.slot, align 8 + %4 = call i8* @__cxa_begin_catch(i8* %exn5) #3 + %5 = bitcast i8* %4 to i32* + %6 = load i32, i32* %5, align 4 + store i32 %6, i32* %x4, align 4 + %7 = load i32, i32* %x4, align 4 + %cmp6 = icmp ne i32 %7, 5 + %conv7 = zext i1 %cmp6 to i32 + store i32 %conv7, i32* %retval, align 4 + call void @__cxa_end_catch() #3 + br label %return + +catch.fallthrough: ; preds = %catch.dispatch + %8 = call i32 @llvm.eh.typeid.for(i8* bitcast (i8** @_ZTIc to i8*)) #3 + %matches1 = icmp eq i32 %sel, %8 + br i1 %matches1, label %catch, label %eh.resume + +catch: ; preds = %catch.fallthrough + %exn = load i8*, i8** %exn.slot, align 8 + %9 = call i8* @__cxa_begin_catch(i8* %exn) #3 + %10 = load i8, i8* %9, align 1 + store i8 %10, i8* %x, align 1 + %11 = load i8, i8* %x, align 1 + %conv = sext i8 %11 to i32 + %cmp = icmp ne i32 %conv, 3 + %conv2 = zext i1 %cmp to i32 + store i32 %conv2, i32* %retval, align 4 + call void @__cxa_end_catch() #3 + br label %return + +try.cont: ; preds = %invoke.cont + store i32 1, i32* %retval, align 4 + br label %return + +return: ; preds = %try.cont, %catch3, %catch + %12 = load i32, i32* %retval, align 4 + ret i32 %12 + +eh.resume: ; preds = %catch.fallthrough + %exn8 = load i8*, i8** %exn.slot, align 8 + %sel9 = load i32, i32* %ehselector.slot, align 4 + %lpad.val = insertvalue { i8*, i32 } undef, i8* %exn8, 0 + %lpad.val10 = insertvalue { i8*, i32 } %lpad.val, i32 %sel9, 1 + resume { i8*, i32 } %lpad.val10 +} + +declare dso_local void @_Z3foov() #1 + +declare dso_local i32 @__gxx_personality_sj0(...) + +; Function Attrs: nounwind readnone +declare i32 @llvm.eh.typeid.for(i8*) #2 + +declare dso_local i8* @__cxa_begin_catch(i8*) + +declare dso_local void @__cxa_end_catch() + +!llvm.module.flags = !{!0, !1, !2} + +!0 = !{i32 1, !"wchar_size", i32 4} +!1 = !{i32 4, !"cf-protection-return", i32 1} +!2 = !{i32 4, !"cf-protection-branch", i32 1}