Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 12 additions & 6 deletions llvm/lib/Target/AIE/AIEOuterLoopPipeliner.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -550,18 +550,24 @@ void AIEOuterLoopPipeliner::swapInClonedLS(
SteadyLS.setOuterPreheader(Preheader);

// The clone's latch exit edge still points at OrigExit (left external by
// cloneLS); that is correct. Repoint the exit's loop-carried PHIs from
// the original latch to the clone's latch, mapping each incoming value
// through the clone VMap so the exit sees the clone's definitions.
// cloneLS); that is correct. Add a clone-latch incoming to the exit's
// loop-carried PHIs, mapping each value through the clone VMap so the exit
// sees the clone's definitions.
//
// Add — do not rename the original-latch entry: when the exit is reached
// directly by the latch (shared with the preheader-bypass edge, no dedicated
// exit.loopexit), the original latch still branches here until removeFromCFG
// deletes it, so its phi entry must survive to be removed cleanly. The entry
// is later retargeted to the last-iteration epilogue in wireLastIterIntoCFG.
for (PHINode &PHI : OrigExit->phis()) {
int Idx = PHI.getBasicBlockIndex(OrigLS.getOuterLatch());
if (Idx < 0)
continue;
Value *V = PHI.getIncomingValue(Idx);
auto It = SteadyVMap.find(V);
if (It != SteadyVMap.end())
PHI.setIncomingValue(Idx, It->second);
PHI.setIncomingBlock(Idx, SteadyLS.getOuterLatch());
Value *SteadyV =
It != SteadyVMap.end() ? static_cast<Value *>(It->second) : V;
PHI.addIncoming(SteadyV, SteadyLS.getOuterLatch());
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
; NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py UTC_ARGS: --version 5
; This file is licensed under the Apache License v2.0 with LLVM Exceptions.
; See https://llvm.org/LICENSE.txt for license information.
; SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
;
; (c) Copyright 2026 Advanced Micro Devices, Inc. or its affiliates
;
; RUN: llc -mtriple=aie2p -O2 -aie-enable-outer-loop-pipelining \
; RUN: -stop-after=irtranslator \
; RUN: -o - %s 2>&1 | FileCheck %s
;
; section); regenerate them whenever the pass output changes.

; The outer loop's exit block is shared between the preheader-bypass edge
; (entry -> exit) and the loop back-edge, so the live-out is an LCSSA phi with
; an incoming value from entry and no dedicated exit.loopexit block. The
; original latch still branches to the exit until it is deleted, so its phi
; entry must survive swap-in (a clone-latch incoming is added, not renamed) and
; then be retargeted to the last-iteration epilogue. This previously crashed
; while deleting the original loop.

;
;
;
;
;
;
;
;
;

define i32 @shared_exit(ptr noalias %a, ptr noalias %c, i32 %N, i32 %M) {
; CHECK-LABEL: name: shared_exit
; CHECK: bb.1.entry:
; CHECK-NEXT: successors: %bb.2(0x40000000), %bb.10(0x40000000)
; CHECK-NEXT: liveins: $p0, $p1, $r1, $r2
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: [[COPY:%[0-9]+]]:_(p0) = COPY $p0
; CHECK-NEXT: [[COPY1:%[0-9]+]]:_(p0) = COPY $p1
; CHECK-NEXT: [[COPY2:%[0-9]+]]:_(s32) = COPY $r1
; CHECK-NEXT: [[COPY3:%[0-9]+]]:_(s32) = COPY $r2
; CHECK-NEXT: [[C:%[0-9]+]]:_(s32) = G_CONSTANT i32 1
; CHECK-NEXT: [[C1:%[0-9]+]]:_(s32) = G_CONSTANT i32 0
; CHECK-NEXT: [[ICMP:%[0-9]+]]:_(s1) = G_ICMP intpred(sgt), [[COPY2]](s32), [[C]]
; CHECK-NEXT: G_BRCOND [[ICMP]](s1), %bb.2
; CHECK-NEXT: G_BR %bb.10
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: bb.2.outer.header.preheader:
; CHECK-NEXT: successors: %bb.3(0x80000000)
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: bb.3.steady.preheader:
; CHECK-NEXT: successors: %bb.4(0x80000000)
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: [[LOAD:%[0-9]+]]:_(s32) = G_LOAD [[COPY]](p0) :: (load (s32) from %ir.a)
; CHECK-NEXT: [[SUB:%[0-9]+]]:_(s32) = G_SUB [[COPY2]], [[C]]
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: bb.4.steady.header:
; CHECK-NEXT: successors: %bb.5(0x80000000)
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: [[PHI:%[0-9]+]]:_(s32) = G_PHI %19(s32), %bb.6, [[C1]](s32), %bb.3
; CHECK-NEXT: [[PHI1:%[0-9]+]]:_(p0) = G_PHI %14(p0), %bb.6, [[COPY]](p0), %bb.3
; CHECK-NEXT: [[PHI2:%[0-9]+]]:_(p0) = G_PHI %15(p0), %bb.6, [[COPY1]](p0), %bb.3
; CHECK-NEXT: [[PHI3:%[0-9]+]]:_(s32) = G_PHI [[LOAD]](s32), %bb.3, %21(s32), %bb.6
; CHECK-NEXT: G_INTRINSIC_W_SIDE_EFFECTS intrinsic(@llvm.set.loop.iterations), [[COPY3]](s32)
; CHECK-NEXT: [[C2:%[0-9]+]]:_(s20) = G_CONSTANT i20 4
; CHECK-NEXT: %14:_(p0) = nuw nusw G_PTR_ADD [[PHI1]], [[C2]](s20)
; CHECK-NEXT: %15:_(p0) = nuw nusw G_PTR_ADD [[PHI2]], [[C2]](s20)
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: bb.5.steady.inner.header:
; CHECK-NEXT: successors: %bb.5(0x7c000000), %bb.6(0x04000000)
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: [[PHI4:%[0-9]+]]:_(s32) = G_PHI [[C1]](s32), %bb.4, %17(s32), %bb.5
; CHECK-NEXT: [[ADD:%[0-9]+]]:_(s32) = G_ADD [[PHI4]], [[PHI3]]
; CHECK-NEXT: [[INT:%[0-9]+]]:_(s1) = G_INTRINSIC_W_SIDE_EFFECTS intrinsic(@llvm.loop.decrement), [[C]](s32)
; CHECK-NEXT: G_BRCOND [[INT]](s1), %bb.5
; CHECK-NEXT: G_BR %bb.6
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: bb.6.steady.latch:
; CHECK-NEXT: successors: %bb.4(0x7c000000), %bb.7(0x04000000)
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: G_STORE [[ADD]](s32), [[PHI2]](p0) :: (store (s32) into %ir.c.ptr.steady)
; CHECK-NEXT: [[ADD1:%[0-9]+]]:_(s32) = G_ADD [[PHI]], [[C]]
; CHECK-NEXT: [[ICMP1:%[0-9]+]]:_(s1) = G_ICMP intpred(slt), [[ADD1]](s32), [[SUB]]
; CHECK-NEXT: [[LOAD1:%[0-9]+]]:_(s32) = G_LOAD %14(p0) :: (load (s32) from %ir.a.ptr.next.steady)
; CHECK-NEXT: G_BRCOND [[ICMP1]](s1), %bb.4
; CHECK-NEXT: G_BR %bb.7
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: bb.7.lastiter.prologue:
; CHECK-NEXT: successors: %bb.8(0x80000000)
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: G_INTRINSIC_W_SIDE_EFFECTS intrinsic(@llvm.set.loop.iterations), [[COPY3]](s32)
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: bb.8.steady.inner.header.lastiter:
; CHECK-NEXT: successors: %bb.8(0x7c000000), %bb.9(0x04000000)
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: [[PHI5:%[0-9]+]]:_(s32) = G_PHI [[C1]](s32), %bb.7, %23(s32), %bb.8
; CHECK-NEXT: [[ADD2:%[0-9]+]]:_(s32) = G_ADD [[PHI5]], [[LOAD1]]
; CHECK-NEXT: [[INT1:%[0-9]+]]:_(s1) = G_INTRINSIC_W_SIDE_EFFECTS intrinsic(@llvm.loop.decrement), [[C]](s32)
; CHECK-NEXT: G_BRCOND [[INT1]](s1), %bb.8
; CHECK-NEXT: G_BR %bb.9
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: bb.9.lastiter.epilogue:
; CHECK-NEXT: successors: %bb.10(0x80000000)
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: G_STORE [[ADD2]](s32), %15(p0) :: (store (s32) into %ir.c.ptr.next.steady)
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: bb.10.exit:
; CHECK-NEXT: [[PHI6:%[0-9]+]]:_(s32) = G_PHI [[C1]](s32), %bb.1, [[ADD2]](s32), %bb.9
; CHECK-NEXT: $r0 = COPY [[PHI6]](s32)
; CHECK-NEXT: PseudoRET implicit $lr, implicit $r0
entry:
%cmp.outer = icmp sgt i32 %N, 1
br i1 %cmp.outer, label %outer.header, label %exit

outer.header:
%i = phi i32 [ 0, %entry ], [ %i.next, %outer.latch ]
%a.ptr = phi ptr [ %a, %entry ], [ %a.ptr.next, %outer.latch ]
%c.ptr = phi ptr [ %c, %entry ], [ %c.ptr.next, %outer.latch ]
%v0 = load i32, ptr %a.ptr, align 4
call void @llvm.set.loop.iterations.i32(i32 %M)
br label %inner.header

inner.header:
%acc = phi i32 [ 0, %outer.header ], [ %acc.next, %inner.header ]
%acc.next = add i32 %acc, %v0
%inner.cond = call i1 @llvm.loop.decrement.i32(i32 1)
br i1 %inner.cond, label %inner.header, label %outer.latch, !llvm.loop !1

outer.latch:
store i32 %acc.next, ptr %c.ptr, align 4
%a.ptr.next = getelementptr inbounds i32, ptr %a.ptr, i32 1
%c.ptr.next = getelementptr inbounds i32, ptr %c.ptr, i32 1
%i.next = add i32 %i, 1
%outer.cond = icmp slt i32 %i.next, %N
br i1 %outer.cond, label %outer.header, label %exit, !llvm.loop !0

exit:
%acc.lcssa = phi i32 [ 0, %entry ], [ %acc.next, %outer.latch ]
ret i32 %acc.lcssa
}

declare void @llvm.set.loop.iterations.i32(i32)
declare i1 @llvm.loop.decrement.i32(i32)

!0 = distinct !{!0, !2, !3}
!1 = distinct !{!1, !2}
!2 = !{!"llvm.loop.mustprogress"}
!3 = !{!"llvm.loop.itercount.range", i32 2}
Loading