Skip to content

Commit

Permalink
[lld] add context-sensitive PGO options for MachO
Browse files Browse the repository at this point in the history
Enable support for CSPGO for lld MachO targets.

Since lld MachO does not support `-plugin-opt=`, we need to create the `--cs-profile-generate` and `--cs-profile-path=` options and propagate them in `Darwin.cpp`. These flags are not supported by ld64.

Also outline code into `getLastCSProfileGenerateArg()` to share between `CommonArgs.cpp` and `Darwin.cpp`.

CSPGO is already implemented for ELF (https://reviews.llvm.org/D56675) and COFF (https://reviews.llvm.org/D98763).

Reviewed By: MaskRay

Differential Revision: https://reviews.llvm.org/D151589
  • Loading branch information
ellishg committed Jun 1, 2023
1 parent ed7be0d commit 85af42d
Show file tree
Hide file tree
Showing 12 changed files with 91 additions and 17 deletions.
7 changes: 1 addition & 6 deletions clang/lib/Driver/ToolChains/Clang.cpp
Expand Up @@ -716,12 +716,7 @@ static void addPGOAndCoverageFlags(const ToolChain &TC, Compilation &C,
PGOGenerateArg->getOption().matches(options::OPT_fno_profile_generate))
PGOGenerateArg = nullptr;

auto *CSPGOGenerateArg = Args.getLastArg(options::OPT_fcs_profile_generate,
options::OPT_fcs_profile_generate_EQ,
options::OPT_fno_profile_generate);
if (CSPGOGenerateArg &&
CSPGOGenerateArg->getOption().matches(options::OPT_fno_profile_generate))
CSPGOGenerateArg = nullptr;
auto *CSPGOGenerateArg = getLastCSProfileGenerateArg(Args);

auto *ProfileGenerateArg = Args.getLastArg(
options::OPT_fprofile_instr_generate,
Expand Down
24 changes: 13 additions & 11 deletions clang/lib/Driver/ToolChains/CommonArgs.cpp
Expand Up @@ -772,16 +772,7 @@ void tools::addLTOOptions(const ToolChain &ToolChain, const ArgList &Args,
"sample-profile=" + FName));
}

auto *CSPGOGenerateArg = Args.getLastArg(options::OPT_fcs_profile_generate,
options::OPT_fcs_profile_generate_EQ,
options::OPT_fno_profile_generate);
if (CSPGOGenerateArg &&
CSPGOGenerateArg->getOption().matches(options::OPT_fno_profile_generate))
CSPGOGenerateArg = nullptr;

auto *ProfileUseArg = getLastProfileUseArg(Args);

