diff --git a/llvm/lib/Transforms/Scalar/LoopUnrollPass.cpp b/llvm/lib/Transforms/Scalar/LoopUnrollPass.cpp index b1e06bf1e29316..18007c2bdd4223 100644 --- a/llvm/lib/Transforms/Scalar/LoopUnrollPass.cpp +++ b/llvm/lib/Transforms/Scalar/LoopUnrollPass.cpp @@ -1155,9 +1155,11 @@ tryToUnrollLoop(Loop *L, DominatorTree &DT, LoopInfo *LI, ScalarEvolution &SE, // automatic unrolling from interfering with the user requested // transformation. Loop *ParentL = L->getParentLoop(); + const bool UnrollIsForcedByUser = + hasUnrollTransformation(L) == TM_ForcedByUser; if (ParentL != nullptr && hasUnrollAndJamTransformation(ParentL) == TM_ForcedByUser && - hasUnrollTransformation(L) != TM_ForcedByUser) { + !UnrollIsForcedByUser) { LLVM_DEBUG(dbgs() << "Not unrolling loop since parent loop has" << " llvm.loop.unroll_and_jam.\n"); return LoopUnrollResult::Unmodified; @@ -1167,7 +1169,7 @@ tryToUnrollLoop(Loop *L, DominatorTree &DT, LoopInfo *LI, ScalarEvolution &SE, // loop has an explicit unroll-and-jam pragma. This is to prevent automatic // unrolling from interfering with the user requested transformation. if (hasUnrollAndJamTransformation(L) == TM_ForcedByUser && - hasUnrollTransformation(L) != TM_ForcedByUser) { + !UnrollIsForcedByUser) { LLVM_DEBUG( dbgs() << " Not unrolling loop since it has llvm.loop.unroll_and_jam.\n"); @@ -1217,7 +1219,11 @@ tryToUnrollLoop(Loop *L, DominatorTree &DT, LoopInfo *LI, ScalarEvolution &SE, if (OptForSize) UP.Threshold = std::max(UP.Threshold, LoopSize + 1); - if (UCE.NumInlineCandidates != 0) { + // Ignore the potential for inlining if unrolling is forced by the user. It's + // only _very likely_ that `NumInlineCandidates` functions will be inlined; + // things like profile data can make this significantly less likely. + if ((PrepareForLTO || !UnrollIsForcedByUser) && + UCE.NumInlineCandidates != 0) { LLVM_DEBUG(dbgs() << " Not unrolling loop with inlinable calls.\n"); return LoopUnrollResult::Unmodified; } diff --git a/llvm/test/Transforms/LoopUnroll/unroll-calls-if-forced.ll b/llvm/test/Transforms/LoopUnroll/unroll-calls-if-forced.ll new file mode 100644 index 00000000000000..00b774ea898d5c --- /dev/null +++ b/llvm/test/Transforms/LoopUnroll/unroll-calls-if-forced.ll @@ -0,0 +1,35 @@ +; RUN: opt -passes=loop-unroll -S < %s | FileCheck %s +; +; Ensure that loop unrolling occurs if the user forces it, even if there are +; calls that may be inlined. + +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" + +define internal void @foo() { + ret void +} + +; CHECK-LABEL: @forced( +; CHECK: call {{.*}}void @foo +; CHECK: call {{.*}}void @foo +define void @forced(ptr nocapture %a) { +entry: + br label %for.body + +for.body: + %indvars.iv = phi i64 [ 0, %entry ], [ %indvars.iv.next, %for.body ] + %arrayidx = getelementptr inbounds i32, ptr %a, i64 %indvars.iv + call void @foo() + %0 = load i32, ptr %arrayidx, align 4 + %inc = add nsw i32 %0, 1 + store i32 %inc, ptr %arrayidx, align 4 + %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1 + %exitcond = icmp eq i64 %indvars.iv.next, 64 + br i1 %exitcond, label %for.end, label %for.body, !llvm.loop !0 + +for.end: + ret void +} + +!0 = distinct !{!0, !{!"llvm.loop.unroll.enable"}, + !{!"llvm.loop.unroll.count", i32 2}}