diff --git a/lld/COFF/Config.h b/lld/COFF/Config.h --- a/lld/COFF/Config.h +++ b/lld/COFF/Config.h @@ -223,6 +223,9 @@ // Used for /lto-cs-profile-path llvm::StringRef ltoCSProfileFile; + // Used for /lto-pgo-warn-mismatch: + bool ltoPGOWarnMismatch = true; + // Used for /call-graph-ordering-file: llvm::MapVector, uint64_t> diff --git a/lld/COFF/Driver.cpp b/lld/COFF/Driver.cpp --- a/lld/COFF/Driver.cpp +++ b/lld/COFF/Driver.cpp @@ -1750,6 +1750,8 @@ config->ltoCSProfileGenerate = args.hasArg(OPT_lto_cs_profile_generate); config->ltoCSProfileFile = args.getLastArgValue(OPT_lto_cs_profile_file); // Handle miscellaneous boolean flags. + config->ltoPGOWarnMismatch = args.hasFlag(OPT_lto_pgo_warn_mismatch, + OPT_lto_pgo_warn_mismatch_no, true); config->allowBind = args.hasFlag(OPT_allowbind, OPT_allowbind_no, true); config->allowIsolation = args.hasFlag(OPT_allowisolation, OPT_allowisolation_no, true); diff --git a/lld/COFF/LTO.cpp b/lld/COFF/LTO.cpp --- a/lld/COFF/LTO.cpp +++ b/lld/COFF/LTO.cpp @@ -87,6 +87,7 @@ c.DebugPassManager = config->ltoDebugPassManager; c.CSIRProfile = std::string(config->ltoCSProfileFile); c.RunCSIRInstr = config->ltoCSProfileGenerate; + c.PGOWarnMismatch = config->ltoPGOWarnMismatch; if (config->saveTemps) checkError(c.addSaveTemps(std::string(config->outputFile) + ".", diff --git a/lld/COFF/Options.td b/lld/COFF/Options.td --- a/lld/COFF/Options.td +++ b/lld/COFF/Options.td @@ -244,6 +244,10 @@ HelpText<"Perform context sensitive PGO instrumentation">; def lto_cs_profile_file : P<"lto-cs-profile-file", "Context sensitive profile file path">; +defm lto_pgo_warn_mismatch: B< + "lto-pgo-warn-mismatch", + "turn on warnings about profile cfg mismatch (default)>", + "turn off warnings about profile cfg mismatch">; def dash_dash_version : Flag<["--"], "version">, HelpText<"Display the version number and exit">; def threads diff --git a/lld/ELF/Config.h b/lld/ELF/Config.h --- a/lld/ELF/Config.h +++ b/lld/ELF/Config.h @@ -178,6 +178,7 @@ bool ignoreDataAddressEquality; bool ignoreFunctionAddressEquality; bool ltoCSProfileGenerate; + bool ltoPGOWarnMismatch; bool ltoDebugPassManager; bool ltoEmitAsm; bool ltoNewPassManager; diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp --- a/lld/ELF/Driver.cpp +++ b/lld/ELF/Driver.cpp @@ -1069,6 +1069,8 @@ config->ltoAAPipeline = args.getLastArgValue(OPT_lto_aa_pipeline); config->ltoCSProfileGenerate = args.hasArg(OPT_lto_cs_profile_generate); config->ltoCSProfileFile = args.getLastArgValue(OPT_lto_cs_profile_file); + config->ltoPGOWarnMismatch = args.hasFlag(OPT_lto_pgo_warn_mismatch, + OPT_no_lto_pgo_warn_mismatch, true); config->ltoDebugPassManager = args.hasArg(OPT_lto_debug_pass_manager); config->ltoEmitAsm = args.hasArg(OPT_lto_emit_asm); config->ltoNewPassManager = diff --git a/lld/ELF/LTO.cpp b/lld/ELF/LTO.cpp --- a/lld/ELF/LTO.cpp +++ b/lld/ELF/LTO.cpp @@ -163,6 +163,7 @@ c.CSIRProfile = std::string(config->ltoCSProfileFile); c.RunCSIRInstr = config->ltoCSProfileGenerate; + c.PGOWarnMismatch = config->ltoPGOWarnMismatch; if (config->emitLLVM) { c.PostInternalizeModuleHook = [](size_t task, const Module &m) { diff --git a/lld/ELF/Options.td b/lld/ELF/Options.td --- a/lld/ELF/Options.td +++ b/lld/ELF/Options.td @@ -563,6 +563,9 @@ HelpText<"Perform context sensitive PGO instrumentation">; def lto_cs_profile_file: JJ<"lto-cs-profile-file=">, HelpText<"Context sensitive profile file path">; +defm lto_pgo_warn_mismatch: BB<"lto-pgo-warn-mismatch", + "turn on warnings about profile cfg mismatch (default)>", + "turn off warnings about profile cfg mismatch">; def lto_obj_path_eq: JJ<"lto-obj-path=">; def lto_sample_profile: JJ<"lto-sample-profile=">, HelpText<"Sample profile file path">; diff --git a/lld/test/COFF/Inputs/thinlto_cs.proftext b/lld/test/COFF/Inputs/thinlto_cs.proftext new file mode 100644 --- /dev/null +++ b/lld/test/COFF/Inputs/thinlto_cs.proftext @@ -0,0 +1,11 @@ +# CSIR level Instrumentation Flag +:csir +f +# Func Hash: +1535914979662757887 +# Num Counters: +2 +# Counter Values: +1 +0 + diff --git a/lld/test/COFF/thinlto-pgo-warn.ll b/lld/test/COFF/thinlto-pgo-warn.ll new file mode 100644 --- /dev/null +++ b/lld/test/COFF/thinlto-pgo-warn.ll @@ -0,0 +1,57 @@ +; REQUIRES: x86 + +; Basic ThinLTO tests. +; RUN: opt -module-summary %s -o %t1.obj +; RUN: llvm-profdata merge %S/Inputs/thinlto_cs.proftext -o %t2.profdata + +; Ensure lld generates warnings for profile cfg mismatch. +; RUN: lld-link /out:%t3.dll /dll /noentry /export:f /lto-cs-profile-file:%t2.profdata /lto-pgo-warn-mismatch /opt:lldlto=2 %t1.obj 2>&1 | FileCheck --check-prefix CHECK-WARNING %s + +; Ensure lld will not generate warnings for profile cfg mismatch. +; RUN: lld-link /out:%t3.dll /dll /noentry /export:f /lto-cs-profile-file:%t2.profdata /lto-pgo-warn-mismatch:no /opt:lldlto=2 %t1.obj 2>&1 | FileCheck --allow-empty %s + +; CHECK-WARNING: warning: {{.*}} function control flow change detected (hash mismatch) f Hash = 1895182923573755903 +; CHECK-NOT: warning: {{.*}} function control flow change detected (hash mismatch) f Hash = 1895182923573755903 + +target datalayout = "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-pc-windows-msvc" + +define i32 @f(i32 returned %a) #0 { +entry: + ret i32 %a +} + +attributes #0 = { "target-cpu"="x86-64" } + +!llvm.module.flags = !{!0, !1} + +!0 = !{i32 1, !"wchar_size", i32 4} +!1 = !{i32 1, !"ProfileSummary", !2} +!2 = !{!3, !4, !5, !6, !7, !8, !9, !10, !11, !12} +!3 = !{!"ProfileFormat", !"InstrProf"} +!4 = !{!"TotalCount", i64 2} +!5 = !{!"MaxCount", i64 1} +!6 = !{!"MaxInternalCount", i64 0} +!7 = !{!"MaxFunctionCount", i64 1} +!8 = !{!"NumCounts", i64 3} +!9 = !{!"NumFunctions", i64 2} +!10 = !{!"IsPartialProfile", i64 0} +!11 = !{!"PartialProfileRatio", double 0.000000e+00} +!12 = !{!"DetailedSummary", !13} +!13 = !{!14, !15, !16, !17, !18, !19, !20, !21, !22, !23, !24, !25, !26, !27, !28, !29} +!14 = !{i32 10000, i64 0, i32 0} +!15 = !{i32 100000, i64 0, i32 0} +!16 = !{i32 200000, i64 0, i32 0} +!17 = !{i32 300000, i64 0, i32 0} +!18 = !{i32 400000, i64 0, i32 0} +!19 = !{i32 500000, i64 1, i32 2} +!20 = !{i32 600000, i64 1, i32 2} +!21 = !{i32 700000, i64 1, i32 2} +!22 = !{i32 800000, i64 1, i32 2} +!23 = !{i32 900000, i64 1, i32 2} +!24 = !{i32 950000, i64 1, i32 2} +!25 = !{i32 990000, i64 1, i32 2} +!26 = !{i32 999000, i64 1, i32 2} +!27 = !{i32 999900, i64 1, i32 2} +!28 = !{i32 999990, i64 1, i32 2} +!29 = !{i32 999999, i64 1, i32 2} diff --git a/lld/test/ELF/lto/Inputs/thinlto_cs.proftext b/lld/test/ELF/lto/Inputs/thinlto_cs.proftext new file mode 100644 --- /dev/null +++ b/lld/test/ELF/lto/Inputs/thinlto_cs.proftext @@ -0,0 +1,11 @@ +# CSIR level Instrumentation Flag +:csir +f +# Func Hash: +1535914979662757887 +# Num Counters: +2 +# Counter Values: +1 +0 + diff --git a/lld/test/ELF/lto/thinlto-pgo-warn.ll b/lld/test/ELF/lto/thinlto-pgo-warn.ll new file mode 100644 --- /dev/null +++ b/lld/test/ELF/lto/thinlto-pgo-warn.ll @@ -0,0 +1,57 @@ +; REQUIRES: x86 + +;; Basic ThinLTO tests. +; RUN: opt -module-summary %s -o %t1.bc +; RUN: llvm-profdata merge %S/Inputs/thinlto_cs.proftext -o %t2.profdata + +;; Ensure lld generates warnings for profile cfg mismatch. +; RUN: ld.lld --lto-cs-profile-file=%t2.profdata --lto-pgo-warn-mismatch --lto-O2 -shared %t1.bc -o /dev/null 2>&1 | FileCheck --check-prefix CHECK-WARNING %s + +;; Ensure lld will not generate warnings for profile cfg mismatch. +; RUN: ld.lld --lto-cs-profile-file=%t2.profdata --no-lto-pgo-warn-mismatch --lto-O2 -shared %t1.bc -o /dev/null 2>&1 | FileCheck --allow-empty %s + +; CHECK-WARNING: warning: {{.*}} function control flow change detected (hash mismatch) f Hash = 1895182923573755903 +; CHECK-NOT: warning: {{.*}} function control flow change detected (hash mismatch) f Hash = 1895182923573755903 + +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 i32 @f(i32 returned %a) #0 { +entry: + ret i32 %a +} + +attributes #0 = { "target-cpu"="x86-64" } + +!llvm.module.flags = !{!0, !1} + +!0 = !{i32 1, !"wchar_size", i32 4} +!1 = !{i32 1, !"ProfileSummary", !2} +!2 = !{!3, !4, !5, !6, !7, !8, !9, !10, !11, !12} +!3 = !{!"ProfileFormat", !"InstrProf"} +!4 = !{!"TotalCount", i64 2} +!5 = !{!"MaxCount", i64 1} +!6 = !{!"MaxInternalCount", i64 0} +!7 = !{!"MaxFunctionCount", i64 1} +!8 = !{!"NumCounts", i64 3} +!9 = !{!"NumFunctions", i64 2} +!10 = !{!"IsPartialProfile", i64 0} +!11 = !{!"PartialProfileRatio", double 0.000000e+00} +!12 = !{!"DetailedSummary", !13} +!13 = !{!14, !15, !16, !17, !18, !19, !20, !21, !22, !23, !24, !25, !26, !27, !28, !29} +!14 = !{i32 10000, i64 0, i32 0} +!15 = !{i32 100000, i64 0, i32 0} +!16 = !{i32 200000, i64 0, i32 0} +!17 = !{i32 300000, i64 0, i32 0} +!18 = !{i32 400000, i64 0, i32 0} +!19 = !{i32 500000, i64 1, i32 2} +!20 = !{i32 600000, i64 1, i32 2} +!21 = !{i32 700000, i64 1, i32 2} +!22 = !{i32 800000, i64 1, i32 2} +!23 = !{i32 900000, i64 1, i32 2} +!24 = !{i32 950000, i64 1, i32 2} +!25 = !{i32 990000, i64 1, i32 2} +!26 = !{i32 999000, i64 1, i32 2} +!27 = !{i32 999900, i64 1, i32 2} +!28 = !{i32 999990, i64 1, i32 2} +!29 = !{i32 999999, i64 1, i32 2} diff --git a/llvm/include/llvm/LTO/Config.h b/llvm/include/llvm/LTO/Config.h --- a/llvm/include/llvm/LTO/Config.h +++ b/llvm/include/llvm/LTO/Config.h @@ -70,6 +70,9 @@ /// Run PGO context sensitive IR instrumentation. bool RunCSIRInstr = false; + /// Turn on/off the warning about a hash mismatch in the PGO profile data. + bool PGOWarnMismatch = true; + /// Asserts whether we can assume whole program visibility during the LTO /// link. bool HasWholeProgramVisibility = false; diff --git a/llvm/lib/LTO/CMakeLists.txt b/llvm/lib/LTO/CMakeLists.txt --- a/llvm/lib/LTO/CMakeLists.txt +++ b/llvm/lib/LTO/CMakeLists.txt @@ -25,6 +25,7 @@ Extensions IPO InstCombine + Instrumentation Linker MC ObjCARC diff --git a/llvm/lib/LTO/LTOBackend.cpp b/llvm/lib/LTO/LTOBackend.cpp --- a/llvm/lib/LTO/LTOBackend.cpp +++ b/llvm/lib/LTO/LTOBackend.cpp @@ -74,6 +74,10 @@ cl::desc("Assume the input has already undergone ThinLTO function " "importing and the other pre-optimization pipeline changes.")); +namespace llvm { +extern cl::opt NoPGOWarnMismatch; +} + [[noreturn]] static void reportOpenError(StringRef Path, Twine Msg) { errs() << "failed to open " << Path << ": " << Msg << '\n'; errs().flush(); @@ -221,6 +225,7 @@ PGOOpt = PGOOptions(Conf.CSIRProfile, "", Conf.ProfileRemapping, PGOOptions::IRUse, PGOOptions::CSIRUse, Conf.AddFSDiscriminator); + NoPGOWarnMismatch = !Conf.PGOWarnMismatch; } else if (Conf.AddFSDiscriminator) { PGOOpt = PGOOptions("", "", "", PGOOptions::NoAction, PGOOptions::NoCSAction, true); diff --git a/llvm/lib/Transforms/Instrumentation/PGOInstrumentation.cpp b/llvm/lib/Transforms/Instrumentation/PGOInstrumentation.cpp --- a/llvm/lib/Transforms/Instrumentation/PGOInstrumentation.cpp +++ b/llvm/lib/Transforms/Instrumentation/PGOInstrumentation.cpp @@ -198,12 +198,14 @@ "warnings about missing profile data for " "functions.")); +namespace llvm { // Command line option to enable/disable the warning about a hash mismatch in // the profile data. -static cl::opt +cl::opt NoPGOWarnMismatch("no-pgo-warn-mismatch", cl::init(false), cl::Hidden, cl::desc("Use this option to turn off/on " "warnings about profile cfg mismatch.")); +} // Command line option to enable/disable the warning about a hash mismatch in // the profile data for Comdat functions, which often turns out to be false