diff --git a/lld/ELF/Config.h b/lld/ELF/Config.h --- a/lld/ELF/Config.h +++ b/lld/ELF/Config.h @@ -175,6 +175,7 @@ bool ltoEmitAsm; bool ltoNewPassManager; bool ltoUniqueBasicBlockSectionNames; + bool ltoSplitMachineFunctions; bool ltoWholeProgramVisibility; bool mergeArmExidx; bool mipsN32Abi = false; diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp --- a/lld/ELF/Driver.cpp +++ b/lld/ELF/Driver.cpp @@ -973,6 +973,9 @@ config->ltoUniqueBasicBlockSectionNames = args.hasFlag(OPT_lto_unique_basic_block_section_names, OPT_no_lto_unique_basic_block_section_names, false); + config->ltoSplitMachineFunctions = + args.hasFlag(OPT_lto_split_machine_functions, + OPT_no_lto_split_machine_functions, false); config->mapFile = args.getLastArgValue(OPT_Map); config->mipsGotSize = args::getInteger(args, OPT_mips_got_size, 0xfff0); config->mergeArmExidx = diff --git a/lld/ELF/LTO.cpp b/lld/ELF/LTO.cpp --- a/lld/ELF/LTO.cpp +++ b/lld/ELF/LTO.cpp @@ -115,6 +115,8 @@ c.Options.UniqueBasicBlockSectionNames = config->ltoUniqueBasicBlockSectionNames; + c.Options.EnableMachineFunctionSplitter = config->ltoSplitMachineFunctions; + if (auto relocModel = getRelocModelFromCMModel()) c.RelocModel = *relocModel; else if (config->relocatable) diff --git a/lld/ELF/Options.td b/lld/ELF/Options.td --- a/lld/ELF/Options.td +++ b/lld/ELF/Options.td @@ -557,6 +557,9 @@ defm lto_unique_basic_block_section_names: BB<"lto-unique-basic-block-section-names", "Give unique names to every basic block section for LTO", "Do not give unique names to every basic block section for LTO (default)">; +defm lto_split_machine_functions: BB<"lto-split-machine-functions", + "Enable late function splitting using profile information for LTO (x86 ELF)", + "Disable late function splitting using profile information for LTO (x86 ELF)">; def shuffle_sections: JJ<"shuffle-sections=">, MetaVarName<"">, HelpText<"Shuffle input sections using the given seed. If 0, use a random seed">; def thinlto_cache_dir: JJ<"thinlto-cache-dir=">, diff --git a/lld/test/ELF/lto/split-machine-functions.ll b/lld/test/ELF/lto/split-machine-functions.ll new file mode 100644 --- /dev/null +++ b/lld/test/ELF/lto/split-machine-functions.ll @@ -0,0 +1,52 @@ +; REQUIRES: x86 +; RUN: llvm-as %s -o %t.o +; RUN: ld.lld %t.o -o %t --lto-split-machine-functions --lto-O0 --save-temps +; RUN: llvm-nm %t.lto.o | FileCheck %s + +target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +define void @foo1(i1 zeroext %0) nounwind !prof !14 !section_prefix !15 { +;; Check that cold block is split out with new symbol. +; CHECK: foo1.cold + br i1 %0, label %2, label %4, !prof !17 + +2: ; preds = %1 + %3 = call i32 @bar() + br label %6 + +4: ; preds = %1 + %5 = call i32 @baz() + br label %6 + +6: ; preds = %4, %2 + ret void +} + +define i32 @bar() noinline optnone { + ret i32 1; +} + +define i32 @baz() noinline optnone { + ret i32 1; +} + +!llvm.module.flags = !{!0} +!0 = !{i32 1, !"ProfileSummary", !1} +!1 = !{!2, !3, !4, !5, !6, !7, !8, !9} +!2 = !{!"ProfileFormat", !"InstrProf"} +!3 = !{!"TotalCount", i64 10000} +!4 = !{!"MaxCount", i64 10} +!5 = !{!"MaxInternalCount", i64 1} +!6 = !{!"MaxFunctionCount", i64 1000} +!7 = !{!"NumCounts", i64 3} +!8 = !{!"NumFunctions", i64 5} +!9 = !{!"DetailedSummary", !10} +!10 = !{!11, !12, !13} +!11 = !{i32 10000, i64 100, i32 1} +!12 = !{i32 999900, i64 100, i32 1} +!13 = !{i32 999999, i64 1, i32 2} +!14 = !{!"function_entry_count", i64 7000} +!15 = !{!"function_section_prefix", !".hot"} +!16 = !{!"function_section_prefix", !".unlikely"} +!17 = !{!"branch_weights", i32 7000, i32 0}