1 //===- BitstreamRemarkSerializer.cpp --------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
9 // This file provides the implementation of the LLVM bitstream remark serializer
10 // using LLVM's bitstream writer.
12 //===----------------------------------------------------------------------===//
14 #include "llvm/Remarks/BitstreamRemarkSerializer.h"
15 #include "llvm/Remarks/Remark.h"
19 using namespace llvm::remarks
;
21 BitstreamRemarkSerializerHelper::BitstreamRemarkSerializerHelper(
22 BitstreamRemarkContainerType ContainerType
)
23 : Bitstream(Encoded
), ContainerType(ContainerType
) {}
25 static void push(SmallVectorImpl
<uint64_t> &R
, StringRef Str
) {
29 static void setRecordName(unsigned RecordID
, BitstreamWriter
&Bitstream
,
30 SmallVectorImpl
<uint64_t> &R
, StringRef Str
) {
32 R
.push_back(RecordID
);
34 Bitstream
.EmitRecord(bitc::BLOCKINFO_CODE_SETRECORDNAME
, R
);
37 static void initBlock(unsigned BlockID
, BitstreamWriter
&Bitstream
,
38 SmallVectorImpl
<uint64_t> &R
, StringRef Str
) {
41 Bitstream
.EmitRecord(bitc::BLOCKINFO_CODE_SETBID
, R
);
45 Bitstream
.EmitRecord(bitc::BLOCKINFO_CODE_BLOCKNAME
, R
);
48 void BitstreamRemarkSerializerHelper::setupMetaBlockInfo() {
49 // Setup the metadata block.
50 initBlock(META_BLOCK_ID
, Bitstream
, R
, MetaBlockName
);
52 // The container information.
53 setRecordName(RECORD_META_CONTAINER_INFO
, Bitstream
, R
,
54 MetaContainerInfoName
);
56 auto Abbrev
= std::make_shared
<BitCodeAbbrev
>();
57 Abbrev
->Add(BitCodeAbbrevOp(RECORD_META_CONTAINER_INFO
));
58 Abbrev
->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed
, 32)); // Version.
59 Abbrev
->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed
, 2)); // Type.
60 RecordMetaContainerInfoAbbrevID
=
61 Bitstream
.EmitBlockInfoAbbrev(META_BLOCK_ID
, Abbrev
);
64 void BitstreamRemarkSerializerHelper::setupMetaRemarkVersion() {
65 setRecordName(RECORD_META_REMARK_VERSION
, Bitstream
, R
,
66 MetaRemarkVersionName
);
68 auto Abbrev
= std::make_shared
<BitCodeAbbrev
>();
69 Abbrev
->Add(BitCodeAbbrevOp(RECORD_META_REMARK_VERSION
));
70 Abbrev
->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed
, 32)); // Version.
71 RecordMetaRemarkVersionAbbrevID
=
72 Bitstream
.EmitBlockInfoAbbrev(META_BLOCK_ID
, Abbrev
);
75 void BitstreamRemarkSerializerHelper::emitMetaRemarkVersion(
76 uint64_t RemarkVersion
) {
77 // The remark version is emitted only if we emit remarks.
79 R
.push_back(RECORD_META_REMARK_VERSION
);
80 R
.push_back(RemarkVersion
);
81 Bitstream
.EmitRecordWithAbbrev(RecordMetaRemarkVersionAbbrevID
, R
);
84 void BitstreamRemarkSerializerHelper::setupMetaStrTab() {
85 setRecordName(RECORD_META_STRTAB
, Bitstream
, R
, MetaStrTabName
);
87 auto Abbrev
= std::make_shared
<BitCodeAbbrev
>();
88 Abbrev
->Add(BitCodeAbbrevOp(RECORD_META_STRTAB
));
89 Abbrev
->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob
)); // Raw table.
90 RecordMetaStrTabAbbrevID
=
91 Bitstream
.EmitBlockInfoAbbrev(META_BLOCK_ID
, Abbrev
);
94 void BitstreamRemarkSerializerHelper::emitMetaStrTab(
95 const StringTable
&StrTab
) {
96 // The string table is not emitted if we emit remarks separately.
98 R
.push_back(RECORD_META_STRTAB
);
100 // Serialize to a blob.
102 raw_string_ostream
OS(Buf
);
103 StrTab
.serialize(OS
);
104 StringRef Blob
= OS
.str();
105 Bitstream
.EmitRecordWithBlob(RecordMetaStrTabAbbrevID
, R
, Blob
);
108 void BitstreamRemarkSerializerHelper::setupMetaExternalFile() {
109 setRecordName(RECORD_META_EXTERNAL_FILE
, Bitstream
, R
, MetaExternalFileName
);
111 auto Abbrev
= std::make_shared
<BitCodeAbbrev
>();
112 Abbrev
->Add(BitCodeAbbrevOp(RECORD_META_EXTERNAL_FILE
));
113 Abbrev
->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob
)); // Filename.
114 RecordMetaExternalFileAbbrevID
=
115 Bitstream
.EmitBlockInfoAbbrev(META_BLOCK_ID
, Abbrev
);
118 void BitstreamRemarkSerializerHelper::emitMetaExternalFile(StringRef Filename
) {
119 // The external file is emitted only if we emit the separate metadata.
121 R
.push_back(RECORD_META_EXTERNAL_FILE
);
122 Bitstream
.EmitRecordWithBlob(RecordMetaExternalFileAbbrevID
, R
, Filename
);
125 void BitstreamRemarkSerializerHelper::setupRemarkBlockInfo() {
126 // Setup the remark block.
127 initBlock(REMARK_BLOCK_ID
, Bitstream
, R
, RemarkBlockName
);
129 // The header of a remark.
131 setRecordName(RECORD_REMARK_HEADER
, Bitstream
, R
, RemarkHeaderName
);
133 auto Abbrev
= std::make_shared
<BitCodeAbbrev
>();
134 Abbrev
->Add(BitCodeAbbrevOp(RECORD_REMARK_HEADER
));
135 Abbrev
->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed
, 3)); // Type
136 Abbrev
->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR
, 6)); // Remark Name
137 Abbrev
->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR
, 6)); // Pass name
138 Abbrev
->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR
, 8)); // Function name
139 RecordRemarkHeaderAbbrevID
=
140 Bitstream
.EmitBlockInfoAbbrev(REMARK_BLOCK_ID
, Abbrev
);
143 // The location of a remark.
145 setRecordName(RECORD_REMARK_DEBUG_LOC
, Bitstream
, R
, RemarkDebugLocName
);
147 auto Abbrev
= std::make_shared
<BitCodeAbbrev
>();
148 Abbrev
->Add(BitCodeAbbrevOp(RECORD_REMARK_DEBUG_LOC
));
149 Abbrev
->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR
, 7)); // File
150 Abbrev
->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed
, 32)); // Line
151 Abbrev
->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed
, 32)); // Column
152 RecordRemarkDebugLocAbbrevID
=
153 Bitstream
.EmitBlockInfoAbbrev(REMARK_BLOCK_ID
, Abbrev
);
156 // The hotness of a remark.
158 setRecordName(RECORD_REMARK_HOTNESS
, Bitstream
, R
, RemarkHotnessName
);
160 auto Abbrev
= std::make_shared
<BitCodeAbbrev
>();
161 Abbrev
->Add(BitCodeAbbrevOp(RECORD_REMARK_HOTNESS
));
162 Abbrev
->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR
, 8)); // Hotness
163 RecordRemarkHotnessAbbrevID
=
164 Bitstream
.EmitBlockInfoAbbrev(REMARK_BLOCK_ID
, Abbrev
);
167 // An argument entry with a debug location attached.
169 setRecordName(RECORD_REMARK_ARG_WITH_DEBUGLOC
, Bitstream
, R
,
170 RemarkArgWithDebugLocName
);
172 auto Abbrev
= std::make_shared
<BitCodeAbbrev
>();
173 Abbrev
->Add(BitCodeAbbrevOp(RECORD_REMARK_ARG_WITH_DEBUGLOC
));
174 Abbrev
->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR
, 7)); // Key
175 Abbrev
->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR
, 7)); // Value
176 Abbrev
->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR
, 7)); // File
177 Abbrev
->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed
, 32)); // Line
178 Abbrev
->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed
, 32)); // Column
179 RecordRemarkArgWithDebugLocAbbrevID
=
180 Bitstream
.EmitBlockInfoAbbrev(REMARK_BLOCK_ID
, Abbrev
);
183 // An argument entry with no debug location attached.
185 setRecordName(RECORD_REMARK_ARG_WITHOUT_DEBUGLOC
, Bitstream
, R
,
186 RemarkArgWithoutDebugLocName
);
188 auto Abbrev
= std::make_shared
<BitCodeAbbrev
>();
189 Abbrev
->Add(BitCodeAbbrevOp(RECORD_REMARK_ARG_WITHOUT_DEBUGLOC
));
190 Abbrev
->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR
, 7)); // Key
191 Abbrev
->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR
, 7)); // Value
192 RecordRemarkArgWithoutDebugLocAbbrevID
=
193 Bitstream
.EmitBlockInfoAbbrev(REMARK_BLOCK_ID
, Abbrev
);
197 void BitstreamRemarkSerializerHelper::setupBlockInfo() {
198 // Emit magic number.
199 for (const char C
: ContainerMagic
)
200 Bitstream
.Emit(static_cast<unsigned>(C
), 8);
202 Bitstream
.EnterBlockInfoBlock();
204 // Setup the main metadata. Depending on the container type, we'll setup the
205 // required records next.
206 setupMetaBlockInfo();
208 switch (ContainerType
) {
209 case BitstreamRemarkContainerType::SeparateRemarksMeta
:
210 // Needs a string table that the separate remark file is using.
212 // Needs to know where the external remarks file is.
213 setupMetaExternalFile();
215 case BitstreamRemarkContainerType::SeparateRemarksFile
:
216 // Contains remarks: emit the version.
217 setupMetaRemarkVersion();
218 // Contains remarks: emit the remark abbrevs.
219 setupRemarkBlockInfo();
221 case BitstreamRemarkContainerType::Standalone
:
222 // Contains remarks: emit the version.
223 setupMetaRemarkVersion();
224 // Needs a string table.
226 // Contains remarks: emit the remark abbrevs.
227 setupRemarkBlockInfo();
231 Bitstream
.ExitBlock();
234 void BitstreamRemarkSerializerHelper::emitMetaBlock(
235 uint64_t ContainerVersion
, std::optional
<uint64_t> RemarkVersion
,
236 std::optional
<const StringTable
*> StrTab
,
237 std::optional
<StringRef
> Filename
) {
238 // Emit the meta block
239 Bitstream
.EnterSubblock(META_BLOCK_ID
, 3);
241 // The container version and type.
243 R
.push_back(RECORD_META_CONTAINER_INFO
);
244 R
.push_back(ContainerVersion
);
245 R
.push_back(static_cast<uint64_t>(ContainerType
));
246 Bitstream
.EmitRecordWithAbbrev(RecordMetaContainerInfoAbbrevID
, R
);
248 switch (ContainerType
) {
249 case BitstreamRemarkContainerType::SeparateRemarksMeta
:
250 assert(StrTab
!= std::nullopt
&& *StrTab
!= nullptr);
251 emitMetaStrTab(**StrTab
);
252 assert(Filename
!= std::nullopt
);
253 emitMetaExternalFile(*Filename
);
255 case BitstreamRemarkContainerType::SeparateRemarksFile
:
256 assert(RemarkVersion
!= std::nullopt
);
257 emitMetaRemarkVersion(*RemarkVersion
);
259 case BitstreamRemarkContainerType::Standalone
:
260 assert(RemarkVersion
!= std::nullopt
);
261 emitMetaRemarkVersion(*RemarkVersion
);
262 assert(StrTab
!= std::nullopt
&& *StrTab
!= nullptr);
263 emitMetaStrTab(**StrTab
);
267 Bitstream
.ExitBlock();
270 void BitstreamRemarkSerializerHelper::emitRemarkBlock(const Remark
&Remark
,
271 StringTable
&StrTab
) {
272 Bitstream
.EnterSubblock(REMARK_BLOCK_ID
, 4);
275 R
.push_back(RECORD_REMARK_HEADER
);
276 R
.push_back(static_cast<uint64_t>(Remark
.RemarkType
));
277 R
.push_back(StrTab
.add(Remark
.RemarkName
).first
);
278 R
.push_back(StrTab
.add(Remark
.PassName
).first
);
279 R
.push_back(StrTab
.add(Remark
.FunctionName
).first
);
280 Bitstream
.EmitRecordWithAbbrev(RecordRemarkHeaderAbbrevID
, R
);
282 if (const std::optional
<RemarkLocation
> &Loc
= Remark
.Loc
) {
284 R
.push_back(RECORD_REMARK_DEBUG_LOC
);
285 R
.push_back(StrTab
.add(Loc
->SourceFilePath
).first
);
286 R
.push_back(Loc
->SourceLine
);
287 R
.push_back(Loc
->SourceColumn
);
288 Bitstream
.EmitRecordWithAbbrev(RecordRemarkDebugLocAbbrevID
, R
);
291 if (std::optional
<uint64_t> Hotness
= Remark
.Hotness
) {
293 R
.push_back(RECORD_REMARK_HOTNESS
);
294 R
.push_back(*Hotness
);
295 Bitstream
.EmitRecordWithAbbrev(RecordRemarkHotnessAbbrevID
, R
);
298 for (const Argument
&Arg
: Remark
.Args
) {
300 unsigned Key
= StrTab
.add(Arg
.Key
).first
;
301 unsigned Val
= StrTab
.add(Arg
.Val
).first
;
302 bool HasDebugLoc
= Arg
.Loc
!= std::nullopt
;
303 R
.push_back(HasDebugLoc
? RECORD_REMARK_ARG_WITH_DEBUGLOC
304 : RECORD_REMARK_ARG_WITHOUT_DEBUGLOC
);
308 R
.push_back(StrTab
.add(Arg
.Loc
->SourceFilePath
).first
);
309 R
.push_back(Arg
.Loc
->SourceLine
);
310 R
.push_back(Arg
.Loc
->SourceColumn
);
312 Bitstream
.EmitRecordWithAbbrev(HasDebugLoc
313 ? RecordRemarkArgWithDebugLocAbbrevID
314 : RecordRemarkArgWithoutDebugLocAbbrevID
,
317 Bitstream
.ExitBlock();
320 void BitstreamRemarkSerializerHelper::flushToStream(raw_ostream
&OS
) {
321 OS
.write(Encoded
.data(), Encoded
.size());
325 StringRef
BitstreamRemarkSerializerHelper::getBuffer() {
326 return StringRef(Encoded
.data(), Encoded
.size());
329 BitstreamRemarkSerializer::BitstreamRemarkSerializer(raw_ostream
&OS
,
331 : RemarkSerializer(Format::Bitstream
, OS
, Mode
),
332 Helper(BitstreamRemarkContainerType::SeparateRemarksFile
) {
333 assert(Mode
== SerializerMode::Separate
&&
334 "For SerializerMode::Standalone, a pre-filled string table needs to "
336 // We always use a string table with bitstream.
340 BitstreamRemarkSerializer::BitstreamRemarkSerializer(raw_ostream
&OS
,
342 StringTable StrTabIn
)
343 : RemarkSerializer(Format::Bitstream
, OS
, Mode
),
344 Helper(Mode
== SerializerMode::Separate
345 ? BitstreamRemarkContainerType::SeparateRemarksFile
346 : BitstreamRemarkContainerType::Standalone
) {
347 StrTab
= std::move(StrTabIn
);
350 void BitstreamRemarkSerializer::emit(const Remark
&Remark
) {
352 // Emit the metadata that is embedded in the remark file.
353 // If we're in standalone mode, serialize the string table as well.
355 Helper
.ContainerType
== BitstreamRemarkContainerType::Standalone
;
356 BitstreamMetaSerializer
MetaSerializer(
358 IsStandalone
? &*StrTab
359 : std::optional
<const StringTable
*>(std::nullopt
));
360 MetaSerializer
.emit();
365 "The Block info block and the meta block were not emitted yet.");
366 Helper
.emitRemarkBlock(Remark
, *StrTab
);
368 Helper
.flushToStream(OS
);
371 std::unique_ptr
<MetaSerializer
> BitstreamRemarkSerializer::metaSerializer(
372 raw_ostream
&OS
, std::optional
<StringRef
> ExternalFilename
) {
373 assert(Helper
.ContainerType
!=
374 BitstreamRemarkContainerType::SeparateRemarksMeta
);
376 Helper
.ContainerType
== BitstreamRemarkContainerType::Standalone
;
377 return std::make_unique
<BitstreamMetaSerializer
>(
379 IsStandalone
? BitstreamRemarkContainerType::Standalone
380 : BitstreamRemarkContainerType::SeparateRemarksMeta
,
381 &*StrTab
, ExternalFilename
);
384 void BitstreamMetaSerializer::emit() {
385 Helper
->setupBlockInfo();
386 Helper
->emitMetaBlock(CurrentContainerVersion
, CurrentRemarkVersion
, StrTab
,
388 Helper
->flushToStream(OS
);