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