Skip to content

[SampleFDO] Match functions with the same base function name #126688

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Mar 24, 2025

Conversation

wlei-llvm
Copy link
Contributor

@wlei-llvm wlei-llvm commented Feb 11, 2025

Sometimes, there may be no matched anchors but the functions still match. e.g. if the function’s template typename changes, all the callsites that use the type are mismatched and the caller function that contains those callsite are mismatched. Introduce a check to match the functions if their demangled base names are the same.

@wlei-llvm wlei-llvm marked this pull request as ready for review February 13, 2025 08:00
@llvmbot llvmbot added PGO Profile Guided Optimizations llvm:transforms labels Feb 13, 2025
@llvmbot
Copy link
Member

llvmbot commented Feb 13, 2025

@llvm/pr-subscribers-llvm-transforms

Author: Lei Wang (wlei-llvm)

Changes

Sometimes, there may be no anchors for the profile or IR but the functions still match. Introduce a check to match the functions if their demangled base names are the same.


Full diff: https://github.com/llvm/llvm-project/pull/126688.diff

4 Files Affected:

  • (modified) llvm/lib/Transforms/IPO/CMakeLists.txt (+1)
  • (modified) llvm/lib/Transforms/IPO/SampleProfileMatcher.cpp (+28)
  • (added) llvm/test/Transforms/SampleProfile/Inputs/pseudo-probe-stale-profile-name-similarity.prof (+12)
  • (added) llvm/test/Transforms/SampleProfile/pseudo-probe-stale-profile-name-similarity.ll (+133)
