• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/Remarks/BitstreamRemarkContainer.h"
17 #include "llvm/Support/MemoryBuffer.h"
18 #include "llvm/Support/Path.h"
19 
20 using namespace llvm;
21 using namespace llvm::remarks;
22 
unknownRecord(const char * BlockName,unsigned RecordID)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);
28 }
29 
malformedRecord(const char * BlockName,const char * RecordName)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);
35 }
36 
BitstreamMetaParserHelper(BitstreamCursor & Stream,BitstreamBlockInfo & BlockInfo)37 BitstreamMetaParserHelper::BitstreamMetaParserHelper(
38     BitstreamCursor &Stream, BitstreamBlockInfo &BlockInfo)
39     : Stream(Stream), BlockInfo(BlockInfo) {}
40 
41 /// Parse a record and fill in the fields in the parser.
parseRecord(BitstreamMetaParserHelper & Parser,unsigned Code)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();
51 
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;
59   }
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;
65   }
66   case RECORD_META_STRTAB: {
67     if (Record.size() != 0)
68       return malformedRecord("BLOCK_META", "RECORD_META_STRTAB");
69     Parser.StrTabBuf = Blob;
70     break;
71   }
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;
77   }
78   default:
79     return unknownRecord("BLOCK_META", *RecordID);
80   }
81   return Error::success();
82 }
83 
BitstreamRemarkParserHelper(BitstreamCursor & Stream)84 BitstreamRemarkParserHelper::BitstreamRemarkParserHelper(
85     BitstreamCursor &Stream)
86     : Stream(Stream) {}
87 
88 /// Parse a record and fill in the fields in the parser.
parseRecord(BitstreamRemarkParserHelper & Parser,unsigned Code)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();
98 
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;
108   }
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;
116   }
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;
122   }
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;
137   }
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;
150   }
151   default:
152     return unknownRecord("BLOCK_REMARK", *RecordID);
153   }
154   return Error::success();
155 }
156 
157 template <typename T>
parseBlock(T & ParserHelper,unsigned BlockID,const char * BlockName)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);
173 
174   // Stop when there is nothing to read anymore or when we encounter an
175   // END_BLOCK.
176   while (!Stream.AtEndOfStream()) {
177     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;
192     }
193   }
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);
199 }
200 
parse()201 Error BitstreamMetaParserHelper::parse() {
202   return parseBlock(*this, META_BLOCK_ID, "META_BLOCK");
203 }
204 
parse()205 Error BitstreamRemarkParserHelper::parse() {
206   return parseBlock(*this, REMARK_BLOCK_ID, "REMARK_BLOCK");
207 }
208 
BitstreamParserHelper(StringRef Buffer)209 BitstreamParserHelper::BitstreamParserHelper(StringRef Buffer)
210     : Stream(Buffer) {}
211 
parseMagic()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;
220 }
221 
parseBlockInfoBlock()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, ...].");
232 
233   Expected<Optional<BitstreamBlockInfo>> MaybeBlockInfo =
234       Stream.ReadBlockInfoBlock();
235   if (!MaybeBlockInfo)
236     return MaybeBlockInfo.takeError();
237 
238   if (!*MaybeBlockInfo)
239     return createStringError(
240         std::make_error_code(std::errc::illegal_byte_sequence),
241         "Error while parsing BLOCKINFO_BLOCK.");
242 
243   BlockInfo = **MaybeBlockInfo;
244 
245   Stream.setBlockInfo(&BlockInfo);
246   return Error::success();
247 }
248 
isBlock(BitstreamCursor & Stream,unsigned BlockID)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;
267   }
268   if (Error E = Stream.JumpToBit(PreviousBitNo))
269     return std::move(E);
270   return Result;
271 }
272 
isMetaBlock()273 Expected<bool> BitstreamParserHelper::isMetaBlock() {
274   return isBlock(Stream, META_BLOCK_ID);
275 }
276 
isRemarkBlock()277 Expected<bool> BitstreamParserHelper::isRemarkBlock() {
278   return isBlock(Stream, META_BLOCK_ID);
279 }
280 
validateMagicNumber(StringRef MagicNumber)281 static Error validateMagicNumber(StringRef MagicNumber) {
282   if (MagicNumber != 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(), MagicNumber.data());
286   return Error::success();
287 }
288 
advanceToMetaBlock(BitstreamParserHelper & Helper)289 static Error advanceToMetaBlock(BitstreamParserHelper &Helper) {
290   Expected<std::array<char, 4>> MagicNumber = Helper.parseMagic();
291   if (!MagicNumber)
292     return MagicNumber.takeError();
293   if (Error E = validateMagicNumber(
294           StringRef(MagicNumber->data(), MagicNumber->size())))
295     return E;
296   if (Error E = Helper.parseBlockInfoBlock())
297     return E;
298   Expected<bool> isMetaBlock = Helper.isMetaBlock();
299   if (!isMetaBlock)
300     return isMetaBlock.takeError();
301   if (!*isMetaBlock)
302     return createStringError(
303         std::make_error_code(std::errc::illegal_byte_sequence),
304         "Expecting META_BLOCK after the BLOCKINFO_BLOCK.");
305   return Error::success();
306 }
307 
308 Expected<std::unique_ptr<BitstreamRemarkParser>>
createBitstreamParserFromMeta(StringRef Buf,Optional<ParsedStringTable> StrTab,Optional<StringRef> ExternalFilePrependPath)309 remarks::createBitstreamParserFromMeta(
310     StringRef Buf, Optional<ParsedStringTable> StrTab,
311     Optional<StringRef> ExternalFilePrependPath) {
312   BitstreamParserHelper Helper(Buf);
313   Expected<std::array<char, 4>> MagicNumber = Helper.parseMagic();
314   if (!MagicNumber)
315     return MagicNumber.takeError();
316 
317   if (Error E = validateMagicNumber(
318           StringRef(MagicNumber->data(), MagicNumber->size())))
319     return std::move(E);
320 
321   auto Parser =
322       StrTab ? std::make_unique<BitstreamRemarkParser>(Buf, std::move(*StrTab))
323              : std::make_unique<BitstreamRemarkParser>(Buf);
324 
325   if (ExternalFilePrependPath)
326     Parser->ExternalFilePrependPath = *ExternalFilePrependPath;
327 
328   return std::move(Parser);
329 }
330 
next()331 Expected<std::unique_ptr<Remark>> BitstreamRemarkParser::next() {
332   if (ParserHelper.atEndOfStream())
333     return make_error<EndOfFileError>();
334 
335   if (!ReadyToParseRemarks) {
336     if (Error E = parseMeta())
337       return std::move(E);
338     ReadyToParseRemarks = true;
339   }
340 
341   return parseRemark();
342 }
343 
parseMeta()344 Error BitstreamRemarkParser::parseMeta() {
345   // Advance and to the meta block.
346   if (Error E = advanceToMetaBlock(ParserHelper))
347     return E;
348 
349   BitstreamMetaParserHelper MetaHelper(ParserHelper.Stream,
350                                        ParserHelper.BlockInfo);
351   if (Error E = MetaHelper.parse())
352     return E;
353 
354   if (Error E = processCommonMeta(MetaHelper))
355     return E;
356 
357   switch (ContainerType) {
358   case BitstreamRemarkContainerType::Standalone:
359     return processStandaloneMeta(MetaHelper);
360   case BitstreamRemarkContainerType::SeparateRemarksFile:
361     return processSeparateRemarksFileMeta(MetaHelper);
362   case BitstreamRemarkContainerType::SeparateRemarksMeta:
363     return processSeparateRemarksMetaMeta(MetaHelper);
364   }
365   llvm_unreachable("Unknown BitstreamRemarkContainerType enum");
366 }
367 
processCommonMeta(BitstreamMetaParserHelper & Helper)368 Error BitstreamRemarkParser::processCommonMeta(
369     BitstreamMetaParserHelper &Helper) {
370   if (Optional<uint64_t> Version = Helper.ContainerVersion)
371     ContainerVersion = *Version;
372   else
373     return createStringError(
374         std::make_error_code(std::errc::illegal_byte_sequence),
375         "Error while parsing BLOCK_META: missing container version.");
376 
377   if (Optional<uint8_t> Type = Helper.ContainerType) {
378     // Always >= BitstreamRemarkContainerType::First since it's unsigned.
379     if (*Type > static_cast<uint8_t>(BitstreamRemarkContainerType::Last))
380       return createStringError(
381           std::make_error_code(std::errc::illegal_byte_sequence),
382           "Error while parsing BLOCK_META: invalid container type.");
383 
384     ContainerType = static_cast<BitstreamRemarkContainerType>(*Type);
385   } else
386     return createStringError(
387         std::make_error_code(std::errc::illegal_byte_sequence),
388         "Error while parsing BLOCK_META: missing container type.");
389 
390   return Error::success();
391 }
392 
processStrTab(BitstreamRemarkParser & P,Optional<StringRef> StrTabBuf)393 static Error processStrTab(BitstreamRemarkParser &P,
394                            Optional<StringRef> StrTabBuf) {
395   if (!StrTabBuf)
396     return createStringError(
397         std::make_error_code(std::errc::illegal_byte_sequence),
398         "Error while parsing BLOCK_META: missing string table.");
399   // Parse and assign the string table.
400   P.StrTab.emplace(*StrTabBuf);
401   return Error::success();
402 }
403 
processRemarkVersion(BitstreamRemarkParser & P,Optional<uint64_t> RemarkVersion)404 static Error processRemarkVersion(BitstreamRemarkParser &P,
405                                   Optional<uint64_t> RemarkVersion) {
406   if (!RemarkVersion)
407     return createStringError(
408         std::make_error_code(std::errc::illegal_byte_sequence),
409         "Error while parsing BLOCK_META: missing remark version.");
410   P.RemarkVersion = *RemarkVersion;
411   return Error::success();
412 }
413 
processExternalFilePath(Optional<StringRef> ExternalFilePath)414 Error BitstreamRemarkParser::processExternalFilePath(
415     Optional<StringRef> ExternalFilePath) {
416   if (!ExternalFilePath)
417     return createStringError(
418         std::make_error_code(std::errc::illegal_byte_sequence),
419         "Error while parsing BLOCK_META: missing external file path.");
420 
421   SmallString<80> FullPath(ExternalFilePrependPath);
422   sys::path::append(FullPath, *ExternalFilePath);
423 
424   // External file: open the external file, parse it, check if its metadata
425   // matches the one from the separate metadata, then replace the current parser
426   // with the one parsing the remarks.
427   ErrorOr<std::unique_ptr<MemoryBuffer>> BufferOrErr =
428       MemoryBuffer::getFile(FullPath);
429   if (std::error_code EC = BufferOrErr.getError())
430     return createFileError(FullPath, EC);
431 
432   TmpRemarkBuffer = std::move(*BufferOrErr);
433 
434   // Don't try to parse the file if it's empty.
435   if (TmpRemarkBuffer->getBufferSize() == 0)
436     return make_error<EndOfFileError>();
437 
438   // Create a separate parser used for parsing the separate file.
439   ParserHelper = BitstreamParserHelper(TmpRemarkBuffer->getBuffer());
440   // Advance and check until we can parse the meta block.
441   if (Error E = advanceToMetaBlock(ParserHelper))
442     return E;
443   // Parse the meta from the separate file.
444   // Note: here we overwrite the BlockInfo with the one from the file. This will
445   // be used to parse the rest of the file.
446   BitstreamMetaParserHelper SeparateMetaHelper(ParserHelper.Stream,
447                                                ParserHelper.BlockInfo);
448   if (Error E = SeparateMetaHelper.parse())
449     return E;
450 
451   uint64_t PreviousContainerVersion = ContainerVersion;
452   if (Error E = processCommonMeta(SeparateMetaHelper))
453     return E;
454 
455   if (ContainerType != BitstreamRemarkContainerType::SeparateRemarksFile)
456     return createStringError(
457         std::make_error_code(std::errc::illegal_byte_sequence),
458         "Error while parsing external file's BLOCK_META: wrong container "
459         "type.");
460 
461   if (PreviousContainerVersion != ContainerVersion)
462     return createStringError(
463         std::make_error_code(std::errc::illegal_byte_sequence),
464         "Error while parsing external file's BLOCK_META: mismatching versions: "
465         "original meta: %lu, external file meta: %lu.",
466         PreviousContainerVersion, ContainerVersion);
467 
468   // Process the meta from the separate file.
469   return processSeparateRemarksFileMeta(SeparateMetaHelper);
470 }
471 
processStandaloneMeta(BitstreamMetaParserHelper & Helper)472 Error BitstreamRemarkParser::processStandaloneMeta(
473     BitstreamMetaParserHelper &Helper) {
474   if (Error E = processStrTab(*this, Helper.StrTabBuf))
475     return E;
476   return processRemarkVersion(*this, Helper.RemarkVersion);
477 }
478 
processSeparateRemarksFileMeta(BitstreamMetaParserHelper & Helper)479 Error BitstreamRemarkParser::processSeparateRemarksFileMeta(
480     BitstreamMetaParserHelper &Helper) {
481   return processRemarkVersion(*this, Helper.RemarkVersion);
482 }
483 
processSeparateRemarksMetaMeta(BitstreamMetaParserHelper & Helper)484 Error BitstreamRemarkParser::processSeparateRemarksMetaMeta(
485     BitstreamMetaParserHelper &Helper) {
486   if (Error E = processStrTab(*this, Helper.StrTabBuf))
487     return E;
488   return processExternalFilePath(Helper.ExternalFilePath);
489 }
490 
parseRemark()491 Expected<std::unique_ptr<Remark>> BitstreamRemarkParser::parseRemark() {
492   BitstreamRemarkParserHelper RemarkHelper(ParserHelper.Stream);
493   if (Error E = RemarkHelper.parse())
494     return std::move(E);
495 
496   return processRemark(RemarkHelper);
497 }
498 
499 Expected<std::unique_ptr<Remark>>
processRemark(BitstreamRemarkParserHelper & Helper)500 BitstreamRemarkParser::processRemark(BitstreamRemarkParserHelper &Helper) {
501   std::unique_ptr<Remark> Result = std::make_unique<Remark>();
502   Remark &R = *Result;
503 
504   if (StrTab == None)
505     return createStringError(
506         std::make_error_code(std::errc::invalid_argument),
507         "Error while parsing BLOCK_REMARK: missing string table.");
508 
509   if (!Helper.Type)
510     return createStringError(
511         std::make_error_code(std::errc::illegal_byte_sequence),
512         "Error while parsing BLOCK_REMARK: missing remark type.");
513 
514   // Always >= Type::First since it's unsigned.
515   if (*Helper.Type > static_cast<uint8_t>(Type::Last))
516     return createStringError(
517         std::make_error_code(std::errc::illegal_byte_sequence),
518         "Error while parsing BLOCK_REMARK: unknown remark type.");
519 
520   R.RemarkType = static_cast<Type>(*Helper.Type);
521 
522   if (!Helper.RemarkNameIdx)
523     return createStringError(
524         std::make_error_code(std::errc::illegal_byte_sequence),
525         "Error while parsing BLOCK_REMARK: missing remark name.");
526 
527   if (Expected<StringRef> RemarkName = (*StrTab)[*Helper.RemarkNameIdx])
528     R.RemarkName = *RemarkName;
529   else
530     return RemarkName.takeError();
531 
532   if (!Helper.PassNameIdx)
533     return createStringError(
534         std::make_error_code(std::errc::illegal_byte_sequence),
535         "Error while parsing BLOCK_REMARK: missing remark pass.");
536 
537   if (Expected<StringRef> PassName = (*StrTab)[*Helper.PassNameIdx])
538     R.PassName = *PassName;
539   else
540     return PassName.takeError();
541 
542   if (!Helper.FunctionNameIdx)
543     return createStringError(
544         std::make_error_code(std::errc::illegal_byte_sequence),
545         "Error while parsing BLOCK_REMARK: missing remark function name.");
546   if (Expected<StringRef> FunctionName = (*StrTab)[*Helper.FunctionNameIdx])
547     R.FunctionName = *FunctionName;
548   else
549     return FunctionName.takeError();
550 
551   if (Helper.SourceFileNameIdx && Helper.SourceLine && Helper.SourceColumn) {
552     Expected<StringRef> SourceFileName = (*StrTab)[*Helper.SourceFileNameIdx];
553     if (!SourceFileName)
554       return SourceFileName.takeError();
555     R.Loc.emplace();
556     R.Loc->SourceFilePath = *SourceFileName;
557     R.Loc->SourceLine = *Helper.SourceLine;
558     R.Loc->SourceColumn = *Helper.SourceColumn;
559   }
560 
561   if (Helper.Hotness)
562     R.Hotness = *Helper.Hotness;
563 
564   if (!Helper.Args)
565     return std::move(Result);
566 
567   for (const BitstreamRemarkParserHelper::Argument &Arg : *Helper.Args) {
568     if (!Arg.KeyIdx)
569       return createStringError(
570           std::make_error_code(std::errc::illegal_byte_sequence),
571           "Error while parsing BLOCK_REMARK: missing key in remark argument.");
572     if (!Arg.ValueIdx)
573       return createStringError(
574           std::make_error_code(std::errc::illegal_byte_sequence),
575           "Error while parsing BLOCK_REMARK: missing value in remark "
576           "argument.");
577 
578     // We have at least a key and a value, create an entry.
579     R.Args.emplace_back();
580 
581     if (Expected<StringRef> Key = (*StrTab)[*Arg.KeyIdx])
582       R.Args.back().Key = *Key;
583     else
584       return Key.takeError();
585 
586     if (Expected<StringRef> Value = (*StrTab)[*Arg.ValueIdx])
587       R.Args.back().Val = *Value;
588     else
589       return Value.takeError();
590 
591     if (Arg.SourceFileNameIdx && Arg.SourceLine && Arg.SourceColumn) {
592       if (Expected<StringRef> SourceFileName =
593               (*StrTab)[*Arg.SourceFileNameIdx]) {
594         R.Args.back().Loc.emplace();
595         R.Args.back().Loc->SourceFilePath = *SourceFileName;
596         R.Args.back().Loc->SourceLine = *Arg.SourceLine;
597         R.Args.back().Loc->SourceColumn = *Arg.SourceColumn;
598       } else
599         return SourceFileName.takeError();
600     }
601   }
602 
603   return std::move(Result);
604 }
605