Skip to content

Commit 0074a46

Browse files
authored
[LoopInterchange] Hoist isComputableLoopNest() in the control flow (#124247)
The profiling of the LLVM Test-suite reveals that a significant portion, specifically 14,090 out of 139,323, loop nests were identified as non-viable candidates for transformation, leading to the transform exiting from isComputableLoopNest() without any action. More importantly, dependence information was computed for these loop nests before reaching the function isComputableLoopNest(), which does not require DI and relies solely on scalar evolution (SE). To enhance compile-time efficiency, this patch moves the call to isComputableLoopNest() earlier in the control-flow, thereby avoiding unnecessary dependence calculations. The impact of this change is evident on the compile-time-tracker, with the overall geometric mean improvement recorded at 0.11%, while the lencode benchmark gets a more substantial benefit of 0.44%. This improvement can be tracked in the isc-ln-exp-2 branch under my repo.
1 parent 646d352 commit 0074a46

7 files changed

+215
-24
lines changed

llvm/lib/Transforms/Scalar/LoopInterchange.cpp

Lines changed: 35 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -276,6 +276,27 @@ static bool hasSupportedLoopDepth(SmallVectorImpl<Loop *> &LoopList,
276276
}
277277
return true;
278278
}
279+
280+
static bool isComputableLoopNest(ScalarEvolution *SE,
281+
ArrayRef<Loop *> LoopList) {
282+
for (Loop *L : LoopList) {
283+
const SCEV *ExitCountOuter = SE->getBackedgeTakenCount(L);
284+
if (isa<SCEVCouldNotCompute>(ExitCountOuter)) {
285+
LLVM_DEBUG(dbgs() << "Couldn't compute backedge count\n");
286+
return false;
287+
}
288+
if (L->getNumBackEdges() != 1) {
289+
LLVM_DEBUG(dbgs() << "NumBackEdges is not equal to 1\n");
290+
return false;
291+
}
292+
if (!L->getExitingBlock()) {
293+
LLVM_DEBUG(dbgs() << "Loop doesn't have unique exit block\n");
294+
return false;
295+
}
296+
}
297+
return true;
298+
}
299+
279300
namespace {
280301

281302
/// LoopInterchangeLegality checks if it is legal to interchange the loop.
@@ -431,25 +452,6 @@ struct LoopInterchange {
431452
return processLoopList(LoopList);
432453
}
433454

434-
bool isComputableLoopNest(ArrayRef<Loop *> LoopList) {
435-
for (Loop *L : LoopList) {
436-
const SCEV *ExitCountOuter = SE->getBackedgeTakenCount(L);
437-
if (isa<SCEVCouldNotCompute>(ExitCountOuter)) {
438-
LLVM_DEBUG(dbgs() << "Couldn't compute backedge count\n");
439-
return false;
440-
}
441-
if (L->getNumBackEdges() != 1) {
442-
LLVM_DEBUG(dbgs() << "NumBackEdges is not equal to 1\n");
443-
return false;
444-
}
445-
if (!L->getExitingBlock()) {
446-
LLVM_DEBUG(dbgs() << "Loop doesn't have unique exit block\n");
447-
return false;
448-
}
449-
}
450-
return true;
451-
}
452-
453455
unsigned selectLoopForInterchange(ArrayRef<Loop *> LoopList) {
454456
// TODO: Add a better heuristic to select the loop to be interchanged based
455457
// on the dependence matrix. Currently we select the innermost loop.
@@ -464,10 +466,6 @@ struct LoopInterchange {
464466
"Unsupported depth of loop nest.");
465467

466468
unsigned LoopNestDepth = LoopList.size();
467-
if (!isComputableLoopNest(LoopList)) {
468-
LLVM_DEBUG(dbgs() << "Not valid loop candidate for interchange\n");
469-
return false;
470-
}
471469

472470
LLVM_DEBUG(dbgs() << "Processing LoopList of size = " << LoopNestDepth
473471
<< "\n");
@@ -1761,10 +1759,23 @@ PreservedAnalyses LoopInterchangePass::run(LoopNest &LN,
17611759
// Ensure minimum depth of the loop nest to do the interchange.
17621760
if (!hasSupportedLoopDepth(LoopList, ORE))
17631761
return PreservedAnalyses::all();
1762+
// Ensure computable loop nest.
1763+
if (!isComputableLoopNest(&AR.SE, LoopList)) {
1764+
LLVM_DEBUG(dbgs() << "Not valid loop candidate for interchange\n");
1765+
return PreservedAnalyses::all();
1766+
}
1767+
1768+
ORE.emit([&]() {
1769+
return OptimizationRemarkAnalysis(DEBUG_TYPE, "Dependence",
1770+
LN.getOutermostLoop().getStartLoc(),
1771+
LN.getOutermostLoop().getHeader())
1772+
<< "Computed dependence info, invoking the transform.";
1773+
});
1774+
17641775
DependenceInfo DI(&F, &AR.AA, &AR.SE, &AR.LI);
17651776
std::unique_ptr<CacheCost> CC =
17661777
CacheCost::getCacheCost(LN.getOutermostLoop(), AR, DI);
1767-
1778+
17681779
if (!LoopInterchange(&AR.SE, &AR.LI, &DI, &AR.DT, CC, &ORE).run(LN))
17691780
return PreservedAnalyses::all();
17701781
U.markLoopNestChanged(true);

llvm/test/Transforms/LoopInterchange/loop-interchange-optimization-remarks.ll

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,14 @@ for.end19:
5858
ret void
5959
}
6060

61+
; CHECK: --- !Analysis
62+
; CHECK-NEXT: Pass: loop-interchange
63+
; CHECK-NEXT: Name: Dependence
64+
; CHECK-NEXT: Function: test01
65+
; CHECK-NEXT: Args:
66+
; CHECK-NEXT: - String: Computed dependence info, invoking the transform.
67+
; CHECK-NEXT: ...
68+
6169
; CHECK: --- !Missed
6270
; CHECK-NEXT: Pass: loop-interchange
6371
; CHECK-NEXT: Name: Dependence
@@ -66,6 +74,14 @@ for.end19:
6674
; CHECK-NEXT: - String: Cannot interchange loops due to dependences.
6775
; CHECK-NEXT: ...
6876

77+
; DELIN: --- !Analysis
78+
; DELIN-NEXT: Pass: loop-interchange
79+
; DELIN-NEXT: Name: Dependence
80+
; DELIN-NEXT: Function: test01
81+
; DELIN-NEXT: Args:
82+
; DELIN-NEXT: - String: Computed dependence info, invoking the transform.
83+
; DELIN-NEXT: ...
84+
6985
; DELIN: --- !Missed
7086
; DELIN-NEXT: Pass: loop-interchange
7187
; DELIN-NEXT: Name: InterchangeNotProfitable
@@ -118,6 +134,14 @@ define void @test02(i32 %k, i32 %N) {
118134
ret void
119135
}
120136

137+
; CHECK: --- !Analysis
138+
; CHECK-NEXT: Pass: loop-interchange
139+
; CHECK-NEXT: Name: Dependence
140+
; CHECK-NEXT: Function: test02
141+
; CHECK-NEXT: Args:
142+
; CHECK-NEXT: - String: Computed dependence info, invoking the transform.
143+
; CHECK-NEXT: ...
144+
121145
; CHECK: --- !Missed
122146
; CHECK-NEXT: Pass: loop-interchange
123147
; CHECK-NEXT: Name: Dependence
@@ -126,6 +150,14 @@ define void @test02(i32 %k, i32 %N) {
126150
; CHECK-NEXT: - String: Cannot interchange loops due to dependences.
127151
; CHECK-NEXT: ...
128152

153+
; DELIN: --- !Analysis
154+
; DELIN-NEXT: Pass: loop-interchange
155+
; DELIN-NEXT: Name: Dependence
156+
; DELIN-NEXT: Function: test02
157+
; DELIN-NEXT: Args:
158+
; DELIN-NEXT: - String: Computed dependence info, invoking the transform.
159+
; DELIN-NEXT: ...
160+
129161
; DELIN: --- !Passed
130162
; DELIN-NEXT: Pass: loop-interchange
131163
; DELIN-NEXT: Name: Interchanged
@@ -174,6 +206,14 @@ for.body4: ; preds = %for.body4, %for.con
174206
br i1 %exitcond, label %for.body4, label %for.cond.loopexit
175207
}
176208

209+
; CHECK: --- !Analysis
210+
; CHECK-NEXT: Pass: loop-interchange
211+
; CHECK-NEXT: Name: Dependence
212+
; CHECK-NEXT: Function: test03
213+
; CHECK-NEXT: Args:
214+
; CHECK-NEXT: - String: Computed dependence info, invoking the transform.
215+
; CHECK-NEXT: ...
216+
177217
; CHECK: --- !Passed
178218
; CHECK-NEXT: Pass: loop-interchange
179219
; CHECK-NEXT: Name: Interchanged
@@ -182,6 +222,14 @@ for.body4: ; preds = %for.body4, %for.con
182222
; CHECK-NEXT: - String: Loop interchanged with enclosing loop.
183223
; CHECK-NEXT: ...
184224

225+
; DELIN: --- !Analysis
226+
; DELIN-NEXT: Pass: loop-interchange
227+
; DELIN-NEXT: Name: Dependence
228+
; DELIN-NEXT: Function: test03
229+
; DELIN-NEXT: Args:
230+
; DELIN-NEXT: - String: Computed dependence info, invoking the transform.
231+
; DELIN-NEXT: ...
232+
185233
; DELIN: --- !Passed
186234
; DELIN-NEXT: Pass: loop-interchange
187235
; DELIN-NEXT: Name: Interchanged
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
; RUN: opt %s -passes='loop-interchange' -pass-remarks=loop-interchange -disable-output 2>&1 | FileCheck --allow-empty %s
2+
3+
target triple = "aarch64-unknown-linux-gnu"
4+
5+
; CHECK-NOT: Computed dependence info, invoking the transform.
6+
7+
; For the below test, backedge count cannot be computed.
8+
; Computing backedge count requires only SCEV and should
9+
; not require dependence info.
10+
;
11+
; void bar(int m, int n) {
12+
; for (unsigned int i = 0; i < m; ++i) {
13+
; for (unsigned int j = 0; j < m; ++j) {
14+
; // dummy code
15+
; }
16+
; }
17+
;}
18+
19+
define void @bar(i32 %m, i32 %n)
20+
{
21+
entry:
22+
br label %outer.header
23+
24+
outer.header:
25+
%m_temp1 = phi i32 [%m, %entry], [%m_temp, %outer.latch]
26+
br label %inner.header
27+
28+
29+
inner.header:
30+
%n_temp1 = phi i32 [%n, %outer.header], [%n_temp, %inner.latch]
31+
32+
br label %body
33+
34+
body:
35+
; dummy code
36+
37+
br label %inner.latch
38+
39+
inner.latch:
40+
%n_temp = add i32 %n_temp1, 1
41+
%cmp2 = icmp eq i32 %n_temp, 1
42+
br i1 %cmp2, label %outer.latch, label %inner.header
43+
44+
outer.latch:
45+
%m_temp = add i32 %n, 1
46+
%cmp3 = icmp eq i32 %m_temp, 1
47+
br i1 %cmp3, label %exit, label %outer.header
48+
49+
exit:
50+
ret void
51+
}
52+

llvm/test/Transforms/LoopInterchange/pr43326-ideal-access-pattern.ll

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,14 @@
1414
; }
1515
; }
1616

