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<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 | MagicNumber: StringRef(MagicNumber->data(), MagicNumber->size()))) |
319 | return std::move(E); |
320 | |
321 | auto Parser = std::make_unique<BitstreamRemarkParser>(args&: Buf); |
322 | |
323 | if (ExternalFilePrependPath) |
324 | Parser->ExternalFilePrependPath = std::string(*ExternalFilePrependPath); |
325 | |
326 | return std::move(Parser); |
327 | } |
328 | |
329 | Expected<std::unique_ptr<Remark>> BitstreamRemarkParser::() { |
330 | if (ParserHelper.atEndOfStream()) |
331 | return make_error<EndOfFileError>(); |
332 | |
333 | if (!ReadyToParseRemarks) { |
334 | if (Error E = parseMeta()) |
335 | return std::move(E); |
336 | ReadyToParseRemarks = true; |
337 | } |
338 | |
339 | return parseRemark(); |
340 | } |
341 | |
342 | Error BitstreamRemarkParser::() { |
343 | // Advance and to the meta block. |
344 | if (Error E = advanceToMetaBlock(Helper&: ParserHelper)) |
345 | return E; |
346 | |
347 | BitstreamMetaParserHelper MetaHelper(ParserHelper.Stream, |
348 | ParserHelper.BlockInfo); |
349 | if (Error E = MetaHelper.parse()) |
350 | return E; |
351 | |
352 | if (Error E = processCommonMeta(Helper&: MetaHelper)) |
353 | return E; |
354 | |
355 | switch (ContainerType) { |
356 | case BitstreamRemarkContainerType::Standalone: |
357 | return processStandaloneMeta(Helper&: MetaHelper); |
358 | case BitstreamRemarkContainerType::SeparateRemarksFile: |
359 | return processSeparateRemarksFileMeta(Helper&: MetaHelper); |
360 | case BitstreamRemarkContainerType::SeparateRemarksMeta: |
361 | return processSeparateRemarksMetaMeta(Helper&: MetaHelper); |
362 | } |
363 | llvm_unreachable("Unknown BitstreamRemarkContainerType enum" ); |
364 | } |
365 | |
366 | Error BitstreamRemarkParser::( |
367 | BitstreamMetaParserHelper &Helper) { |
368 | if (std::optional<uint64_t> Version = Helper.ContainerVersion) |
369 | ContainerVersion = *Version; |
370 | else |
371 | return createStringError( |
372 | EC: std::make_error_code(e: std::errc::illegal_byte_sequence), |
373 | S: "Error while parsing BLOCK_META: missing container version." ); |
374 | |
375 | if (std::optional<uint8_t> Type = Helper.ContainerType) { |
376 | // Always >= BitstreamRemarkContainerType::First since it's unsigned. |
377 | if (*Type > static_cast<uint8_t>(BitstreamRemarkContainerType::Last)) |
378 | return createStringError( |
379 | EC: std::make_error_code(e: std::errc::illegal_byte_sequence), |
380 | S: "Error while parsing BLOCK_META: invalid container type." ); |
381 | |
382 | ContainerType = static_cast<BitstreamRemarkContainerType>(*Type); |
383 | } else |
384 | return createStringError( |
385 | EC: std::make_error_code(e: std::errc::illegal_byte_sequence), |
386 | S: "Error while parsing BLOCK_META: missing container type." ); |
387 | |
388 | return Error::success(); |
389 | } |
390 | |
391 | static Error (BitstreamRemarkParser &P, |
392 | std::optional<StringRef> StrTabBuf) { |
393 | if (!StrTabBuf) |
394 | return createStringError( |
395 | EC: std::make_error_code(e: std::errc::illegal_byte_sequence), |
396 | S: "Error while parsing BLOCK_META: missing string table." ); |
397 | // Parse and assign the string table. |
398 | P.StrTab.emplace(args&: *StrTabBuf); |
399 | return Error::success(); |
400 | } |
401 | |
402 | static Error (BitstreamRemarkParser &P, |
403 | std::optional<uint64_t> ) { |
404 | if (!RemarkVersion) |
405 | return createStringError( |
406 | EC: std::make_error_code(e: std::errc::illegal_byte_sequence), |
407 | S: "Error while parsing BLOCK_META: missing remark version." ); |
408 | P.RemarkVersion = *RemarkVersion; |
409 | return Error::success(); |
410 | } |
411 | |
412 | Error BitstreamRemarkParser::( |
413 | std::optional<StringRef> ExternalFilePath) { |
414 | if (!ExternalFilePath) |
415 | return createStringError( |
416 | EC: std::make_error_code(e: std::errc::illegal_byte_sequence), |
417 | S: "Error while parsing BLOCK_META: missing external file path." ); |
418 | |
419 | SmallString<80> FullPath(ExternalFilePrependPath); |
420 | sys::path::append(path&: FullPath, a: *ExternalFilePath); |
421 | |
422 | // External file: open the external file, parse it, check if its metadata |
423 | // matches the one from the separate metadata, then replace the current parser |
424 | // with the one parsing the remarks. |
425 | ErrorOr<std::unique_ptr<MemoryBuffer>> BufferOrErr = |
426 | MemoryBuffer::getFile(Filename: FullPath); |
427 | if (std::error_code EC = BufferOrErr.getError()) |
428 | return createFileError(F: FullPath, EC); |
429 | |
430 | TmpRemarkBuffer = std::move(*BufferOrErr); |
431 | |
432 | // Don't try to parse the file if it's empty. |
433 | if (TmpRemarkBuffer->getBufferSize() == 0) |
434 | return make_error<EndOfFileError>(); |
435 | |
436 | // Create a separate parser used for parsing the separate file. |
437 | ParserHelper = BitstreamParserHelper(TmpRemarkBuffer->getBuffer()); |
438 | // Advance and check until we can parse the meta block. |
439 | if (Error E = advanceToMetaBlock(Helper&: ParserHelper)) |
440 | return E; |
441 | // Parse the meta from the separate file. |
442 | // Note: here we overwrite the BlockInfo with the one from the file. This will |
443 | // be used to parse the rest of the file. |
444 | BitstreamMetaParserHelper SeparateMetaHelper(ParserHelper.Stream, |
445 | ParserHelper.BlockInfo); |
446 | if (Error E = SeparateMetaHelper.parse()) |
447 | return E; |
448 | |
449 | uint64_t PreviousContainerVersion = ContainerVersion; |
450 | if (Error E = processCommonMeta(Helper&: SeparateMetaHelper)) |
451 | return E; |
452 | |
453 | if (ContainerType != BitstreamRemarkContainerType::SeparateRemarksFile) |
454 | return createStringError( |
455 | EC: std::make_error_code(e: std::errc::illegal_byte_sequence), |
456 | S: "Error while parsing external file's BLOCK_META: wrong container " |
457 | "type." ); |
458 | |
459 | if (PreviousContainerVersion != ContainerVersion) |
460 | return createStringError( |
461 | EC: std::make_error_code(e: std::errc::illegal_byte_sequence), |
462 | Fmt: "Error while parsing external file's BLOCK_META: mismatching versions: " |
463 | "original meta: %lu, external file meta: %lu." , |
464 | Vals: PreviousContainerVersion, Vals: ContainerVersion); |
465 | |
466 | // Process the meta from the separate file. |
467 | return processSeparateRemarksFileMeta(Helper&: SeparateMetaHelper); |
468 | } |
469 | |
470 | Error BitstreamRemarkParser::processStandaloneMeta( |
471 | BitstreamMetaParserHelper &Helper) { |
472 | if (Error E = processStrTab(P&: *this, StrTabBuf: Helper.StrTabBuf)) |
473 | return E; |
474 | return processRemarkVersion(P&: *this, RemarkVersion: Helper.RemarkVersion); |
475 | } |
476 | |
477 | Error BitstreamRemarkParser::( |
478 | BitstreamMetaParserHelper &Helper) { |
479 | return processRemarkVersion(P&: *this, RemarkVersion: Helper.RemarkVersion); |
480 | } |
481 | |
482 | Error BitstreamRemarkParser::( |
483 | BitstreamMetaParserHelper &Helper) { |
484 | if (Error E = processStrTab(P&: *this, StrTabBuf: Helper.StrTabBuf)) |
485 | return E; |
486 | return processExternalFilePath(ExternalFilePath: Helper.ExternalFilePath); |
487 | } |
488 | |
489 | Expected<std::unique_ptr<Remark>> BitstreamRemarkParser::() { |
490 | BitstreamRemarkParserHelper (ParserHelper.Stream); |
491 | if (Error E = RemarkHelper.parse()) |
492 | return std::move(E); |
493 | |
494 | return processRemark(Helper&: RemarkHelper); |
495 | } |
496 | |
497 | Expected<std::unique_ptr<Remark>> |
498 | BitstreamRemarkParser::(BitstreamRemarkParserHelper &Helper) { |
499 | std::unique_ptr<Remark> Result = std::make_unique<Remark>(); |
500 | Remark &R = *Result; |
501 | |
502 | if (StrTab == std::nullopt) |
503 | return createStringError( |
504 | EC: std::make_error_code(e: std::errc::invalid_argument), |
505 | S: "Error while parsing BLOCK_REMARK: missing string table." ); |
506 | |
507 | if (!Helper.Type) |
508 | return createStringError( |
509 | EC: std::make_error_code(e: std::errc::illegal_byte_sequence), |
510 | S: "Error while parsing BLOCK_REMARK: missing remark type." ); |
511 | |
512 | // Always >= Type::First since it's unsigned. |
513 | if (*Helper.Type > static_cast<uint8_t>(Type::Last)) |
514 | return createStringError( |
515 | EC: std::make_error_code(e: std::errc::illegal_byte_sequence), |
516 | S: "Error while parsing BLOCK_REMARK: unknown remark type." ); |
517 | |
518 | R.RemarkType = static_cast<Type>(*Helper.Type); |
519 | |
520 | if (!Helper.RemarkNameIdx) |
521 | return createStringError( |
522 | EC: std::make_error_code(e: std::errc::illegal_byte_sequence), |
523 | S: "Error while parsing BLOCK_REMARK: missing remark name." ); |
524 | |
525 | if (Expected<StringRef> = (*StrTab)[*Helper.RemarkNameIdx]) |
526 | R.RemarkName = *RemarkName; |
527 | else |
528 | return RemarkName.takeError(); |
529 | |
530 | if (!Helper.PassNameIdx) |
531 | return createStringError( |
532 | EC: std::make_error_code(e: std::errc::illegal_byte_sequence), |
533 | S: "Error while parsing BLOCK_REMARK: missing remark pass." ); |
534 | |
535 | if (Expected<StringRef> PassName = (*StrTab)[*Helper.PassNameIdx]) |
536 | R.PassName = *PassName; |
537 | else |
538 | return PassName.takeError(); |
539 | |
540 | if (!Helper.FunctionNameIdx) |
541 | return createStringError( |
542 | EC: std::make_error_code(e: std::errc::illegal_byte_sequence), |
543 | S: "Error while parsing BLOCK_REMARK: missing remark function name." ); |
544 | if (Expected<StringRef> FunctionName = (*StrTab)[*Helper.FunctionNameIdx]) |
545 | R.FunctionName = *FunctionName; |
546 | else |
547 | return FunctionName.takeError(); |
548 | |
549 | if (Helper.SourceFileNameIdx && Helper.SourceLine && Helper.SourceColumn) { |
550 | Expected<StringRef> SourceFileName = (*StrTab)[*Helper.SourceFileNameIdx]; |
551 | if (!SourceFileName) |
552 | return SourceFileName.takeError(); |
553 | R.Loc.emplace(); |
554 | R.Loc->SourceFilePath = *SourceFileName; |
555 | R.Loc->SourceLine = *Helper.SourceLine; |
556 | R.Loc->SourceColumn = *Helper.SourceColumn; |
557 | } |
558 | |
559 | if (Helper.Hotness) |
560 | R.Hotness = *Helper.Hotness; |
561 | |
562 | if (!Helper.Args) |
563 | return std::move(Result); |
564 | |
565 | for (const BitstreamRemarkParserHelper::Argument &Arg : *Helper.Args) { |
566 | if (!Arg.KeyIdx) |
567 | return createStringError( |
568 | EC: std::make_error_code(e: std::errc::illegal_byte_sequence), |
569 | S: "Error while parsing BLOCK_REMARK: missing key in remark argument." ); |
570 | if (!Arg.ValueIdx) |
571 | return createStringError( |
572 | EC: std::make_error_code(e: std::errc::illegal_byte_sequence), |
573 | S: "Error while parsing BLOCK_REMARK: missing value in remark " |
574 | "argument." ); |
575 | |
576 | // We have at least a key and a value, create an entry. |
577 | R.Args.emplace_back(); |
578 | |
579 | if (Expected<StringRef> Key = (*StrTab)[*Arg.KeyIdx]) |
580 | R.Args.back().Key = *Key; |
581 | else |
582 | return Key.takeError(); |
583 | |
584 | if (Expected<StringRef> Value = (*StrTab)[*Arg.ValueIdx]) |
585 | R.Args.back().Val = *Value; |
586 | else |
587 | return Value.takeError(); |
588 | |
589 | if (Arg.SourceFileNameIdx && Arg.SourceLine && Arg.SourceColumn) { |
590 | if (Expected<StringRef> SourceFileName = |
591 | (*StrTab)[*Arg.SourceFileNameIdx]) { |
592 | R.Args.back().Loc.emplace(); |
593 | R.Args.back().Loc->SourceFilePath = *SourceFileName; |
594 | R.Args.back().Loc->SourceLine = *Arg.SourceLine; |
595 | R.Args.back().Loc->SourceColumn = *Arg.SourceColumn; |
596 | } else |
597 | return SourceFileName.takeError(); |
598 | } |
599 | } |
600 | |
601 | return std::move(Result); |
602 | } |
603 | |