Skip to content

Commit a27706d

Browse files
chiragramaniDeniz Dizman
authored andcommitted
Add IRPGO and CSIRPGO options to Swift (swiftlang#84335)
This PR introduces three new instrumentation flags and plumbs them through to IRGen: 1. `-ir-profile-generate` - enable IR-level instrumentation. 2. `-cs-profile-generate` - enable context-sensitive IR-level instrumentation. 3. `-ir-profile-use` - IR-level PGO input profdata file to enable profile-guided optimization (both IRPGO and CSIRPGO) **Context:** https://forums.swift.org/t/ir-level-pgo-instrumentation-in-swift/82123 **Swift-driver PR:** swiftlang/swift-driver#1992 **Tests and validation:** This PR includes ir level verification tests, also checks few edge-cases when `-ir-profile-use` supplied profile is either missing or is an invalid IR profile. However, for argument validation, linking, and generating IR profiles that can later be consumed by -cs-profile-generate, I’ll need corresponding swift-driver changes. Those changes are being tracked in swiftlang/swift-driver#1992
1 parent ac01ca6 commit a27706d

15 files changed

+409
-11
lines changed

include/swift/AST/DiagnosticsIRGen.def

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,11 @@ ERROR(too_few_output_filenames,none,
4141
ERROR(no_input_files_for_mt,none,
4242
"no swift input files for multi-threaded compilation", ())
4343

44+
ERROR(ir_profile_read_failed, none,
45+
"error reading profile '%0': %1", (StringRef, StringRef))
46+
ERROR(ir_profile_invalid, none,
47+
"invalid ir profile '%0'", (StringRef))
48+
4449
ERROR(alignment_dynamic_type_layout_unsupported,none,
4550
"'@_alignment' is not supported on types with dynamic layout", ())
4651
ERROR(alignment_less_than_natural,none,

include/swift/AST/IRGenOptions.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -548,10 +548,23 @@ class IRGenOptions {
548548
/// Path to the profdata file to be used for PGO, or the empty string.
549549
std::string UseProfile = "";
550550

551+
/// Path to the profdata file to be used for IR/CS-IR PGO, or the empty string.
552+
std::string UseIRProfile = "";
553+
551554
/// Path to the data file to be used for sampling-based PGO,
552555
/// or the empty string.
553556
std::string UseSampleProfile = "";
554557

558+
/// Name of the profile file to use as output for -ir-profile-generate,
559+
/// and -cs-profile-generate, or the default string.
560+
std::string InstrProfileOutput = "default_%m.profraw";
561+
562+
/// Whether to enable context-sensitive IR PGO generation.
563+
bool EnableCSIRProfileGen = false;
564+
565+
/// Whether to enable IR level instrumentation.
566+
bool EnableIRProfileGen = false;
567+
555568
/// Controls whether DWARF discriminators are added to the IR.
556569
unsigned DebugInfoForProfiling : 1;
557570

include/swift/Option/Options.td

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1631,6 +1631,29 @@ def profile_sample_use : Joined<["-"], "profile-sample-use=">,
16311631
MetaVarName<"<profile data>">,
16321632
HelpText<"Supply sampling-based profiling data from llvm-profdata to enable profile-guided optimization">;
16331633

1634+
def cs_profile_generate : Flag<["-"], "cs-profile-generate">,
1635+
Flags<[FrontendOption, NoInteractiveOption]>,
1636+
HelpText<"Generate instrumented code to collect context sensitive execution counts into default.profraw (overridden by LLVM_PROFILE_FILE env var)">;
1637+
1638+
def cs_profile_generate_EQ : Joined<["-"], "cs-profile-generate=">,
1639+
Flags<[FrontendOption, NoInteractiveOption]>,
1640+
MetaVarName<"<directory>">,
1641+
HelpText<"Generate instrumented code to collect context sensitive execution counts into <directory>/default.profraw (overridden by LLVM_PROFILE_FILE env var)">;
1642+
1643+
def ir_profile_generate: Flag<["-"], "ir-profile-generate">,
1644+
Flags<[FrontendOption, NoInteractiveOption]>,
1645+
HelpText<"Generate instrumented code to collect execution counts into default.profraw (overridden by LLVM_PROFILE_FILE env var)">;
1646+
1647+
def ir_profile_generate_EQ : Joined<["-"], "ir-profile-generate=">,
1648+
Flags<[FrontendOption, NoInteractiveOption]>,
1649+
MetaVarName<"<directory>">,
1650+
HelpText<"Generate instrumented code to collect execution counts into <directory>/default.profraw (overridden by LLVM_PROFILE_FILE env var)">;
1651+
1652+
def ir_profile_use : CommaJoined<["-"], "ir-profile-use=">,
1653+
Flags<[FrontendOption, NoInteractiveOption, ArgumentIsPath]>,
1654+
MetaVarName<"<profdata>">,
1655+
HelpText<"Supply an IR-level PGO profdata file to enable profile-guided optimization">;
1656+
16341657
def embed_bitcode : Flag<["-"], "embed-bitcode">,
16351658
Flags<[FrontendOption, NoInteractiveOption]>,
16361659
HelpText<"Embed LLVM IR bitcode as data">;

lib/Driver/DarwinToolChains.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
using namespace swift;
4343
using namespace swift::driver;
4444
using namespace llvm::opt;
45+
using namespace swift::driver::toolchains;
4546

4647
std::string
4748
toolchains::Darwin::findProgramRelativeToSwiftImpl(StringRef name) const {
@@ -472,7 +473,7 @@ void
472473
toolchains::Darwin::addProfileGenerationArgs(ArgStringList &Arguments,
473474
const JobContext &context) const {
474475
const llvm::Triple &Triple = getTriple();
475-
if (context.Args.hasArg(options::OPT_profile_generate)) {
476+
if (needsInstrProfileRuntime(context.Args)) {
476477
SmallString<128> LibProfile;
477478
getClangLibraryPath(context.Args, LibProfile);
478479

lib/Driver/Driver.cpp

Lines changed: 77 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -176,19 +176,92 @@ static void validateWarningControlArgs(DiagnosticEngine &diags,
176176
}
177177
}
178178

179+
/// Validates only *generate* profiling flags and their mutual conflicts.
180+
static void validateProfilingGenerateArgs(DiagnosticEngine &diags,
181+
const ArgList &args) {
182+
const Arg *ProfileGenerate = args.getLastArg(options::OPT_profile_generate);
183+
const Arg *IRProfileGenerate =
184+
args.getLastArg(options::OPT_ir_profile_generate);
185+
const Arg *CSProfileGenerate =
186+
args.getLastArg(options::OPT_cs_profile_generate);
187+
const Arg *CSProfileGenerateEQ =
188+
args.getLastArg(options::OPT_cs_profile_generate_EQ);
189+
const Arg *IRProfileGenerateEQ =
190+
args.getLastArg(options::OPT_ir_profile_generate_EQ);
191+
192+
// If both CS Profile forms were specified, report a clear conflict.
193+
if (CSProfileGenerate && CSProfileGenerateEQ) {
194+
diags.diagnose(SourceLoc(), diag::error_conflicting_options,
195+
"-cs-profile-generate", "-cs-profile-generate=");
196+
CSProfileGenerateEQ = nullptr;
197+
}
198+
// If both IR Profile forms were specified, report a clear conflict.
199+
if (IRProfileGenerate && IRProfileGenerateEQ) {
200+
diags.diagnose(SourceLoc(), diag::error_conflicting_options,
201+
"-ir-profile-generate", "-ir-profile-generate=");
202+
IRProfileGenerateEQ = nullptr;
203+
}
204+
205+
llvm::SmallVector<std::pair<const Arg *, const char *>, 3> gens;
206+
if (ProfileGenerate)
207+
gens.push_back({ProfileGenerate, "-profile-generate"});
208+
if (IRProfileGenerate)
209+
gens.push_back({IRProfileGenerate, "-ir-profile-generate"});
210+
if (IRProfileGenerateEQ)
211+
gens.push_back({IRProfileGenerateEQ, "-ir-profile-generate="});
212+
if (CSProfileGenerate)
213+
gens.push_back({CSProfileGenerate, "-cs-profile-generate"});
214+
else if (CSProfileGenerateEQ)
215+
gens.push_back({CSProfileGenerateEQ, "-cs-profile-generate="});
216+
217+
// Emit pairwise conflicts if more than one generate-mode was selected
218+
for (size_t i = 0; i + 1 < gens.size(); ++i) {
219+
for (size_t j = i + 1; j < gens.size(); ++j) {
220+
diags.diagnose(SourceLoc(), diag::error_conflicting_options,
221+
gens[i].second, gens[j].second);
222+
}
223+
}
224+
}
225+
179226
static void validateProfilingArgs(DiagnosticEngine &diags,
180227
const ArgList &args) {
228+
validateProfilingGenerateArgs(diags, args);
181229
const Arg *ProfileGenerate = args.getLastArg(options::OPT_profile_generate);
182230
const Arg *ProfileUse = args.getLastArg(options::OPT_profile_use);
231+
const Arg *IRProfileGenerate =
232+
args.getLastArg(options::OPT_ir_profile_generate);
233+
const Arg *IRProfileGenerateEQ =
234+
args.getLastArg(options::OPT_ir_profile_generate_EQ);
235+
const Arg *IRProfileUse = args.getLastArg(options::OPT_ir_profile_use);
183236
if (ProfileGenerate && ProfileUse) {
184237
diags.diagnose(SourceLoc(), diag::error_conflicting_options,
185238
"-profile-generate", "-profile-use");
186239
}
187-
240+
if (ProfileGenerate && IRProfileUse) {
241+
diags.diagnose(SourceLoc(), diag::error_conflicting_options,
242+
"-profile-generate", "-ir-profile-use");
243+
}
244+
if (IRProfileGenerate && ProfileUse) {
245+
diags.diagnose(SourceLoc(), diag::error_conflicting_options,
246+
"-ir-profile-generate", "-profile-use");
247+
}
248+
if (IRProfileGenerate && IRProfileUse) {
249+
diags.diagnose(SourceLoc(), diag::error_conflicting_options,
250+
"-ir-profile-generate", "-ir-profile-use");
251+
}
252+
if (IRProfileGenerateEQ && ProfileUse) {
253+
diags.diagnose(SourceLoc(), diag::error_conflicting_options,
254+
"-ir-profile-generate=", "-profile-use");
255+
}
256+
if (IRProfileGenerateEQ && IRProfileUse) {
257+
diags.diagnose(SourceLoc(), diag::error_conflicting_options,
258+
"-ir-profile-generate=", "-ir-profile-use");
259+
}
188260
// Check if the profdata is missing
189-
if (ProfileUse && !llvm::sys::fs::exists(ProfileUse->getValue())) {
190-
diags.diagnose(SourceLoc(), diag::error_profile_missing,
191-
ProfileUse->getValue());
261+
for (const Arg *use : {ProfileUse, IRProfileUse}) {
262+
if (use && !llvm::sys::fs::exists(use->getValue())) {
263+
diags.diagnose(SourceLoc(), diag::error_profile_missing, use->getValue());
264+
}
192265
}
193266
}
194267

lib/Driver/ToolChains.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,16 @@ bool containsValue(
160160

161161
}
162162

163+
namespace swift::driver::toolchains {
164+
bool needsInstrProfileRuntime(const llvm::opt::ArgList &Args) {
165+
return Args.hasArg(options::OPT_profile_generate) ||
166+
Args.hasArg(options::OPT_cs_profile_generate) ||
167+
Args.hasArg(options::OPT_cs_profile_generate_EQ) ||
168+
Args.hasArg(options::OPT_ir_profile_generate) ||
169+
Args.hasArg(options::OPT_ir_profile_generate_EQ);
170+
}
171+
} // namespace swift::driver::toolchains
172+
163173
void ToolChain::addCommonFrontendArgs(const OutputInfo &OI,
164174
const CommandOutput &output,
165175
const ArgList &inputArgs,
@@ -323,6 +333,11 @@ void ToolChain::addCommonFrontendArgs(const OutputInfo &OI,
323333
inputArgs.AddLastArg(arguments, options::OPT_PackageCMO);
324334
inputArgs.AddLastArg(arguments, options::OPT_profile_generate);
325335
inputArgs.AddLastArg(arguments, options::OPT_profile_use);
336+
inputArgs.AddLastArg(arguments, options::OPT_ir_profile_generate);
337+
inputArgs.AddLastArg(arguments, options::OPT_ir_profile_generate_EQ);
338+
inputArgs.AddLastArg(arguments, options::OPT_ir_profile_use);
339+
inputArgs.AddLastArg(arguments, options::OPT_cs_profile_generate);
340+
inputArgs.AddLastArg(arguments, options::OPT_cs_profile_generate_EQ);
326341
inputArgs.AddLastArg(arguments, options::OPT_profile_coverage_mapping);
327342
inputArgs.AddAllArgs(arguments, options::OPT_warning_treating_Group);
328343
inputArgs.AddLastArg(arguments, options::OPT_sanitize_EQ);

lib/Driver/ToolChains.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,11 @@ class DiagnosticEngine;
2525
namespace driver {
2626
namespace toolchains {
2727

28+
/// True if any *generation* mode of instrumentation-based profile is enabled.
29+
///
30+
/// This is used to determine if the profiler runtime should be linked.
31+
bool needsInstrProfileRuntime(const llvm::opt::ArgList &Args);
32+
2833
class LLVM_LIBRARY_VISIBILITY Darwin : public ToolChain {
2934
protected:
3035

lib/Driver/UnixToolChains.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
using namespace swift;
4141
using namespace swift::driver;
4242
using namespace llvm::opt;
43+
using namespace swift::driver::toolchains;
4344

4445
std::string
4546
toolchains::GenericUnix::sanitizerRuntimeLibName(StringRef Sanitizer,
@@ -330,7 +331,7 @@ toolchains::GenericUnix::constructInvocation(const DynamicLinkJobAction &job,
330331
}
331332
}
332333

333-
if (context.Args.hasArg(options::OPT_profile_generate)) {
334+
if (needsInstrProfileRuntime(context.Args)) {
334335
SmallString<128> LibProfile(SharedResourceDirPath);
335336
llvm::sys::path::remove_filename(LibProfile); // remove platform name
336337
llvm::sys::path::append(LibProfile, "clang", "lib");

lib/Driver/WebAssemblyToolChains.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
using namespace swift;
3939
using namespace swift::driver;
4040
using namespace llvm::opt;
41+
using namespace swift::driver::toolchains;
4142

4243
std::string
4344
toolchains::WebAssembly::sanitizerRuntimeLibName(StringRef Sanitizer,
@@ -168,7 +169,7 @@ toolchains::WebAssembly::constructInvocation(const DynamicLinkJobAction &job,
168169
"-fsanitize=" + getSanitizerList(context.OI.SelectedSanitizers)));
169170
}
170171

171-
if (context.Args.hasArg(options::OPT_profile_generate)) {
172+
if (needsInstrProfileRuntime(context.Args)) {
172173
SmallString<128> LibProfile(SharedResourceDirPath);
173174
llvm::sys::path::remove_filename(LibProfile); // remove platform name
174175
llvm::sys::path::append(LibProfile, "clang", "lib");

lib/Driver/WindowsToolChains.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
using namespace swift;
3737
using namespace swift::driver;
3838
using namespace llvm::opt;
39+
using namespace swift::driver::toolchains;
3940

4041
std::string toolchains::Windows::sanitizerRuntimeLibName(StringRef Sanitizer,
4142
bool shared) const {
@@ -89,7 +90,7 @@ toolchains::Windows::constructInvocation(const DynamicLinkJobAction &job,
8990
// for now, which supports the behavior via a flag.
9091
// TODO: Once we've changed coverage to no longer rely on emitting
9192
// duplicate weak symbols (rdar://131295678), we can remove this.
92-
if (context.Args.getLastArg(options::OPT_profile_generate)) {
93+
if (swift::driver::toolchains::needsInstrProfileRuntime(context.Args)) {
9394
return true;
9495
}
9596
return false;
@@ -186,7 +187,7 @@ toolchains::Windows::constructInvocation(const DynamicLinkJobAction &job,
186187
sanitizerRuntimeLibName("ubsan"));
187188
}
188189

189-
if (context.Args.hasArg(options::OPT_profile_generate)) {
190+
if (needsInstrProfileRuntime(context.Args)) {
190191
Arguments.push_back(context.Args.MakeArgString("-Xlinker"));
191192
Arguments.push_back(context.Args.MakeArgString(
192193
Twine({"-include:", llvm::getInstrProfRuntimeHookVarName()})));

0 commit comments

Comments
 (0)