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 @@ -65,8 +65,20 @@ /// Convert the instruction operands from referencing the current values into /// those specified by VMap. void llvm::remapInstruction(Instruction *I, ValueToValueMapTy &VMap) { - for (unsigned op = 0, E = I->getNumOperands(); op != E; ++op) { - Value *Op = I->getOperand(op); + for (unsigned OpNo = 0, E = I->getNumOperands(); OpNo != E; ++OpNo) { + Value *Op = I->getOperand(OpNo); + + // If we have a BlockAddress operand where the BasicBlock of the + // BlockAddress was remapped and the BlockAddress is the operand of a + // CallBrInst, then we need to update the CallBrInst's operand to be a + // BlockAddress of the remapped BasicBlock, not the original BasicBlock. + if (auto *BA = dyn_cast(Op)) { + ValueToValueMapTy::iterator It = VMap.find(BA->getBasicBlock()); + if (It != VMap.end() && isa(*I)) { + I->setOperand(OpNo, BlockAddress::get(cast(It->second))); + continue; + } + } // Unwrap arguments of dbg.value intrinsics. bool Wrapped = false; @@ -83,7 +95,7 @@ ValueToValueMapTy::iterator It = VMap.find(Op); if (It != VMap.end()) - I->setOperand(op, wrap(It->second)); + I->setOperand(OpNo, wrap(It->second)); } if (PHINode *PN = dyn_cast(I)) { @@ -537,7 +549,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 +605,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 | 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 void @d() { +entry: + br label %for.body + +for.cond.cleanup: ; preds = %for.inc + ret void + +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