Skip to content

Commit 1e15371

Browse files
[ThinLTO][TypeProf] Implement vtable def import (#79381)
Add annotated vtable GUID as referenced variables in per function summary, and update bitcode writer to create value-ids for these referenced vtables. - This is the part3 of type profiling work, and described in the "Virtual Table Definition Import" [1] section of the RFC. [1] https://github.com/llvm/llvm-project/pull/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
1 parent 1d5e5f4 commit 1e15371

File tree

6 files changed

+120
-36
lines changed

6 files changed

+120
-36
lines changed

llvm/include/llvm/ProfileData/InstrProf.h

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -283,14 +283,24 @@ void annotateValueSite(Module &M, Instruction &Inst,
283283

284284
/// Extract the value profile data from \p Inst which is annotated with
285285
/// value profile meta data. Return false if there is no value data annotated,
286-
/// otherwise return true.
286+
/// otherwise return true.
287287
bool getValueProfDataFromInst(const Instruction &Inst,
288288
InstrProfValueKind ValueKind,
289289
uint32_t MaxNumValueData,
290290
InstrProfValueData ValueData[],
291291
uint32_t &ActualNumValueData, uint64_t &TotalC,
292292
bool GetNoICPValue = false);
293293

294+
/// Extract the value profile data from \p Inst and returns them if \p Inst is
295+
/// annotated with value profile data. Returns nullptr otherwise. It's similar
296+
/// to `getValueProfDataFromInst` above except that an array is allocated only
297+
/// after a preliminary checking that the value profiles of kind `ValueKind`
298+
/// exist.
299+
std::unique_ptr<InstrProfValueData[]>
300+
getValueProfDataFromInst(const Instruction &Inst, InstrProfValueKind ValueKind,
301+
uint32_t MaxNumValueData, uint32_t &ActualNumValueData,
302+
uint64_t &TotalC, bool GetNoICPValue = false);
303+
294304
inline StringRef getPGOFuncNameMetadataName() { return "PGOFuncName"; }
295305

296306
/// Return the PGOFuncName meta data associated with a function.

llvm/lib/Analysis/IndirectCallPromotionAnalysis.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,10 @@ static cl::opt<unsigned>
4545
cl::desc("Max number of promotions for a single indirect "
4646
"call callsite"));
4747

48+
cl::opt<unsigned> MaxNumVTableAnnotations(
49+
"icp-max-num-vtables", cl::init(6), cl::Hidden,
50+
cl::desc("Max number of vtables annotated for a vtable load instruction."));
51+
4852
ICallPromotionAnalysis::ICallPromotionAnalysis() {
4953
ValueDataArray = std::make_unique<InstrProfValueData[]>(MaxNumPromotions);
5054
}

llvm/lib/Analysis/ModuleSummaryAnalysis.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,8 @@ static cl::opt<std::string> ModuleSummaryDotFile(
8282

8383
extern cl::opt<bool> ScalePartialSampleProfileWorkingSetSize;
8484

85+
extern cl::opt<unsigned> MaxNumVTableAnnotations;
86+
8587
// Walk through the operands of a given User via worklist iteration and populate
8688
// the set of GlobalValue references encountered. Invoked either on an
8789
// Instruction or a GlobalVariable (which walks its initializer).
@@ -124,6 +126,24 @@ static bool findRefEdges(ModuleSummaryIndex &Index, const User *CurUser,
124126
Worklist.push_back(Operand);
125127
}
126128
}
129+
130+
const Instruction *I = dyn_cast<Instruction>(CurUser);
131+
if (I) {
132+
uint32_t ActualNumValueData = 0;
133+
uint64_t TotalCount = 0;
134+
// MaxNumVTableAnnotations is the maximum number of vtables annotated on
135+
// the instruction.
136+
auto ValueDataArray =
137+
getValueProfDataFromInst(*I, IPVK_VTableTarget, MaxNumVTableAnnotations,
138+
ActualNumValueData, TotalCount);
139+
140+
if (ValueDataArray.get()) {
141+
for (uint32_t j = 0; j < ActualNumValueData; j++) {
142+
RefEdges.insert(Index.getOrInsertValueInfo(/* VTableGUID = */
143+
ValueDataArray[j].Value));
144+
}
145+
}
146+
}
127147
return HasBlockAddress;
128148
}
129149

