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
) {
27 static void setRecordName(unsigned RecordID
, BitstreamWriter
&Bitstream
,
28 SmallVectorImpl
<uint64_t> &R
, StringRef Str
) {
30 R
.push_back(RecordID
);
32 Bitstream
.EmitRecord(bitc::BLOCKINFO_CODE_SETRECORDNAME
, R
);
35 static void initBlock(unsigned BlockID
, BitstreamWriter
&Bitstream
,
36 SmallVectorImpl
<uint64_t> &R
, StringRef Str
) {
39 Bitstream
.EmitRecord(bitc::BLOCKINFO_CODE_SETBID
, R
);
43 Bitstream
.EmitRecord(bitc::BLOCKINFO_CODE_BLOCKNAME
, R
);
46 void BitstreamRemarkSerializerHelper::setupMetaBlockInfo() {
47 // Setup the metadata block.
48 initBlock(META_BLOCK_ID
, Bitstream
, R
, MetaBlockName
);
50 // The container information.
51 setRecordName(RECORD_META_CONTAINER_INFO
, Bitstream
, R
,
52 MetaContainerInfoName
);
54 auto Abbrev
= std::make_shared
<BitCodeAbbrev
>();
55 Abbrev
->Add(BitCodeAbbrevOp(RECORD_META_CONTAINER_INFO
));
56 Abbrev
->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed
, 32)); // Version.
57 Abbrev
->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed
, 2)); // Type.
58 RecordMetaContainerInfoAbbrevID
=
59 Bitstream
.EmitBlockInfoAbbrev(META_BLOCK_ID
, Abbrev
);
62 void BitstreamRemarkSerializerHelper::setupMetaRemarkVersion() {
63 setRecordName(RECORD_META_REMARK_VERSION
, Bitstream
, R
,
64 MetaRemarkVersionName
);
66 auto Abbrev
= std::make_shared
<BitCodeAbbrev
>();
67 Abbrev
->Add(BitCodeAbbrevOp(RECORD_META_REMARK_VERSION
));
68 Abbrev
->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed
, 32)); // Version.
69 RecordMetaRemarkVersionAbbrevID
=
70 Bitstream
.EmitBlockInfoAbbrev(META_BLOCK_ID
, Abbrev
);
73 void BitstreamRemarkSerializerHelper::emitMetaRemarkVersion(
74 uint64_t RemarkVersion
) {
75 // The remark version is emitted only if we emit remarks.
77 R
.push_back(RECORD_META_REMARK_VERSION
);
78 R
.push_back(RemarkVersion
);
79 Bitstream
.EmitRecordWithAbbrev(RecordMetaRemarkVersionAbbrevID
, R
);
82 void BitstreamRemarkSerializerHelper::setupMetaStrTab() {
83 setRecordName(RECORD_META_STRTAB
, Bitstream
, R
, MetaStrTabName
);
85 auto Abbrev
= std::make_shared
<BitCodeAbbrev
>();
86 Abbrev
->Add(BitCodeAbbrevOp(RECORD_META_STRTAB
));
87 Abbrev
->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob
)); // Raw table.
88 RecordMetaStrTabAbbrevID
=
89 Bitstream
.EmitBlockInfoAbbrev(META_BLOCK_ID
, Abbrev
);
92 void BitstreamRemarkSerializerHelper::emitMetaStrTab(
93 const StringTable
&StrTab
) {
94 // The string table is not emitted if we emit remarks separately.
96 R
.push_back(RECORD_META_STRTAB
);
98 // Serialize to a blob.
100 raw_string_ostream
OS(Buf
);
101 StrTab
.serialize(OS
);
102 StringRef Blob
= OS
.str();
103 Bitstream
.EmitRecordWithBlob(RecordMetaStrTabAbbrevID
, R
, Blob
);
106 void BitstreamRemarkSerializerHelper::setupMetaExternalFile() {
107 setRecordName(RECORD_META_EXTERNAL_FILE
, Bitstream
, R
, MetaExternalFileName
);
109 auto Abbrev
= std::make_shared
<BitCodeAbbrev
>();
110 Abbrev
->Add(BitCodeAbbrevOp(RECORD_META_EXTERNAL_FILE
));
111 Abbrev
->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob
)); // Filename.
112 RecordMetaExternalFileAbbrevID
=
113 Bitstream
.EmitBlockInfoAbbrev(META_BLOCK_ID
, Abbrev
);
116 void BitstreamRemarkSerializerHelper::emitMetaExternalFile(StringRef Filename
) {
117 // The external file is emitted only if we emit the separate metadata.
119 R
.push_back(RECORD_META_EXTERNAL_FILE
);
120 Bitstream
.EmitRecordWithBlob(RecordMetaExternalFileAbbrevID
, R
, Filename
);
123 void BitstreamRemarkSerializerHelper::setupRemarkBlockInfo() {
124 // Setup the remark block.
125 initBlock(REMARK_BLOCK_ID
, Bitstream
, R
, RemarkBlockName
);
127 // The header of a remark.
129 setRecordName(RECORD_REMARK_HEADER
, Bitstream
, R
, RemarkHeaderName
);
131 auto Abbrev
= std::make_shared
<BitCodeAbbrev
>();
132 Abbrev
->Add(BitCodeAbbrevOp(RECORD_REMARK_HEADER
));
133 Abbrev
->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed
, 3)); // Type
134 Abbrev
->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR
, 6)); // Remark Name
135 Abbrev
->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR
, 6)); // Pass name
136 Abbrev
->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR
, 8)); // Function name
137 RecordRemarkHeaderAbbrevID
=
138 Bitstream
.EmitBlockInfoAbbrev(REMARK_BLOCK_ID
, Abbrev
);
141 // The location of a remark.
143 setRecordName(RECORD_REMARK_DEBUG_LOC
, Bitstream
, R
, RemarkDebugLocName
);
145 auto Abbrev
= std::make_shared
<BitCodeAbbrev
>();
146 Abbrev
->Add(BitCodeAbbrevOp(RECORD_REMARK_DEBUG_LOC
));
147 Abbrev
->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR
, 7)); // File
148 Abbrev
->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed
, 32)); // Line
149 Abbrev
->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed
, 32)); // Column
150 RecordRemarkDebugLocAbbrevID
=
151 Bitstream
.EmitBlockInfoAbbrev(REMARK_BLOCK_ID
, Abbrev
);
154 // The hotness of a remark.
156 setRecordName(RECORD_REMARK_HOTNESS
, Bitstream
, R
, RemarkHotnessName
);
158 auto Abbrev
= std::make_shared
<BitCodeAbbrev
>();
159 Abbrev
->Add(BitCodeAbbrevOp(RECORD_REMARK_HOTNESS
));
160 Abbrev
->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR
, 8)); // Hotness
161 RecordRemarkHotnessAbbrevID
=
162 Bitstream
.EmitBlockInfoAbbrev(REMARK_BLOCK_ID
, Abbrev
);
165 // An argument entry with a debug location attached.
167 setRecordName(RECORD_REMARK_ARG_WITH_DEBUGLOC
, Bitstream
, R
,
168 RemarkArgWithDebugLocName
);
170 auto Abbrev
= std::make_shared
<BitCodeAbbrev
>();
171 Abbrev
->Add(BitCodeAbbrevOp(RECORD_REMARK_ARG_WITH_DEBUGLOC
));
172 Abbrev
->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR
, 7)); // Key
173 Abbrev
->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR
, 7)); // Value
174 Abbrev
->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR
, 7)); // File
175 Abbrev
->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed
, 32)); // Line
176 Abbrev
->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed
, 32)); // Column
177 RecordRemarkArgWithDebugLocAbbrevID
=
178 Bitstream
.EmitBlockInfoAbbrev(REMARK_BLOCK_ID
, Abbrev
);
181 // An argument entry with no debug location attached.
183 setRecordName(RECORD_REMARK_ARG_WITHOUT_DEBUGLOC
, Bitstream
, R
,
184 RemarkArgWithoutDebugLocName
);
186 auto Abbrev
= std::make_shared
<BitCodeAbbrev
>();
187 Abbrev
->Add(BitCodeAbbrevOp(RECORD_REMARK_ARG_WITHOUT_DEBUGLOC
));
188 Abbrev
->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR
, 7)); // Key
189 Abbrev
->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR
, 7)); // Value
190 RecordRemarkArgWithoutDebugLocAbbrevID
=
191 Bitstream
.EmitBlockInfoAbbrev(REMARK_BLOCK_ID
, Abbrev
);
195 void BitstreamRemarkSerializerHelper::setupBlockInfo() {
196 // Emit magic number.
197 for (const char C
: ContainerMagic
)
198 Bitstream
.Emit(static_cast<unsigned>(C
), 8);
200 Bitstream
.EnterBlockInfoBlock();
202 // Setup the main metadata. Depending on the container type, we'll setup the
203 // required records next.
204 setupMetaBlockInfo();
206 switch (ContainerType
) {
207 case BitstreamRemarkContainerType::SeparateRemarksMeta
:
208 // Needs a string table that the separate remark file is using.
210 // Needs to know where the external remarks file is.
211 setupMetaExternalFile();
213 case BitstreamRemarkContainerType::SeparateRemarksFile
:
214 // Contains remarks: emit the version.
215 setupMetaRemarkVersion();
216 // Contains remarks: emit the remark abbrevs.
217 setupRemarkBlockInfo();
219 case BitstreamRemarkContainerType::Standalone
:
220 // Contains remarks: emit the version.
221 setupMetaRemarkVersion();
222 // Needs a string table.
224 // Contains remarks: emit the remark abbrevs.
225 setupRemarkBlockInfo();
229 Bitstream
.ExitBlock();
232 void BitstreamRemarkSerializerHelper::emitMetaBlock(
233 uint64_t ContainerVersion
, Optional
<uint64_t> RemarkVersion
,
234 Optional
<const StringTable
*> StrTab
, Optional
<StringRef
> Filename
) {
235 // Emit the meta block
236 Bitstream
.EnterSubblock(META_BLOCK_ID
, 3);
238 // The container version and type.
240 R
.push_back(RECORD_META_CONTAINER_INFO
);
241 R
.push_back(ContainerVersion
);
242 R
.push_back(static_cast<uint64_t>(ContainerType
));
243 Bitstream
.EmitRecordWithAbbrev(RecordMetaContainerInfoAbbrevID
, R
);
245 switch (ContainerType
) {
246 case BitstreamRemarkContainerType::SeparateRemarksMeta
:
247 assert(StrTab
!= None
&& *StrTab
!= nullptr);
248 emitMetaStrTab(**StrTab
);
249 assert(Filename
!= None
);
250 emitMetaExternalFile(*Filename
);
252 case BitstreamRemarkContainerType::SeparateRemarksFile
:
253 assert(RemarkVersion
!= None
);
254 emitMetaRemarkVersion(*RemarkVersion
);
256 case BitstreamRemarkContainerType::Standalone
:
257 assert(RemarkVersion
!= None
);
258 emitMetaRemarkVersion(*RemarkVersion
);
259 assert(StrTab
!= None
&& *StrTab
!= nullptr);
260 emitMetaStrTab(**StrTab
);
264 Bitstream
.ExitBlock();
267 void BitstreamRemarkSerializerHelper::emitRemarkBlock(const Remark
&Remark
,
268 StringTable
&StrTab
) {
269 Bitstream
.EnterSubblock(REMARK_BLOCK_ID
, 4);
272 R
.push_back(RECORD_REMARK_HEADER
);
273 R
.push_back(static_cast<uint64_t>(Remark
.RemarkType
));
274 R
.push_back(StrTab
.add(Remark
.RemarkName
).first
);
275 R
.push_back(StrTab
.add(Remark
.PassName
).first
);
276 R
.push_back(StrTab
.add(Remark
.FunctionName
).first
);
277 Bitstream
.EmitRecordWithAbbrev(RecordRemarkHeaderAbbrevID
, R
);
279 if (const Optional
<RemarkLocation
> &Loc
= Remark
.Loc
) {
281 R
.push_back(RECORD_REMARK_DEBUG_LOC
);
282 R
.push_back(StrTab
.add(Loc
->SourceFilePath
).first
);
283 R
.push_back(Loc
->SourceLine
);
284 R
.push_back(Loc
->SourceColumn
);
285 Bitstream
.EmitRecordWithAbbrev(RecordRemarkDebugLocAbbrevID
, R
);
288 if (Optional
<uint64_t> Hotness
= Remark
.Hotness
) {
290 R
.push_back(RECORD_REMARK_HOTNESS
);
291 R
.push_back(*Hotness
);
292 Bitstream
.EmitRecordWithAbbrev(RecordRemarkHotnessAbbrevID
, R
);
295 for (const Argument
&Arg
: Remark
.Args
) {
297 unsigned Key
= StrTab
.add(Arg
.Key
).first
;
298 unsigned Val
= StrTab
.add(Arg
.Val
).first
;
299 bool HasDebugLoc
= Arg
.Loc
!= None
;
300 R
.push_back(HasDebugLoc
? RECORD_REMARK_ARG_WITH_DEBUGLOC
301 : RECORD_REMARK_ARG_WITHOUT_DEBUGLOC
);
305 R
.push_back(StrTab
.add(Arg
.Loc
->SourceFilePath
).first
);
306 R
.push_back(Arg
.Loc
->SourceLine
);
307 R
.push_back(Arg
.Loc
->SourceColumn
);
309 Bitstream
.EmitRecordWithAbbrev(HasDebugLoc
310 ? RecordRemarkArgWithDebugLocAbbrevID
311 : RecordRemarkArgWithoutDebugLocAbbrevID
,
314 Bitstream
.ExitBlock();
317 void BitstreamRemarkSerializerHelper::flushToStream(raw_ostream
&OS
) {
318 OS
.write(Encoded
.data(), Encoded
.size());
322 StringRef
BitstreamRemarkSerializerHelper::getBuffer() {
323 return StringRef(Encoded
.data(), Encoded
.size());
326 BitstreamRemarkSerializer::BitstreamRemarkSerializer(raw_ostream
&OS
,
328 : RemarkSerializer(Format::Bitstream
, OS
, Mode
),
329 Helper(BitstreamRemarkContainerType::SeparateRemarksFile
) {
330 assert(Mode
== SerializerMode::Separate
&&
331 "For SerializerMode::Standalone, a pre-filled string table needs to "
333 // We always use a string table with bitstream.
337 BitstreamRemarkSerializer::BitstreamRemarkSerializer(raw_ostream
&OS
,
339 StringTable StrTabIn
)
340 : RemarkSerializer(Format::Bitstream
, OS
, Mode
),
341 Helper(Mode
== SerializerMode::Separate
342 ? BitstreamRemarkContainerType::SeparateRemarksFile
343 : BitstreamRemarkContainerType::Standalone
) {
344 StrTab
= std::move(StrTabIn
);
347 void BitstreamRemarkSerializer::emit(const Remark
&Remark
) {
349 // Emit the metadata that is embedded in the remark file.
350 // If we're in standalone mode, serialize the string table as well.
352 Helper
.ContainerType
== BitstreamRemarkContainerType::Standalone
;
353 BitstreamMetaSerializer
MetaSerializer(
355 IsStandalone
? &*StrTab
: Optional
<const StringTable
*>(None
));
356 MetaSerializer
.emit();
361 "The Block info block and the meta block were not emitted yet.");
362 Helper
.emitRemarkBlock(Remark
, *StrTab
);
364 Helper
.flushToStream(OS
);
367 std::unique_ptr
<MetaSerializer
> BitstreamRemarkSerializer::metaSerializer(
368 raw_ostream
&OS
, Optional
<StringRef
> ExternalFilename
) {
369 assert(Helper
.ContainerType
!=
370 BitstreamRemarkContainerType::SeparateRemarksMeta
);
372 Helper
.ContainerType
== BitstreamRemarkContainerType::Standalone
;
373 return std::make_unique
<BitstreamMetaSerializer
>(
375 IsStandalone
? BitstreamRemarkContainerType::Standalone
376 : BitstreamRemarkContainerType::SeparateRemarksMeta
,
377 &*StrTab
, ExternalFilename
);
380 void BitstreamMetaSerializer::emit() {
381 Helper
->setupBlockInfo();
382 Helper
->emitMetaBlock(CurrentContainerVersion
, CurrentRemarkVersion
, StrTab
,
384 Helper
->flushToStream(OS
);