17+
; REMARKS: --- !Analysis
18+
; REMARKS-NEXT: Pass: loop-interchange
19+
; REMARKS-NEXT: Name: Dependence
20+
; REMARKS-NEXT: Function: pr43326-triply-nested
21+
; REMARKS-NEXT: Args:
22+
; REMARKS-NEXT: - String: Computed dependence info, invoking the transform.
23+
; REMARKS-NEXT: ...
24+
1725
; REMARKS: --- !Passed
1826
; REMARKS-NEXT: Pass: loop-interchange
1927
; REMARKS-NEXT: Name: Interchanged

llvm/test/Transforms/LoopInterchange/pr43326.ll

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,14 @@
88
@d = global i32 0
99
@e = global [1 x [1 x i32]] zeroinitializer
1010

11+
; REMARKS: --- !Analysis
12+
; REMARKS-NEXT: Pass: loop-interchange
13+
; REMARKS-NEXT: Name: Dependence
14+
; REMARKS-NEXT: Function: pr43326
15+
; REMARKS-NEXT: Args:
16+
; REMARKS-NEXT: - String: Computed dependence info, invoking the transform.
17+
; REMARKS-NEXT: ...
18+
1119
; REMARKS: --- !Passed
1220
; REMARKS-NEXT: Pass: loop-interchange
1321
; REMARKS-NEXT: Name: Interchanged

