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