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 | |
24 | static Error unknownRecord(const char *BlockName, unsigned RecordID) { |
25 | return createStringError( |
26 | EC: std::make_error_code(e: std::errc::illegal_byte_sequence), |
27 | Fmt: "Error while parsing %s: unknown record entry (%lu)." , Vals: BlockName, |
28 | Vals: RecordID); |
29 | } |
30 | |
31 | static Error malformedRecord(const char *BlockName, const char *RecordName) { |
32 | return createStringError( |
33 | EC: std::make_error_code(e: std::errc::illegal_byte_sequence), |
34 | Fmt: "Error while parsing %s: malformed record entry (%s)." , Vals: BlockName, |
35 | Vals: RecordName); |
36 | } |
37 | |
38 | BitstreamMetaParserHelper::( |
39 | BitstreamCursor &Stream, BitstreamBlockInfo &BlockInfo) |
40 | : Stream(Stream), BlockInfo(BlockInfo) {} |
41 | |
42 | /// Parse a record and fill in the fields in the parser. |
43 | static Error (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(AbbrevID: Code, Vals&: Record, Blob: &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(BlockName: "BLOCK_META" , RecordName: "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(BlockName: "BLOCK_META" , RecordName: "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(BlockName: "BLOCK_META" , RecordName: "RECORD_META_STRTAB" ); |
70 | Parser.StrTabBuf = Blob; |
71 | break; |
72 | } |
73 | case RECORD_META_EXTERNAL_FILE: { |
74 | if (Record.size() != 0) |
75 | return malformedRecord(BlockName: "BLOCK_META" , RecordName: "RECORD_META_EXTERNAL_FILE" ); |
76 | Parser.ExternalFilePath = Blob; |
77 | break; |
78 | } |
79 | default: |
80 | return unknownRecord(BlockName: "BLOCK_META" , RecordID: *RecordID); |
81 | } |
82 | return Error::success(); |
83 | } |
84 | |
85 | BitstreamRemarkParserHelper::( |
86 | BitstreamCursor &Stream) |
87 | : Stream(Stream) {} |
88 | |
89 | /// Parse a record and fill in the fields in the parser. |
90 | static Error (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(AbbrevID: Code, Vals&: Record, Blob: &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(BlockName: "BLOCK_REMARK" , RecordName: "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(BlockName: "BLOCK_REMARK" , RecordName: "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(BlockName: "BLOCK_REMARK" , RecordName: "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(BlockName: "BLOCK_REMARK" , RecordName: "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(BlockName: "BLOCK_REMARK" , |
142 | RecordName: "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(BlockName: "BLOCK_REMARK" , RecordID: *RecordID); |
154 | } |
155 | return Error::success(); |
156 | } |
157 | |
158 | template <typename T> |
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 | EC: std::make_error_code(e: std::errc::illegal_byte_sequence), |
168 | Fmt: "Error while parsing %s: expecting [ENTER_SUBBLOCK, %s, ...]." , |
169 | Vals: BlockName, Vals: BlockName); |
170 | if (Stream.EnterSubBlock(BlockID)) |
171 | return createStringError( |
172 | EC: std::make_error_code(e: std::errc::illegal_byte_sequence), |
173 | Fmt: "Error while entering %s." , Vals: 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 | EC: std::make_error_code(e: std::errc::illegal_byte_sequence), |
188 | Fmt: "Error while parsing %s: expecting records." , Vals: 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 | EC: std::make_error_code(e: std::errc::illegal_byte_sequence), |
199 | Fmt: "Error while parsing %s: unterminated block." , Vals: BlockName); |
200 | } |
201 | |
202 | Error BitstreamMetaParserHelper::() { |
203 | return parseBlock(ParserHelper&: *this, BlockID: META_BLOCK_ID, BlockName: "META_BLOCK" ); |
204 | } |
205 | |
206 | Error BitstreamRemarkParserHelper::() { |
207 | return parseBlock(ParserHelper&: *this, BlockID: REMARK_BLOCK_ID, BlockName: "REMARK_BLOCK" ); |
208 | } |
209 | |
210 | BitstreamParserHelper::(StringRef Buffer) |
211 | : Stream(Buffer) {} |
212 | |
213 | Expected<std::array<char, 4>> BitstreamParserHelper::() { |
214 | std::array<char, 4> Result; |
215 | for (unsigned i = 0; i < 4; ++i) |
216 | if (Expected<unsigned> R = Stream.Read(NumBits: 8)) |
217 | Result[i] = *R; |
218 | else |
219 | return R.takeError(); |
220 | return Result; |
221 | } |
222 | |
223 | Error BitstreamParserHelper::() { |
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 | EC: std::make_error_code(e: std::errc::illegal_byte_sequence), |
231 | S: "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 | EC: std::make_error_code(e: std::errc::illegal_byte_sequence), |
242 | S: "Error while parsing BLOCKINFO_BLOCK." ); |
243 | |
244 | BlockInfo = **MaybeBlockInfo; |
245 | |
246 | Stream.setBlockInfo(&BlockInfo); |
247 | return Error::success(); |
248 | } |
249 | |
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 | EC: std::make_error_code(e: std::errc::illegal_byte_sequence), |
264 | S: "Unexpected error while parsing bitstream." ); |
265 | default: |
266 | Result = false; |
267 | break; |
268 | } |
269 | if (Error E = Stream.JumpToBit(BitNo: PreviousBitNo)) |
270 | return std::move(E); |
271 | return Result; |
272 | } |
273 | |
274 | Expected<bool> BitstreamParserHelper::() { |
275 | return isBlock(Stream, BlockID: META_BLOCK_ID); |
276 | } |
277 | |
278 | Expected<bool> BitstreamParserHelper::() { |
279 | return isBlock(Stream, BlockID: META_BLOCK_ID); |
280 | } |
281 | |
282 | static Error validateMagicNumber(StringRef MagicNumber) { |
283 | if (MagicNumber != remarks::ContainerMagic) |
284 | return createStringError(EC: std::make_error_code(e: std::errc::invalid_argument), |
285 | Fmt: "Unknown magic number: expecting %s, got %.4s." , |
286 | Vals: remarks::ContainerMagic.data(), Vals: MagicNumber.data()); |
287 | return Error::success(); |
288 | } |
289 | |
290 | static Error (BitstreamParserHelper &Helper) { |
291 | Expected<std::array<char, 4>> MagicNumber = Helper.parseMagic(); |
292 | if (!MagicNumber) |
293 | return MagicNumber.takeError(); |
294 | if (Error E = validateMagicNumber( |
295 | MagicNumber: 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 | EC: std::make_error_code(e: std::errc::illegal_byte_sequence), |
305 | S: "Expecting META_BLOCK after the BLOCKINFO_BLOCK." ); |
306 | return Error::success(); |
307 | } |
308 | |
309 | Expected<std::unique_ptr<BitstreamRemarkParser>> |
310 | remarks::( |
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 | MagicNumber: StringRef(MagicNumber->data(), MagicNumber->size()))) |
320 | return std::move(E); |
321 | |
322 | auto Parser = |
323 | StrTab ? std::make_unique<BitstreamRemarkParser>(args&: Buf, args: std::move(*StrTab)) |
324 | : std::make_unique<BitstreamRemarkParser>(args&: Buf); |
325 | |
326 | if (ExternalFilePrependPath) |
327 | Parser->ExternalFilePrependPath = std::string(*ExternalFilePrependPath); |
328 | |
329 | return std::move(Parser); |
330 | } |
331 | |
332 | Expected<std::unique_ptr<Remark>> BitstreamRemarkParser::() { |
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 | |
345 | Error BitstreamRemarkParser::() { |
346 | // Advance and to the meta block. |
347 | if (Error E = advanceToMetaBlock(Helper&: 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(Helper&: MetaHelper)) |
356 | return E; |
357 | |
358 | switch (ContainerType) { |
359 | case BitstreamRemarkContainerType::Standalone: |
360 | return processStandaloneMeta(Helper&: MetaHelper); |
361 | case BitstreamRemarkContainerType::SeparateRemarksFile: |
362 | return processSeparateRemarksFileMeta(Helper&: MetaHelper); |
363 | case BitstreamRemarkContainerType::SeparateRemarksMeta: |
364 | return processSeparateRemarksMetaMeta(Helper&: MetaHelper); |
365 | } |
366 | llvm_unreachable("Unknown BitstreamRemarkContainerType enum" ); |
367 | } |
368 | |
369 | Error BitstreamRemarkParser::( |
370 | BitstreamMetaParserHelper &Helper) { |
371 | if (std::optional<uint64_t> Version = Helper.ContainerVersion) |
372 | ContainerVersion = *Version; |
373 | else |
374 | return createStringError( |
375 | EC: std::make_error_code(e: std::errc::illegal_byte_sequence), |
376 | S: "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 | EC: std::make_error_code(e: std::errc::illegal_byte_sequence), |
383 | S: "Error while parsing BLOCK_META: invalid container type." ); |
384 | |
385 | ContainerType = static_cast<BitstreamRemarkContainerType>(*Type); |
386 | } else |
387 | return createStringError( |
388 | EC: std::make_error_code(e: std::errc::illegal_byte_sequence), |
389 | S: "Error while parsing BLOCK_META: missing container type." ); |
390 | |
391 | return Error::success(); |
392 | } |
393 | |
394 | static Error (BitstreamRemarkParser &P, |
395 | std::optional<StringRef> StrTabBuf) { |
396 | if (!StrTabBuf) |
397 | return createStringError( |
398 | EC: std::make_error_code(e: std::errc::illegal_byte_sequence), |
399 | S: "Error while parsing BLOCK_META: missing string table." ); |
400 | // Parse and assign the string table. |
401 | P.StrTab.emplace(args&: *StrTabBuf); |
402 | return Error::success(); |
403 | } |
404 | |
405 | static Error (BitstreamRemarkParser &P, |
406 | std::optional<uint64_t> ) { |
407 | if (!RemarkVersion) |
408 | return createStringError( |
409 | EC: std::make_error_code(e: std::errc::illegal_byte_sequence), |
410 | S: "Error while parsing BLOCK_META: missing remark version." ); |
411 | P.RemarkVersion = *RemarkVersion; |
412 | return Error::success(); |
413 | } |
414 | |
415 | Error BitstreamRemarkParser::( |
416 | std::optional<StringRef> ExternalFilePath) { |
417 | if (!ExternalFilePath) |
418 | return createStringError( |
419 | EC: std::make_error_code(e: std::errc::illegal_byte_sequence), |
420 | S: "Error while parsing BLOCK_META: missing external file path." ); |
421 | |
422 | SmallString<80> FullPath(ExternalFilePrependPath); |
423 | sys::path::append(path&: FullPath, a: *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(Filename: FullPath); |
430 | if (std::error_code EC = BufferOrErr.getError()) |
431 | return createFileError(F: 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(Helper&: 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(Helper&: SeparateMetaHelper)) |
454 | return E; |
455 | |
456 | if (ContainerType != BitstreamRemarkContainerType::SeparateRemarksFile) |
457 | return createStringError( |
458 | EC: std::make_error_code(e: std::errc::illegal_byte_sequence), |
459 | S: "Error while parsing external file's BLOCK_META: wrong container " |
460 | "type." ); |
461 | |
462 | if (PreviousContainerVersion != ContainerVersion) |
463 | return createStringError( |
464 | EC: std::make_error_code(e: std::errc::illegal_byte_sequence), |
465 | Fmt: "Error while parsing external file's BLOCK_META: mismatching versions: " |
466 | "original meta: %lu, external file meta: %lu." , |
467 | Vals: PreviousContainerVersion, Vals: ContainerVersion); |
468 | |
469 | // Process the meta from the separate file. |
470 | return processSeparateRemarksFileMeta(Helper&: SeparateMetaHelper); |
471 | } |
472 | |
473 | Error BitstreamRemarkParser::processStandaloneMeta( |
474 | BitstreamMetaParserHelper &Helper) { |
475 | if (Error E = processStrTab(P&: *this, StrTabBuf: Helper.StrTabBuf)) |
476 | return E; |
477 | return processRemarkVersion(P&: *this, RemarkVersion: Helper.RemarkVersion); |
478 | } |
479 | |
480 | Error BitstreamRemarkParser::( |
481 | BitstreamMetaParserHelper &Helper) { |
482 | return processRemarkVersion(P&: *this, RemarkVersion: Helper.RemarkVersion); |
483 | } |
484 | |
485 | Error BitstreamRemarkParser::( |
486 | BitstreamMetaParserHelper &Helper) { |
487 | if (Error E = processStrTab(P&: *this, StrTabBuf: Helper.StrTabBuf)) |
488 | return E; |
489 | return processExternalFilePath(ExternalFilePath: Helper.ExternalFilePath); |
490 | } |
491 | |
492 | Expected<std::unique_ptr<Remark>> BitstreamRemarkParser::() { |
493 | BitstreamRemarkParserHelper (ParserHelper.Stream); |
494 | if (Error E = RemarkHelper.parse()) |
495 | return std::move(E); |
496 | |
497 | return processRemark(Helper&: RemarkHelper); |
498 | } |
499 | |
500 | Expected<std::unique_ptr<Remark>> |
501 | BitstreamRemarkParser::(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 | EC: std::make_error_code(e: std::errc::invalid_argument), |
508 | S: "Error while parsing BLOCK_REMARK: missing string table." ); |
509 | |
510 | if (!Helper.Type) |
511 | return createStringError( |
512 | EC: std::make_error_code(e: std::errc::illegal_byte_sequence), |
513 | S: "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 | EC: std::make_error_code(e: std::errc::illegal_byte_sequence), |
519 | S: "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 | EC: std::make_error_code(e: std::errc::illegal_byte_sequence), |
526 | S: "Error while parsing BLOCK_REMARK: missing remark name." ); |
527 | |
528 | if (Expected<StringRef> = (*StrTab)[*Helper.RemarkNameIdx]) |
529 | R.RemarkName = *RemarkName; |
530 | else |
531 | return RemarkName.takeError(); |
532 | |
533 | if (!Helper.PassNameIdx) |
534 | return createStringError( |
535 | EC: std::make_error_code(e: std::errc::illegal_byte_sequence), |
536 | S: "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 | EC: std::make_error_code(e: std::errc::illegal_byte_sequence), |
546 | S: "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 | EC: std::make_error_code(e: std::errc::illegal_byte_sequence), |
572 | S: "Error while parsing BLOCK_REMARK: missing key in remark argument." ); |
573 | if (!Arg.ValueIdx) |
574 | return createStringError( |
575 | EC: std::make_error_code(e: std::errc::illegal_byte_sequence), |
576 | S: "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 | |