Index: clang/docs/ClangCommandLineReference.rst =================================================================== --- clang/docs/ClangCommandLineReference.rst +++ clang/docs/ClangCommandLineReference.rst @@ -2016,6 +2016,16 @@ Use instrumentation data for profile-guided optimization. If pathname is a directory, it reads from /default.profdata. Otherwise, it reads from file . +.. option:: -fprofile-omit-cold-opt, -fno-profile-omit-cold-opt + +Adds ``optnone`` attributes to functions whose instrumentation-based PGO profiling counts are equal to zero (i.e. "cold"). + +.. program:: clang1 +.. option:: -fprofile-omit-cold-opt= +.. program:: clang + +This allows you to choose the lower % of functions, sorted by their profiling counts, as cold functions that will not be optimized. + .. option:: -freciprocal-math, -fno-reciprocal-math Allow division operations to be reassociated Index: clang/include/clang/Driver/Options.td =================================================================== --- clang/include/clang/Driver/Options.td +++ clang/include/clang/Driver/Options.td @@ -793,6 +793,17 @@ Alias; defm debug_info_for_profiling : OptInFFlag<"debug-info-for-profiling", "Emit extra debug info to make sample profile more accurate">; + +// Options to omit optimizations on cold code. +def fprofile_omit_cold_opt : Flag<["-"], "fprofile-omit-cold-opt">, + Group, Flags<[CoreOption]>, + HelpText<"Do not optimize functions that profiling indicates are cold">; +def fno_profile_omit_cold_opt : Flag<["-"], "fno-profile-omit-cold-opt">, + Group, Flags<[CoreOption]>; +def fprofile_omit_cold_opt_EQ : Joined<["-"], "fprofile-omit-cold-opt=">, + Group, Flags<[CoreOption]>, MetaVarName<"">, + HelpText<"Do not optimize functions whose profiling count is lower than this percentage">; + def fprofile_instr_generate : Flag<["-"], "fprofile-instr-generate">, Group, Flags<[CoreOption]>, HelpText<"Generate instrumented code to collect execution counts into default.profraw file (overridden by '=' form of option or LLVM_PROFILE_FILE env var)">; Index: clang/lib/Driver/ToolChains/Clang.cpp =================================================================== --- clang/lib/Driver/ToolChains/Clang.cpp +++ clang/lib/Driver/ToolChains/Clang.cpp @@ -824,6 +824,19 @@ CmdArgs.push_back( Args.MakeArgString(Twine("-fprofile-instrument-use-path=") + Path)); } + // Tell profile passes to avoid optimizing cold functions. + if (Args.hasFlag(options::OPT_fprofile_omit_cold_opt, + options::OPT_fprofile_omit_cold_opt_EQ, + options::OPT_fno_profile_omit_cold_opt, false)) { + CmdArgs.push_back("-mllvm"); + CmdArgs.push_back("-profile-omit-cold-func-opt=true"); + + if (Arg *A = Args.getLastArg(options::OPT_fprofile_omit_cold_opt_EQ)) { + CmdArgs.push_back("-mllvm"); + CmdArgs.push_back(Args.MakeArgString( + Twine("-profile-omit-cold-func-opt-percent=") + A->getValue())); + } + } } bool EmitCovNotes = Args.hasFlag(options::OPT_ftest_coverage, Index: clang/lib/Driver/ToolChains/CommonArgs.cpp =================================================================== --- clang/lib/Driver/ToolChains/CommonArgs.cpp +++ clang/lib/Driver/ToolChains/CommonArgs.cpp @@ -516,6 +516,18 @@ llvm::sys::path::append(Path, "default.profdata"); CmdArgs.push_back(Args.MakeArgString(Twine("-plugin-opt=cs-profile-path=") + Path)); + // Propagate -profile-omit-cold-func-opt options + if (Args.hasFlag(options::OPT_fprofile_omit_cold_opt, + options::OPT_fprofile_omit_cold_opt_EQ, + options::OPT_fno_profile_omit_cold_opt, false)) { + CmdArgs.push_back("-plugin-opt=-profile-omit-cold-func-opt=true"); + Arg *A = Args.getLastArg(options::OPT_fprofile_omit_cold_opt_EQ); + if (A) { + CmdArgs.push_back(Args.MakeArgString( + Twine("-plugin-opt=-profile-omit-cold-func-opt-percent=") + + A->getValue())); + } + } } // Need this flag to turn on new pass manager via Gold plugin. Index: clang/test/Driver/gold-lto-omit-cold-opt.c =================================================================== --- /dev/null +++ clang/test/Driver/gold-lto-omit-cold-opt.c @@ -0,0 +1,11 @@ +// RUN: touch %t.o +// +// RUN: %clang -### -fprofile-instr-use -fprofile-omit-cold-opt %t.o -flto 2>&1 \ +// RUN: | FileCheck --check-prefix=CHECK-BASE %s + +// RUN: %clang -### -fprofile-instr-use -fprofile-omit-cold-opt=87 \ +// RUN: %t.o -flto 2>&1 \ +// RUN: | FileCheck --check-prefixes=CHECK-BASE,CHECK-PERCENT %s + +// CHECK-BASE: "-plugin-opt=-profile-omit-cold-func-opt=true" +// CHECK-PERCENT: "-plugin-opt=-profile-omit-cold-func-opt-percent=87" Index: clang/test/Driver/omit-cold-opt.c =================================================================== --- /dev/null +++ clang/test/Driver/omit-cold-opt.c @@ -0,0 +1,20 @@ +// RUN: %clang -### -fprofile-instr-use -fprofile-omit-cold-opt -c %s 2>&1 \ +// RUN: | FileCheck --check-prefix=CHECK-BASE %s + +// RUN: %clang -### -fprofile-instr-use \ +// RUN: -fprofile-omit-cold-opt=87 \ +// RUN: -c %s 2>&1 \ +// RUN: | FileCheck --check-prefixes=CHECK-BASE,CHECK-PERCENT %s + +// RUN: %clang -### -fprofile-instr-use \ +// RUN: -fprofile-omit-cold-opt -fno-profile-omit-cold-opt \ +// RUN: -c %s 2>&1 \ +// RUN: | FileCheck --check-prefix=CHECK-NEG %s + +// Shouldn't do anything if it's not using PGO profile +// RUN: %clang -### -fprofile-omit-cold-opt -c %s 2>&1 \ +// RUN: | FileCheck --check-prefix=CHECK-NEG %s + +// CHECK-BASE: "-mllvm" "-profile-omit-cold-func-opt=true" +// CHECK-PERCENT: "-mllvm" "-profile-omit-cold-func-opt-percent=87" +// CHECK-NEG-NOT: "-profile-omit-cold-func-opt=true"