llvm/test/Transforms/LoopInterchange/pr48212.ll

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,14 @@
22
; RUN: -verify-dom-info -verify-loop-info -verify-loop-lcssa 2>&1
33
; RUN: FileCheck --input-file=%t --check-prefix=REMARKS %s
44

5+
; REMARKS: --- !Analysis
6+
; REMARKS-NEXT: Pass: loop-interchange
7+
; REMARKS-NEXT: Name: Dependence
8+
; REMARKS-NEXT: Function: pr48212
9+
; REMARKS-NEXT: Args:
10+
; REMARKS-NEXT: - String: Computed dependence info, invoking the transform.
11+
; REMARKS-NEXT: ...
12+
513
; REMARKS: --- !Passed
614
; REMARKS-NEXT: Pass: loop-interchange
715
; REMARKS-NEXT: Name: Interchanged

llvm/test/Transforms/LoopInterchange/reductions-across-inner-and-outer-loop.ll

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,14 @@
55

66
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
77

8+
; REMARKS: --- !Analysis
9+
; REMARKS-NEXT: Pass: loop-interchange
10+
; REMARKS-NEXT: Name: Dependence
11+
; REMARKS-NEXT: Function: test1
12+
; REMARKS-NEXT: Args:
13+
; REMARKS-NEXT: - String: Computed dependence info, invoking the transform.
14+
; REMARKS-NEXT: ...
15+
816
; REMARKS: --- !Passed
917
; REMARKS-NEXT: Pass: loop-interchange
1018
; REMARKS-NEXT: Name: Interchanged
@@ -77,6 +85,14 @@ for1.loopexit: ; preds = %for1.inc
7785

