diff --git a/llvm/lib/CodeGen/BasicBlockSections.cpp b/llvm/lib/CodeGen/BasicBlockSections.cpp --- a/llvm/lib/CodeGen/BasicBlockSections.cpp +++ b/llvm/lib/CodeGen/BasicBlockSections.cpp @@ -128,6 +128,12 @@ "into clusters of basic blocks.", false, false) +/// Basic blocks with an explicit unconditional branch to its fallthrough block +/// do not need an extra unconditional branch. +static bool hasUncoditionalBranch(const MachineBasicBlock &MBB) { + return !MBB.empty() && MBB.back().isUnconditionalBranch(); +} + // This function updates and optimizes the branching instructions of every basic // block in a given function to account for changes in the layout. static void updateBranches( @@ -144,7 +150,8 @@ // reorderd by the linker, or // 2- the fallthrough block is not adjacent to the block in the new // order. - if (FTMBB && (MBB.isEndSection() || &*NextMBBI != FTMBB)) + if (FTMBB && (MBB.isEndSection() || &*NextMBBI != FTMBB) && + !hasUncoditionalBranch(MBB)) TII->insertUnconditionalBranch(MBB, FTMBB, MBB.findBranchDebugLoc()); // We do not optimize branches for machine basic blocks ending sections, as diff --git a/llvm/test/CodeGen/X86/basic-block-sections-redundant-br.ll b/llvm/test/CodeGen/X86/basic-block-sections-redundant-br.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/X86/basic-block-sections-redundant-br.ll @@ -0,0 +1,55 @@ +; Test if basic block sections pass can skip inserting a unconditional branch when a basic block +; already has an unconditional branch to its fallthrough block. +; RUN: llc < %s -mtriple=x86_64-pc-linux -basic-block-sections=all -O0 | FileCheck %s +; This test case is generated from code: +; int +; mapping (int len) +; { +; switch (len) +; { +; case 7: return 333; +; default: +; goto unknown; +; } +; unknown: +; return 0; +; } +; clang -O0 -fbasic-block-sections=all test.c + +; Function Attrs: noinline nounwind optnone uwtable +define dso_local i32 @mapping(i32 noundef %len) { +; CHECK: mapping: +; CHECK-NEXT: .cfi_startproc +; CHECK-NEXT: # %bb.0: # %entry +; CHECK-NEXT: movl {{.*}} +; CHECK-NEXT: movl {{.*}} +; CHECK-NEXT: subl {{.*}} +; CHECK-NEXT: jne mapping.__part.2 +; CHECK-NEXT: jmp mapping.__part.1 +; CHECK-NOT: jmp +; CHECK: mapping.__part.1: +; CHECK: mapping.__part.2: +entry: + %retval = alloca i32, align 4 + %len.addr = alloca i32, align 4 + store i32 %len, ptr %len.addr, align 4 + %0 = load i32, ptr %len.addr, align 4 + switch i32 %0, label %sw.default [ + i32 7, label %sw.bb + ] + +sw.bb: ; preds = %entry + store i32 333, ptr %retval, align 4 + br label %return + +sw.default: ; preds = %entry + br label %unknown + +unknown: ; preds = %sw.default + store i32 0, ptr %retval, align 4 + br label %return + +return: ; preds = %unknown, %sw.bb + %1 = load i32, ptr %retval, align 4 + ret i32 %1 +}