namespace llvm {
class BlockFrequencyInfo;
+class ProfileSummaryInfo;
/// Direct function to compute a \c ModuleSummaryIndex from a given module.
///
/// that information.
ModuleSummaryIndex buildModuleSummaryIndex(
const Module &M,
- std::function<BlockFrequencyInfo *(const Function &F)> GetBFICallback =
- nullptr);
+ std::function<BlockFrequencyInfo *(const Function &F)> GetBFICallback,
+ ProfileSummaryInfo *PSI);
/// Analysis pass to provide the ModuleSummaryIndex object.
class ModuleSummaryIndexAnalysis
// and combined index cases.
enum GlobalValueSummarySymtabCodes {
// PERMODULE: [valueid, flags, instcount, numrefs, numrefs x valueid,
- // n x (valueid, callsitecount)]
+ // n x (valueid)]
FS_PERMODULE = 1,
// PERMODULE_PROFILE: [valueid, flags, instcount, numrefs,
// numrefs x valueid,
- // n x (valueid, callsitecount, profilecount)]
+ // n x (valueid, hotness)]
FS_PERMODULE_PROFILE = 2,
// PERMODULE_GLOBALVAR_INIT_REFS: [valueid, flags, n x valueid]
FS_PERMODULE_GLOBALVAR_INIT_REFS = 3,
// COMBINED: [valueid, modid, flags, instcount, numrefs, numrefs x valueid,
- // n x (valueid, callsitecount)]
+ // n x (valueid)]
FS_COMBINED = 4,
// COMBINED_PROFILE: [valueid, modid, flags, instcount, numrefs,
// numrefs x valueid,
- // n x (valueid, callsitecount, profilecount)]
+ // n x (valueid, hotness)]
FS_COMBINED_PROFILE = 5,
// COMBINED_GLOBALVAR_INIT_REFS: [valueid, modid, flags, n x valueid]
FS_COMBINED_GLOBALVAR_INIT_REFS = 6,
/// \brief Class to accumulate and hold information about a callee.
struct CalleeInfo {
- /// The static number of callsites calling corresponding function.
- unsigned CallsiteCount;
- /// The cumulative profile count of calls to corresponding function
- /// (if using PGO, otherwise 0).
- uint64_t ProfileCount;
- CalleeInfo() : CallsiteCount(0), ProfileCount(0) {}
- CalleeInfo(unsigned CallsiteCount, uint64_t ProfileCount)
- : CallsiteCount(CallsiteCount), ProfileCount(ProfileCount) {}
- CalleeInfo &operator+=(uint64_t RHSProfileCount) {
- CallsiteCount++;
- ProfileCount += RHSProfileCount;
- return *this;
+ enum class HotnessType : uint8_t { Unknown = 0, Cold = 1, None = 2, Hot = 3 };
+ HotnessType Hotness = HotnessType::Unknown;
+
+ CalleeInfo() = default;
+ explicit CalleeInfo(HotnessType Hotness) : Hotness(Hotness) {}
+
+ void updateHotness(const HotnessType OtherHotness) {
+ Hotness = std::max(Hotness, OtherHotness);
}
};
#include "llvm/Analysis/BranchProbabilityInfo.h"
#include "llvm/Analysis/IndirectCallPromotionAnalysis.h"
#include "llvm/Analysis/LoopInfo.h"
+#include "llvm/Analysis/ProfileSummaryInfo.h"
#include "llvm/IR/CallSite.h"
#include "llvm/IR/Dominators.h"
#include "llvm/IR/InstIterator.h"
}
}
+static CalleeInfo::HotnessType getHotness(uint64_t ProfileCount,
+ ProfileSummaryInfo *PSI) {
+ if (!PSI)
+ return CalleeInfo::HotnessType::Unknown;
+ if (PSI->isHotCount(ProfileCount))
+ return CalleeInfo::HotnessType::Hot;
+ if (PSI->isColdCount(ProfileCount))
+ return CalleeInfo::HotnessType::Cold;
+ return CalleeInfo::HotnessType::None;
+}
+
static void computeFunctionSummary(ModuleSummaryIndex &Index, const Module &M,
- const Function &F, BlockFrequencyInfo *BFI) {
+ const Function &F, BlockFrequencyInfo *BFI,
+ ProfileSummaryInfo *PSI) {
// Summary not currently supported for anonymous functions, they must
// be renamed.
if (!F.hasName())
auto ScaledCount = BFI ? BFI->getBlockProfileCount(&BB) : None;
auto *CalleeId =
M.getValueSymbolTable().lookup(CalledFunction->getName());
- CallGraphEdges[CalleeId] += (ScaledCount ? ScaledCount.getValue() : 0);
+
+ auto Hotness = ScaledCount ? getHotness(ScaledCount.getValue(), PSI)
+ : CalleeInfo::HotnessType::Unknown;
+ CallGraphEdges[CalleeId].updateHotness(Hotness);
} else {
const auto *CI = dyn_cast<CallInst>(&I);
// Skip inline assembly calls.
ICallAnalysis.getPromotionCandidatesForInstruction(
&I, NumVals, TotalCount, NumCandidates);
for (auto &Candidate : CandidateProfileData)
- IndirectCallEdges[Candidate.Value] += Candidate.Count;
+ IndirectCallEdges[Candidate.Value].updateHotness(
+ getHotness(Candidate.Count, PSI));
}
}
ModuleSummaryIndex llvm::buildModuleSummaryIndex(
const Module &M,
- std::function<BlockFrequencyInfo *(const Function &F)> GetBFICallback) {
+ std::function<BlockFrequencyInfo *(const Function &F)> GetBFICallback,
+ ProfileSummaryInfo *PSI) {
ModuleSummaryIndex Index;
// Check if the module can be promoted, otherwise just disable importing from
// it by not emitting any summary.
BFI = BFIPtr.get();
}
- computeFunctionSummary(Index, M, F, BFI);
+ computeFunctionSummary(Index, M, F, BFI, PSI);
}
// Compute summaries for all variables defined in module, and save in the
ModuleSummaryIndex
ModuleSummaryIndexAnalysis::run(Module &M, ModuleAnalysisManager &AM) {
+ ProfileSummaryInfo &PSI = AM.getResult<ProfileSummaryAnalysis>(M);
auto &FAM = AM.getResult<FunctionAnalysisManagerModuleProxy>(M).getManager();
- return buildModuleSummaryIndex(M, [&FAM](const Function &F) {
- return &FAM.getResult<BlockFrequencyAnalysis>(*const_cast<Function *>(&F));
- });
+ return buildModuleSummaryIndex(
+ M,
+ [&FAM](const Function &F) {
+ return &FAM.getResult<BlockFrequencyAnalysis>(
+ *const_cast<Function *>(&F));
+ },
+ &PSI);
}
char ModuleSummaryIndexWrapperPass::ID = 0;
}
bool ModuleSummaryIndexWrapperPass::runOnModule(Module &M) {
- Index = buildModuleSummaryIndex(M, [this](const Function &F) {
- return &(this->getAnalysis<BlockFrequencyInfoWrapperPass>(
- *const_cast<Function *>(&F))
- .getBFI());
- });
+ auto &PSI = *getAnalysis<ProfileSummaryInfoWrapperPass>().getPSI(M);
+ Index = buildModuleSummaryIndex(
+ M,
+ [this](const Function &F) {
+ return &(this->getAnalysis<BlockFrequencyInfoWrapperPass>(
+ *const_cast<Function *>(&F))
+ .getBFI());
+ },
+ &PSI);
return false;
}
void ModuleSummaryIndexWrapperPass::getAnalysisUsage(AnalysisUsage &AU) const {
AU.setPreservesAll();
AU.addRequired<BlockFrequencyInfoWrapperPass>();
+ AU.addRequired<ProfileSummaryInfoWrapperPass>();
}
bool llvm::moduleCanBeRenamedForThinLTO(const Module &M) {
std::pair<GlobalValue::GUID, GlobalValue::GUID>
getGUIDFromValueId(unsigned ValueId);
+ std::pair<GlobalValue::GUID, CalleeInfo::HotnessType>
+ readCallGraphEdge(const SmallVector<uint64_t, 64> &Record, unsigned int &I,
+ bool IsOldProfileFormat, bool HasProfile);
};
} // end anonymous namespace
return error("Invalid Summary Block: version expected");
}
const uint64_t Version = Record[0];
- if (Version != 1)
- return error("Invalid summary version " + Twine(Version) + ", 1 expected");
+ const bool IsOldProfileFormat = Version == 1;
+ if (!IsOldProfileFormat && Version != 2)
+ return error("Invalid summary version " + Twine(Version) +
+ ", 1 or 2 expected");
Record.clear();
// Keep around the last seen summary to be used when we see an optional
default: // Default behavior: ignore.
break;
// FS_PERMODULE: [valueid, flags, instcount, numrefs, numrefs x valueid,
- // n x (valueid, callsitecount)]
+ // n x (valueid)]
// FS_PERMODULE_PROFILE: [valueid, flags, instcount, numrefs,
// numrefs x valueid,
- // n x (valueid, callsitecount, profilecount)]
+ // n x (valueid, hotness)]
case bitc::FS_PERMODULE:
case bitc::FS_PERMODULE_PROFILE: {
unsigned ValueID = Record[0];
bool HasProfile = (BitCode == bitc::FS_PERMODULE_PROFILE);
for (unsigned I = CallGraphEdgeStartIndex, E = Record.size(); I != E;
++I) {
- unsigned CalleeValueId = Record[I];
- unsigned CallsiteCount = Record[++I];
- uint64_t ProfileCount = HasProfile ? Record[++I] : 0;
- GlobalValue::GUID CalleeGUID = getGUIDFromValueId(CalleeValueId).first;
- FS->addCallGraphEdge(CalleeGUID,
- CalleeInfo(CallsiteCount, ProfileCount));
+ CalleeInfo::HotnessType Hotness;
+ GlobalValue::GUID CalleeGUID;
+ std::tie(CalleeGUID, Hotness) =
+ readCallGraphEdge(Record, I, IsOldProfileFormat, HasProfile);
+ FS->addCallGraphEdge(CalleeGUID, CalleeInfo(Hotness));
}
auto GUID = getGUIDFromValueId(ValueID);
FS->setOriginalName(GUID.second);
break;
}
// FS_COMBINED: [valueid, modid, flags, instcount, numrefs,
- // numrefs x valueid, n x (valueid, callsitecount)]
+ // numrefs x valueid, n x (valueid)]
// FS_COMBINED_PROFILE: [valueid, modid, flags, instcount, numrefs,
- // numrefs x valueid,
- // n x (valueid, callsitecount, profilecount)]
+ // numrefs x valueid, n x (valueid, hotness)]
case bitc::FS_COMBINED:
case bitc::FS_COMBINED_PROFILE: {
unsigned ValueID = Record[0];
bool HasProfile = (BitCode == bitc::FS_COMBINED_PROFILE);
for (unsigned I = CallGraphEdgeStartIndex, E = Record.size(); I != E;
++I) {
- unsigned CalleeValueId = Record[I];
- unsigned CallsiteCount = Record[++I];
- uint64_t ProfileCount = HasProfile ? Record[++I] : 0;
- GlobalValue::GUID CalleeGUID = getGUIDFromValueId(CalleeValueId).first;
- FS->addCallGraphEdge(CalleeGUID,
- CalleeInfo(CallsiteCount, ProfileCount));
+ CalleeInfo::HotnessType Hotness;
+ GlobalValue::GUID CalleeGUID;
+ std::tie(CalleeGUID, Hotness) =
+ readCallGraphEdge(Record, I, IsOldProfileFormat, HasProfile);
+ FS->addCallGraphEdge(CalleeGUID, CalleeInfo(Hotness));
}
GlobalValue::GUID GUID = getGUIDFromValueId(ValueID).first;
TheIndex->addGlobalValueSummary(GUID, std::move(FS));
llvm_unreachable("Exit infinite loop");
}
+std::pair<GlobalValue::GUID, CalleeInfo::HotnessType>
+ModuleSummaryIndexBitcodeReader::readCallGraphEdge(
+ const SmallVector<uint64_t, 64> &Record, unsigned int &I,
+ const bool IsOldProfileFormat, const bool HasProfile) {
+
+ auto Hotness = CalleeInfo::HotnessType::Unknown;
+ unsigned CalleeValueId = Record[I];
+ GlobalValue::GUID CalleeGUID = getGUIDFromValueId(CalleeValueId).first;
+ if (IsOldProfileFormat) {
+ I += 1; // Skip old callsitecount field
+ if (HasProfile)
+ I += 1; // Skip old profilecount field
+ } else if (HasProfile)
+ Hotness = static_cast<CalleeInfo::HotnessType>(Record[++I]);
+ return {CalleeGUID, Hotness};
+}
+
// Parse the module string table block into the Index.
// This populates the ModulePathStringTable map in the index.
std::error_code ModuleSummaryIndexBitcodeReader::parseModuleStringTable() {
bool HasProfileData = F.getEntryCount().hasValue();
for (auto &ECI : Calls) {
NameVals.push_back(getValueId(ECI.first));
- assert(ECI.second.CallsiteCount > 0 && "Expected at least one callsite");
- NameVals.push_back(ECI.second.CallsiteCount);
if (HasProfileData)
- NameVals.push_back(ECI.second.ProfileCount);
+ NameVals.push_back(static_cast<uint8_t>(ECI.second.Hotness));
}
unsigned FSAbbrev = (HasProfileData ? FSCallsProfileAbbrev : FSCallsAbbrev);
// Current version for the summary.
// This is bumped whenever we introduce changes in the way some record are
// interpreted, like flags for instance.
-static const uint64_t INDEX_VERSION = 1;
+static const uint64_t INDEX_VERSION = 2;
/// Emit the per-module summary section alongside the rest of
/// the module's bitcode.
Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // flags
Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // instcount
Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 4)); // numrefs
- // numrefs x valueid, n x (valueid, callsitecount)
+ // numrefs x valueid, n x (valueid)
Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Array));
Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8));
unsigned FSCallsAbbrev = Stream.EmitAbbrev(Abbv);
Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // flags
Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // instcount
Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 4)); // numrefs
- // numrefs x valueid, n x (valueid, callsitecount, profilecount)
+ // numrefs x valueid, n x (valueid, hotness)
Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Array));
Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8));
unsigned FSCallsProfileAbbrev = Stream.EmitAbbrev(Abbv);
Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // flags
Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // instcount
Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 4)); // numrefs
- // numrefs x valueid, n x (valueid, callsitecount)
+ // numrefs x valueid, n x (valueid)
Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Array));
Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8));
unsigned FSCallsAbbrev = Stream.EmitAbbrev(Abbv);
Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // flags
Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // instcount
Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 4)); // numrefs
- // numrefs x valueid, n x (valueid, callsitecount, profilecount)
+ // numrefs x valueid, n x (valueid, hotness)
Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Array));
Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8));
unsigned FSCallsProfileAbbrev = Stream.EmitAbbrev(Abbv);
bool HasProfileData = false;
for (auto &EI : FS->calls()) {
- HasProfileData |= EI.second.ProfileCount != 0;
+ HasProfileData |= EI.second.Hotness != CalleeInfo::HotnessType::Unknown;
if (HasProfileData)
break;
}
if (!hasValueId(EI.first.getGUID()))
continue;
NameVals.push_back(getValueId(EI.first.getGUID()));
- assert(EI.second.CallsiteCount > 0 && "Expected at least one callsite");
- NameVals.push_back(EI.second.CallsiteCount);
if (HasProfileData)
- NameVals.push_back(EI.second.ProfileCount);
+ NameVals.push_back(static_cast<uint8_t>(EI.second.Hotness));
}
unsigned FSAbbrev = (HasProfileData ? FSCallsProfileAbbrev : FSCallsAbbrev);
#include "llvm/ADT/Statistic.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Analysis/ModuleSummaryAnalysis.h"
+#include "llvm/Analysis/ProfileSummaryInfo.h"
#include "llvm/Analysis/TargetLibraryInfo.h"
#include "llvm/Analysis/TargetTransformInfo.h"
#include "llvm/Bitcode/BitcodeWriterPass.h"
SmallVector<char, 128> OutputBuffer;
{
raw_svector_ostream OS(OutputBuffer);
- auto Index = buildModuleSummaryIndex(TheModule);
+ ProfileSummaryInfo PSI(TheModule);
+ auto Index = buildModuleSummaryIndex(TheModule, nullptr, nullptr);
WriteBitcodeToFile(&TheModule, OS, true, &Index);
}
return make_unique<ObjectMemoryBuffer>(std::move(OutputBuffer));
cl::desc("As we import functions, multiply the "
"`import-instr-limit` threshold by this factor "
"before processing newly imported functions"));
+static cl::opt<float> ImportHotMultiplier(
+ "import-hot-multiplier", cl::init(3.0), cl::Hidden, cl::value_desc("x"),
+ cl::ZeroOrMore, cl::desc("Multiply the `import-instr-limit` threshold for "
+ "hot callsites"));
static cl::opt<bool> PrintImports("print-imports", cl::init(false), cl::Hidden,
cl::desc("Print imported functions"));
/// exported from their source module.
static void computeImportForFunction(
const FunctionSummary &Summary, const ModuleSummaryIndex &Index,
- unsigned Threshold, const GVSummaryMapTy &DefinedGVSummaries,
+ const unsigned Threshold, const GVSummaryMapTy &DefinedGVSummaries,
SmallVectorImpl<EdgeInfo> &Worklist,
FunctionImporter::ImportMapTy &ImportList,
StringMap<FunctionImporter::ExportSetTy> *ExportLists = nullptr) {
continue;
}
- auto *CalleeSummary = selectCallee(GUID, Threshold, Index);
+ // FIXME: Also lower the threshold for cold callsites.
+ const auto NewThreshold =
+ Edge.second.Hotness == CalleeInfo::HotnessType::Hot
+ ? Threshold * ImportHotMultiplier
+ : Threshold;
+ auto *CalleeSummary = selectCallee(GUID, NewThreshold, Index);
if (!CalleeSummary) {
DEBUG(dbgs() << "ignored! No qualifying callee with summary found.\n");
continue;
} else
ResolvedCalleeSummary = cast<FunctionSummary>(CalleeSummary);
- assert(ResolvedCalleeSummary->instCount() <= Threshold &&
+ assert(ResolvedCalleeSummary->instCount() <= NewThreshold &&
"selectCallee() didn't honor the threshold");
auto ExportModulePath = ResolvedCalleeSummary->modulePath();
--- /dev/null
+; ModuleID = 'thinlto-function-summary-callgraph-profile-summary2.ll'
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+
+define void @hot1() #1 {
+ ret void
+}
+define void @hot2() #1 {
+ ret void
+}
+define void @hot3() #1 {
+ ret void
+}
+define void @cold() #1 {
+ ret void
+}
+define void @none1() #1 {
+ ret void
+}
+define void @none2() #1 {
+ ret void
+}
+define void @none3() #1 {
+ ret void
+}
+
; RUN: opt -module-summary %s -o - | llvm-bcanalyzer -dump | FileCheck %s
; CHECK: <GLOBALVAL_SUMMARY_BLOCK
-; CHECK: <VERSION op0=1/>
+; CHECK: <VERSION op0=2/>
; CHECK-NEXT: <VERSION
; See if the call to func is registered, using the expected callsite count
; and value id matching the subsequent value symbol table.
-; CHECK-NEXT: <PERMODULE {{.*}} op4=[[FUNCID:[0-9]+]] op5=1/>
+; CHECK-NEXT: <PERMODULE {{.*}} op4=[[FUNCID:[0-9]+]]/>
; CHECK-NEXT: </GLOBALVAL_SUMMARY_BLOCK>
; CHECK-NEXT: <VALUE_SYMTAB
; CHECK-NEXT: <FNENTRY {{.*}} record string = 'main'
; COMBINED-NEXT: <VERSION
; See if the call to analias is registered, using the expected callsite count
; and value id matching the subsequent value symbol table.
-; COMBINED-NEXT: <COMBINED {{.*}} op5=[[ALIASID:[0-9]+]] op6=1/>
+; COMBINED-NEXT: <COMBINED {{.*}} op5=[[ALIASID:[0-9]+]]/>
; Followed by the alias and aliasee
; COMBINED-NEXT: <COMBINED {{.*}}
; COMBINED-NEXT: <COMBINED_ALIAS {{.*}} op3=[[ALIASEEID:[0-9]+]]
; Test to check the callgraph in summary when there is PGO
; RUN: opt -module-summary %s -o %t.o
; RUN: llvm-bcanalyzer -dump %t.o | FileCheck %s
+
; RUN: opt -module-summary %p/Inputs/thinlto-function-summary-callgraph.ll -o %t2.o
; RUN: llvm-lto -thinlto -o %t3 %t.o %t2.o
; RUN: llvm-bcanalyzer -dump %t3.thinlto.bc | FileCheck %s --check-prefix=COMBINED
+; Check parsing for old summary versions generated from this file.
+; RUN: llvm-lto -thinlto-index-stats %p/Inputs/thinlto-function-summary-callgraph-pgo.1.bc | FileCheck %s --check-prefix=OLD
+; RUN: llvm-lto -thinlto-index-stats %p/Inputs/thinlto-function-summary-callgraph-pgo-combined.1.bc | FileCheck %s --check-prefix=OLD-COMBINED
+
; CHECK: <GLOBALVAL_SUMMARY_BLOCK
; CHECK-NEXT: <VERSION
; See if the call to func is registered, using the expected callsite count
-; and profile count, with value id matching the subsequent value symbol table.
-; CHECK-NEXT: <PERMODULE_PROFILE {{.*}} op4=[[FUNCID:[0-9]+]] op5=1 op6=1/>
+; and hotness type, with value id matching the subsequent value symbol table.
+; CHECK-NEXT: <PERMODULE_PROFILE {{.*}} op4=[[FUNCID:[0-9]+]] op5=2/>
; CHECK-NEXT: </GLOBALVAL_SUMMARY_BLOCK>
; CHECK-NEXT: <VALUE_SYMTAB
; CHECK-NEXT: <FNENTRY {{.*}} record string = 'main'
; COMBINED-NEXT: <VERSION
; COMBINED-NEXT: <COMBINED
; See if the call to func is registered, using the expected callsite count
-; and profile count, with value id matching the subsequent value symbol table.
-; COMBINED-NEXT: <COMBINED_PROFILE {{.*}} op5=[[FUNCID:[0-9]+]] op6=1 op7=1/>
+; and hotness type, with value id matching the subsequent value symbol table.
+; op6=2 which is hotnessType::None.
+; COMBINED-NEXT: <COMBINED_PROFILE {{.*}} op5=[[FUNCID:[0-9]+]] op6=2/>
; COMBINED-NEXT: </GLOBALVAL_SUMMARY_BLOCK>
; COMBINED-NEXT: <VALUE_SYMTAB
; Entry for function func should have entry with value id FUNCID
declare void @func(...) #1
!2 = !{!"function_entry_count", i64 1}
+
+; OLD: Index {{.*}} contains 1 nodes (1 functions, 0 alias, 0 globals) and 1 edges (0 refs and 1 calls)
+; OLD-COMBINED: Index {{.*}} contains 2 nodes (2 functions, 0 alias, 0 globals) and 1 edges (0 refs and 1 calls)
--- /dev/null
+; Test to check the callgraph in summary when there is PGO
+; RUN: opt -module-summary %s -o %t.o
+; RUN: llvm-bcanalyzer -dump %t.o | FileCheck %s
+; RUN: opt -module-summary %p/Inputs/thinlto-function-summary-callgraph-profile-summary.ll -o %t2.o
+; RUN: llvm-lto -thinlto -o %t3 %t.o %t2.o
+; RUN: llvm-bcanalyzer -dump %t3.thinlto.bc | FileCheck %s --check-prefix=COMBINED
+
+
+; CHECK-LABEL: <GLOBALVAL_SUMMARY_BLOCK
+; CHECK-NEXT: <VERSION
+; See if the call to func is registered, using the expected callsite count
+; and profile count, with value id matching the subsequent value symbol table.
+; CHECK-NEXT: <PERMODULE_PROFILE {{.*}} op4=[[HOT1:.*]] op5=3 op6=[[HOT2:.*]] op7=3 op8=[[HOT3:.*]] op9=3 op10=[[COLD:.*]] op11=1 op12=[[NONE1:.*]] op13=2 op14=[[NONE2:.*]] op15=2 op16=[[NONE3:.*]] op17=2/>
+; CHECK-NEXT: </GLOBALVAL_SUMMARY_BLOCK>
+; CHECK-LABEL: <VALUE_SYMTAB
+; CHECK-NEXT: <FNENTRY {{.*}} record string = 'hot_function
+; CHECK-DAG: <ENTRY abbrevid=6 op0=[[NONE1]] {{.*}} record string = 'none1'
+; CHECK-DAG: <ENTRY abbrevid=6 op0=[[COLD]] {{.*}} record string = 'cold'
+; CHECK-DAG: <ENTRY abbrevid=6 op0=[[NONE2]] {{.*}} record string = 'none2'
+; CHECK-DAG: <ENTRY abbrevid=6 op0=[[NONE3]] {{.*}} record string = 'none3'
+; CHECK-DAG: <ENTRY abbrevid=6 op0=[[HOT1]] {{.*}} record string = 'hot1'
+; CHECK-DAG: <ENTRY abbrevid=6 op0=[[HOT2]] {{.*}} record string = 'hot2'
+; CHECK-DAG: <ENTRY abbrevid=6 op0=[[HOT3]] {{.*}} record string = 'hot3'
+; CHECK-LABEL: </VALUE_SYMTAB>
+
+; COMBINED: <GLOBALVAL_SUMMARY_BLOCK
+; COMBINED-NEXT: <VERSION
+; COMBINED-NEXT: <COMBINED abbrevid=
+; COMBINED-NEXT: <COMBINED abbrevid=
+; COMBINED-NEXT: <COMBINED abbrevid=
+; COMBINED-NEXT: <COMBINED abbrevid=
+; COMBINED-NEXT: <COMBINED abbrevid=
+; COMBINED-NEXT: <COMBINED abbrevid=
+; COMBINED-NEXT: <COMBINED_PROFILE {{.*}} op5=[[HOT1:.*]] op6=3 op7=[[HOT2:.*]] op8=3 op9=[[HOT3:.*]] op10=3 op11=[[COLD:.*]] op12=1 op13=[[NONE1:.*]] op14=2 op15=[[NONE2:.*]] op16=2 op17=[[NONE3:.*]] op18=2/>
+; COMBINED_NEXT: <COMBINED abbrevid=
+; COMBINED_NEXT: </GLOBALVAL_SUMMARY_BLOCK>
+
+
+; ModuleID = 'thinlto-function-summary-callgraph.ll'
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+; This function have high profile count, so entry block is hot.
+define void @hot_function(i1 %a, i1 %a2) !prof !20 {
+entry:
+ call void @hot1()
+ br i1 %a, label %Cold, label %Hot, !prof !41
+Cold: ; 1/1000 goes here
+ call void @cold()
+ call void @hot2()
+ call void @none1()
+ br label %exit
+Hot: ; 999/1000 goes here
+ call void @hot2()
+ call void @hot3()
+ br i1 %a2, label %None1, label %None2, !prof !42
+None1: ; half goes here
+ call void @none1()
+ call void @none2()
+ br label %exit
+None2: ; half goes here
+ call void @none3()
+ br label %exit
+exit:
+ ret void
+}
+
+declare void @hot1() #1
+declare void @hot2() #1
+declare void @hot3() #1
+declare void @cold() #1
+declare void @none1() #1
+declare void @none2() #1
+declare void @none3() #1
+
+
+!41 = !{!"branch_weights", i32 1, i32 1000}
+!42 = !{!"branch_weights", i32 1, i32 1}
+
+
+
+!llvm.module.flags = !{!1}
+!20 = !{!"function_entry_count", i64 110}
+
+!1 = !{i32 1, !"ProfileSummary", !2}
+!2 = !{!3, !4, !5, !6, !7, !8, !9, !10}
+!3 = !{!"ProfileFormat", !"InstrProf"}
+!4 = !{!"TotalCount", i64 10000}
+!5 = !{!"MaxCount", i64 10}
+!6 = !{!"MaxInternalCount", i64 1}
+!7 = !{!"MaxFunctionCount", i64 1000}
+!8 = !{!"NumCounts", i64 3}
+!9 = !{!"NumFunctions", i64 3}
+!10 = !{!"DetailedSummary", !11}
+!11 = !{!12, !13, !14}
+!12 = !{i32 10000, i64 100, i32 1}
+!13 = !{i32 999000, i64 100, i32 1}
+!14 = !{i32 999999, i64 1, i32 2}
; Test to check the callgraph in summary
; RUN: opt -module-summary %s -o %t.o
; RUN: llvm-bcanalyzer -dump %t.o | FileCheck %s
+
; RUN: opt -module-summary %p/Inputs/thinlto-function-summary-callgraph.ll -o %t2.o
; RUN: llvm-lto -thinlto -o %t3 %t.o %t2.o
; RUN: llvm-bcanalyzer -dump %t3.thinlto.bc | FileCheck %s --check-prefix=COMBINED
+; Check parsing for old summary versions generated from this file.
+; RUN: llvm-lto -thinlto-index-stats %p/Inputs/thinlto-function-summary-callgraph.1.bc | FileCheck %s --check-prefix=OLD
+; RUN: llvm-lto -thinlto-index-stats %p/Inputs/thinlto-function-summary-callgraph-combined.1.bc | FileCheck %s --check-prefix=OLD-COMBINED
+
; CHECK: <GLOBALVAL_SUMMARY_BLOCK
; CHECK-NEXT: <VERSION
; See if the call to func is registered, using the expected callsite count
; and value id matching the subsequent value symbol table.
-; CHECK-NEXT: <PERMODULE {{.*}} op4=[[FUNCID:[0-9]+]] op5=1/>
+; CHECK-NEXT: <PERMODULE {{.*}} op4=[[FUNCID:[0-9]+]]/>
; CHECK-NEXT: </GLOBALVAL_SUMMARY_BLOCK>
; CHECK-NEXT: <VALUE_SYMTAB
; CHECK-NEXT: <FNENTRY {{.*}} record string = 'main'
; COMBINED-NEXT: <COMBINED
; See if the call to func is registered, using the expected callsite count
; and value id matching the subsequent value symbol table.
-; COMBINED-NEXT: <COMBINED {{.*}} op5=[[FUNCID:[0-9]+]] op6=1/>
+; COMBINED-NEXT: <COMBINED {{.*}} op5=[[FUNCID:[0-9]+]]/>
; COMBINED-NEXT: </GLOBALVAL_SUMMARY_BLOCK>
; COMBINED-NEXT: <VALUE_SYMTAB
; Entry for function func should have entry with value id FUNCID
}
declare void @func(...) #1
+
+; OLD: Index {{.*}} contains 1 nodes (1 functions, 0 alias, 0 globals) and 1 edges (0 refs and 1 calls)
+; OLD-COMBINED: Index {{.*}} contains 2 nodes (2 functions, 0 alias, 0 globals) and 1 edges (0 refs and 1 calls)
\ No newline at end of file
; llvm.ctpop.i8.
; CHECK: <GLOBALVAL_SUMMARY_BLOCK
; Function main contains call to func, as well as address reference to func:
-; CHECK-DAG: <PERMODULE {{.*}} op0=[[MAINID:[0-9]+]] op1=0 {{.*}} op3=1 op4=[[FUNCID:[0-9]+]] op5=[[FUNCID]] op6=1/>
+; CHECK-DAG: <PERMODULE {{.*}} op0=[[MAINID:[0-9]+]] op1=0 {{.*}} op3=1 op4=[[FUNCID:[0-9]+]] op5=[[FUNCID]]/>
; Function W contains a call to func3 as well as a reference to globalvar:
-; CHECK-DAG: <PERMODULE {{.*}} op0=[[WID:[0-9]+]] op1=5 {{.*}} op3=1 op4=[[GLOBALVARID:[0-9]+]] op5=[[FUNC3ID:[0-9]+]] op6=1/>
+; CHECK-DAG: <PERMODULE {{.*}} op0=[[WID:[0-9]+]] op1=5 {{.*}} op3=1 op4=[[GLOBALVARID:[0-9]+]] op5=[[FUNC3ID:[0-9]+]]/>
; Function X contains call to foo, as well as address reference to foo
; which is in the same instruction as the call:
-; CHECK-DAG: <PERMODULE {{.*}} op0=[[XID:[0-9]+]] op1=1 {{.*}} op3=1 op4=[[FOOID:[0-9]+]] op5=[[FOOID]] op6=1/>
+; CHECK-DAG: <PERMODULE {{.*}} op0=[[XID:[0-9]+]] op1=1 {{.*}} op3=1 op4=[[FOOID:[0-9]+]] op5=[[FOOID]]/>
; Function Y contains call to func2, and ensures we don't incorrectly add
; a reference to it when reached while earlier analyzing the phi using its
; return value:
-; CHECK-DAG: <PERMODULE {{.*}} op0=[[YID:[0-9]+]] op1=8 {{.*}} op3=0 op4=[[FUNC2ID:[0-9]+]] op5=1/>
+; CHECK-DAG: <PERMODULE {{.*}} op0=[[YID:[0-9]+]] op1=8 {{.*}} op3=0 op4=[[FUNC2ID:[0-9]+]]/>
; Function Z contains call to func2, and ensures we don't incorrectly add
; a reference to it when reached while analyzing subsequent use of its return
; value:
-; CHECK-DAG: <PERMODULE {{.*}} op0=[[ZID:[0-9]+]] op1=3 {{.*}} op3=0 op4=[[FUNC2ID:[0-9]+]] op5=1/>
+; CHECK-DAG: <PERMODULE {{.*}} op0=[[ZID:[0-9]+]] op1=3 {{.*}} op3=0 op4=[[FUNC2ID:[0-9]+]]/>
; Variable bar initialization contains address reference to func:
; CHECK-DAG: <PERMODULE_GLOBALVAR_INIT_REFS {{.*}} op0=[[BARID:[0-9]+]] op1=0 op2=[[FUNCID]]/>
; CHECK: </GLOBALVAL_SUMMARY_BLOCK>
--- /dev/null
+; ModuleID = 'thinlto-function-summary-callgraph-profile-summary2.ll'
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+
+define void @hot1() #1 {
+ ret void
+}
+define void @hot2() #1 {
+ call void @externalFunction()
+ call void @externalFunction()
+ ret void
+}
+define void @hot3() #1 {
+ call void @externalFunction()
+ call void @externalFunction()
+ call void @externalFunction()
+ ret void
+}
+define void @cold() #1 {
+ ret void
+}
+define void @cold2() #1 {
+ call void @externalFunction()
+ call void @externalFunction()
+ ret void
+}
+
+define void @none1() #1 {
+ ret void
+}
+define void @none2() #1 {
+ call void @externalFunction()
+ ret void
+}
+define void @none3() #1 {
+ call void @externalFunction()
+ call void @externalFunction()
+ ret void
+}
+
+
+declare void @externalFunction()
--- /dev/null
+; Test to check the callgraph in summary when there is PGO
+; RUN: opt -module-summary %s -o %t.bc
+; RUN: opt -module-summary %p/Inputs/hotness_based_import.ll -o %t2.bc
+; RUN: llvm-lto -thinlto -o %t3 %t.bc %t2.bc
+
+; Test import with default hot multiplier (3)
+; RUN: opt -function-import -summary-file %t3.thinlto.bc %t.bc -import-instr-limit=1 --S | FileCheck %s --check-prefix=CHECK --check-prefix=HOT-DEFAULT
+; RUN: opt -function-import -summary-file %t3.thinlto.bc %t.bc -import-instr-limit=1 --S -import-hot-multiplier=3.0 | FileCheck %s --check-prefix=CHECK --check-prefix=HOT-DEFAULT
+; HOT-DEFAULT-DAG: define available_externally void @hot1()
+; HOT-DEFAULT-DAG: define available_externally void @hot2()
+; HOT-DEFAULT-DAG: define available_externally void @cold()
+; HOT-DEFAULT-DAG: define available_externally void @none1()
+
+; HOT-DEFAULT-NOT: define available_externally void @hot3()
+; HOT-DEFAULT-NOT: define available_externally void @none2()
+; HOT-DEFAULT-NOT: define available_externally void @none3()
+; HOT-DEFAULT-NOT: define available_externally void @cold2()
+
+
+; Test import with hot multiplier 1.0 - treat hot callsites as normal.
+; RUN: opt -function-import -summary-file %t3.thinlto.bc %t.bc -import-instr-limit=1 -import-hot-multiplier=1.0 --S | FileCheck %s --check-prefix=CHECK --check-prefix=HOT-ONE
+; HOT-ONE-DAG: define available_externally void @hot1()
+; HOT-ONE-DAG: define available_externally void @cold()
+; HOT-ONE-DAG: define available_externally void @none1()
+; HOT-ONE-NOT: define available_externally void @hot2()
+; HOT-ONE-NOT: define available_externally void @hot3()
+; HOT-ONE-NOT: define available_externally void @none2()
+; HOT-ONE-NOT: define available_externally void @none3()
+; HOT-ONE-NOT: define available_externally void @cold2()
+
+
+; Test import with hot multiplier 0.0 and high threshold - don't import functions called from hot callsite.
+; RUN: opt -function-import -summary-file %t3.thinlto.bc %t.bc -import-instr-limit=10 -import-hot-multiplier=0.0 --S | FileCheck %s --check-prefix=CHECK --check-prefix=HOT-ZERO
+; HOT-ZERO-DAG: define available_externally void @cold()
+; HOT-ZERO-DAG: define available_externally void @none1()
+; HOT-ZERO-DAG: define available_externally void @none2()
+; HOT-ZERO-DAG: define available_externally void @none3()
+; HOT-ZERO-DAG: define available_externally void @cold2()
+; HOT-ZERO-NOT: define available_externally void @hot2()
+; HOT-ZERO-NOT: define available_externally void @hot1()
+; HOT-ZERO-NOT: define available_externally void @hot3()
+
+
+
+; ModuleID = 'thinlto-function-summary-callgraph.ll'
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+; This function have high profile count, so entry block is hot.
+define void @hot_function(i1 %a, i1 %a2) !prof !20 {
+entry:
+ call void @hot1()
+ br i1 %a, label %Cold, label %Hot, !prof !41
+Cold: ; 1/1000 goes here
+ call void @cold()
+ call void @cold2()
+ call void @hot2()
+ call void @none1()
+ br label %exit
+Hot: ; 999/1000 goes here
+ call void @hot2()
+ call void @hot3()
+ br i1 %a2, label %None1, label %None2, !prof !42
+None1: ; half goes here
+ call void @none1()
+ call void @none2()
+ br label %exit
+None2: ; half goes here
+ call void @none3()
+ br label %exit
+exit:
+ ret void
+}
+
+declare void @hot1() #1
+declare void @hot2() #1
+declare void @hot3() #1
+declare void @cold() #1
+declare void @cold2() #1
+declare void @none1() #1
+declare void @none2() #1
+declare void @none3() #1
+
+
+!41 = !{!"branch_weights", i32 1, i32 1000}
+!42 = !{!"branch_weights", i32 1, i32 1}
+
+
+
+!llvm.module.flags = !{!1}
+!20 = !{!"function_entry_count", i64 110}
+
+!1 = !{i32 1, !"ProfileSummary", !2}
+!2 = !{!3, !4, !5, !6, !7, !8, !9, !10}
+!3 = !{!"ProfileFormat", !"InstrProf"}
+!4 = !{!"TotalCount", i64 10000}
+!5 = !{!"MaxCount", i64 10}
+!6 = !{!"MaxInternalCount", i64 1}
+!7 = !{!"MaxFunctionCount", i64 1000}
+!8 = !{!"NumCounts", i64 3}
+!9 = !{!"NumFunctions", i64 3}
+!10 = !{!"DetailedSummary", !11}
+!11 = !{!12, !13, !14}
+!12 = !{i32 10000, i64 100, i32 1}
+!13 = !{i32 999000, i64 100, i32 1}
+!14 = !{i32 999999, i64 1, i32 2}