xref: /llvm-project/llvm/lib/Remarks/RemarkParser.cpp (revision a81a0c97f1a0016686fdc5c5d10644fa2628b376)
11c4bab3bSFrancis Visoiu Mistrih //===- RemarkParser.cpp --------------------------------------------------===//
21c4bab3bSFrancis Visoiu Mistrih //
31c4bab3bSFrancis Visoiu Mistrih // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
41c4bab3bSFrancis Visoiu Mistrih // See https://llvm.org/LICENSE.txt for license information.
51c4bab3bSFrancis Visoiu Mistrih // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
61c4bab3bSFrancis Visoiu Mistrih //
71c4bab3bSFrancis Visoiu Mistrih //===----------------------------------------------------------------------===//
81c4bab3bSFrancis Visoiu Mistrih //
91c4bab3bSFrancis Visoiu Mistrih // This file provides utility methods used by clients that want to use the
101c4bab3bSFrancis Visoiu Mistrih // parser for remark diagnostics in LLVM.
111c4bab3bSFrancis Visoiu Mistrih //
121c4bab3bSFrancis Visoiu Mistrih //===----------------------------------------------------------------------===//
131c4bab3bSFrancis Visoiu Mistrih 
145a05cc0eSFrancis Visoiu Mistrih #include "llvm/Remarks/RemarkParser.h"
15a85d9ef1SFrancis Visoiu Mistrih #include "BitstreamRemarkParser.h"
165a05cc0eSFrancis Visoiu Mistrih #include "YAMLRemarkParser.h"
171c4bab3bSFrancis Visoiu Mistrih #include "llvm-c/Remarks.h"
185a05cc0eSFrancis Visoiu Mistrih #include "llvm/Support/CBindingWrapping.h"
19e9b0bcb6SKazu Hirata #include <optional>
201c4bab3bSFrancis Visoiu Mistrih 
211c4bab3bSFrancis Visoiu Mistrih using namespace llvm;
225a05cc0eSFrancis Visoiu Mistrih using namespace llvm::remarks;
231c4bab3bSFrancis Visoiu Mistrih 
2494bad22cSFrancis Visoiu Mistrih char EndOfFileError::ID = 0;
255a05cc0eSFrancis Visoiu Mistrih 
ParsedStringTable(StringRef InBuffer)267fee2b89SFrancis Visoiu Mistrih ParsedStringTable::ParsedStringTable(StringRef InBuffer) : Buffer(InBuffer) {
277fee2b89SFrancis Visoiu Mistrih   while (!InBuffer.empty()) {
287fee2b89SFrancis Visoiu Mistrih     // Strings are separated by '\0' bytes.
297fee2b89SFrancis Visoiu Mistrih     std::pair<StringRef, StringRef> Split = InBuffer.split('\0');
307fee2b89SFrancis Visoiu Mistrih     // We only store the offset from the beginning of the buffer.
317fee2b89SFrancis Visoiu Mistrih     Offsets.push_back(Split.first.data() - Buffer.data());
327fee2b89SFrancis Visoiu Mistrih     InBuffer = Split.second;
337fee2b89SFrancis Visoiu Mistrih   }
347fee2b89SFrancis Visoiu Mistrih }
357fee2b89SFrancis Visoiu Mistrih 
operator [](size_t Index) const36e6ba313aSFrancis Visoiu Mistrih Expected<StringRef> ParsedStringTable::operator[](size_t Index) const {
377fee2b89SFrancis Visoiu Mistrih   if (Index >= Offsets.size())
387fee2b89SFrancis Visoiu Mistrih     return createStringError(
397fee2b89SFrancis Visoiu Mistrih         std::make_error_code(std::errc::invalid_argument),
407fee2b89SFrancis Visoiu Mistrih         "String with index %u is out of bounds (size = %u).", Index,
417fee2b89SFrancis Visoiu Mistrih         Offsets.size());
427fee2b89SFrancis Visoiu Mistrih 
437fee2b89SFrancis Visoiu Mistrih   size_t Offset = Offsets[Index];
447fee2b89SFrancis Visoiu Mistrih   // If it's the last offset, we can't use the next offset to know the size of
457fee2b89SFrancis Visoiu Mistrih   // the string.
467fee2b89SFrancis Visoiu Mistrih   size_t NextOffset =
477fee2b89SFrancis Visoiu Mistrih       (Index == Offsets.size() - 1) ? Buffer.size() : Offsets[Index + 1];
487fee2b89SFrancis Visoiu Mistrih   return StringRef(Buffer.data() + Offset, NextOffset - Offset - 1);
497fee2b89SFrancis Visoiu Mistrih }
507fee2b89SFrancis Visoiu Mistrih 
51ab56cf89SFrancis Visoiu Mistrih Expected<std::unique_ptr<RemarkParser>>
createRemarkParser(Format ParserFormat,StringRef Buf)52c5b5cc45SFrancis Visoiu Mistrih llvm::remarks::createRemarkParser(Format ParserFormat, StringRef Buf) {
5394bad22cSFrancis Visoiu Mistrih   switch (ParserFormat) {
5494bad22cSFrancis Visoiu Mistrih   case Format::YAML:
550eaee545SJonas Devlieghere     return std::make_unique<YAMLRemarkParser>(Buf);
56c5b5cc45SFrancis Visoiu Mistrih   case Format::YAMLStrTab:
57c5b5cc45SFrancis Visoiu Mistrih     return createStringError(
58c5b5cc45SFrancis Visoiu Mistrih         std::make_error_code(std::errc::invalid_argument),
59c5b5cc45SFrancis Visoiu Mistrih         "The YAML with string table format requires a parsed string table.");
6084e80979SFrancis Visoiu Mistrih   case Format::Bitstream:
61a85d9ef1SFrancis Visoiu Mistrih     return std::make_unique<BitstreamRemarkParser>(Buf);
6294bad22cSFrancis Visoiu Mistrih   case Format::Unknown:
6394bad22cSFrancis Visoiu Mistrih     return createStringError(std::make_error_code(std::errc::invalid_argument),
6494bad22cSFrancis Visoiu Mistrih                              "Unknown remark parser format.");
6594bad22cSFrancis Visoiu Mistrih   }
66509ad30dSHaojian Wu   llvm_unreachable("unhandled ParseFormat");
67c5b5cc45SFrancis Visoiu Mistrih }
68c5b5cc45SFrancis Visoiu Mistrih 
69ab56cf89SFrancis Visoiu Mistrih Expected<std::unique_ptr<RemarkParser>>
createRemarkParser(Format ParserFormat,StringRef Buf,ParsedStringTable StrTab)70c5b5cc45SFrancis Visoiu Mistrih llvm::remarks::createRemarkParser(Format ParserFormat, StringRef Buf,
714287c95bSFrancis Visoiu Mistrih                                   ParsedStringTable StrTab) {
72c5b5cc45SFrancis Visoiu Mistrih   switch (ParserFormat) {
73c5b5cc45SFrancis Visoiu Mistrih   case Format::YAML:
74c5b5cc45SFrancis Visoiu Mistrih     return createStringError(std::make_error_code(std::errc::invalid_argument),
75c5b5cc45SFrancis Visoiu Mistrih                              "The YAML format can't be used with a string "
76c5b5cc45SFrancis Visoiu Mistrih                              "table. Use yaml-strtab instead.");
77c5b5cc45SFrancis Visoiu Mistrih   case Format::YAMLStrTab:
780eaee545SJonas Devlieghere     return std::make_unique<YAMLStrTabRemarkParser>(Buf, std::move(StrTab));
7984e80979SFrancis Visoiu Mistrih   case Format::Bitstream:
80a85d9ef1SFrancis Visoiu Mistrih     return std::make_unique<BitstreamRemarkParser>(Buf, std::move(StrTab));
81c5b5cc45SFrancis Visoiu Mistrih   case Format::Unknown:
82c5b5cc45SFrancis Visoiu Mistrih     return createStringError(std::make_error_code(std::errc::invalid_argument),
83c5b5cc45SFrancis Visoiu Mistrih                              "Unknown remark parser format.");
84c5b5cc45SFrancis Visoiu Mistrih   }
85509ad30dSHaojian Wu   llvm_unreachable("unhandled ParseFormat");
8694bad22cSFrancis Visoiu Mistrih }
8794bad22cSFrancis Visoiu Mistrih 
8864a5f9e1SFrancis Visoiu Mistrih Expected<std::unique_ptr<RemarkParser>>
createRemarkParserFromMeta(Format ParserFormat,StringRef Buf,std::optional<ParsedStringTable> StrTab,std::optional<StringRef> ExternalFilePrependPath)89684605ecSFrancis Visoiu Mistrih llvm::remarks::createRemarkParserFromMeta(
90*a81a0c97SKrzysztof Parzyszek     Format ParserFormat, StringRef Buf, std::optional<ParsedStringTable> StrTab,
91*a81a0c97SKrzysztof Parzyszek     std::optional<StringRef> ExternalFilePrependPath) {
9264a5f9e1SFrancis Visoiu Mistrih   switch (ParserFormat) {
9364a5f9e1SFrancis Visoiu Mistrih   // Depending on the metadata, the format can be either yaml or yaml-strtab,
9464a5f9e1SFrancis Visoiu Mistrih   // regardless of the input argument.
9564a5f9e1SFrancis Visoiu Mistrih   case Format::YAML:
9664a5f9e1SFrancis Visoiu Mistrih   case Format::YAMLStrTab:
97684605ecSFrancis Visoiu Mistrih     return createYAMLParserFromMeta(Buf, std::move(StrTab),
98684605ecSFrancis Visoiu Mistrih                                     std::move(ExternalFilePrependPath));
9984e80979SFrancis Visoiu Mistrih   case Format::Bitstream:
100684605ecSFrancis Visoiu Mistrih     return createBitstreamParserFromMeta(Buf, std::move(StrTab),
101684605ecSFrancis Visoiu Mistrih                                          std::move(ExternalFilePrependPath));
10264a5f9e1SFrancis Visoiu Mistrih   case Format::Unknown:
10364a5f9e1SFrancis Visoiu Mistrih     return createStringError(std::make_error_code(std::errc::invalid_argument),
10464a5f9e1SFrancis Visoiu Mistrih                              "Unknown remark parser format.");
10564a5f9e1SFrancis Visoiu Mistrih   }
106f5a33836SFrancis Visoiu Mistrih   llvm_unreachable("unhandled ParseFormat");
10764a5f9e1SFrancis Visoiu Mistrih }
10864a5f9e1SFrancis Visoiu Mistrih 
109dc5f805dSBenjamin Kramer namespace {
11094bad22cSFrancis Visoiu Mistrih // Wrapper that holds the state needed to interact with the C API.
11194bad22cSFrancis Visoiu Mistrih struct CParser {
112ab56cf89SFrancis Visoiu Mistrih   std::unique_ptr<RemarkParser> TheParser;
113e9b0bcb6SKazu Hirata   std::optional<std::string> Err;
11494bad22cSFrancis Visoiu Mistrih 
CParser__anon0c7b5db60111::CParser11594bad22cSFrancis Visoiu Mistrih   CParser(Format ParserFormat, StringRef Buf,
116aadaafacSKazu Hirata           std::optional<ParsedStringTable> StrTab = std::nullopt)
1174287c95bSFrancis Visoiu Mistrih       : TheParser(cantFail(
1184287c95bSFrancis Visoiu Mistrih             StrTab ? createRemarkParser(ParserFormat, Buf, std::move(*StrTab))
119c5b5cc45SFrancis Visoiu Mistrih                    : createRemarkParser(ParserFormat, Buf))) {}
12094bad22cSFrancis Visoiu Mistrih 
handleError__anon0c7b5db60111::CParser12194bad22cSFrancis Visoiu Mistrih   void handleError(Error E) { Err.emplace(toString(std::move(E))); }
hasError__anon0c7b5db60111::CParser122064a08cdSKazu Hirata   bool hasError() const { return Err.has_value(); }
getMessage__anon0c7b5db60111::CParser12394bad22cSFrancis Visoiu Mistrih   const char *getMessage() const { return Err ? Err->c_str() : nullptr; };
12494bad22cSFrancis Visoiu Mistrih };
125dc5f805dSBenjamin Kramer } // namespace
12694bad22cSFrancis Visoiu Mistrih 
1275a05cc0eSFrancis Visoiu Mistrih // Create wrappers for C Binding types (see CBindingWrapping.h).
DEFINE_SIMPLE_CONVERSION_FUNCTIONS(CParser,LLVMRemarkParserRef)12894bad22cSFrancis Visoiu Mistrih DEFINE_SIMPLE_CONVERSION_FUNCTIONS(CParser, LLVMRemarkParserRef)
1295a05cc0eSFrancis Visoiu Mistrih 
1305a05cc0eSFrancis Visoiu Mistrih extern "C" LLVMRemarkParserRef LLVMRemarkParserCreateYAML(const void *Buf,
1315a05cc0eSFrancis Visoiu Mistrih                                                           uint64_t Size) {
13294bad22cSFrancis Visoiu Mistrih   return wrap(new CParser(Format::YAML,
13394bad22cSFrancis Visoiu Mistrih                           StringRef(static_cast<const char *>(Buf), Size)));
1345a05cc0eSFrancis Visoiu Mistrih }
1355a05cc0eSFrancis Visoiu Mistrih 
LLVMRemarkParserCreateBitstream(const void * Buf,uint64_t Size)136a85d9ef1SFrancis Visoiu Mistrih extern "C" LLVMRemarkParserRef LLVMRemarkParserCreateBitstream(const void *Buf,
137a85d9ef1SFrancis Visoiu Mistrih                                                                uint64_t Size) {
138a85d9ef1SFrancis Visoiu Mistrih   return wrap(new CParser(Format::Bitstream,
139a85d9ef1SFrancis Visoiu Mistrih                           StringRef(static_cast<const char *>(Buf), Size)));
140a85d9ef1SFrancis Visoiu Mistrih }
141a85d9ef1SFrancis Visoiu Mistrih 
1425a05cc0eSFrancis Visoiu Mistrih extern "C" LLVMRemarkEntryRef
LLVMRemarkParserGetNext(LLVMRemarkParserRef Parser)1435a05cc0eSFrancis Visoiu Mistrih LLVMRemarkParserGetNext(LLVMRemarkParserRef Parser) {
14494bad22cSFrancis Visoiu Mistrih   CParser &TheCParser = *unwrap(Parser);
145ab56cf89SFrancis Visoiu Mistrih   remarks::RemarkParser &TheParser = *TheCParser.TheParser;
1465a05cc0eSFrancis Visoiu Mistrih 
14794bad22cSFrancis Visoiu Mistrih   Expected<std::unique_ptr<Remark>> MaybeRemark = TheParser.next();
14894bad22cSFrancis Visoiu Mistrih   if (Error E = MaybeRemark.takeError()) {
14994bad22cSFrancis Visoiu Mistrih     if (E.isA<EndOfFileError>()) {
15094bad22cSFrancis Visoiu Mistrih       consumeError(std::move(E));
1511c4bab3bSFrancis Visoiu Mistrih       return nullptr;
1521c4bab3bSFrancis Visoiu Mistrih     }
1531c4bab3bSFrancis Visoiu Mistrih 
15494bad22cSFrancis Visoiu Mistrih     // Handle the error. Allow it to be checked through HasError and
15594bad22cSFrancis Visoiu Mistrih     // GetErrorMessage.
15694bad22cSFrancis Visoiu Mistrih     TheCParser.handleError(std::move(E));
1575a05cc0eSFrancis Visoiu Mistrih     return nullptr;
15894bad22cSFrancis Visoiu Mistrih   }
15994bad22cSFrancis Visoiu Mistrih 
1605a05cc0eSFrancis Visoiu Mistrih   // Valid remark.
16194bad22cSFrancis Visoiu Mistrih   return wrap(MaybeRemark->release());
1625a05cc0eSFrancis Visoiu Mistrih }
1635a05cc0eSFrancis Visoiu Mistrih 
LLVMRemarkParserHasError(LLVMRemarkParserRef Parser)1641c4bab3bSFrancis Visoiu Mistrih extern "C" LLVMBool LLVMRemarkParserHasError(LLVMRemarkParserRef Parser) {
16594bad22cSFrancis Visoiu Mistrih   return unwrap(Parser)->hasError();
1661c4bab3bSFrancis Visoiu Mistrih }
1671c4bab3bSFrancis Visoiu Mistrih 
1681c4bab3bSFrancis Visoiu Mistrih extern "C" const char *
LLVMRemarkParserGetErrorMessage(LLVMRemarkParserRef Parser)1691c4bab3bSFrancis Visoiu Mistrih LLVMRemarkParserGetErrorMessage(LLVMRemarkParserRef Parser) {
17094bad22cSFrancis Visoiu Mistrih   return unwrap(Parser)->getMessage();
1711c4bab3bSFrancis Visoiu Mistrih }
1721c4bab3bSFrancis Visoiu Mistrih 
LLVMRemarkParserDispose(LLVMRemarkParserRef Parser)1731c4bab3bSFrancis Visoiu Mistrih extern "C" void LLVMRemarkParserDispose(LLVMRemarkParserRef Parser) {
1741c4bab3bSFrancis Visoiu Mistrih   delete unwrap(Parser);
1751c4bab3bSFrancis Visoiu Mistrih }
176