Index: include/clang/Basic/DiagnosticDriverKinds.td =================================================================== --- include/clang/Basic/DiagnosticDriverKinds.td +++ include/clang/Basic/DiagnosticDriverKinds.td @@ -27,6 +27,8 @@ "invalid thread model '%0' in '%1' for this target">; def err_drv_invalid_linker_name : Error< "invalid linker name in argument '%0'">; +def err_drv_invalid_pgo_instrumentor: Error< + "invalid PGO instrumentor in argument '%0'">; def err_drv_invalid_rtlib_name : Error< "invalid runtime library name in argument '%0'">; def err_drv_unsupported_rtlib_for_platform : Error< Index: include/clang/Driver/CC1Options.td =================================================================== --- include/clang/Driver/CC1Options.td +++ include/clang/Driver/CC1Options.td @@ -268,6 +268,10 @@ def fsanitize_coverage_8bit_counters : Flag<["-"], "fsanitize-coverage-8bit-counters">, HelpText<"Enable frequency counters in sanitizer coverage">; +def fprofile_instrument_EQ: Joined<["-"], "fprofile-instrument=">, + HelpText<"Specify the kind of instrumentation that instruments the code " + "to generate execution counts to use with PGO. Accepted values " + "are Clang and LLVM">; //===----------------------------------------------------------------------===// // Dependency Output Options Index: include/clang/Driver/Options.td =================================================================== --- include/clang/Driver/Options.td +++ include/clang/Driver/Options.td @@ -446,7 +446,7 @@ def fauto_profile_EQ : Joined<["-"], "fauto-profile=">, Alias; def fprofile_instr_generate : Flag<["-"], "fprofile-instr-generate">, - Group, Flags<[CC1Option]>, + Group, Flags<[DriverOption]>, HelpText<"Generate instrumented code to collect execution counts into default.profraw file (overriden by '=' form of option or LLVM_PROFILE_FILE env var)">; def fprofile_instr_generate_EQ : Joined<["-"], "fprofile-instr-generate=">, Group, Flags<[CC1Option]>, MetaVarName<"">, Index: include/clang/Frontend/CodeGenOptions.h =================================================================== --- include/clang/Frontend/CodeGenOptions.h +++ include/clang/Frontend/CodeGenOptions.h @@ -108,6 +108,13 @@ SRCK_InRegs // Small structs in registers (-freg-struct-return). }; + enum ProfileInstrKind { + ProfileNoInstr, // No instrumentation. + ProfileClangInstr, // Clang instrumentation to generate execution counts + // to use with PGO. + ProfileIRInstr // IR level PGO instrumentation in LLVM. + }; + /// The code model to use (-mcmodel). std::string CodeModel; Index: include/clang/Frontend/CodeGenOptions.def =================================================================== --- include/clang/Frontend/CodeGenOptions.def +++ include/clang/Frontend/CodeGenOptions.def @@ -103,8 +103,8 @@ VALUE_CODEGENOPT(OptimizationLevel, 2, 0) ///< The -O[0-3] option specified. VALUE_CODEGENOPT(OptimizeSize, 2, 0) ///< If -Os (==1) or -Oz (==2) is specified. -CODEGENOPT(ProfileInstrGenerate , 1, 0) ///< Instrument code to generate - ///< execution counts to use with PGO. +/// \brief Choose PGO instrumenation kind. +ENUM_CODEGENOPT(ProfileInstr, ProfileInstrKind, 2, ProfileNoInstr) CODEGENOPT(CoverageMapping , 1, 0) ///< Generate coverage mapping regions to ///< enable code coverage analysis. CODEGENOPT(DumpCoverageMapping , 1, 0) ///< Dump the generated coverage mapping Index: lib/CodeGen/BackendUtil.cpp =================================================================== --- lib/CodeGen/BackendUtil.cpp +++ lib/CodeGen/BackendUtil.cpp @@ -429,11 +429,24 @@ MPM->add(createStripSymbolsPass(true)); } - if (CodeGenOpts.ProfileInstrGenerate) { + switch (CodeGenOpts.getProfileInstr()) { + case CodeGenOptions::ProfileClangInstr: { InstrProfOptions Options; Options.NoRedZone = CodeGenOpts.DisableRedZone; Options.InstrProfileOutput = CodeGenOpts.InstrProfileOutput; MPM->add(createInstrProfilingPass(Options)); + break; + } + case CodeGenOptions::ProfileIRInstr: + if (!CodeGenOpts.InstrProfileInput.empty()) + PMBuilder.PGOInstrUse = CodeGenOpts.InstrProfileInput; + else if (!CodeGenOpts.InstrProfileOutput.empty()) + PMBuilder.PGOInstrGen = CodeGenOpts.InstrProfileOutput; + else + PMBuilder.PGOInstrGen = "default.profraw"; + break; + default: + break; } if (!CodeGenOpts.SampleProfileFile.empty()) Index: lib/CodeGen/CGStmt.cpp =================================================================== --- lib/CodeGen/CGStmt.cpp +++ lib/CodeGen/CGStmt.cpp @@ -1153,7 +1153,8 @@ // If the body of the case is just a 'break', try to not emit an empty block. // If we're profiling or we're not optimizing, leave the block in for better // debug and coverage analysis. - if (!CGM.getCodeGenOpts().ProfileInstrGenerate && + if (CGM.getCodeGenOpts().getProfileInstr() != + CodeGenOptions::ProfileClangInstr && CGM.getCodeGenOpts().OptimizationLevel > 0 && isa(S.getSubStmt())) { JumpDest Block = BreakContinueStack.back().BreakBlock; @@ -1200,7 +1201,8 @@ if (SwitchWeights) SwitchWeights->push_back(getProfileCount(NextCase)); - if (CGM.getCodeGenOpts().ProfileInstrGenerate) { + if (CGM.getCodeGenOpts().getProfileInstr() == + CodeGenOptions::ProfileClangInstr) { CaseDest = createBasicBlock("sw.bb"); EmitBlockWithFallThrough(CaseDest, &S); } Index: lib/CodeGen/CodeGenFunction.h =================================================================== --- lib/CodeGen/CodeGenFunction.h +++ lib/CodeGen/CodeGenFunction.h @@ -952,7 +952,8 @@ public: /// Increment the profiler's counter for the given statement. void incrementProfileCounter(const Stmt *S) { - if (CGM.getCodeGenOpts().ProfileInstrGenerate) + if (CGM.getCodeGenOpts().getProfileInstr() == + CodeGenOptions::ProfileClangInstr) PGO.emitCounterIncrement(Builder, S); PGO.setCurrentStmt(S); } Index: lib/CodeGen/CodeGenFunction.cpp =================================================================== --- lib/CodeGen/CodeGenFunction.cpp +++ lib/CodeGen/CodeGenFunction.cpp @@ -883,7 +883,9 @@ void CodeGenFunction::EmitBlockWithFallThrough(llvm::BasicBlock *BB, const Stmt *S) { llvm::BasicBlock *SkipCountBB = nullptr; - if (HaveInsertPoint() && CGM.getCodeGenOpts().ProfileInstrGenerate) { + if (HaveInsertPoint() && + CGM.getCodeGenOpts().getProfileInstr() == + CodeGenOptions::ProfileClangInstr) { // When instrumenting for profiling, the fallthrough to certain // statements needs to skip over the instrumentation code so that we // get an accurate count. 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.getProfileInstr() != CodeGenOptions::ProfileIRInstr && + !CodeGenOpts.InstrProfileInput.empty()) { auto ReaderOrErr = llvm::IndexedInstrProfReader::create(CodeGenOpts.InstrProfileInput); if (std::error_code EC = ReaderOrErr.getError()) { Index: lib/CodeGen/CodeGenPGO.cpp =================================================================== --- lib/CodeGen/CodeGenPGO.cpp +++ lib/CodeGen/CodeGenPGO.cpp @@ -37,7 +37,8 @@ PGOReader ? PGOReader->getVersion() : llvm::IndexedInstrProf::Version); // If we're generating a profile, create a variable for the name. - if (CGM.getCodeGenOpts().ProfileInstrGenerate) + if (CGM.getCodeGenOpts().getProfileInstr() == + CodeGenOptions::ProfileClangInstr) FuncNameVar = llvm::createPGOFuncNameVar(CGM.getModule(), Linkage, FuncName); } @@ -610,7 +611,8 @@ void CodeGenPGO::assignRegionCounters(GlobalDecl GD, llvm::Function *Fn) { const Decl *D = GD.getDecl(); - bool InstrumentRegions = CGM.getCodeGenOpts().ProfileInstrGenerate; + bool InstrumentRegions = (CGM.getCodeGenOpts().getProfileInstr() == + CodeGenOptions::ProfileClangInstr); llvm::IndexedInstrProfReader *PGOReader = CGM.getPGOReader(); if (!InstrumentRegions && !PGOReader) return; @@ -729,7 +731,9 @@ } void CodeGenPGO::emitCounterIncrement(CGBuilderTy &Builder, const Stmt *S) { - if (!CGM.getCodeGenOpts().ProfileInstrGenerate || !RegionCounterMap) + if (CGM.getCodeGenOpts().getProfileInstr() != + CodeGenOptions::ProfileClangInstr || + !RegionCounterMap) return; if (!Builder.GetInsertBlock()) return; @@ -754,7 +758,8 @@ if (!ValuePtr || !ValueSite || !Builder.GetInsertBlock()) return; - bool InstrumentValueSites = CGM.getCodeGenOpts().ProfileInstrGenerate; + bool InstrumentValueSites = (CGM.getCodeGenOpts().getProfileInstr() == + CodeGenOptions::ProfileClangInstr); if (InstrumentValueSites && RegionCounterMap) { llvm::LLVMContext &Ctx = CGM.getLLVMContext(); auto *I8PtrTy = llvm::Type::getInt8PtrTy(Ctx); Index: lib/Driver/Tools.cpp =================================================================== --- lib/Driver/Tools.cpp +++ lib/Driver/Tools.cpp @@ -3230,8 +3230,9 @@ llvm::sys::path::append(Path, "default.profraw"); CmdArgs.push_back( Args.MakeArgString(Twine("-fprofile-instr-generate=") + Path)); - } else - Args.AddAllArgs(CmdArgs, options::OPT_fprofile_instr_generate); + } + // The default is to use Clang Instrumentation. + CmdArgs.push_back("-fprofile-instrument=Clang"); } if (ProfileUseArg) { Index: lib/Frontend/CompilerInvocation.cpp =================================================================== --- lib/Frontend/CompilerInvocation.cpp +++ lib/Frontend/CompilerInvocation.cpp @@ -477,8 +477,29 @@ Opts.DisableIntegratedAS = Args.hasArg(OPT_fno_integrated_as); Opts.Autolink = !Args.hasArg(OPT_fno_autolink); Opts.SampleProfileFile = Args.getLastArgValue(OPT_fprofile_sample_use_EQ); - Opts.ProfileInstrGenerate = Args.hasArg(OPT_fprofile_instr_generate) || - Args.hasArg(OPT_fprofile_instr_generate_EQ); + + enum PGOInstrumentor { Unknown, Clang, LLVM }; + if (Arg *A = Args.getLastArg(OPT_fprofile_instrument_EQ)) { + StringRef Value = A->getValue(); + PGOInstrumentor Method = llvm::StringSwitch(Value) + .Case("Clang", Clang) + .Case("LLVM", LLVM) + .Default(Unknown); + switch (Method) { + case LLVM: + Opts.setProfileInstr(CodeGenOptions::ProfileIRInstr); + break; + case Clang: + Opts.setProfileInstr(CodeGenOptions::ProfileClangInstr); + break; + case Unknown: + default: + Diags.Report(diag::err_drv_invalid_pgo_instrumentor) + << A->getAsString(Args) << Value; + break; + } + } + Opts.InstrProfileOutput = Args.getLastArgValue(OPT_fprofile_instr_generate_EQ); Opts.InstrProfileInput = Args.getLastArgValue(OPT_fprofile_instr_use_EQ); Opts.CoverageMapping = Index: test/CodeGen/pgo-instrumentation.c =================================================================== --- /dev/null +++ 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/pgotest.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/pgotest.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/pgotest.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