//===-- 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_BITSTREAMREMARKSERIALIZER_H #define LLVM_REMARKS_BITSTREAMREMARKSERIALIZER_H #include "llvm/Bitstream/BitstreamWriter.h" #include "llvm/Remarks/BitstreamRemarkContainer.h" #include "llvm/Remarks/RemarkSerializer.h" #include namespace llvm { namespace remarks { struct 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 Encoded; /// Buffer used to construct records and pass to the bitstream writer. SmallVector 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, std::optional RemarkVersion, std::optional StrTab = std::nullopt, std::optional Filename = std::nullopt); /// 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( raw_ostream &OS, std::optional ExternalFilename = std::nullopt) 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. std::optional TmpHelper; /// The actual helper, that can point to \p TmpHelper or to an external helper /// object. BitstreamRemarkSerializerHelper *Helper = nullptr; std::optional StrTab; std::optional ExternalFilename; /// Create a new meta serializer based on \p ContainerType. BitstreamMetaSerializer( raw_ostream &OS, BitstreamRemarkContainerType ContainerType, std::optional StrTab = std::nullopt, std::optional ExternalFilename = std::nullopt) : MetaSerializer(OS), TmpHelper(std::nullopt), 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, std::optional StrTab = std::nullopt, std::optional ExternalFilename = std::nullopt) : MetaSerializer(OS), TmpHelper(std::nullopt), Helper(&Helper), StrTab(StrTab), ExternalFilename(ExternalFilename) {} void emit() override; }; } // end namespace remarks } // end namespace llvm #endif // LLVM_REMARKS_BITSTREAMREMARKSERIALIZER_H