mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
Add IRPGO and CSIRPGO options to Swift (#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:** https://github.com/swiftlang/swift-driver/pull/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 https://github.com/swiftlang/swift-driver/pull/1992
This commit is contained in:
@@ -176,19 +176,92 @@ static void validateWarningControlArgs(DiagnosticEngine &diags,
|
||||
}
|
||||
}
|
||||
|
||||
/// Validates only *generate* profiling flags and their mutual conflicts.
|
||||
static void validateProfilingGenerateArgs(DiagnosticEngine &diags,
|
||||
const ArgList &args) {
|
||||
const Arg *ProfileGenerate = args.getLastArg(options::OPT_profile_generate);
|
||||
const Arg *IRProfileGenerate =
|
||||
args.getLastArg(options::OPT_ir_profile_generate);
|
||||
const Arg *CSProfileGenerate =
|
||||
args.getLastArg(options::OPT_cs_profile_generate);
|
||||
const Arg *CSProfileGenerateEQ =
|
||||
args.getLastArg(options::OPT_cs_profile_generate_EQ);
|
||||
const Arg *IRProfileGenerateEQ =
|
||||
args.getLastArg(options::OPT_ir_profile_generate_EQ);
|
||||
|
||||
// If both CS Profile forms were specified, report a clear conflict.
|
||||
if (CSProfileGenerate && CSProfileGenerateEQ) {
|
||||
diags.diagnose(SourceLoc(), diag::error_conflicting_options,
|
||||
"-cs-profile-generate", "-cs-profile-generate=");
|
||||
CSProfileGenerateEQ = nullptr;
|
||||
}
|
||||
// If both IR Profile forms were specified, report a clear conflict.
|
||||
if (IRProfileGenerate && IRProfileGenerateEQ) {
|
||||
diags.diagnose(SourceLoc(), diag::error_conflicting_options,
|
||||
"-ir-profile-generate", "-ir-profile-generate=");
|
||||
IRProfileGenerateEQ = nullptr;
|
||||
}
|
||||
|
||||
llvm::SmallVector<std::pair<const Arg *, const char *>, 3> gens;
|
||||
if (ProfileGenerate)
|
||||
gens.push_back({ProfileGenerate, "-profile-generate"});
|
||||
if (IRProfileGenerate)
|
||||
gens.push_back({IRProfileGenerate, "-ir-profile-generate"});
|
||||
if (IRProfileGenerateEQ)
|
||||
gens.push_back({IRProfileGenerateEQ, "-ir-profile-generate="});
|
||||
if (CSProfileGenerate)
|
||||
gens.push_back({CSProfileGenerate, "-cs-profile-generate"});
|
||||
else if (CSProfileGenerateEQ)
|
||||
gens.push_back({CSProfileGenerateEQ, "-cs-profile-generate="});
|
||||
|
||||
// Emit pairwise conflicts if more than one generate-mode was selected
|
||||
for (size_t i = 0; i + 1 < gens.size(); ++i) {
|
||||
for (size_t j = i + 1; j < gens.size(); ++j) {
|
||||
diags.diagnose(SourceLoc(), diag::error_conflicting_options,
|
||||
gens[i].second, gens[j].second);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void validateProfilingArgs(DiagnosticEngine &diags,
|
||||
const ArgList &args) {
|
||||
validateProfilingGenerateArgs(diags, args);
|
||||
const Arg *ProfileGenerate = args.getLastArg(options::OPT_profile_generate);
|
||||
const Arg *ProfileUse = args.getLastArg(options::OPT_profile_use);
|
||||
const Arg *IRProfileGenerate =
|
||||
args.getLastArg(options::OPT_ir_profile_generate);
|
||||
const Arg *IRProfileGenerateEQ =
|
||||
args.getLastArg(options::OPT_ir_profile_generate_EQ);
|
||||
const Arg *IRProfileUse = args.getLastArg(options::OPT_ir_profile_use);
|
||||
if (ProfileGenerate && ProfileUse) {
|
||||
diags.diagnose(SourceLoc(), diag::error_conflicting_options,
|
||||
"-profile-generate", "-profile-use");
|
||||
}
|
||||
|
||||
if (ProfileGenerate && IRProfileUse) {
|
||||
diags.diagnose(SourceLoc(), diag::error_conflicting_options,
|
||||
"-profile-generate", "-ir-profile-use");
|
||||
}
|
||||
if (IRProfileGenerate && ProfileUse) {
|
||||
diags.diagnose(SourceLoc(), diag::error_conflicting_options,
|
||||
"-ir-profile-generate", "-profile-use");
|
||||
}
|
||||
if (IRProfileGenerate && IRProfileUse) {
|
||||
diags.diagnose(SourceLoc(), diag::error_conflicting_options,
|
||||
"-ir-profile-generate", "-ir-profile-use");
|
||||
}
|
||||
if (IRProfileGenerateEQ && ProfileUse) {
|
||||
diags.diagnose(SourceLoc(), diag::error_conflicting_options,
|
||||
"-ir-profile-generate=", "-profile-use");
|
||||
}
|
||||
if (IRProfileGenerateEQ && IRProfileUse) {
|
||||
diags.diagnose(SourceLoc(), diag::error_conflicting_options,
|
||||
"-ir-profile-generate=", "-ir-profile-use");
|
||||
}
|
||||
// Check if the profdata is missing
|
||||
if (ProfileUse && !llvm::sys::fs::exists(ProfileUse->getValue())) {
|
||||
diags.diagnose(SourceLoc(), diag::error_profile_missing,
|
||||
ProfileUse->getValue());
|
||||
for (const Arg *use : {ProfileUse, IRProfileUse}) {
|
||||
if (use && !llvm::sys::fs::exists(use->getValue())) {
|
||||
diags.diagnose(SourceLoc(), diag::error_profile_missing, use->getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user