diff options
Diffstat (limited to 'include/llvm/Remarks')
-rw-r--r-- | include/llvm/Remarks/BitstreamRemarkContainer.h | 106 | ||||
-rw-r--r-- | include/llvm/Remarks/BitstreamRemarkParser.h | 116 | ||||
-rw-r--r-- | include/llvm/Remarks/BitstreamRemarkSerializer.h | 196 | ||||
-rw-r--r-- | include/llvm/Remarks/Remark.h | 36 | ||||
-rw-r--r-- | include/llvm/Remarks/RemarkFormat.h | 4 | ||||
-rw-r--r-- | include/llvm/Remarks/RemarkParser.h | 38 | ||||
-rw-r--r-- | include/llvm/Remarks/RemarkSerializer.h | 70 | ||||
-rw-r--r-- | include/llvm/Remarks/RemarkStringTable.h | 24 | ||||
-rw-r--r-- | include/llvm/Remarks/YAMLRemarkSerializer.h | 108 |
9 files changed, 653 insertions, 45 deletions
diff --git a/include/llvm/Remarks/BitstreamRemarkContainer.h b/include/llvm/Remarks/BitstreamRemarkContainer.h new file mode 100644 index 000000000000..a2282fca04ab --- /dev/null +++ b/include/llvm/Remarks/BitstreamRemarkContainer.h @@ -0,0 +1,106 @@ +//===-- BitstreamRemarkContainer.h - Container for remarks --------------*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file provides declarations for things used in the various types of +// remark containers. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_REMARKS_REMARK_CONTAINER_H +#define LLVM_REMARKS_REMARK_CONTAINER_H + +#include "llvm/ADT/StringRef.h" +#include "llvm/Bitstream/BitCodes.h" +#include <cstdint> + +namespace llvm { +namespace remarks { + +/// The current version of the remark container. +/// Note: this is different from the version of the remark entry. +constexpr uint64_t CurrentContainerVersion = 0; +/// The magic number used for identifying remark blocks. +constexpr StringLiteral ContainerMagic("RMRK"); + +/// Type of the remark container. +/// The remark container has two modes: +/// * separate: the metadata is separate from the remarks and points to the +/// auxiliary file that contains the remarks. +/// * standalone: the metadata and the remarks are emitted together. +enum class BitstreamRemarkContainerType { + /// The metadata emitted separately. + /// This will contain the following: + /// * Container version and type + /// * String table + /// * External file + SeparateRemarksMeta, + /// The remarks emitted separately. + /// This will contain the following: + /// * Container version and type + /// * Remark version + SeparateRemarksFile, + /// Everything is emitted together. + /// This will contain the following: + /// * Container version and type + /// * Remark version + /// * String table + Standalone, + First = SeparateRemarksMeta, + Last = Standalone, +}; + +/// The possible blocks that will be encountered in a bitstream remark +/// container. +enum BlockIDs { + /// The metadata block is mandatory. It should always come after the + /// BLOCKINFO_BLOCK, and contains metadata that should be used when parsing + /// REMARK_BLOCKs. + /// There should always be only one META_BLOCK. + META_BLOCK_ID = bitc::FIRST_APPLICATION_BLOCKID, + /// One remark entry is represented using a REMARK_BLOCK. There can be + /// multiple REMARK_BLOCKs in the same file. + REMARK_BLOCK_ID +}; + +constexpr StringRef MetaBlockName = StringRef("Meta", 4); +constexpr StringRef RemarkBlockName = StringRef("Remark", 6); + +/// The possible records that can be encountered in the previously described +/// blocks. +enum RecordIDs { + // Meta block records. + RECORD_META_CONTAINER_INFO = 1, + RECORD_META_REMARK_VERSION, + RECORD_META_STRTAB, + RECORD_META_EXTERNAL_FILE, + // Remark block records. + RECORD_REMARK_HEADER, + RECORD_REMARK_DEBUG_LOC, + RECORD_REMARK_HOTNESS, + RECORD_REMARK_ARG_WITH_DEBUGLOC, + RECORD_REMARK_ARG_WITHOUT_DEBUGLOC, + // Helpers. + RECORD_FIRST = RECORD_META_CONTAINER_INFO, + RECORD_LAST = RECORD_REMARK_ARG_WITHOUT_DEBUGLOC +}; + +constexpr StringRef MetaContainerInfoName = StringRef("Container info", 14); +constexpr StringRef MetaRemarkVersionName = StringRef("Remark version", 14); +constexpr StringRef MetaStrTabName = StringRef("String table", 12); +constexpr StringRef MetaExternalFileName = StringRef("External File", 13); +constexpr StringRef RemarkHeaderName = StringRef("Remark header", 13); +constexpr StringRef RemarkDebugLocName = StringRef("Remark debug location", 21); +constexpr StringRef RemarkHotnessName = StringRef("Remark hotness", 14); +constexpr StringRef RemarkArgWithDebugLocName = + StringRef("Argument with debug location", 28); +constexpr StringRef RemarkArgWithoutDebugLocName = StringRef("Argument", 8); + +} // end namespace remarks +} // end namespace llvm + +#endif /* LLVM_REMARKS_REMARK_CONTAINER_H */ diff --git a/include/llvm/Remarks/BitstreamRemarkParser.h b/include/llvm/Remarks/BitstreamRemarkParser.h new file mode 100644 index 000000000000..7ebd731693b2 --- /dev/null +++ b/include/llvm/Remarks/BitstreamRemarkParser.h @@ -0,0 +1,116 @@ +//===-- BitstreamRemarkParser.h - Bitstream parser --------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file provides an implementation of the remark parser using the LLVM +// Bitstream format. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_REMARKS_BITSTREAM_REMARK_PARSER_H +#define LLVM_REMARKS_BITSTREAM_REMARK_PARSER_H + +#include "llvm/ADT/StringRef.h" +#include "llvm/Bitstream/BitstreamReader.h" +#include "llvm/Remarks/BitstreamRemarkContainer.h" +#include "llvm/Remarks/Remark.h" +#include "llvm/Remarks/RemarkParser.h" +#include "llvm/Support/Error.h" +#include <array> + +namespace llvm { +namespace remarks { + +/// Helper to parse a META_BLOCK for a bitstream remark container. +struct BitstreamMetaParserHelper { + /// The Bitstream reader. + BitstreamCursor &Stream; + /// Reference to the storage for the block info. + BitstreamBlockInfo &BlockInfo; + /// The parsed content: depending on the container type, some fields might be + /// empty. + Optional<uint64_t> ContainerVersion; + Optional<uint8_t> ContainerType; + Optional<StringRef> StrTabBuf; + Optional<StringRef> ExternalFilePath; + Optional<uint64_t> RemarkVersion; + + /// Continue parsing with \p Stream. \p Stream is expected to contain a + /// ENTER_SUBBLOCK to the META_BLOCK at the current position. + /// \p Stream is expected to have a BLOCKINFO_BLOCK set. + BitstreamMetaParserHelper(BitstreamCursor &Stream, + BitstreamBlockInfo &BlockInfo); + + /// Parse the META_BLOCK and fill the available entries. + /// This helper does not check for the validity of the fields. + Error parse(); +}; + +/// Helper to parse a REMARK_BLOCK for a bitstream remark container. +struct BitstreamRemarkParserHelper { + /// The Bitstream reader. + BitstreamCursor &Stream; + /// The parsed content: depending on the remark, some fields might be empty. + Optional<uint8_t> Type; + Optional<uint64_t> RemarkNameIdx; + Optional<uint64_t> PassNameIdx; + Optional<uint64_t> FunctionNameIdx; + Optional<uint64_t> SourceFileNameIdx; + Optional<uint32_t> SourceLine; + Optional<uint32_t> SourceColumn; + Optional<uint64_t> Hotness; + struct Argument { + Optional<uint64_t> KeyIdx; + Optional<uint64_t> ValueIdx; + Optional<uint64_t> SourceFileNameIdx; + Optional<uint32_t> SourceLine; + Optional<uint32_t> SourceColumn; + }; + Optional<ArrayRef<Argument>> Args; + /// Avoid re-allocating a vector every time. + SmallVector<Argument, 8> TmpArgs; + + /// Continue parsing with \p Stream. \p Stream is expected to contain a + /// ENTER_SUBBLOCK to the REMARK_BLOCK at the current position. + /// \p Stream is expected to have a BLOCKINFO_BLOCK set and to have already + /// parsed the META_BLOCK. + BitstreamRemarkParserHelper(BitstreamCursor &Stream); + + /// Parse the REMARK_BLOCK and fill the available entries. + /// This helper does not check for the validity of the fields. + Error parse(); +}; + +/// Helper to parse any bitstream remark container. +struct BitstreamParserHelper { + /// The Bitstream reader. + BitstreamCursor Stream; + /// The block info block. + BitstreamBlockInfo BlockInfo; + /// Start parsing at \p Buffer. + BitstreamParserHelper(StringRef Buffer); + /// Parse the magic number. + Expected<std::array<char, 4>> parseMagic(); + /// Parse the block info block containing all the abbrevs. + /// This needs to be called before calling any other parsing function. + Error parseBlockInfoBlock(); + /// Return true if the next block is a META_BLOCK. This function does not move + /// the cursor. + Expected<bool> isMetaBlock(); + /// Return true if the next block is a REMARK_BLOCK. This function does not + /// move the cursor. + Expected<bool> isRemarkBlock(); + /// Return true if the parser reached the end of the stream. + bool atEndOfStream() { return Stream.AtEndOfStream(); } + /// Jump to the end of the stream, skipping everything. + void skipToEnd() { return Stream.skipToEnd(); } +}; + +} // end namespace remarks +} // end namespace llvm + +#endif /* LLVM_REMARKS_BITSTREAM_REMARK_PARSER_H */ diff --git a/include/llvm/Remarks/BitstreamRemarkSerializer.h b/include/llvm/Remarks/BitstreamRemarkSerializer.h new file mode 100644 index 000000000000..62a175a1db0b --- /dev/null +++ b/include/llvm/Remarks/BitstreamRemarkSerializer.h @@ -0,0 +1,196 @@ +//===-- BitstreamRemarkSerializer.h - Bitstream serializer ------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file provides an implementation of the serializer using the LLVM +// Bitstream format. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_REMARKS_BITSTREAM_REMARK_SERIALIZER_H +#define LLVM_REMARKS_BITSTREAM_REMARK_SERIALIZER_H + +#include "llvm/Bitstream/BitstreamWriter.h" +#include "llvm/Remarks/BitstreamRemarkContainer.h" +#include "llvm/Remarks/RemarkSerializer.h" +#include "llvm/Support/raw_ostream.h" + +namespace llvm { +namespace remarks { + +/// Serialize the remarks to LLVM bitstream. +/// This class provides ways to emit remarks in the LLVM bitstream format and +/// its associated metadata. +/// +/// * The separate model: +/// Separate meta: | Container info +/// | String table +/// | External file +/// +/// Separate remarks: | Container info +/// | Remark version +/// | Remark0 +/// | Remark1 +/// | Remark2 +/// | ... +/// +/// * The standalone model: | Container info +/// | String table +/// | Remark version +/// | Remark0 +/// | Remark1 +/// | Remark2 +/// | ... +/// +struct BitstreamRemarkSerializerHelper { + /// Buffer used for encoding the bitstream before writing it to the final + /// stream. + SmallVector<char, 1024> Encoded; + /// Buffer used to construct records and pass to the bitstream writer. + SmallVector<uint64_t, 64> R; + /// The Bitstream writer. + BitstreamWriter Bitstream; + /// The type of the container we are serializing. + BitstreamRemarkContainerType ContainerType; + + /// Abbrev IDs initialized in the block info block. + /// Note: depending on the container type, some IDs might be uninitialized. + /// Warning: When adding more abbrev IDs, make sure to update the + /// BlockCodeSize (in the call to EnterSubblock). + uint64_t RecordMetaContainerInfoAbbrevID = 0; + uint64_t RecordMetaRemarkVersionAbbrevID = 0; + uint64_t RecordMetaStrTabAbbrevID = 0; + uint64_t RecordMetaExternalFileAbbrevID = 0; + uint64_t RecordRemarkHeaderAbbrevID = 0; + uint64_t RecordRemarkDebugLocAbbrevID = 0; + uint64_t RecordRemarkHotnessAbbrevID = 0; + uint64_t RecordRemarkArgWithDebugLocAbbrevID = 0; + uint64_t RecordRemarkArgWithoutDebugLocAbbrevID = 0; + + BitstreamRemarkSerializerHelper(BitstreamRemarkContainerType ContainerType); + + // Disable copy and move: Bitstream points to Encoded, which needs special + // handling during copy/move, but moving the vectors is probably useless + // anyway. + BitstreamRemarkSerializerHelper(const BitstreamRemarkSerializerHelper &) = + delete; + BitstreamRemarkSerializerHelper & + operator=(const BitstreamRemarkSerializerHelper &) = delete; + BitstreamRemarkSerializerHelper(BitstreamRemarkSerializerHelper &&) = delete; + BitstreamRemarkSerializerHelper & + operator=(BitstreamRemarkSerializerHelper &&) = delete; + + /// Set up the necessary block info entries according to the container type. + void setupBlockInfo(); + + /// Set up the block info for the metadata block. + void setupMetaBlockInfo(); + /// The remark version in the metadata block. + void setupMetaRemarkVersion(); + void emitMetaRemarkVersion(uint64_t RemarkVersion); + /// The strtab in the metadata block. + void setupMetaStrTab(); + void emitMetaStrTab(const StringTable &StrTab); + /// The external file in the metadata block. + void setupMetaExternalFile(); + void emitMetaExternalFile(StringRef Filename); + + /// The block info for the remarks block. + void setupRemarkBlockInfo(); + + /// Emit the metadata for the remarks. + void emitMetaBlock(uint64_t ContainerVersion, + Optional<uint64_t> RemarkVersion, + Optional<const StringTable *> StrTab = None, + Optional<StringRef> Filename = None); + + /// Emit a remark block. The string table is required. + void emitRemarkBlock(const Remark &Remark, StringTable &StrTab); + /// Finalize the writing to \p OS. + void flushToStream(raw_ostream &OS); + /// Finalize the writing to a buffer. + /// The contents of the buffer remain valid for the lifetime of the object. + /// Any call to any other function in this class will invalidate the buffer. + StringRef getBuffer(); +}; + +/// Implementation of the remark serializer using LLVM bitstream. +struct BitstreamRemarkSerializer : public RemarkSerializer { + /// The file should contain: + /// 1) The block info block that describes how to read the blocks. + /// 2) The metadata block that contains various information about the remarks + /// in the file. + /// 3) A number of remark blocks. + + /// We need to set up 1) and 2) first, so that we can emit 3) after. This flag + /// is used to emit the first two blocks only once. + bool DidSetUp = false; + /// The helper to emit bitstream. + BitstreamRemarkSerializerHelper Helper; + + /// Construct a serializer that will create its own string table. + BitstreamRemarkSerializer(raw_ostream &OS, SerializerMode Mode); + /// Construct a serializer with a pre-filled string table. + BitstreamRemarkSerializer(raw_ostream &OS, SerializerMode Mode, + StringTable StrTab); + + /// Emit a remark to the stream. This also emits the metadata associated to + /// the remarks based on the SerializerMode specified at construction. + /// This writes the serialized output to the provided stream. + void emit(const Remark &Remark) override; + /// The metadata serializer associated to this remark serializer. Based on the + /// container type of the current serializer, the container type of the + /// metadata serializer will change. + std::unique_ptr<MetaSerializer> + metaSerializer(raw_ostream &OS, + Optional<StringRef> ExternalFilename = None) override; + + static bool classof(const RemarkSerializer *S) { + return S->SerializerFormat == Format::Bitstream; + } +}; + +/// Serializer of metadata for bitstream remarks. +struct BitstreamMetaSerializer : public MetaSerializer { + /// This class can be used with [1] a pre-constructed + /// BitstreamRemarkSerializerHelper, or with [2] one that is owned by the meta + /// serializer. In case of [1], we need to be able to store a reference to the + /// object, while in case of [2] we need to store the whole object. + Optional<BitstreamRemarkSerializerHelper> TmpHelper; + /// The actual helper, that can point to \p TmpHelper or to an external helper + /// object. + BitstreamRemarkSerializerHelper *Helper = nullptr; + + Optional<const StringTable *> StrTab; + Optional<StringRef> ExternalFilename; + + /// Create a new meta serializer based on \p ContainerType. + BitstreamMetaSerializer(raw_ostream &OS, + BitstreamRemarkContainerType ContainerType, + Optional<const StringTable *> StrTab = None, + Optional<StringRef> ExternalFilename = None) + : MetaSerializer(OS), TmpHelper(None), Helper(nullptr), StrTab(StrTab), + ExternalFilename(ExternalFilename) { + TmpHelper.emplace(ContainerType); + Helper = &*TmpHelper; + } + + /// Create a new meta serializer based on a previously built \p Helper. + BitstreamMetaSerializer(raw_ostream &OS, + BitstreamRemarkSerializerHelper &Helper, + Optional<const StringTable *> StrTab = None, + Optional<StringRef> ExternalFilename = None) + : MetaSerializer(OS), TmpHelper(None), Helper(&Helper), StrTab(StrTab), + ExternalFilename(ExternalFilename) {} + + void emit() override; +}; + +} // end namespace remarks +} // end namespace llvm + +#endif /* LLVM_REMARKS_BITSTREAM_REMARK_SERIALIZER_H */ diff --git a/include/llvm/Remarks/Remark.h b/include/llvm/Remarks/Remark.h index 05d0ea60accd..1243311fb8c5 100644 --- a/include/llvm/Remarks/Remark.h +++ b/include/llvm/Remarks/Remark.h @@ -23,7 +23,8 @@ namespace llvm { namespace remarks { -constexpr uint64_t Version = 0; +/// The current version of the remark entry. +constexpr uint64_t CurrentRemarkVersion = 0; /// The debug location used to track a remark back to the source file. struct RemarkLocation { @@ -58,7 +59,8 @@ enum class Type { AnalysisFPCommute, AnalysisAliasing, Failure, - LastTypeValue = Failure + First = Unknown, + Last = Failure }; /// A remark type used for both emission and parsing. @@ -107,6 +109,36 @@ private: // Create wrappers for C Binding types (see CBindingWrapping.h). DEFINE_SIMPLE_CONVERSION_FUNCTIONS(Remark, LLVMRemarkEntryRef) +/// Comparison operators for Remark objects and dependent objects. +inline bool operator==(const RemarkLocation &LHS, const RemarkLocation &RHS) { + return LHS.SourceFilePath == RHS.SourceFilePath && + LHS.SourceLine == RHS.SourceLine && + LHS.SourceColumn == RHS.SourceColumn; +} + +inline bool operator!=(const RemarkLocation &LHS, const RemarkLocation &RHS) { + return !(LHS == RHS); +} + +inline bool operator==(const Argument &LHS, const Argument &RHS) { + return LHS.Key == RHS.Key && LHS.Val == RHS.Val && LHS.Loc == RHS.Loc; +} + +inline bool operator!=(const Argument &LHS, const Argument &RHS) { + return !(LHS == RHS); +} + +inline bool operator==(const Remark &LHS, const Remark &RHS) { + return LHS.RemarkType == RHS.RemarkType && LHS.PassName == RHS.PassName && + LHS.RemarkName == RHS.RemarkName && + LHS.FunctionName == RHS.FunctionName && LHS.Loc == RHS.Loc && + LHS.Hotness == RHS.Hotness && LHS.Args == RHS.Args; +} + +inline bool operator!=(const Remark &LHS, const Remark &RHS) { + return !(LHS == RHS); +} + } // end namespace remarks } // end namespace llvm diff --git a/include/llvm/Remarks/RemarkFormat.h b/include/llvm/Remarks/RemarkFormat.h index e167d99d2517..6dd32b226099 100644 --- a/include/llvm/Remarks/RemarkFormat.h +++ b/include/llvm/Remarks/RemarkFormat.h @@ -19,10 +19,10 @@ namespace llvm { namespace remarks { -constexpr StringRef Magic("REMARKS", 7); +constexpr StringLiteral Magic("REMARKS"); /// The format used for serializing/deserializing remarks. -enum class Format { Unknown, YAML }; +enum class Format { Unknown, YAML, YAMLStrTab, Bitstream }; /// Parse and validate a string for the remark format. Expected<Format> parseFormat(StringRef FormatStr); diff --git a/include/llvm/Remarks/RemarkParser.h b/include/llvm/Remarks/RemarkParser.h index 671e1abe5ec7..d6b1fddb06ff 100644 --- a/include/llvm/Remarks/RemarkParser.h +++ b/include/llvm/Remarks/RemarkParser.h @@ -23,9 +23,6 @@ namespace llvm { namespace remarks { -struct ParserImpl; -struct ParsedStringTable; - class EndOfFileError : public ErrorInfo<EndOfFileError> { public: static char ID; @@ -39,11 +36,13 @@ public: }; /// Parser used to parse a raw buffer to remarks::Remark objects. -struct Parser { +struct RemarkParser { /// The format of the parser. Format ParserFormat; + /// Path to prepend when opening an external remark file. + std::string ExternalFilePrependPath; - Parser(Format ParserFormat) : ParserFormat(ParserFormat) {} + RemarkParser(Format ParserFormat) : ParserFormat(ParserFormat) {} /// If no error occurs, this returns a valid Remark object. /// If an error of type EndOfFileError occurs, it is safe to recover from it @@ -52,7 +51,7 @@ struct Parser { /// The pointer should never be null. virtual Expected<std::unique_ptr<Remark>> next() = 0; - virtual ~Parser() = default; + virtual ~RemarkParser() = default; }; /// In-memory representation of the string table parsed from a buffer (e.g. the @@ -60,16 +59,33 @@ struct Parser { struct ParsedStringTable { /// The buffer mapped from the section contents. StringRef Buffer; - /// Collection of offsets in the buffer for each string entry. - SmallVector<size_t, 8> Offsets; + /// This object has high changes to be std::move'd around, so don't use a + /// SmallVector for once. + std::vector<size_t> Offsets; - Expected<StringRef> operator[](size_t Index) const; ParsedStringTable(StringRef Buffer); + /// Disable copy. + ParsedStringTable(const ParsedStringTable &) = delete; + ParsedStringTable &operator=(const ParsedStringTable &) = delete; + /// Should be movable. + ParsedStringTable(ParsedStringTable &&) = default; + ParsedStringTable &operator=(ParsedStringTable &&) = default; + + size_t size() const { return Offsets.size(); } + Expected<StringRef> operator[](size_t Index) const; }; -Expected<std::unique_ptr<Parser>> +Expected<std::unique_ptr<RemarkParser>> createRemarkParser(Format ParserFormat, + StringRef Buf); + +Expected<std::unique_ptr<RemarkParser>> createRemarkParser(Format ParserFormat, StringRef Buf, - Optional<const ParsedStringTable *> StrTab = None); + ParsedStringTable StrTab); + +Expected<std::unique_ptr<RemarkParser>> +createRemarkParserFromMeta(Format ParserFormat, StringRef Buf, + Optional<ParsedStringTable> StrTab = None, + Optional<StringRef> ExternalFilePrependPath = None); } // end namespace remarks } // end namespace llvm diff --git a/include/llvm/Remarks/RemarkSerializer.h b/include/llvm/Remarks/RemarkSerializer.h index def5c2e16620..35752cd5f6fb 100644 --- a/include/llvm/Remarks/RemarkSerializer.h +++ b/include/llvm/Remarks/RemarkSerializer.h @@ -14,54 +14,74 @@ #define LLVM_REMARKS_REMARK_SERIALIZER_H #include "llvm/Remarks/Remark.h" +#include "llvm/Remarks/RemarkFormat.h" #include "llvm/Remarks/RemarkStringTable.h" -#include "llvm/Support/YAMLTraits.h" #include "llvm/Support/raw_ostream.h" namespace llvm { namespace remarks { +enum class SerializerMode { + Separate, // A mode where the metadata is serialized separately from the + // remarks. Typically, this is used when the remarks need to be + // streamed to a side file and the metadata is embedded into the + // final result of the compilation. + Standalone // A mode where everything can be retrieved in the same + // file/buffer. Typically, this is used for storing remarks for + // later use. +}; + +struct MetaSerializer; + /// This is the base class for a remark serializer. /// It includes support for using a string table while emitting. -struct Serializer { +struct RemarkSerializer { + /// The format of the serializer. + Format SerializerFormat; /// The open raw_ostream that the remark diagnostics are emitted to. raw_ostream &OS; + /// The serialization mode. + SerializerMode Mode; /// The string table containing all the unique strings used in the output. /// The table can be serialized to be consumed after the compilation. Optional<StringTable> StrTab; - Serializer(raw_ostream &OS) : OS(OS), StrTab() {} + RemarkSerializer(Format SerializerFormat, raw_ostream &OS, + SerializerMode Mode) + : SerializerFormat(SerializerFormat), OS(OS), Mode(Mode), StrTab() {} /// This is just an interface. - virtual ~Serializer() = default; + virtual ~RemarkSerializer() = default; + /// Emit a remark to the stream. virtual void emit(const Remark &Remark) = 0; + /// Return the corresponding metadata serializer. + virtual std::unique_ptr<MetaSerializer> + metaSerializer(raw_ostream &OS, + Optional<StringRef> ExternalFilename = None) = 0; }; -/// Wether the serializer should use a string table while emitting. -enum class UseStringTable { No, Yes }; - -/// Serialize the remarks to YAML. One remark entry looks like this: -/// --- !<TYPE> -/// Pass: <PASSNAME> -/// Name: <REMARKNAME> -/// DebugLoc: { File: <SOURCEFILENAME>, Line: <SOURCELINE>, -/// Column: <SOURCECOLUMN> } -/// Function: <FUNCTIONNAME> -/// Args: -/// - <KEY>: <VALUE> -/// DebugLoc: { File: <FILE>, Line: <LINE>, Column: <COL> } -/// ... -struct YAMLSerializer : public Serializer { - /// The YAML streamer. - yaml::Output YAMLOutput; +/// This is the base class for a remark metadata serializer. +struct MetaSerializer { + /// The open raw_ostream that the metadata is emitted to. + raw_ostream &OS; - YAMLSerializer(raw_ostream &OS, - UseStringTable UseStringTable = remarks::UseStringTable::No); + MetaSerializer(raw_ostream &OS) : OS(OS) {} - /// Emit a remark to the stream. - void emit(const Remark &Remark) override; + /// This is just an interface. + virtual ~MetaSerializer() = default; + virtual void emit() = 0; }; +/// Create a remark serializer. +Expected<std::unique_ptr<RemarkSerializer>> +createRemarkSerializer(Format RemarksFormat, SerializerMode Mode, + raw_ostream &OS); + +/// Create a remark serializer that uses a pre-filled string table. +Expected<std::unique_ptr<RemarkSerializer>> +createRemarkSerializer(Format RemarksFormat, SerializerMode Mode, + raw_ostream &OS, remarks::StringTable StrTab); + } // end namespace remarks } // end namespace llvm diff --git a/include/llvm/Remarks/RemarkStringTable.h b/include/llvm/Remarks/RemarkStringTable.h index f9b4fdbbfb8d..4ce27ee884c8 100644 --- a/include/llvm/Remarks/RemarkStringTable.h +++ b/include/llvm/Remarks/RemarkStringTable.h @@ -18,7 +18,7 @@ #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringRef.h" -#include "llvm/Support/Allocator.h" +#include "llvm/Remarks/Remark.h" #include <vector> namespace llvm { @@ -27,21 +27,35 @@ class raw_ostream; namespace remarks { +struct ParsedStringTable; + /// The string table used for serializing remarks. /// This table can be for example serialized in a section to be consumed after /// the compilation. struct StringTable { - /// Allocator holding all the memory used by the map. - BumpPtrAllocator Allocator; /// The string table containing all the unique strings used in the output. /// It maps a string to an unique ID. - StringMap<unsigned, BumpPtrAllocator &> StrTab; + StringMap<unsigned, BumpPtrAllocator> StrTab; /// Total size of the string table when serialized. size_t SerializedSize = 0; - StringTable() : Allocator(), StrTab(Allocator) {} + StringTable() = default; + + /// Disable copy. + StringTable(const StringTable &) = delete; + StringTable &operator=(const StringTable &) = delete; + /// Should be movable. + StringTable(StringTable &&) = default; + StringTable &operator=(StringTable &&) = default; + + /// Construct a string table from a ParsedStringTable. + StringTable(const ParsedStringTable &Other); + /// Add a string to the table. It returns an unique ID of the string. std::pair<unsigned, StringRef> add(StringRef Str); + /// Modify \p R to use strings from this string table. If the string table + /// does not contain the strings, it adds them. + void internalize(Remark &R); /// Serialize the string table to a stream. It is serialized as a little /// endian uint64 (the size of the table in bytes) followed by a sequence of /// NULL-terminated strings, where the N-th string is the string with the ID N diff --git a/include/llvm/Remarks/YAMLRemarkSerializer.h b/include/llvm/Remarks/YAMLRemarkSerializer.h new file mode 100644 index 000000000000..f1213beab15d --- /dev/null +++ b/include/llvm/Remarks/YAMLRemarkSerializer.h @@ -0,0 +1,108 @@ +//===-- YAMLRemarkSerializer.h - YAML Remark serialization ---*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file provides an interface for serializing remarks to YAML. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_REMARKS_YAML_REMARK_SERIALIZER_H +#define LLVM_REMARKS_YAML_REMARK_SERIALIZER_H + +#include "llvm/Remarks/RemarkSerializer.h" +#include "llvm/Support/YAMLTraits.h" + +namespace llvm { +namespace remarks { + +/// Serialize the remarks to YAML. One remark entry looks like this: +/// --- !<TYPE> +/// Pass: <PASSNAME> +/// Name: <REMARKNAME> +/// DebugLoc: { File: <SOURCEFILENAME>, Line: <SOURCELINE>, +/// Column: <SOURCECOLUMN> } +/// Function: <FUNCTIONNAME> +/// Args: +/// - <KEY>: <VALUE> +/// DebugLoc: { File: <FILE>, Line: <LINE>, Column: <COL> } +/// ... +struct YAMLRemarkSerializer : public RemarkSerializer { + /// The YAML streamer. + yaml::Output YAMLOutput; + + YAMLRemarkSerializer(raw_ostream &OS, SerializerMode Mode, + Optional<StringTable> StrTab = None); + + void emit(const Remark &Remark) override; + std::unique_ptr<MetaSerializer> + metaSerializer(raw_ostream &OS, + Optional<StringRef> ExternalFilename = None) override; + + static bool classof(const RemarkSerializer *S) { + return S->SerializerFormat == Format::YAML; + } + +protected: + YAMLRemarkSerializer(Format SerializerFormat, raw_ostream &OS, + SerializerMode Mode, + Optional<StringTable> StrTab = None); +}; + +struct YAMLMetaSerializer : public MetaSerializer { + Optional<StringRef> ExternalFilename; + + YAMLMetaSerializer(raw_ostream &OS, Optional<StringRef> ExternalFilename) + : MetaSerializer(OS), ExternalFilename(ExternalFilename) {} + + void emit() override; +}; + +/// Serialize the remarks to YAML using a string table. An remark entry looks +/// like the regular YAML remark but instead of string entries it's using +/// numbers that map to an index in the string table. +struct YAMLStrTabRemarkSerializer : public YAMLRemarkSerializer { + /// Wether we already emitted the metadata in standalone mode. + /// This should be set to true after the first invocation of `emit`. + bool DidEmitMeta = false; + + YAMLStrTabRemarkSerializer(raw_ostream &OS, SerializerMode Mode) + : YAMLRemarkSerializer(Format::YAMLStrTab, OS, Mode) { + // We always need a string table for this type of serializer. + StrTab.emplace(); + } + YAMLStrTabRemarkSerializer(raw_ostream &OS, SerializerMode Mode, + StringTable StrTab) + : YAMLRemarkSerializer(Format::YAMLStrTab, OS, Mode, std::move(StrTab)) {} + + /// Override to emit the metadata if necessary. + void emit(const Remark &Remark) override; + + std::unique_ptr<MetaSerializer> + metaSerializer(raw_ostream &OS, + Optional<StringRef> ExternalFilename = None) override; + + static bool classof(const RemarkSerializer *S) { + return S->SerializerFormat == Format::YAMLStrTab; + } +}; + +struct YAMLStrTabMetaSerializer : public YAMLMetaSerializer { + /// The string table is part of the metadata. + const StringTable &StrTab; + + YAMLStrTabMetaSerializer(raw_ostream &OS, + Optional<StringRef> ExternalFilename, + const StringTable &StrTab) + : YAMLMetaSerializer(OS, ExternalFilename), StrTab(StrTab) {} + + void emit() override; +}; + +} // end namespace remarks +} // end namespace llvm + +#endif /* LLVM_REMARKS_REMARK_SERIALIZER_H */ |