[llvm] [profcheck] Require `unknown` metadata have a origin parameter (PR #157594)

Mircea Trofin via llvm-commits llvm-commits at lists.llvm.org
Mon Sep 8 19:56:20 PDT 2025


https://github.com/mtrofin created https://github.com/llvm/llvm-project/pull/157594

None

>From afcef0d82f434274f95951fa578e5156fb201371 Mon Sep 17 00:00:00 2001
From: Mircea Trofin <mtrofin at google.com>
Date: Tue, 9 Sep 2025 02:46:36 +0000
Subject: [PATCH] [profcheck] Require `unknown` metadata have a origin
 parameter

---
 llvm/include/llvm/IR/ProfDataUtils.h          |  9 +++--
 llvm/lib/IR/ProfDataUtils.cpp                 | 12 +++---
 llvm/lib/IR/Verifier.cpp                      | 25 ++++++++----
 .../lib/Transforms/IPO/WholeProgramDevirt.cpp |  2 +-
 .../Transforms/Scalar/JumpTableToSwitch.cpp   |  2 +-
 .../Transforms/JumpTableToSwitch/basic.ll     |  2 +-
 .../PGOProfile/prof-inject-existing.ll        |  4 +-
 .../PGOProfile/prof-verify-existing.ll        |  4 +-
 .../branch-funnel-profile.ll                  |  4 +-
 llvm/test/Verifier/branch-weight.ll           | 38 ++++++++++++++++---
 10 files changed, 73 insertions(+), 29 deletions(-)

diff --git a/llvm/include/llvm/IR/ProfDataUtils.h b/llvm/include/llvm/IR/ProfDataUtils.h
index b8386ddc86ca8..61434735506f9 100644
--- a/llvm/include/llvm/IR/ProfDataUtils.h
+++ b/llvm/include/llvm/IR/ProfDataUtils.h
@@ -177,12 +177,15 @@ inline uint32_t scaleBranchCount(uint64_t Count, uint64_t Scale) {
 /// do not accidentally drop profile info, and this API is called in cases where
 /// the pass explicitly cannot provide that info. Defaulting it in would hide
 /// bugs where the pass forgets to transfer over or otherwise specify profile
-/// info.
-LLVM_ABI void setExplicitlyUnknownBranchWeights(Instruction &I);
+/// info. Use `PassName` to capture the pass name (i.e. DEBUG_TYPE) for
+/// debuggability.
+LLVM_ABI void setExplicitlyUnknownBranchWeights(Instruction &I,
+                                                StringRef PassName);
 
 /// Analogous to setExplicitlyUnknownBranchWeights, but for functions and their
 /// entry counts.
-LLVM_ABI void setExplicitlyUnknownFunctionEntryCount(Function &F);
+LLVM_ABI void setExplicitlyUnknownFunctionEntryCount(Function &F,
+                                                     StringRef PassName);
 
 LLVM_ABI bool isExplicitlyUnknownProfileMetadata(const MDNode &MD);
 LLVM_ABI bool hasExplicitlyUnknownBranchWeights(const Instruction &I);
diff --git a/llvm/lib/IR/ProfDataUtils.cpp b/llvm/lib/IR/ProfDataUtils.cpp
index b41256f599096..d0b91d9356613 100644
--- a/llvm/lib/IR/ProfDataUtils.cpp
+++ b/llvm/lib/IR/ProfDataUtils.cpp
@@ -242,24 +242,26 @@ bool extractProfTotalWeight(const Instruction &I, uint64_t &TotalVal) {
   return extractProfTotalWeight(I.getMetadata(LLVMContext::MD_prof), TotalVal);
 }
 
-void setExplicitlyUnknownBranchWeights(Instruction &I) {
+void setExplicitlyUnknownBranchWeights(Instruction &I, StringRef PassName) {
   MDBuilder MDB(I.getContext());
   I.setMetadata(
       LLVMContext::MD_prof,
       MDNode::get(I.getContext(),
-                  MDB.createString(MDProfLabels::UnknownBranchWeightsMarker)));
+                  {MDB.createString(MDProfLabels::UnknownBranchWeightsMarker),
+                   MDB.createString(PassName)}));
 }
 
-void setExplicitlyUnknownFunctionEntryCount(Function &F) {
+void setExplicitlyUnknownFunctionEntryCount(Function &F, StringRef PassName) {
   MDBuilder MDB(F.getContext());
   F.setMetadata(
       LLVMContext::MD_prof,
       MDNode::get(F.getContext(),
-                  MDB.createString(MDProfLabels::UnknownBranchWeightsMarker)));
+                  {MDB.createString(MDProfLabels::UnknownBranchWeightsMarker),
+                   MDB.createString(PassName)}));
 }
 
 bool isExplicitlyUnknownProfileMetadata(const MDNode &MD) {
-  if (MD.getNumOperands() != 1)
+  if (MD.getNumOperands() != 2)
     return false;
   return MD.getOperand(0).equalsStr(MDProfLabels::UnknownBranchWeightsMarker);
 }
diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp
index f38871f09f35f..51c9955e3e6d1 100644
--- a/llvm/lib/IR/Verifier.cpp
+++ b/llvm/lib/IR/Verifier.cpp
@@ -631,7 +631,7 @@ class Verifier : public InstVisitor<Verifier>, VerifierSupport {
   void verifyFunctionAttrs(FunctionType *FT, AttributeList Attrs,
                            const Value *V, bool IsIntrinsic, bool IsInlineAsm);
   void verifyFunctionMetadata(ArrayRef<std::pair<unsigned, MDNode *>> MDs);
-
+  void verifyUnknownProfileMetadata(MDNode *MD);
   void visitConstantExprsRecursively(const Constant *EntryC);
   void visitConstantExpr(const ConstantExpr *CE);
   void visitConstantPtrAuth(const ConstantPtrAuth *CPA);
@@ -2515,19 +2515,31 @@ void Verifier::verifyFunctionAttrs(FunctionType *FT, AttributeList Attrs,
                   V);
   }
 }
+void Verifier::verifyUnknownProfileMetadata(MDNode *MD) {
+  Check(MD->getNumOperands() == 2,
+        "'unknown' !prof should have a single additional operand", MD);
+  auto *PassName = dyn_cast<MDString>(MD->getOperand(1));
+  Check(PassName != nullptr,
+        "'unknown' !prof should have an additional operand of type "
+        "string");
+  Check(!PassName->getString().empty(),
+        "the 'unknown' !prof operand should not be an empty string");
+}
 
 void Verifier::verifyFunctionMetadata(
     ArrayRef<std::pair<unsigned, MDNode *>> MDs) {
   for (const auto &Pair : MDs) {
     if (Pair.first == LLVMContext::MD_prof) {
       MDNode *MD = Pair.second;
+      Check(MD->getNumOperands() >= 2,
+            "!prof annotations should have no less than 2 operands", MD);
       // We may have functions that are synthesized by the compiler, e.g. in
       // WPD, that we can't currently determine the entry count.
-      if (isExplicitlyUnknownProfileMetadata(*MD))
+      if (MD->getOperand(0).equalsStr(
+              MDProfLabels::UnknownBranchWeightsMarker)) {
+        verifyUnknownProfileMetadata(MD);
         continue;
-
-      Check(MD->getNumOperands() >= 2,
-            "!prof annotations should have no less than 2 operands", MD);
+      }
 
       // Check first operand.
       Check(MD->getOperand(0) != nullptr, "first operand should not be null",
@@ -5054,8 +5066,7 @@ void Verifier::visitProfMetadata(Instruction &I, MDNode *MD) {
           "'unknown' !prof should only appear on instructions on which "
           "'branch_weights' would",
           MD);
-    Check(MD->getNumOperands() == 1,
-          "'unknown' !prof should have no additional operands", MD);
+    verifyUnknownProfileMetadata(MD);
     return;
   }
 
diff --git a/llvm/lib/Transforms/IPO/WholeProgramDevirt.cpp b/llvm/lib/Transforms/IPO/WholeProgramDevirt.cpp
index bfb25c806e53f..09bffa7bf5846 100644
--- a/llvm/lib/Transforms/IPO/WholeProgramDevirt.cpp
+++ b/llvm/lib/Transforms/IPO/WholeProgramDevirt.cpp
@@ -1495,7 +1495,7 @@ void DevirtModule::tryICallBranchFunnel(
 
   if (!JT->getEntryCount().has_value()) {
     // FIXME: we could pass through thinlto the necessary information.
-    setExplicitlyUnknownFunctionEntryCount(*JT);
+    setExplicitlyUnknownFunctionEntryCount(*JT, DEBUG_TYPE);
   }
 }
 
diff --git a/llvm/lib/Transforms/Scalar/JumpTableToSwitch.cpp b/llvm/lib/Transforms/Scalar/JumpTableToSwitch.cpp
index b0478ee1fd94e..2025fbbf05973 100644
--- a/llvm/lib/Transforms/Scalar/JumpTableToSwitch.cpp
+++ b/llvm/lib/Transforms/Scalar/JumpTableToSwitch.cpp
@@ -186,7 +186,7 @@ expandToSwitch(CallBase *CB, const JumpTableTy &JT, DomTreeUpdater &DTU,
     setBranchWeights(*Switch, downscaleWeights(BranchWeights),
                      /*IsExpected=*/false);
   } else
-    setExplicitlyUnknownBranchWeights(*Switch);
+    setExplicitlyUnknownBranchWeights(*Switch, DEBUG_TYPE);
   if (PHI)
     CB->replaceAllUsesWith(PHI);
   CB->eraseFromParent();
diff --git a/llvm/test/Transforms/JumpTableToSwitch/basic.ll b/llvm/test/Transforms/JumpTableToSwitch/basic.ll
index e3c032b9d4bf7..c6f59406f7337 100644
--- a/llvm/test/Transforms/JumpTableToSwitch/basic.ll
+++ b/llvm/test/Transforms/JumpTableToSwitch/basic.ll
@@ -286,7 +286,7 @@ define i32 @function_with_jump_table_addrspace_42(i32 %index) addrspace(42) {
 ; CHECK: [[META0]] = !{i64 5678}
 ; CHECK: [[META1]] = !{i64 5555}
 ; CHECK: [[PROF2]] = !{!"branch_weights", i32 0, i32 20, i32 5}
-; CHECK: [[PROF3]] = !{!"unknown"}
+; CHECK: [[PROF3]] = !{!"unknown", !"jump-table-to-switch"}
 ;.
 ; THRESHOLD-0: [[META0]] = !{i64 5678}
 ; THRESHOLD-0: [[META1]] = !{i64 5555}
diff --git a/llvm/test/Transforms/PGOProfile/prof-inject-existing.ll b/llvm/test/Transforms/PGOProfile/prof-inject-existing.ll
index f51ec17d9166a..d2c12fb2670f9 100644
--- a/llvm/test/Transforms/PGOProfile/prof-inject-existing.ll
+++ b/llvm/test/Transforms/PGOProfile/prof-inject-existing.ll
@@ -14,9 +14,9 @@ no:
 }
 
 !0 = !{!"branch_weights", i32 1, i32 2}
-!1 = !{!"unknown"}
+!1 = !{!"unknown", !"test"}
 ; CHECK: define void @foo(i32 %i) !prof !0
 ; CHECK: br i1 %c, label %yes, label %no, !prof !1
 ; CHECK: !0 = !{!"function_entry_count", i64 1000}
 ; CHECK: !1 = !{!"branch_weights", i32 1, i32 2}
-; CHECK: !2 = !{!"unknown"}
+; CHECK: !2 = !{!"unknown", !"test"}
diff --git a/llvm/test/Transforms/PGOProfile/prof-verify-existing.ll b/llvm/test/Transforms/PGOProfile/prof-verify-existing.ll
index 793b221c4ea66..c3f0f6d3e44b4 100644
--- a/llvm/test/Transforms/PGOProfile/prof-verify-existing.ll
+++ b/llvm/test/Transforms/PGOProfile/prof-verify-existing.ll
@@ -15,9 +15,9 @@ no:
 
 !0 = !{!"function_entry_count", i32 1}
 !1 = !{!"branch_weights", i32 1, i32 2}
-!2 = !{!"unknown"}
+!2 = !{!"unknown", !"test"}
 ; CHECK: define void @foo(i32 %i) !prof !0
 ; CHECK: br i1 %c, label %yes, label %no, !prof !1
 ; CHECK: !0 = !{!"function_entry_count", i64 1}
 ; CHECK: !1 = !{!"branch_weights", i32 1, i32 2}
-; CHECK: !2 = !{!"unknown"}
+; CHECK: !2 = !{!"unknown", !"test"}
diff --git a/llvm/test/Transforms/WholeProgramDevirt/branch-funnel-profile.ll b/llvm/test/Transforms/WholeProgramDevirt/branch-funnel-profile.ll
index dd1aa926de8a5..f1a28ca8d681c 100644
--- a/llvm/test/Transforms/WholeProgramDevirt/branch-funnel-profile.ll
+++ b/llvm/test/Transforms/WholeProgramDevirt/branch-funnel-profile.ll
@@ -17,7 +17,7 @@
 ; NORETP: define hidden void @__typeid_typeid1_rv_0_branch_funnel(ptr nest %0, ...) !prof !11
 ; NORETP: define internal void @branch_funnel(ptr nest %0, ...) !prof !11
 ; NORETP: define internal void @branch_funnel.1(ptr nest %0, ...) !prof !11
-; NORETP: !11 = !{!"unknown"}
+; NORETP: !11 = !{!"unknown", !"wholeprogramdevirt"}
 
 ; O3: define hidden void @__typeid_typeid1_0_branch_funnel(ptr nest %0, ...) local_unnamed_addr #5 !prof !11
 ; O3: define hidden void @__typeid_typeid1_rv_0_branch_funnel(ptr nest %0, ...) local_unnamed_addr #5 !prof !11
@@ -27,7 +27,7 @@
 ; O3: define hidden void @__typeid_typeid3_rv_0_branch_funnel(ptr nest %0, ...) local_unnamed_addr #5 !prof !12
 ; O3: !10 = !{!"function_entry_count", i64 1000}
 ; O3: !11 = !{!"function_entry_count", i64 3000}
-; O3: !12 = !{!"unknown"}
+; O3: !12 = !{!"unknown", !"wholeprogramdevirt"}
 
 target datalayout = "e-p:64:64"
 target triple = "x86_64-unknown-linux-gnu"
diff --git a/llvm/test/Verifier/branch-weight.ll b/llvm/test/Verifier/branch-weight.ll
index d4f92c191e231..62d5357ed6d2c 100644
--- a/llvm/test/Verifier/branch-weight.ll
+++ b/llvm/test/Verifier/branch-weight.ll
@@ -11,6 +11,8 @@
 ; RUN: opt -passes=verify %t/unknown-correct.ll --disable-output
 
 ; RUN: not opt -passes=verify %t/unknown-invalid.ll --disable-output 2>&1 | FileCheck %s --check-prefix=EXTRA-ARGS
+; RUN: not opt -passes=verify %t/unknown-noargs.ll --disable-output 2>&1 | FileCheck %s --check-prefix=NO-ARGS
+; RUN: not opt -passes=verify %t/unknown-empty.ll --disable-output 2>&1 | FileCheck %s --check-prefix=EMPTY-ARGS
 ; RUN: opt -passes=verify %t/unknown-on-function1.ll -S -o - | FileCheck %s --check-prefix=ON-FUNCTION1
 ; RUN: not opt -passes=verify %t/unknown-on-function2.ll --disable-output 2>&1 | FileCheck %s --check-prefix=ON-FUNCTION2
 ; RUN: not opt -passes=verify %t/invalid-unknown-placement.ll --disable-output 2>&1 | FileCheck %s --check-prefix=INVALID-UNKNOWN-PLACEMENT
@@ -111,7 +113,7 @@ exit:
   ret i32 %r
 }
 
-!0 = !{!"unknown"}
+!0 = !{!"unknown", !"test"}
 
 ;--- unknown-invalid.ll
 define void @test(i32 %a) {
@@ -124,14 +126,14 @@ no:
 }
 
 !0 = !{!"unknown", i32 12, i32 67}
-; EXTRA-ARGS: 'unknown' !prof should have no additional operands
+; EXTRA-ARGS: 'unknown' !prof should have a single additional operand
 
 ;--- unknown-on-function1.ll
 define void @test() !prof !0 {
   ret void
 }
 
-!0 = !{!"unknown"}
+!0 = !{!"unknown", !"test"}
 ; ON-FUNCTION1: define void @test() !prof !0
 
 ;--- unknown-on-function2.ll
@@ -140,12 +142,38 @@ define void @test() !prof !0 {
 }
 
 !0 = !{!"unknown", i64 123}
-; ON-FUNCTION2: first operand should be 'function_entry_count' or 'synthetic_function_entry_count'
+; ON-FUNCTION2: 'unknown' !prof should have an additional operand of type string
 
 ;--- invalid-unknown-placement.ll
 define i32 @test() {
   %r = add i32 1, 2, !prof !0
   ret i32 %r
 }
-!0 = !{!"unknown"}
+!0 = !{!"unknown", !"test"}
 ; INVALID-UNKNOWN-PLACEMENT: 'unknown' !prof should only appear on instructions on which 'branch_weights' would
+
+;--- unknown-noargs.ll
+define void @test(i32 %a) {
+  %c = icmp eq i32 %a, 0
+  br i1 %c, label %yes, label %no, !prof !0
+yes:
+  ret void
+no:
+  ret void
+}
+
+!0 = !{!"unknown"}
+; NO-ARGS: 'unknown' !prof should have a single additional operand
+
+;--- unknown-empty.ll
+define void @test(i32 %a) {
+  %c = icmp eq i32 %a, 0
+  br i1 %c, label %yes, label %no, !prof !0
+yes:
+  ret void
+no:
+  ret void
+}
+
+!0 = !{!"unknown", !""}
+; EMPTY-ARGS: the 'unknown' !prof operand should not be an empty string



More information about the llvm-commits mailing list