diff --git a/llvm/lib/Transforms/Utils/BreakCriticalEdges.cpp b/llvm/lib/Transforms/Utils/BreakCriticalEdges.cpp --- a/llvm/lib/Transforms/Utils/BreakCriticalEdges.cpp +++ b/llvm/lib/Transforms/Utils/BreakCriticalEdges.cpp @@ -150,10 +150,6 @@ // it in this generic function. if (DestBB->isEHPad()) return nullptr; - // Don't split the non-fallthrough edge from a callbr. - if (isa(TI) && SuccNum > 0) - return nullptr; - if (Options.IgnoreUnreachableDests && isa(DestBB->getFirstNonPHIOrDbgOrLifetime())) return nullptr; @@ -206,14 +202,14 @@ BranchInst *NewBI = BranchInst::Create(DestBB, NewBB); NewBI->setDebugLoc(TI->getDebugLoc()); - // Branch to the new block, breaking the edge. - TI->setSuccessor(SuccNum, NewBB); - // Insert the block into the function... right after the block TI lives in. Function &F = *TIBB->getParent(); Function::iterator FBBI = TIBB->getIterator(); F.getBasicBlockList().insert(++FBBI, NewBB); + // Branch to the new block, breaking the edge. + TI->setSuccessor(SuccNum, NewBB); + // If there are any PHI nodes in DestBB, we need to update them so that they // merge incoming values from NewBB instead of from TIBB. { diff --git a/llvm/test/Transforms/CallSiteSplitting/callsite-split-callbr.ll b/llvm/test/Transforms/CallSiteSplitting/callsite-split-callbr.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Transforms/CallSiteSplitting/callsite-split-callbr.ll @@ -0,0 +1,53 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt -callsite-splitting -S -o - < %s | FileCheck %s + +; Check that we can split the critical edge between Top and CallSiteBB, and +; rewrite the first callbr's indirect destination correctly. + +define void @caller() { +; CHECK-LABEL: @caller( +; CHECK-NEXT: Top: +; CHECK-NEXT: callbr void asm sideeffect "", "X,~{dirflag},~{fpsr},~{flags}"(i8* blockaddress(@caller, [[TOP_SPLIT:%.*]])) +; CHECK-NEXT: to label [[NEXTCOND:%.*]] [label %Top.split] +; CHECK-LABEL: Top.split: +; CHECK-NEXT: call void @callee(i1 false) +; CHECK-NEXT: br label [[CALLSITEBB:%.*]] +; CHECK-LABEL: NextCond: +; CHECK-NEXT: br label [[NEXTCOND_SPLIT:%.*]] +; CHECK-LABEL: NextCond.split: +; CHECK-NEXT: call void @callee(i1 true) +; CHECK-NEXT: br label [[CALLSITEBB]] +; CHECK-LABEL: CallSiteBB: +; CHECK-NEXT: [[PHI:%.*]] = phi i1 [ false, [[TOP_SPLIT]] ], [ true, [[NEXTCOND_SPLIT]] ] +; CHECK-NEXT: callbr void asm sideeffect "", "r,X,~{dirflag},~{fpsr},~{flags}"(i1 [[PHI]], i8* blockaddress(@caller, [[END2:%.*]])) +; CHECK-NEXT: to label [[END:%.*]] [label %End2] +; CHECK-LABEL: End: +; CHECK-NEXT: ret void +; CHECK-LABEL: End2: +; CHECK-NEXT: ret void +; +Top: + callbr void asm sideeffect "", "X,~{dirflag},~{fpsr},~{flags}"(i8* blockaddress(@caller, %CallSiteBB)) + to label %NextCond [label %CallSiteBB] + +NextCond: + br label %CallSiteBB + +CallSiteBB: + %phi = phi i1 [0, %Top],[1, %NextCond] + call void @callee(i1 %phi) + callbr void asm sideeffect "", "r,X,~{dirflag},~{fpsr},~{flags}"(i1 %phi, i8* blockaddress(@caller, %End2)) + to label %End [label %End2] + +End: + ret void +End2: + ret void +} + +define void @callee(i1 %b) { +; CHECK-LABEL: @callee( +; CHECK-NEXT: ret void +; + ret void +}