Thanks to visit codestin.com
Credit goes to llvm.org

LLVM 22.0.0git
BitstreamRemarkParser.cpp
Go to the documentation of this file.
1//===- BitstreamRemarkParser.cpp ------------------------------------------===//
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// This file provides utility methods used by clients that want to use the
10// parser for remark diagnostics in LLVM.
11//
12//===----------------------------------------------------------------------===//
13
16#include "llvm/Support/Path.h"
17#include <optional>
18
19using namespace llvm;
20using namespace llvm::remarks;
21
22namespace {
23
24template <typename... Ts> Error error(char const *Fmt, const Ts &...Vals) {
25 std::string Buffer;
26 raw_string_ostream OS(Buffer);
27 OS << formatv(Fmt, Vals...);
29 std::move(Buffer),
30 std::make_error_code(std::errc::illegal_byte_sequence));
31}
32
33} // namespace
34
36 return error("Unknown record entry ({}).", AbbrevID);
37}
38
40 return error("Unexpected record entry ({}).", RecordName);
41}
42
44 return error("Malformed record entry ({}).", RecordName);
45}
46
48 return error("Unexpected subblock ({}).", Code);
49}
50
53 if (!Next)
54 return Next.takeError();
55 switch (Next->Kind) {
57 return Next->ID;
60 return error("Expected subblock, but got unexpected record.");
62 return error("Expected subblock, but got unexpected end of bitstream.");
63 }
64 llvm_unreachable("Unexpected BitstreamEntry");
65}
66
68 auto MaybeBlockID = expectSubBlock(Stream);
69 if (!MaybeBlockID)
70 return MaybeBlockID.takeError();
71 if (*MaybeBlockID != BlockID)
72 return error("Expected {} block, but got unexpected block ({}).", BlockName,
73 *MaybeBlockID);
74 return Error::success();
75}
76
78 if (Stream.EnterSubBlock(BlockID))
79 return error("Error while entering {} block.", BlockName);
80 return Error::success();
81}
82
84 // Note: 2 is used here because it's the max number of fields we have per
85 // record.
87 StringRef Blob;
88 Expected<unsigned> RecordID = Stream.readRecord(Code, Record, &Blob);
89 if (!RecordID)
90 return RecordID.takeError();
91
92 switch (*RecordID) {
94 if (Record.size() != 2)
96 Container = {Record[0], Record[1]};
97 // Error immediately if container version is outdated, so the user sees an
98 // explanation instead of a parser error.
99 if (Container->Version != CurrentContainerVersion) {
100 return ::error(
101 "Unsupported remark container version (expected: {}, read: {}). "
102 "Please upgrade/downgrade your toolchain to read this container.",
104 }
105 break;
106 }
108 if (Record.size() != 1)
111 // Error immediately if remark version is outdated, so the user sees an
112 // explanation instead of a parser error.
114 return ::error(
115 "Unsupported remark version in container (expected: {}, read: {}). "
116 "Please upgrade/downgrade your toolchain to read this container.",
118 }
119 break;
120 }
121 case RECORD_META_STRTAB: {
122 if (Record.size() != 0)
124 StrTabBuf = Blob;
125 break;
126 }
128 if (Record.size() != 0)
130 ExternalFilePath = Blob;
131 break;
132 }
133 default:
134 return unknownRecord(*RecordID);
135 }
136 return Error::success();
137}
138
140 Record.clear();
141 Expected<unsigned> MaybeRecordID =
142 Stream.readRecord(Code, Record, &RecordBlob);
143 if (!MaybeRecordID)
144 return MaybeRecordID.takeError();
145 RecordID = *MaybeRecordID;
146 return handleRecord();
147}
148
150 switch (RecordID) {
152 if (Record.size() != 4)
154 Type = Record[0];
156 PassNameIdx = Record[2];
158 break;
159 }
161 if (Record.size() != 3)
163 Loc = {Record[0], Record[1], Record[2]};
164 break;
165 }
167 if (Record.size() != 1)
169 Hotness = Record[0];
170 break;
171 }
173 if (Record.size() != 5)
175 auto &Arg = Args.emplace_back(Record[0], Record[1]);
176 Arg.Loc = {Record[2], Record[3], Record[4]};
177 break;
178 }
180 if (Record.size() != 2)
182 Args.emplace_back(Record[0], Record[1]);
183 break;
184 }
185 default:
186 return unknownRecord(RecordID);
187 }
188 return Error::success();
189}
190
192 Type.reset();
193 RemarkNameIdx.reset();
194 PassNameIdx.reset();
195 FunctionNameIdx.reset();
196 Hotness.reset();
197 Loc.reset();
198 Args.clear();
199
200 return parseBlock();
201}
202
204 std::array<char, 4> Result;
205 for (unsigned I = 0; I < 4; ++I)
206 if (Expected<unsigned> R = Stream.Read(8))
207 Result[I] = *R;
208 else
209 return R.takeError();
210
211 StringRef MagicNumber{Result.data(), Result.size()};
213 return error("Unknown magic number: expecting {}, got {}.",
215 return Error::success();
216}
217
220 if (!Next)
221 return Next.takeError();
222 if (Next->Kind != BitstreamEntry::SubBlock ||
224 return error(
225 "Error while parsing BLOCKINFO_BLOCK: expecting [ENTER_SUBBLOCK, "
226 "BLOCKINFO_BLOCK, ...].");
227
229 Stream.ReadBlockInfoBlock();
230 if (!MaybeBlockInfo)
231 return MaybeBlockInfo.takeError();
232
233 if (!*MaybeBlockInfo)
234 return error("Missing BLOCKINFO_BLOCK.");
235
236 BlockInfo = **MaybeBlockInfo;
237
238 Stream.setBlockInfo(&BlockInfo);
239 return Error::success();
240}
241
243 if (Error E = expectMagic())
244 return E;
245 if (Error E = parseBlockInfoBlock())
246 return E;
247
248 // Parse early meta block.
249 if (Error E = MetaHelper.expectBlock())
250 return E;
251 if (Error E = MetaHelper.parseBlock())
252 return E;
253
254 // Skip all Remarks blocks.
255 while (!Stream.AtEndOfStream()) {
256 auto MaybeBlockID = expectSubBlock(Stream);
257 if (!MaybeBlockID)
258 return MaybeBlockID.takeError();
259 if (*MaybeBlockID == META_BLOCK_ID)
260 break;
261 if (*MaybeBlockID != REMARK_BLOCK_ID)
262 return error("Unexpected block between meta blocks.");
263 // Remember first remark block.
265 RemarkStartBitPos = Stream.GetCurrentBitNo();
266 if (Error E = Stream.SkipBlock())
267 return E;
268 }
269
270 // Late meta block is optional if there are no remarks.
271 if (Stream.AtEndOfStream())
272 return Error::success();
273
274 // Parse late meta block.
275 if (Error E = MetaHelper.parseBlock())
276 return E;
277 return Error::success();
278}
279
281 if (RemarkStartBitPos) {
282 RemarkStartBitPos.reset();
283 } else {
284 auto MaybeBlockID = expectSubBlock(Stream);
285 if (!MaybeBlockID)
286 return MaybeBlockID.takeError();
287 if (*MaybeBlockID != REMARK_BLOCK_ID)
289 }
290 return RemarksHelper->parseNext();
291}
292
295 StringRef Buf, std::optional<StringRef> ExternalFilePrependPath) {
296 auto Parser = std::make_unique<BitstreamRemarkParser>(Buf);
297
298 if (ExternalFilePrependPath)
299 Parser->ExternalFilePrependPath = std::string(*ExternalFilePrependPath);
300
301 return std::move(Parser);
302}
303
306
308 if (!IsMetaReady) {
309 // Container is completely empty.
310 if (ParserHelper->Stream.AtEndOfStream())
312
313 if (Error E = parseMeta())
314 return std::move(E);
315 IsMetaReady = true;
316
317 // Container has meta, but no remarks blocks.
318 if (!ParserHelper->RemarkStartBitPos)
319 return error(
320 "Container is non-empty, but does not contain any remarks blocks.");
321
322 if (Error E =
323 ParserHelper->Stream.JumpToBit(*ParserHelper->RemarkStartBitPos))
324 return std::move(E);
325 ParserHelper->RemarksHelper.emplace(ParserHelper->Stream);
326 }
327
328 if (Error E = ParserHelper->parseRemark())
329 return std::move(E);
330 return processRemark();
331}
332
334 if (Error E = ParserHelper->parseMeta())
335 return E;
336 if (Error E = processCommonMeta())
337 return E;
338
339 switch (ContainerType) {
341 return processExternalFilePath();
343 return processFileContainerMeta();
344 }
345 llvm_unreachable("Unknown BitstreamRemarkContainerType enum");
346}
347
348Error BitstreamRemarkParser::processCommonMeta() {
349 auto &Helper = ParserHelper->MetaHelper;
350 if (!Helper.Container)
351 return Helper.error("Missing container info.");
352 auto &Container = *Helper.Container;
353 ContainerVersion = Container.Version;
354 // Always >= BitstreamRemarkContainerType::First since it's unsigned.
355 if (Container.Type > static_cast<uint8_t>(BitstreamRemarkContainerType::Last))
356 return Helper.error("Invalid container type.");
357 ContainerType = static_cast<BitstreamRemarkContainerType>(Container.Type);
358 return Error::success();
359}
360
361Error BitstreamRemarkParser::processFileContainerMeta() {
362 if (Error E = processRemarkVersion())
363 return E;
364 if (Error E = processStrTab())
365 return E;
366 return Error::success();
367}
368
369Error BitstreamRemarkParser::processStrTab() {
370 auto &Helper = ParserHelper->MetaHelper;
371 if (!Helper.StrTabBuf)
372 return Helper.error("Missing string table.");
373 // Parse and assign the string table.
374 StrTab.emplace(*Helper.StrTabBuf);
375 return Error::success();
376}
377
378Error BitstreamRemarkParser::processRemarkVersion() {
379 auto &Helper = ParserHelper->MetaHelper;
380 if (!Helper.RemarkVersion)
381 return Helper.error("Missing remark version.");
382 RemarkVersion = *Helper.RemarkVersion;
383 return Error::success();
384}
385
386Error BitstreamRemarkParser::processExternalFilePath() {
387 auto &Helper = ParserHelper->MetaHelper;
388 if (!Helper.ExternalFilePath)
389 return Helper.error("Missing external file path.");
390
391 SmallString<80> FullPath(ExternalFilePrependPath);
392 sys::path::append(FullPath, *Helper.ExternalFilePath);
393
394 // External file: open the external file, parse it, check if its metadata
395 // matches the one from the separate metadata, then replace the current
396 // parser with the one parsing the remarks.
397 ErrorOr<std::unique_ptr<MemoryBuffer>> BufferOrErr =
398 MemoryBuffer::getFile(FullPath);
399 if (std::error_code EC = BufferOrErr.getError())
400 return createFileError(FullPath, EC);
401
402 TmpRemarkBuffer = std::move(*BufferOrErr);
403
404 // Don't try to parse the file if it's empty.
405 if (TmpRemarkBuffer->getBufferSize() == 0)
407
408 // Create a separate parser used for parsing the separate file.
409 ParserHelper.emplace(TmpRemarkBuffer->getBuffer());
410 if (Error E = parseMeta())
411 return E;
412
414 return ParserHelper->MetaHelper.error(
415 "Wrong container type in external file.");
416
417 return Error::success();
418}
419
420Expected<std::unique_ptr<Remark>> BitstreamRemarkParser::processRemark() {
421 auto &Helper = *ParserHelper->RemarksHelper;
422 std::unique_ptr<Remark> Result = std::make_unique<Remark>();
423 Remark &R = *Result;
424
425 if (!StrTab)
426 return Helper.error("Missing string table.");
427
428 if (!Helper.Type)
429 return Helper.error("Missing remark type.");
430
431 // Always >= Type::First since it's unsigned.
432 if (*Helper.Type > static_cast<uint8_t>(Type::Last))
433 return Helper.error("Unknown remark type.");
434
435 R.RemarkType = static_cast<Type>(*Helper.Type);
436
437 if (!Helper.RemarkNameIdx)
438 return Helper.error("Missing remark name.");
439
440 if (Expected<StringRef> RemarkName = (*StrTab)[*Helper.RemarkNameIdx])
441 R.RemarkName = *RemarkName;
442 else
443 return RemarkName.takeError();
444
445 if (!Helper.PassNameIdx)
446 return Helper.error("Missing remark pass.");
447
448 if (Expected<StringRef> PassName = (*StrTab)[*Helper.PassNameIdx])
449 R.PassName = *PassName;
450 else
451 return PassName.takeError();
452
453 if (!Helper.FunctionNameIdx)
454 return Helper.error("Missing remark function name.");
455
456 if (Expected<StringRef> FunctionName = (*StrTab)[*Helper.FunctionNameIdx])
457 R.FunctionName = *FunctionName;
458 else
459 return FunctionName.takeError();
460
461 if (Helper.Loc) {
462 Expected<StringRef> SourceFileName =
463 (*StrTab)[Helper.Loc->SourceFileNameIdx];
464 if (!SourceFileName)
465 return SourceFileName.takeError();
466 R.Loc.emplace();
467 R.Loc->SourceFilePath = *SourceFileName;
468 R.Loc->SourceLine = Helper.Loc->SourceLine;
469 R.Loc->SourceColumn = Helper.Loc->SourceColumn;
470 }
471
472 if (Helper.Hotness)
473 R.Hotness = *Helper.Hotness;
474
475 for (const BitstreamRemarkParserHelper::Argument &Arg : Helper.Args) {
476 if (!Arg.KeyIdx)
477 return Helper.error("Missing key in remark argument.");
478 if (!Arg.ValueIdx)
479 return Helper.error("Missing value in remark argument.");
480
481 // We have at least a key and a value, create an entry.
482 auto &RArg = R.Args.emplace_back();
483
484 if (Expected<StringRef> Key = (*StrTab)[*Arg.KeyIdx])
485 RArg.Key = *Key;
486 else
487 return Key.takeError();
488
489 if (Expected<StringRef> Value = (*StrTab)[*Arg.ValueIdx])
490 RArg.Val = *Value;
491 else
492 return Value.takeError();
493
494 if (Arg.Loc) {
495 if (Expected<StringRef> SourceFileName =
496 (*StrTab)[Arg.Loc->SourceFileNameIdx]) {
497 RArg.Loc.emplace();
498 RArg.Loc->SourceFilePath = *SourceFileName;
499 RArg.Loc->SourceLine = Arg.Loc->SourceLine;
500 RArg.Loc->SourceColumn = Arg.Loc->SourceColumn;
501 } else
502 return SourceFileName.takeError();
503 }
504 }
505
506 return std::move(Result);
507}
static Expected< unsigned > expectSubBlock(BitstreamCursor &Stream)
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
#define I(x, y, z)
Definition MD5.cpp:58
#define error(X)
static const char PassName[]
This represents a position within a bitcode file, implemented on top of a SimpleBitstreamCursor.
Expected< BitstreamEntry > advance(unsigned Flags=0)
Advance the current bitstream, returning the next entry in the stream.
std::error_code getError() const
Definition ErrorOr.h:152
Lightweight error class with error context and mandatory checking.
Definition Error.h:159
static ErrorSuccess success()
Create a success value.
Definition Error.h:336
Tagged union holding either a T or a Error.
Definition Error.h:485
Error takeError()
Take ownership of the stored error.
Definition Error.h:612
static ErrorOr< std::unique_ptr< MemoryBuffer > > getFile(const Twine &Filename, bool IsText=false, bool RequiresNullTerminator=true, bool IsVolatile=false, std::optional< Align > Alignment=std::nullopt)
Open the specified file as a MemoryBuffer, returning a new MemoryBuffer if successful,...
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
StringRef - Represent a constant reference to a string, i.e.
Definition StringRef.h:55
A raw_ostream that writes to an std::string.
std::optional< ContainerInfo > Container
The parsed content: depending on the container type, some fields might be empty.
std::optional< uint8_t > Type
The parsed content: depending on the remark, some fields might be empty.
Error parseNext()
Clear helper state and parse next remark block.
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
@ BLOCKINFO_BLOCK_ID
BLOCKINFO_BLOCK is used to define metadata about blocks, for example, standard abbrevs that should be...
constexpr StringLiteral RemarkDebugLocName("Remark debug location")
BitstreamRemarkContainerType
Type of the remark container.
@ RemarksFileExternal
Emit a link to an external remarks file (usually as a section of the object file, to enable discovery...
@ RemarksFile
Emit metadata and remarks into a file RemarksFile: | Meta: | | Container info | | Remark version | Re...
constexpr StringLiteral RemarkArgWithDebugLocName("Argument with debug location")
@ REMARK_BLOCK_ID
One remark entry is represented using a REMARK_BLOCK.
@ META_BLOCK_ID
The metadata block is mandatory.
constexpr uint64_t CurrentContainerVersion
The current version of the remark container.
constexpr StringLiteral MetaExternalFileName("External File")
constexpr StringLiteral MetaRemarkVersionName("Remark version")
Format
The format used for serializing/deserializing remarks.
constexpr StringLiteral MetaContainerInfoName("Container info")
Expected< std::unique_ptr< BitstreamRemarkParser > > createBitstreamParserFromMeta(StringRef Buf, std::optional< StringRef > ExternalFilePrependPath=std::nullopt)
constexpr StringLiteral RemarkHeaderName("Remark header")
constexpr StringLiteral RemarkArgWithoutDebugLocName("Argument")
constexpr uint64_t CurrentRemarkVersion
The current version of the remark entry.
Definition Remark.h:29
constexpr StringLiteral ContainerMagic("RMRK")
The magic number used for identifying remark blocks.
constexpr StringLiteral MetaStrTabName("String table")
Type
The type of the remark.
Definition Remark.h:66
constexpr StringLiteral RemarkHotnessName("Remark hotness")
LLVM_ABI void append(SmallVectorImpl< char > &path, const Twine &a, const Twine &b="", const Twine &c="", const Twine &d="")
Append to path.
Definition Path.cpp:456
This is an optimization pass for GlobalISel generic memory operations.
FunctionAddr VTableAddr Value
Definition InstrProf.h:137
Error createFileError(const Twine &F, Error E)
Concatenate a source file path and/or name with an Error.
Definition Error.h:1399
auto formatv(bool Validate, const char *Fmt, Ts &&...Vals)
LLVM_ATTRIBUTE_VISIBILITY_DEFAULT AnalysisKey InnerAnalysisManagerProxy< AnalysisManagerT, IRUnitT, ExtraArgTs... >::Key
Error make_error(ArgTs &&... Args)
Make a Error instance representing failure using the given error info type.
Definition Error.h:340
FunctionAddr VTableAddr Next
Definition InstrProf.h:141
Error parseRemark()
Parse the next remark. This populates the remark helper data.
Error parseMeta()
Parse all metadata blocks in the file. This populates the meta helper.
BitstreamMetaParserHelper MetaHelper
Helper to parse the metadata blocks in this bitstream.
BitstreamBlockInfo BlockInfo
The block info block.
BitstreamCursor Stream
The Bitstream reader.
std::optional< uint64_t > RemarkStartBitPos
The position of the first remark block we encounter after the initial metadata block.
std::optional< BitstreamRemarkParserHelper > RemarksHelper
Helper to parse the remark blocks in this bitstream.
Error parseBlockInfoBlock()
Parse the block info block containing all the abbrevs.
Error expectMagic()
Parse and validate the magic number.
Error parseMeta()
Parse and process the metadata of the buffer.
std::optional< ParsedStringTable > StrTab
The string table used for parsing strings.
std::unique_ptr< MemoryBuffer > TmpRemarkBuffer
Temporary remark buffer used when the remarks are stored separately.
uint64_t ContainerVersion
The common metadata used to decide how to parse the buffer.
std::optional< BitstreamParserHelper > ParserHelper
The buffer to parse.
Expected< std::unique_ptr< Remark > > next() override
If no error occurs, this returns a valid Remark object.
BitstreamRemarkParser(StringRef Buf)
Create a parser that expects to find a string table embedded in the stream.
bool IsMetaReady
Whether the metadata has already been parsed, so we can continue parsing remarks.
BitstreamRemarkContainerType ContainerType
std::string ExternalFilePrependPath
Path to prepend when opening an external remark file.
RemarkParser(Format ParserFormat)