Index: llvm/lib/CodeGen/BasicBlockSections.cpp =================================================================== --- llvm/lib/CodeGen/BasicBlockSections.cpp +++ 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( @@ -141,10 +147,13 @@ // If this block had a fallthrough before we need an explicit unconditional // branch to that block if either // 1- the block ends a section, which means its next block may be - // reorderd by the linker, or + // reorderd by the linker, // 2- the fallthrough block is not adjacent to the block in the new - // order. - if (FTMBB && (MBB.isEndSection() || &*NextMBBI != FTMBB)) + // order, or + // 3- the terminator of the block is not an unconditional branch to its + // fallthrough. + 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 Index: llvm/test/CodeGen/X86/basic-block-sections-redundant-br.ll =================================================================== --- /dev/null +++ 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 +}