if (CSPGOGenerateArg) {
if (auto *CSPGOGenerateArg = getLastCSProfileGenerateArg(Args)) {
CmdArgs.push_back(Args.MakeArgString(Twine(PluginOptPrefix) + ExtraDash +
"cs-profile-generate"));
if (CSPGOGenerateArg->getOption().matches(
Expand All @@ -794,7 +785,7 @@ void tools::addLTOOptions(const ToolChain &ToolChain, const ArgList &Args,
CmdArgs.push_back(
Args.MakeArgString(Twine(PluginOptPrefix) + ExtraDash +
"cs-profile-path=default_%m.profraw"));
} else if (ProfileUseArg) {
} else if (auto *ProfileUseArg = getLastProfileUseArg(Args)) {
SmallString<128> Path(
ProfileUseArg->getNumValues() == 0 ? "" : ProfileUseArg->getValue());
if (Path.empty() || llvm::sys::fs::is_directory(Path))
Expand Down Expand Up @@ -1348,6 +1339,17 @@ void tools::claimNoWarnArgs(const ArgList &Args) {
Args.ClaimAllArgs(options::OPT_fno_lto);
}

Arg *tools::getLastCSProfileGenerateArg(const ArgList &Args) {
auto *CSPGOGenerateArg = Args.getLastArg(options::OPT_fcs_profile_generate,
options::OPT_fcs_profile_generate_EQ,
options::OPT_fno_profile_generate);
if (CSPGOGenerateArg &&
CSPGOGenerateArg->getOption().matches(options::OPT_fno_profile_generate))
CSPGOGenerateArg = nullptr;

return CSPGOGenerateArg;
}

Arg *tools::getLastProfileUseArg(const ArgList &Args) {
auto *ProfileUseArg = Args.getLastArg(
options::OPT_fprofile_instr_use, options::OPT_fprofile_instr_use_EQ,
Expand Down
1 change: 1 addition & 0 deletions clang/lib/Driver/ToolChains/CommonArgs.h
Expand Up @@ -143,6 +143,7 @@ void addHIPRuntimeLibArgs(const ToolChain &TC, const llvm::opt::ArgList &Args,

const char *getAsNeededOption(const ToolChain &TC, bool as_needed);

llvm::opt::Arg *getLastCSProfileGenerateArg(const llvm::opt::ArgList &Args);
llvm::opt::Arg *getLastProfileUseArg(const llvm::opt::ArgList &Args);
llvm::opt::Arg *getLastProfileSampleUseArg(const llvm::opt::ArgList &Args);

Expand Down
17 changes: 17 additions & 0 deletions clang/lib/Driver/ToolChains/Darwin.cpp
Expand Up @@ -449,6 +449,23 @@ void darwin::Linker::AddLinkArgs(Compilation &C, const ArgList &Args,
Args.AddAllArgs(CmdArgs, options::OPT_dylinker__install__name);
Args.AddLastArg(CmdArgs, options::OPT_dylinker);
Args.AddLastArg(CmdArgs, options::OPT_Mach);

if (LinkerIsLLD) {
if (auto *CSPGOGenerateArg = getLastCSProfileGenerateArg(Args)) {
SmallString<128> Path(CSPGOGenerateArg->getNumValues() == 0
? ""
: CSPGOGenerateArg->getValue());
llvm::sys::path::append(Path, "default_%m.profraw");
CmdArgs.push_back("--cs-profile-generate");
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(Args.MakeArgString(Twine("--cs-profile-path=") + Path));
}
}
}

/// Determine whether we are linking the ObjC runtime.
Expand Down
14 changes: 14 additions & 0 deletions clang/test/Driver/cspgo-lto.c
Expand Up @@ -4,3 +4,17 @@
// RUN: -fprofile-use 2>&1 | FileCheck %s

// CHECK: -plugin-opt=cs-profile-path=default.profdata

// RUN: %clang --target=apple-arm64-ios -### %t.o -flto=thin -fuse-ld=lld -fprofile-use 2>&1 | FileCheck %s --check-prefix=DARWIN-USE1
// RUN: %clang --target=apple-arm64-ios -### %t.o -flto=thin -fuse-ld=lld -fprofile-use=a.profdata 2>&1 | FileCheck %s --check-prefix=DARWIN-USE2

// DARWIN-USE1: "--cs-profile-path=default.profdata"
// DARWIN-USE2: "--cs-profile-path=a.profdata"

// RUN: %clang --target=apple-arm64-ios -### %t.o -flto=thin -fuse-ld=lld -fcs-profile-generate 2>&1 | FileCheck %s --check-prefix=DARWIN-GEN1
// RUN: %clang --target=apple-arm64-ios -### %t.o -flto=thin -fuse-ld=lld -fcs-profile-generate=directory 2>&1 | FileCheck %s --check-prefix=DARWIN-GEN2

// DARWIN-GEN1: "--cs-profile-generate"
// DARWIN-GEN1-SAME: "--cs-profile-path=default_%m.profraw"
// DARWIN-GEN2: "--cs-profile-generate"
// DARWIN-GEN2-SAME: "--cs-profile-path=directory{{(/|\\\\)}}default_%m.profraw"
2 changes: 2 additions & 0 deletions lld/MachO/Config.h
Expand Up @@ -206,6 +206,8 @@ struct Configuration {
std::vector<SectionAlign> sectionAlignments;
std::vector<SegmentProtection> segmentProtections;
bool ltoDebugPassManager = false;
bool csProfileGenerate = false;
llvm::StringRef csProfilePath;

bool callGraphProfileSort = false;
llvm::StringRef printSymbolOrder;
Expand Down
2 changes: 2 additions & 0 deletions lld/MachO/Driver.cpp
Expand Up @@ -1637,6 +1637,8 @@ bool macho::link(ArrayRef<const char *> argsArr, llvm::raw_ostream &stdoutOS,
config->ignoreAutoLinkOptions.insert(arg->getValue());
config->strictAutoLink = args.hasArg(OPT_strict_auto_link);
config->ltoDebugPassManager = args.hasArg(OPT_lto_debug_pass_manager);
config->csProfileGenerate = args.hasArg(OPT_cs_profile_generate);
config->csProfilePath = args.getLastArgValue(OPT_cs_profile_path);

for (const Arg *arg : args.filtered(OPT_alias)) {
config->aliasedSymbols.push_back(
Expand Down
2 changes: 2 additions & 0 deletions lld/MachO/LTO.cpp
Expand Up @@ -69,6 +69,8 @@ static lto::Config createConfig() {
c.TimeTraceEnabled = config->timeTraceEnabled;
c.TimeTraceGranularity = config->timeTraceGranularity;
c.DebugPassManager = config->ltoDebugPassManager;
c.CSIRProfile = std::string(config->csProfilePath);
c.RunCSIRInstr = config->csProfileGenerate;
c.OptLevel = config->ltoo;
c.CGOptLevel = config->ltoCgo;
if (config->saveTemps)
Expand Down
4 changes: 4 additions & 0 deletions lld/MachO/Options.td
Expand Up @@ -126,6 +126,10 @@ def check_category_conflicts : Flag<["--"], "check-category-conflicts">,
Group<grp_lld>;
def lto_debug_pass_manager: Flag<["--"], "lto-debug-pass-manager">,
HelpText<"Debug new pass manager">, Group<grp_lld>;
def cs_profile_generate: Flag<["--"], "cs-profile-generate">,
HelpText<"Perform context senstive PGO instrumentation">, Group<grp_lld>;
def cs_profile_path: Joined<["--"], "cs-profile-path=">,
HelpText<"Context sensitive profile file path">, Group<grp_lld>;

// This is a complete Options.td compiled from Apple's ld(1) manpage
// dated 2018-03-07 and cross checked with ld64 source code in repo
Expand Down
16 changes: 16 additions & 0 deletions lld/test/MachO/cspgo-gen.ll
@@ -0,0 +1,16 @@
; REQUIRES: x86

; RUN: llvm-as %s -o %t.o
; RUN: %lld -dylib --cs-profile-generate --cs-profile-path=default_%m.profraw %t.o -o %t --lto-debug-pass-manager 2>&1 | FileCheck %s --implicit-check-not=PGOInstrumentation

; CHECK: PGOInstrumentationGen

target triple = "x86_64-apple-darwin"
target datalayout = "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"

@__llvm_profile_runtime = global i32 0, align 4

define void @foo() {
entry:
ret void
}
18 changes: 18 additions & 0 deletions lld/test/MachO/cspgo-use.ll
@@ -0,0 +1,18 @@
; REQUIRES: x86

; Create an empty profile
; RUN: echo > %t.proftext
; RUN: llvm-profdata merge %t.proftext -o %t.profdata

; RUN: llvm-as %s -o %t.o
; RUN: %lld -dylib --cs-profile-path=%t.profdata %t.o -o %t --lto-debug-pass-manager 2>&1 | FileCheck %s --implicit-check-not=PGOInstrumentation

; CHECK: Running pass: PGOInstrumentationUse

target triple = "x86_64-apple-darwin"
target datalayout = "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"

define void @foo() {
entry:
ret void
}
1 change: 1 addition & 0 deletions lld/test/lit.cfg.py
Expand Up @@ -45,6 +45,7 @@
"llvm-objdump",
"llvm-otool",
"llvm-pdbutil",
"llvm-profdata",
"llvm-dwarfdump",
"llvm-readelf",
"llvm-readobj",
Expand Down

0 comments on commit 85af42d

Please sign in to comment.