28#define EXPECT_OR_RET(LHS, RHS) \
31 return LHS.takeError();
33#define RET_ON_ERR(EXPR) \
34 if (auto Err = (EXPR)) \
40 auto [Iter, Inserted] =
44 "Duplicate GUID for same callsite.");
52Error PGOCtxProfileReader::wrongValue(
const Twine &Msg) {
56Error PGOCtxProfileReader::unsupported(
const Twine &Msg) {
69 PGOCtxProfileBlockIDs::LAST_VALID < Blk->
ID)
77 return tryGetNextKnownBlockID(
Test) &&
Test ==
ID;
93 "Unexpected profile kind");
96 std::optional<ctx_profile::GUID>
Guid;
97 std::optional<SmallVector<uint64_t, 16>>
Counters;
99 std::optional<uint64_t> TotalEntryCount;
100 std::optional<CtxProfFlatProfile> Unhandled;
108 auto GotAllWeNeed = [&]() {
111 (!IsRoot || TotalEntryCount.has_value()) &&
112 (!IsRoot || Unhandled.has_value());
115 while (!GotAllWeNeed()) {
116 RecordValues.
clear();
127 "Expected records before encountering more subcontexts");
131 switch (*ReadRecord) {
133 if (RecordValues.
size() != 1)
134 return wrongValue(
"The GUID record should have exactly one value");
135 Guid = RecordValues[0];
140 return wrongValue(
"Empty counters. At least the entry counter (one "
141 "value) was expected");
145 return wrongValue(
"The root context should not have a callee index");
146 if (RecordValues.
size() != 1)
147 return wrongValue(
"The callee index should have exactly one value");
152 return wrongValue(
"Non-root has a total entry count record");
153 if (RecordValues.
size() != 1)
155 "The root total entry count record should have exactly one value");
156 TotalEntryCount = RecordValues[0];
166 std::move(Unhandled));
170 auto &Targets =
Ret.callsites()[*SC->first];
172 Targets.insert({SC->second.guid(), std::move(SC->second)});
175 "Unexpected duplicate target (callee) at the same callsite.");
180Error PGOCtxProfileReader::readMetadata() {
190 return unsupported(
"Expected Block ID");
197 return unsupported(
"Expected Version record");
202 return unsupported(
"Expected Version record");
207 return unsupported(
"Expected Version record");
209 return unsupported(
"Version " +
Twine(*Code) +
210 " is higher than supported version " +
219 auto Key = E->second.guid();
220 if (!
P.insert({Key, std::move(E->second)}).second)
221 return wrongValue(
"Duplicate roots");
229 auto Guid = E->second.guid();
230 if (!
P.insert({Guid, std::move(E->second.counters())}).second)
231 return wrongValue(
"Duplicate flat profile entries");
239 return loadFlatProfileList(
P);
246 for (
auto I = 0;
I < 2; ++
I) {
247 if (!tryGetNextKnownBlockID(
Test))
252 RET_ON_ERR(loadFlatProfiles(Ret.FlatProfiles));
254 return wrongValue(
"Unexpected section");
258 return std::move(Ret);
269void toYaml(yaml::Output &Out,
273 void *SaveData =
nullptr;
274 for (
const auto &[
_, Ctx] : CallTargets) {
275 Out.preflightElement(Index++, SaveData);
277 Out.postflightElement(
nullptr);
282void toYaml(yaml::Output &Out,
286 assert(MaxIt != AllCS.end() &&
"We should have a max value because the "
287 "callsites collection is not empty.");
288 void *SaveData =
nullptr;
290 for (
auto I = 0U;
I <= *MaxIt; ++
I) {
291 Out.preflightElement(
I, SaveData);
292 auto It = Callsites.find(
I);
293 if (It == Callsites.end()) {
295 Out.beginFlowSequence();
296 Out.endFlowSequence();
298 toYaml(Out, It->second);
300 Out.postflightElement(
nullptr);
312 yaml::EmptyContext
Empty;
314 void *SaveInfo =
nullptr;
315 bool UseDefault =
false;
317 Out.preflightKey(
"Guid",
true,
false,
318 UseDefault, SaveInfo);
319 yaml::yamlize(Out,
Guid,
true, Empty);
320 Out.postflightKey(
nullptr);
323 Out.preflightKey(
"TotalRootEntryCount",
true,
false, UseDefault, SaveInfo);
325 Out.postflightKey(
nullptr);
328 Out.preflightKey(
"Counters",
true,
false, UseDefault, SaveInfo);
329 Out.beginFlowSequence();
330 for (
size_t I = 0U, E =
Counters.size();
I < E; ++
I) {
331 Out.preflightFlowElement(
I, SaveInfo);
333 yaml::yamlize(Out, V,
true, Empty);
334 Out.postflightFlowElement(SaveInfo);
336 Out.endFlowSequence();
337 Out.postflightKey(
nullptr);
340 if (!Unhandled.empty()) {
342 Out.preflightKey(
"Unhandled",
false,
false, UseDefault, SaveInfo);
343 toYaml(Out, Unhandled);
344 Out.postflightKey(
nullptr);
347 if (!Callsites.empty()) {
348 Out.preflightKey(
"Callsites",
true,
false, UseDefault, SaveInfo);
349 toYaml(Out, Callsites);
350 Out.postflightKey(
nullptr);
356 void *SaveInfo =
nullptr;
360 Out.preflightElement(ElemID++, SaveInfo);
362 Out.postflightElement(
nullptr);
378 yaml::Output Out(
OS);
379 void *SaveInfo =
nullptr;
380 bool UseDefault =
false;
382 if (!
Profile.Contexts.empty()) {
383 Out.preflightKey(
"Contexts",
false,
false, UseDefault, SaveInfo);
385 Out.postflightKey(
nullptr);
387 if (!
Profile.FlatProfiles.empty()) {
388 Out.preflightKey(
"FlatProfiles",
false,
false, UseDefault, SaveInfo);
389 toYaml(Out,
Profile.FlatProfiles);
390 Out.postflightKey(
nullptr);
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
#define EXPECT_OR_RET(LHS, RHS)
Reader for contextual iFDO profile, which comes in bitstream format.
@ AF_DontAutoprocessAbbrevs
If this flag is used, abbrev entries are returned just like normal records.
Expected< BitstreamEntry > advance(unsigned Flags=0)
Advance the current bitstream, returning the next entry in the stream.
LLVM_ABI Expected< unsigned > readRecord(unsigned AbbrevID, SmallVectorImpl< uint64_t > &Vals, StringRef *Blob=nullptr)
LLVM_ABI Error EnterSubBlock(unsigned BlockID, unsigned *NumWordsP=nullptr)
Having read the ENTER_SUBBLOCK abbrevid, and enter the block.
Error SkipBlock()
Having read the ENTER_SUBBLOCK abbrevid and a BlockID, skip over the body of this block.
Lightweight error class with error context and mandatory checking.
static ErrorSuccess success()
Create a success value.
Tagged union holding either a T or a Error.
A node (context) in the loaded contextual profile, suitable for mutation during IPO passes.
GlobalValue::GUID guid() const
const SmallVectorImpl< uint64_t > & counters() const
std::map< uint32_t, CallTargetMapTy > CallsiteMapTy
const CtxProfFlatProfile & getUnhandled() const
uint64_t getTotalRootEntryCount() const
std::map< GlobalValue::GUID, PGOCtxProfContext > CallTargetMapTy
const CallsiteMapTy & callsites() const
LLVM_ABI Expected< PGOCtxProfile > loadProfiles()
static constexpr uint32_t CurrentVersion
static constexpr StringRef ContainerMagic
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
constexpr size_t size() const
size - Get the string size.
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
This class implements an extremely fast bulk output stream that can only output to a stream.
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
@ BLOCKINFO_BLOCK_ID
BLOCKINFO_BLOCK is used to define metadata about blocks, for example, standard abbrevs that should be...
This is an optimization pass for GlobalISel generic memory operations.
std::map< GlobalValue::GUID, PGOCtxProfContext > CtxProfContextualProfiles
std::map< GlobalValue::GUID, SmallVector< uint64_t, 1 > > CtxProfFlatProfile
auto make_first_range(ContainerTy &&c)
Given a container of pairs, return a range over the first elements.
auto max_element(R &&Range)
Provide wrappers to std::max_element which take ranges instead of having to pass begin/end explicitly...
LLVM_ABI void convertCtxProfToYaml(raw_ostream &OS, const PGOCtxProfile &Profile)
void consumeError(Error Err)
Consume a Error without doing anything.
@ FlatProfilesSectionBlockID
When advancing through a bitstream cursor, each advance can discover a few different kinds of entries...