diff --git a/llvm/lib/Transforms/IPO/CMakeLists.txt b/llvm/lib/Transforms/IPO/CMakeLists.txt
index 15cb57399d246..a1ebd0cbbbe3c 100644
--- a/llvm/lib/Transforms/IPO/CMakeLists.txt
+++ b/llvm/lib/Transforms/IPO/CMakeLists.txt
@@ -64,6 +64,7 @@ add_llvm_component_library(LLVMipo
   FrontendOpenMP
   InstCombine
   IRReader
+  Demangle
   Linker
   Object
   ProfileData
diff --git a/llvm/lib/Transforms/IPO/SampleProfileMatcher.cpp b/llvm/lib/Transforms/IPO/SampleProfileMatcher.cpp
index 313a50477a314..f203da82785be 100644
--- a/llvm/lib/Transforms/IPO/SampleProfileMatcher.cpp
+++ b/llvm/lib/Transforms/IPO/SampleProfileMatcher.cpp
@@ -12,6 +12,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "llvm/Transforms/IPO/SampleProfileMatcher.h"
+#include "llvm/Demangle/Demangle.h"
 #include "llvm/IR/IntrinsicInst.h"
 #include "llvm/IR/MDBuilder.h"
 #include "llvm/Support/CommandLine.h"
@@ -727,6 +728,33 @@ bool SampleProfileMatcher::functionMatchesProfileHelper(
   // two sequences are.
   float Similarity = 0.0;
 
+  // Match the functions if they have the same base name(after demangling) and
+  // skip the similarity check.
+  ItaniumPartialDemangler Demangler;
+  // Helper lambda to demangle and get the base name. If the demangling failed,
+  // return an empty string.
+  auto GetBaseName = [&](StringRef FName) {
+    auto FunctionName = FName.str();
+    if (Demangler.partialDemangle(FunctionName.c_str()))
+      return std::string();
+    constexpr size_t MaxBaseNameSize = 4096;
+    char BaseNameBuf[MaxBaseNameSize] = {};
+    size_t BaseNameSize = MaxBaseNameSize;
+    char *BaseNamePtr =
+        Demangler.getFunctionBaseName(BaseNameBuf, &BaseNameSize);
+    return (BaseNamePtr && BaseNameSize)
+               ? std::string(BaseNamePtr, BaseNameSize)
+               : std::string();
+  };
+  auto IRBaseName = GetBaseName(IRFunc.getName());
+  auto ProfBaseName = GetBaseName(ProfFunc.stringRef());
+  if (!IRBaseName.empty() && IRBaseName == ProfBaseName) {
+    LLVM_DEBUG(dbgs() << "The functions " << IRFunc.getName() << "(IR) and "
+                      << ProfFunc << "(Profile) share the same base name: "
+                      << IRBaseName << ".\n");
+    return true;
+  }
+
   const auto *FSForMatching = getFlattenedSamplesFor(ProfFunc);
   // With extbinary profile format, initial profile loading only reads profile
   // based on current function names in the module.
diff --git a/llvm/test/Transforms/SampleProfile/Inputs/pseudo-probe-stale-profile-name-similarity.prof b/llvm/test/Transforms/SampleProfile/Inputs/pseudo-probe-stale-profile-name-similarity.prof
new file mode 100644
index 0000000000000..e194d4d4aae32
--- /dev/null
+++ b/llvm/test/Transforms/SampleProfile/Inputs/pseudo-probe-stale-profile-name-similarity.prof
@@ -0,0 +1,12 @@
+main:200:0
+ 1: 0
+ 2: 50
+ 3: 0
+ 4: 50
+ 5: 52 _Z3fooi:52
+ 6: 50
+ 7: 0
+ !CFGChecksum: 281582264815352
+_Z3fooi:52:52
+ 1: 52
+ !CFGChecksum: 4294967295000
diff --git a/llvm/test/Transforms/SampleProfile/pseudo-probe-stale-profile-name-similarity.ll b/llvm/test/Transforms/SampleProfile/pseudo-probe-stale-profile-name-similarity.ll
new file mode 100644
index 0000000000000..4e435f4586465
--- /dev/null
+++ b/llvm/test/Transforms/SampleProfile/pseudo-probe-stale-profile-name-similarity.ll
@@ -0,0 +1,133 @@
+; REQUIRES: x86_64-linux
+; REQUIRES: asserts
+; RUN: opt < %s -passes=sample-profile -sample-profile-file=%S/Inputs/pseudo-probe-stale-profile-name-similarity.prof --salvage-stale-profile --salvage-unused-profile -S --debug-only=sample-profile,sample-profile-matcher,sample-profile-impl 2>&1 | FileCheck %s
+
+; CHECK: Function _Z3fool is not in profile or profile symbol list.
+; CHECK: Run stale profile matching for main
+; CHECK: The functions _Z3fool(IR) and _Z3fooi(Profile) share the same base name: foo
+; CHECK: Function:_Z3fool matches profile:_Z3fooi
+; CHECK: Run stale profile matching for _Z3fool
+
+
+target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+@x = dso_local global i32 0, align 4, !dbg !0
+
+; Function Attrs: mustprogress noinline nounwind uwtable
+define dso_local void @_Z3fool(i64 noundef %y) #0 !dbg !17 {
+entry:
+    #dbg_value(i64 %y, !22, !DIExpression(), !23)
+  call void @llvm.pseudoprobe(i64 5326982120444056491, i64 1, i32 0, i64 -1), !dbg !24
+  %0 = load volatile i32, ptr @x, align 4, !dbg !25, !tbaa !26
+  %conv = sext i32 %0 to i64, !dbg !25
+  %add = add nsw i64 %conv, %y, !dbg !25
+  %conv1 = trunc i64 %add to i32, !dbg !25
+  store volatile i32 %conv1, ptr @x, align 4, !dbg !25, !tbaa !26
+  ret void, !dbg !30
+}
+
+; Function Attrs: mustprogress norecurse nounwind uwtable
+define dso_local noundef i32 @main() #1 !dbg !31 {
+entry:
+  call void @llvm.pseudoprobe(i64 -2624081020897602054, i64 1, i32 0, i64 -1), !dbg !37
+    #dbg_value(i32 0, !35, !DIExpression(), !38)
+  br label %for.cond, !dbg !39
+
+for.cond:                                         ; preds = %for.body, %entry
+  %i.0 = phi i32 [ 0, %entry ], [ %inc, %for.body ], !dbg !40
+    #dbg_value(i32 %i.0, !35, !DIExpression(), !38)
+  call void @llvm.pseudoprobe(i64 -2624081020897602054, i64 2, i32 0, i64 -1), !dbg !41
+  %cmp = icmp slt i32 %i.0, 1000000, !dbg !43
+  br i1 %cmp, label %for.body, label %for.cond.cleanup, !dbg !44
+
+for.cond.cleanup:                                 ; preds = %for.cond
+  call void @llvm.pseudoprobe(i64 -2624081020897602054, i64 3, i32 0, i64 -1), !dbg !45
+  call void @llvm.pseudoprobe(i64 -2624081020897602054, i64 7, i32 0, i64 -1), !dbg !46
+  ret i32 0, !dbg !46
+
+for.body:                                         ; preds = %for.cond
+  call void @llvm.pseudoprobe(i64 -2624081020897602054, i64 4, i32 0, i64 -1), !dbg !47
+  %conv = sext i32 %i.0 to i64, !dbg !47
+  call void @_Z3fool(i64 noundef %conv), !dbg !49
+  call void @llvm.pseudoprobe(i64 -2624081020897602054, i64 6, i32 0, i64 -1), !dbg !51
+  %inc = add nsw i32 %i.0, 1, !dbg !51
+    #dbg_value(i32 %inc, !35, !DIExpression(), !38)
+  br label %for.cond, !dbg !52, !llvm.loop !53
+}
+
+; Function Attrs: mustprogress nocallback nofree nosync nounwind willreturn memory(argmem: readwrite)
+declare void @llvm.lifetime.start.p0(i64 immarg, ptr captures(none)) #2
+
+; Function Attrs: mustprogress nocallback nofree nosync nounwind willreturn memory(argmem: readwrite)
+declare void @llvm.lifetime.end.p0(i64 immarg, ptr captures(none)) #2
+
+; Function Attrs: mustprogress nocallback nofree nosync nounwind willreturn memory(inaccessiblemem: readwrite)
+declare void @llvm.pseudoprobe(i64, i64, i32, i64) #3
+
+attributes #0 = { mustprogress noinline nounwind uwtable "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" "use-sample-profile" }
+attributes #1 = { mustprogress norecurse nounwind uwtable "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" "use-sample-profile" }
+attributes #2 = { mustprogress nocallback nofree nosync nounwind willreturn memory(argmem: readwrite) }
+attributes #3 = { mustprogress nocallback nofree nosync nounwind willreturn memory(inaccessiblemem: readwrite) }
+
+!llvm.dbg.cu = !{!2}
+!llvm.module.flags = !{!7, !8, !9, !10, !11, !12, !13}
+!llvm.ident = !{!14}
+!llvm.pseudo_probe_desc = !{!15, !16}
+
+!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression())
+!1 = distinct !DIGlobalVariable(name: "x", scope: !2, file: !3, line: 1, type: !5, isLocal: false, isDefinition: true)
+!2 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !3, producer: "clang version 21.0.0git (https://github.com/llvm/llvm-project.git c9f1d2cbf18990311ea1287cc154e3784a10a3b0)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, globals: !4, splitDebugInlining: false, nameTableKind: None)
+!3 = !DIFile(filename: "test_rename.c", directory: "/home", checksumkind: CSK_MD5, checksum: "2991f6c78cef4c393285c97c0f5dabc4")
+!4 = !{!0}
+!5 = !DIDerivedType(tag: DW_TAG_volatile_type, baseType: !6)
+!6 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!7 = !{i32 7, !"Dwarf Version", i32 5}
+!8 = !{i32 2, !"Debug Info Version", i32 3}
+!9 = !{i32 1, !"wchar_size", i32 4}
+!10 = !{i32 8, !"PIC Level", i32 2}
+!11 = !{i32 7, !"PIE Level", i32 2}
+!12 = !{i32 7, !"uwtable", i32 2}
+!13 = !{i32 7, !"debug-info-assignment-tracking", i1 true}
+!14 = !{!"clang version 21.0.0git (https://github.com/llvm/llvm-project.git c9f1d2cbf18990311ea1287cc154e3784a10a3b0)"}
+!15 = !{i64 5326982120444056491, i64 4294967295, !"_Z3fool"}
+!16 = !{i64 -2624081020897602054, i64 281582264815352, !"main"}
+!17 = distinct !DISubprogram(name: "foo", linkageName: "_Z3fool", scope: !3, file: !3, line: 3, type: !18, scopeLine: 3, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !2, retainedNodes: !21)
+!18 = !DISubroutineType(types: !19)
+!19 = !{null, !20}
+!20 = !DIBasicType(name: "long", size: 64, encoding: DW_ATE_signed)
+!21 = !{!22}
+!22 = !DILocalVariable(name: "y", arg: 1, scope: !17, file: !3, line: 3, type: !20)
+!23 = !DILocation(line: 0, scope: !17)
+!24 = !DILocation(line: 4, column: 9, scope: !17)
+!25 = !DILocation(line: 4, column: 6, scope: !17)
+!26 = !{!27, !27, i64 0}
+!27 = !{!"int", !28, i64 0}
+!28 = !{!"omnipotent char", !29, i64 0}
+!29 = !{!"Simple C++ TBAA"}
+!30 = !DILocation(line: 5, column: 1, scope: !17)
+!31 = distinct !DISubprogram(name: "main", scope: !3, file: !3, line: 7, type: !32, scopeLine: 7, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !2, retainedNodes: !34)
+!32 = !DISubroutineType(types: !33)
+!33 = !{!6}
+!34 = !{!35}
+!35 = !DILocalVariable(name: "i", scope: !36, file: !3, line: 8, type: !6)
+!36 = distinct !DILexicalBlock(scope: !31, file: !3, line: 8, column: 3)
+!37 = !DILocation(line: 8, column: 12, scope: !36)
+!38 = !DILocation(line: 0, scope: !36)
+!39 = !DILocation(line: 8, column: 8, scope: !36)
+!40 = !DILocation(line: 8, scope: !36)
+!41 = !DILocation(line: 8, column: 19, scope: !42)
+!42 = distinct !DILexicalBlock(scope: !36, file: !3, line: 8, column: 3)
+!43 = !DILocation(line: 8, column: 21, scope: !42)
+!44 = !DILocation(line: 8, column: 3, scope: !36)
+!45 = !DILocation(line: 0, scope: !31)
+!46 = !DILocation(line: 11, column: 1, scope: !31)
+!47 = !DILocation(line: 9, column: 11, scope: !48)
+!48 = distinct !DILexicalBlock(scope: !42, file: !3, line: 8, column: 41)
+!49 = !DILocation(line: 9, column: 7, scope: !50)
+!50 = !DILexicalBlockFile(scope: !48, file: !3, discriminator: 455082031)
+!51 = !DILocation(line: 8, column: 37, scope: !42)
+!52 = !DILocation(line: 8, column: 3, scope: !42)
+!53 = distinct !{!53, !44, !54, !55}
+!54 = !DILocation(line: 10, column: 3, scope: !36)
+!55 = !{!"llvm.loop.mustprogress"}

