Index: include/clang/Driver/CC1Options.td =================================================================== --- include/clang/Driver/CC1Options.td +++ include/clang/Driver/CC1Options.td @@ -271,8 +271,8 @@ : Flag<["-"], "fsanitize-coverage-8bit-counters">, HelpText<"Enable frequency counters in sanitizer coverage">; def fprofile_instrument_EQ : Joined<["-"], "fprofile-instrument=">, - HelpText<"Enable PGO instrumentation. The accepted values is clang or " - "none">; + HelpText<"Enable PGO instrumentation. The accepted value is clang, llvm, " + "or none">; def fprofile_instrument_path_EQ : Joined<["-"], "fprofile-instrument-path=">, HelpText<"Generate instrumented code to collect execution counts into " " (overridden by LLVM_PROFILE_FILE env var)">; Index: include/clang/Frontend/CodeGenOptions.h =================================================================== --- include/clang/Frontend/CodeGenOptions.h +++ include/clang/Frontend/CodeGenOptions.h @@ -81,8 +81,9 @@ enum ProfileInstrKind { ProfileNoInstr, // No instrumentation. - ProfileClangInstr // Clang instrumentation to generate execution counts + ProfileClangInstr, // Clang instrumentation to generate execution counts // to use with PGO. + ProfileIRInstr // IR level PGO instrumentation in LLVM. }; /// The code model to use (-mcmodel). @@ -223,6 +224,11 @@ bool hasProfileClangInstr() const { return getProfileInstr() == ProfileClangInstr; } + + /// \brief Check if IR level profile instrumentation is on. + bool hasProfileIRInstr() const { + return getProfileInstr() == ProfileIRInstr; + } }; } // end namespace clang Index: lib/CodeGen/BackendUtil.cpp =================================================================== --- lib/CodeGen/BackendUtil.cpp +++ lib/CodeGen/BackendUtil.cpp @@ -434,6 +434,13 @@ Options.NoRedZone = CodeGenOpts.DisableRedZone; Options.InstrProfileOutput = CodeGenOpts.InstrProfileOutput; MPM->add(createInstrProfilingPass(Options)); + } else if (CodeGenOpts.hasProfileIRInstr()) { + if (!CodeGenOpts.InstrProfileInput.empty()) + PMBuilder.PGOInstrUse = CodeGenOpts.InstrProfileInput; + else if (!CodeGenOpts.InstrProfileOutput.empty()) + PMBuilder.PGOInstrGen = CodeGenOpts.InstrProfileOutput; + else + PMBuilder.PGOInstrGen = "default.profraw"; } if (!CodeGenOpts.SampleProfileFile.empty()) Index: lib/CodeGen/CodeGenModule.cpp =================================================================== --- lib/CodeGen/CodeGenModule.cpp +++ lib/CodeGen/CodeGenModule.cpp @@ -147,7 +147,8 @@ if (C.getLangOpts().ObjC1) ObjCData = new ObjCEntrypoints(); - if (!CodeGenOpts.InstrProfileInput.empty()) { + if (!CodeGenOpts.hasProfileIRInstr() && + !CodeGenOpts.InstrProfileInput.empty()) { auto ReaderOrErr = llvm::IndexedInstrProfReader::create(CodeGenOpts.InstrProfileInput); if (std::error_code EC = ReaderOrErr.getError()) { Index: lib/Driver/CMakeLists.txt =================================================================== --- lib/Driver/CMakeLists.txt +++ lib/Driver/CMakeLists.txt @@ -1,6 +1,7 @@ set(LLVM_LINK_COMPONENTS Option Support + ProfileData ) add_clang_library(clangDriver Index: lib/Driver/Tools.cpp =================================================================== --- lib/Driver/Tools.cpp +++ lib/Driver/Tools.cpp @@ -32,6 +32,7 @@ #include "llvm/Option/Arg.h" #include "llvm/Option/ArgList.h" #include "llvm/Option/Option.h" +#include "llvm/ProfileData/InstrProfReader.h" #include "llvm/Support/CodeGen.h" #include "llvm/Support/Compression.h" #include "llvm/Support/ErrorHandling.h" @@ -3196,6 +3197,18 @@ return VersionTuple(); } +// Set the profile kind if it's not the default clang kind. +static void setProfileKindFlag(ArgStringList &CmdArgs, + std::string ProfileName) { + auto ReaderOrErr = llvm::IndexedInstrProfReader::create(ProfileName); + if (ReaderOrErr.getError()) + return; + std::unique_ptr PGOReader = + std::move(ReaderOrErr.get()); + if (PGOReader->isIRLevelProfile()) + CmdArgs.push_back("-fprofile-instrument=llvm"); +} + static void addPGOAndCoverageFlags(Compilation &C, const Driver &D, const InputInfo &Output, const ArgList &Args, ArgStringList &CmdArgs) { @@ -3238,8 +3251,10 @@ } if (ProfileUseArg) { - if (ProfileUseArg->getOption().matches(options::OPT_fprofile_instr_use_EQ)) + if (ProfileUseArg->getOption().matches(options::OPT_fprofile_instr_use_EQ)) { ProfileUseArg->render(Args, CmdArgs); + setProfileKindFlag(CmdArgs, ProfileUseArg->getValue()); + } else if ((ProfileUseArg->getOption().matches( options::OPT_fprofile_use_EQ) || ProfileUseArg->getOption().matches( @@ -3250,6 +3265,7 @@ llvm::sys::path::append(Path, "default.profdata"); CmdArgs.push_back( Args.MakeArgString(Twine("-fprofile-instr-use=") + Path)); + setProfileKindFlag(CmdArgs, Path.str().str()); } } Index: lib/Frontend/CompilerInvocation.cpp =================================================================== --- lib/Frontend/CompilerInvocation.cpp +++ lib/Frontend/CompilerInvocation.cpp @@ -478,14 +478,18 @@ Opts.Autolink = !Args.hasArg(OPT_fno_autolink); Opts.SampleProfileFile = Args.getLastArgValue(OPT_fprofile_sample_use_EQ); - enum PGOInstrumentor { Unknown, None, Clang }; + enum PGOInstrumentor { Unknown, None, Clang, LLVM }; if (Arg *A = Args.getLastArg(OPT_fprofile_instrument_EQ)) { StringRef Value = A->getValue(); PGOInstrumentor Method = llvm::StringSwitch(Value) - .Case("clang", Clang) .Case("none", None) + .Case("clang", Clang) + .Case("llvm", LLVM) .Default(Unknown); switch (Method) { + case LLVM: + Opts.setProfileInstr(CodeGenOptions::ProfileIRInstr); + break; case Clang: Opts.setProfileInstr(CodeGenOptions::ProfileClangInstr); break; Index: test/CodeGen/Inputs/pgotestir.profraw =================================================================== --- test/CodeGen/Inputs/pgotestir.profraw +++ test/CodeGen/Inputs/pgotestir.profraw @@ -0,0 +1 @@ +:ir Index: test/CodeGen/pgo-instrumentation.c =================================================================== --- test/CodeGen/pgo-instrumentation.c +++ test/CodeGen/pgo-instrumentation.c @@ -0,0 +1,28 @@ +// Test if PGO instrumentation and use pass are invoked. +// +// Ensure Pass PGOInstrumentationGenPass is invoked. +// RUN: %clang -O2 -c -Xclang -fprofile-instrument=llvm -fprofile-instr-generate %s -mllvm -debug-pass=Structure 2>&1 | FileCheck %s -check-prefix=CHECK-PGOGENPASS-INVOKED-INSTR-GEN +// CHECK-PGOGENPASS-INVOKED-INSTR-GEN: PGOInstrumentationGenPass +// +// Ensure Pass PGOInstrumentationGenPass is invoked. +// RUN: %clang -O2 -c -Xclang -fprofile-instrument=llvm -fprofile-generate %s -mllvm -debug-pass=Structure 2>&1 | FileCheck %s -check-prefix=CHECK-PGOGENPASS-INVOKED-GEN +// CHECK-PGOGENPASS-INVOKED-GEN: PGOInstrumentationGenPass +// +// Ensure Pass PGOInstrumentationGenPass is not invoked. +// RUN: %clang -O2 -c -Xclang -fprofile-instrument=clang -fprofile-instr-generate %s -mllvm -debug-pass=Structure 2>&1 | FileCheck %s -check-prefix=CHECK-PGOGENPASS-INVOKED-INSTR-GEN-CLANG +// CHECK-PGOGENPASS-INVOKED-INSTR-GEN-CLANG-NOT: PGOInstrumentationGenPass +// +// Ensure Pass PGOInstrumentationUsePass is invoked. +// RUN: llvm-profdata merge -o %t.profdata %S/Inputs/pgotestir.profraw +// RUN: %clang -O2 -c -Xclang -fprofile-instrument=llvm -fprofile-instr-use=%t.profdata %s -mllvm -debug-pass=Structure 2>&1 | FileCheck %s -check-prefix=CHECK-PGOUSEPASS-INVOKED-INSTR-USE +// CHECK-PGOUSEPASS-INVOKED-INSTR-USE: PGOInstrumentationUsePass +// +// Ensure Pass PGOInstrumentationUsePass is invoked. +// RUN: llvm-profdata merge -o %t.profdata %S/Inputs/pgotestir.profraw +// RUN: %clang -O2 -c -Xclang -fprofile-instrument=llvm -fprofile-use=%t.profdata %s -mllvm -debug-pass=Structure 2>&1 | FileCheck %s -check-prefix=CHECK-PGOUSEPASS-INVOKED-USE +// CHECK-PGOUSEPASS-INVOKED-USE: PGOInstrumentationUsePass +// +// Ensure Pass PGOInstrumentationUsePass is not invoked. +// RUN: llvm-profdata merge -o %t.profdata %S/Inputs/pgotestclang.profraw +// RUN: %clang -O2 -c -Xclang -fprofile-instrument=clang -fprofile-use=%t.profdata %s -mllvm -debug-pass=Structure 2>&1 | FileCheck %s -check-prefix=CHECK-PGOUSEPASS-INVOKED-USE-CLANG +// CHECK-PGOUSEPASS-INVOKED-USE-CLANG-NOT: PGOInstrumentationUsePass