[llvm] [SampleProfileMatcher] Add direct basename early matching for orphan functions (PR #184409)
Grigory Pastukhov via llvm-commits
llvm-commits at lists.llvm.org
Wed Mar 4 17:54:39 PST 2026
================
@@ -728,6 +732,121 @@ void SampleProfileMatcher::findFunctionsWithoutProfile() {
}
}
+// Demangle \p FName and return the base function name (stripping namespaces,
+// templates, and parameter types). Returns an empty string on failure.
+static std::string getDemangledBaseName(ItaniumPartialDemangler &Demangler,
+ StringRef FName) {
+ auto FunctionName = FName.str();
+ if (Demangler.partialDemangle(FunctionName.c_str()))
+ return std::string();
+ size_t BaseNameSize = 0;
+ // The demangler API follows the __cxa_demangle one, and thus needs a
+ // pointer that originates from malloc (or nullptr) and the caller is
+ // responsible for free()-ing the buffer.
+ char *BaseNamePtr = Demangler.getFunctionBaseName(nullptr, &BaseNameSize);
+ std::string Result = (BaseNamePtr && BaseNameSize)
+ ? std::string(BaseNamePtr, BaseNameSize)
+ : std::string();
+ free(BaseNamePtr);
+ // Trim trailing whitespace/null — getFunctionBaseName may include trailing
+ // characters in the reported size.
+ while (!Result.empty() && (Result.back() == ' ' || Result.back() == '\0'))
+ Result.pop_back();
+ return Result;
+}
+
+void SampleProfileMatcher::matchFunctionsWithoutProfileByBasename() {
+ if (FunctionsWithoutProfile.empty() || !LoadFuncProfileforCGMatching)
+ return;
+ auto *NameTable = Reader.getNameTable();
+ if (!NameTable)
+ return;
+
+ ItaniumPartialDemangler Demangler;
+
+ // Build a map from demangled basename to orphan function. Only keep
+ // basenames that map to exactly one orphan — ambiguous basenames like
+ // "get" or "operator()" would produce false positives.
+ StringMap<Function *> OrphansByBaseName;
+ StringSet<> AmbiguousBaseNames;
+ for (auto &[FuncId, Func] : FunctionsWithoutProfile) {
+ std::string BaseName = getDemangledBaseName(Demangler, Func->getName());
+ if (BaseName.empty() || AmbiguousBaseNames.count(BaseName))
+ continue;
+ auto [It, Inserted] = OrphansByBaseName.try_emplace(BaseName, Func);
+ if (!Inserted) {
+ // More than one orphan shares this basename — mark ambiguous.
+ OrphansByBaseName.erase(It);
+ AmbiguousBaseNames.insert(BaseName);
+ }
+ }
+ if (OrphansByBaseName.empty())
+ return;
+
+ // Scan the profile NameTable for candidates whose demangled basename matches
+ // a unique orphan. Use a quick substring check to avoid demangling every
+ // entry. Only keep 1:1 basename matches (exactly one profile candidate).
+ // Maps basename -> profile FunctionId; entries with multiple candidates are
+ // removed.
+ StringMap<FunctionId> CandidateByBaseName;
+ for (auto &ProfileFuncId : *NameTable) {
+ StringRef ProfName = ProfileFuncId.stringRef();
+ if (ProfName.empty())
+ continue;
+ for (auto &[BaseName, _] : OrphansByBaseName) {
----------------
grigorypas wrote:
I wonder what is the build time impact given the nested for loops. Did you measure on any binaries?
https://github.com/llvm/llvm-project/pull/184409
More information about the llvm-commits
mailing list