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