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 @@ -134,6 +134,14 @@ "into clusters of basic blocks.", false, false) +// Returns whether the given basic block has an unconditional branch. +bool hasUnconditionalBranch(const MachineBasicBlock &MBB) { + if (MBB.terminators().empty()) + return false; + const MachineInstr &Terminator = *(--MBB.terminators().end()); + return Terminator.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 @@ -145,12 +153,14 @@ auto NextMBBI = std::next(MBB.getIterator()); auto *FTMBB = PreLayoutFallThroughs[MBB.getNumber()]; // If this block had a fallthrough before we need an explicit unconditional - // branch to that block if either + // branch to that block if either one of these two conditions hold and the + // block doesn't currently have an unconditional branch. // 1- the block ends a section, which means its next block may be // 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) && + !hasUnconditionalBranch(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-avoids-redundant-br.ll b/llvm/test/CodeGen/X86/basic-block-sections-avoids-redundant-br.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/X86/basic-block-sections-avoids-redundant-br.ll @@ -0,0 +1,56 @@ +; Tests that basic block sections avoids inserting an unconditional branch when a basic block +; already has an unconditional branch to its fallthrough block. +; RUN: llc < %s -mtriple=x86_64 -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) { +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 +} + +; 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: