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 @@ -758,14 +758,18 @@ } /// Get the name of a profiling variable for a particular function. -static std::string getVarName(InstrProfIncrementInst *Inc, StringRef Prefix) { +static std::string getVarName(InstrProfIncrementInst *Inc, StringRef Prefix, + bool &Renamed) { StringRef NamePrefix = getInstrProfNameVarPrefix(); StringRef Name = Inc->getName()->getName().substr(NamePrefix.size()); Function *F = Inc->getParent()->getParent(); Module *M = F->getParent(); if (!DoHashBasedCounterSplit || !isIRPGOFlagSet(M) || - !canRenameComdatFunc(*F)) + !canRenameComdatFunc(*F)) { + Renamed = false; return (Prefix + Name).str(); + } + Renamed = true; uint64_t FuncHash = Inc->getHash()->getZExtValue(); SmallVector HashPostfix; if (Name.endswith((Twine(".") + Twine(FuncHash)).toStringRef(HashPostfix))) @@ -878,8 +882,11 @@ // discarded. bool DataReferencedByCode = profDataReferencedByCode(*M); bool NeedComdat = needsComdatForCounter(*Fn, *M); - std::string CntsVarName = getVarName(Inc, getInstrProfCountersVarPrefix()); - std::string DataVarName = getVarName(Inc, getInstrProfDataVarPrefix()); + bool Renamed; + std::string CntsVarName = + getVarName(Inc, getInstrProfCountersVarPrefix(), Renamed); + std::string DataVarName = + getVarName(Inc, getInstrProfDataVarPrefix(), Renamed); auto MaybeSetComdat = [&](GlobalVariable *GV) { bool UseComdat = (NeedComdat || TT.isOSBinFormatELF()); if (UseComdat) { @@ -920,7 +927,7 @@ ArrayType *ValuesTy = ArrayType::get(Type::getInt64Ty(Ctx), NS); auto *ValuesVar = new GlobalVariable( *M, ValuesTy, false, Linkage, Constant::getNullValue(ValuesTy), - getVarName(Inc, getInstrProfValuesVarPrefix())); + getVarName(Inc, getInstrProfValuesVarPrefix(), Renamed)); ValuesVar->setVisibility(Visibility); ValuesVar->setSection( getInstrProfSectionName(IPSK_vals, TT.getObjectFormat())); @@ -955,8 +962,14 @@ // // On COFF, a comdat leader cannot be local so we require DataReferencedByCode // to be false. - if (NS == 0 && (TT.isOSBinFormatELF() || - (!DataReferencedByCode && TT.isOSBinFormatCOFF()))) { + // + // If Fn in a comdat is not renamed, when NS==0, it is still possible for a + // different copy to need value profiling and cause the data variable to be + // referenced by code. Making the data private can cause relocation to + // discarded section linker errors. + if (NS == 0 && !(Fn->GlobalValue::hasComdat() && !Renamed) && + (TT.isOSBinFormatELF() || + (!DataReferencedByCode && TT.isOSBinFormatCOFF()))) { Linkage = GlobalValue::PrivateLinkage; Visibility = GlobalValue::DefaultVisibility; } diff --git a/llvm/test/Transforms/PGOProfile/comdat.ll b/llvm/test/Transforms/PGOProfile/comdat.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Transforms/PGOProfile/comdat.ll @@ -0,0 +1,35 @@ +; There are two main cases where comdats are necessary: +; 1. standard inline functions (weak_odr / linkonce_odr) +; 2. available externally functions (C99 inline / extern template / dllimport) +; Check that we do the right thing for the two object formats with comdats, ELF +; and COFF. +; +; Test comdat functions. Non-comdat functions are tested in linkage.ll. +; RUN: opt < %s -mtriple=x86_64-linux -passes=pgo-instr-gen,instrprof -S | FileCheck %s --check-prefixes=ELF +; RUN: opt < %s -mtriple=x86_64-windows -passes=pgo-instr-gen,instrprof -S | FileCheck %s --check-prefixes=COFF + +;--- main.ll +declare void @llvm.instrprof.increment(i8*, i64, i32, i32) + +$unnamed = comdat any +$weakodr = comdat any + +; ELF: @__profc_unnamed.[[#]] = linkonce_odr hidden global {{.*}} comdat, align 8 +; ELF: @__profd_unnamed.[[#]] = private global {{.*}} comdat($__profc_unnamed.[[#]]), align 8 +; COFF: @__profc_unnamed.[[#]] = linkonce_odr hidden global {{.*}} comdat, align 8 +; COFF: @__profd_unnamed.[[#]] = linkonce_odr hidden global {{.*}} comdat, align 8 +define linkonce_odr void @unnamed() unnamed_addr comdat { + ret void +} + +;; weakodr in a comdat is not renamed. We may have other copies which are non-local +;; (if value profiling is enabled). If we cannot make this profd private, the non-prevailing, +;; when inlined into another function, may reference a discarded profd. + +; ELF: @__profc_weakodr = weak_odr hidden global {{.*}} comdat, align 8 +; ELF: @__profd_weakodr = weak_odr hidden global {{.*}} comdat($__profc_weakodr), align 8 +; COFF: @__profc_weakodr = weak_odr hidden global {{.*}} comdat, align 8 +; COFF: @__profd_weakodr = weak_odr hidden global {{.*}} comdat, align 8 +define weak_odr void @weakodr() comdat { + ret void +}