Index: docs/UsersManual.rst =================================================================== --- docs/UsersManual.rst +++ docs/UsersManual.rst @@ -1745,7 +1745,8 @@ ``-fprofile-use``. Although these flags are semantically equivalent to their GCC counterparts, they *do not* handle GCC-compatible profiles. They are only meant to implement GCC's semantics with respect to -profile creation and use. +profile creation and use. Flag ``-fcs-profile-generate`` also instruments +programs using the same instrumentation method as ``-fprofile-generate``. .. option:: -fprofile-generate[=] @@ -1778,6 +1779,45 @@ ``LLVM_PROFILE_FILE`` can still be used to override the directory and filename for the profile file at runtime. +.. option:: -fcs-profile-generate[=] + + The ``-fcs-profile-generate`` and ``-fcs-profile-generate=`` flags will use + the same instrumentation method, and generate the same profile as in the + ``-fprofile-generate`` and ``-fprofile-generate=`` flags. The difference is + that the instrumentation is performed after inlining so that the resulted + profile has a better context sensitive information. They cannot be used + together with ``-fprofile-generate`` and ``-fprofile-generate=`` flags. + They are typically used in conjunction with ``-fprofile-use`` flag. + The profile generated by ``-fcs-profile-generate`` and ``-fprofile-generate`` + can be merged by llvm-profdata. A use example: + + .. code-block:: console + + $ clang++ -O2 -fprofile-generate=yyy/zzz code.cc -o code + $ ./code + $ llvm-profdata merge -output=code.profdata yyy/zzz/ + + The first few steps are the same as that in ``-fprofile-generate`` + compilation. Then perform a second round of instrumentation. + + .. code-block:: console + + $ clang++ -O2 -fprofile-use=code.profdata -fcs-profile-generate=sss/ttt \ + -o cs_code + $ ./cs_code + $ llvm-profdata merge -output=cs_code.profdata sss/ttt code.profdata + + The resulted ``cs_code.prodata`` combines ``code.profdata`` and the profile + generated from binary ``cs_code``. Profile ``cs_code.profata`` can be used by + ``-fprofile-use`` compilaton. + + .. code-block:: console + + $ clang++ -O2 -fprofile-use=cs_code.profdata + + The above command will read both profiles to the compiler at the identical + point of instrumenations. + .. option:: -fprofile-use[=] Without any other arguments, ``-fprofile-use`` behaves identically to Index: include/clang/Basic/CodeGenOptions.h =================================================================== --- include/clang/Basic/CodeGenOptions.h +++ include/clang/Basic/CodeGenOptions.h @@ -100,6 +100,7 @@ ProfileClangInstr, // Clang instrumentation to generate execution counts // to use with PGO. ProfileIRInstr, // IR level PGO instrumentation in LLVM. + ProfileCSIRInstr, // IR level PGO context sensitive instrumentation in LLVM. }; enum EmbedBitcodeKind { @@ -203,8 +204,8 @@ /// A list of linker options to embed in the object file. std::vector LinkerOptions; - /// Name of the profile file to use as output for -fprofile-instr-generate - /// and -fprofile-generate. + /// Name of the profile file to use as output for -fprofile-instr-generate, + /// -fprofile-generate, and -fcs-profile-generate. std::string InstrProfileOutput; /// Name of the profile file to use with -fprofile-sample-use. @@ -318,6 +319,11 @@ return getProfileInstr() == ProfileIRInstr; } + /// Check if CS IR level profile instrumentation is on. + bool hasProfileCSIRInstr() const { + return getProfileInstr() == ProfileCSIRInstr; + } + /// Check if Clang profile use is on. bool hasProfileClangUse() const { return getProfileUse() == ProfileClangInstr; @@ -325,9 +331,12 @@ /// Check if IR level profile use is on. bool hasProfileIRUse() const { - return getProfileUse() == ProfileIRInstr; + return getProfileUse() == ProfileIRInstr || + getProfileUse() == ProfileCSIRInstr; } + /// Check if CSIR profile use is on. + bool hasProfileCSIRUse() const { return getProfileUse() == ProfileCSIRInstr; } }; } // end namespace clang Index: include/clang/Driver/Options.td =================================================================== --- include/clang/Driver/Options.td +++ include/clang/Driver/Options.td @@ -747,6 +747,12 @@ def fprofile_generate_EQ : Joined<["-"], "fprofile-generate=">, Group, Flags<[DriverOption]>, MetaVarName<"">, HelpText<"Generate instrumented code to collect execution counts into /default.profraw (overridden by LLVM_PROFILE_FILE env var)">; +def fcs_profile_generate : Flag<["-"], "fcs-profile-generate">, + Group, Flags<[DriverOption]>, + HelpText<"Generate instrumented code to collect context sensitive execution counts into default.profraw (overridden by LLVM_PROFILE_FILE env var)">; +def fcs_profile_generate_EQ : Joined<["-"], "fcs-profile-generate=">, + Group, Flags<[DriverOption]>, MetaVarName<"">, + HelpText<"Generate instrumented code to collect context sensitive execution counts into /default.profraw (overridden by LLVM_PROFILE_FILE env var)">; def fprofile_use : Flag<["-"], "fprofile-use">, Group, Alias; def fprofile_use_EQ : Joined<["-"], "fprofile-use=">, Index: lib/CodeGen/BackendUtil.cpp =================================================================== --- lib/CodeGen/BackendUtil.cpp +++ lib/CodeGen/BackendUtil.cpp @@ -687,17 +687,33 @@ // the driver level. Options.Atomic = LangOpts.Sanitize.has(SanitizerKind::Thread); - MPM.add(createInstrProfilingLegacyPass(Options)); + MPM.add(createInstrProfilingLegacyPass(Options, false)); } + bool hasIRInstr = false; if (CodeGenOpts.hasProfileIRInstr()) { PMBuilder.EnablePGOInstrGen = true; + hasIRInstr = true; + } + if (CodeGenOpts.hasProfileCSIRInstr()) { + assert(!CodeGenOpts.hasProfileCSIRUse() && + "Cannot have both CSProfileUse pass and CSProfileGen pass at the " + "same time"); + assert(!hasIRInstr && + "Cannot have both ProfileGen pass and CSProfileGen pass at the " + "same time"); + PMBuilder.EnablePGOCSInstrGen = true; + hasIRInstr = true; + } + if (hasIRInstr) { if (!CodeGenOpts.InstrProfileOutput.empty()) PMBuilder.PGOInstrGen = CodeGenOpts.InstrProfileOutput; else PMBuilder.PGOInstrGen = DefaultProfileGenName; } - if (CodeGenOpts.hasProfileIRUse()) + if (CodeGenOpts.hasProfileIRUse()) { PMBuilder.PGOInstrUse = CodeGenOpts.ProfileInstrumentUsePath; + PMBuilder.EnablePGOCSInstrUse = CodeGenOpts.hasProfileCSIRUse(); + } if (!CodeGenOpts.SampleProfileFile.empty()) PMBuilder.PGOSampleUse = CodeGenOpts.SampleProfileFile; @@ -970,21 +986,48 @@ PGOOpt = PGOOptions(CodeGenOpts.InstrProfileOutput.empty() ? DefaultProfileGenName : CodeGenOpts.InstrProfileOutput, - "", "", "", true, + "", "", PGOOptions::IRInstr, PGOOptions::NoCSAction, CodeGenOpts.DebugInfoForProfiling); - else if (CodeGenOpts.hasProfileIRUse()) + else if (CodeGenOpts.hasProfileIRUse()) { // -fprofile-use. - PGOOpt = PGOOptions("", CodeGenOpts.ProfileInstrumentUsePath, "", - CodeGenOpts.ProfileRemappingFile, false, - CodeGenOpts.DebugInfoForProfiling); - else if (!CodeGenOpts.SampleProfileFile.empty()) + auto CSAction = CodeGenOpts.hasProfileCSIRUse() ? PGOOptions::CSIRUse + : PGOOptions::NoCSAction; + PGOOpt = PGOOptions(CodeGenOpts.ProfileInstrumentUsePath, "", + CodeGenOpts.ProfileRemappingFile, PGOOptions::IRUse, + CSAction, CodeGenOpts.DebugInfoForProfiling); + } else if (!CodeGenOpts.SampleProfileFile.empty()) // -fprofile-sample-use - PGOOpt = PGOOptions("", "", CodeGenOpts.SampleProfileFile, - CodeGenOpts.ProfileRemappingFile, false, - CodeGenOpts.DebugInfoForProfiling); + PGOOpt = + PGOOptions(CodeGenOpts.SampleProfileFile, "", + CodeGenOpts.ProfileRemappingFile, PGOOptions::SampleUse, + PGOOptions::NoCSAction, CodeGenOpts.DebugInfoForProfiling); else if (CodeGenOpts.DebugInfoForProfiling) // -fdebug-info-for-profiling - PGOOpt = PGOOptions("", "", "", "", false, true); + PGOOpt = PGOOptions("", "", "", PGOOptions::NoAction, + PGOOptions::NoCSAction, true); + + // Check to see if we want to generate a CS profile. + if (CodeGenOpts.hasProfileCSIRInstr()) { + assert(!CodeGenOpts.hasProfileCSIRUse() && + "Cannot have both CSProfileUse pass and CSProfileGen pass at " + "the same time"); + if (PGOOpt.hasValue()) { + assert(PGOOpt->Action != PGOOptions::IRInstr && + PGOOpt->Action != PGOOptions::SampleUse && + "Cannot run CSProfileGen pass with ProfileGen or SampleUse " + " pass"); + PGOOpt->CSProfileGenFile = CodeGenOpts.InstrProfileOutput.empty() + ? DefaultProfileGenName + : CodeGenOpts.InstrProfileOutput; + PGOOpt->CSAction = PGOOptions::CSIRInstr; + } else + PGOOpt = PGOOptions("", + CodeGenOpts.InstrProfileOutput.empty() + ? DefaultProfileGenName + : CodeGenOpts.InstrProfileOutput, + "", PGOOptions::NoAction, PGOOptions::CSIRInstr, + CodeGenOpts.DebugInfoForProfiling); + } PassBuilder PB(TM.get(), PGOOpt); @@ -1302,6 +1345,16 @@ Conf.CGOptLevel = getCGOptLevel(CGOpts); initTargetOptions(Conf.Options, CGOpts, TOpts, LOpts, HeaderOpts); Conf.SampleProfile = std::move(SampleProfile); + + // Context sensitive profile. + if (CGOpts.hasProfileCSIRInstr()) { + Conf.RunCSIRInstr = true; + Conf.CSIRProfile = std::move(CGOpts.InstrProfileOutput); + } else if (CGOpts.hasProfileCSIRUse()) { + Conf.RunCSIRInstr = false; + Conf.CSIRProfile = std::move(CGOpts.ProfileInstrumentUsePath); + } + Conf.ProfileRemapping = std::move(ProfileRemapping); Conf.UseNewPM = CGOpts.ExperimentalNewPassManager; Conf.DebugPassManager = CGOpts.DebugPassManager; Index: lib/Driver/ToolChain.cpp =================================================================== --- lib/Driver/ToolChain.cpp +++ lib/Driver/ToolChain.cpp @@ -405,6 +405,8 @@ if (needsGCovInstrumentation(Args) || Args.hasArg(options::OPT_fprofile_generate) || Args.hasArg(options::OPT_fprofile_generate_EQ) || + Args.hasArg(options::OPT_fcs_profile_generate) || + Args.hasArg(options::OPT_fcs_profile_generate_EQ) || Args.hasArg(options::OPT_fprofile_instr_generate) || Args.hasArg(options::OPT_fprofile_instr_generate_EQ) || Args.hasArg(options::OPT_fcreate_profile)) Index: lib/Driver/ToolChains/Clang.cpp =================================================================== --- lib/Driver/ToolChains/Clang.cpp +++ lib/Driver/ToolChains/Clang.cpp @@ -729,6 +729,13 @@ 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 *ProfileGenerateArg = Args.getLastArg( options::OPT_fprofile_instr_generate, options::OPT_fprofile_instr_generate_EQ, @@ -752,6 +759,10 @@ D.Diag(diag::err_drv_argument_not_allowed_with) << ProfileGenerateArg->getSpelling() << ProfileUseArg->getSpelling(); + if (CSPGOGenerateArg && PGOGenerateArg) + D.Diag(diag::err_drv_argument_not_allowed_with) + << CSPGOGenerateArg->getSpelling() << PGOGenerateArg->getSpelling(); + if (ProfileGenerateArg) { if (ProfileGenerateArg->getOption().matches( options::OPT_fprofile_instr_generate_EQ)) @@ -761,11 +772,22 @@ CmdArgs.push_back("-fprofile-instrument=clang"); } + Arg *PGOGenArg = nullptr; if (PGOGenerateArg) { + assert(!CSPGOGenerateArg); + PGOGenArg = PGOGenerateArg; CmdArgs.push_back("-fprofile-instrument=llvm"); - if (PGOGenerateArg->getOption().matches( - options::OPT_fprofile_generate_EQ)) { - SmallString<128> Path(PGOGenerateArg->getValue()); + } + if (CSPGOGenerateArg) { + assert(!PGOGenerateArg); + PGOGenArg = CSPGOGenerateArg; + CmdArgs.push_back("-fprofile-instrument=csllvm"); + } + if (PGOGenArg) { + if (PGOGenArg->getOption().matches( + PGOGenerateArg ? options::OPT_fprofile_generate_EQ + : options::OPT_fcs_profile_generate_EQ)) { + SmallString<128> Path(PGOGenArg->getValue()); llvm::sys::path::append(Path, "default_%m.profraw"); CmdArgs.push_back( Args.MakeArgString(Twine("-fprofile-instrument-path=") + Path)); @@ -4613,6 +4635,14 @@ // Forward -f options with positive and negative forms; we translate // these by hand. if (Arg *A = getLastProfileSampleUseArg(Args)) { + auto *PGOArg = Args.getLastArg( + options::OPT_fprofile_generate, options::OPT_fprofile_generate_EQ, + options::OPT_fcs_profile_generate, options::OPT_fcs_profile_generate_EQ, + options::OPT_fprofile_use, options::OPT_fprofile_use_EQ); + if (PGOArg) + D.Diag(diag::err_drv_argument_not_allowed_with) + << "SampleUse with PGO options"; + StringRef fname = A->getValue(); if (!llvm::sys::fs::exists(fname)) D.Diag(diag::err_drv_no_such_file) << fname; Index: lib/Driver/ToolChains/CommonArgs.cpp =================================================================== --- lib/Driver/ToolChains/CommonArgs.cpp +++ lib/Driver/ToolChains/CommonArgs.cpp @@ -443,6 +443,31 @@ Args.MakeArgString(Twine("-plugin-opt=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) { + CmdArgs.push_back(Args.MakeArgString("-plugin-opt=cs-profile-generate")); + if (CSPGOGenerateArg->getOption().matches( + options::OPT_fcs_profile_generate_EQ)) { + SmallString<128> Path(CSPGOGenerateArg->getValue()); + llvm::sys::path::append(Path, "default_%m.profraw"); + CmdArgs.push_back( + Args.MakeArgString(Twine("-plugin-opt=cs-profile-path=") + Path)); + } else + CmdArgs.push_back( + Args.MakeArgString("-plugin-opt=cs-profile-path=default_%m.profraw")); + } else if (ProfileUseArg) { + CmdArgs.push_back(Args.MakeArgString(Twine("-plugin-opt=cs-profile-path=") + + ProfileUseArg->getValue())); + } + // Need this flag to turn on new pass manager via Gold plugin. if (Args.hasFlag(options::OPT_fexperimental_new_pass_manager, options::OPT_fno_experimental_new_pass_manager, Index: lib/Frontend/CompilerInvocation.cpp =================================================================== --- lib/Frontend/CompilerInvocation.cpp +++ lib/Frontend/CompilerInvocation.cpp @@ -588,6 +588,7 @@ .Case("none", CodeGenOptions::ProfileNone) .Case("clang", CodeGenOptions::ProfileClangInstr) .Case("llvm", CodeGenOptions::ProfileIRInstr) + .Case("csllvm", CodeGenOptions::ProfileCSIRInstr) .Default(~0U); if (I == ~0U) { Diags.Report(diag::err_drv_invalid_pgo_instrumentor) << A->getAsString(Args) @@ -610,9 +611,12 @@ } std::unique_ptr PGOReader = std::move(ReaderOrErr.get()); - if (PGOReader->isIRLevelProfile()) - Opts.setProfileUse(CodeGenOptions::ProfileIRInstr); - else + if (PGOReader->isIRLevelProfile()) { + if (PGOReader->hasCSIRLevelProfile()) + Opts.setProfileUse(CodeGenOptions::ProfileCSIRInstr); + else + Opts.setProfileUse(CodeGenOptions::ProfileIRInstr); + } else Opts.setProfileUse(CodeGenOptions::ProfileClangInstr); }