llvm/lib/Bitcode/Writer/BitcodeWriter.cpp

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -203,14 +203,23 @@ class ModuleBitcodeWriterBase : public BitcodeWriterBase {
203203
for (const auto &GUIDSummaryLists : *Index)
204204
// Examine all summaries for this GUID.
205205
for (auto &Summary : GUIDSummaryLists.second.SummaryList)
206-
if (auto FS = dyn_cast<FunctionSummary>(Summary.get()))
206+
if (auto FS = dyn_cast<FunctionSummary>(Summary.get())) {
207207
// For each call in the function summary, see if the call
208208
// is to a GUID (which means it is for an indirect call,
209209
// otherwise we would have a Value for it). If so, synthesize
210210
// a value id.
211211
for (auto &CallEdge : FS->calls())
212212
if (!CallEdge.first.haveGVs() || !CallEdge.first.getValue())
213213
assignValueId(CallEdge.first.getGUID());
214+
215+
// For each referenced variables in the function summary, see if the
216+
// variable is represented by a GUID (as opposed to a symbol to
217+
// declarations or definitions in the module). If so, synthesize a
218+
// value id.
219+
for (auto &RefEdge : FS->refs())
220+
if (!RefEdge.haveGVs() || !RefEdge.getValue())
221+
assignValueId(RefEdge.getGUID());
222+
}
214223
}
215224

