diff --git a/llvm/lib/CodeGen/BranchFolding.cpp b/llvm/lib/CodeGen/BranchFolding.cpp --- a/llvm/lib/CodeGen/BranchFolding.cpp +++ b/llvm/lib/CodeGen/BranchFolding.cpp @@ -159,6 +159,7 @@ void BranchFolder::RemoveDeadBlock(MachineBasicBlock *MBB) { assert(MBB->pred_empty() && "MBB must be dead!"); LLVM_DEBUG(dbgs() << "\nRemoving MBB: " << *MBB); + assert(!MBB->hasAddressTaken() && "Someone is using this MBB"); MachineFunction *MF = MBB->getParent(); // drop all successors. @@ -1212,7 +1213,7 @@ MadeChange |= OptimizeBlock(MBB); // If it is dead, remove it. - if (MBB->pred_empty()) { + if (MBB->pred_empty() && !MBB->hasAddressTaken()) { RemoveDeadBlock(MBB); MadeChange = true; ++NumDeadBlocks; diff --git a/llvm/test/CodeGen/X86/callbr-asm-branch-folding2.ll b/llvm/test/CodeGen/X86/callbr-asm-branch-folding2.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/X86/callbr-asm-branch-folding2.ll @@ -0,0 +1,40 @@ +; RUN: llc < %s -mtriple=x86_64-unknown-linux-gnu -stop-after=branch-folder 2>&1 | FileCheck %s +@.str = private unnamed_addr constant [26 x i8] c"inline asm#1 returned %d\0A\00", align 1 +@.str.2 = private unnamed_addr constant [26 x i8] c"inline asm#2 returned %d\0A\00", align 1 +@str = private unnamed_addr constant [30 x i8] c"inline asm#1 caused exception\00", align 1 +@str.4 = private unnamed_addr constant [30 x i8] c"inline asm#2 caused exception\00", align 1 + +; Function Attrs: nounwind uwtable +define dso_local i32 @main(i32 %argc, i8** nocapture readnone %argv) { +entry: + %0 = callbr i32 asm "jmp ${1:l}", "=r,X,~{dirflag},~{fpsr},~{flags}"(i8* blockaddress(@main, %error_happened)) #3 + to label %asm.fallthrough [label %error_happened] + +asm.fallthrough: ; preds = %entry + %call = tail call i32 (i8*, ...) @printf(i8* nonnull dereferenceable(1) getelementptr inbounds ([26 x i8], [26 x i8]* @.str, i64 0, i64 0), i32 %0) + %1 = callbr i32 asm "jmp ${1:l}", "=r,X,~{dirflag},~{fpsr},~{flags}"(i8* blockaddress(@main, %if.then3)) #3 + to label %if.end5 [label %if.then3] + +if.then3: ; preds = %asm.fallthrough + %puts11 = tail call i32 @puts(i8* nonnull dereferenceable(1) getelementptr inbounds ([30 x i8], [30 x i8]* @str.4, i64 0, i64 0)) + br label %cleanup + +if.end5: ; preds = %asm.fallthrough + %call6 = tail call i32 (i8*, ...) @printf(i8* nonnull dereferenceable(1) getelementptr inbounds ([26 x i8], [26 x i8]* @.str.2, i64 0, i64 0), i32 %1) + br label %cleanup + +error_happened: ; preds = %entry + %puts = tail call i32 @puts(i8* nonnull dereferenceable(1) getelementptr inbounds ([30 x i8], [30 x i8]* @str, i64 0, i64 0)) + br label %cleanup + +cleanup: ; preds = %error_happened, %if.end5, %if.then3 + %retval.0 = phi i32 [ 1, %if.then3 ], [ 0, %if.end5 ], [ 1, %error_happened ] + ret i32 %retval.0 +} + +declare dso_local i32 @printf(i8* nocapture readonly, ...) local_unnamed_addr +declare i32 @puts(i8* nocapture readonly) local_unnamed_addr + +; This test is checking that the callbr targets don't get eliminated. +; CHECK: bb.{{.}}.error_happened (address-taken): +; CHECK: bb.{{.}}.if.then3 (address-taken): diff --git a/llvm/test/CodeGen/X86/callbr-asm-outputs.ll b/llvm/test/CodeGen/X86/callbr-asm-outputs.ll --- a/llvm/test/CodeGen/X86/callbr-asm-outputs.ll +++ b/llvm/test/CodeGen/X86/callbr-asm-outputs.ll @@ -11,7 +11,7 @@ ; CHECK-NEXT: #NO_APP ; CHECK-NEXT: .LBB0_1: ; CHECK-NEXT: retl -; CHECK-LABEL: .Ltmp0: # Address of block that was removed by CodeGen +; CHECK-LABEL: .Ltmp0: # Block address taken define i32 @test1(i32 %x) { entry: %add = add nsw i32 %x, 4 @@ -44,8 +44,14 @@ ; CHECK-NEXT: movl %esi, %eax ; CHECK-NEXT: addl %edi, %eax ; CHECK-NEXT: .Ltmp2: -; CHECK-NEXT: # %bb.5: # %return -; CHECK-LABEL: .Ltmp1: # Address of block that was removed by CodeGen +; CHECK-NEXT: .LBB1_6: # %return +; CHECK-NEXT: popl %esi +; CHECK-NEXT: .cfi_def_cfa_offset 8 +; CHECK-NEXT: popl %edi +; CHECK-NEXT: .cfi_def_cfa_offset 4 +; CHECK-NEXT: retl +; CHECK-LABEL: .Ltmp1: # Block address taken +; CHECK-NEXT: # %bb.5: # %label_true define i32 @test2(i32 %out1, i32 %out2) { entry: %cmp = icmp slt i32 %out1, %out2 @@ -91,7 +97,8 @@ ; CHECK-NEXT: .LBB2_4: ; CHECK-NEXT: movl %edx, %eax ; CHECK-NEXT: .LBB2_5: # %asm.fallthrough -; CHECK-LABEL: .Ltmp3: # Address of block that was removed by CodeGen +; CHECK-LABEL: .Ltmp3: # Block address taken + define i32 @test3(i1 %cmp) { entry: br i1 %cmp, label %true, label %false @@ -130,10 +137,13 @@ ; CHECK-NEXT: .LBB3_2: ; CHECK-NEXT: addl %edx, %ecx ; CHECK-NEXT: movl %ecx, %eax -; CHECK-NEXT: .Ltmp5: -; CHECK-NEXT: # %bb.3: # %return ; CHECK-NEXT: retl -; CHECK-LABEL: .Ltmp4: # Address of block that was removed by CodeGen +; CHECK-LABEL: .Ltmp4: # Block address taken +; CHECK-NEXT: # %bb.3: # %label_true +; CHECK-NEXT: movl $-2, %eax +; CHECK-LABEL: .Ltmp5: # Block address taken +; CHECK-NEXT: # %bb.4: # %return +; CHECK-NEXT: retl define i32 @test4(i32 %out1, i32 %out2) { entry: %0 = callbr { i32, i32 } asm sideeffect "testl $0, $0; testl $1, $2; jne ${3:l}", "=r,=r,r,X,X,~{dirflag},~{fpsr},~{flags}"(i32 %out1, i8* blockaddress(@test4, %label_true), i8* blockaddress(@test4, %return))