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