[llvm] [Metadata][profcheck] Handle identical MDNodes in getMergedProfMetadata (PR #175701)

Snehasish Kumar via llvm-commits llvm-commits at lists.llvm.org
Wed Jan 14 10:46:12 PST 2026


https://github.com/snehasish updated https://github.com/llvm/llvm-project/pull/175701

>From a068116f0a35fec5793b945d979920f465ca982a Mon Sep 17 00:00:00 2001
From: Snehasish Kumar <snehasishk at google.com>
Date: Tue, 13 Jan 2026 02:40:51 +0000
Subject: [PATCH 1/7] [Metadata][profcheck] Handle identical MDNodes in
 getMergedProfMetadata

This fixes a bug where !prof metadata was dropped from SelectInsts when GVN simplified/merged them.
Guarded by -profcheck-disable-metadata-fixes. Exposed by the tests in
Transforms/SampleProfile.
---
 llvm/lib/IR/Metadata.cpp           | 12 +++++++
 llvm/unittests/IR/MetadataTest.cpp | 50 ++++++++++++++++++++++++++++++
 2 files changed, 62 insertions(+)

diff --git a/llvm/lib/IR/Metadata.cpp b/llvm/lib/IR/Metadata.cpp
index 1add0c7930bc9..f5009b212856d 100644
--- a/llvm/lib/IR/Metadata.cpp
+++ b/llvm/lib/IR/Metadata.cpp
@@ -46,6 +46,8 @@
 #include "llvm/IR/Type.h"
 #include "llvm/IR/Value.h"
 #include "llvm/Support/Casting.h"
+#include "llvm/Support/CommandLine.h"
+
 #include "llvm/Support/ErrorHandling.h"
 #include "llvm/Support/MathExtras.h"
 #include "llvm/Support/ModRef.h"
@@ -58,6 +60,10 @@
 
 using namespace llvm;
 
+namespace llvm {
+extern cl::opt<bool> ProfcheckDisableMetadataFixes;
+}
+
 MetadataAsValue::MetadataAsValue(Type *Ty, Metadata *MD)
     : Value(Ty, MetadataAsValueVal), MD(MD) {
   track();
@@ -1242,6 +1248,12 @@ MDNode *MDNode::getMergedProfMetadata(MDNode *A, MDNode *B,
     return A ? A : B;
   }
 
+  if (A == B && !ProfcheckDisableMetadataFixes) {
+    // For calls, we want to sum the weights even if identical.
+    if (!isa<CallInst>(AInstr))
+      return A;
+  }
+
   assert(AInstr->getMetadata(LLVMContext::MD_prof) == A &&
          "Caller should guarantee");
   assert(BInstr->getMetadata(LLVMContext::MD_prof) == B &&
diff --git a/llvm/unittests/IR/MetadataTest.cpp b/llvm/unittests/IR/MetadataTest.cpp
index 85c79d13ae7ce..24e8b47b7af34 100644
--- a/llvm/unittests/IR/MetadataTest.cpp
+++ b/llvm/unittests/IR/MetadataTest.cpp
@@ -5463,6 +5463,56 @@ TEST_F(MDTupleAllocationTest, Tracking2) {
   EXPECT_EQ(A->getOperand(2), Value2);
 }
 
+TEST_F(MDNodeTest, MergedProfMetadata) {
+  // Check that identical profile metadata is merged correctly.
+  Metadata *Ops[] = {
+      ConstantAsMetadata::get(ConstantInt::get(Context, APInt(32, 1))),
+      ConstantAsMetadata::get(ConstantInt::get(Context, APInt(32, 10))),
+      ConstantAsMetadata::get(ConstantInt::get(Context, APInt(32, 20)))};
+  MDNode *Prof = MDNode::get(Context, Ops);
+
+  // Create instructions to pass to getMergedProfMetadata.
+  // It requires the instructions to be of a supported type (e.g., SelectInst).
+  Value *C = ConstantInt::get(Context, APInt(1, 1));
+  Value *V1 = ConstantInt::get(Context, APInt(32, 1));
+  Value *V2 = ConstantInt::get(Context, APInt(32, 2));
+  std::unique_ptr<SelectInst> SI1(SelectInst::Create(C, V1, V2));
+  std::unique_ptr<SelectInst> SI2(SelectInst::Create(C, V1, V2));
+
+  SI1->setMetadata(LLVMContext::MD_prof, Prof);
+  SI2->setMetadata(LLVMContext::MD_prof, Prof);
+
+  MDNode *Merged =
+      MDNode::getMergedProfMetadata(Prof, Prof, SI1.get(), SI2.get());
+  EXPECT_EQ(Merged, Prof);
+}
+
+TEST_F(MDNodeTest, MergedProfMetadata_CallInst) {
+  // Check that identical profile metadata on CallInsts is SUMMED, not preserved.
+  Metadata *Ops[] = {
+      MDString::get(Context, "branch_weights"),
+      ConstantAsMetadata::get(ConstantInt::get(Context, APInt(32, 10)))};
+  MDNode *Prof = MDNode::get(Context, Ops);
+
+  // Create two CallInsts.
+  FunctionType *FTy = FunctionType::get(Type::getVoidTy(Context), false);
+  std::unique_ptr<CallInst> CI1(CallInst::Create(FTy, getFunction("f"), ArrayRef<Value *>()));
+  std::unique_ptr<CallInst> CI2(CallInst::Create(FTy, getFunction("f"), ArrayRef<Value *>()));
+
+  CI1->setMetadata(LLVMContext::MD_prof, Prof);
+  CI2->setMetadata(LLVMContext::MD_prof, Prof);
+
+  MDNode *Merged =
+      MDNode::getMergedProfMetadata(Prof, Prof, CI1.get(), CI2.get());
+
+  // Expect merged node to be different (summed weights).
+  EXPECT_NE(Merged, Prof);
+  // Verify value is 20.
+  ASSERT_EQ(Merged->getNumOperands(), 2u);
+  ConstantInt *W = mdconst::extract<ConstantInt>(Merged->getOperand(1));
+  EXPECT_EQ(W->getZExtValue(), 20u);
+}
+
 #if defined(GTEST_HAS_DEATH_TEST) && !defined(NDEBUG) && !defined(GTEST_HAS_SEH)
 typedef MetadataTest MDTupleAllocationDeathTest;
 TEST_F(MDTupleAllocationDeathTest, ResizeRejected) {

>From 01ec841118db22aeb20c014815b966bb2e0abdd7 Mon Sep 17 00:00:00 2001
From: Snehasish Kumar <snehasishk at google.com>
Date: Tue, 13 Jan 2026 04:11:53 +0000
Subject: [PATCH 2/7] Move the check after merging for calls to simplify the
 condition

---
 llvm/lib/IR/Metadata.cpp | 9 +++------
 1 file changed, 3 insertions(+), 6 deletions(-)

diff --git a/llvm/lib/IR/Metadata.cpp b/llvm/lib/IR/Metadata.cpp
index f5009b212856d..326abd87ddae9 100644
--- a/llvm/lib/IR/Metadata.cpp
+++ b/llvm/lib/IR/Metadata.cpp
@@ -1248,12 +1248,6 @@ MDNode *MDNode::getMergedProfMetadata(MDNode *A, MDNode *B,
     return A ? A : B;
   }
 
-  if (A == B && !ProfcheckDisableMetadataFixes) {
-    // For calls, we want to sum the weights even if identical.
-    if (!isa<CallInst>(AInstr))
-      return A;
-  }
-
   assert(AInstr->getMetadata(LLVMContext::MD_prof) == A &&
          "Caller should guarantee");
   assert(BInstr->getMetadata(LLVMContext::MD_prof) == B &&
@@ -1267,6 +1261,9 @@ MDNode *MDNode::getMergedProfMetadata(MDNode *A, MDNode *B,
       BCall->getCalledFunction())
     return mergeDirectCallProfMetadata(A, B, AInstr, BInstr);
 
+  if (A == B && !ProfcheckDisableMetadataFixes)
+    return A;
+
   // The rest of the cases are not implemented but could be added
   // when there are use cases.
   return nullptr;

>From 2192484a349c0d41c8f72117d7e7ec8772656e3e Mon Sep 17 00:00:00 2001
From: Snehasish Kumar <snehasishk at google.com>
Date: Tue, 13 Jan 2026 04:14:06 +0000
Subject: [PATCH 3/7] Drop the summation unittest since it's already covered by
 the gvn lit tests

---
 llvm/unittests/IR/MetadataTest.cpp | 26 --------------------------
 1 file changed, 26 deletions(-)

diff --git a/llvm/unittests/IR/MetadataTest.cpp b/llvm/unittests/IR/MetadataTest.cpp
index 24e8b47b7af34..edf28a9503fe2 100644
--- a/llvm/unittests/IR/MetadataTest.cpp
+++ b/llvm/unittests/IR/MetadataTest.cpp
@@ -5487,32 +5487,6 @@ TEST_F(MDNodeTest, MergedProfMetadata) {
   EXPECT_EQ(Merged, Prof);
 }
 
-TEST_F(MDNodeTest, MergedProfMetadata_CallInst) {
-  // Check that identical profile metadata on CallInsts is SUMMED, not preserved.
-  Metadata *Ops[] = {
-      MDString::get(Context, "branch_weights"),
-      ConstantAsMetadata::get(ConstantInt::get(Context, APInt(32, 10)))};
-  MDNode *Prof = MDNode::get(Context, Ops);
-
-  // Create two CallInsts.
-  FunctionType *FTy = FunctionType::get(Type::getVoidTy(Context), false);
-  std::unique_ptr<CallInst> CI1(CallInst::Create(FTy, getFunction("f"), ArrayRef<Value *>()));
-  std::unique_ptr<CallInst> CI2(CallInst::Create(FTy, getFunction("f"), ArrayRef<Value *>()));
-
-  CI1->setMetadata(LLVMContext::MD_prof, Prof);
-  CI2->setMetadata(LLVMContext::MD_prof, Prof);
-
-  MDNode *Merged =
-      MDNode::getMergedProfMetadata(Prof, Prof, CI1.get(), CI2.get());
-
-  // Expect merged node to be different (summed weights).
-  EXPECT_NE(Merged, Prof);
-  // Verify value is 20.
-  ASSERT_EQ(Merged->getNumOperands(), 2u);
-  ConstantInt *W = mdconst::extract<ConstantInt>(Merged->getOperand(1));
-  EXPECT_EQ(W->getZExtValue(), 20u);
-}
-
 #if defined(GTEST_HAS_DEATH_TEST) && !defined(NDEBUG) && !defined(GTEST_HAS_SEH)
 typedef MetadataTest MDTupleAllocationDeathTest;
 TEST_F(MDTupleAllocationDeathTest, ResizeRejected) {

>From e0427360baa645b4cf7e56744ba53040f328e29c Mon Sep 17 00:00:00 2001
From: Snehasish Kumar <snehasishk at google.com>
Date: Tue, 13 Jan 2026 05:37:22 +0000
Subject: [PATCH 4/7] Revert "Drop the summation unittest since it's already
 covered by the gvn lit tests"

This reverts commit fb0d7df21794ab50eaab4cb6e249679089a5a501.
---
 llvm/unittests/IR/MetadataTest.cpp | 26 ++++++++++++++++++++++++++
 1 file changed, 26 insertions(+)

diff --git a/llvm/unittests/IR/MetadataTest.cpp b/llvm/unittests/IR/MetadataTest.cpp
index edf28a9503fe2..24e8b47b7af34 100644
--- a/llvm/unittests/IR/MetadataTest.cpp
+++ b/llvm/unittests/IR/MetadataTest.cpp
@@ -5487,6 +5487,32 @@ TEST_F(MDNodeTest, MergedProfMetadata) {
   EXPECT_EQ(Merged, Prof);
 }
 
+TEST_F(MDNodeTest, MergedProfMetadata_CallInst) {
+  // Check that identical profile metadata on CallInsts is SUMMED, not preserved.
+  Metadata *Ops[] = {
+      MDString::get(Context, "branch_weights"),
+      ConstantAsMetadata::get(ConstantInt::get(Context, APInt(32, 10)))};
+  MDNode *Prof = MDNode::get(Context, Ops);
+
+  // Create two CallInsts.
+  FunctionType *FTy = FunctionType::get(Type::getVoidTy(Context), false);
+  std::unique_ptr<CallInst> CI1(CallInst::Create(FTy, getFunction("f"), ArrayRef<Value *>()));
+  std::unique_ptr<CallInst> CI2(CallInst::Create(FTy, getFunction("f"), ArrayRef<Value *>()));
+
+  CI1->setMetadata(LLVMContext::MD_prof, Prof);
+  CI2->setMetadata(LLVMContext::MD_prof, Prof);
+
+  MDNode *Merged =
+      MDNode::getMergedProfMetadata(Prof, Prof, CI1.get(), CI2.get());
+
+  // Expect merged node to be different (summed weights).
+  EXPECT_NE(Merged, Prof);
+  // Verify value is 20.
+  ASSERT_EQ(Merged->getNumOperands(), 2u);
+  ConstantInt *W = mdconst::extract<ConstantInt>(Merged->getOperand(1));
+  EXPECT_EQ(W->getZExtValue(), 20u);
+}
+
 #if defined(GTEST_HAS_DEATH_TEST) && !defined(NDEBUG) && !defined(GTEST_HAS_SEH)
 typedef MetadataTest MDTupleAllocationDeathTest;
 TEST_F(MDTupleAllocationDeathTest, ResizeRejected) {

>From 13dd5df83370a4e06864f3512d37ba592005c54d Mon Sep 17 00:00:00 2001
From: Snehasish Kumar <snehasishk at google.com>
Date: Tue, 13 Jan 2026 06:01:40 +0000
Subject: [PATCH 5/7] clang format

---
 llvm/unittests/IR/MetadataTest.cpp | 9 ++++++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/llvm/unittests/IR/MetadataTest.cpp b/llvm/unittests/IR/MetadataTest.cpp
index 24e8b47b7af34..5b4935f8ba88f 100644
--- a/llvm/unittests/IR/MetadataTest.cpp
+++ b/llvm/unittests/IR/MetadataTest.cpp
@@ -5488,7 +5488,8 @@ TEST_F(MDNodeTest, MergedProfMetadata) {
 }
 
 TEST_F(MDNodeTest, MergedProfMetadata_CallInst) {
-  // Check that identical profile metadata on CallInsts is SUMMED, not preserved.
+  // Check that identical profile metadata on CallInsts is SUMMED, not
+  // preserved.
   Metadata *Ops[] = {
       MDString::get(Context, "branch_weights"),
       ConstantAsMetadata::get(ConstantInt::get(Context, APInt(32, 10)))};
@@ -5496,8 +5497,10 @@ TEST_F(MDNodeTest, MergedProfMetadata_CallInst) {
 
   // Create two CallInsts.
   FunctionType *FTy = FunctionType::get(Type::getVoidTy(Context), false);
-  std::unique_ptr<CallInst> CI1(CallInst::Create(FTy, getFunction("f"), ArrayRef<Value *>()));
-  std::unique_ptr<CallInst> CI2(CallInst::Create(FTy, getFunction("f"), ArrayRef<Value *>()));
+  std::unique_ptr<CallInst> CI1(
+      CallInst::Create(FTy, getFunction("f"), ArrayRef<Value *>()));
+  std::unique_ptr<CallInst> CI2(
+      CallInst::Create(FTy, getFunction("f"), ArrayRef<Value *>()));
 
   CI1->setMetadata(LLVMContext::MD_prof, Prof);
   CI2->setMetadata(LLVMContext::MD_prof, Prof);

>From 923144c59651263e8c3a0491b3a8887d66eee5b1 Mon Sep 17 00:00:00 2001
From: Snehasish Kumar <snehasishk at google.com>
Date: Wed, 14 Jan 2026 06:55:24 +0000
Subject: [PATCH 6/7] Update profcheck-xfail.txt

---
 llvm/utils/profcheck-xfail.txt | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/llvm/utils/profcheck-xfail.txt b/llvm/utils/profcheck-xfail.txt
index 564fbf3d00a48..d42d58d17cc94 100644
--- a/llvm/utils/profcheck-xfail.txt
+++ b/llvm/utils/profcheck-xfail.txt
@@ -505,8 +505,9 @@ Transforms/PreISelIntrinsicLowering/AArch64/expand-exp.ll
 Transforms/PreISelIntrinsicLowering/AArch64/expand-log.ll
 Transforms/PreISelIntrinsicLowering/PowerPC/memset-pattern.ll
 Transforms/PreISelIntrinsicLowering/RISCV/memset-pattern.ll
-Transforms/SampleProfile/pseudo-probe-profile-mismatch-thinlto.ll
-Transforms/SampleProfile/remarks-hotness.ll
+Transforms/PreISelIntrinsicLowering/X86/memcpy-inline-non-constant-len.ll
+Transforms/PreISelIntrinsicLowering/X86/memset-inline-non-constant-len.ll
+Transforms/PreISelIntrinsicLowering/X86/memset-pattern.ll
 Transforms/ScalarizeMaskedMemIntrin/AArch64/expand-masked-load.ll
 Transforms/ScalarizeMaskedMemIntrin/AArch64/expand-masked-store.ll
 Transforms/ScalarizeMaskedMemIntrin/AArch64/streaming-compatible-expand-masked-gather-scatter.ll

>From d87e81e91d1a20bf4c99e0a3abf9790a58ed1bdf Mon Sep 17 00:00:00 2001
From: Snehasish Kumar <snehasishk at google.com>
Date: Wed, 14 Jan 2026 18:45:24 +0000
Subject: [PATCH 7/7] fix bad merge

---
 llvm/utils/profcheck-xfail.txt | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/llvm/utils/profcheck-xfail.txt b/llvm/utils/profcheck-xfail.txt
index d42d58d17cc94..3a1a26dfd8840 100644
--- a/llvm/utils/profcheck-xfail.txt
+++ b/llvm/utils/profcheck-xfail.txt
@@ -505,9 +505,6 @@ Transforms/PreISelIntrinsicLowering/AArch64/expand-exp.ll
 Transforms/PreISelIntrinsicLowering/AArch64/expand-log.ll
 Transforms/PreISelIntrinsicLowering/PowerPC/memset-pattern.ll
 Transforms/PreISelIntrinsicLowering/RISCV/memset-pattern.ll
-Transforms/PreISelIntrinsicLowering/X86/memcpy-inline-non-constant-len.ll
-Transforms/PreISelIntrinsicLowering/X86/memset-inline-non-constant-len.ll
-Transforms/PreISelIntrinsicLowering/X86/memset-pattern.ll
 Transforms/ScalarizeMaskedMemIntrin/AArch64/expand-masked-load.ll
 Transforms/ScalarizeMaskedMemIntrin/AArch64/expand-masked-store.ll
 Transforms/ScalarizeMaskedMemIntrin/AArch64/streaming-compatible-expand-masked-gather-scatter.ll



More information about the llvm-commits mailing list