Skip to content

Commit 1d37cae

Browse files
fhahnmemfrob
authored and
memfrob
committed
[LoopInterchange] Form LCSSA phis for values in orig outer loop header.
Values defined in the outer loop header could be used in the inner loop latch. In that case, we need to create LCSSA phis for them, because after interchanging they will be defined in the new inner loop and used in the new outer loop.
1 parent 4f09798 commit 1d37cae

File tree

2 files changed

+74
-0
lines changed

2 files changed

+74
-0
lines changed

llvm/lib/Transforms/Scalar/LoopInterchange.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
#include "llvm/IR/DiagnosticInfo.h"
2828
#include "llvm/IR/Dominators.h"
2929
#include "llvm/IR/Function.h"
30+
#include "llvm/IR/IRBuilder.h"
3031
#include "llvm/IR/InstrTypes.h"
3132
#include "llvm/IR/Instruction.h"
3233
#include "llvm/IR/Instructions.h"
@@ -1594,6 +1595,17 @@ bool LoopInterchangeTransform::adjustLoopBranches() {
15941595
InnerLoopHeader->replacePhiUsesWith(OuterLoopPreHeader, InnerLoopPreHeader);
15951596
InnerLoopHeader->replacePhiUsesWith(OuterLoopLatch, InnerLoopLatch);
15961597

1598+
// Values defined in the outer loop header could be used in the inner loop
1599+
// latch. In that case, we need to create LCSSA phis for them, because after
1600+
// interchanging they will be defined in the new inner loop and used in the
1601+
// new outer loop.
1602+
IRBuilder<> Builder(OuterLoopHeader->getContext());
1603+
SmallVector<Instruction *, 4> MayNeedLCSSAPhis;
1604+
for (Instruction &I :
1605+
make_range(OuterLoopHeader->begin(), std::prev(OuterLoopHeader->end())))
1606+
MayNeedLCSSAPhis.push_back(&I);
1607+
formLCSSAForInstructions(MayNeedLCSSAPhis, *DT, *LI, SE, Builder);
1608+
15971609
return true;
15981610
}
15991611

llvm/test/Transforms/LoopInterchange/lcssa-preheader.ll

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,3 +101,65 @@ outer.crit_edge: ; preds = %outer.latch
101101
for.cond.cleanup: ; preds = %outer.crit_edge, %entry
102102
ret void
103103
}
104+
105+
@global = external local_unnamed_addr global [4 x [4 x [2 x i16]]] align 16
106+
107+
; %N.ext is defined in the outer loop header and used in the inner loop. After
108+
; interchanging, it will be defined in the new inner loop and used in the new;
109+
; outer latch, so we need to create a new LCSSA phi node for it.
110+
111+
define void @test2(i32 %N) {
112+
; CHECK-LABEL: @test2(
113+
; CHECK-NEXT: bb:
114+
; CHECK-NEXT: br label [[INNER_PREHEADER:%.*]]
115+
; CHECK: outer.header.preheader:
116+
; CHECK-NEXT: br label [[OUTER_HEADER:%.*]]
117+
; CHECK: outer.header:
118+
; CHECK-NEXT: [[OUTER_IV:%.*]] = phi i64 [ [[OUTER_IV_NEXT:%.*]], [[OUTER_LATCH:%.*]] ], [ 0, [[OUTER_HEADER_PREHEADER:%.*]] ]
119+
; CHECK-NEXT: [[N_EXT:%.*]] = sext i32 [[N:%.*]] to i64
120+
; CHECK-NEXT: br label [[INNER_SPLIT1:%.*]]
121+
; CHECK: inner.preheader:
122+
; CHECK-NEXT: br label [[INNER:%.*]]
123+
; CHECK: inner:
124+
; CHECK-NEXT: [[INNER_IV:%.*]] = phi i64 [ [[TMP0:%.*]], [[INNER_SPLIT:%.*]] ], [ 0, [[INNER_PREHEADER]] ]
125+
; CHECK-NEXT: br label [[OUTER_HEADER_PREHEADER]]
126+
; CHECK: inner.split1:
127+
; CHECK-NEXT: [[TMP8:%.*]] = getelementptr inbounds [4 x [4 x [2 x i16]]], [4 x [4 x [2 x i16]]]* @global, i64 0, i64 [[INNER_IV]], i64 [[OUTER_IV]], i64 0
128+
; CHECK-NEXT: [[INNER_IV_NEXT:%.*]] = add nsw i64 [[INNER_IV]], 1
129+
; CHECK-NEXT: [[C_1:%.*]] = icmp ne i64 [[INNER_IV_NEXT]], [[N_EXT]]
130+
; CHECK-NEXT: br label [[OUTER_LATCH]]
131+
; CHECK: inner.split:
132+
; CHECK-NEXT: [[N_EXT_LCSSA:%.*]] = phi i64 [ [[N_EXT]], [[OUTER_LATCH]] ]
133+
; CHECK-NEXT: [[TMP0]] = add nsw i64 [[INNER_IV]], 1
134+
; CHECK-NEXT: [[TMP1:%.*]] = icmp ne i64 [[TMP0]], [[N_EXT_LCSSA]]
135+
; CHECK-NEXT: br i1 [[TMP1]], label [[INNER]], label [[EXIT:%.*]]
136+
; CHECK: outer.latch:
137+
; CHECK-NEXT: [[OUTER_IV_NEXT]] = add nsw i64 [[OUTER_IV]], 1
138+
; CHECK-NEXT: [[C_2:%.*]] = icmp ne i64 [[OUTER_IV]], [[N_EXT]]
139+
; CHECK-NEXT: br i1 [[C_2]], label [[OUTER_HEADER]], label [[INNER_SPLIT]]
140+
; CHECK: exit:
141+
; CHECK-NEXT: ret void
142+
;
143+
bb:
144+
br label %outer.header
145+
146+
outer.header: ; preds = %bb11, %bb2
147+
%outer.iv = phi i64 [ 0, %bb ], [ %outer.iv.next, %outer.latch ]
148+
%N.ext = sext i32 %N to i64
149+
br label %inner
150+
151+
inner: ; preds = %bb6, %bb4
152+
%inner.iv = phi i64 [ 0, %outer.header ], [ %inner.iv.next, %inner ]
153+
%tmp8 = getelementptr inbounds [4 x [4 x [2 x i16]]], [4 x [4 x [2 x i16]]]* @global, i64 0, i64 %inner.iv, i64 %outer.iv, i64 0
154+
%inner.iv.next = add nsw i64 %inner.iv, 1
155+
%c.1 = icmp ne i64 %inner.iv.next, %N.ext
156+
br i1 %c.1, label %inner, label %outer.latch
157+
158+
outer.latch: ; preds = %bb6
159+
%outer.iv.next = add nsw i64 %outer.iv, 1
160+
%c.2 = icmp ne i64 %outer.iv, %N.ext
161+
br i1 %c.2 , label %outer.header, label %exit
162+
163+
exit: ; preds = %bb11
164+
ret void
165+
}

0 commit comments

Comments
 (0)