Skip to content

Commit 47051ce

Browse files
committed
Merge branch 'pgo-estimated-trip-count' into fix-peel-branch-weights
2 parents 83531b3 + 59cd184 commit 47051ce

File tree

3 files changed

+97
-19
lines changed

3 files changed

+97
-19
lines changed

llvm/include/llvm/Transforms/Utils/LoopUtils.h

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -324,12 +324,12 @@ LLVM_ABI void addStringMetadataToLoop(Loop *TheLoop, const char *MDString,
324324
unsigned V = 0);
325325

326326
/// Return either:
327+
/// - \c std::nullopt, if the implementation is unable to handle the loop form
328+
/// of \p L (e.g., \p L must have a latch block that controls the loop exit).
327329
/// - The value of \c llvm.loop.estimated_trip_count from the loop metadata of
328330
/// \p L, if that metadata is present.
329331
/// - Else, a new estimate of the trip count from the latch branch weights of
330-
/// \p L, if the estimation's implementation is able to handle the loop form
331-
/// of \p L (e.g., \p L must have a latch block that controls the loop exit).
332-
/// - Else, \c std::nullopt.
332+
/// \p L.
333333
///
334334
/// An estimated trip count is always a valid positive trip count, saturated at
335335
/// \c UINT_MAX.
@@ -350,17 +350,15 @@ getLoopEstimatedTripCount(Loop *L,
350350
unsigned *EstimatedLoopInvocationWeight = nullptr);
351351

352352
/// Set \c llvm.loop.estimated_trip_count with the value \p EstimatedTripCount
353-
/// in the loop metadata of \p L.
353+
/// in the loop metadata of \p L. Return false if the implementation is unable
354+
/// to handle the loop form of \p L (e.g., \p L must have a latch block that
355+
/// controls the loop exit). Otherwise, return true.
354356
///
355357
/// In addition, if \p EstimatedLoopInvocationWeight, set the branch weight
356358
/// metadata of \p L to reflect that \p L has an estimated
357359
/// \p EstimatedTripCount iterations and has \c *EstimatedLoopInvocationWeight
358360
/// exit weight through the loop's latch.
359361
///
360-
/// Return false if \p EstimatedLoopInvocationWeight and if branch weight
361-
/// metadata could not be successfully updated (e.g., if \p L does not have a
362-
/// latch block that controls the loop exit). Otherwise, return true.
363-
///
364362
/// TODO: Eventually, once all passes have migrated away from setting branch
365363
/// weights to indicate estimated trip counts, this function will drop the
366364
/// \p EstimatedLoopInvocationWeight parameter.

llvm/lib/Transforms/Utils/LoopUtils.cpp

