[llvm] [LoopInfo] Preserve profile information in makeLoopInvariant (PR #174171)

Aiden Grossman via llvm-commits llvm-commits at lists.llvm.org
Sat Feb 21 15:44:57 PST 2026


https://github.com/boomanaiden154 updated https://github.com/llvm/llvm-project/pull/174171

>From 2cee2e3482f272910b0c1e1643a21f7603588321 Mon Sep 17 00:00:00 2001
From: Aiden Grossman <aidengrossman at google.com>
Date: Fri, 2 Jan 2026 01:15:29 +0000
Subject: [PATCH 1/4] [LoopInfo] Preserve profile information in
 makeLoopInvariant

When hoisting loop invariant instructions, we can preserve profile
metadata because it depends solely on the condition (which is loop
invariant) rather than where we are in the control flow graph.
---
 llvm/lib/Analysis/LoopInfo.cpp                    | 13 +++++++++++--
 .../invalidate-scev-after-hoisting.ll             | 15 +++++++++++----
 llvm/utils/profcheck-xfail.txt                    |  1 -
 3 files changed, 22 insertions(+), 7 deletions(-)

diff --git a/llvm/lib/Analysis/LoopInfo.cpp b/llvm/lib/Analysis/LoopInfo.cpp
index d84721b7f8f4b..a780f3231a546 100644
--- a/llvm/lib/Analysis/LoopInfo.cpp
+++ b/llvm/lib/Analysis/LoopInfo.cpp
@@ -54,6 +54,10 @@ static cl::opt<bool, true>
     VerifyLoopInfoX("verify-loop-info", cl::location(VerifyLoopInfo),
                     cl::Hidden, cl::desc("Verify loop info (time consuming)"));
 
+namespace llvm {
+extern cl::opt<bool> ProfcheckDisableMetadataFixes;
+} // end namespace llvm
+
 //===----------------------------------------------------------------------===//
 // Loop implementation
 //
@@ -112,8 +116,13 @@ bool Loop::makeLoopInvariant(Instruction *I, bool &Changed,
   // There is possibility of hoisting this instruction above some arbitrary
   // condition. Any metadata defined on it can be control dependent on this
   // condition. Conservatively strip it here so that we don't give any wrong
-  // information to the optimizer.
-  I->dropUnknownNonDebugMetadata();
+  // information to the optimizer. We preserve profile metadata as instructions
+  // that can take profile metadata (select and br) with loop invariant
+  // conditions will maintain their weights.
+  if (ProfcheckDisableMetadataFixes)
+    I->dropUnknownNonDebugMetadata();
+  else
+    I->dropUnknownNonDebugMetadata({LLVMContext::MD_prof});
 
   if (SE)
     SE->forgetBlockAndLoopDispositions(I);
diff --git a/llvm/test/Transforms/LoopDeletion/invalidate-scev-after-hoisting.ll b/llvm/test/Transforms/LoopDeletion/invalidate-scev-after-hoisting.ll
index bdd51c2b6bc53..79c3773ebb686 100644
--- a/llvm/test/Transforms/LoopDeletion/invalidate-scev-after-hoisting.ll
+++ b/llvm/test/Transforms/LoopDeletion/invalidate-scev-after-hoisting.ll
@@ -1,4 +1,4 @@
-; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --check-globals
 ; RUN: opt -passes='loop(indvars,loop-deletion),verify<scalar-evolution>,print<scalar-evolution>' -S %s 2>&1| FileCheck %s
 
 ; Make sure the SCEV for %invar is invalidated properly when the instruction is
@@ -123,13 +123,13 @@ outer.latch:
   br label %outer.header
 }
 
-define void @test_pr58314() {
+define void @test_pr58314() !prof !0 {
 ; CHECK-LABEL: @test_pr58314(
 ; CHECK-NEXT:  entry:
 ; CHECK-NEXT:    br label [[OUTER_HEADER:%.*]]
 ; CHECK:       outer.header:
 ; CHECK-NEXT:    [[C:%.*]] = icmp ne i16 0, 0
-; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[C]], i1 false, i1 true
+; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[C]], i1 false, i1 true, !prof [[PROF1:![0-9]+]]
 ; CHECK-NEXT:    br label [[INNER:%.*]]
 ; CHECK:       inner:
 ; CHECK-NEXT:    br i1 true, label [[INNER]], label [[OUTER_LATCH:%.*]]
@@ -147,7 +147,7 @@ outer.header:
 
 inner:
   %c = icmp ne i16 0, 0
-  %sel = select i1 %c, i1 false, i1 true
+  %sel = select i1 %c, i1 false, i1 true, !prof !1
   br i1 true, label %inner, label %outer.latch
 
 outer.latch:
@@ -156,3 +156,10 @@ outer.latch:
 exit:
   ret void
 }
+
+!0 = !{!"function_entry_count", i64 1000}
+!1 = !{!"branch_weights", i32 4, i32 1}
+;.
+; CHECK: [[META0:![0-9]+]] = !{!"function_entry_count", i64 1000}
+; CHECK: [[PROF1]] = !{!"branch_weights", i32 4, i32 1}
+;.
diff --git a/llvm/utils/profcheck-xfail.txt b/llvm/utils/profcheck-xfail.txt
index beffde14d5f8b..56612973f9574 100644
--- a/llvm/utils/profcheck-xfail.txt
+++ b/llvm/utils/profcheck-xfail.txt
@@ -454,7 +454,6 @@ Transforms/IROutliner/region-inputs-in-phi-nodes.ll
 Transforms/LoopBoundSplit/bug51866.ll
 Transforms/LoopBoundSplit/bug-loop-bound-split-phi-in-exit-block.ll
 Transforms/LoopBoundSplit/loop-bound-split.ll
-Transforms/LoopDeletion/invalidate-scev-after-hoisting.ll
 Transforms/LoopIdiom/AArch64/byte-compare-index.ll
 Transforms/LoopIdiom/AArch64/find-first-byte.ll
 Transforms/LoopIdiom/RISCV/byte-compare-index.ll

>From e0897f4f5222ce35c0d7762d0b6204f91412daa8 Mon Sep 17 00:00:00 2001
From: Aiden Grossman <aidengrossman at google.com>
Date: Sat, 21 Feb 2026 23:25:08 +0000
Subject: [PATCH 2/4] feedback

---
 llvm/lib/Analysis/LoopInfo.cpp                | 27 +++++++++----
 .../Transforms/LoopSimplify/profile-info.ll   | 40 +++++++++++++++++++
 2 files changed, 60 insertions(+), 7 deletions(-)
 create mode 100644 llvm/test/Transforms/LoopSimplify/profile-info.ll

diff --git a/llvm/lib/Analysis/LoopInfo.cpp b/llvm/lib/Analysis/LoopInfo.cpp
index a4010aceff150..97695cb0d1190 100644
--- a/llvm/lib/Analysis/LoopInfo.cpp
+++ b/llvm/lib/Analysis/LoopInfo.cpp
@@ -34,6 +34,7 @@
 #include "llvm/IR/Module.h"
 #include "llvm/IR/PassManager.h"
 #include "llvm/IR/PrintPasses.h"
+#include "llvm/IR/ProfDataUtils.h"
 #include "llvm/InitializePasses.h"
 #include "llvm/Support/CommandLine.h"
 #include "llvm/Support/Compiler.h"
@@ -83,6 +84,7 @@ bool Loop::makeLoopInvariant(Value *V, bool &Changed, Instruction *InsertPt,
 bool Loop::makeLoopInvariant(Instruction *I, bool &Changed,
                              Instruction *InsertPt, MemorySSAUpdater *MSSAU,
                              ScalarEvolution *SE) const {
+  BasicBlock* OriginalParent = I->getParent();
   // Test if the value is already loop-invariant.
   if (isLoopInvariant(I))
     return true;
@@ -113,16 +115,27 @@ bool Loop::makeLoopInvariant(Instruction *I, bool &Changed,
       MSSAU->moveToPlace(MUD, InsertPt->getParent(),
                          MemorySSA::BeforeTerminator);
 
+  // We want to preserve profile metadata if possible. However, we need to
+  // ensure that profile metadata would remain the same outside of the loop.
+  // Given at this point we know the conditional is loop-invariant, we just
+  // need to worry about other control flow in the loop conditioned on values
+  // that are potentially not independent of the condition of the instruction
+  // we are interested in hoisting. Given this is not knowable in the general
+  // case, we only hoist from a loop header or unique latch (constitutes the
+  // majority of cases), where we are guaranteed to not run into problems.
+  SmallVector<unsigned, 1> ProfileMetadataToPreserve;
+  if (!ProfcheckDisableMetadataFixes)
+    if (OriginalParent == getHeader() || OriginalParent == getLoopLatch())
+      ProfileMetadataToPreserve.push_back(LLVMContext::MD_prof);
+
   // There is possibility of hoisting this instruction above some arbitrary
   // condition. Any metadata defined on it can be control dependent on this
   // condition. Conservatively strip it here so that we don't give any wrong
-  // information to the optimizer. We preserve profile metadata as instructions
-  // that can take profile metadata (select and br) with loop invariant
-  // conditions will maintain their weights.
-  if (ProfcheckDisableMetadataFixes)
-    I->dropUnknownNonDebugMetadata();
-  else
-    I->dropUnknownNonDebugMetadata({LLVMContext::MD_prof});
+  // information to the optimizer.
+  I->dropUnknownNonDebugMetadata(ProfileMetadataToPreserve);
+  
+  if (ProfileMetadataToPreserve.empty() && isa<SelectInst>(I))
+    setExplicitlyUnknownBranchWeightsIfProfiled(*I, "LoopInfo");
 
   if (SE)
     SE->forgetBlockAndLoopDispositions(I);
diff --git a/llvm/test/Transforms/LoopSimplify/profile-info.ll b/llvm/test/Transforms/LoopSimplify/profile-info.ll
new file mode 100644
index 0000000000000..d46fba37026b6
--- /dev/null
+++ b/llvm/test/Transforms/LoopSimplify/profile-info.ll
@@ -0,0 +1,40 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6
+; RUN: opt -passes="loop-simplify" -S %s | FileCheck %s
+
+define void @test_drop(i8 %a) !prof !0 {
+; CHECK-LABEL: define void @test_drop(
+; CHECK-SAME: i8 [[A:%.*]]) !prof [[PROF0]] {
+; CHECK-NEXT:  [[HEADER_BACKEDGE2:.*:]]
+; CHECK-NEXT:    [[S:%.*]] = select i1 true, i1 true, i1 false, !prof [[PROF2:![0-9]+]]
+; CHECK-NEXT:    br label %[[HEADER:.*]]
+; CHECK:       [[HEADER]]:
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i8 [[A]], 0
+; CHECK-NEXT:    [[OR_COND:%.*]] = select i1 true, i1 [[CMP]], i1 false
+; CHECK-NEXT:    br i1 [[OR_COND]], label %[[EXIT:.*]], label %[[HEADER_BACKEDGE:.*]]
+; CHECK:       [[HEADER_BACKEDGE]]:
+; CHECK-NEXT:    br label %[[HEADER]]
+; CHECK:       [[EXIT]]:
+; CHECK-NEXT:    ret void
+;
+entry:
+  br label %header
+
+header:
+  br i1 false, label %header, label %body
+
+body:
+  %s = select i1 true, i1 true, i1 false, !prof !1
+  %cmp = icmp eq i8 %a, 0
+  br i1 %cmp, label %exit, label %header
+
+exit:
+  ret void
+}
+
+!0 = !{!"function_entry_count", i64 1000}
+!1 = !{!"branch_weights", i32 4, i32 1}
+;.
+; CHECK: [[PROF0]] = !{!"function_entry_count", i64 1000}
+; CHECK: [[PROF1]] = !{!"branch_weights", i32 4, i32 1}
+; CHECK: [[PROF2]] = !{!"unknown", !"LoopInfo"}
+;.

>From 773a8a2d647f2b9e9f52b2597bca92416d4f3fc8 Mon Sep 17 00:00:00 2001
From: Aiden Grossman <aidengrossman at google.com>
Date: Sat, 21 Feb 2026 23:41:38 +0000
Subject: [PATCH 3/4] Formatting

---
 llvm/lib/Analysis/LoopInfo.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/llvm/lib/Analysis/LoopInfo.cpp b/llvm/lib/Analysis/LoopInfo.cpp
index 97695cb0d1190..1d7fda4887794 100644
--- a/llvm/lib/Analysis/LoopInfo.cpp
+++ b/llvm/lib/Analysis/LoopInfo.cpp
@@ -84,7 +84,7 @@ bool Loop::makeLoopInvariant(Value *V, bool &Changed, Instruction *InsertPt,
 bool Loop::makeLoopInvariant(Instruction *I, bool &Changed,
                              Instruction *InsertPt, MemorySSAUpdater *MSSAU,
                              ScalarEvolution *SE) const {
-  BasicBlock* OriginalParent = I->getParent();
+  BasicBlock *OriginalParent = I->getParent();
   // Test if the value is already loop-invariant.
   if (isLoopInvariant(I))
     return true;
@@ -133,7 +133,7 @@ bool Loop::makeLoopInvariant(Instruction *I, bool &Changed,
   // condition. Conservatively strip it here so that we don't give any wrong
   // information to the optimizer.
   I->dropUnknownNonDebugMetadata(ProfileMetadataToPreserve);
-  
+
   if (ProfileMetadataToPreserve.empty() && isa<SelectInst>(I))
     setExplicitlyUnknownBranchWeightsIfProfiled(*I, "LoopInfo");
 

>From a8a725bbf9b43b4bfd5443738289a6d882219470 Mon Sep 17 00:00:00 2001
From: Aiden Grossman <aidengrossman at google.com>
Date: Sat, 21 Feb 2026 23:44:06 +0000
Subject: [PATCH 4/4] fix test

---
 llvm/test/Transforms/LoopSimplify/profile-info.ll | 7 +++----
 1 file changed, 3 insertions(+), 4 deletions(-)

diff --git a/llvm/test/Transforms/LoopSimplify/profile-info.ll b/llvm/test/Transforms/LoopSimplify/profile-info.ll
index d46fba37026b6..409556646e64d 100644
--- a/llvm/test/Transforms/LoopSimplify/profile-info.ll
+++ b/llvm/test/Transforms/LoopSimplify/profile-info.ll
@@ -3,9 +3,9 @@
 
 define void @test_drop(i8 %a) !prof !0 {
 ; CHECK-LABEL: define void @test_drop(
-; CHECK-SAME: i8 [[A:%.*]]) !prof [[PROF0]] {
+; CHECK-SAME: i8 [[A:%.*]]) !prof [[PROF0:![0-9]+]] {
 ; CHECK-NEXT:  [[HEADER_BACKEDGE2:.*:]]
-; CHECK-NEXT:    [[S:%.*]] = select i1 true, i1 true, i1 false, !prof [[PROF2:![0-9]+]]
+; CHECK-NEXT:    [[S:%.*]] = select i1 true, i1 true, i1 false, !prof [[PROF1:![0-9]+]]
 ; CHECK-NEXT:    br label %[[HEADER:.*]]
 ; CHECK:       [[HEADER]]:
 ; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i8 [[A]], 0
@@ -35,6 +35,5 @@ exit:
 !1 = !{!"branch_weights", i32 4, i32 1}
 ;.
 ; CHECK: [[PROF0]] = !{!"function_entry_count", i64 1000}
-; CHECK: [[PROF1]] = !{!"branch_weights", i32 4, i32 1}
-; CHECK: [[PROF2]] = !{!"unknown", !"LoopInfo"}
+; CHECK: [[PROF1]] = !{!"unknown", !"LoopInfo"}
 ;.



More information about the llvm-commits mailing list