216225
protected:
@@ -4188,7 +4197,7 @@ void ModuleBitcodeWriterBase::writePerModuleFunctionSummaryRecord(
41884197
NameVals.push_back(SpecialRefCnts.second); // worefcnt
41894198

41904199
for (auto &RI : FS->refs())
4191-
NameVals.push_back(VE.getValueID(RI.getValue()));
4200+
NameVals.push_back(getValueId(RI));
41924201

41934202
const bool UseRelBFRecord =
41944203
WriteRelBFToSummary && !F.hasProfileData() &&

llvm/lib/ProfileData/InstrProf.cpp

Lines changed: 49 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1271,46 +1271,44 @@ void annotateValueSite(Module &M, Instruction &Inst,
12711271
Inst.setMetadata(LLVMContext::MD_prof, MDNode::get(Ctx, Vals));
12721272
}
12731273

1274-
bool getValueProfDataFromInst(const Instruction &Inst,
1275-
InstrProfValueKind ValueKind,
1276-
uint32_t MaxNumValueData,
1277-
InstrProfValueData ValueData[],
1278-
uint32_t &ActualNumValueData, uint64_t &TotalC,
1279-
bool GetNoICPValue) {
1274+
MDNode *mayHaveValueProfileOfKind(const Instruction &Inst,
1275+
InstrProfValueKind ValueKind) {
12801276
MDNode *MD = Inst.getMetadata(LLVMContext::MD_prof);
12811277
if (!MD)
1282-
return false;
1278+
return nullptr;
12831279

1284-
unsigned NOps = MD->getNumOperands();
1280+
if (MD->getNumOperands() < 5)
1281+
return nullptr;
12851282

1286-
if (NOps < 5)
1287-
return false;
1288-
1289-
// Operand 0 is a string tag "VP":
12901283
MDString *Tag = cast<MDString>(MD->getOperand(0));
1291-
if (!Tag)
1292-
return false;
1293-
1294-
if (!Tag->getString().equals("VP"))
1295-
return false;
1284+
if (!Tag || !Tag->getString().equals("VP"))
1285+
return nullptr;
12961286

12971287
// Now check kind:
12981288
ConstantInt *KindInt = mdconst::dyn_extract<ConstantInt>(MD->getOperand(1));
12991289
if (!KindInt)
1300-
return false;
1290+
return nullptr;
13011291
if (KindInt->getZExtValue() != ValueKind)
1302-
return false;
1292+
return nullptr;
1293+
1294+
return MD;
1295+
}
13031296

1297+
static bool getValueProfDataFromInstImpl(const MDNode *const MD,
1298+
const uint32_t MaxNumDataWant,
1299+
InstrProfValueData ValueData[],
1300+
uint32_t &ActualNumValueData,
1301+
uint64_t &TotalC, bool GetNoICPValue) {
1302+
const unsigned NOps = MD->getNumOperands();
13041303
// Get total count
13051304
ConstantInt *TotalCInt = mdconst::dyn_extract<ConstantInt>(MD->getOperand(2));
13061305
if (!TotalCInt)
13071306
return false;
13081307
TotalC = TotalCInt->getZExtValue();
1309-
13101308
ActualNumValueData = 0;
13111309

13121310
for (unsigned I = 3; I < NOps; I += 2) {
1313-
if (ActualNumValueData >= MaxNumValueData)
1311+
if (ActualNumValueData >= MaxNumDataWant)
13141312
break;
13151313
ConstantInt *Value = mdconst::dyn_extract<ConstantInt>(MD->getOperand(I));
13161314
ConstantInt *Count =
@@ -1327,6 +1325,36 @@ bool getValueProfDataFromInst(const Instruction &Inst,
13271325
return true;
13281326
}
13291327

1328+
std::unique_ptr<InstrProfValueData[]>
1329+
getValueProfDataFromInst(const Instruction &Inst, InstrProfValueKind ValueKind,
1330+
uint32_t MaxNumValueData, uint32_t &ActualNumValueData,
1331+
uint64_t &TotalC, bool GetNoICPValue) {
1332+
MDNode *MD = mayHaveValueProfileOfKind(Inst, ValueKind);
1333+
if (!MD)
1334+
return nullptr;
1335+
auto ValueDataArray = std::make_unique<InstrProfValueData[]>(MaxNumValueData);
1336+
if (!getValueProfDataFromInstImpl(MD, MaxNumValueData, ValueDataArray.get(),
1337+
ActualNumValueData, TotalC, GetNoICPValue))
1338+
return nullptr;
1339+
return ValueDataArray;
1340+
}
1341+
1342+
// FIXME: Migrate existing callers to the function above that returns an
1343+
// array.
1344+
bool getValueProfDataFromInst(const Instruction &Inst,
1345+
InstrProfValueKind ValueKind,
1346+
uint32_t MaxNumValueData,
1347+
InstrProfValueData ValueData[],
1348+
uint32_t &ActualNumValueData, uint64_t &TotalC,
1349+
bool GetNoICPValue) {
1350+
MDNode *MD = mayHaveValueProfileOfKind(Inst, ValueKind);
1351+
if (!MD)
1352+
return false;
1353+
return getValueProfDataFromInstImpl(MD, MaxNumValueData, ValueData,
1354+
ActualNumValueData, TotalC,
1355+
GetNoICPValue);
1356+
}
1357+
13301358
MDNode *getPGOFuncNameMetadata(const Function &F) {
13311359
return F.getMetadata(getPGOFuncNameMetadataName());
13321360
}

llvm/test/Bitcode/thinlto-func-summary-vtableref-pgo.ll

Lines changed: 25 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,31 @@
1-
; RUN: opt -module-summary %s -o %t.o
1+
; Promote at most one function and annotate at most one vtable.
2+
; As a result, only one value (of each relevant kind) shows up in the function
3+
; summary.
4+
5+
; RUN: opt -module-summary -icp-max-num-vtables=1 -icp-max-prom=1 %s -o %t.o
26

37
; RUN: llvm-bcanalyzer -dump %t.o | FileCheck %s
48

59
; RUN: llvm-dis -o - %t.o | FileCheck %s --check-prefix=DIS
6-
10+
; Round trip it through llvm-as
11+
; RUN: llvm-dis -o - %t.o | llvm-as -o - | llvm-dis -o - | FileCheck %s --check-prefix=DIS
712

813
; CHECK: <GLOBALVAL_SUMMARY_BLOCK
914
; CHECK-NEXT: <VERSION op0=9/>
1015
; CHECK-NEXT: <FLAGS op0=0/>
16+
; The `VALUE_GUID` below represents the "_ZTV4Base" referenced by the instruction
17+
; that loads vtable pointers.
18+
; CHECK-NEXT: <VALUE_GUID op0=21 op1=1960855528937986108/>
1119
; The `VALUE_GUID` below represents the "_ZN4Base4funcEv" referenced by the
1220
; indirect call instruction.
13-
; CHECK-NEXT: <VALUE_GUID op0=17 op1=5459407273543877811/>
21+
; CHECK-NEXT: <VALUE_GUID op0=20 op1=5459407273543877811/>
22+
; NOTE vtables and functions from Derived class is dropped because
23+
; `-icp-max-num-vtables` and `-icp-max-prom` are both set to one.
1424
; <PERMODULE_PROFILE> has the format [valueid, flags, instcount, funcflags,
1525
; numrefs, rorefcnt, worefcnt,
26+
; m x valueid,
1627
; n x (valueid, hotness+tailcall)]
17-
; CHECK-NEXT: <PERMODULE_PROFILE abbrevid=4 op0=0 op1=0 op2=4 op3=256 op4=0 op5=0 op6=0 op7=17 op8=3/>
28+
; CHECK-NEXT: <PERMODULE_PROFILE abbrevid=4 op0=0 op1=0 op2=4 op3=256 op4=1 op5=1 op6=0 op7=21 op8=20 op9=3/>
1829
; CHECK-NEXT: </GLOBALVAL_SUMMARY_BLOCK>
1930

2031
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
@@ -31,7 +42,6 @@ define i32 @_Z4testP4Base(ptr %0) !prof !15 {
3142

3243
!llvm.module.flags = !{!1}
3344

34-
3545
!1 = !{i32 1, !"ProfileSummary", !2}
3646
!2 = !{!3, !4, !5, !6, !7, !8, !9, !10}
3747
!3 = !{!"ProfileFormat", !"InstrProf"}
@@ -48,14 +58,17 @@ define i32 @_Z4testP4Base(ptr %0) !prof !15 {
4858
!14 = !{i32 999999, i64 1, i32 2}
4959

5060
!15 = !{!"function_entry_count", i32 150}
51-
; 1960855528937986108 is the MD5 hash of _ZTV4Base
52-
!16 = !{!"VP", i32 2, i64 1600, i64 1960855528937986108, i64 1600}
53-
; 5459407273543877811 is the MD5 hash of _ZN4Base4funcEv
54-
!17 = !{!"VP", i32 0, i64 1600, i64 5459407273543877811, i64 1600}
61+
; 1960855528937986108 is the MD5 hash of _ZTV4Base, and
62+
; 13870436605473471591 is the MD5 hash of _ZTV7Derived
63+
!16 = !{!"VP", i32 2, i64 150, i64 1960855528937986108, i64 100, i64 13870436605473471591, i64 50}
64+
; 5459407273543877811 is the MD5 hash of _ZN4Base4funcEv, and
65+
; 6174874150489409711 is the MD5 hash of _ZN7Derived4funcEv
66+
!17 = !{!"VP", i32 0, i64 150, i64 5459407273543877811, i64 100, i64 6174874150489409711, i64 50}
5567

5668
; ModuleSummaryIndex stores <guid, global-value summary> map in std::map; so
5769
; global value summares are printed out in the order that gv's guid increases.
5870
; DIS: ^0 = module: (path: "{{.*}}", hash: (0, 0, 0, 0, 0))
59-
; DIS: ^1 = gv: (guid: 5459407273543877811)
60-
; DIS: ^2 = gv: (name: "_Z4testP4Base", summaries: (function: (module: ^0, flags: (linkage: external, visibility: default, notEligibleToImport: 0, live: 0, dsoLocal: 0, canAutoHide: 0), insts: 4, funcFlags: (readNone: 0, readOnly: 0, noRecurse: 0, returnDoesNotAlias: 0, noInline: 0, alwaysInline: 0, noUnwind: 0, mayThrow: 0, hasUnknownCall: 1, mustBeUnreachable: 0), calls: ((callee: ^1, hotness: hot))))) ; guid = 15857150948103218965
61-
; DIS: ^3 = blockcount: 0
71+
; DIS: ^1 = gv: (guid: 1960855528937986108)
72+
; DIS: ^2 = gv: (guid: 5459407273543877811)
73+
; DIS: ^3 = gv: (name: "_Z4testP4Base", summaries: (function: (module: ^0, flags: (linkage: external, visibility: default, notEligibleToImport: 0, live: 0, dsoLocal: 0, canAutoHide: 0), insts: 4, funcFlags: (readNone: 0, readOnly: 0, noRecurse: 0, returnDoesNotAlias: 0, noInline: 0, alwaysInline: 0, noUnwind: 0, mayThrow: 0, hasUnknownCall: 1, mustBeUnreachable: 0), calls: ((callee: ^2, hotness: hot)), refs: (readonly ^1)))) ; guid = 15857150948103218965
74+
; DIS: ^4 = blockcount: 0

0 commit comments

Comments
 (0)