Index: cfe/trunk/lib/CodeGen/BackendUtil.cpp =================================================================== --- cfe/trunk/lib/CodeGen/BackendUtil.cpp +++ cfe/trunk/lib/CodeGen/BackendUtil.cpp @@ -1117,6 +1117,16 @@ // code generation. MPM.addPass(AlwaysInlinerPass(/*InsertLifetimeIntrinsics=*/false)); + // At -O0, we can still do PGO. Add all the requested passes for + // instrumentation PGO, if requested. + if (PGOOpt && (PGOOpt->Action == PGOOptions::IRInstr || + PGOOpt->Action == PGOOptions::IRUse)) + PB.addPGOInstrPassesForO0( + MPM, CodeGenOpts.DebugPassManager, + /* RunProfileGen */ (PGOOpt->Action == PGOOptions::IRInstr), + /* IsCS */ false, PGOOpt->ProfileFile, + PGOOpt->ProfileRemappingFile); + // At -O0 we directly run necessary sanitizer passes. if (LangOpts.Sanitize.has(SanitizerKind::LocalBounds)) MPM.addPass(createModuleToFunctionPassAdaptor(BoundsCheckingPass())); Index: cfe/trunk/test/Profile/Inputs/gcc-flag-compatibility_IR.proftext =================================================================== --- cfe/trunk/test/Profile/Inputs/gcc-flag-compatibility_IR.proftext +++ cfe/trunk/test/Profile/Inputs/gcc-flag-compatibility_IR.proftext @@ -0,0 +1,11 @@ +# IR level Instrumentation Flag +:ir +main +# Func Hash: +34137660316 +# Num Counters: +2 +# Counter Values: +100 +1 + Index: cfe/trunk/test/Profile/gcc-flag-compatibility.c =================================================================== --- cfe/trunk/test/Profile/gcc-flag-compatibility.c +++ cfe/trunk/test/Profile/gcc-flag-compatibility.c @@ -7,26 +7,50 @@ // -fprofile-use= Uses the profile file /default.profdata // -fprofile-use=/file Uses the profile file /file -// RUN: %clang %s -c -S -o - -emit-llvm -fprofile-generate | FileCheck -check-prefix=PROFILE-GEN %s -// PROFILE-GEN: __llvm_profile_filename +// RUN: %clang %s -c -S -o - -emit-llvm -fprofile-generate -fno-experimental-new-pass-manager | FileCheck -check-prefix=PROFILE-GEN %s +// RUN: %clang %s -c -S -o - -emit-llvm -fprofile-generate -fexperimental-new-pass-manager | FileCheck -check-prefix=PROFILE-GEN %s +// PROFILE-GEN: @__profc_main = private global [2 x i64] zeroinitializer, section "__llvm_prf_cnts", align 8 +// PROFILE-GEN: @__profd_main = private global // Check that -fprofile-generate=/path/to generates /path/to/default.profraw -// RUN: %clang %s -c -S -o - -emit-llvm -fprofile-generate=/path/to | FileCheck -check-prefix=PROFILE-GEN-EQ %s +// RUN: %clang %s -c -S -o - -emit-llvm -fprofile-generate=/path/to -fno-experimental-new-pass-manager | FileCheck -check-prefixes=PROFILE-GEN,PROFILE-GEN-EQ %s +// RxUN: %clang %s -c -S -o - -emit-llvm -fprofile-generate=/path/to -fexperimental-new-pass-manager | FileCheck -check-prefixes=PROFILE-GEN,PROFILE-GEN-EQ %s // PROFILE-GEN-EQ: constant [{{.*}} x i8] c"/path/to{{/|\\5C}}{{.*}}\00" // Check that -fprofile-use=some/path reads some/path/default.profdata +// This uses Clang FE format profile. // RUN: rm -rf %t.dir // RUN: mkdir -p %t.dir/some/path // RUN: llvm-profdata merge %S/Inputs/gcc-flag-compatibility.proftext -o %t.dir/some/path/default.profdata -// RUN: %clang %s -o - -Xclang -disable-llvm-passes -emit-llvm -S -fprofile-use=%t.dir/some/path | FileCheck -check-prefix=PROFILE-USE-2 %s -// PROFILE-USE-2: = !{!"branch_weights", i32 101, i32 2} +// RUN: %clang %s -o - -Xclang -disable-llvm-passes -emit-llvm -S -fprofile-use=%t.dir/some/path -fno-experimental-new-pass-manager | FileCheck -check-prefix=PROFILE-USE %s +// RUN: %clang %s -o - -Xclang -disable-llvm-passes -emit-llvm -S -fprofile-use=%t.dir/some/path -fexperimental-new-pass-manager | FileCheck -check-prefix=PROFILE-USE %s // Check that -fprofile-use=some/path/file.prof reads some/path/file.prof +// This uses Clang FE format profile. // RUN: rm -rf %t.dir // RUN: mkdir -p %t.dir/some/path // RUN: llvm-profdata merge %S/Inputs/gcc-flag-compatibility.proftext -o %t.dir/some/path/file.prof -// RUN: %clang %s -o - -Xclang -disable-llvm-passes -emit-llvm -S -fprofile-use=%t.dir/some/path/file.prof | FileCheck -check-prefix=PROFILE-USE-3 %s -// PROFILE-USE-3: = !{!"branch_weights", i32 101, i32 2} +// RUN: %clang %s -o - -Xclang -disable-llvm-passes -emit-llvm -S -fprofile-use=%t.dir/some/path/file.prof -fno-experimental-new-pass-manager | FileCheck -check-prefix=PROFILE-USE %s +// RUN: %clang %s -o - -Xclang -disable-llvm-passes -emit-llvm -S -fprofile-use=%t.dir/some/path/file.prof -fexperimental-new-pass-manager | FileCheck -check-prefix=PROFILE-USE %s +// PROFILE-USE: = !{!"branch_weights", i32 101, i32 2} + +// Check that -fprofile-use=some/path reads some/path/default.profdata +// This uses LLVM IR format profile. +// RUN: rm -rf %t.dir +// RUN: mkdir -p %t.dir/some/path +// RUN: llvm-profdata merge %S/Inputs/gcc-flag-compatibility_IR.proftext -o %t.dir/some/path/default.profdata +// RUN: %clang %s -o - -emit-llvm -S -fprofile-use=%t.dir/some/path -fno-experimental-new-pass-manager | FileCheck -check-prefix=PROFILE-USE-IR %s +// RUN: %clang %s -o - -emit-llvm -S -fprofile-use=%t.dir/some/path -fexperimental-new-pass-manager | FileCheck -check-prefix=PROFILE-USE-IR %s + +// Check that -fprofile-use=some/path/file.prof reads some/path/file.prof +// This uses LLVM IR format profile. +// RUN: rm -rf %t.dir +// RUN: mkdir -p %t.dir/some/path +// RUN: llvm-profdata merge %S/Inputs/gcc-flag-compatibility_IR.proftext -o %t.dir/some/path/file.prof +// RUN: %clang %s -o - -emit-llvm -S -fprofile-use=%t.dir/some/path/file.prof -fno-experimental-new-pass-manager | FileCheck -check-prefix=PROFILE-USE-IR %s +// RUN: %clang %s -o - -emit-llvm -S -fprofile-use=%t.dir/some/path/file.prof -fexperimental-new-pass-manager | FileCheck -check-prefix=PROFILE-USE-IR %s + +// PROFILE-USE-IR: = !{!"branch_weights", i32 100, i32 1} int X = 0; Index: llvm/trunk/include/llvm/Passes/PassBuilder.h =================================================================== --- llvm/trunk/include/llvm/Passes/PassBuilder.h +++ llvm/trunk/include/llvm/Passes/PassBuilder.h @@ -629,6 +629,12 @@ TopLevelPipelineParsingCallbacks.push_back(C); } + /// Add PGOInstrumenation passes for O0 only. + void addPGOInstrPassesForO0(ModulePassManager &MPM, bool DebugLogging, + bool RunProfileGen, bool IsCS, + std::string ProfileFile, + std::string ProfileRemappingFile); + private: static Optional> parsePipelineText(StringRef Text); @@ -660,7 +666,6 @@ OptimizationLevel Level, bool RunProfileGen, bool IsCS, std::string ProfileFile, std::string ProfileRemappingFile); - void invokePeepholeEPCallbacks(FunctionPassManager &, OptimizationLevel); // Extension Point callbacks Index: llvm/trunk/lib/Passes/PassBuilder.cpp =================================================================== --- llvm/trunk/lib/Passes/PassBuilder.cpp +++ llvm/trunk/lib/Passes/PassBuilder.cpp @@ -541,6 +541,7 @@ bool RunProfileGen, bool IsCS, std::string ProfileFile, std::string ProfileRemappingFile) { + assert(Level != O0 && "Not expecting O0 here!"); // Generally running simplification passes and the inliner with an high // threshold results in smaller executables, but there may be cases where // the size grows, so let's be conservative here and skip this simplification @@ -571,34 +572,62 @@ CGPipeline.addPass(createCGSCCToFunctionPassAdaptor(std::move(FPM))); MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPipeline))); + + // Delete anything that is now dead to make sure that we don't instrument + // dead code. Instrumentation can end up keeping dead code around and + // dramatically increase code size. + MPM.addPass(GlobalDCEPass()); } - // Delete anything that is now dead to make sure that we don't instrument - // dead code. Instrumentation can end up keeping dead code around and - // dramatically increase code size. - MPM.addPass(GlobalDCEPass()); + if (!RunProfileGen) { + assert(!ProfileFile.empty() && "Profile use expecting a profile file!"); + MPM.addPass(PGOInstrumentationUse(ProfileFile, ProfileRemappingFile, IsCS)); + // Cache ProfileSummaryAnalysis once to avoid the potential need to insert + // RequireAnalysisPass for PSI before subsequent non-module passes. + MPM.addPass(RequireAnalysisPass()); + return; + } - if (RunProfileGen) { - MPM.addPass(PGOInstrumentationGen(IsCS)); + // Perform PGO instrumentation. + MPM.addPass(PGOInstrumentationGen(IsCS)); - FunctionPassManager FPM; - FPM.addPass( - createFunctionToLoopPassAdaptor(LoopRotatePass(), DebugLogging)); - MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM))); - - // Add the profile lowering pass. - InstrProfOptions Options; - if (!ProfileFile.empty()) - Options.InstrProfileOutput = ProfileFile; - Options.DoCounterPromotion = true; - Options.UseBFIInPromotion = IsCS; - MPM.addPass(InstrProfiling(Options, IsCS)); - } else if (!ProfileFile.empty()) { + FunctionPassManager FPM; + FPM.addPass(createFunctionToLoopPassAdaptor(LoopRotatePass(), DebugLogging)); + MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM))); + + // Add the profile lowering pass. + InstrProfOptions Options; + if (!ProfileFile.empty()) + Options.InstrProfileOutput = ProfileFile; + // Do counter promotion at Level greater than O0. + Options.DoCounterPromotion = true; + Options.UseBFIInPromotion = IsCS; + MPM.addPass(InstrProfiling(Options, IsCS)); +} + +void PassBuilder::addPGOInstrPassesForO0(ModulePassManager &MPM, + bool DebugLogging, bool RunProfileGen, + bool IsCS, std::string ProfileFile, + std::string ProfileRemappingFile) { + if (!RunProfileGen) { + assert(!ProfileFile.empty() && "Profile use expecting a profile file!"); MPM.addPass(PGOInstrumentationUse(ProfileFile, ProfileRemappingFile, IsCS)); // Cache ProfileSummaryAnalysis once to avoid the potential need to insert // RequireAnalysisPass for PSI before subsequent non-module passes. MPM.addPass(RequireAnalysisPass()); + return; } + + // Perform PGO instrumentation. + MPM.addPass(PGOInstrumentationGen(IsCS)); + // Add the profile lowering pass. + InstrProfOptions Options; + if (!ProfileFile.empty()) + Options.InstrProfileOutput = ProfileFile; + // Do not do counter promotion at O0. + Options.DoCounterPromotion = false; + Options.UseBFIInPromotion = IsCS; + MPM.addPass(InstrProfiling(Options, IsCS)); } static InlineParams @@ -1801,9 +1830,19 @@ .Case("O3", O3) .Case("Os", Os) .Case("Oz", Oz); - if (L == O0) - // At O0 we do nothing at all! + if (L == O0) { + // Add instrumentation PGO passes -- at O0 we can still do PGO. + if (PGOOpt && Matches[1] != "thinlto" && + (PGOOpt->Action == PGOOptions::IRInstr || + PGOOpt->Action == PGOOptions::IRUse)) + addPGOInstrPassesForO0( + MPM, DebugLogging, + /* RunProfileGen */ (PGOOpt->Action == PGOOptions::IRInstr), + /* IsCS */ false, PGOOpt->ProfileFile, + PGOOpt->ProfileRemappingFile); + // Do nothing else at all! return Error::success(); + } if (Matches[1] == "default") { MPM.addPass(buildPerModuleDefaultPipeline(L, DebugLogging)); Index: llvm/trunk/test/Other/new-pm-pgo-O0.ll =================================================================== --- llvm/trunk/test/Other/new-pm-pgo-O0.ll +++ llvm/trunk/test/Other/new-pm-pgo-O0.ll @@ -0,0 +1,21 @@ +; RUN: opt -debug-pass-manager -passes='default' -pgo-kind=pgo-instr-gen-pipeline -profile-file='temp' %s 2>&1 |FileCheck %s --check-prefixes=GEN +; RUN: llvm-profdata merge %S/Inputs/new-pm-pgo.proftext -o %t.profdata +; RUN: opt -debug-pass-manager -passes='default' -pgo-kind=pgo-instr-use-pipeline -profile-file='%t.profdata' %s 2>&1 |FileCheck %s --check-prefixes=USE_DEFAULT,USE +; RUN: opt -debug-pass-manager -passes='thinlto-pre-link' -pgo-kind=pgo-instr-use-pipeline -profile-file='%t.profdata' %s 2>&1 \ +; RUN: |FileCheck %s --check-prefixes=USE_PRE_LINK,USE +; RUN: opt -debug-pass-manager -passes='lto-pre-link' -pgo-kind=pgo-instr-use-pipeline -profile-file='%t.profdata' %s 2>&1 \ +; RUN: |FileCheck %s --check-prefixes=USE_PRE_LINK,USE +; RUN: opt -debug-pass-manager -passes='thinlto' -pgo-kind=pgo-instr-use-pipeline -profile-file='%t.profdata' %s 2>&1 \ +; RUN: |FileCheck %s --check-prefixes=USE_POST_LINK,USE + +; +; GEN: Running pass: PGOInstrumentationGen +; USE_DEFAULT: Running pass: PGOInstrumentationUse +; USE_PRE_LINK: Running pass: PGOInstrumentationUse +; USE_POST_LINK-NOT: Running pass: PGOInstrumentationUse +; USE-NOT: Running pass: PGOIndirectCallPromotion +; USE-NOT: Running pass: PGOMemOPSizeOpt + +define void @foo() { + ret void +}