diff options
| author | Joel E. Denny <jdenny.ornl@gmail.com> | 2025-10-29 20:43:32 -0400 |
|---|---|---|
| committer | Joel E. Denny <jdenny.ornl@gmail.com> | 2025-10-29 20:43:32 -0400 |
| commit | 705d54e557e1c42218835e4595f72b07e938cb88 (patch) | |
| tree | f776183a0ed31e32ed17758a34c45734671f17a3 | |
| parent | a4ffa1f3d53c8d0ae7141da3c508ec1c549f7ddc (diff) | |
[LoopUnroll] Do not copy !llvm.loop from latch to non-latchusers/jdenny-ornl/unroll-dont-copy-latch-loop-id
When LoopUnroll copies the original loop's latch to the corresponding
non-latch branch in an unrolled iteration, any `!llvm.loop` is copied
along with it, but `!llvm.loop` is useless and misleading there. This
patch discards it.
e06831a3b29d did the same for LoopPeel.
6 files changed, 115 insertions, 23 deletions
diff --git a/llvm/lib/Transforms/Utils/LoopUnroll.cpp b/llvm/lib/Transforms/Utils/LoopUnroll.cpp index 4fe736ac29b0..8bbc857715d2 100644 --- a/llvm/lib/Transforms/Utils/LoopUnroll.cpp +++ b/llvm/lib/Transforms/Utils/LoopUnroll.cpp @@ -919,6 +919,12 @@ llvm::UnrollLoop(Loop *L, UnrollLoopOptions ULO, LoopInfo *LI, Latches[i]->getTerminator()->replaceSuccessorWith(Headers[i], Headers[j]); } + // Remove loop metadata copied from the original loop latch to branches that + // are no longer latches. + for (unsigned I = 0, E = Latches.size() - (CompletelyUnroll ? 0 : 1); I < E; + ++I) + Latches[I]->getTerminator()->setMetadata(LLVMContext::MD_loop, nullptr); + // Update dominators of blocks we might reach through exits. // Immediate dominator of such block might change, because we add more // routes which can lead to the exit: we can now reach it from the copied diff --git a/llvm/test/Transforms/LoopUnroll/convergent.controlled.ll b/llvm/test/Transforms/LoopUnroll/convergent.controlled.ll index 6e600d2a659d..5dc613e733f0 100644 --- a/llvm/test/Transforms/LoopUnroll/convergent.controlled.ll +++ b/llvm/test/Transforms/LoopUnroll/convergent.controlled.ll @@ -491,41 +491,41 @@ define i32 @unroll_nest(i32 %n, i1 %cond) { ; CHECK-NEXT: entry: ; CHECK-NEXT: br label [[L3:%.*]] ; CHECK: l3: -; CHECK-NEXT: br label [[L2:%.*]], !llvm.loop [[LOOP4]] +; CHECK-NEXT: br label [[L2:%.*]] ; CHECK: l2: ; CHECK-NEXT: [[TOK_L2:%.*]] = call token @llvm.experimental.convergence.anchor() ; CHECK-NEXT: call void @f() [ "convergencectrl"(token [[TOK_L2]]) ] -; CHECK-NEXT: br i1 [[COND:%.*]], label [[L2_1:%.*]], label [[LATCH:%.*]], !llvm.loop [[LOOP4]] +; CHECK-NEXT: br i1 [[COND:%.*]], label [[L2_1:%.*]], label [[LATCH:%.*]] ; CHECK: l2.1: ; CHECK-NEXT: [[TOK_L2_1:%.*]] = call token @llvm.experimental.convergence.anchor() ; CHECK-NEXT: call void @f() [ "convergencectrl"(token [[TOK_L2_1]]) ] ; CHECK-NEXT: br i1 [[COND]], label [[L2]], label [[LATCH]], !llvm.loop [[LOOP9:![0-9]+]] ; CHECK: latch: -; CHECK-NEXT: br label [[L2_12:%.*]], !llvm.loop [[LOOP4]] +; CHECK-NEXT: br label [[L2_12:%.*]] ; CHECK: l2.12: ; CHECK-NEXT: [[TOK_L2_11:%.*]] = call token @llvm.experimental.convergence.anchor() ; CHECK-NEXT: call void @f() [ "convergencectrl"(token [[TOK_L2_11]]) ] -; CHECK-NEXT: br i1 [[COND]], label [[L2_1_1:%.*]], label [[LATCH_1:%.*]], !llvm.loop [[LOOP4]] +; CHECK-NEXT: br i1 [[COND]], label [[L2_1_1:%.*]], label [[LATCH_1:%.*]] ; CHECK: l2.1.1: ; CHECK-NEXT: [[TOK_L2_1_1:%.*]] = call token @llvm.experimental.convergence.anchor() ; CHECK-NEXT: call void @f() [ "convergencectrl"(token [[TOK_L2_1_1]]) ] ; CHECK-NEXT: br i1 [[COND]], label [[L2_12]], label [[LATCH_1]], !llvm.loop [[LOOP9]] ; CHECK: latch.1: -; CHECK-NEXT: br label [[L2_2:%.*]], !llvm.loop [[LOOP4]] +; CHECK-NEXT: br label [[L2_2:%.*]] ; CHECK: l2.2: ; CHECK-NEXT: [[TOK_L2_2:%.*]] = call token @llvm.experimental.convergence.anchor() ; CHECK-NEXT: call void @f() [ "convergencectrl"(token [[TOK_L2_2]]) ] -; CHECK-NEXT: br i1 [[COND]], label [[L2_1_2:%.*]], label [[LATCH_2:%.*]], !llvm.loop [[LOOP4]] +; CHECK-NEXT: br i1 [[COND]], label [[L2_1_2:%.*]], label [[LATCH_2:%.*]] ; CHECK: l2.1.2: ; CHECK-NEXT: [[TOK_L2_1_2:%.*]] = call token @llvm.experimental.convergence.anchor() ; CHECK-NEXT: call void @f() [ "convergencectrl"(token [[TOK_L2_1_2]]) ] ; CHECK-NEXT: br i1 [[COND]], label [[L2_2]], label [[LATCH_2]], !llvm.loop [[LOOP9]] ; CHECK: latch.2: -; CHECK-NEXT: br label [[L2_3:%.*]], !llvm.loop [[LOOP4]] +; CHECK-NEXT: br label [[L2_3:%.*]] ; CHECK: l2.3: ; CHECK-NEXT: [[TOK_L2_3:%.*]] = call token @llvm.experimental.convergence.anchor() ; CHECK-NEXT: call void @f() [ "convergencectrl"(token [[TOK_L2_3]]) ] -; CHECK-NEXT: br i1 [[COND]], label [[L2_1_3:%.*]], label [[LATCH_3:%.*]], !llvm.loop [[LOOP4]] +; CHECK-NEXT: br i1 [[COND]], label [[L2_1_3:%.*]], label [[LATCH_3:%.*]] ; CHECK: l2.1.3: ; CHECK-NEXT: [[TOK_L2_1_3:%.*]] = call token @llvm.experimental.convergence.anchor() ; CHECK-NEXT: call void @f() [ "convergencectrl"(token [[TOK_L2_1_3]]) ] @@ -541,7 +541,7 @@ l3: %tok.loop = call token @llvm.experimental.convergence.anchor() %inc = add nsw i32 %x.0, 1 %exitcond = icmp eq i32 %inc, 4 - br label %l2, !llvm.loop !1 + br label %l2 l2: %tok.l2 = call token @llvm.experimental.convergence.anchor() diff --git a/llvm/test/Transforms/LoopUnroll/followup.ll b/llvm/test/Transforms/LoopUnroll/followup.ll index 051e43d52b3b..b6561781d29c 100644 --- a/llvm/test/Transforms/LoopUnroll/followup.ll +++ b/llvm/test/Transforms/LoopUnroll/followup.ll @@ -36,11 +36,11 @@ for.end: ; preds = %for.body, %entry ; COMMON-LABEL: @test( -; COUNT: br i1 %exitcond.1, label %for.end.loopexit, label %for.body, !llvm.loop ![[LOOP:[0-9]+]] +; COUNT: br i1 %exitcond.1, label %for.end.loopexit, label %for.body, !llvm.loop ![[#LOOP:]] -; COUNT: ![[FOLLOWUP_ALL:[0-9]+]] = !{!"FollowupAll"} -; COUNT: ![[FOLLOWUP_UNROLLED:[0-9]+]] = !{!"FollowupUnrolled"} -; COUNT: ![[LOOP]] = distinct !{![[LOOP]], ![[FOLLOWUP_ALL]], ![[FOLLOWUP_UNROLLED]]} +; COUNT: ![[#LOOP]] = distinct !{![[#LOOP]], ![[#FOLLOWUP_ALL:]], ![[#FOLLOWUP_UNROLLED:]]} +; COUNT: ![[#FOLLOWUP_ALL]] = !{!"FollowupAll"} +; COUNT: ![[#FOLLOWUP_UNROLLED]] = !{!"FollowupUnrolled"} ; EPILOG: br i1 %niter.ncmp.7, label %for.end.loopexit.unr-lcssa, label %for.body, !llvm.loop ![[LOOP_0:[0-9]+]] diff --git a/llvm/test/Transforms/LoopUnroll/pr131465.ll b/llvm/test/Transforms/LoopUnroll/pr131465.ll index 643b020c6c11..60bea6a4d904 100644 --- a/llvm/test/Transforms/LoopUnroll/pr131465.ll +++ b/llvm/test/Transforms/LoopUnroll/pr131465.ll @@ -11,11 +11,11 @@ define i32 @pr131465(i1 %x) mustprogress { ; CHECK-NEXT: [[INDVAR:%.*]] = phi i32 [ 2, %[[ENTRY]] ], [ [[NEXT_1:%.*]], %[[FOR_BODY_1:.*]] ] ; CHECK-NEXT: [[NEXT:%.*]] = add nsw i32 [[INDVAR]], [[INC]] ; CHECK-NEXT: [[EXITCOND:%.*]] = icmp eq i32 [[NEXT]], 2 -; CHECK-NEXT: br i1 [[EXITCOND]], label %[[FOR_END:.*]], label %[[FOR_BODY_1]], !llvm.loop [[LOOP0:![0-9]+]] +; CHECK-NEXT: br i1 [[EXITCOND]], label %[[FOR_END:.*]], label %[[FOR_BODY_1]] ; CHECK: [[FOR_BODY_1]]: ; CHECK-NEXT: [[NEXT_1]] = add nsw i32 [[NEXT]], [[INC]] ; CHECK-NEXT: [[EXITCOND_1:%.*]] = icmp eq i32 [[NEXT_1]], 2 -; CHECK-NEXT: br i1 [[EXITCOND_1]], label %[[FOR_END]], label %[[FOR_BODY]], !llvm.loop [[LOOP2:![0-9]+]] +; CHECK-NEXT: br i1 [[EXITCOND_1]], label %[[FOR_END]], label %[[FOR_BODY]], !llvm.loop [[LOOP0:![0-9]+]] ; CHECK: [[FOR_END]]: ; CHECK-NEXT: ret i32 0 ; @@ -37,7 +37,5 @@ for.end: !0 = !{!0, !{!"llvm.loop.unroll.count", i32 2}} ;. ; CHECK: [[LOOP0]] = distinct !{[[LOOP0]], [[META1:![0-9]+]]} -; CHECK: [[META1]] = !{!"llvm.loop.unroll.count", i32 2} -; CHECK: [[LOOP2]] = distinct !{[[LOOP2]], [[META3:![0-9]+]]} -; CHECK: [[META3]] = !{!"llvm.loop.unroll.disable"} +; CHECK: [[META1]] = !{!"llvm.loop.unroll.disable"} ;. diff --git a/llvm/test/Transforms/LoopUnroll/unroll-dont-copy-latch-loop-id.ll b/llvm/test/Transforms/LoopUnroll/unroll-dont-copy-latch-loop-id.ll new file mode 100644 index 000000000000..191ebb023b7c --- /dev/null +++ b/llvm/test/Transforms/LoopUnroll/unroll-dont-copy-latch-loop-id.ll @@ -0,0 +1,90 @@ +; Check that !llvm.loop is not copied from the original loop's latch to the +; corresponding non-latch branch in any unrolled iteration. + +; The -implicit-check-not options make sure that no additional label or +; !llvm.loop shows up. +; DEFINE: %{unroll} = opt < %s -passes=loop-unroll -S +; DEFINE: %{fc} = FileCheck %s \ +; DEFINE: -implicit-check-not='{{^[^ ;]*:}}' \ +; DEFINE: -implicit-check-not='!llvm.loop' \ +; DEFINE: -check-prefixes + +; Check partial unroll: only the unrolled loop's latch has !llvm.loop. +; RUN: %{unroll} -unroll-count=3 | %{fc} ALL,UR,UR3 + +; Check complete unroll: no !llvm.loop remains because no loop remains. +; RUN: %{unroll} -unroll-count=4 | %{fc} ALL,UR,UR4 + +; Check remainder: both loops have a !llvm.loop. +; DEFINE: %{rt} = %{unroll} -unroll-count=3 -unroll-runtime +; RUN: %{rt} -unroll-runtime-epilog=true | %{fc} ALL,RT,EPILOG +; RUN: %{rt} -unroll-runtime-epilog=false | %{fc} ALL,RT,PROLOG + +; ALL: define void @test(i32 %n) { +; ALL: entry: +; UR: br label %body +; EPILOG: br i1 %{{.*}}, label %body.epil.preheader, label %entry.new +; PROLOG: br i1 %{{.*}}, label %body.prol.preheader, label %body.prol.loopexit +; PROLOG: body.prol.preheader: +; PROLOG: br label %body.prol +; PROLOG: body.prol: +; PROLOG: br i1 %{{.*}}, label %body.prol, label %body.prol.loopexit.unr-lcssa, !llvm.loop !0 +; PROLOG: body.prol.loopexit.unr-lcssa: +; PROLOG: br label %body.prol.loopexit +; PROLOG: body.prol.loopexit: +; PROLOG: br i1 %{{.*}}, label %exit, label %entry.new +; RT: entry.new: +; RT: br label %body +; ALL: body: +; UR: br i1 %c, label %body.1, label %exit +; EPILOG: br i1 %{{.*}}, label %body, label %exit.unr-lcssa, !llvm.loop !0 +; PROLOG: br i1 %{{.*}}, label %body, label %exit.unr-lcssa, !llvm.loop !2 +; UR: body.1: +; UR: br i1 %c.1, label %body.2, label %exit +; UR: body.2: +; UR3: br i1 %c.2, label %body, label %exit, !llvm.loop !0 +; UR4: br i1 %c.2, label %body.3, label %exit +; UR4: body.3: +; UR4: br label %exit +; RT: exit.unr-lcssa: +; EPILOG: br i1 {{.*}}, label %body.epil.preheader, label %exit +; PROLOG: br label %exit +; EPILOG: body.epil.preheader: +; EPILOG: br label %body.epil +; EPILOG: body.epil: +; EPILOG: br i1 {{.*}}, label %body.epil, label %exit.epilog-lcssa, !llvm.loop !3 +; EPILOG: exit.epilog-lcssa: +; EPILOG: br label %exit +; ALL: exit: +; ALL: ret void +; ALL: } +define void @test(i32 %n) { +entry: + %max = call i32 @llvm.umin.i32(i32 %n, i32 3) + br label %body + +body: + %i = phi i32 [ 0, %entry ], [ %inc, %body ] + %inc = add i32 %i, 1 + %c = icmp ult i32 %i, %max + br i1 %c, label %body, label %exit, !llvm.loop !0 + +exit: + ret void +} + +; UR3: !0 = distinct !{!0, !1, !2} +; UR3: !1 = !{!"copied"} +; UR3: !2 = !{!"llvm.loop.unroll.disable"} +; +; EPILOG: !0 = distinct !{!0, !1, !2} +; EPILOG: !1 = !{!"copied"} +; EPILOG: !2 = !{!"llvm.loop.unroll.disable"} +; EPILOG: !3 = distinct !{!3, !2} +; +; PROLOG: !0 = distinct !{!0, !1} +; PROLOG: !1 = !{!"llvm.loop.unroll.disable"} +; PROLOG: !2 = distinct !{!2, !3, !1} +; PROLOG: !3 = !{!"copied"} +!0 = distinct !{!0, !1} +!1 = !{!"copied"} diff --git a/llvm/test/Transforms/LoopUnroll/unroll-loads-cse.ll b/llvm/test/Transforms/LoopUnroll/unroll-loads-cse.ll index f85aac75539c..77dd3429b684 100644 --- a/llvm/test/Transforms/LoopUnroll/unroll-loads-cse.ll +++ b/llvm/test/Transforms/LoopUnroll/unroll-loads-cse.ll @@ -419,7 +419,7 @@ define void @loop_body_with_dead_blocks(ptr %src) { ; CHECK-NEXT: call void @foo() ; CHECK-NEXT: [[L_2:%.*]] = load i32, ptr [[SRC]], align 8 ; CHECK-NEXT: [[C_2:%.*]] = icmp eq i32 [[L_2]], 1 -; CHECK-NEXT: br i1 [[C_2]], label [[EXIT:%.*]], label [[LOOP_HEADER_1:%.*]], !llvm.loop [[LOOP7:![0-9]+]] +; CHECK-NEXT: br i1 [[C_2]], label [[EXIT:%.*]], label [[LOOP_HEADER_1:%.*]] ; CHECK: loop.header.1: ; CHECK-NEXT: br label [[LOOP_BB_1:%.*]] ; CHECK: loop.bb.1: @@ -429,7 +429,7 @@ define void @loop_body_with_dead_blocks(ptr %src) { ; CHECK-NEXT: call void @foo() ; CHECK-NEXT: [[L_2_1:%.*]] = load i32, ptr [[SRC]], align 8 ; CHECK-NEXT: [[C_2_1:%.*]] = icmp eq i32 [[L_2_1]], 1 -; CHECK-NEXT: br i1 [[C_2_1]], label [[EXIT]], label [[LOOP_HEADER]], !llvm.loop [[LOOP9:![0-9]+]] +; CHECK-NEXT: br i1 [[C_2_1]], label [[EXIT]], label [[LOOP_HEADER]], !llvm.loop [[LOOP7:![0-9]+]] ; CHECK: exit: ; CHECK-NEXT: ret void ; @@ -471,7 +471,5 @@ exit: ; CHECK: [[LOOP4]] = distinct !{[[LOOP4]], [[META1]], [[META2]]} ; CHECK: [[LOOP5]] = distinct !{[[LOOP5]], [[META1]], [[META2]]} ; CHECK: [[LOOP6]] = distinct !{[[LOOP6]], [[META1]], [[META2]]} -; CHECK: [[LOOP7]] = distinct !{[[LOOP7]], [[META1]], [[META8:![0-9]+]]} -; CHECK: [[META8]] = !{!"llvm.loop.unroll.count", i32 2} -; CHECK: [[LOOP9]] = distinct !{[[LOOP9]], [[META1]], [[META2]]} +; CHECK: [[LOOP7]] = distinct !{[[LOOP7]], [[META1]], [[META2]]} ;. |