Lines changed: 38 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -868,23 +868,42 @@ static std::optional<unsigned> estimateLoopTripCount(Loop *L) {
868868
std::optional<unsigned>
869869
llvm::getLoopEstimatedTripCount(Loop *L,
870870
unsigned *EstimatedLoopInvocationWeight) {
871+
// If EstimatedLoopInvocationWeight, we do not support this loop if
872+
// getExpectedExitLoopLatchBranch returns nullptr.
873+
//
874+
// FIXME: Also, this is a stop-gap solution for nested loops. It avoids
875+
// mistaking LLVMLoopEstimatedTripCount metadata to be for an outer loop when
876+
// it was created for an inner loop. The problem is that loop metadata is
877+
// attached to the branch instruction in the loop latch block, but that can be
878+
// shared by the loops. The solution is to attach loop metadata to loop
879+
// headers instead, but that would be a large change to LLVM.
880+
//
881+
// Until that happens, we work around the problem as follows.
882+
// getExpectedExitLoopLatchBranch (which also guards
883+
// setLoopEstimatedTripCount) will not recognize the same latch for both loops
884+
// unless the latch exits both loops and has only two successors. However, to
885+
// exit both loops, the latch must have at least three successors: the inner
886+
// loop header, the outer loop header (exit for the inner loop), and an exit
887+
// for the outer loop.
888+
BranchInst *ExitingBranch = getExpectedExitLoopLatchBranch(L);
889+
if (!ExitingBranch)
890+
return std::nullopt;
891+
871892
// If requested, either compute *EstimatedLoopInvocationWeight or return
872893
// nullopt if cannot.
873894
//
874895
// TODO: Eventually, once all passes have migrated away from setting branch
875896
// weights to indicate estimated trip counts, this function will drop the
876897
// EstimatedLoopInvocationWeight parameter.
877898
if (EstimatedLoopInvocationWeight) {
878-
if (BranchInst *ExitingBranch = getExpectedExitLoopLatchBranch(L)) {
879-
uint64_t LoopWeight = 0, ExitWeight = 0; // Inits expected to be unused.
880-
if (!extractBranchWeights(*ExitingBranch, LoopWeight, ExitWeight))
881-
return std::nullopt;
882-
if (L->contains(ExitingBranch->getSuccessor(1)))
883-
std::swap(LoopWeight, ExitWeight);
884-
if (!ExitWeight)
885-
return std::nullopt;
886-
*EstimatedLoopInvocationWeight = ExitWeight;
887-
}
899+
uint64_t LoopWeight = 0, ExitWeight = 0; // Inits expected to be unused.
900+
if (!extractBranchWeights(*ExitingBranch, LoopWeight, ExitWeight))
901+
return std::nullopt;
902+
if (L->contains(ExitingBranch->getSuccessor(1)))
903+
std::swap(LoopWeight, ExitWeight);
904+
if (!ExitWeight)
905+
return std::nullopt;
906+
*EstimatedLoopInvocationWeight = ExitWeight;
888907
}
889908

890909
// Return the estimated trip count from metadata unless the metadata is
@@ -903,6 +922,15 @@ llvm::getLoopEstimatedTripCount(Loop *L,
903922
bool llvm::setLoopEstimatedTripCount(
904923
Loop *L, unsigned EstimatedTripCount,
905924
std::optional<unsigned> EstimatedloopInvocationWeight) {
925+
// If EstimatedLoopInvocationWeight, we do not support this loop if
926+
// getExpectedExitLoopLatchBranch returns nullptr.
927+
//
928+
// FIXME: See comments in getLoopEstimatedTripCount for why this is required
929+
// here regardless of EstimatedLoopInvocationWeight.
930+
BranchInst *LatchBranch = getExpectedExitLoopLatchBranch(L);
931+
if (!LatchBranch)
932+
return false;
933+
906934
// Set the metadata.
907935
addStringMetadataToLoop(L, LLVMLoopEstimatedTripCount, EstimatedTripCount);
908936

@@ -915,7 +943,6 @@ bool llvm::setLoopEstimatedTripCount(
915943
// here at all.
916944
if (!EstimatedloopInvocationWeight)
917945
return true;
918-
BranchInst *LatchBranch = getExpectedExitLoopLatchBranch(L);
919946
if (!LatchBranch)
920947
return false;
921948

llvm/unittests/Transforms/Utils/LoopUtilsTest.cpp

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,3 +142,56 @@ TEST(LoopUtils, IsKnownNonPositiveInLoopTest) {
142142
EXPECT_EQ(isKnownNonPositiveInLoop(ArgSCEV, L, SE), true);
143143
});
144144
}
145+
146+
// The inner and outer loop here share a latch. Because any loop metadata must
147+
// be attached to that latch, loop metadata cannot distinguish between the two
148+
// loops. Until that problem is solved (by moving loop metadata to loops'
149+
// header blocks instead), getLoopEstimatedTripCount and
150+
// setLoopEstimatedTripCount must refuse to operate on at least one of the two
151+
// loops. They choose to reject the outer loop here because the latch does not
152+
// exit it.
153+
TEST(LoopUtils, nestedLoopSharedLatchEstimatedTripCount) {
154+
LLVMContext C;
155+
std::unique_ptr<Module> M =
156+
parseIR(C, "declare i1 @f()\n"
157+
"declare i1 @g()\n"
158+
"define void @foo() {\n"
159+
"entry:\n"
160+
" br label %outer\n"
161+
"outer:\n"
162+
" %c0 = call i1 @f()"
163+
" br i1 %c0, label %inner, label %exit, !prof !0\n"
164+
"inner:\n"
165+
" %c1 = call i1 @g()"
166+
" br i1 %c1, label %inner, label %outer, !prof !1\n"
167+
"exit:\n"
168+
" ret void\n"
169+
"}\n"
170+
"!0 = !{!\"branch_weights\", i32 100, i32 1}\n"
171+
"!1 = !{!\"branch_weights\", i32 4, i32 1}\n"
172+
"\n");
173+
174+
run(*M, "foo",
175+
[&](Function &F, DominatorTree &DT, ScalarEvolution &SE, LoopInfo &LI) {
176+
assert(LI.end() - LI.begin() == 1 && "Expected one outer loop");
177+
Loop *Outer = *LI.begin();
178+
assert(Outer->end() - Outer->begin() == 1 && "Expected one inner loop");
179+
Loop *Inner = *Outer->begin();
180+
181+
// Even before llvm.loop.estimated_trip_count is added to either loop,
182+
// getLoopEstimatedTripCount rejects the outer loop.
183+
EXPECT_EQ(getLoopEstimatedTripCount(Inner), 5);
184+
EXPECT_EQ(getLoopEstimatedTripCount(Outer), std::nullopt);
185+
186+
// setLoopEstimatedTripCount for the inner loop does not affect
187+
// getLoopEstimatedTripCount for the outer loop.
188+
EXPECT_EQ(setLoopEstimatedTripCount(Inner, 100), true);
189+
EXPECT_EQ(getLoopEstimatedTripCount(Inner), 100);
190+
EXPECT_EQ(getLoopEstimatedTripCount(Outer), std::nullopt);
191+
192+
// setLoopEstimatedTripCount rejects the outer loop.
193+
EXPECT_EQ(setLoopEstimatedTripCount(Outer, 999), false);
194+
EXPECT_EQ(getLoopEstimatedTripCount(Inner), 100);
195+
EXPECT_EQ(getLoopEstimatedTripCount(Outer), std::nullopt);
196+
});
197+
}

0 commit comments

Comments
 (0)