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"
17 using namespace llvm::remarks
;
19 BitstreamRemarkSerializerHelper::BitstreamRemarkSerializerHelper(
20 BitstreamRemarkContainerType ContainerType
)
21 : Encoded(), R(), Bitstream(Encoded
), ContainerType(ContainerType
) {}
23 static void push(SmallVectorImpl
<uint64_t> &R
, StringRef Str
) {
24 for (const char C
: Str
)
28 static void setRecordName(unsigned RecordID
, BitstreamWriter
&Bitstream
,
29 SmallVectorImpl
<uint64_t> &R
, StringRef Str
) {
31 R
.push_back(RecordID
);
33 Bitstream
.EmitRecord(bitc::BLOCKINFO_CODE_SETRECORDNAME
, R
);
36 static void initBlock(unsigned BlockID
, BitstreamWriter
&Bitstream
,
37 SmallVectorImpl
<uint64_t> &R
, StringRef Str
) {
40 Bitstream
.EmitRecord(bitc::BLOCKINFO_CODE_SETBID
, R
);
44 Bitstream
.EmitRecord(bitc::BLOCKINFO_CODE_BLOCKNAME
, R
);
47 void BitstreamRemarkSerializerHelper::setupMetaBlockInfo() {
48 // Setup the metadata block.
49 initBlock(META_BLOCK_ID
, Bitstream
, R
, MetaBlockName
);
51 // The container information.
52 setRecordName(RECORD_META_CONTAINER_INFO
, Bitstream
, R
,
53 MetaContainerInfoName
);
55 auto Abbrev
= std::make_shared
<BitCodeAbbrev
>();
56 Abbrev
->Add(BitCodeAbbrevOp(RECORD_META_CONTAINER_INFO
));
57 Abbrev
->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed
, 32)); // Version.
58 Abbrev
->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed
, 2)); // Type.
59 RecordMetaContainerInfoAbbrevID
=
60 Bitstream
.EmitBlockInfoAbbrev(META_BLOCK_ID
, Abbrev
);
63 void BitstreamRemarkSerializerHelper::setupMetaRemarkVersion() {
64 setRecordName(RECORD_META_REMARK_VERSION
, Bitstream
, R
,
65 MetaRemarkVersionName
);
67 auto Abbrev
= std::make_shared
<BitCodeAbbrev
>();
68 Abbrev
->Add(BitCodeAbbrevOp(RECORD_META_REMARK_VERSION
));
69 Abbrev
->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed
, 32)); // Version.
70 RecordMetaRemarkVersionAbbrevID
=
71 Bitstream
.EmitBlockInfoAbbrev(META_BLOCK_ID
, Abbrev
);
74 void BitstreamRemarkSerializerHelper::emitMetaRemarkVersion(
75 uint64_t RemarkVersion
) {
76 // The remark version is emitted only if we emit remarks.
78 R
.push_back(RECORD_META_REMARK_VERSION
);
79 R
.push_back(RemarkVersion
);
80 Bitstream
.EmitRecordWithAbbrev(RecordMetaRemarkVersionAbbrevID
, R
);
83 void BitstreamRemarkSerializerHelper::setupMetaStrTab() {
84 setRecordName(RECORD_META_STRTAB
, Bitstream
, R
, MetaStrTabName
);
86 auto Abbrev
= std::make_shared
<BitCodeAbbrev
>();
87 Abbrev
->Add(BitCodeAbbrevOp(RECORD_META_STRTAB
));
88 Abbrev
->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob
)); // Raw table.
89 RecordMetaStrTabAbbrevID
=
90 Bitstream
.EmitBlockInfoAbbrev(META_BLOCK_ID
, Abbrev
);
93 void BitstreamRemarkSerializerHelper::emitMetaStrTab(
94 const StringTable
&StrTab
) {
95 // The string table is not emitted if we emit remarks separately.
97 R
.push_back(RECORD_META_STRTAB
);
99 // Serialize to a blob.
101 raw_string_ostream
OS(Buf
);
102 StrTab
.serialize(OS
);
103 StringRef Blob
= OS
.str();
104 Bitstream
.EmitRecordWithBlob(RecordMetaStrTabAbbrevID
, R
, Blob
);
107 void BitstreamRemarkSerializerHelper::setupMetaExternalFile() {
108 setRecordName(RECORD_META_EXTERNAL_FILE
, Bitstream
, R
, MetaExternalFileName
);
110 auto Abbrev
= std::make_shared
<BitCodeAbbrev
>();
111 Abbrev
->Add(BitCodeAbbrevOp(RECORD_META_EXTERNAL_FILE
));
112 Abbrev
->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob
)); // Filename.
113 RecordMetaExternalFileAbbrevID
=
114 Bitstream
.EmitBlockInfoAbbrev(META_BLOCK_ID
, Abbrev
);
117 void BitstreamRemarkSerializerHelper::emitMetaExternalFile(StringRef Filename
) {
118 // The external file is emitted only if we emit the separate metadata.
120 R
.push_back(RECORD_META_EXTERNAL_FILE
);
121 Bitstream
.EmitRecordWithBlob(RecordMetaExternalFileAbbrevID
, R
, Filename
);
124 void BitstreamRemarkSerializerHelper::setupRemarkBlockInfo() {
125 // Setup the remark block.
126 initBlock(REMARK_BLOCK_ID
, Bitstream
, R
, RemarkBlockName
);
128 // The header of a remark.
130 setRecordName(RECORD_REMARK_HEADER
, Bitstream
, R
, RemarkHeaderName
);
132 auto Abbrev
= std::make_shared
<BitCodeAbbrev
>();
133 Abbrev
->Add(BitCodeAbbrevOp(RECORD_REMARK_HEADER
));
134 Abbrev
->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed
, 3)); // Type
135 Abbrev
->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR
, 6)); // Remark Name
136 Abbrev
->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR
, 6)); // Pass name
137 Abbrev
->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR
, 8)); // Function name
138 RecordRemarkHeaderAbbrevID
=
139 Bitstream
.EmitBlockInfoAbbrev(REMARK_BLOCK_ID
, Abbrev
);
142 // The location of a remark.
144 setRecordName(RECORD_REMARK_DEBUG_LOC
, Bitstream
, R
, RemarkDebugLocName
);
146 auto Abbrev
= std::make_shared
<BitCodeAbbrev
>();
147 Abbrev
->Add(BitCodeAbbrevOp(RECORD_REMARK_DEBUG_LOC
));
148 Abbrev
->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR
, 7)); // File
149 Abbrev
->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed
, 32)); // Line
150 Abbrev
->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed
, 32)); // Column
151 RecordRemarkDebugLocAbbrevID
=
152 Bitstream
.EmitBlockInfoAbbrev(REMARK_BLOCK_ID
, Abbrev
);
155 // The hotness of a remark.
157 setRecordName(RECORD_REMARK_HOTNESS
, Bitstream
, R
, RemarkHotnessName
);
159 auto Abbrev
= std::make_shared
<BitCodeAbbrev
>();
160 Abbrev
->Add(BitCodeAbbrevOp(RECORD_REMARK_HOTNESS
));
161 Abbrev
->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR
, 8)); // Hotness
162 RecordRemarkHotnessAbbrevID
=
163 Bitstream
.EmitBlockInfoAbbrev(REMARK_BLOCK_ID
, Abbrev
);
166 // An argument entry with a debug location attached.
168 setRecordName(RECORD_REMARK_ARG_WITH_DEBUGLOC
, Bitstream
, R
,
169 RemarkArgWithDebugLocName
);
171 auto Abbrev
= std::make_shared
<BitCodeAbbrev
>();
172 Abbrev
->Add(BitCodeAbbrevOp(RECORD_REMARK_ARG_WITH_DEBUGLOC
));
173 Abbrev
->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR
, 7)); // Key
174 Abbrev
->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR
, 7)); // Value
175 Abbrev
->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR
, 7)); // File
176 Abbrev
->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed
, 32)); // Line
177 Abbrev
->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed
, 32)); // Column
178 RecordRemarkArgWithDebugLocAbbrevID
=
179 Bitstream
.EmitBlockInfoAbbrev(REMARK_BLOCK_ID
, Abbrev
);
182 // An argument entry with no debug location attached.
184 setRecordName(RECORD_REMARK_ARG_WITHOUT_DEBUGLOC
, Bitstream
, R
,
185 RemarkArgWithoutDebugLocName
);
187 auto Abbrev
= std::make_shared
<BitCodeAbbrev
>();
188 Abbrev
->Add(BitCodeAbbrevOp(RECORD_REMARK_ARG_WITHOUT_DEBUGLOC
));
189 Abbrev
->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR
, 7)); // Key
190 Abbrev
->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR
, 7)); // Value
191 RecordRemarkArgWithoutDebugLocAbbrevID
=
192 Bitstream
.EmitBlockInfoAbbrev(REMARK_BLOCK_ID
, Abbrev
);
196 void BitstreamRemarkSerializerHelper::setupBlockInfo() {
197 // Emit magic number.
198 for (const char C
: ContainerMagic
)
199 Bitstream
.Emit(static_cast<unsigned>(C
), 8);
201 Bitstream
.EnterBlockInfoBlock();
203 // Setup the main metadata. Depending on the container type, we'll setup the
204 // required records next.
205 setupMetaBlockInfo();
207 switch (ContainerType
) {
208 case BitstreamRemarkContainerType::SeparateRemarksMeta
:
209 // Needs a string table that the separate remark file is using.
211 // Needs to know where the external remarks file is.
212 setupMetaExternalFile();
214 case BitstreamRemarkContainerType::SeparateRemarksFile
:
215 // Contains remarks: emit the version.
216 setupMetaRemarkVersion();
217 // Contains remarks: emit the remark abbrevs.
218 setupRemarkBlockInfo();
220 case BitstreamRemarkContainerType::Standalone
:
221 // Contains remarks: emit the version.
222 setupMetaRemarkVersion();
223 // Needs a string table.
225 // Contains remarks: emit the remark abbrevs.
226 setupRemarkBlockInfo();
230 Bitstream
.ExitBlock();
233 void BitstreamRemarkSerializerHelper::emitMetaBlock(
234 uint64_t ContainerVersion
, Optional
<uint64_t> RemarkVersion
,
235 Optional
<const StringTable
*> StrTab
, Optional
<StringRef
> Filename
) {
236 // Emit the meta block
237 Bitstream
.EnterSubblock(META_BLOCK_ID
, 3);
239 // The container version and type.
241 R
.push_back(RECORD_META_CONTAINER_INFO
);
242 R
.push_back(ContainerVersion
);
243 R
.push_back(static_cast<uint64_t>(ContainerType
));
244 Bitstream
.EmitRecordWithAbbrev(RecordMetaContainerInfoAbbrevID
, R
);
246 switch (ContainerType
) {
247 case BitstreamRemarkContainerType::SeparateRemarksMeta
:
248 assert(StrTab
!= None
&& *StrTab
!= nullptr);
249 emitMetaStrTab(**StrTab
);
250 assert(Filename
!= None
);
251 emitMetaExternalFile(*Filename
);
253 case BitstreamRemarkContainerType::SeparateRemarksFile
:
254 assert(RemarkVersion
!= None
);
255 emitMetaRemarkVersion(*RemarkVersion
);
257 case BitstreamRemarkContainerType::Standalone
:
258 assert(RemarkVersion
!= None
);
259 emitMetaRemarkVersion(*RemarkVersion
);
260 assert(StrTab
!= None
&& *StrTab
!= nullptr);
261 emitMetaStrTab(**StrTab
);
265 Bitstream
.ExitBlock();
268 void BitstreamRemarkSerializerHelper::emitRemarkBlock(const Remark
&Remark
,
269 StringTable
&StrTab
) {
270 Bitstream
.EnterSubblock(REMARK_BLOCK_ID
, 4);
273 R
.push_back(RECORD_REMARK_HEADER
);
274 R
.push_back(static_cast<uint64_t>(Remark
.RemarkType
));
275 R
.push_back(StrTab
.add(Remark
.RemarkName
).first
);
276 R
.push_back(StrTab
.add(Remark
.PassName
).first
);
277 R
.push_back(StrTab
.add(Remark
.FunctionName
).first
);
278 Bitstream
.EmitRecordWithAbbrev(RecordRemarkHeaderAbbrevID
, R
);
280 if (const Optional
<RemarkLocation
> &Loc
= Remark
.Loc
) {
282 R
.push_back(RECORD_REMARK_DEBUG_LOC
);
283 R
.push_back(StrTab
.add(Loc
->SourceFilePath
).first
);
284 R
.push_back(Loc
->SourceLine
);
285 R
.push_back(Loc
->SourceColumn
);
286 Bitstream
.EmitRecordWithAbbrev(RecordRemarkDebugLocAbbrevID
, R
);
289 if (Optional
<uint64_t> Hotness
= Remark
.Hotness
) {
291 R
.push_back(RECORD_REMARK_HOTNESS
);
292 R
.push_back(*Hotness
);
293 Bitstream
.EmitRecordWithAbbrev(RecordRemarkHotnessAbbrevID
, R
);
296 for (const Argument
&Arg
: Remark
.Args
) {
298 unsigned Key
= StrTab
.add(Arg
.Key
).first
;
299 unsigned Val
= StrTab
.add(Arg
.Val
).first
;
300 bool HasDebugLoc
= Arg
.Loc
!= None
;
301 R
.push_back(HasDebugLoc
? RECORD_REMARK_ARG_WITH_DEBUGLOC
302 : RECORD_REMARK_ARG_WITHOUT_DEBUGLOC
);
306 R
.push_back(StrTab
.add(Arg
.Loc
->SourceFilePath
).first
);
307 R
.push_back(Arg
.Loc
->SourceLine
);
308 R
.push_back(Arg
.Loc
->SourceColumn
);
310 Bitstream
.EmitRecordWithAbbrev(HasDebugLoc
311 ? RecordRemarkArgWithDebugLocAbbrevID
312 : RecordRemarkArgWithoutDebugLocAbbrevID
,
315 Bitstream
.ExitBlock();
318 void BitstreamRemarkSerializerHelper::flushToStream(raw_ostream
&OS
) {
319 OS
.write(Encoded
.data(), Encoded
.size());
323 StringRef
BitstreamRemarkSerializerHelper::getBuffer() {
324 return StringRef(Encoded
.data(), Encoded
.size());
327 BitstreamRemarkSerializer::BitstreamRemarkSerializer(raw_ostream
&OS
,
329 : RemarkSerializer(OS
, Mode
),
330 Helper(BitstreamRemarkContainerType::SeparateRemarksFile
) {
331 assert(Mode
== SerializerMode::Separate
&&
332 "For SerializerMode::Standalone, a pre-filled string table needs to "
334 // We always use a string table with bitstream.
338 BitstreamRemarkSerializer::BitstreamRemarkSerializer(raw_ostream
&OS
,
340 StringTable StrTabIn
)
341 : RemarkSerializer(OS
, Mode
),
342 Helper(Mode
== SerializerMode::Separate
343 ? BitstreamRemarkContainerType::SeparateRemarksFile
344 : BitstreamRemarkContainerType::Standalone
) {
345 StrTab
= std::move(StrTabIn
);
348 void BitstreamRemarkSerializer::emit(const Remark
&Remark
) {
350 // Emit the metadata that is embedded in the remark file.
351 // If we're in standalone mode, serialize the string table as well.
353 Helper
.ContainerType
== BitstreamRemarkContainerType::Standalone
;
354 BitstreamMetaSerializer
MetaSerializer(
356 IsStandalone
? &*StrTab
: Optional
<const StringTable
*>(None
));
357 MetaSerializer
.emit();
362 "The Block info block and the meta block were not emitted yet.");
363 Helper
.emitRemarkBlock(Remark
, *StrTab
);
365 Helper
.flushToStream(OS
);
368 std::unique_ptr
<MetaSerializer
> BitstreamRemarkSerializer::metaSerializer(
369 raw_ostream
&OS
, Optional
<StringRef
> ExternalFilename
) {
370 assert(Helper
.ContainerType
!=
371 BitstreamRemarkContainerType::SeparateRemarksMeta
);
373 Helper
.ContainerType
== BitstreamRemarkContainerType::Standalone
;
374 return std::make_unique
<BitstreamMetaSerializer
>(
376 IsStandalone
? BitstreamRemarkContainerType::Standalone
377 : BitstreamRemarkContainerType::SeparateRemarksMeta
,
378 &*StrTab
, ExternalFilename
);
381 void BitstreamMetaSerializer::emit() {
382 Helper
->setupBlockInfo();
383 Helper
->emitMetaBlock(CurrentContainerVersion
, CurrentRemarkVersion
, StrTab
,
385 Helper
->flushToStream(OS
);