@llvmbot
Copy link
Member

llvmbot commented Feb 13, 2025

@llvm/pr-subscribers-pgo

Author: Lei Wang (wlei-llvm)

Changes

Sometimes, there may be no anchors for the profile or IR but the functions still match. Introduce a check to match the functions if their demangled base names are the same.


Full diff: https://github.com/llvm/llvm-project/pull/126688.diff

4 Files Affected:

  • (modified) llvm/lib/Transforms/IPO/CMakeLists.txt (+1)
  • (modified) llvm/lib/Transforms/IPO/SampleProfileMatcher.cpp (+28)
  • (added) llvm/test/Transforms/SampleProfile/Inputs/pseudo-probe-stale-profile-name-similarity.prof (+12)
  • (added) llvm/test/Transforms/SampleProfile/pseudo-probe-stale-profile-name-similarity.ll (+133)
diff --git a/llvm/lib/Transforms/IPO/CMakeLists.txt b/llvm/lib/Transforms/IPO/CMakeLists.txt
index 15cb57399d246..a1ebd0cbbbe3c 100644
--- a/llvm/lib/Transforms/IPO/CMakeLists.txt
+++ b/llvm/lib/Transforms/IPO/CMakeLists.txt
@@ -64,6 +64,7 @@ add_llvm_component_library(LLVMipo
   FrontendOpenMP
   InstCombine
   IRReader
+  Demangle
   Linker
   Object
   ProfileData
diff --git a/llvm/lib/Transforms/IPO/SampleProfileMatcher.cpp b/llvm/lib/Transforms/IPO/SampleProfileMatcher.cpp
index 313a50477a314..f203da82785be 100644
--- a/llvm/lib/Transforms/IPO/SampleProfileMatcher.cpp
+++ b/llvm/lib/Transforms/IPO/SampleProfileMatcher.cpp
@@ -12,6 +12,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "llvm/Transforms/IPO/SampleProfileMatcher.h"
+#include "llvm/Demangle/Demangle.h"
 #include "llvm/IR/IntrinsicInst.h"
 #include "llvm/IR/MDBuilder.h"
 #include "llvm/Support/CommandLine.h"
@@ -727,6 +728,33 @@ bool SampleProfileMatcher::functionMatchesProfileHelper(
   // two sequences are.
   float Similarity = 0.0;
 
+  // Match the functions if they have the same base name(after demangling) and
+  // skip the similarity check.
+  ItaniumPartialDemangler Demangler;
+  // Helper lambda to demangle and get the base name. If the demangling failed,
+  // return an empty string.
+  auto GetBaseName = [&](StringRef FName) {
+    auto FunctionName = FName.str();
+    if (Demangler.partialDemangle(FunctionName.c_str()))
+      return std::string();
+    constexpr size_t MaxBaseNameSize = 4096;
+    char BaseNameBuf[MaxBaseNameSize] = {};
+    size_t BaseNameSize = MaxBaseNameSize;
+    char *BaseNamePtr =
+        Demangler.getFunctionBaseName(BaseNameBuf, &BaseNameSize);
+    return (BaseNamePtr && BaseNameSize)
+               ? std::string(BaseNamePtr, BaseNameSize)
+               : std::string();
+  };
+  auto IRBaseName = GetBaseName(IRFunc.getName());
+  auto ProfBaseName = GetBaseName(ProfFunc.stringRef());
+  if (!IRBaseName.empty() && IRBaseName == ProfBaseName) {
+    LLVM_DEBUG(dbgs() << "The functions " << IRFunc.getName() << "(IR) and "
+                      << ProfFunc << "(Profile) share the same base name: "
+                      << IRBaseName << ".\n");
+    return true;
+  }
+
   const auto *FSForMatching = getFlattenedSamplesFor(ProfFunc);
   // With extbinary profile format, initial profile loading only reads profile
   // based on current function names in the module.
diff --git a/llvm/test/Transforms/SampleProfile/Inputs/pseudo-probe-stale-profile-name-similarity.prof b/llvm/test/Transforms/SampleProfile/Inputs/pseudo-probe-stale-profile-name-similarity.prof
new file mode 100644
index 0000000000000..e194d4d4aae32
--- /dev/null
+++ b/llvm/test/Transforms/SampleProfile/Inputs/pseudo-probe-stale-profile-name-similarity.prof
@@ -0,0 +1,12 @@
+main:200:0
+ 1: 0
+ 2: 50
+ 3: 0
+ 4: 50
+ 5: 52 _Z3fooi:52
+ 6: 50
+ 7: 0
+ !CFGChecksum: 281582264815352
+_Z3fooi:52:52
+ 1: 52
+ !CFGChecksum: 4294967295000
diff --git a/llvm/test/Transforms/SampleProfile/pseudo-probe-stale-profile-name-similarity.ll b/llvm/test/Transforms/SampleProfile/pseudo-probe-stale-profile-name-similarity.ll
new file mode 100644
index 0000000000000..4e435f4586465
--- /dev/null
+++ b/llvm/test/Transforms/SampleProfile/pseudo-probe-stale-profile-name-similarity.ll
@@ -0,0 +1,133 @@
+; REQUIRES: x86_64-linux
+; REQUIRES: asserts
+; RUN: opt < %s -passes=sample-profile -sample-profile-file=%S/Inputs/pseudo-probe-stale-profile-name-similarity.prof --salvage-stale-profile --salvage-unused-profile -S --debug-only=sample-profile,sample-profile-matcher,sample-profile-impl 2>&1 | FileCheck %s
+
+; CHECK: Function _Z3fool is not in profile or profile symbol list.
+; CHECK: Run stale profile matching for main
+; CHECK: The functions _Z3fool(IR) and _Z3fooi(Profile) share the same base name: foo
+; CHECK: Function:_Z3fool matches profile:_Z3fooi
+; CHECK: Run stale profile matching for _Z3fool
+
+
+target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+@x = dso_local global i32 0, align 4, !dbg !0
+
+; Function Attrs: mustprogress noinline nounwind uwtable
+define dso_local void @_Z3fool(i64 noundef %y) #0 !dbg !17 {
+entry:
+    #dbg_value(i64 %y, !22, !DIExpression(), !23)
+  call void @llvm.pseudoprobe(i64 5326982120444056491, i64 1, i32 0, i64 -1), !dbg !24
+  %0 = load volatile i32, ptr @x, align 4, !dbg !25, !tbaa !26
+  %conv = sext i32 %0 to i64, !dbg !25
+  %add = add nsw i64 %conv, %y, !dbg !25
+  %conv1 = trunc i64 %add to i32, !dbg !25
+  store volatile i32 %conv1, ptr @x, align 4, !dbg !25, !tbaa !26
+  ret void, !dbg !30
+}
+
+; Function Attrs: mustprogress norecurse nounwind uwtable
+define dso_local noundef i32 @main() #1 !dbg !31 {
+entry:
+  call void @llvm.pseudoprobe(i64 -2624081020897602054, i64 1, i32 0, i64 -1), !dbg !37
+    #dbg_value(i32 0, !35, !DIExpression(), !38)
+  br label %for.cond, !dbg !39
+
+for.cond:                                         ; preds = %for.body, %entry
+  %i.0 = phi i32 [ 0, %entry ], [ %inc, %for.body ], !dbg !40
+    #dbg_value(i32 %i.0, !35, !DIExpression(), !38)
+  call void @llvm.pseudoprobe(i64 -2624081020897602054, i64 2, i32 0, i64 -1), !dbg !41
+  %cmp = icmp slt i32 %i.0, 1000000, !dbg !43
+  br i1 %cmp, label %for.body, label %for.cond.cleanup, !dbg !44
+
+for.cond.cleanup:                                 ; preds = %for.cond
+  call void @llvm.pseudoprobe(i64 -2624081020897602054, i64 3, i32 0, i64 -1), !dbg !45
+  call void @llvm.pseudoprobe(i64 -2624081020897602054, i64 7, i32 0, i64 -1), !dbg !46
+  ret i32 0, !dbg !46
+
+for.body:                                         ; preds = %for.cond
+  call void @llvm.pseudoprobe(i64 -2624081020897602054, i64 4, i32 0, i64 -1), !dbg !47
+  %conv = sext i32 %i.0 to i64, !dbg !47
+  call void @_Z3fool(i64 noundef %conv), !dbg !49
+  call void @llvm.pseudoprobe(i64 -2624081020897602054, i64 6, i32 0, i64 -1), !dbg !51
+  %inc = add nsw i32 %i.0, 1, !dbg !51
+    #dbg_value(i32 %inc, !35, !DIExpression(), !38)
+  br label %for.cond, !dbg !52, !llvm.loop !53
+}
+
+; Function Attrs: mustprogress nocallback nofree nosync nounwind willreturn memory(argmem: readwrite)
+declare void @llvm.lifetime.start.p0(i64 immarg, ptr captures(none)) #2
+
+; Function Attrs: mustprogress nocallback nofree nosync nounwind willreturn memory(argmem: readwrite)
+declare void @llvm.lifetime.end.p0(i64 immarg, ptr captures(none)) #2
+
+; Function Attrs: mustprogress nocallback nofree nosync nounwind willreturn memory(inaccessiblemem: readwrite)
+declare void @llvm.pseudoprobe(i64, i64, i32, i64) #3
+
+attributes #0 = { mustprogress noinline nounwind uwtable "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" "use-sample-profile" }
+attributes #1 = { mustprogress norecurse nounwind uwtable "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" "use-sample-profile" }
+attributes #2 = { mustprogress nocallback nofree nosync nounwind willreturn memory(argmem: readwrite) }
+attributes #3 = { mustprogress nocallback nofree nosync nounwind willreturn memory(inaccessiblemem: readwrite) }
+
+!llvm.dbg.cu = !{!2}
+!llvm.module.flags = !{!7, !8, !9, !10, !11, !12, !13}
+!llvm.ident = !{!14}
+!llvm.pseudo_probe_desc = !{!15, !16}
+
+!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression())
+!1 = distinct !DIGlobalVariable(name: "x", scope: !2, file: !3, line: 1, type: !5, isLocal: false, isDefinition: true)
+!2 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !3, producer: "clang version 21.0.0git (https://github.com/llvm/llvm-project.git c9f1d2cbf18990311ea1287cc154e3784a10a3b0)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, globals: !4, splitDebugInlining: false, nameTableKind: None)
+!3 = !DIFile(filename: "test_rename.c", directory: "/home", checksumkind: CSK_MD5, checksum: "2991f6c78cef4c393285c97c0f5dabc4")
+!4 = !{!0}
+!5 = !DIDerivedType(tag: DW_TAG_volatile_type, baseType: !6)
+!6 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!7 = !{i32 7, !"Dwarf Version", i32 5}
+!8 = !{i32 2, !"Debug Info Version", i32 3}
+!9 = !{i32 1, !"wchar_size", i32 4}
+!10 = !{i32 8, !"PIC Level", i32 2}
+!11 = !{i32 7, !"PIE Level", i32 2}
+!12 = !{i32 7, !"uwtable", i32 2}
+!13 = !{i32 7, !"debug-info-assignment-tracking", i1 true}
+!14 = !{!"clang version 21.0.0git (https://github.com/llvm/llvm-project.git c9f1d2cbf18990311ea1287cc154e3784a10a3b0)"}
+!15 = !{i64 5326982120444056491, i64 4294967295, !"_Z3fool"}
+!16 = !{i64 -2624081020897602054, i64 281582264815352, !"main"}
+!17 = distinct !DISubprogram(name: "foo", linkageName: "_Z3fool", scope: !3, file: !3, line: 3, type: !18, scopeLine: 3, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !2, retainedNodes: !21)
+!18 = !DISubroutineType(types: !19)
+!19 = !{null, !20}
+!20 = !DIBasicType(name: "long", size: 64, encoding: DW_ATE_signed)
+!21 = !{!22}
+!22 = !DILocalVariable(name: "y", arg: 1, scope: !17, file: !3, line: 3, type: !20)
+!23 = !DILocation(line: 0, scope: !17)
+!24 = !DILocation(line: 4, column: 9, scope: !17)
+!25 = !DILocation(line: 4, column: 6, scope: !17)
+!26 = !{!27, !27, i64 0}
+!27 = !{!"int", !28, i64 0}
+!28 = !{!"omnipotent char", !29, i64 0}
+!29 = !{!"Simple C++ TBAA"}
+!30 = !DILocation(line: 5, column: 1, scope: !17)
+!31 = distinct !DISubprogram(name: "main", scope: !3, file: !3, line: 7, type: !32, scopeLine: 7, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !2, retainedNodes: !34)
+!32 = !DISubroutineType(types: !33)
+!33 = !{!6}
+!34 = !{!35}
+!35 = !DILocalVariable(name: "i", scope: !36, file: !3, line: 8, type: !6)
+!36 = distinct !DILexicalBlock(scope: !31, file: !3, line: 8, column: 3)
+!37 = !DILocation(line: 8, column: 12, scope: !36)
+!38 = !DILocation(line: 0, scope: !36)
+!39 = !DILocation(line: 8, column: 8, scope: !36)
+!40 = !DILocation(line: 8, scope: !36)
+!41 = !DILocation(line: 8, column: 19, scope: !42)
+!42 = distinct !DILexicalBlock(scope: !36, file: !3, line: 8, column: 3)
+!43 = !DILocation(line: 8, column: 21, scope: !42)
+!44 = !DILocation(line: 8, column: 3, scope: !36)
+!45 = !DILocation(line: 0, scope: !31)
+!46 = !DILocation(line: 11, column: 1, scope: !31)
+!47 = !DILocation(line: 9, column: 11, scope: !48)
+!48 = distinct !DILexicalBlock(scope: !42, file: !3, line: 8, column: 41)
+!49 = !DILocation(line: 9, column: 7, scope: !50)
+!50 = !DILexicalBlockFile(scope: !48, file: !3, discriminator: 455082031)
+!51 = !DILocation(line: 8, column: 37, scope: !42)
+!52 = !DILocation(line: 8, column: 3, scope: !42)
+!53 = distinct !{!53, !44, !54, !55}
+!54 = !DILocation(line: 10, column: 3, scope: !36)
+!55 = !{!"llvm.loop.mustprogress"}

