[InstCombine] Signed saturation tests. NFC
[llvm-complete.git] / lib / Remarks / BitstreamRemarkParser.cpp
blob99a82e1ee3af4c20dcec70e6f230c3fa1b3741c2
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.
12 //===----------------------------------------------------------------------===//
14 #include "llvm/Remarks/BitstreamRemarkParser.h"
15 #include "BitstreamRemarkParser.h"
16 #include "llvm/Remarks/BitstreamRemarkContainer.h"
17 #include "llvm/Support/MemoryBuffer.h"
18 #include "llvm/Support/Path.h"
20 using namespace llvm;
21 using namespace llvm::remarks;
23 static Error unknownRecord(const char *BlockName, unsigned RecordID) {
24 return createStringError(
25 std::make_error_code(std::errc::illegal_byte_sequence),
26 "Error while parsing %s: unknown record entry (%lu).", BlockName,
27 RecordID);
30 static Error malformedRecord(const char *BlockName, const char *RecordName) {
31 return createStringError(
32 std::make_error_code(std::errc::illegal_byte_sequence),
33 "Error while parsing %s: malformed record entry (%s).", BlockName,
34 RecordName);
37 BitstreamMetaParserHelper::BitstreamMetaParserHelper(
38 BitstreamCursor &Stream, BitstreamBlockInfo &BlockInfo)
39 : Stream(Stream), BlockInfo(BlockInfo) {}
41 /// Parse a record and fill in the fields in the parser.
42 static Error parseRecord(BitstreamMetaParserHelper &Parser, unsigned Code) {
43 BitstreamCursor &Stream = Parser.Stream;
44 // Note: 2 is used here because it's the max number of fields we have per
45 // record.
46 SmallVector<uint64_t, 2> Record;
47 StringRef Blob;
48 Expected<unsigned> RecordID = Stream.readRecord(Code, Record, &Blob);
49 if (!RecordID)
50 return RecordID.takeError();
52 switch (*RecordID) {
53 case RECORD_META_CONTAINER_INFO: {
54 if (Record.size() != 2)
55 return malformedRecord("BLOCK_META", "RECORD_META_CONTAINER_INFO");
56 Parser.ContainerVersion = Record[0];
57 Parser.ContainerType = Record[1];
58 break;
60 case RECORD_META_REMARK_VERSION: {
61 if (Record.size() != 1)
62 return malformedRecord("BLOCK_META", "RECORD_META_REMARK_VERSION");
63 Parser.RemarkVersion = Record[0];
64 break;
66 case RECORD_META_STRTAB: {
67 if (Record.size() != 0)
68 return malformedRecord("BLOCK_META", "RECORD_META_STRTAB");
69 Parser.StrTabBuf = Blob;
70 break;
72 case RECORD_META_EXTERNAL_FILE: {
73 if (Record.size() != 0)
74 return malformedRecord("BLOCK_META", "RECORD_META_EXTERNAL_FILE");
75 Parser.ExternalFilePath = Blob;
76 break;
78 default:
79 return unknownRecord("BLOCK_META", *RecordID);
81 return Error::success();
84 BitstreamRemarkParserHelper::BitstreamRemarkParserHelper(
85 BitstreamCursor &Stream)
86 : Stream(Stream) {}
88 /// Parse a record and fill in the fields in the parser.
89 static Error parseRecord(BitstreamRemarkParserHelper &Parser, unsigned Code) {
90 BitstreamCursor &Stream = Parser.Stream;
91 // Note: 5 is used here because it's the max number of fields we have per
92 // record.
93 SmallVector<uint64_t, 5> Record;
94 StringRef Blob;
95 Expected<unsigned> RecordID = Stream.readRecord(Code, Record, &Blob);
96 if (!RecordID)
97 return RecordID.takeError();
99 switch (*RecordID) {
100 case RECORD_REMARK_HEADER: {
101 if (Record.size() != 4)
102 return malformedRecord("BLOCK_REMARK", "RECORD_REMARK_HEADER");
103 Parser.Type = Record[0];
104 Parser.RemarkNameIdx = Record[1];
105 Parser.PassNameIdx = Record[2];
106 Parser.FunctionNameIdx = Record[3];
107 break;
109 case RECORD_REMARK_DEBUG_LOC: {
110 if (Record.size() != 3)
111 return malformedRecord("BLOCK_REMARK", "RECORD_REMARK_DEBUG_LOC");
112 Parser.SourceFileNameIdx = Record[0];
113 Parser.SourceLine = Record[1];
114 Parser.SourceColumn = Record[2];
115 break;
117 case RECORD_REMARK_HOTNESS: {
118 if (Record.size() != 1)
119 return malformedRecord("BLOCK_REMARK", "RECORD_REMARK_HOTNESS");
120 Parser.Hotness = Record[0];
121 break;
123 case RECORD_REMARK_ARG_WITH_DEBUGLOC: {
124 if (Record.size() != 5)
125 return malformedRecord("BLOCK_REMARK", "RECORD_REMARK_ARG_WITH_DEBUGLOC");
126 // Create a temporary argument. Use that as a valid memory location for this
127 // argument entry.
128 Parser.TmpArgs.emplace_back();
129 Parser.TmpArgs.back().KeyIdx = Record[0];
130 Parser.TmpArgs.back().ValueIdx = Record[1];
131 Parser.TmpArgs.back().SourceFileNameIdx = Record[2];
132 Parser.TmpArgs.back().SourceLine = Record[3];
133 Parser.TmpArgs.back().SourceColumn = Record[4];
134 Parser.Args =
135 ArrayRef<BitstreamRemarkParserHelper::Argument>(Parser.TmpArgs);
136 break;
138 case RECORD_REMARK_ARG_WITHOUT_DEBUGLOC: {
139 if (Record.size() != 2)
140 return malformedRecord("BLOCK_REMARK",
141 "RECORD_REMARK_ARG_WITHOUT_DEBUGLOC");
142 // Create a temporary argument. Use that as a valid memory location for this
143 // argument entry.
144 Parser.TmpArgs.emplace_back();
145 Parser.TmpArgs.back().KeyIdx = Record[0];
146 Parser.TmpArgs.back().ValueIdx = Record[1];
147 Parser.Args =
148 ArrayRef<BitstreamRemarkParserHelper::Argument>(Parser.TmpArgs);
149 break;
151 default:
152 return unknownRecord("BLOCK_REMARK", *RecordID);
154 return Error::success();
157 template <typename T>
158 static Error parseBlock(T &ParserHelper, unsigned BlockID,
159 const char *BlockName) {
160 BitstreamCursor &Stream = ParserHelper.Stream;
161 Expected<BitstreamEntry> Next = Stream.advance();
162 if (!Next)
163 return Next.takeError();
164 if (Next->Kind != BitstreamEntry::SubBlock || Next->ID != BlockID)
165 return createStringError(
166 std::make_error_code(std::errc::illegal_byte_sequence),
167 "Error while parsing %s: expecting [ENTER_SUBBLOCK, %s, ...].",
168 BlockName, BlockName);
169 if (Stream.EnterSubBlock(BlockID))
170 return createStringError(
171 std::make_error_code(std::errc::illegal_byte_sequence),
172 "Error while entering %s.", BlockName);
174 // Stop when there is nothing to read anymore or when we encounter an
175 // END_BLOCK.
176 while (!Stream.AtEndOfStream()) {
177 Expected<BitstreamEntry> Next = Stream.advance();
178 if (!Next)
179 return Next.takeError();
180 switch (Next->Kind) {
181 case BitstreamEntry::EndBlock:
182 return Error::success();
183 case BitstreamEntry::Error:
184 case BitstreamEntry::SubBlock:
185 return createStringError(
186 std::make_error_code(std::errc::illegal_byte_sequence),
187 "Error while parsing %s: expecting records.", BlockName);
188 case BitstreamEntry::Record:
189 if (Error E = parseRecord(ParserHelper, Next->ID))
190 return E;
191 continue;
194 // If we're here, it means we didn't get an END_BLOCK yet, but we're at the
195 // end of the stream. In this case, error.
196 return createStringError(
197 std::make_error_code(std::errc::illegal_byte_sequence),
198 "Error while parsing %s: unterminated block.", BlockName);
201 Error BitstreamMetaParserHelper::parse() {
202 return parseBlock(*this, META_BLOCK_ID, "META_BLOCK");
205 Error BitstreamRemarkParserHelper::parse() {
206 return parseBlock(*this, REMARK_BLOCK_ID, "REMARK_BLOCK");
209 BitstreamParserHelper::BitstreamParserHelper(StringRef Buffer)
210 : Stream(Buffer) {}
212 Expected<std::array<char, 4>> BitstreamParserHelper::parseMagic() {
213 std::array<char, 4> Result;
214 for (unsigned i = 0; i < 4; ++i)
215 if (Expected<unsigned> R = Stream.Read(8))
216 Result[i] = *R;
217 else
218 return R.takeError();
219 return Result;
222 Error BitstreamParserHelper::parseBlockInfoBlock() {
223 Expected<BitstreamEntry> Next = Stream.advance();
224 if (!Next)
225 return Next.takeError();
226 if (Next->Kind != BitstreamEntry::SubBlock ||
227 Next->ID != llvm::bitc::BLOCKINFO_BLOCK_ID)
228 return createStringError(
229 std::make_error_code(std::errc::illegal_byte_sequence),
230 "Error while parsing BLOCKINFO_BLOCK: expecting [ENTER_SUBBLOCK, "
231 "BLOCKINFO_BLOCK, ...].");
233 Expected<Optional<BitstreamBlockInfo>> MaybeBlockInfo =
234 Stream.ReadBlockInfoBlock();
235 if (!MaybeBlockInfo)
236 return MaybeBlockInfo.takeError();
238 if (!*MaybeBlockInfo)
239 return createStringError(
240 std::make_error_code(std::errc::illegal_byte_sequence),
241 "Error while parsing BLOCKINFO_BLOCK.");
243 BlockInfo = **MaybeBlockInfo;
245 Stream.setBlockInfo(&BlockInfo);
246 return Error::success();
249 static Expected<bool> isBlock(BitstreamCursor &Stream, unsigned BlockID) {
250 bool Result = false;
251 uint64_t PreviousBitNo = Stream.GetCurrentBitNo();
252 Expected<BitstreamEntry> Next = Stream.advance();
253 if (!Next)
254 return Next.takeError();
255 switch (Next->Kind) {
256 case BitstreamEntry::SubBlock:
257 // Check for the block id.
258 Result = Next->ID == BlockID;
259 break;
260 case BitstreamEntry::Error:
261 return createStringError(
262 std::make_error_code(std::errc::illegal_byte_sequence),
263 "Unexpected error while parsing bitstream.");
264 default:
265 Result = false;
266 break;
268 if (Error E = Stream.JumpToBit(PreviousBitNo))
269 return std::move(E);
270 return Result;
273 Expected<bool> BitstreamParserHelper::isMetaBlock() {
274 return isBlock(Stream, META_BLOCK_ID);
277 Expected<bool> BitstreamParserHelper::isRemarkBlock() {
278 return isBlock(Stream, META_BLOCK_ID);
281 static Error validateMagicNumber(StringRef Magic) {
282 if (Magic != remarks::ContainerMagic)
283 return createStringError(std::make_error_code(std::errc::invalid_argument),
284 "Unknown magic number: expecting %s, got %.4s.",
285 remarks::ContainerMagic.data(), Magic.data());
286 return Error::success();
289 static Error advanceToMetaBlock(BitstreamParserHelper &Helper) {
290 Expected<std::array<char, 4>> Magic = Helper.parseMagic();
291 if (!Magic)
292 return Magic.takeError();
293 if (Error E = validateMagicNumber(StringRef(Magic->data(), Magic->size())))
294 return E;
295 if (Error E = Helper.parseBlockInfoBlock())
296 return E;
297 Expected<bool> isMetaBlock = Helper.isMetaBlock();
298 if (!isMetaBlock)
299 return isMetaBlock.takeError();
300 if (!*isMetaBlock)
301 return createStringError(
302 std::make_error_code(std::errc::illegal_byte_sequence),
303 "Expecting META_BLOCK after the BLOCKINFO_BLOCK.");
304 return Error::success();
307 Expected<std::unique_ptr<BitstreamRemarkParser>>
308 remarks::createBitstreamParserFromMeta(
309 StringRef Buf, Optional<ParsedStringTable> StrTab,
310 Optional<StringRef> ExternalFilePrependPath) {
311 BitstreamParserHelper Helper(Buf);
312 Expected<std::array<char, 4>> Magic = Helper.parseMagic();
313 if (!Magic)
314 return Magic.takeError();
316 if (Error E = validateMagicNumber(StringRef(Magic->data(), Magic->size())))
317 return std::move(E);
319 auto Parser =
320 StrTab ? std::make_unique<BitstreamRemarkParser>(Buf, std::move(*StrTab))
321 : std::make_unique<BitstreamRemarkParser>(Buf);
323 if (ExternalFilePrependPath)
324 Parser->ExternalFilePrependPath = *ExternalFilePrependPath;
326 return std::move(Parser);
329 Expected<std::unique_ptr<Remark>> BitstreamRemarkParser::next() {
330 if (ParserHelper.atEndOfStream())
331 return make_error<EndOfFileError>();
333 if (!ReadyToParseRemarks) {
334 if (Error E = parseMeta())
335 return std::move(E);
336 ReadyToParseRemarks = true;
339 return parseRemark();
342 Error BitstreamRemarkParser::parseMeta() {
343 // Advance and to the meta block.
344 if (Error E = advanceToMetaBlock(ParserHelper))
345 return E;
347 BitstreamMetaParserHelper MetaHelper(ParserHelper.Stream,
348 ParserHelper.BlockInfo);
349 if (Error E = MetaHelper.parse())
350 return E;
352 if (Error E = processCommonMeta(MetaHelper))
353 return E;
355 switch (ContainerType) {
356 case BitstreamRemarkContainerType::Standalone:
357 return processStandaloneMeta(MetaHelper);
358 case BitstreamRemarkContainerType::SeparateRemarksFile:
359 return processSeparateRemarksFileMeta(MetaHelper);
360 case BitstreamRemarkContainerType::SeparateRemarksMeta:
361 return processSeparateRemarksMetaMeta(MetaHelper);
363 llvm_unreachable("Unknown BitstreamRemarkContainerType enum");
366 Error BitstreamRemarkParser::processCommonMeta(
367 BitstreamMetaParserHelper &MetaHelper) {
368 if (Optional<uint64_t> Version = MetaHelper.ContainerVersion)
369 ContainerVersion = *Version;
370 else
371 return createStringError(
372 std::make_error_code(std::errc::illegal_byte_sequence),
373 "Error while parsing BLOCK_META: missing container version.");
375 if (Optional<uint8_t> Type = MetaHelper.ContainerType) {
376 // Always >= BitstreamRemarkContainerType::First since it's unsigned.
377 if (*Type > static_cast<uint8_t>(BitstreamRemarkContainerType::Last))
378 return createStringError(
379 std::make_error_code(std::errc::illegal_byte_sequence),
380 "Error while parsing BLOCK_META: invalid container type.");
382 ContainerType = static_cast<BitstreamRemarkContainerType>(*Type);
383 } else
384 return createStringError(
385 std::make_error_code(std::errc::illegal_byte_sequence),
386 "Error while parsing BLOCK_META: missing container type.");
388 return Error::success();
391 static Error processStrTab(BitstreamRemarkParser &P,
392 Optional<StringRef> StrTabBuf) {
393 if (!StrTabBuf)
394 return createStringError(
395 std::make_error_code(std::errc::illegal_byte_sequence),
396 "Error while parsing BLOCK_META: missing string table.");
397 // Parse and assign the string table.
398 P.StrTab.emplace(*StrTabBuf);
399 return Error::success();
402 static Error processRemarkVersion(BitstreamRemarkParser &P,
403 Optional<uint64_t> RemarkVersion) {
404 if (!RemarkVersion)
405 return createStringError(
406 std::make_error_code(std::errc::illegal_byte_sequence),
407 "Error while parsing BLOCK_META: missing remark version.");
408 P.RemarkVersion = *RemarkVersion;
409 return Error::success();
412 Error BitstreamRemarkParser::processExternalFilePath(
413 Optional<StringRef> ExternalFilePath) {
414 if (!ExternalFilePath)
415 return createStringError(
416 std::make_error_code(std::errc::illegal_byte_sequence),
417 "Error while parsing BLOCK_META: missing external file path.");
419 SmallString<80> FullPath(ExternalFilePrependPath);
420 sys::path::append(FullPath, *ExternalFilePath);
422 // External file: open the external file, parse it, check if its metadata
423 // matches the one from the separate metadata, then replace the current parser
424 // with the one parsing the remarks.
425 ErrorOr<std::unique_ptr<MemoryBuffer>> BufferOrErr =
426 MemoryBuffer::getFile(FullPath);
427 if (std::error_code EC = BufferOrErr.getError())
428 return createFileError(FullPath, EC);
429 TmpRemarkBuffer = std::move(*BufferOrErr);
431 // Create a separate parser used for parsing the separate file.
432 ParserHelper = BitstreamParserHelper(TmpRemarkBuffer->getBuffer());
433 // Advance and check until we can parse the meta block.
434 if (Error E = advanceToMetaBlock(ParserHelper))
435 return E;
436 // Parse the meta from the separate file.
437 // Note: here we overwrite the BlockInfo with the one from the file. This will
438 // be used to parse the rest of the file.
439 BitstreamMetaParserHelper SeparateMetaHelper(ParserHelper.Stream,
440 ParserHelper.BlockInfo);
441 if (Error E = SeparateMetaHelper.parse())
442 return E;
444 uint64_t PreviousContainerVersion = ContainerVersion;
445 if (Error E = processCommonMeta(SeparateMetaHelper))
446 return E;
448 if (ContainerType != BitstreamRemarkContainerType::SeparateRemarksFile)
449 return createStringError(
450 std::make_error_code(std::errc::illegal_byte_sequence),
451 "Error while parsing external file's BLOCK_META: wrong container "
452 "type.");
454 if (PreviousContainerVersion != ContainerVersion)
455 return createStringError(
456 std::make_error_code(std::errc::illegal_byte_sequence),
457 "Error while parsing external file's BLOCK_META: mismatching versions: "
458 "original meta: %lu, external file meta: %lu.",
459 PreviousContainerVersion, ContainerVersion);
461 // Process the meta from the separate file.
462 return processSeparateRemarksFileMeta(SeparateMetaHelper);
465 Error BitstreamRemarkParser::processStandaloneMeta(
466 BitstreamMetaParserHelper &Helper) {
467 if (Error E = processStrTab(*this, Helper.StrTabBuf))
468 return E;
469 return processRemarkVersion(*this, Helper.RemarkVersion);
472 Error BitstreamRemarkParser::processSeparateRemarksFileMeta(
473 BitstreamMetaParserHelper &Helper) {
474 return processRemarkVersion(*this, Helper.RemarkVersion);
477 Error BitstreamRemarkParser::processSeparateRemarksMetaMeta(
478 BitstreamMetaParserHelper &Helper) {
479 if (Error E = processStrTab(*this, Helper.StrTabBuf))
480 return E;
481 return processExternalFilePath(Helper.ExternalFilePath);
484 Expected<std::unique_ptr<Remark>> BitstreamRemarkParser::parseRemark() {
485 BitstreamRemarkParserHelper RemarkHelper(ParserHelper.Stream);
486 if (Error E = RemarkHelper.parse())
487 return std::move(E);
489 return processRemark(RemarkHelper);
492 Expected<std::unique_ptr<Remark>>
493 BitstreamRemarkParser::processRemark(BitstreamRemarkParserHelper &Helper) {
494 std::unique_ptr<Remark> Result = std::make_unique<Remark>();
495 Remark &R = *Result;
497 if (StrTab == None)
498 return createStringError(
499 std::make_error_code(std::errc::invalid_argument),
500 "Error while parsing BLOCK_REMARK: missing string table.");
502 if (!Helper.Type)
503 return createStringError(
504 std::make_error_code(std::errc::illegal_byte_sequence),
505 "Error while parsing BLOCK_REMARK: missing remark type.");
507 // Always >= Type::First since it's unsigned.
508 if (*Helper.Type > static_cast<uint8_t>(Type::Last))
509 return createStringError(
510 std::make_error_code(std::errc::illegal_byte_sequence),
511 "Error while parsing BLOCK_REMARK: unknown remark type.");
513 R.RemarkType = static_cast<Type>(*Helper.Type);
515 if (!Helper.RemarkNameIdx)
516 return createStringError(
517 std::make_error_code(std::errc::illegal_byte_sequence),
518 "Error while parsing BLOCK_REMARK: missing remark name.");
520 if (Expected<StringRef> RemarkName = (*StrTab)[*Helper.RemarkNameIdx])
521 R.RemarkName = *RemarkName;
522 else
523 return RemarkName.takeError();
525 if (!Helper.PassNameIdx)
526 return createStringError(
527 std::make_error_code(std::errc::illegal_byte_sequence),
528 "Error while parsing BLOCK_REMARK: missing remark pass.");
530 if (Expected<StringRef> PassName = (*StrTab)[*Helper.PassNameIdx])
531 R.PassName = *PassName;
532 else
533 return PassName.takeError();
535 if (!Helper.FunctionNameIdx)
536 return createStringError(
537 std::make_error_code(std::errc::illegal_byte_sequence),
538 "Error while parsing BLOCK_REMARK: missing remark function name.");
539 if (Expected<StringRef> FunctionName = (*StrTab)[*Helper.FunctionNameIdx])
540 R.FunctionName = *FunctionName;
541 else
542 return FunctionName.takeError();
544 if (Helper.SourceFileNameIdx && Helper.SourceLine && Helper.SourceColumn) {
545 Expected<StringRef> SourceFileName = (*StrTab)[*Helper.SourceFileNameIdx];
546 if (!SourceFileName)
547 return SourceFileName.takeError();
548 R.Loc.emplace();
549 R.Loc->SourceFilePath = *SourceFileName;
550 R.Loc->SourceLine = *Helper.SourceLine;
551 R.Loc->SourceColumn = *Helper.SourceColumn;
554 if (Helper.Hotness)
555 R.Hotness = *Helper.Hotness;
557 if (!Helper.Args)
558 return std::move(Result);
560 for (const BitstreamRemarkParserHelper::Argument &Arg : *Helper.Args) {
561 if (!Arg.KeyIdx)
562 return createStringError(
563 std::make_error_code(std::errc::illegal_byte_sequence),
564 "Error while parsing BLOCK_REMARK: missing key in remark argument.");
565 if (!Arg.ValueIdx)
566 return createStringError(
567 std::make_error_code(std::errc::illegal_byte_sequence),
568 "Error while parsing BLOCK_REMARK: missing value in remark "
569 "argument.");
571 // We have at least a key and a value, create an entry.
572 R.Args.emplace_back();
574 if (Expected<StringRef> Key = (*StrTab)[*Arg.KeyIdx])
575 R.Args.back().Key = *Key;
576 else
577 return Key.takeError();
579 if (Expected<StringRef> Value = (*StrTab)[*Arg.ValueIdx])
580 R.Args.back().Val = *Value;
581 else
582 return Value.takeError();
584 if (Arg.SourceFileNameIdx && Arg.SourceLine && Arg.SourceColumn) {
585 if (Expected<StringRef> SourceFileName =
586 (*StrTab)[*Arg.SourceFileNameIdx]) {
587 R.Args.back().Loc.emplace();
588 R.Args.back().Loc->SourceFilePath = *SourceFileName;
589 R.Args.back().Loc->SourceLine = *Arg.SourceLine;
590 R.Args.back().Loc->SourceColumn = *Arg.SourceColumn;
591 } else
592 return SourceFileName.takeError();
596 return std::move(Result);