diff --git a/lld/COFF/LTO.cpp b/lld/COFF/LTO.cpp --- a/lld/COFF/LTO.cpp +++ b/lld/COFF/LTO.cpp @@ -223,7 +223,7 @@ continue; if (config->saveTemps) - saveBuffer(buf[i], ltoObjName); + saveBuffer(objBuf, ltoObjName); ret.push_back(make(MemoryBufferRef(objBuf, ltoObjName))); } diff --git a/llvm/lib/LTO/LTO.cpp b/llvm/lib/LTO/LTO.cpp --- a/llvm/lib/LTO/LTO.cpp +++ b/llvm/lib/LTO/LTO.cpp @@ -34,6 +34,7 @@ #include "llvm/LTO/SummaryBasedOptimizations.h" #include "llvm/Linker/IRMover.h" #include "llvm/Object/IRObjectFile.h" +#include "llvm/ProfileData/InstrProf.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Error.h" #include "llvm/Support/FileSystem.h" @@ -847,6 +848,15 @@ M.setModuleInlineAsm(NewIA + M.getModuleInlineAsm()); } + // Since IRPGO flag symbol (__llvm_profile_raw_version) has external linkage, + // it may not be kept if it's not prevailing in a mixed-LTO mode (both regular + // and thin LTO modules) compilation. This symbol will be used in later PGO + // Instrumentation phase by isIRPGOFlagSet. Keep this symbol will cause a + // duplicate symbol error on ELF. Try set the Module flag beforehand that can + // be evaluated later through enablesValueProfiling in PGO pass. + if (isIRPGOFlagSet(&M)) + M.addModuleFlag(llvm::Module::Warning, "EnableValueProfiling", 1); + assert(MsymI == MsymE); return std::move(Mod); } @@ -1216,6 +1226,15 @@ if (!MOrErr) return MOrErr.takeError(); + // The IRPGO flag var (__llvm_profile_raw_version) may not be imported if + // it's not prevailing and no use in thinLTO module. However this symbol + // will be accessed later in PGO Instrumentation phase by isIRPGOFlagSet. + // Try set the Module flag instead that can be evaluated later through + // enablesValueProfiling in the PGO pass. + Module &M = **MOrErr; + if (isIRPGOFlagSet(&M)) + M.addModuleFlag(llvm::Module::Warning, "EnableValueProfiling", 1); + return thinBackend(Conf, Task, AddStream, **MOrErr, CombinedIndex, ImportList, DefinedGlobals, &ModuleMap); }; diff --git a/llvm/lib/Transforms/Instrumentation/InstrProfiling.cpp b/llvm/lib/Transforms/Instrumentation/InstrProfiling.cpp --- a/llvm/lib/Transforms/Instrumentation/InstrProfiling.cpp +++ b/llvm/lib/Transforms/Instrumentation/InstrProfiling.cpp @@ -757,13 +757,28 @@ CoverageNamesVar->eraseFromParent(); } +static uint64_t getIntModuleFlagOrZero(const Module &M, StringRef Flag) { + auto *MD = dyn_cast_or_null(M.getModuleFlag(Flag)); + if (!MD) + return 0; + + // If the flag is a ConstantAsMetadata, it should be an integer representable + // in 64-bits. + return cast(MD->getValue())->getZExtValue(); +} + +static bool enablesValueProfiling(const Module &M) { + return getIntModuleFlagOrZero(M, "EnableValueProfiling") != 0 || + isIRPGOFlagSet(&M); +} + /// Get the name of a profiling variable for a particular function. static std::string getVarName(InstrProfIncrementInst *Inc, StringRef Prefix) { StringRef NamePrefix = getInstrProfNameVarPrefix(); StringRef Name = Inc->getName()->getName().substr(NamePrefix.size()); Function *F = Inc->getParent()->getParent(); Module *M = F->getParent(); - if (!DoHashBasedCounterSplit || !isIRPGOFlagSet(M) || + if (!DoHashBasedCounterSplit || !enablesValueProfiling(*M) || !canRenameComdatFunc(*F)) return (Prefix + Name).str(); uint64_t FuncHash = Inc->getHash()->getZExtValue(); @@ -773,20 +788,6 @@ return (Prefix + Name + "." + Twine(FuncHash)).str(); } -static uint64_t getIntModuleFlagOrZero(const Module &M, StringRef Flag) { - auto *MD = dyn_cast_or_null(M.getModuleFlag(Flag)); - if (!MD) - return 0; - - // If the flag is a ConstantAsMetadata, it should be an integer representable - // in 64-bits. - return cast(MD->getValue())->getZExtValue(); -} - -static bool enablesValueProfiling(const Module &M) { - return isIRPGOFlagSet(&M) || - getIntModuleFlagOrZero(M, "EnableValueProfiling") != 0; -} // Conservatively returns true if data variables may be referenced by code. static bool profDataReferencedByCode(const Module &M) { diff --git a/llvm/test/Instrumentation/InstrProfiling/comdat.ll b/llvm/test/Instrumentation/InstrProfiling/comdat.ll --- a/llvm/test/Instrumentation/InstrProfiling/comdat.ll +++ b/llvm/test/Instrumentation/InstrProfiling/comdat.ll @@ -10,8 +10,8 @@ ; RUN: cat %t/main.ll %t/enable.ll > %t1.ll ; RUN: opt < %t0.ll -mtriple=x86_64-linux -passes=instrprof -S | FileCheck %s --check-prefixes=ELF ; RUN: opt < %t1.ll -mtriple=x86_64-linux -passes=instrprof -S | FileCheck %s --check-prefixes=ELF -; RUN: opt < %t0.ll -mtriple=x86_64-windows -passes=instrprof -S | FileCheck %s --check-prefixes=COFF -; RUN: opt < %t1.ll -mtriple=x86_64-windows -passes=instrprof -S | FileCheck %s --check-prefixes=COFF +; RUN: opt < %t0.ll -mtriple=x86_64-windows -passes=instrprof -S | FileCheck %s --check-prefixes=COFF0 +; RUN: opt < %t1.ll -mtriple=x86_64-windows -passes=instrprof -S | FileCheck %s --check-prefixes=COFF1 ;--- main.ll declare void @llvm.instrprof.increment(i8*, i64, i32, i32) @@ -38,12 +38,14 @@ ret void } -; ELF: @__profc_foo_extern = linkonce_odr hidden global{{.*}}, section "__llvm_prf_cnts", comdat, align 8 +; ELF0: @__profc_foo_extern = linkonce_odr hidden global{{.*}}, section "__llvm_prf_cnts", comdat, align 8 +; ELF1: @__profc_foo_extern.0 = linkonce_odr hidden global{{.*}}, section "__llvm_prf_cnts", comdat, align 8 ; ELF0: @__profd_foo_extern = private global{{.*}}, section "__llvm_prf_data", comdat($__profc_foo_extern), align 8 -; ELF1: @__profd_foo_extern = linkonce_odr hidden global{{.*}}, section "__llvm_prf_data", comdat($__profc_foo_extern), align 8 -; COFF: @__profc_foo_extern = linkonce_odr hidden global{{.*}}, section ".lprfc$M", comdat, align 8 +; ELF1: @__profd_foo_extern.0 = linkonce_odr hidden global{{.*}}, section "__llvm_prf_data", comdat($__profc_foo_extern), align 8 +; COFF0: @__profc_foo_extern = linkonce_odr hidden global{{.*}}, section ".lprfc$M", comdat, align 8 +; COFF1: @__profc_foo_extern.0 = linkonce_odr hidden global{{.*}}, section ".lprfc$M", comdat, align 8 ; COFF0: @__profd_foo_extern = private global{{.*}}, section ".lprfd$M", comdat($__profc_foo_extern), align 8 -; COFF1: @__profd_foo_extern = linkonce_odr hidden global{{.*}}, section ".lprfd$M", comdat, align 8 +; COFF1: @__profd_foo_extern.0 = linkonce_odr hidden global{{.*}}, section ".lprfd$M", comdat, align 8 define available_externally void @foo_extern() { call void @llvm.instrprof.increment(i8* getelementptr inbounds ([10 x i8], [10 x i8]* @__profn_foo_extern, i32 0, i32 0), i64 0, i32 1, i32 0) ret void diff --git a/llvm/test/Transforms/PGOProfile/lto_cspgo_gen.ll b/llvm/test/Transforms/PGOProfile/lto_cspgo_gen.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Transforms/PGOProfile/lto_cspgo_gen.ll @@ -0,0 +1,32 @@ +; REQUIRES: x86-registered-target + +; RUN: opt -module-summary %s -o %t1.bc +; RUN: llvm-lto2 run -lto-cspgo-profile-file=alloc -lto-cspgo-gen -save-temps -o %t %t1.bc \ +; RUN: -r=%t1.bc,f,pl \ +; RUN: -r=%t1.bc,__llvm_profile_filename,x \ +; RUN: -r=%t1.bc,__llvm_profile_raw_version,x +; RUN: llvm-dis %t.0.0.preopt.bc -o - | FileCheck %s --check-prefix=VALUEPROFILE + +; VALUEPROFILE: {{.*}} !"EnableValueProfiling", i32 1} + +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" + +$__llvm_profile_filename = comdat any +$__llvm_profile_raw_version = comdat any +@__llvm_profile_filename = local_unnamed_addr constant [19 x i8] c"default_%m.profraw\00", comdat +@__llvm_profile_raw_version = local_unnamed_addr constant i64 216172782113783813, comdat + +; Function Attrs: nofree norecurse nosync nounwind readnone uwtable willreturn mustprogress +define dso_local i32 @f() local_unnamed_addr #0 { +entry: + ret i32 1 +} + +attributes #0 = { "target-cpu"="x86-64" } + +!llvm.module.flags = !{!0, !1, !2} + +!0 = !{i32 1, !"wchar_size", i32 4} +!1 = !{i32 7, !"uwtable", i32 1} +!2 = !{i32 1, !"ThinLTO", i32 0} diff --git a/llvm/test/Transforms/PGOProfile/thinlto_cspgo_gen.ll b/llvm/test/Transforms/PGOProfile/thinlto_cspgo_gen.ll --- a/llvm/test/Transforms/PGOProfile/thinlto_cspgo_gen.ll +++ b/llvm/test/Transforms/PGOProfile/thinlto_cspgo_gen.ll @@ -17,6 +17,7 @@ ; CSGEN: @__profc_ ; CSGEN: @__profd_ +; CSGEN: {{.*}} !"EnableValueProfiling", i32 1} source_filename = "cspgo.c" target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"