Copy link
Member

@WenleiHe WenleiHe left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

there may be no anchors for the profile or IR but the functions still match

When does that happen?

Comment on lines +746 to +747
? std::string(BaseNamePtr, BaseNameSize)
: std::string();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Haven't looked closely, but is BaseNamePtr reusing some the buffer from BaseNameBuf? We cannot return anything pointing to local buffer.

Copy link
Contributor Author

@wlei-llvm wlei-llvm Feb 22, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I checked the https://cplusplus.com/reference/string/string/string/, for std::string ctor

(4) from c-string
Copies the null-terminated character sequence (C-string) pointed by s.

the std::string(const char* s, size_t n) ctor doesn't reuse the memory from the input s but creates an internal memory to copy the value. So it doesn't return value from the local buffer(BaseNameBuf)

? std::string(BaseNamePtr, BaseNameSize)
: std::string();
};
auto IRBaseName = GetBaseName(IRFunc.getName());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does the base name include parameters? can we differentiate overload functions with the base name only? If not, I wonder if we should treat base name comparison as a fall back only when there is no anchor in functions?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point. It doesn't include the parameters. I was thinking to make the check in the early place so that if it passes, we can skip the later anchor LCS which is a heavy check.

If not, I wonder if we should treat base name comparison as a fall back only when there is no anchor in functions?

