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/ProfileData/InstrProf.cpp b/llvm/lib/ProfileData/InstrProf.cpp --- a/llvm/lib/ProfileData/InstrProf.cpp +++ b/llvm/lib/ProfileData/InstrProf.cpp @@ -1142,8 +1142,17 @@ const StringRef VarName(INSTR_PROF_QUOTE(INSTR_PROF_RAW_VERSION_VAR)); Type *IntTy64 = Type::getInt64Ty(M.getContext()); uint64_t ProfileVersion = (INSTR_PROF_RAW_VERSION | VARIANT_MASK_IR_PROF); - if (IsCS) + if (IsCS) { ProfileVersion |= VARIANT_MASK_CSIR_PROF; + + // The IRPGO flag var (__llvm_profile_raw_version) has external linkage, + // it may not be kept if it's non-prevailing in a mixed-LTO mode (both + // regular and thin LTO modules) compilation. This symbol may be accessed + // in PGO Instrumentation phase by isIRPGOFlagSet. Simply keep it will cause + // a duplicate symbol error on ELF. Try set the ValueProfiling module flag + // that can be evaluated by enablesValueProfiling instead. + M.addModuleFlag(llvm::Module::Warning, "EnableValueProfiling", 1); + } if (InstrEntryBBEnabled) ProfileVersion |= VARIANT_MASK_INSTR_ENTRY; auto IRLevelVersionVariable = new GlobalVariable( 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,29 @@ +; REQUIRES: x86-registered-target + +; RUN: opt -passes='thinlto-pre-link' --cs-profilegen-file=alloc -cspgo-kind=cspgo-instr-gen-pipeline -module-summary %s -o %t.bc +; RUN: llvm-dis %t.bc -o - | FileCheck %s --check-prefix=VALUEPROFILE + +; RUN: llvm-lto2 run -lto-cspgo-profile-file=alloc -lto-cspgo-gen -save-temps -o %t %t.bc \ +; RUN: -r=%t.bc,f,pl \ +; RUN: -r=%t.bc,__llvm_profile_filename,x \ +; RUN: -r=%t.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" + +; 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}