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