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"
191c4bab3bSFrancis Visoiu Mistrih 
201c4bab3bSFrancis Visoiu Mistrih using namespace llvm;
215a05cc0eSFrancis Visoiu Mistrih using namespace llvm::remarks;
221c4bab3bSFrancis Visoiu Mistrih 
2394bad22cSFrancis Visoiu Mistrih char EndOfFileError::ID = 0;
245a05cc0eSFrancis Visoiu Mistrih 
ParsedStringTable(StringRef InBuffer)257fee2b89SFrancis Visoiu Mistrih ParsedStringTable::ParsedStringTable(StringRef InBuffer) : Buffer(InBuffer) {
267fee2b89SFrancis Visoiu Mistrih   while (!InBuffer.empty()) {
277fee2b89SFrancis Visoiu Mistrih     // Strings are separated by '\0' bytes.
287fee2b89SFrancis Visoiu Mistrih     std::pair<StringRef, StringRef> Split = InBuffer.split('\0');
297fee2b89SFrancis Visoiu Mistrih     // We only store the offset from the beginning of the buffer.
307fee2b89SFrancis Visoiu Mistrih     Offsets.push_back(Split.first.data() - Buffer.data());
317fee2b89SFrancis Visoiu Mistrih     InBuffer = Split.second;
327fee2b89SFrancis Visoiu Mistrih   }
337fee2b89SFrancis Visoiu Mistrih }
347fee2b89SFrancis Visoiu Mistrih 
operator [](size_t Index) const35e6ba313aSFrancis Visoiu Mistrih Expected<StringRef> ParsedStringTable::operator[](size_t Index) const {
367fee2b89SFrancis Visoiu Mistrih   if (Index >= Offsets.size())
377fee2b89SFrancis Visoiu Mistrih     return createStringError(
387fee2b89SFrancis Visoiu Mistrih         std::make_error_code(std::errc::invalid_argument),
397fee2b89SFrancis Visoiu Mistrih         "String with index %u is out of bounds (size = %u).", Index,
407fee2b89SFrancis Visoiu Mistrih         Offsets.size());
417fee2b89SFrancis Visoiu Mistrih 
427fee2b89SFrancis Visoiu Mistrih   size_t Offset = Offsets[Index];
437fee2b89SFrancis Visoiu Mistrih   // If it's the last offset, we can't use the next offset to know the size of
447fee2b89SFrancis Visoiu Mistrih   // the string.
457fee2b89SFrancis Visoiu Mistrih   size_t NextOffset =
467fee2b89SFrancis Visoiu Mistrih       (Index == Offsets.size() - 1) ? Buffer.size() : Offsets[Index + 1];
477fee2b89SFrancis Visoiu Mistrih   return StringRef(Buffer.data() + Offset, NextOffset - Offset - 1);
487fee2b89SFrancis Visoiu Mistrih }
497fee2b89SFrancis Visoiu Mistrih 
50ab56cf89SFrancis Visoiu Mistrih Expected<std::unique_ptr<RemarkParser>>
createRemarkParser(Format ParserFormat,StringRef Buf)51c5b5cc45SFrancis Visoiu Mistrih llvm::remarks::createRemarkParser(Format ParserFormat, StringRef Buf) {
5294bad22cSFrancis Visoiu Mistrih   switch (ParserFormat) {
5394bad22cSFrancis Visoiu Mistrih   case Format::YAML:
540eaee545SJonas Devlieghere     return std::make_unique<YAMLRemarkParser>(Buf);
55c5b5cc45SFrancis Visoiu Mistrih   case Format::YAMLStrTab:
56c5b5cc45SFrancis Visoiu Mistrih     return createStringError(
57c5b5cc45SFrancis Visoiu Mistrih         std::make_error_code(std::errc::invalid_argument),
58c5b5cc45SFrancis Visoiu Mistrih         "The YAML with string table format requires a parsed string table.");
5984e80979SFrancis Visoiu Mistrih   case Format::Bitstream:
60a85d9ef1SFrancis Visoiu Mistrih     return std::make_unique<BitstreamRemarkParser>(Buf);
6194bad22cSFrancis Visoiu Mistrih   case Format::Unknown:
6294bad22cSFrancis Visoiu Mistrih     return createStringError(std::make_error_code(std::errc::invalid_argument),
6394bad22cSFrancis Visoiu Mistrih                              "Unknown remark parser format.");
6494bad22cSFrancis Visoiu Mistrih   }
65509ad30dSHaojian Wu   llvm_unreachable("unhandled ParseFormat");
66c5b5cc45SFrancis Visoiu Mistrih }
67c5b5cc45SFrancis Visoiu Mistrih 
68ab56cf89SFrancis Visoiu Mistrih Expected<std::unique_ptr<RemarkParser>>
createRemarkParser(Format ParserFormat,StringRef Buf,ParsedStringTable StrTab)69c5b5cc45SFrancis Visoiu Mistrih llvm::remarks::createRemarkParser(Format ParserFormat, StringRef Buf,
704287c95bSFrancis Visoiu Mistrih                                   ParsedStringTable StrTab) {
71c5b5cc45SFrancis Visoiu Mistrih   switch (ParserFormat) {
72c5b5cc45SFrancis Visoiu Mistrih   case Format::YAML:
73c5b5cc45SFrancis Visoiu Mistrih     return createStringError(std::make_error_code(std::errc::invalid_argument),
74c5b5cc45SFrancis Visoiu Mistrih                              "The YAML format can't be used with a string "
75c5b5cc45SFrancis Visoiu Mistrih                              "table. Use yaml-strtab instead.");
76c5b5cc45SFrancis Visoiu Mistrih   case Format::YAMLStrTab:
770eaee545SJonas Devlieghere     return std::make_unique<YAMLStrTabRemarkParser>(Buf, std::move(StrTab));
7884e80979SFrancis Visoiu Mistrih   case Format::Bitstream:
79a85d9ef1SFrancis Visoiu Mistrih     return std::make_unique<BitstreamRemarkParser>(Buf, std::move(StrTab));
80c5b5cc45SFrancis Visoiu Mistrih   case Format::Unknown:
81c5b5cc45SFrancis Visoiu Mistrih     return createStringError(std::make_error_code(std::errc::invalid_argument),
82c5b5cc45SFrancis Visoiu Mistrih                              "Unknown remark parser format.");
83c5b5cc45SFrancis Visoiu Mistrih   }
84509ad30dSHaojian Wu   llvm_unreachable("unhandled ParseFormat");
8594bad22cSFrancis Visoiu Mistrih }
8694bad22cSFrancis Visoiu Mistrih 
8764a5f9e1SFrancis Visoiu Mistrih Expected<std::unique_ptr<RemarkParser>>
createRemarkParserFromMeta(Format ParserFormat,StringRef Buf,Optional<ParsedStringTable> StrTab,Optional<StringRef> ExternalFilePrependPath)88684605ecSFrancis Visoiu Mistrih llvm::remarks::createRemarkParserFromMeta(
89684605ecSFrancis Visoiu Mistrih     Format ParserFormat, StringRef Buf, Optional<ParsedStringTable> StrTab,
90684605ecSFrancis Visoiu Mistrih     Optional<StringRef> ExternalFilePrependPath) {
9164a5f9e1SFrancis Visoiu Mistrih   switch (ParserFormat) {
9264a5f9e1SFrancis Visoiu Mistrih   // Depending on the metadata, the format can be either yaml or yaml-strtab,
9364a5f9e1SFrancis Visoiu Mistrih   // regardless of the input argument.
9464a5f9e1SFrancis Visoiu Mistrih   case Format::YAML:
9564a5f9e1SFrancis Visoiu Mistrih   case Format::YAMLStrTab:
96684605ecSFrancis Visoiu Mistrih     return createYAMLParserFromMeta(Buf, std::move(StrTab),
97684605ecSFrancis Visoiu Mistrih                                     std::move(ExternalFilePrependPath));
9884e80979SFrancis Visoiu Mistrih   case Format::Bitstream:
99684605ecSFrancis Visoiu Mistrih     return createBitstreamParserFromMeta(Buf, std::move(StrTab),
100684605ecSFrancis Visoiu Mistrih                                          std::move(ExternalFilePrependPath));
10164a5f9e1SFrancis Visoiu Mistrih   case Format::Unknown:
10264a5f9e1SFrancis Visoiu Mistrih     return createStringError(std::make_error_code(std::errc::invalid_argument),
10364a5f9e1SFrancis Visoiu Mistrih                              "Unknown remark parser format.");
10464a5f9e1SFrancis Visoiu Mistrih   }
105f5a33836SFrancis Visoiu Mistrih   llvm_unreachable("unhandled ParseFormat");
10664a5f9e1SFrancis Visoiu Mistrih }
10764a5f9e1SFrancis Visoiu Mistrih 
108dc5f805dSBenjamin Kramer namespace {
10994bad22cSFrancis Visoiu Mistrih // Wrapper that holds the state needed to interact with the C API.
11094bad22cSFrancis Visoiu Mistrih struct CParser {
111ab56cf89SFrancis Visoiu Mistrih   std::unique_ptr<RemarkParser> TheParser;
11294bad22cSFrancis Visoiu Mistrih   Optional<std::string> Err;
11394bad22cSFrancis Visoiu Mistrih 
CParser__anon75aa8d330111::CParser11494bad22cSFrancis Visoiu Mistrih   CParser(Format ParserFormat, StringRef Buf,
1154287c95bSFrancis Visoiu Mistrih           Optional<ParsedStringTable> StrTab = None)
1164287c95bSFrancis Visoiu Mistrih       : TheParser(cantFail(
1174287c95bSFrancis Visoiu Mistrih             StrTab ? createRemarkParser(ParserFormat, Buf, std::move(*StrTab))
118c5b5cc45SFrancis Visoiu Mistrih                    : createRemarkParser(ParserFormat, Buf))) {}
11994bad22cSFrancis Visoiu Mistrih 
handleError__anon75aa8d330111::CParser12094bad22cSFrancis Visoiu Mistrih   void handleError(Error E) { Err.emplace(toString(std::move(E))); }
hasError__anon75aa8d330111::CParser121*064a08cdSKazu Hirata   bool hasError() const { return Err.has_value(); }
getMessage__anon75aa8d330111::CParser12294bad22cSFrancis Visoiu Mistrih   const char *getMessage() const { return Err ? Err->c_str() : nullptr; };
12394bad22cSFrancis Visoiu Mistrih };
124dc5f805dSBenjamin Kramer } // namespace
12594bad22cSFrancis Visoiu Mistrih 
1265a05cc0eSFrancis Visoiu Mistrih // Create wrappers for C Binding types (see CBindingWrapping.h).
DEFINE_SIMPLE_CONVERSION_FUNCTIONS(CParser,LLVMRemarkParserRef)12794bad22cSFrancis Visoiu Mistrih DEFINE_SIMPLE_CONVERSION_FUNCTIONS(CParser, LLVMRemarkParserRef)
1285a05cc0eSFrancis Visoiu Mistrih 
1295a05cc0eSFrancis Visoiu Mistrih extern "C" LLVMRemarkParserRef LLVMRemarkParserCreateYAML(const void *Buf,
1305a05cc0eSFrancis Visoiu Mistrih                                                           uint64_t Size) {
13194bad22cSFrancis Visoiu Mistrih   return wrap(new CParser(Format::YAML,
13294bad22cSFrancis Visoiu Mistrih                           StringRef(static_cast<const char *>(Buf), Size)));
1335a05cc0eSFrancis Visoiu Mistrih }
1345a05cc0eSFrancis Visoiu Mistrih 
LLVMRemarkParserCreateBitstream(const void * Buf,uint64_t Size)135a85d9ef1SFrancis Visoiu Mistrih extern "C" LLVMRemarkParserRef LLVMRemarkParserCreateBitstream(const void *Buf,
136a85d9ef1SFrancis Visoiu Mistrih                                                                uint64_t Size) {
137a85d9ef1SFrancis Visoiu Mistrih   return wrap(new CParser(Format::Bitstream,
138a85d9ef1SFrancis Visoiu Mistrih                           StringRef(static_cast<const char *>(Buf), Size)));
139a85d9ef1SFrancis Visoiu Mistrih }
140a85d9ef1SFrancis Visoiu Mistrih 
1415a05cc0eSFrancis Visoiu Mistrih extern "C" LLVMRemarkEntryRef
LLVMRemarkParserGetNext(LLVMRemarkParserRef Parser)1425a05cc0eSFrancis Visoiu Mistrih LLVMRemarkParserGetNext(LLVMRemarkParserRef Parser) {
14394bad22cSFrancis Visoiu Mistrih   CParser &TheCParser = *unwrap(Parser);
144ab56cf89SFrancis Visoiu Mistrih   remarks::RemarkParser &TheParser = *TheCParser.TheParser;
1455a05cc0eSFrancis Visoiu Mistrih 
14694bad22cSFrancis Visoiu Mistrih   Expected<std::unique_ptr<Remark>> MaybeRemark = TheParser.next();
14794bad22cSFrancis Visoiu Mistrih   if (Error E = MaybeRemark.takeError()) {
14894bad22cSFrancis Visoiu Mistrih     if (E.isA<EndOfFileError>()) {
14994bad22cSFrancis Visoiu Mistrih       consumeError(std::move(E));
1501c4bab3bSFrancis Visoiu Mistrih       return nullptr;
1511c4bab3bSFrancis Visoiu Mistrih     }
1521c4bab3bSFrancis Visoiu Mistrih 
15394bad22cSFrancis Visoiu Mistrih     // Handle the error. Allow it to be checked through HasError and
15494bad22cSFrancis Visoiu Mistrih     // GetErrorMessage.
15594bad22cSFrancis Visoiu Mistrih     TheCParser.handleError(std::move(E));
1565a05cc0eSFrancis Visoiu Mistrih     return nullptr;
15794bad22cSFrancis Visoiu Mistrih   }
15894bad22cSFrancis Visoiu Mistrih 
1595a05cc0eSFrancis Visoiu Mistrih   // Valid remark.
16094bad22cSFrancis Visoiu Mistrih   return wrap(MaybeRemark->release());
1615a05cc0eSFrancis Visoiu Mistrih }
1625a05cc0eSFrancis Visoiu Mistrih 
LLVMRemarkParserHasError(LLVMRemarkParserRef Parser)1631c4bab3bSFrancis Visoiu Mistrih extern "C" LLVMBool LLVMRemarkParserHasError(LLVMRemarkParserRef Parser) {
16494bad22cSFrancis Visoiu Mistrih   return unwrap(Parser)->hasError();
1651c4bab3bSFrancis Visoiu Mistrih }
1661c4bab3bSFrancis Visoiu Mistrih 
1671c4bab3bSFrancis Visoiu Mistrih extern "C" const char *
LLVMRemarkParserGetErrorMessage(LLVMRemarkParserRef Parser)1681c4bab3bSFrancis Visoiu Mistrih LLVMRemarkParserGetErrorMessage(LLVMRemarkParserRef Parser) {
16994bad22cSFrancis Visoiu Mistrih   return unwrap(Parser)->getMessage();
1701c4bab3bSFrancis Visoiu Mistrih }
1711c4bab3bSFrancis Visoiu Mistrih 
LLVMRemarkParserDispose(LLVMRemarkParserRef Parser)1721c4bab3bSFrancis Visoiu Mistrih extern "C" void LLVMRemarkParserDispose(LLVMRemarkParserRef Parser) {
1731c4bab3bSFrancis Visoiu Mistrih   delete unwrap(Parser);
1741c4bab3bSFrancis Visoiu Mistrih }
175