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