diff --git a/clang/docs/ClangCommandLineReference.rst b/clang/docs/ClangCommandLineReference.rst --- a/clang/docs/ClangCommandLineReference.rst +++ b/clang/docs/ClangCommandLineReference.rst @@ -2128,6 +2128,10 @@ Enables splitting of the LTO unit +.. option:: -fsplit-machine-functions, -fno-split-machine-functions + +Split machine functions using profile information (x86-elf only) + .. option:: -fsplit-stack .. option:: -fstack-clash-protection diff --git a/clang/include/clang/Basic/CodeGenOptions.def b/clang/include/clang/Basic/CodeGenOptions.def --- a/clang/include/clang/Basic/CodeGenOptions.def +++ b/clang/include/clang/Basic/CodeGenOptions.def @@ -162,6 +162,7 @@ CODEGENOPT(NullPointerIsValid , 1, 0) ///< Assume Null pointer deference is defined. CODEGENOPT(CorrectlyRoundedDivSqrt, 1, 0) ///< -cl-fp32-correctly-rounded-divide-sqrt CODEGENOPT(UniqueInternalLinkageNames, 1, 0) ///< Internal Linkage symbols get unique names. +CODEGENOPT(SplitMachineFunctions, 1, 0) ///< Split machine functions using profile information. /// When false, this attempts to generate code as if the result of an /// overflowing conversion matches the overflowing behavior of a target's native diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -1989,6 +1989,12 @@ defm unique_section_names : OptOutFFlag<"unique-section-names", "", "Don't use unique names for text and data sections">; +def fsplit_machine_functions : Flag <["-"], "fsplit-machine-functions">, + Group, Flags<[CC1Option]>, + HelpText<"Split machine functions using profile information (x86-elf only)">; +def fno_split_machine_functions: Flag <["-"], "fno-split-machine-functions">, + Group; + defm strict_return : OptOutFFlag<"strict-return", "", "Don't treat control flow paths that fall off the end of a non-void function as unreachable">; diff --git a/clang/lib/CodeGen/BackendUtil.cpp b/clang/lib/CodeGen/BackendUtil.cpp --- a/clang/lib/CodeGen/BackendUtil.cpp +++ b/clang/lib/CodeGen/BackendUtil.cpp @@ -9,6 +9,7 @@ #include "clang/CodeGen/BackendUtil.h" #include "clang/Basic/CodeGenOptions.h" #include "clang/Basic/Diagnostic.h" +#include "clang/Basic/DiagnosticFrontend.h" #include "clang/Basic/LangOptions.h" #include "clang/Basic/TargetOptions.h" #include "clang/Frontend/FrontendDiagnostic.h" @@ -514,6 +515,15 @@ Options.BBSectionsFuncListBuf = std::move(*MBOrErr); } + if (CodeGenOpts.SplitMachineFunctions) { + if (CodeGenOpts.getProfileUse() != CodeGenOptions::ProfileNone) + Options.EnableMachineFunctionSplitter = true; + else + Diags.Report(diag::warn_fe_backend_optimization_failure) + << "ignored -fsplit-machine-functions, no profile provided via " + "-fprofile-use"; + } + Options.FunctionSections = CodeGenOpts.FunctionSections; Options.DataSections = CodeGenOpts.DataSections; Options.UniqueSectionNames = CodeGenOpts.UniqueSectionNames; diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -4256,6 +4256,8 @@ options::OPT_fno_unique_section_names, options::OPT_funique_basic_block_section_names, options::OPT_fno_unique_basic_block_section_names, + options::OPT_fsplit_machine_functions, + options::OPT_fno_split_machine_functions, options::OPT_mrestrict_it, options::OPT_mno_restrict_it, options::OPT_mstackrealign, @@ -4911,6 +4913,15 @@ options::OPT_fno_unique_basic_block_section_names, false)) CmdArgs.push_back("-funique-basic-block-section-names"); + if (Args.hasFlag(options::OPT_fsplit_machine_functions, + options::OPT_fno_split_machine_functions, false)) { + if (Triple.isX86() && Triple.isOSBinFormatELF()) + CmdArgs.push_back("-fsplit-machine-functions"); + else + D.Diag(diag::err_drv_unsupported_opt_for_target) + << "-fsplit-machine-functions" << TripleStr; + } + Args.AddLastArg(CmdArgs, options::OPT_finstrument_functions, options::OPT_finstrument_functions_after_inlining, options::OPT_finstrument_function_entry_bare); diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -998,6 +998,8 @@ Opts.UniqueInternalLinkageNames = Args.hasArg(OPT_funique_internal_linkage_names); + Opts.SplitMachineFunctions = Args.hasArg(OPT_fsplit_machine_functions); + Opts.MergeFunctions = Args.hasArg(OPT_fmerge_functions); Opts.NoUseJumpTables = Args.hasArg(OPT_fno_jump_tables); diff --git a/clang/test/CodeGen/split-machine-functions.c b/clang/test/CodeGen/split-machine-functions.c new file mode 100644 --- /dev/null +++ b/clang/test/CodeGen/split-machine-functions.c @@ -0,0 +1,34 @@ +// REQUIRES: x86-registered-target + +// RUN: echo "foo" > %t.proftext +// RUN: echo "# Func Hash:" >> %t.proftext +// RUN: echo "11262309905" >> %t.proftext +// RUN: echo "# Num Counters:" >> %t.proftext +// RUN: echo "2" >> %t.proftext +// RUN: echo "# Counter Values:" >> %t.proftext +// RUN: echo "1000000" >> %t.proftext +// RUN: echo "0" >> %t.proftext +// RUN: llvm-profdata merge -o %t.profdata %t.proftext +// RUN: %clang_cc1 -triple x86_64 -O3 -S -fprofile-instrument-use-path=%t.profdata -fsplit-machine-functions -o - < %s | FileCheck %s + +__attribute__((noinline)) int foo(int argc) { + if (argc % 2 == 0) { + exit(argc); + } else { + return argc + 1; + } +} + +int main(int argc, char *argv[]) { + int total = 0; + for (int i = 0; i < 1000000; ++i) { + total += foo(argc); + } + printf("%d\n", total); +} + +// CHECK: .section .text.hot.,"ax",@progbits +// CHECK: foo: +// CHECK: section .text.unlikely.foo,"ax",@progbits +// CHECK: foo.cold: +// CHECK: callq exit@PLT diff --git a/clang/test/Driver/fsplit-machine-functions.c b/clang/test/Driver/fsplit-machine-functions.c new file mode 100644 --- /dev/null +++ b/clang/test/Driver/fsplit-machine-functions.c @@ -0,0 +1,9 @@ +// RUN: %clang -### -target x86_64 -fsplit-machine-functions %s -c 2>&1 | FileCheck -check-prefix=CHECK-OPT %s +// RUN: %clang -### -target x86_64 -fsplit-machine-functions -fno-split-machine-functions %s -c 2>&1 | FileCheck -check-prefix=CHECK-NOOPT %s +// RUN: %clang -c -target x86_64 -fsplit-machine-functions %s -c 2>&1 | FileCheck -check-prefix=CHECK-WARN %s +// RUN: not %clang -c -target arm-unknown-linux -fsplit-machine-functions %s -c 2>&1 | FileCheck -check-prefix=CHECK-TRIPLE %s + +// CHECK-OPT: "-fsplit-machine-functions" +// CHECK-NOOPT-NOT: "-fsplit-machine-functions" +// CHECK-WARN: ignored -fsplit-machine-functions, no profile provided via -fprofile-use +// CHECK-TRIPLE: error: unsupported option '-fsplit-machine-functions' for target