diff --git a/include/swift/AST/DiagnosticsIRGen.def b/include/swift/AST/DiagnosticsIRGen.def index 4f93def59a63f..81b8fb9a0726d 100644 --- a/include/swift/AST/DiagnosticsIRGen.def +++ b/include/swift/AST/DiagnosticsIRGen.def @@ -41,6 +41,11 @@ ERROR(too_few_output_filenames,none, ERROR(no_input_files_for_mt,none, "no swift input files for multi-threaded compilation", ()) +ERROR(ir_profile_read_failed, none, + "error reading profile '%0': %1", (StringRef, StringRef)) +ERROR(ir_profile_invalid, none, + "invalid ir profile '%0'", (StringRef)) + ERROR(alignment_dynamic_type_layout_unsupported,none, "'@_alignment' is not supported on types with dynamic layout", ()) ERROR(alignment_less_than_natural,none, diff --git a/include/swift/AST/IRGenOptions.h b/include/swift/AST/IRGenOptions.h index baa4709dc05e1..d156c13bd5502 100644 --- a/include/swift/AST/IRGenOptions.h +++ b/include/swift/AST/IRGenOptions.h @@ -548,10 +548,23 @@ class IRGenOptions { /// Path to the profdata file to be used for PGO, or the empty string. std::string UseProfile = ""; + /// Path to the profdata file to be used for IR/CS-IR PGO, or the empty string. + std::string UseIRProfile = ""; + /// Path to the data file to be used for sampling-based PGO, /// or the empty string. std::string UseSampleProfile = ""; + /// Name of the profile file to use as output for -ir-profile-generate, + /// and -cs-profile-generate, or the default string. + std::string InstrProfileOutput = "default_%m.profraw"; + + /// Whether to enable context-sensitive IR PGO generation. + bool EnableCSIRProfileGen = false; + + /// Whether to enable IR level instrumentation. + bool EnableIRProfileGen = false; + /// Controls whether DWARF discriminators are added to the IR. unsigned DebugInfoForProfiling : 1; diff --git a/include/swift/Option/Options.td b/include/swift/Option/Options.td index ff0d0abf1a279..9837d312b9b67 100644 --- a/include/swift/Option/Options.td +++ b/include/swift/Option/Options.td @@ -1608,6 +1608,29 @@ def profile_sample_use : Joined<["-"], "profile-sample-use=">, MetaVarName<"">, HelpText<"Supply sampling-based profiling data from llvm-profdata to enable profile-guided optimization">; +def cs_profile_generate : Flag<["-"], "cs-profile-generate">, + Flags<[FrontendOption, NoInteractiveOption]>, + HelpText<"Generate instrumented code to collect context sensitive execution counts into default.profraw (overridden by LLVM_PROFILE_FILE env var)">; + +def cs_profile_generate_EQ : Joined<["-"], "cs-profile-generate=">, + Flags<[FrontendOption, NoInteractiveOption]>, + MetaVarName<"">, + HelpText<"Generate instrumented code to collect context sensitive execution counts into /default.profraw (overridden by LLVM_PROFILE_FILE env var)">; + +def ir_profile_generate: Flag<["-"], "ir-profile-generate">, + Flags<[FrontendOption, NoInteractiveOption]>, + HelpText<"Generate instrumented code to collect execution counts into default.profraw (overridden by LLVM_PROFILE_FILE env var)">; + +def ir_profile_generate_EQ : Joined<["-"], "ir-profile-generate=">, + Flags<[FrontendOption, NoInteractiveOption]>, + MetaVarName<"">, + HelpText<"Generate instrumented code to collect execution counts into /default.profraw (overridden by LLVM_PROFILE_FILE env var)">; + +def ir_profile_use : CommaJoined<["-"], "ir-profile-use=">, + Flags<[FrontendOption, NoInteractiveOption, ArgumentIsPath]>, + MetaVarName<"">, + HelpText<"Supply an IR-level PGO profdata file to enable profile-guided optimization">; + def embed_bitcode : Flag<["-"], "embed-bitcode">, Flags<[FrontendOption, NoInteractiveOption]>, HelpText<"Embed LLVM IR bitcode as data">; diff --git a/lib/Driver/DarwinToolChains.cpp b/lib/Driver/DarwinToolChains.cpp index 1ca6696397c3f..9d2050e0a9464 100644 --- a/lib/Driver/DarwinToolChains.cpp +++ b/lib/Driver/DarwinToolChains.cpp @@ -42,6 +42,7 @@ using namespace swift; using namespace swift::driver; using namespace llvm::opt; +using namespace swift::driver::toolchains; std::string toolchains::Darwin::findProgramRelativeToSwiftImpl(StringRef name) const { @@ -470,7 +471,7 @@ void toolchains::Darwin::addProfileGenerationArgs(ArgStringList &Arguments, const JobContext &context) const { const llvm::Triple &Triple = getTriple(); - if (context.Args.hasArg(options::OPT_profile_generate)) { + if (needsInstrProfileRuntime(context.Args)) { SmallString<128> LibProfile; getClangLibraryPath(context.Args, LibProfile); diff --git a/lib/Driver/Driver.cpp b/lib/Driver/Driver.cpp index 6c42ca0c8a64c..ac59c09a3ef7b 100644 --- a/lib/Driver/Driver.cpp +++ b/lib/Driver/Driver.cpp @@ -175,19 +175,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, 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()); + } } } diff --git a/lib/Driver/ToolChains.cpp b/lib/Driver/ToolChains.cpp index 8011dd7d02b62..852d4dbd36bad 100644 --- a/lib/Driver/ToolChains.cpp +++ b/lib/Driver/ToolChains.cpp @@ -160,6 +160,16 @@ bool containsValue( } +namespace swift::driver::toolchains { +bool needsInstrProfileRuntime(const llvm::opt::ArgList &Args) { + return Args.hasArg(options::OPT_profile_generate) || + Args.hasArg(options::OPT_cs_profile_generate) || + Args.hasArg(options::OPT_cs_profile_generate_EQ) || + Args.hasArg(options::OPT_ir_profile_generate) || + Args.hasArg(options::OPT_ir_profile_generate_EQ); +} +} // namespace swift::driver::toolchains + void ToolChain::addCommonFrontendArgs(const OutputInfo &OI, const CommandOutput &output, const ArgList &inputArgs, @@ -323,6 +333,11 @@ void ToolChain::addCommonFrontendArgs(const OutputInfo &OI, inputArgs.AddLastArg(arguments, options::OPT_PackageCMO); inputArgs.AddLastArg(arguments, options::OPT_profile_generate); inputArgs.AddLastArg(arguments, options::OPT_profile_use); + inputArgs.AddLastArg(arguments, options::OPT_ir_profile_generate); + inputArgs.AddLastArg(arguments, options::OPT_ir_profile_generate_EQ); + inputArgs.AddLastArg(arguments, options::OPT_ir_profile_use); + inputArgs.AddLastArg(arguments, options::OPT_cs_profile_generate); + inputArgs.AddLastArg(arguments, options::OPT_cs_profile_generate_EQ); inputArgs.AddLastArg(arguments, options::OPT_profile_coverage_mapping); inputArgs.AddAllArgs(arguments, options::OPT_warning_treating_Group); inputArgs.AddLastArg(arguments, options::OPT_sanitize_EQ); diff --git a/lib/Driver/ToolChains.h b/lib/Driver/ToolChains.h index 52adec85b49de..018913ab8d6ea 100644 --- a/lib/Driver/ToolChains.h +++ b/lib/Driver/ToolChains.h @@ -25,6 +25,11 @@ class DiagnosticEngine; namespace driver { namespace toolchains { +/// True if any *generation* mode of instrumentation-based profile is enabled. +/// +/// This is used to determine if the profiler runtime should be linked. +bool needsInstrProfileRuntime(const llvm::opt::ArgList &Args); + class LLVM_LIBRARY_VISIBILITY Darwin : public ToolChain { protected: diff --git a/lib/Driver/UnixToolChains.cpp b/lib/Driver/UnixToolChains.cpp index 12b0a895812ec..3f328e2a26754 100644 --- a/lib/Driver/UnixToolChains.cpp +++ b/lib/Driver/UnixToolChains.cpp @@ -40,6 +40,7 @@ using namespace swift; using namespace swift::driver; using namespace llvm::opt; +using namespace swift::driver::toolchains; std::string toolchains::GenericUnix::sanitizerRuntimeLibName(StringRef Sanitizer, @@ -330,7 +331,7 @@ toolchains::GenericUnix::constructInvocation(const DynamicLinkJobAction &job, } } - if (context.Args.hasArg(options::OPT_profile_generate)) { + if (needsInstrProfileRuntime(context.Args)) { SmallString<128> LibProfile(SharedResourceDirPath); llvm::sys::path::remove_filename(LibProfile); // remove platform name llvm::sys::path::append(LibProfile, "clang", "lib"); diff --git a/lib/Driver/WebAssemblyToolChains.cpp b/lib/Driver/WebAssemblyToolChains.cpp index eb257f1ddbffe..ddc48511780a1 100644 --- a/lib/Driver/WebAssemblyToolChains.cpp +++ b/lib/Driver/WebAssemblyToolChains.cpp @@ -38,6 +38,7 @@ using namespace swift; using namespace swift::driver; using namespace llvm::opt; +using namespace swift::driver::toolchains; std::string toolchains::WebAssembly::sanitizerRuntimeLibName(StringRef Sanitizer, @@ -168,7 +169,7 @@ toolchains::WebAssembly::constructInvocation(const DynamicLinkJobAction &job, "-fsanitize=" + getSanitizerList(context.OI.SelectedSanitizers))); } - if (context.Args.hasArg(options::OPT_profile_generate)) { + if (needsInstrProfileRuntime(context.Args)) { SmallString<128> LibProfile(SharedResourceDirPath); llvm::sys::path::remove_filename(LibProfile); // remove platform name llvm::sys::path::append(LibProfile, "clang", "lib"); diff --git a/lib/Driver/WindowsToolChains.cpp b/lib/Driver/WindowsToolChains.cpp index d50f4a0dfcf8f..a3c58e8e444f9 100644 --- a/lib/Driver/WindowsToolChains.cpp +++ b/lib/Driver/WindowsToolChains.cpp @@ -36,6 +36,7 @@ using namespace swift; using namespace swift::driver; using namespace llvm::opt; +using namespace swift::driver::toolchains; std::string toolchains::Windows::sanitizerRuntimeLibName(StringRef Sanitizer, bool shared) const { @@ -89,7 +90,7 @@ toolchains::Windows::constructInvocation(const DynamicLinkJobAction &job, // for now, which supports the behavior via a flag. // TODO: Once we've changed coverage to no longer rely on emitting // duplicate weak symbols (rdar://131295678), we can remove this. - if (context.Args.getLastArg(options::OPT_profile_generate)) { + if (swift::driver::toolchains::needsInstrProfileRuntime(context.Args)) { return true; } return false; @@ -186,7 +187,7 @@ toolchains::Windows::constructInvocation(const DynamicLinkJobAction &job, sanitizerRuntimeLibName("ubsan")); } - if (context.Args.hasArg(options::OPT_profile_generate)) { + if (needsInstrProfileRuntime(context.Args)) { Arguments.push_back(context.Args.MakeArgString("-Xlinker")); Arguments.push_back(context.Args.MakeArgString( Twine({"-include:", llvm::getInstrProfRuntimeHookVarName()}))); diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp index 8b8f4b419cba3..54facd7b3198b 100644 --- a/lib/Frontend/CompilerInvocation.cpp +++ b/lib/Frontend/CompilerInvocation.cpp @@ -3497,6 +3497,17 @@ static bool ParseIRGenArgs(IRGenOptions &Opts, ArgList &Args, const Arg *ProfileSampleUse = Args.getLastArg(OPT_profile_sample_use); Opts.UseSampleProfile = ProfileSampleUse ? ProfileSampleUse->getValue() : ""; + Opts.EnableIRProfileGen = Args.hasArg(OPT_ir_profile_generate) || + Args.hasArg(OPT_ir_profile_generate_EQ); + if (auto V = Args.getLastArgValue(OPT_ir_profile_generate_EQ); !V.empty()) + Opts.InstrProfileOutput = V.str(); + Opts.EnableCSIRProfileGen = Args.hasArg(OPT_cs_profile_generate) || + Args.hasArg(OPT_cs_profile_generate_EQ); + if (auto V = Args.getLastArgValue(OPT_cs_profile_generate_EQ); !V.empty()) + Opts.InstrProfileOutput = V.str(); + const Arg *IRProfileUse = Args.getLastArg(OPT_ir_profile_use); + Opts.UseIRProfile = IRProfileUse ? IRProfileUse->getValue() : ""; + Opts.DebugInfoForProfiling |= Args.hasArg(OPT_debug_info_for_profiling); diff --git a/lib/IRGen/IRGen.cpp b/lib/IRGen/IRGen.cpp index 659d936641064..7e49598eaac5c 100644 --- a/lib/IRGen/IRGen.cpp +++ b/lib/IRGen/IRGen.cpp @@ -72,6 +72,7 @@ #include "llvm/Passes/PassBuilder.h" #include "llvm/Passes/PassPlugin.h" #include "llvm/Passes/StandardInstrumentations.h" +#include "llvm/ProfileData/InstrProfReader.h" #include "llvm/Remarks/Remark.h" #include "llvm/Remarks/RemarkStreamer.h" #include "llvm/Support/CommandLine.h" @@ -214,8 +215,57 @@ static void align(llvm::Module *Module) { } } +static std::unique_ptr +getProfileReader(const Twine &ProfileName, llvm::vfs::FileSystem &FS, + DiagnosticEngine &Diags) { + auto ReaderOrErr = llvm::IndexedInstrProfReader::create(ProfileName, FS); + if (auto E = ReaderOrErr.takeError()) { + llvm::handleAllErrors(std::move(E), [&](const llvm::ErrorInfoBase &EI) { + Diags.diagnose(SourceLoc(), diag::ir_profile_read_failed, + ProfileName.str(), EI.message()); + }); + return nullptr; + } + return std::move(*ReaderOrErr); +} + +static std::optional buildIRUseOptions(const IRGenOptions &Opts, + DiagnosticEngine &Diags) { + if (Opts.UseIRProfile.empty()) + return std::nullopt; + + auto FS = llvm::vfs::getRealFileSystem(); + std::unique_ptr Reader = + getProfileReader(Opts.UseIRProfile.c_str(), *FS, Diags); + if (!Reader) + return std::nullopt; + + // Currently memprof profiles are only added at the IR level. Mark the + // profile type as IR in that case as well and the subsequent matching + // needs to detect which is available (might be one or both). + const bool IsIR = Reader->isIRLevelProfile() || Reader->hasMemoryProfile(); + if (!IsIR) { + Diags.diagnose(SourceLoc(), diag::ir_profile_invalid, + Opts.UseIRProfile.c_str()); + return std::nullopt; + } + + const bool IsCS = Reader->hasCSIRLevelProfile(); + return PGOOptions( + /*ProfileFile=*/Opts.UseIRProfile, + /*CSProfileGenFile=*/"", + /*ProfileRemappingFile=*/"", + /*MemoryProfile=*/"", + /*FS=*/FS, + /*Action=*/PGOOptions::IRUse, + /*CSPGOAction=*/IsCS ? PGOOptions::CSIRUse : PGOOptions::NoCSAction, + /*ColdType=*/PGOOptions::ColdFuncOpt::Default, + /*DebugInfoForProfiling=*/Opts.DebugInfoForProfiling); +} + static void populatePGOOptions(std::optional &Out, - const IRGenOptions &Opts) { + const IRGenOptions &Opts, + DiagnosticEngine &Diags) { if (!Opts.UseSampleProfile.empty()) { Out = PGOOptions( /*ProfileFile=*/ Opts.UseSampleProfile, @@ -231,6 +281,40 @@ static void populatePGOOptions(std::optional &Out, return; } + if (Opts.EnableCSIRProfileGen) { + const bool hasUse = !Opts.UseIRProfile.empty(); + Out = PGOOptions( + /*ProfileFile=*/Opts.UseIRProfile, + /*CSProfileGenFile=*/Opts.InstrProfileOutput, + /*ProfileRemappingFile=*/"", + /*MemoryProfile=*/"", + /*FS=*/llvm::vfs::getRealFileSystem(), + /*Action=*/hasUse ? PGOOptions::IRUse : PGOOptions::NoAction, + /*CSPGOAction=*/PGOOptions::CSIRInstr, + /*ColdType=*/PGOOptions::ColdFuncOpt::Default, + /*DebugInfoForProfiling=*/Opts.DebugInfoForProfiling); + return; + } + + if (Opts.EnableIRProfileGen) { + Out = PGOOptions( + /*ProfileFile=*/Opts.InstrProfileOutput, + /*CSProfileGenFile=*/"", + /*ProfileRemappingFile=*/"", + /*MemoryProfile=*/"", + /*FS=*/llvm::vfs::getRealFileSystem(), + /*Action=*/PGOOptions::IRInstr, + /*CSPGOAction=*/PGOOptions::NoCSAction, + /*ColdType=*/PGOOptions::ColdFuncOpt::Default, + /*DebugInfoForProfiling=*/Opts.DebugInfoForProfiling); + return; + } + + if (auto IRUseOptions = buildIRUseOptions(Opts, Diags)) { + Out = *IRUseOptions; + return; + } + if (Opts.DebugInfoForProfiling) { Out = PGOOptions( /*ProfileFile=*/ "", @@ -266,7 +350,7 @@ void swift::performLLVMOptimizations(const IRGenOptions &Opts, llvm::TargetMachine *TargetMachine, llvm::raw_pwrite_stream *out) { std::optional PGOOpt; - populatePGOOptions(PGOOpt, Opts); + populatePGOOptions(PGOOpt, Opts, Diags); PipelineTuningOptions PTO; diff --git a/test/IRGen/cs_profile_generate.sil b/test/IRGen/cs_profile_generate.sil new file mode 100644 index 0000000000000..226b1f9a86634 --- /dev/null +++ b/test/IRGen/cs_profile_generate.sil @@ -0,0 +1,71 @@ +// Without directory +// RUN: %target-swift-frontend -O -cs-profile-generate -emit-ir %s | %FileCheck %s + +// With directory +// RUN: %empty-directory(%t.dir) +// RUN: %target-swift-frontend -O -cs-profile-generate=%t.dir -emit-ir %s | %FileCheck %s + +// Ensure Passes: PGOInstrumentationGenPass and InstrProfilingLoweringPass are invoked. +// RUN: %target-swift-frontend -O -cs-profile-generate -emit-ir %s -Xllvm -debug-pass=Structure -Xllvm --time-passes -o /dev/null 2>&1 | %FileCheck -check-prefix=CHECK-PASSES %s +// CHECK-PASSES-DAG: PGOInstrumentationGen +// CHECK-PASSES-DAG: InstrProfilingLoweringPass + +sil_stage canonical + +import Builtin +import Swift +import SwiftShims + +sil @b : $@convention(thin) () -> () + +sil @c : $@convention(thin) () -> () + + +// counter array (2 counters for the then/else) +// CHECK: @__profc_a = {{.*}} global {{.*}} +// data record pointing at the counter array and the function +// CHECK: @__profd_a = {{.*}} global {{.*}} ptr @a.local + + +// CHECK: br i1 {{.*}}, label %[[THEN:[0-9]+]], label %[[ELSE:[0-9]+]] +// THEN: increment counter[0] and call b() +// CHECK: [[THEN]]: +// CHECK: {{.*}}load{{.*}}@__profc_a +// CHECK: {{.*}}store{{.*}}@__profc_a +// CHECK: {{.*}}call{{.*}}@b( +// CHECK: br label %[[MERGE:[0-9]+]] + +// ELSE: increment counter[1] and call c() +// CHECK: [[ELSE]]: +// CHECK: {{.*}} = {{.*}}@__profc_a{{.*}} +// CHECK: store{{.*}}@__profc_a +// CHECK: {{.*}}call{{.*}}@c( +// CHECK: br label %[[MERGE]] + +// CHECK: [[MERGE]]: +// CHECK: ret void + +// CHECK: declare {{.*}}@c( +// CHECK: declare {{.*}}@b( + +sil @a : $@convention(thin) (Bool) -> () { +bb0(%0 : $Bool): + %2 = struct_extract %0, #Bool._value + cond_br %2, bb1, bb2 + +bb1: + // function_ref b() + %4 = function_ref @b : $@convention(thin) () -> () + %5 = apply %4() : $@convention(thin) () -> () + br bb3 + +bb2: + // function_ref c() + %7 = function_ref @c: $@convention(thin) () -> () + %8 = apply %7() : $@convention(thin) () -> () + br bb3 + +bb3: + %10 = tuple () + return %10 +} diff --git a/test/IRGen/ir_profile_generate.sil b/test/IRGen/ir_profile_generate.sil new file mode 100644 index 0000000000000..61e4bb9e8d4e0 --- /dev/null +++ b/test/IRGen/ir_profile_generate.sil @@ -0,0 +1,71 @@ +// Without directory +// RUN: %target-swift-frontend -ir-profile-generate -emit-ir %s | %FileCheck %s + +// With directory +// RUN: %empty-directory(%t.dir) +// RUN: %target-swift-frontend -ir-profile-generate=%t.dir -emit-ir %s | %FileCheck %s + +// Ensure Passes: PGOInstrumentationGenPass and InstrProfilingLoweringPass are invoked. +// RUN: %target-swift-frontend -ir-profile-generate -emit-ir %s -Xllvm -debug-pass=Structure -Xllvm --time-passes -o /dev/null 2>&1 | %FileCheck -check-prefix=CHECK-PASSES %s +// CHECK-PASSES-DAG: PGOInstrumentationGen +// CHECK-PASSES-DAG: InstrProfilingLoweringPass + +sil_stage canonical + +import Builtin +import Swift +import SwiftShims + +sil @b : $@convention(thin) () -> () + +sil @c : $@convention(thin) () -> () + +// counter array (2 counters for the then/else) +// CHECK: @__profc_a = {{.*}} global {{.*}} +// data record pointing at the counter array and the function +// CHECK: @__profd_a = {{.*}} global {{.*}} ptr @a.local + + +// CHECK: br i1 {{.*}}, label %[[THEN:[0-9]+]], label %[[ELSE:[0-9]+]] +// THEN: increment counter[0] and call b() +// CHECK: [[THEN]]: +// CHECK: {{.*}}load{{.*}}@__profc_a +// CHECK: {{.*}}store{{.*}}@__profc_a +// CHECK: {{.*}}call{{.*}}@b( +// CHECK: br label %[[MERGE:[0-9]+]] + +// ELSE: increment counter[1] and call c() +// CHECK: [[ELSE]]: +/// CHECK: {{.*}} = {{.*}}@__profc_a{{.*}} +// CHECK: store{{.*}}@__profc_a +// CHECK: {{.*}}call{{.*}}@c( +// CHECK: br label %[[MERGE]] + +// CHECK: [[MERGE]]: +// CHECK: ret void + +// CHECK: declare {{.*}}@c( +// CHECK: declare {{.*}}@b( +// CHECK: declare {{.*}}@llvm.instrprof.increment + +sil @a : $@convention(thin) (Bool) -> () { +bb0(%0 : $Bool): + %2 = struct_extract %0, #Bool._value + cond_br %2, bb1, bb2 + +bb1: + // function_ref b() + %4 = function_ref @b : $@convention(thin) () -> () + %5 = apply %4() : $@convention(thin) () -> () + br bb3 + +bb2: + // function_ref c() + %7 = function_ref @c: $@convention(thin) () -> () + %8 = apply %7() : $@convention(thin) () -> () + br bb3 + +bb3: + %10 = tuple () + return %10 +} diff --git a/test/IRGen/ir_profile_use.sil b/test/IRGen/ir_profile_use.sil new file mode 100644 index 0000000000000..aaa2068c245ec --- /dev/null +++ b/test/IRGen/ir_profile_use.sil @@ -0,0 +1,23 @@ +// Missing file +// RUN: %target-swift-frontend -ir-profile-use=missing.profdata -emit-ir %s 2>&1 | %FileCheck --ignore-case --check-prefix=CHECK-NOFILE %s +// CHECK-NOFILE: error reading profile +// CHECK-NOFILE: .profdata +// CHECK-NOFILE: No such file or directory + + +// Invalid IR file +// RUN: %empty-directory(%t) +// RUN: echo "" > %t.invalid.profdata +// RUN: %target-swift-frontend -ir-profile-use=%t.invalid.profdata -emit-ir %s 2>&1 | %FileCheck --ignore-case --check-prefix=CHECK-INVALIDFILE %s +// CHECK-INVALIDFILE: error reading profile +// CHECK-INVALIDFILE: invalid.profdata +// CHECK-INVALIDFILE: invalid instrumentation profile data + + +sil_stage canonical + +import Builtin +import Swift +import SwiftShims + +public func foo() {}