diff --git a/llvm/lib/Transforms/Utils/LoopUnroll.cpp b/llvm/lib/Transforms/Utils/LoopUnroll.cpp --- a/llvm/lib/Transforms/Utils/LoopUnroll.cpp +++ b/llvm/lib/Transforms/Utils/LoopUnroll.cpp @@ -86,6 +86,19 @@ I->setOperand(op, wrap(It->second)); } + // If any of the remapped instructions were callbr... + if (isa(*I)) + for (unsigned OpNo = 0, E = I->getNumOperands(); OpNo != E; ++OpNo) + // ... whose operand was a block address ... + if (auto *BA = dyn_cast(I->getOperand(OpNo))) { + // ... that got remapped ... + ValueToValueMapTy::iterator It = VMap.find(BA->getBasicBlock()); + if (It != VMap.end()) + // ... then the operand will be incorrect and needs to be updated. + I->setOperand( + OpNo, BlockAddress::get(static_cast(&*It->second))); + } + if (PHINode *PN = dyn_cast(I)) { for (unsigned i = 0, e = PN->getNumIncomingValues(); i != e; ++i) { ValueToValueMapTy::iterator It = VMap.find(PN->getIncomingBlock(i)); @@ -537,7 +550,6 @@ // For the first iteration of the loop, we should use the precloned values for // PHI nodes. Insert associations now. - ValueToValueMapTy LastValueMap; std::vector OrigPHINode; for (BasicBlock::iterator I = Header->begin(); isa(I); ++I) { OrigPHINode.push_back(cast(I)); @@ -594,6 +606,7 @@ << DIL->getFilename() << " Line: " << DIL->getLine()); } + ValueToValueMapTy LastValueMap; for (unsigned It = 1; It != ULO.Count; ++It) { std::vector NewBlocks; SmallDenseMap NewLoops; diff --git a/llvm/test/Transforms/LoopUnroll/callbr.ll b/llvm/test/Transforms/LoopUnroll/callbr.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Transforms/LoopUnroll/callbr.ll @@ -0,0 +1,47 @@ +; RUN: opt -loop-unroll -S -o - %s 2>&1 | FileCheck %s + +; CHECK-LABEL: if.then: +; CHECK-NEXT: callbr void asm sideeffect "1: nop\0A\09.quad b, ${0:l}, $$5\0A\09", "X,~{dirflag},~{fpsr},~{flags}"(i8* blockaddress(@d, %l_yes)) +; CHECK-NEXT: to label %asm.fallthrough [label %l_yes] +; CHECK-LABEL: l_yes: + +; CHECK-LABEL: if.then.1: +; CHECK-NEXT: callbr void asm sideeffect "1: nop\0A\09.quad b, ${0:l}, $$5\0A\09", "X,~{dirflag},~{fpsr},~{flags}"(i8* blockaddress(@d, %l_yes.1)) +; CHECK-NEXT: to label %asm.fallthrough.1 [label %l_yes.1] +; CHECK-LABLE: l_yes.1: + +; CHECK-LABEL: if.then.2: +; CHECK-NEXT: callbr void asm sideeffect "1: nop\0A\09.quad b, ${0:l}, $$5\0A\09", "X,~{dirflag},~{fpsr},~{flags}"(i8* blockaddress(@d, %l_yes.2)) +; CHECK-NEXT: to label %asm.fallthrough.2 [label %l_yes.2] +; CHECK-LABEL: l_yes.2: + +define dso_local i32 @d() { +entry: + br label %for.body + +for.cond.cleanup: ; preds = %for.inc + ret i32 undef + +for.body: ; preds = %for.inc, %entry + %e.04 = phi i32 [ 0, %entry ], [ %inc, %for.inc ] + %tobool = icmp eq i32 %e.04, 0 + br i1 %tobool, label %for.inc, label %if.then + +if.then: ; preds = %for.body + callbr void asm sideeffect "1: nop\0A\09.quad b, ${0:l}, $$5\0A\09", "X,~{dirflag},~{fpsr},~{flags}"(i8* blockaddress(@d, %l_yes)) + to label %asm.fallthrough [label %l_yes] + +asm.fallthrough: ; preds = %if.then + br label %l_yes + +l_yes: ; preds = %asm.fallthrough, %if.then + %call = tail call i32 (...) @g() + br label %for.inc + +for.inc: ; preds = %for.body, %l_yes + %inc = add nuw nsw i32 %e.04, 1 + %exitcond = icmp eq i32 %inc, 3 + br i1 %exitcond, label %for.cond.cleanup, label %for.body +} + +declare dso_local i32 @g(...) local_unnamed_addr