[llvm] [InstrProf] Disambiguate zero bitmaps in text profiles (PR #213906)
via llvm-commits
llvm-commits at lists.llvm.org
Tue Aug 4 23:48:52 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-pgo
Author: Karim Alweheshy (karim-alweheshy)
<details>
<summary>Changes</summary>
## Summary
- Always emit the bitmap-byte count in instrumentation text profiles, including an explicit `$0` for records without bitmap data.
- Treat only numeric-looking `$...` lines as bitmap counts so a following Swift `$s...` function name is not consumed as malformed bitmap metadata.
- Add a reduced legacy-input regression and update the affected text-output expectation.
## Motivation
`InstrProfWriter` currently omits the bitmap field when it is empty, while `TextInstrProfReader` treats any following line beginning with `$` as the bitmap-byte count. If the next function is a Swift mangled name such as `$s4main3fooyyF`, a valid writer-produced text profile cannot be read back and `llvm-profdata merge` reports `number of bitmap bytes is not a valid integer`.
Writing `$0` makes new text profiles unambiguous. Narrowing the legacy reader check allows existing profiles with the omitted field to recover Swift names. Names beginning with `$` followed by a digit remain inherently ambiguous in legacy text, but writer-produced profiles no longer rely on that boundary.
## Testing
- Reproduced the original failure with Apple LLVM 21 as a negative control.
- Verified the split-file fixture and FileCheck assertions against the expected canonical output.
- Verified changed C++ lines with `clang-format --dry-run --Werror`.
- Verified `git diff --check`.
- LLVM premerge passes on Linux, Linux AArch64, Windows, and macOS arm64; formatter, ABI-annotation, project-computation, and libc++ checks also pass.
- This sparse checkout intentionally has no local full LLVM build.
---
Full diff: https://github.com/llvm/llvm-project/pull/213906.diff
8 Files Affected:
- (modified) llvm/lib/ProfileData/InstrProfReader.cpp (+6-2)
- (modified) llvm/lib/ProfileData/InstrProfWriter.cpp (+2-2)
- (modified) llvm/test/tools/llvm-profdata/Inputs/CSIR_profile.proftext (+2)
- (modified) llvm/test/tools/llvm-profdata/Inputs/IR_profile.proftext (+2)
- (modified) llvm/test/tools/llvm-profdata/Inputs/cs.proftext (+2)
- (modified) llvm/test/tools/llvm-profdata/Inputs/instr-remap.expected (+6)
- (modified) llvm/test/tools/llvm-profdata/merge-filter.test (+6-1)
- (added) llvm/test/tools/llvm-profdata/text-zero-bitmap.test (+25)
``````````diff
diff --git a/llvm/lib/ProfileData/InstrProfReader.cpp b/llvm/lib/ProfileData/InstrProfReader.cpp
index 05770f83ed160..44f938ae90553 100644
--- a/llvm/lib/ProfileData/InstrProfReader.cpp
+++ b/llvm/lib/ProfileData/InstrProfReader.cpp
@@ -444,8 +444,12 @@ Error TextInstrProfReader::readNextRecord(NamedInstrProfRecord &Record) {
Record.Counts.push_back(Count);
}
- // Bitmap byte information is indicated with special character.
- if (Line->starts_with("$")) {
+ // Bitmap byte information is indicated by '$' followed by an integer. Only
+ // treat numeric-looking lines as bitmap records so function names such as
+ // Swift manglings beginning with "$s" remain unambiguous.
+ StringRef BitmapSize =
+ Line->starts_with("$") ? Line->drop_front(1).trim() : StringRef();
+ if (!BitmapSize.empty() && isDigit(BitmapSize.front())) {
Record.BitmapBytes.clear();
// Read the number of bitmap bytes.
uint64_t NumBitmapBytes;
diff --git a/llvm/lib/ProfileData/InstrProfWriter.cpp b/llvm/lib/ProfileData/InstrProfWriter.cpp
index 3dbbcc69ba9e2..1dbace34692e2 100644
--- a/llvm/lib/ProfileData/InstrProfWriter.cpp
+++ b/llvm/lib/ProfileData/InstrProfWriter.cpp
@@ -749,8 +749,8 @@ void InstrProfWriter::writeRecordInText(StringRef Name, uint64_t Hash,
for (uint64_t Count : Func.Counts)
OS << Count << "\n";
- if (Func.BitmapBytes.size() > 0) {
- OS << "# Num Bitmap Bytes:\n$" << Func.BitmapBytes.size() << "\n";
+ OS << "# Num Bitmap Bytes:\n$" << Func.BitmapBytes.size() << "\n";
+ if (!Func.BitmapBytes.empty()) {
OS << "# Bitmap Byte Values:\n";
for (uint8_t Byte : Func.BitmapBytes) {
OS << "0x";
diff --git a/llvm/test/tools/llvm-profdata/Inputs/CSIR_profile.proftext b/llvm/test/tools/llvm-profdata/Inputs/CSIR_profile.proftext
index 0881a532a22e9..ea0645c4f53d3 100644
--- a/llvm/test/tools/llvm-profdata/Inputs/CSIR_profile.proftext
+++ b/llvm/test/tools/llvm-profdata/Inputs/CSIR_profile.proftext
@@ -8,4 +8,6 @@ bar
# Counter Values:
99938
62
+# Num Bitmap Bytes:
+$0
diff --git a/llvm/test/tools/llvm-profdata/Inputs/IR_profile.proftext b/llvm/test/tools/llvm-profdata/Inputs/IR_profile.proftext
index 7b7340ec2956a..88321a2ec448e 100644
--- a/llvm/test/tools/llvm-profdata/Inputs/IR_profile.proftext
+++ b/llvm/test/tools/llvm-profdata/Inputs/IR_profile.proftext
@@ -6,4 +6,6 @@ main
1
# Counter Values:
1
+# Num Bitmap Bytes:
+$0
diff --git a/llvm/test/tools/llvm-profdata/Inputs/cs.proftext b/llvm/test/tools/llvm-profdata/Inputs/cs.proftext
index 99e1825b03602..44bf125c0a89b 100644
--- a/llvm/test/tools/llvm-profdata/Inputs/cs.proftext
+++ b/llvm/test/tools/llvm-profdata/Inputs/cs.proftext
@@ -8,3 +8,5 @@ bar
# Counter Values:
99938
62
+# Num Bitmap Bytes:
+$0
diff --git a/llvm/test/tools/llvm-profdata/Inputs/instr-remap.expected b/llvm/test/tools/llvm-profdata/Inputs/instr-remap.expected
index f5ff527301155..373967ef1976c 100644
--- a/llvm/test/tools/llvm-profdata/Inputs/instr-remap.expected
+++ b/llvm/test/tools/llvm-profdata/Inputs/instr-remap.expected
@@ -8,6 +8,8 @@ bar
# Counter Values:
31
42
+# Num Bitmap Bytes:
+$0
bar
# Func Hash:
@@ -17,6 +19,8 @@ bar
# Counter Values:
500
600
+# Num Bitmap Bytes:
+$0
baz
# Func Hash:
@@ -26,4 +30,6 @@ baz
# Counter Values:
7
8
+# Num Bitmap Bytes:
+$0
diff --git a/llvm/test/tools/llvm-profdata/merge-filter.test b/llvm/test/tools/llvm-profdata/merge-filter.test
index 5c47c6a75a7c4..97432c9f01290 100644
--- a/llvm/test/tools/llvm-profdata/merge-filter.test
+++ b/llvm/test/tools/llvm-profdata/merge-filter.test
@@ -31,6 +31,8 @@ CHECK-NEXT: 2
CHECK-NEXT: # Counter Values:
CHECK-NEXT: 499500
CHECK-NEXT: 179900
+CHECK-NEXT: # Num Bitmap Bytes:
+CHECK-NEXT: $0
CHECK-NEXT:
CHECK-NEXT: foo2
CHECK-NEXT: # Func Hash:
@@ -40,6 +42,8 @@ CHECK-NEXT: 2
CHECK-NEXT: # Counter Values:
CHECK-NEXT: 500500
CHECK-NEXT: 180100
+CHECK-NEXT: # Num Bitmap Bytes:
+CHECK-NEXT: $0
RUN: llvm-profdata merge --instr %p/Inputs/basic.proftext --text --function="foo" --no-function="^foo$" | FileCheck %s --check-prefix=CHECK-FILTER4
CHECK-FILTER4: foo2
@@ -50,6 +54,8 @@ CHECK-NEXT: 2
CHECK-NEXT: # Counter Values:
CHECK-NEXT: 500500
CHECK-NEXT: 180100
+CHECK-NEXT: # Num Bitmap Bytes:
+CHECK-NEXT: $0
RUN: llvm-profdata merge --sample %p/Inputs/cs-sample.proftext --text --function="main.*@.*_Z5funcBi" | FileCheck %s --check-prefix=CHECK-FILTER5
CHECK-FILTER5: [main:3.1 @ _Z5funcBi:1 @ _Z8funcLeafi]:500853:20
@@ -66,4 +72,3 @@ CHECK-NEXT: 0: 19
CHECK-NEXT: 1: 19 _Z8funcLeafi:20
CHECK-NEXT: 3: 12
CHECK-NEXT: !Attributes: 1
-
diff --git a/llvm/test/tools/llvm-profdata/text-zero-bitmap.test b/llvm/test/tools/llvm-profdata/text-zero-bitmap.test
new file mode 100644
index 0000000000000..445b076a5e847
--- /dev/null
+++ b/llvm/test/tools/llvm-profdata/text-zero-bitmap.test
@@ -0,0 +1,25 @@
+# A missing zero-bitmap record must not make a following Swift function name
+# look like a bitmap count. The text writer makes the record explicit so its
+# output can be read back without ambiguity.
+RUN: split-file %s %t
+RUN: llvm-profdata merge --instr --text %t/legacy.proftext -o %t/a
+RUN: FileCheck %s --input-file=%t/a --check-prefix=GENERATED
+RUN: llvm-profdata merge --instr --text %t/a -o %t/b
+RUN: diff %t/a %t/b
+
+GENERATED-LABEL: !zero_bitmap
+GENERATED: # Num Bitmap Bytes:
+GENERATED-NEXT: $0
+GENERATED: $s4main3fooyyF
+GENERATED: # Num Bitmap Bytes:
+GENERATED-NEXT: $0
+
+;--- legacy.proftext
+!zero_bitmap
+1
+1
+7
+$s4main3fooyyF
+2
+1
+9
``````````
</details>
https://github.com/llvm/llvm-project/pull/213906
More information about the llvm-commits
mailing list