LLVM 20.0.0git
PGOCtxProfReader.cpp
Go to the documentation of this file.
1//===- PGOCtxProfReader.cpp - Contextual Instrumentation profile reader ---===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// Read a contextual profile into a datastructure suitable for maintenance
10// throughout IPO
11//
12//===----------------------------------------------------------------------===//
13
19#include "llvm/Support/Error.h"
20
21using namespace llvm;
22
23// FIXME(#92054) - these Error handling macros are (re-)invented in a few
24// places.
25#define EXPECT_OR_RET(LHS, RHS) \
26 auto LHS = RHS; \
27 if (!LHS) \
28 return LHS.takeError();
29
30#define RET_ON_ERR(EXPR) \
31 if (auto Err = (EXPR)) \
32 return Err;
33
35PGOCtxProfContext::getOrEmplace(uint32_t Index, GlobalValue::GUID G,
37 auto [Iter, Inserted] =
38 Callsites[Index].insert({G, PGOCtxProfContext(G, std::move(Counters))});
39 if (!Inserted)
40 return make_error<InstrProfError>(instrprof_error::invalid_prof,
41 "Duplicate GUID for same callsite.");
42 return Iter->second;
43}
44
45Expected<BitstreamEntry> PGOCtxProfileReader::advance() {
47}
48
49Error PGOCtxProfileReader::wrongValue(const Twine &Msg) {
50 return make_error<InstrProfError>(instrprof_error::invalid_prof, Msg);
51}
52
53Error PGOCtxProfileReader::unsupported(const Twine &Msg) {
54 return make_error<InstrProfError>(instrprof_error::unsupported_version, Msg);
55}
56
57bool PGOCtxProfileReader::canReadContext() {
58 auto Blk = advance();
59 if (!Blk) {
60 consumeError(Blk.takeError());
61 return false;
62 }
63 return Blk->Kind == BitstreamEntry::SubBlock &&
65}
66
68PGOCtxProfileReader::readContext(bool ExpectIndex) {
70
71 std::optional<ctx_profile::GUID> Guid;
72 std::optional<SmallVector<uint64_t, 16>> Counters;
73 std::optional<uint32_t> CallsiteIndex;
74
75 SmallVector<uint64_t, 1> RecordValues;
76
77 // We don't prescribe the order in which the records come in, and we are ok
78 // if other unsupported records appear. We seek in the current subblock until
79 // we get all we know.
80 auto GotAllWeNeed = [&]() {
81 return Guid.has_value() && Counters.has_value() &&
82 (!ExpectIndex || CallsiteIndex.has_value());
83 };
84 while (!GotAllWeNeed()) {
85 RecordValues.clear();
86 EXPECT_OR_RET(Entry, advance());
87 if (Entry->Kind != BitstreamEntry::Record)
88 return wrongValue(
89 "Expected records before encountering more subcontexts");
90 EXPECT_OR_RET(ReadRecord,
91 Cursor.readRecord(bitc::UNABBREV_RECORD, RecordValues));
92 switch (*ReadRecord) {
94 if (RecordValues.size() != 1)
95 return wrongValue("The GUID record should have exactly one value");
96 Guid = RecordValues[0];
97 break;
99 Counters = std::move(RecordValues);
100 if (Counters->empty())
101 return wrongValue("Empty counters. At least the entry counter (one "
102 "value) was expected");
103 break;
105 if (!ExpectIndex)
106 return wrongValue("The root context should not have a callee index");
107 if (RecordValues.size() != 1)
108 return wrongValue("The callee index should have exactly one value");
109 CallsiteIndex = RecordValues[0];
110 break;
111 default:
112 // OK if we see records we do not understand, like records (profile
113 // components) introduced later.
114 break;
115 }
116 }
117
118 PGOCtxProfContext Ret(*Guid, std::move(*Counters));
119
120 while (canReadContext()) {
121 EXPECT_OR_RET(SC, readContext(true));
122 auto &Targets = Ret.callsites()[*SC->first];
123 auto [_, Inserted] =
124 Targets.insert({SC->second.guid(), std::move(SC->second)});
125 if (!Inserted)
126 return wrongValue(
127 "Unexpected duplicate target (callee) at the same callsite.");
128 }
129 return std::make_pair(CallsiteIndex, std::move(Ret));
130}
131
132Error PGOCtxProfileReader::readMetadata() {
135 return make_error<InstrProfError>(instrprof_error::invalid_prof,
136 "Invalid magic");
137
139 RET_ON_ERR(Cursor.advance().moveInto(Entry));
140 if (Entry.Kind != BitstreamEntry::SubBlock ||
142 return unsupported("Expected Block ID");
143 // We don't need the blockinfo to read the rest, it's metadata usable for e.g.
144 // llvm-bcanalyzer.
145 RET_ON_ERR(Cursor.SkipBlock());
146
147 EXPECT_OR_RET(Blk, advance());
148 if (Blk->Kind != BitstreamEntry::SubBlock)
149 return unsupported("Expected Version record");
152 EXPECT_OR_RET(MData, advance());
153 if (MData->Kind != BitstreamEntry::Record)
154 return unsupported("Expected Version record");
155
159 return unsupported("Expected Version record");
160 if (Ver.size() != 1 || Ver[0] > PGOCtxProfileWriter::CurrentVersion)
161 return unsupported("Version " + Twine(*Code) +
162 " is higher than supported version " +
164 return Error::success();
165}
166
169 std::map<GlobalValue::GUID, PGOCtxProfContext> Ret;
170 RET_ON_ERR(readMetadata());
171 while (canReadContext()) {
172 EXPECT_OR_RET(E, readContext(false));
173 auto Key = E->second.guid();
174 if (!Ret.insert({Key, std::move(E->second)}).second)
175 return wrongValue("Duplicate roots");
176 }
177 return std::move(Ret);
178}
#define _
#define G(x, y, z)
Definition: MD5.cpp:56
#define RET_ON_ERR(EXPR)
#define EXPECT_OR_RET(LHS, RHS)
Reader for contextual iFDO profile, which comes in bitstream format.
Expected< BitstreamEntry > advance(unsigned Flags=0)
Advance the current bitstream, returning the next entry in the stream.
Expected< unsigned > readRecord(unsigned AbbrevID, SmallVectorImpl< uint64_t > &Vals, StringRef *Blob=nullptr)
Error EnterSubBlock(unsigned BlockID, unsigned *NumWordsP=nullptr)
Having read the ENTER_SUBBLOCK abbrevid, and enter the block.
@ AF_DontAutoprocessAbbrevs
If this flag is used, abbrev entries are returned just like normal records.
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.
Definition: Error.h:160
static ErrorSuccess success()
Create a success value.
Definition: Error.h:337
Tagged union holding either a T or a Error.
Definition: Error.h:481
A node (context) in the loaded contextual profile, suitable for mutation during IPO passes.
Expected< std::map< GlobalValue::GUID, PGOCtxProfContext > > loadContexts()
static constexpr uint32_t CurrentVersion
static constexpr StringRef ContainerMagic
size_t size() const
Definition: SmallVector.h:78
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
Definition: SmallVector.h:573
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Definition: SmallVector.h:1196
constexpr size_t size() const
size - Get the string size.
Definition: StringRef.h:150
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
Definition: Twine.h:81
@ Entry
Definition: COFF.h:844
@ SC
CHAIN = SC CHAIN, Imm128 - System call.
@ BLOCKINFO_BLOCK_ID
BLOCKINFO_BLOCK is used to define metadata about blocks, for example, standard abbrevs that should be...
Definition: BitCodeEnums.h:69
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
void consumeError(Error Err)
Consume a Error without doing anything.
Definition: Error.h:1069
@ ContextNodeBlockID
@ ProfileMetadataBlockID
When advancing through a bitstream cursor, each advance can discover a few different kinds of entries...