I see, but then it doesn't work for the case I mentioned in other comment, where all the anchors are mismatched but the function still match. Seems like a tradeoff
(1) mismatch between overload functions vs (2) mismatch with all parameter changes.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, I wonder if we should do this in bottom-up manner.

For leaf functions, base-name match is enough to conclude a match (currently we conclude mismatch as we don't have enough number of anchors there), but for non-leaf, it can still depend on match from its child? That should safer?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess if we are not doing the function/profile comparison recursively, what I suggested above won't work.
Are we doing it recursively when we cannot decide if where a callee funciton/profile is a match?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess if we are not doing the function/profile comparison recursively, what I suggested above won't work.
Are we doing it recursively when we cannot decide if where a callee funciton/profile is a match?

Yeah, we don't do it recursively, we only look up for two levels for a matched caller.

@snehasish
Copy link
Contributor

@kazutakahirata I think this is relevant for memprof anchor matching too.

@wlei-llvm
Copy link
Contributor Author

there may be no anchors for the profile or IR but the functions still match

When does that happen?

I observed some cases:
The class uses template type(typename), and there could be changes for the type(like using bitset and the size changes)
and all the functions in the class use this type as parameter, so when the type changed, all the function's signature changed.
In a caller function that uses the functions, those callsite anchors are all mismatched. This is a match case as just simple bitset size change.

Copy link
Member

@WenleiHe WenleiHe left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm, thanks.

@wlei-llvm wlei-llvm merged commit 8f3f93c into llvm:main Mar 24, 2025
12 checks passed
@llvm-ci
Copy link
Collaborator

llvm-ci commented Mar 24, 2025

LLVM Buildbot has detected a new failure on builder llvm-clang-x86_64-gcc-ubuntu running on sie-linux-worker3 while building llvm at step 6 "test-build-unified-tree-check-all".

Full details are available at: https://lab.llvm.org/buildbot/#/builders/174/builds/15074

Here is the relevant piece of the build log for the reference
Step 6 (test-build-unified-tree-check-all) failure: test (failure)
******************** TEST 'libFuzzer-x86_64-default-Linux :: reduce_inputs.test' FAILED ********************
Exit Code: 1

Command Output (stderr):
--
RUN: at line 3: rm -rf /home/buildbot/buildbot-root/llvm-clang-x86_64-gcc-ubuntu/build/runtimes/runtimes-bins/compiler-rt/test/fuzzer/X86_64DefaultLinuxConfig/Output/reduce_inputs.test.tmp/C
+ rm -rf /home/buildbot/buildbot-root/llvm-clang-x86_64-gcc-ubuntu/build/runtimes/runtimes-bins/compiler-rt/test/fuzzer/X86_64DefaultLinuxConfig/Output/reduce_inputs.test.tmp/C
RUN: at line 4: mkdir -p /home/buildbot/buildbot-root/llvm-clang-x86_64-gcc-ubuntu/build/runtimes/runtimes-bins/compiler-rt/test/fuzzer/X86_64DefaultLinuxConfig/Output/reduce_inputs.test.tmp/C
+ mkdir -p /home/buildbot/buildbot-root/llvm-clang-x86_64-gcc-ubuntu/build/runtimes/runtimes-bins/compiler-rt/test/fuzzer/X86_64DefaultLinuxConfig/Output/reduce_inputs.test.tmp/C
RUN: at line 5: /home/buildbot/buildbot-root/llvm-clang-x86_64-gcc-ubuntu/build/./bin/clang    -Wthread-safety -Wthread-safety-reference -Wthread-safety-beta   --driver-mode=g++ -O2 -gline-tables-only -fsanitize=address,fuzzer -I/home/buildbot/buildbot-root/llvm-clang-x86_64-gcc-ubuntu/llvm-project/compiler-rt/lib/fuzzer -m64 /home/buildbot/buildbot-root/llvm-clang-x86_64-gcc-ubuntu/llvm-project/compiler-rt/test/fuzzer/ShrinkControlFlowSimpleTest.cpp -o /home/buildbot/buildbot-root/llvm-clang-x86_64-gcc-ubuntu/build/runtimes/runtimes-bins/compiler-rt/test/fuzzer/X86_64DefaultLinuxConfig/Output/reduce_inputs.test.tmp-ShrinkControlFlowSimpleTest
+ /home/buildbot/buildbot-root/llvm-clang-x86_64-gcc-ubuntu/build/./bin/clang -Wthread-safety -Wthread-safety-reference -Wthread-safety-beta --driver-mode=g++ -O2 -gline-tables-only -fsanitize=address,fuzzer -I/home/buildbot/buildbot-root/llvm-clang-x86_64-gcc-ubuntu/llvm-project/compiler-rt/lib/fuzzer -m64 /home/buildbot/buildbot-root/llvm-clang-x86_64-gcc-ubuntu/llvm-project/compiler-rt/test/fuzzer/ShrinkControlFlowSimpleTest.cpp -o /home/buildbot/buildbot-root/llvm-clang-x86_64-gcc-ubuntu/build/runtimes/runtimes-bins/compiler-rt/test/fuzzer/X86_64DefaultLinuxConfig/Output/reduce_inputs.test.tmp-ShrinkControlFlowSimpleTest
RUN: at line 6: /home/buildbot/buildbot-root/llvm-clang-x86_64-gcc-ubuntu/build/./bin/clang    -Wthread-safety -Wthread-safety-reference -Wthread-safety-beta   --driver-mode=g++ -O2 -gline-tables-only -fsanitize=address,fuzzer -I/home/buildbot/buildbot-root/llvm-clang-x86_64-gcc-ubuntu/llvm-project/compiler-rt/lib/fuzzer -m64 /home/buildbot/buildbot-root/llvm-clang-x86_64-gcc-ubuntu/llvm-project/compiler-rt/test/fuzzer/ShrinkControlFlowTest.cpp -o /home/buildbot/buildbot-root/llvm-clang-x86_64-gcc-ubuntu/build/runtimes/runtimes-bins/compiler-rt/test/fuzzer/X86_64DefaultLinuxConfig/Output/reduce_inputs.test.tmp-ShrinkControlFlowTest
+ /home/buildbot/buildbot-root/llvm-clang-x86_64-gcc-ubuntu/build/./bin/clang -Wthread-safety -Wthread-safety-reference -Wthread-safety-beta --driver-mode=g++ -O2 -gline-tables-only -fsanitize=address,fuzzer -I/home/buildbot/buildbot-root/llvm-clang-x86_64-gcc-ubuntu/llvm-project/compiler-rt/lib/fuzzer -m64 /home/buildbot/buildbot-root/llvm-clang-x86_64-gcc-ubuntu/llvm-project/compiler-rt/test/fuzzer/ShrinkControlFlowTest.cpp -o /home/buildbot/buildbot-root/llvm-clang-x86_64-gcc-ubuntu/build/runtimes/runtimes-bins/compiler-rt/test/fuzzer/X86_64DefaultLinuxConfig/Output/reduce_inputs.test.tmp-ShrinkControlFlowTest
RUN: at line 7: /home/buildbot/buildbot-root/llvm-clang-x86_64-gcc-ubuntu/build/runtimes/runtimes-bins/compiler-rt/test/fuzzer/X86_64DefaultLinuxConfig/Output/reduce_inputs.test.tmp-ShrinkControlFlowSimpleTest  -exit_on_item=0eb8e4ed029b774d80f2b66408203801cb982a60   -runs=1000000 /home/buildbot/buildbot-root/llvm-clang-x86_64-gcc-ubuntu/build/runtimes/runtimes-bins/compiler-rt/test/fuzzer/X86_64DefaultLinuxConfig/Output/reduce_inputs.test.tmp/C 2>&1 | FileCheck /home/buildbot/buildbot-root/llvm-clang-x86_64-gcc-ubuntu/llvm-project/compiler-rt/test/fuzzer/reduce_inputs.test
+ FileCheck /home/buildbot/buildbot-root/llvm-clang-x86_64-gcc-ubuntu/llvm-project/compiler-rt/test/fuzzer/reduce_inputs.test
+ /home/buildbot/buildbot-root/llvm-clang-x86_64-gcc-ubuntu/build/runtimes/runtimes-bins/compiler-rt/test/fuzzer/X86_64DefaultLinuxConfig/Output/reduce_inputs.test.tmp-ShrinkControlFlowSimpleTest -exit_on_item=0eb8e4ed029b774d80f2b66408203801cb982a60 -runs=1000000 /home/buildbot/buildbot-root/llvm-clang-x86_64-gcc-ubuntu/build/runtimes/runtimes-bins/compiler-rt/test/fuzzer/X86_64DefaultLinuxConfig/Output/reduce_inputs.test.tmp/C
RUN: at line 11: /home/buildbot/buildbot-root/llvm-clang-x86_64-gcc-ubuntu/build/runtimes/runtimes-bins/compiler-rt/test/fuzzer/X86_64DefaultLinuxConfig/Output/reduce_inputs.test.tmp-ShrinkControlFlowSimpleTest -runs=0 /home/buildbot/buildbot-root/llvm-clang-x86_64-gcc-ubuntu/build/runtimes/runtimes-bins/compiler-rt/test/fuzzer/X86_64DefaultLinuxConfig/Output/reduce_inputs.test.tmp/C 2>&1 | FileCheck /home/buildbot/buildbot-root/llvm-clang-x86_64-gcc-ubuntu/llvm-project/compiler-rt/test/fuzzer/reduce_inputs.test --check-prefix=COUNT
+ /home/buildbot/buildbot-root/llvm-clang-x86_64-gcc-ubuntu/build/runtimes/runtimes-bins/compiler-rt/test/fuzzer/X86_64DefaultLinuxConfig/Output/reduce_inputs.test.tmp-ShrinkControlFlowSimpleTest -runs=0 /home/buildbot/buildbot-root/llvm-clang-x86_64-gcc-ubuntu/build/runtimes/runtimes-bins/compiler-rt/test/fuzzer/X86_64DefaultLinuxConfig/Output/reduce_inputs.test.tmp/C
+ FileCheck /home/buildbot/buildbot-root/llvm-clang-x86_64-gcc-ubuntu/llvm-project/compiler-rt/test/fuzzer/reduce_inputs.test --check-prefix=COUNT
�[1m/home/buildbot/buildbot-root/llvm-clang-x86_64-gcc-ubuntu/llvm-project/compiler-rt/test/fuzzer/reduce_inputs.test:12:8: �[0m�[0;1;31merror: �[0m�[1mCOUNT: expected string not found in input
�[0mCOUNT: seed corpus: files: 4
�[0;1;32m       ^
�[0m�[1m<stdin>:1:1: �[0m�[0;1;30mnote: �[0m�[1mscanning from here
�[0mINFO: Running with entropic power schedule (0xFF, 100).
�[0;1;32m^
�[0m�[1m<stdin>:7:7: �[0m�[0;1;30mnote: �[0m�[1mpossible intended match here
�[0mINFO: seed corpus: files: 3 min: 2b max: 3b total: 7b rss: 31Mb
�[0;1;32m      ^
�[0m
Input file: <stdin>
Check file: /home/buildbot/buildbot-root/llvm-clang-x86_64-gcc-ubuntu/llvm-project/compiler-rt/test/fuzzer/reduce_inputs.test

-dump-input=help explains the following input dump.

Input was:
<<<<<<
�[1m�[0m�[0;1;30m            1: �[0m�[1m�[0;1;46mINFO: Running with entropic power schedule (0xFF, 100). �[0m
�[0;1;31mcheck:12'0     X~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: no match found
�[0m�[0;1;30m            2: �[0m�[1m�[0;1;46mINFO: Seed: 1689091108 �[0m
�[0;1;31mcheck:12'0     ~~~~~~~~~~~~~~~~~~~~~~~
�[0m�[0;1;30m            3: �[0m�[1m�[0;1;46mINFO: Loaded 1 modules (6 inline 8-bit counters): 6 [0x5593d144ee60, 0x5593d144ee66),  �[0m
�[0;1;31mcheck:12'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
�[0m�[0;1;30m            4: �[0m�[1m�[0;1;46mINFO: Loaded 1 PC tables (6 PCs): 6 [0x5593d144ee68,0x5593d144eec8),  �[0m
�[0;1;31mcheck:12'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
�[0m�[0;1;30m            5: �[0m�[1m�[0;1;46mINFO: 3 files found in /home/buildbot/buildbot-root/llvm-clang-x86_64-gcc-ubuntu/build/runtimes/runtimes-bins/compiler-rt/test/fuzzer/X86_64DefaultLinuxConfig/Output/reduce_inputs.test.tmp/C �[0m
�[0;1;31mcheck:12'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
�[0m�[0;1;30m            6: �[0m�[1m�[0;1;46mINFO: -max_len is not provided; libFuzzer will not generate inputs larger than 4096 bytes �[0m
�[0;1;31mcheck:12'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
�[0m�[0;1;30m            7: �[0m�[1m�[0;1;46mINFO: seed corpus: files: 3 min: 2b max: 3b total: 7b rss: 31Mb �[0m
�[0;1;31mcheck:12'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
llvm:transforms PGO Profile Guided Optimizations
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants