1 //===-- BitstreamRemarkSerializer.h - Bitstream serializer ------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This file provides an implementation of the serializer using the LLVM
10 // Bitstream format.
11 //
12 //===----------------------------------------------------------------------===//
13 
14 #ifndef LLVM_REMARKS_BITSTREAMREMARKSERIALIZER_H
15 #define LLVM_REMARKS_BITSTREAMREMARKSERIALIZER_H
16 
17 #include "llvm/Bitstream/BitstreamWriter.h"
18 #include "llvm/Remarks/BitstreamRemarkContainer.h"
19 #include "llvm/Remarks/RemarkSerializer.h"
20 #include <optional>
21 
22 namespace llvm {
23 namespace remarks {
24 
25 struct Remarks;
26 
27 /// Serialize the remarks to LLVM bitstream.
28 /// This class provides ways to emit remarks in the LLVM bitstream format and
29 /// its associated metadata.
30 ///
31 /// * The separate model:
32 ///   Separate meta:        | Container info
33 ///                         | String table
34 ///                         | External file
35 ///
36 ///   Separate remarks:     | Container info
37 ///                         | Remark version
38 ///                         | Remark0
39 ///                         | Remark1
40 ///                         | Remark2
41 ///                         | ...
42 ///
43 /// * The standalone model: | Container info
44 ///                         | String table
45 ///                         | Remark version
46 ///                         | Remark0
47 ///                         | Remark1
48 ///                         | Remark2
49 ///                         | ...
50 ///
51 struct BitstreamRemarkSerializerHelper {
52   /// Buffer used for encoding the bitstream before writing it to the final
53   /// stream.
54   SmallVector<char, 1024> Encoded;
55   /// Buffer used to construct records and pass to the bitstream writer.
56   SmallVector<uint64_t, 64> R;
57   /// The Bitstream writer.
58   BitstreamWriter Bitstream;
59   /// The type of the container we are serializing.
60   BitstreamRemarkContainerType ContainerType;
61 
62   /// Abbrev IDs initialized in the block info block.
63   /// Note: depending on the container type, some IDs might be uninitialized.
64   /// Warning: When adding more abbrev IDs, make sure to update the
65   /// BlockCodeSize (in the call to EnterSubblock).
66   uint64_t RecordMetaContainerInfoAbbrevID = 0;
67   uint64_t RecordMetaRemarkVersionAbbrevID = 0;
68   uint64_t RecordMetaStrTabAbbrevID = 0;
69   uint64_t RecordMetaExternalFileAbbrevID = 0;
70   uint64_t RecordRemarkHeaderAbbrevID = 0;
71   uint64_t RecordRemarkDebugLocAbbrevID = 0;
72   uint64_t RecordRemarkHotnessAbbrevID = 0;
73   uint64_t RecordRemarkArgWithDebugLocAbbrevID = 0;
74   uint64_t RecordRemarkArgWithoutDebugLocAbbrevID = 0;
75 
76   BitstreamRemarkSerializerHelper(BitstreamRemarkContainerType ContainerType);
77 
78   // Disable copy and move: Bitstream points to Encoded, which needs special
79   // handling during copy/move, but moving the vectors is probably useless
80   // anyway.
81   BitstreamRemarkSerializerHelper(const BitstreamRemarkSerializerHelper &) =
82       delete;
83   BitstreamRemarkSerializerHelper &
84   operator=(const BitstreamRemarkSerializerHelper &) = delete;
85   BitstreamRemarkSerializerHelper(BitstreamRemarkSerializerHelper &&) = delete;
86   BitstreamRemarkSerializerHelper &
87   operator=(BitstreamRemarkSerializerHelper &&) = delete;
88 
89   /// Set up the necessary block info entries according to the container type.
90   void setupBlockInfo();
91 
92   /// Set up the block info for the metadata block.
93   void setupMetaBlockInfo();
94   /// The remark version in the metadata block.
95   void setupMetaRemarkVersion();
96   void emitMetaRemarkVersion(uint64_t RemarkVersion);
97   /// The strtab in the metadata block.
98   void setupMetaStrTab();
99   void emitMetaStrTab(const StringTable &StrTab);
100   /// The external file in the metadata block.
101   void setupMetaExternalFile();
102   void emitMetaExternalFile(StringRef Filename);
103 
104   /// The block info for the remarks block.
105   void setupRemarkBlockInfo();
106 
107   /// Emit the metadata for the remarks.
108   void emitMetaBlock(uint64_t ContainerVersion,
109                      std::optional<uint64_t> RemarkVersion,
110                      std::optional<const StringTable *> StrTab = std::nullopt,
111                      std::optional<StringRef> Filename = std::nullopt);
112 
113   /// Emit a remark block. The string table is required.
114   void emitRemarkBlock(const Remark &Remark, StringTable &StrTab);
115   /// Finalize the writing to \p OS.
116   void flushToStream(raw_ostream &OS);
117   /// Finalize the writing to a buffer.
118   /// The contents of the buffer remain valid for the lifetime of the object.
119   /// Any call to any other function in this class will invalidate the buffer.
120   StringRef getBuffer();
121 };
122 
123 /// Implementation of the remark serializer using LLVM bitstream.
124 struct BitstreamRemarkSerializer : public RemarkSerializer {
125   /// The file should contain:
126   /// 1) The block info block that describes how to read the blocks.
127   /// 2) The metadata block that contains various information about the remarks
128   ///    in the file.
129   /// 3) A number of remark blocks.
130 
131   /// We need to set up 1) and 2) first, so that we can emit 3) after. This flag
132   /// is used to emit the first two blocks only once.
133   bool DidSetUp = false;
134   /// The helper to emit bitstream.
135   BitstreamRemarkSerializerHelper Helper;
136 
137   /// Construct a serializer that will create its own string table.
138   BitstreamRemarkSerializer(raw_ostream &OS, SerializerMode Mode);
139   /// Construct a serializer with a pre-filled string table.
140   BitstreamRemarkSerializer(raw_ostream &OS, SerializerMode Mode,
141                             StringTable StrTab);
142 
143   /// Emit a remark to the stream. This also emits the metadata associated to
144   /// the remarks based on the SerializerMode specified at construction.
145   /// This writes the serialized output to the provided stream.
146   void emit(const Remark &Remark) override;
147   /// The metadata serializer associated to this remark serializer. Based on the
148   /// container type of the current serializer, the container type of the
149   /// metadata serializer will change.
150   std::unique_ptr<MetaSerializer> metaSerializer(
151       raw_ostream &OS,
152       std::optional<StringRef> ExternalFilename = std::nullopt) override;
153 
154   static bool classof(const RemarkSerializer *S) {
155     return S->SerializerFormat == Format::Bitstream;
156   }
157 };
158 
159 /// Serializer of metadata for bitstream remarks.
160 struct BitstreamMetaSerializer : public MetaSerializer {
161   /// This class can be used with [1] a pre-constructed
162   /// BitstreamRemarkSerializerHelper, or with [2] one that is owned by the meta
163   /// serializer. In case of [1], we need to be able to store a reference to the
164   /// object, while in case of [2] we need to store the whole object.
165   std::optional<BitstreamRemarkSerializerHelper> TmpHelper;
166   /// The actual helper, that can point to \p TmpHelper or to an external helper
167   /// object.
168   BitstreamRemarkSerializerHelper *Helper = nullptr;
169 
170   std::optional<const StringTable *> StrTab;
171   std::optional<StringRef> ExternalFilename;
172 
173   /// Create a new meta serializer based on \p ContainerType.
174   BitstreamMetaSerializer(
175       raw_ostream &OS, BitstreamRemarkContainerType ContainerType,
176       std::optional<const StringTable *> StrTab = std::nullopt,
177       std::optional<StringRef> ExternalFilename = std::nullopt)
178       : MetaSerializer(OS), TmpHelper(std::nullopt), Helper(nullptr),
179         StrTab(StrTab), ExternalFilename(ExternalFilename) {
180     TmpHelper.emplace(ContainerType);
181     Helper = &*TmpHelper;
182   }
183 
184   /// Create a new meta serializer based on a previously built \p Helper.
185   BitstreamMetaSerializer(
186       raw_ostream &OS, BitstreamRemarkSerializerHelper &Helper,
187       std::optional<const StringTable *> StrTab = std::nullopt,
188       std::optional<StringRef> ExternalFilename = std::nullopt)
189       : MetaSerializer(OS), TmpHelper(std::nullopt), Helper(&Helper),
190         StrTab(StrTab), ExternalFilename(ExternalFilename) {}
191 
192   void emit() override;
193 };
194 
195 } // end namespace remarks
196 } // end namespace llvm
197 
198 #endif // LLVM_REMARKS_BITSTREAMREMARKSERIALIZER_H
199