7886
; In this test case, the inner reduction PHI %inner does not involve the outer
7987
; reduction PHI %sum.outer, do not interchange.
88+
; REMARKS: --- !Analysis
89+
; REMARKS-NEXT: Pass: loop-interchange
90+
; REMARKS-NEXT: Name: Dependence
91+
; REMARKS-NEXT: Function: test2
92+
; REMARKS-NEXT: Args:
93+
; REMARKS-NEXT: - String: Computed dependence info, invoking the transform.
94+
; REMARKS-NEXT: ...
95+
8096
; REMARKS: --- !Missed
8197
; REMARKS-NEXT: Pass: loop-interchange
8298
; REMARKS-NEXT: Name: UnsupportedPHIOuter
@@ -114,6 +130,14 @@ for1.loopexit: ; preds = %for1.inc
114130

115131
; Check that we do not interchange if there is an additional instruction
116132
; between the outer and inner reduction PHIs.
133+
; REMARKS: --- !Analysis
134+
; REMARKS-NEXT: Pass: loop-interchange
135+
; REMARKS-NEXT: Name: Dependence
136+
; REMARKS-NEXT: Function: test3
137+
; REMARKS-NEXT: Args:
138+
; REMARKS-NEXT: - String: Computed dependence info, invoking the transform.
139+
; REMARKS-NEXT: ...
140+
117141
; REMARKS: --- !Missed
118142
; REMARKS-NEXT: Pass: loop-interchange
119143
; REMARKS-NEXT: Name: UnsupportedPHIOuter
@@ -151,6 +175,14 @@ for1.loopexit: ; preds = %for1.inc
151175
}
152176

