[clang] 3a02cca - [Darwin][Clang][PGO] Pass CSPGO related flags to ld when using libLTO.dylib (#195020)
via cfe-commits
cfe-commits at lists.llvm.org
Mon May 4 11:47:56 PDT 2026
Author: Henry Jiang
Date: 2026-05-04T11:47:50-07:00
New Revision: 3a02cca3a351e5b040cd2f29e5a0519cc2175d30
URL: https://github.com/llvm/llvm-project/commit/3a02cca3a351e5b040cd2f29e5a0519cc2175d30
DIFF: https://github.com/llvm/llvm-project/commit/3a02cca3a351e5b040cd2f29e5a0519cc2175d30.diff
LOG: [Darwin][Clang][PGO] Pass CSPGO related flags to ld when using libLTO.dylib (#195020)
Context-sensitive PGO is currently broken when using libLTO.dylib with
ld on Darwin.
1. `Config.RunCSIRInstr` was not set, and was always false.
2. `ThinLTOCodeGenerator::optimizeModule` always passes an empty
PGOOptions.
3. CSPGO flags were only passed for LLD. Now pass to the linker with
`-mllvm` prefix.
Added:
llvm/test/tools/llvm-lto/Inputs/cspgo-cs.proftext
llvm/test/tools/llvm-lto/Inputs/cspgo-noncs.proftext
llvm/test/tools/llvm-lto/cspgo-generate.ll
llvm/test/tools/llvm-lto/cspgo-thinlto-generate.ll
llvm/test/tools/llvm-lto/cspgo-thinlto-use.ll
llvm/test/tools/llvm-lto/cspgo-use.ll
Modified:
clang/lib/Driver/ToolChains/Darwin.cpp
clang/test/Driver/cspgo-lto.c
llvm/lib/LTO/LTOCodeGenerator.cpp
llvm/lib/LTO/ThinLTOCodeGenerator.cpp
Removed:
################################################################################
diff --git a/clang/lib/Driver/ToolChains/Darwin.cpp b/clang/lib/Driver/ToolChains/Darwin.cpp
index 6fd8583a57d0f..79b0544457650 100644
--- a/clang/lib/Driver/ToolChains/Darwin.cpp
+++ b/clang/lib/Driver/ToolChains/Darwin.cpp
@@ -497,6 +497,24 @@ void darwin::Linker::AddLinkArgs(Compilation &C, const ArgList &Args,
CmdArgs.push_back(
Args.MakeArgString(Twine("--codegen-data-generate-path=") +
CodeGenDataGenArg->getValue()));
+ } else {
+ if (auto *CSPGOGenerateArg = getLastCSProfileGenerateArg(Args)) {
+ SmallString<128> Path(CSPGOGenerateArg->getNumValues() == 0
+ ? ""
+ : CSPGOGenerateArg->getValue());
+ llvm::sys::path::append(Path, "default_%m.profraw");
+ CmdArgs.push_back("-mllvm");
+ CmdArgs.push_back("-cs-profile-generate");
+ CmdArgs.push_back("-mllvm");
+ CmdArgs.push_back(Args.MakeArgString(Twine("-cs-profile-path=") + Path));
+ } else if (auto *ProfileUseArg = getLastProfileUseArg(Args)) {
+ SmallString<128> Path(
+ ProfileUseArg->getNumValues() == 0 ? "" : ProfileUseArg->getValue());
+ if (Path.empty() || llvm::sys::fs::is_directory(Path))
+ llvm::sys::path::append(Path, "default.profdata");
+ CmdArgs.push_back("-mllvm");
+ CmdArgs.push_back(Args.MakeArgString(Twine("-cs-profile-path=") + Path));
+ }
}
}
diff --git a/clang/test/Driver/cspgo-lto.c b/clang/test/Driver/cspgo-lto.c
index 232d21bbf948a..e9420d7972b14 100644
--- a/clang/test/Driver/cspgo-lto.c
+++ b/clang/test/Driver/cspgo-lto.c
@@ -18,3 +18,19 @@
// DARWIN-GEN1-SAME: "--cs-profile-path=default_%m.profraw"
// DARWIN-GEN2: "--cs-profile-generate"
// DARWIN-GEN2-SAME: "--cs-profile-path=directory{{(/|\\\\)}}default_%m.profraw"
+
+// RUN: %clang --target=arm64-apple-macos -### %t.o -flto=thin -fcs-profile-generate 2>&1 | FileCheck %s --check-prefix=DARWIN-LD-GEN1
+// RUN: %clang --target=arm64-apple-macos -### %t.o -flto=thin -fcs-profile-generate=directory 2>&1 | FileCheck %s --check-prefix=DARWIN-LD-GEN2
+
+// DARWIN-LD-GEN1: "-mllvm" "-cs-profile-generate"
+// DARWIN-LD-GEN1-SAME: "-mllvm" "-cs-profile-path=default_%m.profraw"
+// DARWIN-LD-GEN2: "-mllvm" "-cs-profile-generate"
+// DARWIN-LD-GEN2-SAME: "-mllvm" "-cs-profile-path=directory{{(/|\\\\)}}default_%m.profraw"
+
+// RUN: %clang --target=arm64-apple-macos -### %t.o -flto=thin -fprofile-use 2>&1 | FileCheck %s --check-prefix=DARWIN-LD-USE1
+// RUN: %clang --target=arm64-apple-macos -### %t.o -flto=thin -fprofile-use=a.profdata 2>&1 | FileCheck %s --check-prefix=DARWIN-LD-USE2
+
+// DARWIN-LD-USE1-NOT: "-cs-profile-generate"
+// DARWIN-LD-USE1: "-mllvm" "-cs-profile-path=default.profdata"
+// DARWIN-LD-USE2-NOT: "-cs-profile-generate"
+// DARWIN-LD-USE2: "-mllvm" "-cs-profile-path=a.profdata"
diff --git a/llvm/lib/LTO/LTOCodeGenerator.cpp b/llvm/lib/LTO/LTOCodeGenerator.cpp
index 46be71da5a092..321826618bc69 100644
--- a/llvm/lib/LTO/LTOCodeGenerator.cpp
+++ b/llvm/lib/LTO/LTOCodeGenerator.cpp
@@ -111,11 +111,11 @@ static cl::opt<std::string> AIXSystemAssemblerPath(
cl::desc("Path to a system assembler, picked up on AIX only"),
cl::value_desc("path"));
-static cl::opt<bool>
+cl::opt<bool>
LTORunCSIRInstr("cs-profile-generate",
cl::desc("Perform context sensitive PGO instrumentation"));
-static cl::opt<std::string>
+cl::opt<std::string>
LTOCSIRProfile("cs-profile-path",
cl::desc("Context sensitive profile file path"));
} // namespace llvm
@@ -557,6 +557,9 @@ bool LTOCodeGenerator::optimize() {
// libLTO parses options late, so re-set them here.
Context.setDiscardValueNames(LTODiscardValueNames);
+ Config.StatsFile = LTOStatsFile;
+ Config.RunCSIRInstr = LTORunCSIRInstr;
+ Config.CSIRProfile = LTOCSIRProfile;
auto DiagFileOrErr = lto::setupLLVMOptimizationRemarks(
Context, RemarksFilename, RemarksPasses, RemarksFormat,
diff --git a/llvm/lib/LTO/ThinLTOCodeGenerator.cpp b/llvm/lib/LTO/ThinLTOCodeGenerator.cpp
index 93b672ae7840c..41d83a591a37b 100644
--- a/llvm/lib/LTO/ThinLTOCodeGenerator.cpp
+++ b/llvm/lib/LTO/ThinLTOCodeGenerator.cpp
@@ -79,6 +79,8 @@ extern cl::opt<bool> RemarksWithHotness;
extern cl::opt<std::optional<uint64_t>, false, remarks::HotnessThresholdParser>
RemarksHotnessThreshold;
extern cl::opt<std::string> RemarksFormat;
+extern cl::opt<bool> LTORunCSIRInstr;
+extern cl::opt<std::string> LTOCSIRProfile;
}
// Default to using all available threads in the system, but using only one
@@ -235,6 +237,16 @@ static void optimizeModule(Module &TheModule, TargetMachine &TM,
unsigned OptLevel, bool Freestanding,
bool DebugPassManager, ModuleSummaryIndex *Index) {
std::optional<PGOOptions> PGOOpt;
+ if (LTORunCSIRInstr) {
+ PGOOpt =
+ PGOOptions("", LTOCSIRProfile, "",
+ /*MemoryProfile=*/"", PGOOptions::IRUse,
+ PGOOptions::CSIRInstr, PGOOptions::ColdFuncOpt::Default);
+ } else if (!LTOCSIRProfile.empty()) {
+ PGOOpt = PGOOptions(LTOCSIRProfile, "", "",
+ /*MemoryProfile=*/"", PGOOptions::IRUse,
+ PGOOptions::CSIRUse, PGOOptions::ColdFuncOpt::Default);
+ }
LoopAnalysisManager LAM;
FunctionAnalysisManager FAM;
CGSCCAnalysisManager CGAM;
diff --git a/llvm/test/tools/llvm-lto/Inputs/cspgo-cs.proftext b/llvm/test/tools/llvm-lto/Inputs/cspgo-cs.proftext
new file mode 100644
index 0000000000000..ce700d863cb2e
--- /dev/null
+++ b/llvm/test/tools/llvm-lto/Inputs/cspgo-cs.proftext
@@ -0,0 +1,5 @@
+:csir
+main
+1895182923573755903
+1
+100000
diff --git a/llvm/test/tools/llvm-lto/Inputs/cspgo-noncs.proftext b/llvm/test/tools/llvm-lto/Inputs/cspgo-noncs.proftext
new file mode 100644
index 0000000000000..04a7c1c1a35aa
--- /dev/null
+++ b/llvm/test/tools/llvm-lto/Inputs/cspgo-noncs.proftext
@@ -0,0 +1 @@
+:ir
diff --git a/llvm/test/tools/llvm-lto/cspgo-generate.ll b/llvm/test/tools/llvm-lto/cspgo-generate.ll
new file mode 100644
index 0000000000000..a5d8718d75380
--- /dev/null
+++ b/llvm/test/tools/llvm-lto/cspgo-generate.ll
@@ -0,0 +1,17 @@
+; REQUIRES: aarch64-registered-target
+;
+; RUN: llvm-profdata merge %S/Inputs/cspgo-noncs.proftext -o %t.profdata
+; RUN: llvm-as %s -o %t.o
+; RUN: llvm-lto -cs-profile-generate -cs-profile-path=%t.profdata \
+; RUN: -exported-symbol=_main -o %t.lto.o %t.o
+; RUN: llvm-nm %t.lto.o | FileCheck %s
+;
+; CHECK: __profc_main
+
+target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128-Fn32"
+target triple = "arm64-apple-macosx14.0.0"
+
+define i32 @main() {
+entry:
+ ret i32 0
+}
diff --git a/llvm/test/tools/llvm-lto/cspgo-thinlto-generate.ll b/llvm/test/tools/llvm-lto/cspgo-thinlto-generate.ll
new file mode 100644
index 0000000000000..c4647443698a9
--- /dev/null
+++ b/llvm/test/tools/llvm-lto/cspgo-thinlto-generate.ll
@@ -0,0 +1,21 @@
+; REQUIRES: aarch64-registered-target
+;
+; RUN: llvm-profdata merge %S/Inputs/cspgo-noncs.proftext -o %t.profdata
+; RUN: opt -module-summary %s -o %t.o
+; RUN: llvm-lto -thinlto-action=optimize \
+; RUN: -cs-profile-generate -cs-profile-path=%t.profdata \
+; RUN: -o %t.opt.bc %t.o
+; RUN: llvm-dis %t.opt.bc -o - | FileCheck %s
+;
+; CHECK: @__profc_main = private global
+; CHECK-LABEL: @main()
+; CHECK: %pgocount = load i64, ptr @__profc_main
+; CHECK: store i64 %{{.*}}, ptr @__profc_main
+
+target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128-Fn32"
+target triple = "arm64-apple-macosx14.0.0"
+
+define i32 @main() {
+entry:
+ ret i32 0
+}
diff --git a/llvm/test/tools/llvm-lto/cspgo-thinlto-use.ll b/llvm/test/tools/llvm-lto/cspgo-thinlto-use.ll
new file mode 100644
index 0000000000000..37d4b5290b3de
--- /dev/null
+++ b/llvm/test/tools/llvm-lto/cspgo-thinlto-use.ll
@@ -0,0 +1,20 @@
+; REQUIRES: aarch64-registered-target
+;
+; RUN: llvm-profdata merge %S/Inputs/cspgo-cs.proftext -o %t.profdata
+; RUN: opt -module-summary %s -o %t.o
+; RUN: llvm-lto -thinlto-action=optimize \
+; RUN: -cs-profile-path=%t.profdata \
+; RUN: -o %t.opt.bc %t.o
+; RUN: llvm-dis %t.opt.bc -o - | FileCheck %s
+;
+; CHECK: @main(){{.*}} !prof [[PROF:![0-9]+]]
+; CHECK: CSProfileSummary
+; CHECK: [[PROF]] = !{!"function_entry_count", i64 100000}
+
+target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128-Fn32"
+target triple = "arm64-apple-macosx14.0.0"
+
+define i32 @main() {
+entry:
+ ret i32 0
+}
diff --git a/llvm/test/tools/llvm-lto/cspgo-use.ll b/llvm/test/tools/llvm-lto/cspgo-use.ll
new file mode 100644
index 0000000000000..acecb05beeedb
--- /dev/null
+++ b/llvm/test/tools/llvm-lto/cspgo-use.ll
@@ -0,0 +1,18 @@
+; REQUIRES: aarch64-registered-target
+;
+; RUN: llvm-profdata merge %S/Inputs/cspgo-cs.proftext -o %t.profdata
+; RUN: llvm-as %s -o %t.o
+; RUN: llvm-lto -cs-profile-path=%t.profdata \
+; RUN: -exported-symbol=_main -o %t.lto.o %t.o
+; RUN: llvm-nm %t.lto.o | FileCheck %s
+;
+; CHECK-NOT: __profc_
+; CHECK: _main
+
+target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128-Fn32"
+target triple = "arm64-apple-macosx14.0.0"
+
+define i32 @main() {
+entry:
+ ret i32 0
+}
More information about the cfe-commits
mailing list