xref: /freebsd-src/contrib/llvm-project/llvm/lib/Remarks/RemarkParser.cpp (revision bdd1243df58e60e85101c09001d9812a789b6bc4)
10b57cec5SDimitry Andric //===- RemarkParser.cpp --------------------------------------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // This file provides utility methods used by clients that want to use the
100b57cec5SDimitry Andric // parser for remark diagnostics in LLVM.
110b57cec5SDimitry Andric //
120b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
130b57cec5SDimitry Andric 
140b57cec5SDimitry Andric #include "llvm/Remarks/RemarkParser.h"
158bcb0991SDimitry Andric #include "BitstreamRemarkParser.h"
160b57cec5SDimitry Andric #include "YAMLRemarkParser.h"
170b57cec5SDimitry Andric #include "llvm-c/Remarks.h"
180b57cec5SDimitry Andric #include "llvm/Support/CBindingWrapping.h"
19*bdd1243dSDimitry Andric #include <optional>
200b57cec5SDimitry Andric 
210b57cec5SDimitry Andric using namespace llvm;
220b57cec5SDimitry Andric using namespace llvm::remarks;
230b57cec5SDimitry Andric 
240b57cec5SDimitry Andric char EndOfFileError::ID = 0;
250b57cec5SDimitry Andric 
ParsedStringTable(StringRef InBuffer)260b57cec5SDimitry Andric ParsedStringTable::ParsedStringTable(StringRef InBuffer) : Buffer(InBuffer) {
270b57cec5SDimitry Andric   while (!InBuffer.empty()) {
280b57cec5SDimitry Andric     // Strings are separated by '\0' bytes.
290b57cec5SDimitry Andric     std::pair<StringRef, StringRef> Split = InBuffer.split('\0');
300b57cec5SDimitry Andric     // We only store the offset from the beginning of the buffer.
310b57cec5SDimitry Andric     Offsets.push_back(Split.first.data() - Buffer.data());
320b57cec5SDimitry Andric     InBuffer = Split.second;
330b57cec5SDimitry Andric   }
340b57cec5SDimitry Andric }
350b57cec5SDimitry Andric 
operator [](size_t Index) const360b57cec5SDimitry Andric Expected<StringRef> ParsedStringTable::operator[](size_t Index) const {
370b57cec5SDimitry Andric   if (Index >= Offsets.size())
380b57cec5SDimitry Andric     return createStringError(
390b57cec5SDimitry Andric         std::make_error_code(std::errc::invalid_argument),
400b57cec5SDimitry Andric         "String with index %u is out of bounds (size = %u).", Index,
410b57cec5SDimitry Andric         Offsets.size());
420b57cec5SDimitry Andric 
430b57cec5SDimitry Andric   size_t Offset = Offsets[Index];
440b57cec5SDimitry Andric   // If it's the last offset, we can't use the next offset to know the size of
450b57cec5SDimitry Andric   // the string.
460b57cec5SDimitry Andric   size_t NextOffset =
470b57cec5SDimitry Andric       (Index == Offsets.size() - 1) ? Buffer.size() : Offsets[Index + 1];
480b57cec5SDimitry Andric   return StringRef(Buffer.data() + Offset, NextOffset - Offset - 1);
490b57cec5SDimitry Andric }
500b57cec5SDimitry Andric 
518bcb0991SDimitry Andric Expected<std::unique_ptr<RemarkParser>>
createRemarkParser(Format ParserFormat,StringRef Buf)528bcb0991SDimitry Andric llvm::remarks::createRemarkParser(Format ParserFormat, StringRef Buf) {
530b57cec5SDimitry Andric   switch (ParserFormat) {
540b57cec5SDimitry Andric   case Format::YAML:
558bcb0991SDimitry Andric     return std::make_unique<YAMLRemarkParser>(Buf);
568bcb0991SDimitry Andric   case Format::YAMLStrTab:
578bcb0991SDimitry Andric     return createStringError(
588bcb0991SDimitry Andric         std::make_error_code(std::errc::invalid_argument),
598bcb0991SDimitry Andric         "The YAML with string table format requires a parsed string table.");
608bcb0991SDimitry Andric   case Format::Bitstream:
618bcb0991SDimitry Andric     return std::make_unique<BitstreamRemarkParser>(Buf);
620b57cec5SDimitry Andric   case Format::Unknown:
630b57cec5SDimitry Andric     return createStringError(std::make_error_code(std::errc::invalid_argument),
640b57cec5SDimitry Andric                              "Unknown remark parser format.");
650b57cec5SDimitry Andric   }
668bcb0991SDimitry Andric   llvm_unreachable("unhandled ParseFormat");
670b57cec5SDimitry Andric }
680b57cec5SDimitry Andric 
698bcb0991SDimitry Andric Expected<std::unique_ptr<RemarkParser>>
createRemarkParser(Format ParserFormat,StringRef Buf,ParsedStringTable StrTab)708bcb0991SDimitry Andric llvm::remarks::createRemarkParser(Format ParserFormat, StringRef Buf,
718bcb0991SDimitry Andric                                   ParsedStringTable StrTab) {
728bcb0991SDimitry Andric   switch (ParserFormat) {
738bcb0991SDimitry Andric   case Format::YAML:
748bcb0991SDimitry Andric     return createStringError(std::make_error_code(std::errc::invalid_argument),
758bcb0991SDimitry Andric                              "The YAML format can't be used with a string "
768bcb0991SDimitry Andric                              "table. Use yaml-strtab instead.");
778bcb0991SDimitry Andric   case Format::YAMLStrTab:
788bcb0991SDimitry Andric     return std::make_unique<YAMLStrTabRemarkParser>(Buf, std::move(StrTab));
798bcb0991SDimitry Andric   case Format::Bitstream:
808bcb0991SDimitry Andric     return std::make_unique<BitstreamRemarkParser>(Buf, std::move(StrTab));
818bcb0991SDimitry Andric   case Format::Unknown:
828bcb0991SDimitry Andric     return createStringError(std::make_error_code(std::errc::invalid_argument),
838bcb0991SDimitry Andric                              "Unknown remark parser format.");
848bcb0991SDimitry Andric   }
858bcb0991SDimitry Andric   llvm_unreachable("unhandled ParseFormat");
868bcb0991SDimitry Andric }
878bcb0991SDimitry Andric 
888bcb0991SDimitry Andric Expected<std::unique_ptr<RemarkParser>>
createRemarkParserFromMeta(Format ParserFormat,StringRef Buf,std::optional<ParsedStringTable> StrTab,std::optional<StringRef> ExternalFilePrependPath)898bcb0991SDimitry Andric llvm::remarks::createRemarkParserFromMeta(
90*bdd1243dSDimitry Andric     Format ParserFormat, StringRef Buf, std::optional<ParsedStringTable> StrTab,
91*bdd1243dSDimitry Andric     std::optional<StringRef> ExternalFilePrependPath) {
928bcb0991SDimitry Andric   switch (ParserFormat) {
938bcb0991SDimitry Andric   // Depending on the metadata, the format can be either yaml or yaml-strtab,
948bcb0991SDimitry Andric   // regardless of the input argument.
958bcb0991SDimitry Andric   case Format::YAML:
968bcb0991SDimitry Andric   case Format::YAMLStrTab:
978bcb0991SDimitry Andric     return createYAMLParserFromMeta(Buf, std::move(StrTab),
988bcb0991SDimitry Andric                                     std::move(ExternalFilePrependPath));
998bcb0991SDimitry Andric   case Format::Bitstream:
1008bcb0991SDimitry Andric     return createBitstreamParserFromMeta(Buf, std::move(StrTab),
1018bcb0991SDimitry Andric                                          std::move(ExternalFilePrependPath));
1028bcb0991SDimitry Andric   case Format::Unknown:
1038bcb0991SDimitry Andric     return createStringError(std::make_error_code(std::errc::invalid_argument),
1048bcb0991SDimitry Andric                              "Unknown remark parser format.");
1058bcb0991SDimitry Andric   }
1068bcb0991SDimitry Andric   llvm_unreachable("unhandled ParseFormat");
1078bcb0991SDimitry Andric }
1088bcb0991SDimitry Andric 
1098bcb0991SDimitry Andric namespace {
1100b57cec5SDimitry Andric // Wrapper that holds the state needed to interact with the C API.
1110b57cec5SDimitry Andric struct CParser {
1128bcb0991SDimitry Andric   std::unique_ptr<RemarkParser> TheParser;
113*bdd1243dSDimitry Andric   std::optional<std::string> Err;
1140b57cec5SDimitry Andric 
CParser__anonbcbe98d50111::CParser1150b57cec5SDimitry Andric   CParser(Format ParserFormat, StringRef Buf,
116*bdd1243dSDimitry Andric           std::optional<ParsedStringTable> StrTab = std::nullopt)
1178bcb0991SDimitry Andric       : TheParser(cantFail(
1188bcb0991SDimitry Andric             StrTab ? createRemarkParser(ParserFormat, Buf, std::move(*StrTab))
1198bcb0991SDimitry Andric                    : createRemarkParser(ParserFormat, Buf))) {}
1200b57cec5SDimitry Andric 
handleError__anonbcbe98d50111::CParser1210b57cec5SDimitry Andric   void handleError(Error E) { Err.emplace(toString(std::move(E))); }
hasError__anonbcbe98d50111::CParser12281ad6265SDimitry Andric   bool hasError() const { return Err.has_value(); }
getMessage__anonbcbe98d50111::CParser1230b57cec5SDimitry Andric   const char *getMessage() const { return Err ? Err->c_str() : nullptr; };
1240b57cec5SDimitry Andric };
1258bcb0991SDimitry Andric } // namespace
1260b57cec5SDimitry Andric 
1270b57cec5SDimitry Andric // Create wrappers for C Binding types (see CBindingWrapping.h).
DEFINE_SIMPLE_CONVERSION_FUNCTIONS(CParser,LLVMRemarkParserRef)1280b57cec5SDimitry Andric DEFINE_SIMPLE_CONVERSION_FUNCTIONS(CParser, LLVMRemarkParserRef)
1290b57cec5SDimitry Andric 
1300b57cec5SDimitry Andric extern "C" LLVMRemarkParserRef LLVMRemarkParserCreateYAML(const void *Buf,
1310b57cec5SDimitry Andric                                                           uint64_t Size) {
1320b57cec5SDimitry Andric   return wrap(new CParser(Format::YAML,
1330b57cec5SDimitry Andric                           StringRef(static_cast<const char *>(Buf), Size)));
1340b57cec5SDimitry Andric }
1350b57cec5SDimitry Andric 
LLVMRemarkParserCreateBitstream(const void * Buf,uint64_t Size)1368bcb0991SDimitry Andric extern "C" LLVMRemarkParserRef LLVMRemarkParserCreateBitstream(const void *Buf,
1378bcb0991SDimitry Andric                                                                uint64_t Size) {
1388bcb0991SDimitry Andric   return wrap(new CParser(Format::Bitstream,
1398bcb0991SDimitry Andric                           StringRef(static_cast<const char *>(Buf), Size)));
1408bcb0991SDimitry Andric }
1418bcb0991SDimitry Andric 
1420b57cec5SDimitry Andric extern "C" LLVMRemarkEntryRef
LLVMRemarkParserGetNext(LLVMRemarkParserRef Parser)1430b57cec5SDimitry Andric LLVMRemarkParserGetNext(LLVMRemarkParserRef Parser) {
1440b57cec5SDimitry Andric   CParser &TheCParser = *unwrap(Parser);
1458bcb0991SDimitry Andric   remarks::RemarkParser &TheParser = *TheCParser.TheParser;
1460b57cec5SDimitry Andric 
1470b57cec5SDimitry Andric   Expected<std::unique_ptr<Remark>> MaybeRemark = TheParser.next();
1480b57cec5SDimitry Andric   if (Error E = MaybeRemark.takeError()) {
1490b57cec5SDimitry Andric     if (E.isA<EndOfFileError>()) {
1500b57cec5SDimitry Andric       consumeError(std::move(E));
1510b57cec5SDimitry Andric       return nullptr;
1520b57cec5SDimitry Andric     }
1530b57cec5SDimitry Andric 
1540b57cec5SDimitry Andric     // Handle the error. Allow it to be checked through HasError and
1550b57cec5SDimitry Andric     // GetErrorMessage.
1560b57cec5SDimitry Andric     TheCParser.handleError(std::move(E));
1570b57cec5SDimitry Andric     return nullptr;
1580b57cec5SDimitry Andric   }
1590b57cec5SDimitry Andric 
1600b57cec5SDimitry Andric   // Valid remark.
1610b57cec5SDimitry Andric   return wrap(MaybeRemark->release());
1620b57cec5SDimitry Andric }
1630b57cec5SDimitry Andric 
LLVMRemarkParserHasError(LLVMRemarkParserRef Parser)1640b57cec5SDimitry Andric extern "C" LLVMBool LLVMRemarkParserHasError(LLVMRemarkParserRef Parser) {
1650b57cec5SDimitry Andric   return unwrap(Parser)->hasError();
1660b57cec5SDimitry Andric }
1670b57cec5SDimitry Andric 
1680b57cec5SDimitry Andric extern "C" const char *
LLVMRemarkParserGetErrorMessage(LLVMRemarkParserRef Parser)1690b57cec5SDimitry Andric LLVMRemarkParserGetErrorMessage(LLVMRemarkParserRef Parser) {
1700b57cec5SDimitry Andric   return unwrap(Parser)->getMessage();
1710b57cec5SDimitry Andric }
1720b57cec5SDimitry Andric 
LLVMRemarkParserDispose(LLVMRemarkParserRef Parser)1730b57cec5SDimitry Andric extern "C" void LLVMRemarkParserDispose(LLVMRemarkParserRef Parser) {
1740b57cec5SDimitry Andric   delete unwrap(Parser);
1750b57cec5SDimitry Andric }
176