153177
; Check that we do not interchange if reduction is stored in an invariant address inside inner loop
178+
; REMARKS: --- !Analysis
179+
; REMARKS-NEXT: Pass: loop-interchange
180+
; REMARKS-NEXT: Name: Dependence
181+
; REMARKS-NEXT: Function: test4
182+
; REMARKS-NEXT: Args:
183+
; REMARKS-NEXT: - String: Computed dependence info, invoking the transform.
184+
; REMARKS-NEXT: ...
185+
154186
; REMARKS: --- !Missed
155187
; REMARKS-NEXT: Pass: loop-interchange
156188
; REMARKS-NEXT: Name: Dependence
@@ -190,6 +222,14 @@ for1.loopexit: ; preds = %for1.inc
190222

191223
; Check that we do not interchange or crash if the PHI in the outer loop gets a
192224
; constant from the inner loop.
225+
; REMARKS: --- !Analysis
226+
; REMARKS-NEXT: Pass: loop-interchange
227+
; REMARKS-NEXT: Name: Dependence
228+
; REMARKS-NEXT: Function: test_constant_inner_loop_res
229+
; REMARKS-NEXT: Args:
230+
; REMARKS-NEXT: - String: Computed dependence info, invoking the transform.
231+
; REMARKS-NEXT: ...
232+
193233
; REMARKS: --- !Missed
194234
; REMARKS-NEXT: Pass: loop-interchange
195235
; REMARKS-NEXT: Name: UnsupportedPHIOuter
@@ -229,6 +269,14 @@ for1.loopexit: ; preds = %for1.inc
229269

230270
; Floating point reductions are interchanged if all the fp instructions
231271
; involved allow reassociation.
272+
; REMARKS: --- !Analysis
273+
; REMARKS-NEXT: Pass: loop-interchange
274+
; REMARKS-NEXT: Name: Dependence
275+
; REMARKS-NEXT: Function: test5
276+
; REMARKS-NEXT: Args:
277+
; REMARKS-NEXT: - String: Computed dependence info, invoking the transform.
278+
; REMARKS-NEXT: ...
279+
232280
; REMARKS: --- !Passed
233281
; REMARKS-NEXT: Pass: loop-interchange
234282
; REMARKS-NEXT: Name: Interchanged
@@ -269,6 +317,14 @@ for.exit: ; preds = %outer.inc
269317

270318
; Floating point reductions are not interchanged if not all the fp instructions
271319
; involved allow reassociation.
320+
; REMARKS: --- !Analysis
321+
; REMARKS-NEXT: Pass: loop-interchange
322+
; REMARKS-NEXT: Name: Dependence
323+
; REMARKS-NEXT: Function: test6
324+
; REMARKS-NEXT: Args:
325+
; REMARKS-NEXT: - String: Computed dependence info, invoking the transform.
326+
; REMARKS-NEXT: ...
327+
272328
; REMARKS: --- !Missed
273329
; REMARKS-NEXT: Pass: loop-interchange
274330
; REMARKS-NEXT: Name: UnsupportedPHIOuter

0 commit comments

Comments
 (0)