[SampleFDO] Support enabling -funique-internal-linkage-name.

now -funique-internal-linkage-name flag is available, and we want to flip
it on by default since it is beneficial to have separate sample profiles
for different internal symbols with the same name. As a preparation, we
want to avoid regression caused by the flip.

When we flip -funique-internal-linkage-name on, the profile is collected
from binary built without -funique-internal-linkage-name so it has no uniq
suffix, but the IR in the optimized build contains the suffix. This kind of
mismatch may introduce transient regression.

To avoid such mismatch, we introduce a NameTable section flag indicating
whether there is any name in the profile containing uniq suffix. Compiler
will decide whether to keep uniq suffix during name canonicalization
depending on the NameTable section flag. The flag is only available for
extbinary format. For other formats, by default compiler will keep uniq
suffix so they will only experience transient regression when
-funique-internal-linkage-name is just flipped.

Another type of regression is caused by places where we miss to call
getCanonicalFnName. Those places are fixed.

Differential Revision: https://reviews.llvm.org/D96932
This commit is contained in:
Wei Mi 2021-01-19 09:20:13 -08:00
parent 98cbdba2c1
commit ee35784a90
12 changed files with 271 additions and 42 deletions

View File

@ -177,7 +177,10 @@ enum class SecNameTableFlags : uint32_t {
SecFlagMD5Name = (1 << 0),
// Store MD5 in fixed length instead of ULEB128 so NameTable can be
// accessed like an array.
SecFlagFixedLengthMD5 = (1 << 1)
SecFlagFixedLengthMD5 = (1 << 1),
// Profile contains ".__uniq." suffix name. Compiler shouldn't strip
// the suffix when doing profile matching when seeing the flag.
SecFlagUniqSuffix = (1 << 2)
};
enum class SecProfSummaryFlags : uint32_t {
SecFlagInValid = 0,
@ -728,13 +731,14 @@ public:
/// GUID to \p S. Also traverse the BodySamples to add hot CallTarget's GUID
/// to \p S.
void findInlinedFunctions(DenseSet<GlobalValue::GUID> &S, const Module *M,
const StringMap<Function *> &SymbolMap,
uint64_t Threshold) const {
if (TotalSamples <= Threshold)
return;
auto isDeclaration = [](const Function *F) {
return !F || F->isDeclaration();
};
if (isDeclaration(M->getFunction(getFuncName()))) {
if (isDeclaration(SymbolMap.lookup(getFuncName()))) {
// Add to the import list only when it's defined out of module.
S.insert(getGUID(Name));
}
@ -743,13 +747,13 @@ public:
for (const auto &BS : BodySamples)
for (const auto &TS : BS.second.getCallTargets())
if (TS.getValue() > Threshold) {
const Function *Callee = M->getFunction(getFuncName(TS.getKey()));
const Function *Callee = SymbolMap.lookup(getFuncName(TS.getKey()));
if (isDeclaration(Callee))
S.insert(getGUID(TS.getKey()));
}
for (const auto &CS : CallsiteSamples)
for (const auto &NameFS : CS.second)
NameFS.second.findInlinedFunctions(S, M, Threshold);
NameFS.second.findInlinedFunctions(S, M, SymbolMap, Threshold);
}
/// Set the name of the function.
@ -780,17 +784,31 @@ public:
return getCanonicalFnName(F.getName(), Attr);
}
static StringRef getCanonicalFnName(StringRef FnName, StringRef Attr = "") {
static const char *knownSuffixes[] = { ".llvm.", ".part." };
/// Name suffixes which canonicalization should handle to avoid
/// profile mismatch.
static constexpr const char *LLVMSuffix = ".llvm.";
static constexpr const char *PartSuffix = ".part.";
static constexpr const char *UniqSuffix = ".__uniq.";
static StringRef getCanonicalFnName(StringRef FnName,
StringRef Attr = "selected") {
// Note the sequence of the suffixes in the knownSuffixes array matters.
// If suffix "A" is appended after the suffix "B", "A" should be in front
// of "B" in knownSuffixes.
const char *knownSuffixes[] = {LLVMSuffix, PartSuffix, UniqSuffix};
if (Attr == "" || Attr == "all") {
return FnName.split('.').first;
} else if (Attr == "selected") {
StringRef Cand(FnName);
for (const auto &Suf : knownSuffixes) {
StringRef Suffix(Suf);
// If the profile contains ".__uniq." suffix, don't strip the
// suffix for names in the IR.
if (Suffix == UniqSuffix && FunctionSamples::HasUniqSuffix)
continue;
auto It = Cand.rfind(Suffix);
if (It == StringRef::npos)
return Cand;
continue;
auto Dit = Cand.rfind('.');
if (Dit == It + Suffix.size() - 1)
Cand = Cand.substr(0, It);
@ -861,6 +879,9 @@ public:
/// Whether the profile uses MD5 to represent string.
static bool UseMD5;
/// Whether the profile contains any ".__uniq." suffix in a name.
static bool HasUniqSuffix;
/// GUIDToFuncNameMap saves the mapping from GUID to the symbol name, for
/// all the function symbols defined or declared in current module.
DenseMap<uint64_t, StringRef> *GUIDToFuncNameMap = nullptr;

View File

@ -363,7 +363,11 @@ public:
/// Print the profile for \p FName on stream \p OS.
void dumpFunctionProfile(StringRef FName, raw_ostream &OS = dbgs());
virtual void collectFuncsFrom(const Module &M) {}
/// Collect functions with definitions in Module M. For reader which
/// support loading function profiles on demand, return true when the
/// reader has been given a module. Always return false for reader
/// which doesn't support loading function profiles on demand.
virtual bool collectFuncsFromModule() { return false; }
/// Print all the profiles on stream \p OS.
void dump(raw_ostream &OS = dbgs());
@ -454,9 +458,13 @@ public:
/// Don't read profile without context if the flag is set. This is only meaningful
/// for ExtBinary format.
virtual void setSkipFlatProf(bool Skip) {}
/// Return whether any name in the profile contains ".__uniq." suffix.
virtual bool hasUniqSuffix() { return false; }
SampleProfileReaderItaniumRemapper *getRemapper() { return Remapper.get(); }
void setModule(const Module *Mod) { M = Mod; }
protected:
/// Map every function to its associated profile.
///
@ -496,6 +504,11 @@ protected:
/// \brief The format of sample.
SampleProfileFormat Format = SPF_None;
/// \brief The current module being compiled if SampleProfileReader
/// is used by compiler. If SampleProfileReader is used by other
/// tools which are not compiler, M is usually nullptr.
const Module *M = nullptr;
};
class SampleProfileReaderText : public SampleProfileReader {
@ -656,8 +669,6 @@ protected:
DenseMap<StringRef, uint64_t> FuncOffsetTable;
/// The set containing the functions to use when compiling a module.
DenseSet<StringRef> FuncsToUse;
/// Use all functions from the input profile.
bool UseAllFuncs = true;
/// Use fixed length MD5 instead of ULEB128 encoding so NameTable doesn't
/// need to be read in up front and can be directly accessed using index.
@ -692,8 +703,9 @@ public:
uint64_t getFileSize();
virtual bool dumpSectionInfo(raw_ostream &OS = dbgs()) override;
/// Collect functions with definitions in Module \p M.
void collectFuncsFrom(const Module &M) override;
/// Collect functions with definitions in Module M. Return true if
/// the reader has been given a module.
bool collectFuncsFromModule() override;
/// Return whether names in the profile are all MD5 numbers.
virtual bool useMD5() override { return MD5StringBuf.get(); }
@ -731,8 +743,6 @@ private:
DenseMap<StringRef, uint64_t> FuncOffsetTable;
/// The set containing the functions to use when compiling a module.
DenseSet<StringRef> FuncsToUse;
/// Use all functions from the input profile.
bool UseAllFuncs = true;
virtual std::error_code verifySPMagic(uint64_t Magic) override;
virtual std::error_code readNameTable() override;
/// Read a string indirectly via the name table.
@ -751,8 +761,9 @@ public:
/// Read samples only for functions to use.
std::error_code readImpl() override;
/// Collect functions to be used when compiling Module \p M.
void collectFuncsFrom(const Module &M) override;
/// Collect functions with definitions in Module M. Return true if
/// the reader has been given a module.
bool collectFuncsFromModule() override;
/// Return whether names in the profile are all MD5 numbers.
virtual bool useMD5() override { return true; }

View File

@ -40,7 +40,8 @@ namespace sampleprof {
SampleProfileFormat FunctionSamples::Format;
bool FunctionSamples::ProfileIsProbeBased = false;
bool FunctionSamples::ProfileIsCS = false;
bool FunctionSamples::UseMD5;
bool FunctionSamples::UseMD5 = false;
bool FunctionSamples::HasUniqSuffix = true;
} // namespace sampleprof
} // namespace llvm
@ -262,6 +263,8 @@ void FunctionSamples::findAllNames(DenseSet<StringRef> &NameSet) const {
const FunctionSamples *FunctionSamples::findFunctionSamplesAt(
const LineLocation &Loc, StringRef CalleeName,
SampleProfileReaderItaniumRemapper *Remapper) const {
CalleeName = getCanonicalFnName(CalleeName);
std::string CalleeGUID;
CalleeName = getRepInFormat(CalleeName, UseMD5, CalleeGUID);

View File

@ -584,6 +584,8 @@ std::error_code SampleProfileReaderExtBinaryBase::readOneSection(
bool UseMD5 = hasSecFlag(Entry, SecNameTableFlags::SecFlagMD5Name);
assert((!FixedLengthMD5 || UseMD5) &&
"If FixedLengthMD5 is true, UseMD5 has to be true");
FunctionSamples::HasUniqSuffix =
hasSecFlag(Entry, SecNameTableFlags::SecFlagUniqSuffix);
if (std::error_code EC = readNameTableSec(UseMD5))
return EC;
break;
@ -615,11 +617,13 @@ std::error_code SampleProfileReaderExtBinaryBase::readOneSection(
return sampleprof_error::success;
}
void SampleProfileReaderExtBinaryBase::collectFuncsFrom(const Module &M) {
UseAllFuncs = false;
bool SampleProfileReaderExtBinaryBase::collectFuncsFromModule() {
if (!M)
return false;
FuncsToUse.clear();
for (auto &F : M)
for (auto &F : *M)
FuncsToUse.insert(FunctionSamples::getCanonicalFnName(F));
return true;
}
std::error_code SampleProfileReaderExtBinaryBase::readFuncOffsetTable() {
@ -648,14 +652,24 @@ std::error_code SampleProfileReaderExtBinaryBase::readFuncOffsetTable() {
}
std::error_code SampleProfileReaderExtBinaryBase::readFuncProfiles() {
// Collect functions used by current module if the Reader has been
// given a module.
// collectFuncsFromModule uses FunctionSamples::getCanonicalFnName
// which will query FunctionSamples::HasUniqSuffix, so it has to be
// called after FunctionSamples::HasUniqSuffix is set, i.e. after
// NameTable section is read.
bool LoadFuncsToBeUsed = collectFuncsFromModule();
// When LoadFuncsToBeUsed is false, load all the function profiles.
const uint8_t *Start = Data;
if (UseAllFuncs) {
if (!LoadFuncsToBeUsed) {
while (Data < End) {
if (std::error_code EC = readFuncProfile(Data))
return EC;
}
assert(Data == End && "More data is read than expected");
} else {
// Load function profiles on demand.
if (Remapper) {
for (auto Name : FuncsToUse) {
Remapper->insert(Name);
@ -688,7 +702,6 @@ std::error_code SampleProfileReaderExtBinaryBase::readFuncProfiles() {
}
Data = End;
}
assert((CSProfileCount == 0 || CSProfileCount == Profiles.size()) &&
"Cannot have both context-sensitive and regular profile");
ProfileIsCS = (CSProfileCount > 0);
@ -783,13 +796,18 @@ std::error_code SampleProfileReaderExtBinaryBase::readImpl() {
}
std::error_code SampleProfileReaderCompactBinary::readImpl() {
// Collect functions used by current module if the Reader has been
// given a module.
bool LoadFuncsToBeUsed = collectFuncsFromModule();
std::vector<uint64_t> OffsetsToUse;
if (UseAllFuncs) {
if (!LoadFuncsToBeUsed) {
// load all the function profiles.
for (auto FuncEntry : FuncOffsetTable) {
OffsetsToUse.push_back(FuncEntry.second);
}
}
else {
} else {
// load function profiles on demand.
for (auto Name : FuncsToUse) {
auto GUID = std::to_string(MD5Hash(Name));
auto iter = FuncOffsetTable.find(StringRef(GUID));
@ -1010,6 +1028,8 @@ static std::string getSecFlagsStr(const SecHdrTableEntry &Entry) {
Flags.append("fixlenmd5,");
else if (hasSecFlag(Entry, SecNameTableFlags::SecFlagMD5Name))
Flags.append("md5,");
if (hasSecFlag(Entry, SecNameTableFlags::SecFlagUniqSuffix))
Flags.append("uniq,");
break;
case SecProfSummary:
if (hasSecFlag(Entry, SecProfSummaryFlags::SecFlagPartial))
@ -1117,11 +1137,13 @@ std::error_code SampleProfileReaderCompactBinary::readFuncOffsetTable() {
return sampleprof_error::success;
}
void SampleProfileReaderCompactBinary::collectFuncsFrom(const Module &M) {
UseAllFuncs = false;
bool SampleProfileReaderCompactBinary::collectFuncsFromModule() {
if (!M)
return false;
FuncsToUse.clear();
for (auto &F : M)
for (auto &F : *M)
FuncsToUse.insert(FunctionSamples::getCanonicalFnName(F));
return true;
}
std::error_code SampleProfileReaderBinary::readSummaryEntry(

View File

@ -204,6 +204,17 @@ std::error_code SampleProfileWriterExtBinaryBase::writeNameTableSection(
addName(I.first());
addNames(I.second);
}
// If NameTable contains ".__uniq." suffix, set SecFlagUniqSuffix flag
// so compiler won't strip the suffix during profile matching after
// seeing the flag in the profile.
for (const auto &I : NameTable) {
if (I.first.find(FunctionSamples::UniqSuffix) != StringRef::npos) {
addSectionFlag(SecNameTable, SecNameTableFlags::SecFlagUniqSuffix);
break;
}
}
if (auto EC = writeNameTable())
return EC;
return sampleprof_error::success;

View File

@ -199,6 +199,8 @@ SampleContextTracker::getCalleeContextSamplesFor(const CallBase &Inst,
if (!DIL)
return nullptr;
CalleeName = FunctionSamples::getCanonicalFnName(CalleeName);
// For indirect call, CalleeName will be empty, in which case the context
// profile for callee with largest total samples will be returned.
ContextTrieNode *CalleeContext = getCalleeContextFor(DIL, CalleeName);

View File

@ -608,7 +608,7 @@ SampleProfileLoader::findCalleeFunctionSamples(const CallBase &Inst) const {
StringRef CalleeName;
if (Function *Callee = Inst.getCalledFunction())
CalleeName = FunctionSamples::getCanonicalFnName(*Callee);
CalleeName = Callee->getName();
if (ProfileIsCS)
return ContextTracker->getCalleeContextSamplesFor(Inst, CalleeName);
@ -994,7 +994,7 @@ bool SampleProfileLoader::inlineHotFunctions(
for (const auto *FS : findIndirectCallFunctionSamples(*I, Sum)) {
uint64_t SumOrigin = Sum;
if (LTOPhase == ThinOrFullLTOPhase::ThinLTOPreLink) {
FS->findInlinedFunctions(InlinedGUIDs, F.getParent(),
FS->findInlinedFunctions(InlinedGUIDs, F.getParent(), SymbolMap,
PSI->getOrCompHotCountThreshold());
continue;
}
@ -1015,7 +1015,8 @@ bool SampleProfileLoader::inlineHotFunctions(
}
} else if (LTOPhase == ThinOrFullLTOPhase::ThinLTOPreLink) {
findCalleeFunctionSamples(*I)->findInlinedFunctions(
InlinedGUIDs, F.getParent(), PSI->getOrCompHotCountThreshold());
InlinedGUIDs, F.getParent(), SymbolMap,
PSI->getOrCompHotCountThreshold());
}
}
Changed |= LocalChanged;
@ -1266,7 +1267,7 @@ bool SampleProfileLoader::inlineHotFunctionsWithPriority(
for (const auto *FS : CalleeSamples) {
// TODO: Consider disable pre-lTO ICP for MonoLTO as well
if (LTOPhase == ThinOrFullLTOPhase::ThinLTOPreLink) {
FS->findInlinedFunctions(InlinedGUIDs, F.getParent(),
FS->findInlinedFunctions(InlinedGUIDs, F.getParent(), SymbolMap,
PSI->getOrCompHotCountThreshold());
continue;
}
@ -1313,7 +1314,8 @@ bool SampleProfileLoader::inlineHotFunctionsWithPriority(
}
} else if (LTOPhase == ThinOrFullLTOPhase::ThinLTOPreLink) {
findCalleeFunctionSamples(*I)->findInlinedFunctions(
InlinedGUIDs, F.getParent(), PSI->getOrCompHotCountThreshold());
InlinedGUIDs, F.getParent(), SymbolMap,
PSI->getOrCompHotCountThreshold());
}
}
@ -1679,7 +1681,9 @@ bool SampleProfileLoader::doInitialization(Module &M,
}
Reader = std::move(ReaderOrErr.get());
Reader->setSkipFlatProf(LTOPhase == ThinOrFullLTOPhase::ThinLTOPostLink);
Reader->collectFuncsFrom(M);
// set module before reading the profile so reader may be able to only
// read the function profiles which are used by the current module.
Reader->setModule(&M);
if (std::error_code EC = Reader->read()) {
std::string Msg = "profile reading failed: " + EC.message();
Ctx.diagnose(DiagnosticInfoSampleProfile(Filename, Msg));
@ -1763,12 +1767,11 @@ bool SampleProfileLoader::runOnModule(Module &M, ModuleAnalysisManager *AM,
for (const auto &N_F : M.getValueSymbolTable()) {
StringRef OrigName = N_F.getKey();
Function *F = dyn_cast<Function>(N_F.getValue());
if (F == nullptr)
if (F == nullptr || OrigName.empty())
continue;
SymbolMap[OrigName] = F;
auto pos = OrigName.find('.');
if (pos != StringRef::npos) {
StringRef NewName = OrigName.substr(0, pos);
StringRef NewName = FunctionSamples::getCanonicalFnName(*F);
if (OrigName != NewName && !NewName.empty()) {
auto r = SymbolMap.insert(std::make_pair(NewName, F));
// Failiing to insert means there is already an entry in SymbolMap,
// thus there are multiple functions that are mapped to the same
@ -1781,12 +1784,13 @@ bool SampleProfileLoader::runOnModule(Module &M, ModuleAnalysisManager *AM,
// Insert the remapped names into SymbolMap.
if (Remapper) {
if (auto MapName = Remapper->lookUpNameInProfile(OrigName)) {
if (*MapName == OrigName)
continue;
SymbolMap.insert(std::make_pair(*MapName, F));
if (*MapName != OrigName && !MapName->empty())
SymbolMap.insert(std::make_pair(*MapName, F));
}
}
}
assert(SymbolMap.count(StringRef()) == 0 &&
"No empty StringRef should be added in SymbolMap");
bool retval = false;
for (auto F : buildFunctionOrder(M, CG)) {

View File

@ -0,0 +1,14 @@
_Z3foov:225715:5930
2: 5553
3: 5391
3: _ZL3moov.__uniq.334154460836426447066042049082945760258:5860
1: 5279 _Z10moo_calleev:5279
2: 5279
3: 5000
3: _ZL3noov.__uniq.334154460836426447066042049082945760258:5860
1: 5000
2: 2000 _Z10noo_calleev:2000
_ZL3goov.__uniq.334154460836426447066042049082945760258:5860:5860
1: 5279
1: _ZL3hoov.__uniq.334154460836426447066042049082945760258:5860
1: 5000

View File

@ -0,0 +1,141 @@
; Make sure profile matching is successful if both profile and IR contain
; ".__uniq." suffix, for text format or extbinary format profile.
; Make sure profile matching is successful if IR contains ".__uniq." suffix
; but profile doesn't contain the suffix, for extbinary format profile.
; RUN: opt < %s -passes=sample-profile -sample-profile-file=%S/Inputs/uniqname.suffix.prof -S | FileCheck %s
; RUN: opt < %s -passes=sample-profile -sample-profile-file=%S/Inputs/uniqname.suffix.afdo -S | FileCheck %s
; RUN: opt < %s -passes=sample-profile -sample-profile-file=%S/Inputs/uniqname.nosuffix.afdo -S | 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"
@cond = dso_local global i8 0, align 1
@p = dso_local global void ()* null, align 8
; Check the callsite in inlined function with uniq suffix is annotated with
; profile correctly.
; CHECK-LABEL: @_Z3foov(
; CHECK: call void @_Z10moo_calleev(), {{.*}} !prof ![[PROF_ID1:[0-9]+]]
; CHECK: call void @_Z10noo_calleev(), {{.*}} !prof ![[PROF_ID2:[0-9]+]]
; CHECK: ret void
; Function Attrs: uwtable mustprogress
define dso_local void @_Z3foov() #0 !dbg !7 {
entry:
store void ()* @_ZL3hoov.__uniq.334154460836426447066042049082945760258, void ()** @p, align 8, !dbg !9, !tbaa !10
call void @_ZL3goov.__uniq.334154460836426447066042049082945760258.llvm.4206369970847378271(), !dbg !14
call void @_ZL3moov.__uniq.334154460836426447066042049082945760258(), !dbg !15
ret void, !dbg !16
}
; Function Attrs: uwtable mustprogress
define internal void @_ZL3hoov.__uniq.334154460836426447066042049082945760258() #1 !dbg !17 {
entry:
call void @_Z10hoo_calleev(), !dbg !18
ret void, !dbg !19
}
; Check the indirect call target with uniq suffix is promoted and the inlined
; body is annotated with profile.
; CHECK: define internal void @_ZL3goov.__uniq.334154460836426447066042049082945760258.llvm.4206369970847378271{{.*}} !prof ![[PROF_ID3:[0-9]+]]
; CHECK: icmp eq void ()* {{.*}} @_ZL3hoov.__uniq.334154460836426447066042049082945760258
; CHECK: call void @_Z10hoo_calleev(), {{.*}} !prof ![[PROF_ID4:[0-9]+]]
; Function Attrs: noinline uwtable mustprogress
define internal void @_ZL3goov.__uniq.334154460836426447066042049082945760258.llvm.4206369970847378271() #2 !dbg !20 {
entry:
%0 = load void ()*, void ()** @p, align 8, !dbg !21, !tbaa !10
call void %0(), !dbg !22
ret void, !dbg !23
}
; Function Attrs: uwtable mustprogress
define internal void @_ZL3moov.__uniq.334154460836426447066042049082945760258() #1 !dbg !24 {
entry:
call void @_Z10moo_calleev(), !dbg !25
%0 = load volatile i8, i8* @cond, align 1, !dbg !26, !tbaa !27, !range !29
%tobool.not = icmp eq i8 %0, 0, !dbg !26
br i1 %tobool.not, label %if.end, label %if.then, !dbg !26
if.then: ; preds = %entry
call void @_ZL3noov.__uniq.334154460836426447066042049082945760258(), !dbg !30
br label %if.end, !dbg !30
if.end: ; preds = %if.then, %entry
ret void, !dbg !31
}
declare !dbg !32 dso_local void @_Z10hoo_calleev() #3
declare !dbg !33 dso_local void @_Z10moo_calleev() #3
; Function Attrs: uwtable mustprogress
define internal void @_ZL3noov.__uniq.334154460836426447066042049082945760258() #1 !dbg !34 {
entry:
%0 = load volatile i8, i8* @cond, align 1, !dbg !35, !tbaa !27, !range !29
%tobool.not = icmp eq i8 %0, 0, !dbg !35
br i1 %tobool.not, label %if.end, label %if.then, !dbg !35
if.then: ; preds = %entry
call void @_Z10noo_calleev(), !dbg !36
br label %if.end, !dbg !36
if.end: ; preds = %if.then, %entry
ret void, !dbg !37
}
declare !dbg !38 dso_local void @_Z10noo_calleev() #3
attributes #0 = { uwtable mustprogress "disable-tail-calls"="false" "frame-pointer"="none" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" "unsafe-fp-math"="false" "use-sample-profile" "use-soft-float"="false" }
attributes #1 = { uwtable mustprogress "disable-tail-calls"="false" "frame-pointer"="none" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="true" "sample-profile-suffix-elision-policy"="selected" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" "unsafe-fp-math"="false" "use-sample-profile" "use-soft-float"="false" }
attributes #2 = { noinline uwtable mustprogress "disable-tail-calls"="false" "frame-pointer"="none" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="true" "sample-profile-suffix-elision-policy"="selected" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" "unsafe-fp-math"="false" "use-sample-profile" "use-soft-float"="false" }
attributes #3 = { "disable-tail-calls"="false" "frame-pointer"="none" "less-precise-fpmad"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" "unsafe-fp-math"="false" "use-soft-float"="false" }
; CHECK: ![[PROF_ID1]] = !{!"branch_weights", i32 5931}
; CHECK: ![[PROF_ID2]] = !{!"branch_weights", i32 2000}
; CHECK: ![[PROF_ID3]] = !{!"function_entry_count", i64 5861}
; CHECK: ![[PROF_ID4]] = !{!"branch_weights", i32 5000}
!llvm.dbg.cu = !{!0}
!llvm.module.flags = !{!3, !4, !5}
!llvm.ident = !{!6}
!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !1, producer: "clang version 12.0.0 (https://github.com/llvm/llvm-project.git e42c17446a2e5cbf9eebc752beafadad3fac7f63)", isOptimized: true, runtimeVersion: 0, emissionKind: LineTablesOnly, enums: !2, splitDebugInlining: false, debugInfoForProfiling: true, nameTableKind: None)
!1 = !DIFile(filename: "1.cc", directory: "/usr/local/google/home/wmi/workarea/llvm/build/splitprofile")
!2 = !{}
!3 = !{i32 7, !"Dwarf Version", i32 4}
!4 = !{i32 2, !"Debug Info Version", i32 3}
!5 = !{i32 1, !"wchar_size", i32 4}
!6 = !{!"clang version 12.0.0 (https://github.com/llvm/llvm-project.git e42c17446a2e5cbf9eebc752beafadad3fac7f63)"}
!7 = distinct !DISubprogram(name: "foo", linkageName: "_Z3foov", scope: !1, file: !1, line: 28, type: !8, scopeLine: 28, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !2)
!8 = !DISubroutineType(types: !2)
!9 = !DILocation(line: 29, column: 5, scope: !7)
!10 = !{!11, !11, i64 0}
!11 = !{!"any pointer", !12, i64 0}
!12 = !{!"omnipotent char", !13, i64 0}
!13 = !{!"Simple C++ TBAA"}
!14 = !DILocation(line: 30, column: 3, scope: !7)
!15 = !DILocation(line: 31, column: 3, scope: !7)
!16 = !DILocation(line: 32, column: 3, scope: !7)
!17 = distinct !DISubprogram(name: "hoo", linkageName: "_ZL3hoov.__uniq.334154460836426447066042049082945760258", scope: !1, file: !1, line: 17, type: !8, scopeLine: 17, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagLocalToUnit | DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !2)
!18 = !DILocation(line: 18, column: 3, scope: !17)
!19 = !DILocation(line: 19, column: 1, scope: !17)
!20 = distinct !DISubprogram(name: "goo", linkageName: "_ZL3goov.__uniq.334154460836426447066042049082945760258.llvm.4206369970847378271", scope: !1, file: !1, line: 24, type: !8, scopeLine: 24, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagLocalToUnit | DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !2)
!21 = !DILocation(line: 25, column: 5, scope: !20)
!22 = !DILocation(line: 25, column: 3, scope: !20)
!23 = !DILocation(line: 26, column: 1, scope: !20)
!24 = distinct !DISubprogram(name: "moo", linkageName: "_ZL3moov.__uniq.334154460836426447066042049082945760258", scope: !1, file: !1, line: 11, type: !8, scopeLine: 11, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagLocalToUnit | DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !2)
!25 = !DILocation(line: 12, column: 3, scope: !24)
!26 = !DILocation(line: 13, column: 7, scope: !24)
!27 = !{!28, !28, i64 0}
!28 = !{!"bool", !12, i64 0}
!29 = !{i8 0, i8 2}
!30 = !DILocation(line: 14, column: 5, scope: !24)
!31 = !DILocation(line: 15, column: 1, scope: !24)
!32 = !DISubprogram(name: "hoo_callee", linkageName: "_Z10hoo_calleev", scope: !1, file: !1, line: 3, type: !8, flags: DIFlagPrototyped, spFlags: DISPFlagOptimized, retainedNodes: !2)
!33 = !DISubprogram(name: "moo_callee", linkageName: "_Z10moo_calleev", scope: !1, file: !1, line: 2, type: !8, flags: DIFlagPrototyped, spFlags: DISPFlagOptimized, retainedNodes: !2)
!34 = distinct !DISubprogram(name: "noo", linkageName: "_ZL3noov.__uniq.334154460836426447066042049082945760258", scope: !1, file: !1, line: 6, type: !8, scopeLine: 6, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagLocalToUnit | DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !2)
!35 = !DILocation(line: 7, column: 7, scope: !34)
!36 = !DILocation(line: 8, column: 5, scope: !34)
!37 = !DILocation(line: 9, column: 1, scope: !34)
!38 = !DISubprogram(name: "noo_callee", linkageName: "_Z10noo_calleev", scope: !1, file: !1, line: 1, type: !8, flags: DIFlagPrototyped, spFlags: DISPFlagOptimized, retainedNodes: !2)

View File

@ -60,7 +60,7 @@ struct SampleProfTest : ::testing::Test {
std::string(Profile), Context, std::string(RemapFile));
ASSERT_TRUE(NoError(ReaderOrErr.getError()));
Reader = std::move(ReaderOrErr.get());
Reader->collectFuncsFrom(M);
Reader->setModule(&M);
}
TempFile createRemapFile() {