diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -716,12 +716,7 @@ 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, diff --git a/clang/lib/Driver/ToolChains/CommonArgs.h b/clang/lib/Driver/ToolChains/CommonArgs.h --- a/clang/lib/Driver/ToolChains/CommonArgs.h +++ b/clang/lib/Driver/ToolChains/CommonArgs.h @@ -143,6 +143,7 @@ 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); diff --git a/clang/lib/Driver/ToolChains/CommonArgs.cpp b/clang/lib/Driver/ToolChains/CommonArgs.cpp --- a/clang/lib/Driver/ToolChains/CommonArgs.cpp +++ b/clang/lib/Driver/ToolChains/CommonArgs.cpp @@ -772,16 +772,7 @@ "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( @@ -794,7 +785,7 @@ 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)) @@ -1348,6 +1339,17 @@ 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, diff --git a/clang/lib/Driver/ToolChains/Darwin.cpp b/clang/lib/Driver/ToolChains/Darwin.cpp --- a/clang/lib/Driver/ToolChains/Darwin.cpp +++ b/clang/lib/Driver/ToolChains/Darwin.cpp @@ -449,6 +449,23 @@ 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. diff --git a/clang/test/Driver/cspgo-lto.c b/clang/test/Driver/cspgo-lto.c --- a/clang/test/Driver/cspgo-lto.c +++ b/clang/test/Driver/cspgo-lto.c @@ -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" diff --git a/lld/MachO/Config.h b/lld/MachO/Config.h --- a/lld/MachO/Config.h +++ b/lld/MachO/Config.h @@ -206,6 +206,8 @@ std::vector sectionAlignments; std::vector segmentProtections; bool ltoDebugPassManager = false; + bool csProfileGenerate = false; + llvm::StringRef csProfilePath; bool callGraphProfileSort = false; llvm::StringRef printSymbolOrder; diff --git a/lld/MachO/Driver.cpp b/lld/MachO/Driver.cpp --- a/lld/MachO/Driver.cpp +++ b/lld/MachO/Driver.cpp @@ -1637,6 +1637,8 @@ 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( diff --git a/lld/MachO/LTO.cpp b/lld/MachO/LTO.cpp --- a/lld/MachO/LTO.cpp +++ b/lld/MachO/LTO.cpp @@ -69,6 +69,8 @@ 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) diff --git a/lld/MachO/Options.td b/lld/MachO/Options.td --- a/lld/MachO/Options.td +++ b/lld/MachO/Options.td @@ -126,6 +126,10 @@ Group; def lto_debug_pass_manager: Flag<["--"], "lto-debug-pass-manager">, HelpText<"Debug new pass manager">, Group; +def cs_profile_generate: Flag<["--"], "cs-profile-generate">, + HelpText<"Perform context senstive PGO instrumentation">, Group; +def cs_profile_path: Joined<["--"], "cs-profile-path=">, + HelpText<"Context sensitive profile file path">, Group; // 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 diff --git a/lld/test/MachO/cspgo-gen.ll b/lld/test/MachO/cspgo-gen.ll new file mode 100644 --- /dev/null +++ b/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 +} diff --git a/lld/test/MachO/cspgo-use.ll b/lld/test/MachO/cspgo-use.ll new file mode 100644 --- /dev/null +++ b/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 +} diff --git a/lld/test/lit.cfg.py b/lld/test/lit.cfg.py --- a/lld/test/lit.cfg.py +++ b/lld/test/lit.cfg.py @@ -45,6 +45,7 @@ "llvm-objdump", "llvm-otool", "llvm-pdbutil", + "llvm-profdata", "llvm-dwarfdump", "llvm-readelf", "llvm-readobj",