[clang] [llvm] [InstrProf] Fix frontend generated function hash (PR #165358)

Stephen Senran Zhang via cfe-commits cfe-commits at lists.llvm.org
Wed Oct 29 18:56:28 PDT 2025


https://github.com/zsrkmyn updated https://github.com/llvm/llvm-project/pull/165358

>From 0fc8d8d02fdf11e2a42b1c8015347ee7ab0a78e0 Mon Sep 17 00:00:00 2001
From: Senran Zhang <zsrkmyn at gmail.com>
Date: Tue, 28 Oct 2025 16:15:07 +0800
Subject: [PATCH 1/3] [InstrProf] Fix frontend generated function hash

The most significant 4 bits in function hash are reserved bits, and are
now used as context-sensitive flag, so they must be masked out. This
tries to fix #160248.
---
 clang/lib/CodeGen/CodeGenPGO.cpp                 |   9 +++++++--
 .../Profile/Inputs/c-counter-overflows.proftext  |   2 +-
 clang/test/Profile/Inputs/c-general.profdata.v12 | Bin 0 -> 2616 bytes
 clang/test/Profile/Inputs/c-general.proftext     |  12 ++++++------
 .../Profile/Inputs/c-unprofiled-blocks.proftext  |   4 ++--
 clang/test/Profile/Inputs/cxx-rangefor.proftext  |   2 +-
 .../Inputs/misexpect-switch-default.proftext     |   2 +-
 .../Inputs/misexpect-switch-nonconst.proftext    |   2 +-
 clang/test/Profile/c-collision.c                 |   4 ++--
 clang/test/Profile/c-general.c                   |   1 +
 llvm/include/llvm/ProfileData/InstrProf.h        |   7 +++++--
 llvm/include/llvm/ProfileData/InstrProfData.inc  |   2 +-
 llvm/lib/ProfileData/InstrProf.cpp               |   5 +++--
 llvm/lib/ProfileData/InstrProfWriter.cpp         |   2 +-
 .../Instrumentation/PGOInstrumentation.cpp       |   2 +-
 .../tools/llvm-profdata/profile-version.test     |   2 +-
 16 files changed, 34 insertions(+), 24 deletions(-)
 create mode 100644 clang/test/Profile/Inputs/c-general.profdata.v12

diff --git a/clang/lib/CodeGen/CodeGenPGO.cpp b/clang/lib/CodeGen/CodeGenPGO.cpp
index 8f095649f87ce..06d7380b4e37c 100644
--- a/clang/lib/CodeGen/CodeGenPGO.cpp
+++ b/clang/lib/CodeGen/CodeGenPGO.cpp
@@ -58,9 +58,10 @@ enum PGOHashVersion : unsigned {
   PGO_HASH_V1,
   PGO_HASH_V2,
   PGO_HASH_V3,
+  PGO_HASH_V4,
 
   // Keep this set to the latest hash version.
-  PGO_HASH_LATEST = PGO_HASH_V3
+  PGO_HASH_LATEST = PGO_HASH_V4
 };
 
 namespace {
@@ -152,7 +153,9 @@ static PGOHashVersion getPGOHashVersion(llvm::IndexedInstrProfReader *PGOReader,
     return PGO_HASH_V1;
   if (PGOReader->getVersion() <= 5)
     return PGO_HASH_V2;
-  return PGO_HASH_V3;
+  if (PGOReader->getVersion() <= 12)
+    return PGO_HASH_V3;
+  return PGO_HASH_V4;
 }
 
 /// A RecursiveASTVisitor that fills a map of statements to PGO counters.
@@ -1099,6 +1102,8 @@ void CodeGenPGO::mapRegionCounters(const Decl *D) {
   assert(Walker.NextCounter > 0 && "no entry counter mapped for decl");
   NumRegionCounters = Walker.NextCounter;
   FunctionHash = Walker.Hash.finalize();
+  if (HashVersion >= PGO_HASH_V4)
+    FunctionHash &= llvm::NamedInstrProfRecord::FUNC_HASH_MASK;
 }
 
 bool CodeGenPGO::skipRegionMappingForDecl(const Decl *D) {
diff --git a/clang/test/Profile/Inputs/c-counter-overflows.proftext b/clang/test/Profile/Inputs/c-counter-overflows.proftext
index 4d0287c787051..8633060507014 100644
--- a/clang/test/Profile/Inputs/c-counter-overflows.proftext
+++ b/clang/test/Profile/Inputs/c-counter-overflows.proftext
@@ -1,5 +1,5 @@
 main
-7779561829442898616
+862032801801816760
 8
 1
 68719476720
diff --git a/clang/test/Profile/Inputs/c-general.profdata.v12 b/clang/test/Profile/Inputs/c-general.profdata.v12
new file mode 100644
index 0000000000000000000000000000000000000000..57a72faaecc85f567936cec900704e0fb531946b
GIT binary patch
literal 2616
zcmb_eTSydP6#jQx(@ITI%v3}LQy(m`lnAezRANa4iHSC at v#UEXJG1SKq(qTzXa?OZ
zql?f=1qRh)2oVJpQN1XUJ=8-{VV4&rdZ- at E_CMb){;SwS`|{2C{&V}!Idf)bRIg8O
zS9)UE{J+#?bNT$`bLAqEmlB;o2(x;UErd=1dtx||kjD|{@E7RimLgvjw<KsF^6$>s
zg1pS#G30S1je8XNtl{XOrk(UrhlhFGvY7Z(!qz+d!XnQ~xMdFMr4a`1#RZ=rXA?hl
zI6nB4NOCS=QToc at la*w|X{_Kp>bQ;0-&W7hm)hs&D;MA`EbG%F<^FVYcQSe2NGR)?
zQ!y1?bEuN;b@?2o?i-unhr9=jAuBS8kg3VDy#IF8jp at y&+^F;M$SB6HmnDrUWr;Ps
za$)c2HEIGxO at Wv}^cr at Mf#AjL!`a$upW5=D7|IID(oN`c_|$I6)uot5d2?ZWUD8h)
zmvFKu#d>-`kkyOGumgsZ*<bLyY|YVu2Vh1?#W<jtvfE`;xc&ZTflDk&h=9mIJ{XMg
z!H>)sqX$Hjf&2wy42Vo21EYjIpa;Y~tn9~Nxvg$zOOiMgZMv at NUP;w;uOW>WH>{h?
zyd at 3=h5&Vj48)6v+k^jCeKFhJ=er7`uIBE=?Z!x9U#G`wqz~1$Y>?lNr4WgrKsXcS
zg?Q+Rt$++Wv<5QlL==`cgN!W+d$h*FUibAU|Ne3%8m*}!6+`iORTpo~cxla0g2xsb
z2t;*~F0c;n3BytLTt6|=fB9M?w&5Al_&WeDhZfp9#@P>Lr at yN<#+PS!b`c_n43UDJ
zWFP|I9Qxq1Ngs%5flS8?sax5vS0^V+or7;M_4%aYaVQ!-8i)oIy)?auwQn7+H&@X?
z5usez;nHR|uDVv<WS9<9k)`%dO&;IE&#j~ex9BF(p(HKr(C5j=-V5LCC|eb&ICZJr
zp{l0ar+0R^2fj{SZ0noq!c|1Sh=<EZ#;M$qp|$o^A4Dc2q|&BzNPJCA%ruPlHYs;e
zaKy+WO(1xpLthl|*vLTeKrA^Rcp&ZqL>$}=d0_5iL`5>th|dsTK{))+cyp0Bel(Bb
YX5x<&$;U{p#P%2R`zY|+Q4m4z4;UZ1fdBvi

literal 0
HcmV?d00001

diff --git a/clang/test/Profile/Inputs/c-general.proftext b/clang/test/Profile/Inputs/c-general.proftext
index 08280ef39a89d..72e1be6e8846f 100644
--- a/clang/test/Profile/Inputs/c-general.proftext
+++ b/clang/test/Profile/Inputs/c-general.proftext
@@ -7,7 +7,7 @@ simple_loops
 75
 
 conditionals
-4904767535850050386
+293081517422662482
 13
 1
 100
@@ -24,7 +24,7 @@ conditionals
 1
 
 early_exits
-2880354649761471549
+574511640547777597
 9
 1
 0
@@ -37,7 +37,7 @@ early_exits
 0
 
 jumps
-15051420506203462683
+63440946314451995
 22
 1
 1
@@ -86,7 +86,7 @@ switches
 0
 
 big_switch
-13144136522122330070
+461999971447013334
 17
 1
 32
@@ -125,7 +125,7 @@ boolean_operators
 33
 
 boolop_loops
-12402604614320574815
+873389568252105055
 13
 1
 50
@@ -149,7 +149,7 @@ conditional_operator
 1
 
 do_fallthrough
-8714614136504380050
+644163604256451218
 4
 1
 10
diff --git a/clang/test/Profile/Inputs/c-unprofiled-blocks.proftext b/clang/test/Profile/Inputs/c-unprofiled-blocks.proftext
index d880663fed32d..7af509715f8f7 100644
--- a/clang/test/Profile/Inputs/c-unprofiled-blocks.proftext
+++ b/clang/test/Profile/Inputs/c-unprofiled-blocks.proftext
@@ -1,5 +1,5 @@
 never_called
-6820425066224770721
+1055817543190535841
 9
 0
 0
@@ -17,7 +17,7 @@ main
 1
 
 dead_code
-5254464978620792806
+642778960193404902
 10
 1
 0
diff --git a/clang/test/Profile/Inputs/cxx-rangefor.proftext b/clang/test/Profile/Inputs/cxx-rangefor.proftext
index d41205bbde147..cfc88da8f9726 100644
--- a/clang/test/Profile/Inputs/cxx-rangefor.proftext
+++ b/clang/test/Profile/Inputs/cxx-rangefor.proftext
@@ -1,5 +1,5 @@
 _Z9range_forv
-8789831523895825398
+719380991647896566
 5
 1
 4
diff --git a/clang/test/Profile/Inputs/misexpect-switch-default.proftext b/clang/test/Profile/Inputs/misexpect-switch-default.proftext
index 533da91765234..112426e0c7b57 100644
--- a/clang/test/Profile/Inputs/misexpect-switch-default.proftext
+++ b/clang/test/Profile/Inputs/misexpect-switch-default.proftext
@@ -1,6 +1,6 @@
 main
 # Func Hash:
-8734802134600123338
+664351602352194506
 # Num Counters:
 9
 # Counter Values:
diff --git a/clang/test/Profile/Inputs/misexpect-switch-nonconst.proftext b/clang/test/Profile/Inputs/misexpect-switch-nonconst.proftext
index 0da9379357ae7..99d067c57f16f 100644
--- a/clang/test/Profile/Inputs/misexpect-switch-nonconst.proftext
+++ b/clang/test/Profile/Inputs/misexpect-switch-nonconst.proftext
@@ -1,6 +1,6 @@
 main
 # Func Hash:
-3721743393642630379
+262978879822089451
 # Num Counters:
 10
 # Counter Values:
diff --git a/clang/test/Profile/c-collision.c b/clang/test/Profile/c-collision.c
index 6c779c6facaa2..f35ba1bfb7627 100644
--- a/clang/test/Profile/c-collision.c
+++ b/clang/test/Profile/c-collision.c
@@ -2,8 +2,8 @@
 // RUN: %clang_cc1 -UEXTRA -triple x86_64-unknown-linux-gnu -main-file-name c-collision.c %s -o - -emit-llvm -fprofile-instrument=clang | FileCheck %s --check-prefix=CHECK-NOEXTRA
 // RUN: %clang_cc1 -DEXTRA -triple x86_64-unknown-linux-gnu -main-file-name c-collision.c %s -o - -emit-llvm -fprofile-instrument=clang | FileCheck %s --check-prefix=CHECK-EXTRA
 
-// CHECK-NOEXTRA: @__profd_foo = private global { {{.*}} } { i64 6699318081062747564, i64 7156072912471487002,
-// CHECK-EXTRA:   @__profd_foo = private global { {{.*}} } { i64 6699318081062747564, i64 -4383447408116050035,
+// CHECK-NOEXTRA: @__profd_foo = private global { {{.*}} } { i64 6699318081062747564, i64 238543884830405146,
+// CHECK-EXTRA:   @__profd_foo = private global { {{.*}} } { i64 6699318081062747564, i64 228238610311337869,
 
 extern int bar;
 void foo(void) {
diff --git a/clang/test/Profile/c-general.c b/clang/test/Profile/c-general.c
index ee36a43dac081..6c865e608a037 100644
--- a/clang/test/Profile/c-general.c
+++ b/clang/test/Profile/c-general.c
@@ -4,6 +4,7 @@
 
 // RUN: llvm-profdata merge %S/Inputs/c-general.proftext -o %t.profdata
 // RUN: %clang_cc1 -triple x86_64-apple-macosx10.9 -main-file-name c-general.c %s -o - -emit-llvm -fprofile-instrument-use=clang -fprofile-instrument-use-path=%t.profdata | FileCheck -allow-deprecated-dag-overlap  -check-prefix=PGOUSE %s
+// RUN: %clang_cc1 -triple x86_64-apple-macosx10.9 -main-file-name c-general.c %s -o - -emit-llvm -fprofile-instrument-use=clang -fprofile-instrument-use-path=%S/Inputs/c-general.profdata.v12 | FileCheck -allow-deprecated-dag-overlap  -check-prefix=PGOUSE %s
 // RUN: %clang_cc1 -triple x86_64-apple-macosx10.9 -main-file-name c-general.c %s -o - -emit-llvm -fprofile-instrument-use=clang -fprofile-instrument-use-path=%S/Inputs/c-general.profdata.v5 | FileCheck -allow-deprecated-dag-overlap  -check-prefix=PGOUSE %s
 // RUN: %clang_cc1 -triple x86_64-apple-macosx10.9 -main-file-name c-general.c %s -o - -emit-llvm -fprofile-instrument-use=clang -fprofile-instrument-use-path=%S/Inputs/c-general.profdata.v3 | FileCheck -allow-deprecated-dag-overlap  -check-prefix=PGOUSE %s
 // Also check compatibility with older profiles.
diff --git a/llvm/include/llvm/ProfileData/InstrProf.h b/llvm/include/llvm/ProfileData/InstrProf.h
index 85a9efe73855b..0532500e68db3 100644
--- a/llvm/include/llvm/ProfileData/InstrProf.h
+++ b/llvm/include/llvm/ProfileData/InstrProf.h
@@ -1059,7 +1059,8 @@ struct NamedInstrProfRecord : InstrProfRecord {
   uint64_t Hash;
 
   // We reserve this bit as the flag for context sensitive profile record.
-  static const int CS_FLAG_IN_FUNC_HASH = 60;
+  static constexpr unsigned CS_FLAG_IN_FUNC_HASH = 60;
+  static constexpr uint64_t FUNC_HASH_MASK = 0x0FFF'FFFF'FFFF'FFFF;
 
   NamedInstrProfRecord() = default;
   NamedInstrProfRecord(StringRef Name, uint64_t Hash,
@@ -1174,7 +1175,9 @@ enum ProfVersion {
   Version11 = 11,
   // VTable profiling, decision record and bitmap are modified for mcdc.
   Version12 = 12,
-  // The current version is 12.
+  // In this version, the frontend PGO stable hash algorithm defaults to V4.
+  Version13 = 13,
+  // The current version is 13.
   CurrentVersion = INSTR_PROF_INDEX_VERSION
 };
 const uint64_t Version = ProfVersion::CurrentVersion;
diff --git a/llvm/include/llvm/ProfileData/InstrProfData.inc b/llvm/include/llvm/ProfileData/InstrProfData.inc
index 0496f240dc823..46d6bb5bd8896 100644
--- a/llvm/include/llvm/ProfileData/InstrProfData.inc
+++ b/llvm/include/llvm/ProfileData/InstrProfData.inc
@@ -722,7 +722,7 @@ serializeValueProfDataFrom(ValueProfRecordClosure *Closure,
 /* Raw profile format version (start from 1). */
 #define INSTR_PROF_RAW_VERSION 10
 /* Indexed profile format version (start from 1). */
-#define INSTR_PROF_INDEX_VERSION 12
+#define INSTR_PROF_INDEX_VERSION 13
 /* Coverage mapping format version (start from 0). */
 #define INSTR_PROF_COVMAP_VERSION 6
 
diff --git a/llvm/lib/ProfileData/InstrProf.cpp b/llvm/lib/ProfileData/InstrProf.cpp
index 02087355ab318..54987872f2d8b 100644
--- a/llvm/lib/ProfileData/InstrProf.cpp
+++ b/llvm/lib/ProfileData/InstrProf.cpp
@@ -1690,7 +1690,7 @@ Expected<Header> Header::readFromBuffer(const unsigned char *Buffer) {
       IndexedInstrProf::ProfVersion::CurrentVersion)
     return make_error<InstrProfError>(instrprof_error::unsupported_version);
 
-  static_assert(IndexedInstrProf::ProfVersion::CurrentVersion == Version12,
+  static_assert(IndexedInstrProf::ProfVersion::CurrentVersion == Version13,
                 "Please update the reader as needed when a new field is added "
                 "or when indexed profile version gets bumped.");
 
@@ -1723,10 +1723,11 @@ size_t Header::size() const {
     // of the header, and byte offset of existing fields shouldn't change when
     // indexed profile version gets incremented.
     static_assert(
-        IndexedInstrProf::ProfVersion::CurrentVersion == Version12,
+        IndexedInstrProf::ProfVersion::CurrentVersion == Version13,
         "Please update the size computation below if a new field has "
         "been added to the header; for a version bump without new "
         "fields, add a case statement to fall through to the latest version.");
+  case 13ull:
   case 12ull:
     return 72;
   case 11ull:
diff --git a/llvm/lib/ProfileData/InstrProfWriter.cpp b/llvm/lib/ProfileData/InstrProfWriter.cpp
index a3473514d4637..0f15ca8ff6df7 100644
--- a/llvm/lib/ProfileData/InstrProfWriter.cpp
+++ b/llvm/lib/ProfileData/InstrProfWriter.cpp
@@ -542,7 +542,7 @@ Error InstrProfWriter::writeImpl(ProfOStream &OS) {
   // The WritePrevVersion handling will either need to be removed or updated
   // if the version is advanced beyond 12.
   static_assert(IndexedInstrProf::ProfVersion::CurrentVersion ==
-                IndexedInstrProf::ProfVersion::Version12);
+                IndexedInstrProf::ProfVersion::Version13);
   if (static_cast<bool>(ProfileKind & InstrProfKind::IRInstrumentation))
     Header.Version |= VARIANT_MASK_IR_PROF;
   if (static_cast<bool>(ProfileKind & InstrProfKind::ContextSensitive))
diff --git a/llvm/lib/Transforms/Instrumentation/PGOInstrumentation.cpp b/llvm/lib/Transforms/Instrumentation/PGOInstrumentation.cpp
index 120c4f65a7292..9981ec8220ff7 100644
--- a/llvm/lib/Transforms/Instrumentation/PGOInstrumentation.cpp
+++ b/llvm/lib/Transforms/Instrumentation/PGOInstrumentation.cpp
@@ -734,7 +734,7 @@ void FuncPGOInstrumentation<Edge, BBInfo>::computeCFGHash() {
   FunctionHash = (((uint64_t)JCH.getCRC()) << 28) + JC.getCRC();
 
   // Reserve bit 60-63 for other information purpose.
-  FunctionHash &= 0x0FFFFFFFFFFFFFFF;
+  FunctionHash &= NamedInstrProfRecord::FUNC_HASH_MASK;
   if (IsCS)
     NamedInstrProfRecord::setCSFlagInHash(FunctionHash);
   LLVM_DEBUG(dbgs() << "Function Hash Computation for " << F.getName() << ":\n"
diff --git a/llvm/test/tools/llvm-profdata/profile-version.test b/llvm/test/tools/llvm-profdata/profile-version.test
index cb68a648d5e5a..e811699ac63ed 100644
--- a/llvm/test/tools/llvm-profdata/profile-version.test
+++ b/llvm/test/tools/llvm-profdata/profile-version.test
@@ -2,7 +2,7 @@ Test the profile version.
 
 RUN: llvm-profdata merge -o %t.profdata %p/Inputs/basic.proftext
 RUN: llvm-profdata show --profile-version %t.profdata | FileCheck %s
-CHECK: Profile version: 12
+CHECK: Profile version: 13
 
 RUN: llvm-profdata merge -o %t.prev.profdata %p/Inputs/basic.proftext --write-prev-version
 RUN: llvm-profdata show --profile-version %t.prev.profdata | FileCheck %s --check-prefix=PREV

>From 395f1ccfe671a676e86a343aca24419aa464ca2d Mon Sep 17 00:00:00 2001
From: Senran Zhang <zsrkmyn at gmail.com>
Date: Tue, 28 Oct 2025 19:15:41 +0800
Subject: [PATCH 2/3] Update clang test

---
 clang/test/Profile/Inputs/cxx-throws.proftext | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/clang/test/Profile/Inputs/cxx-throws.proftext b/clang/test/Profile/Inputs/cxx-throws.proftext
index 043dea08c728f..92b0eab396844 100644
--- a/clang/test/Profile/Inputs/cxx-throws.proftext
+++ b/clang/test/Profile/Inputs/cxx-throws.proftext
@@ -1,5 +1,5 @@
 _Z6throwsv
-18172607911962830854
+878785342860126214
 9
 1
 100

>From 98d0cbc9dcbfded7b1f1b1f4a3e987825a631010 Mon Sep 17 00:00:00 2001
From: Senran Zhang <zsrkmyn at gmail.com>
Date: Thu, 30 Oct 2025 09:56:08 +0800
Subject: [PATCH 3/3] Restruct comment string

---
 llvm/include/llvm/ProfileData/InstrProf.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/llvm/include/llvm/ProfileData/InstrProf.h b/llvm/include/llvm/ProfileData/InstrProf.h
index 0532500e68db3..9f52b6aba0f52 100644
--- a/llvm/include/llvm/ProfileData/InstrProf.h
+++ b/llvm/include/llvm/ProfileData/InstrProf.h
@@ -1059,8 +1059,8 @@ struct NamedInstrProfRecord : InstrProfRecord {
   uint64_t Hash;
 
   // We reserve this bit as the flag for context sensitive profile record.
-  static constexpr unsigned CS_FLAG_IN_FUNC_HASH = 60;
   static constexpr uint64_t FUNC_HASH_MASK = 0x0FFF'FFFF'FFFF'FFFF;
+  static constexpr unsigned CS_FLAG_IN_FUNC_HASH = 60;
 
   NamedInstrProfRecord() = default;
   NamedInstrProfRecord(StringRef Name, uint64_t Hash,



More information about the cfe-commits mailing list