18bcb0991SDimitry Andric //===- BitstreamRemarkSerializer.cpp --------------------------------------===//
28bcb0991SDimitry Andric //
38bcb0991SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
48bcb0991SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
58bcb0991SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
68bcb0991SDimitry Andric //
78bcb0991SDimitry Andric //===----------------------------------------------------------------------===//
88bcb0991SDimitry Andric //
98bcb0991SDimitry Andric // This file provides the implementation of the LLVM bitstream remark serializer
108bcb0991SDimitry Andric // using LLVM's bitstream writer.
118bcb0991SDimitry Andric //
128bcb0991SDimitry Andric //===----------------------------------------------------------------------===//
138bcb0991SDimitry Andric 
148bcb0991SDimitry Andric #include "llvm/Remarks/BitstreamRemarkSerializer.h"
1581ad6265SDimitry Andric #include "llvm/Remarks/Remark.h"
16*bdd1243dSDimitry Andric #include <optional>
178bcb0991SDimitry Andric 
188bcb0991SDimitry Andric using namespace llvm;
198bcb0991SDimitry Andric using namespace llvm::remarks;
208bcb0991SDimitry Andric 
BitstreamRemarkSerializerHelper(BitstreamRemarkContainerType ContainerType)218bcb0991SDimitry Andric BitstreamRemarkSerializerHelper::BitstreamRemarkSerializerHelper(
228bcb0991SDimitry Andric     BitstreamRemarkContainerType ContainerType)
2304eeddc0SDimitry Andric     : Bitstream(Encoded), ContainerType(ContainerType) {}
248bcb0991SDimitry Andric 
push(SmallVectorImpl<uint64_t> & R,StringRef Str)258bcb0991SDimitry Andric static void push(SmallVectorImpl<uint64_t> &R, StringRef Str) {
26fe6060f1SDimitry Andric   append_range(R, Str);
278bcb0991SDimitry Andric }
288bcb0991SDimitry Andric 
setRecordName(unsigned RecordID,BitstreamWriter & Bitstream,SmallVectorImpl<uint64_t> & R,StringRef Str)298bcb0991SDimitry Andric static void setRecordName(unsigned RecordID, BitstreamWriter &Bitstream,
308bcb0991SDimitry Andric                           SmallVectorImpl<uint64_t> &R, StringRef Str) {
318bcb0991SDimitry Andric   R.clear();
328bcb0991SDimitry Andric   R.push_back(RecordID);
338bcb0991SDimitry Andric   push(R, Str);
348bcb0991SDimitry Andric   Bitstream.EmitRecord(bitc::BLOCKINFO_CODE_SETRECORDNAME, R);
358bcb0991SDimitry Andric }
368bcb0991SDimitry Andric 
initBlock(unsigned BlockID,BitstreamWriter & Bitstream,SmallVectorImpl<uint64_t> & R,StringRef Str)378bcb0991SDimitry Andric static void initBlock(unsigned BlockID, BitstreamWriter &Bitstream,
388bcb0991SDimitry Andric                       SmallVectorImpl<uint64_t> &R, StringRef Str) {
398bcb0991SDimitry Andric   R.clear();
408bcb0991SDimitry Andric   R.push_back(BlockID);
418bcb0991SDimitry Andric   Bitstream.EmitRecord(bitc::BLOCKINFO_CODE_SETBID, R);
428bcb0991SDimitry Andric 
438bcb0991SDimitry Andric   R.clear();
448bcb0991SDimitry Andric   push(R, Str);
458bcb0991SDimitry Andric   Bitstream.EmitRecord(bitc::BLOCKINFO_CODE_BLOCKNAME, R);
468bcb0991SDimitry Andric }
478bcb0991SDimitry Andric 
setupMetaBlockInfo()488bcb0991SDimitry Andric void BitstreamRemarkSerializerHelper::setupMetaBlockInfo() {
498bcb0991SDimitry Andric   // Setup the metadata block.
508bcb0991SDimitry Andric   initBlock(META_BLOCK_ID, Bitstream, R, MetaBlockName);
518bcb0991SDimitry Andric 
528bcb0991SDimitry Andric   // The container information.
538bcb0991SDimitry Andric   setRecordName(RECORD_META_CONTAINER_INFO, Bitstream, R,
548bcb0991SDimitry Andric                 MetaContainerInfoName);
558bcb0991SDimitry Andric 
568bcb0991SDimitry Andric   auto Abbrev = std::make_shared<BitCodeAbbrev>();
578bcb0991SDimitry Andric   Abbrev->Add(BitCodeAbbrevOp(RECORD_META_CONTAINER_INFO));
588bcb0991SDimitry Andric   Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // Version.
598bcb0991SDimitry Andric   Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 2));  // Type.
608bcb0991SDimitry Andric   RecordMetaContainerInfoAbbrevID =
618bcb0991SDimitry Andric       Bitstream.EmitBlockInfoAbbrev(META_BLOCK_ID, Abbrev);
628bcb0991SDimitry Andric }
638bcb0991SDimitry Andric 
setupMetaRemarkVersion()648bcb0991SDimitry Andric void BitstreamRemarkSerializerHelper::setupMetaRemarkVersion() {
658bcb0991SDimitry Andric   setRecordName(RECORD_META_REMARK_VERSION, Bitstream, R,
668bcb0991SDimitry Andric                 MetaRemarkVersionName);
678bcb0991SDimitry Andric 
688bcb0991SDimitry Andric   auto Abbrev = std::make_shared<BitCodeAbbrev>();
698bcb0991SDimitry Andric   Abbrev->Add(BitCodeAbbrevOp(RECORD_META_REMARK_VERSION));
708bcb0991SDimitry Andric   Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // Version.
718bcb0991SDimitry Andric   RecordMetaRemarkVersionAbbrevID =
728bcb0991SDimitry Andric       Bitstream.EmitBlockInfoAbbrev(META_BLOCK_ID, Abbrev);
738bcb0991SDimitry Andric }
748bcb0991SDimitry Andric 
emitMetaRemarkVersion(uint64_t RemarkVersion)758bcb0991SDimitry Andric void BitstreamRemarkSerializerHelper::emitMetaRemarkVersion(
768bcb0991SDimitry Andric     uint64_t RemarkVersion) {
778bcb0991SDimitry Andric   // The remark version is emitted only if we emit remarks.
788bcb0991SDimitry Andric   R.clear();
798bcb0991SDimitry Andric   R.push_back(RECORD_META_REMARK_VERSION);
808bcb0991SDimitry Andric   R.push_back(RemarkVersion);
818bcb0991SDimitry Andric   Bitstream.EmitRecordWithAbbrev(RecordMetaRemarkVersionAbbrevID, R);
828bcb0991SDimitry Andric }
838bcb0991SDimitry Andric 
setupMetaStrTab()848bcb0991SDimitry Andric void BitstreamRemarkSerializerHelper::setupMetaStrTab() {
858bcb0991SDimitry Andric   setRecordName(RECORD_META_STRTAB, Bitstream, R, MetaStrTabName);
868bcb0991SDimitry Andric 
878bcb0991SDimitry Andric   auto Abbrev = std::make_shared<BitCodeAbbrev>();
888bcb0991SDimitry Andric   Abbrev->Add(BitCodeAbbrevOp(RECORD_META_STRTAB));
898bcb0991SDimitry Andric   Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Raw table.
908bcb0991SDimitry Andric   RecordMetaStrTabAbbrevID =
918bcb0991SDimitry Andric       Bitstream.EmitBlockInfoAbbrev(META_BLOCK_ID, Abbrev);
928bcb0991SDimitry Andric }
938bcb0991SDimitry Andric 
emitMetaStrTab(const StringTable & StrTab)948bcb0991SDimitry Andric void BitstreamRemarkSerializerHelper::emitMetaStrTab(
958bcb0991SDimitry Andric     const StringTable &StrTab) {
968bcb0991SDimitry Andric   // The string table is not emitted if we emit remarks separately.
978bcb0991SDimitry Andric   R.clear();
988bcb0991SDimitry Andric   R.push_back(RECORD_META_STRTAB);
998bcb0991SDimitry Andric 
1008bcb0991SDimitry Andric   // Serialize to a blob.
1018bcb0991SDimitry Andric   std::string Buf;
1028bcb0991SDimitry Andric   raw_string_ostream OS(Buf);
1038bcb0991SDimitry Andric   StrTab.serialize(OS);
1048bcb0991SDimitry Andric   StringRef Blob = OS.str();
1058bcb0991SDimitry Andric   Bitstream.EmitRecordWithBlob(RecordMetaStrTabAbbrevID, R, Blob);
1068bcb0991SDimitry Andric }
1078bcb0991SDimitry Andric 
setupMetaExternalFile()1088bcb0991SDimitry Andric void BitstreamRemarkSerializerHelper::setupMetaExternalFile() {
1098bcb0991SDimitry Andric   setRecordName(RECORD_META_EXTERNAL_FILE, Bitstream, R, MetaExternalFileName);
1108bcb0991SDimitry Andric 
1118bcb0991SDimitry Andric   auto Abbrev = std::make_shared<BitCodeAbbrev>();
1128bcb0991SDimitry Andric   Abbrev->Add(BitCodeAbbrevOp(RECORD_META_EXTERNAL_FILE));
1138bcb0991SDimitry Andric   Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Filename.
1148bcb0991SDimitry Andric   RecordMetaExternalFileAbbrevID =
1158bcb0991SDimitry Andric       Bitstream.EmitBlockInfoAbbrev(META_BLOCK_ID, Abbrev);
1168bcb0991SDimitry Andric }
1178bcb0991SDimitry Andric 
emitMetaExternalFile(StringRef Filename)1188bcb0991SDimitry Andric void BitstreamRemarkSerializerHelper::emitMetaExternalFile(StringRef Filename) {
1198bcb0991SDimitry Andric   // The external file is emitted only if we emit the separate metadata.
1208bcb0991SDimitry Andric   R.clear();
1218bcb0991SDimitry Andric   R.push_back(RECORD_META_EXTERNAL_FILE);
1228bcb0991SDimitry Andric   Bitstream.EmitRecordWithBlob(RecordMetaExternalFileAbbrevID, R, Filename);
1238bcb0991SDimitry Andric }
1248bcb0991SDimitry Andric 
setupRemarkBlockInfo()1258bcb0991SDimitry Andric void BitstreamRemarkSerializerHelper::setupRemarkBlockInfo() {
1268bcb0991SDimitry Andric   // Setup the remark block.
1278bcb0991SDimitry Andric   initBlock(REMARK_BLOCK_ID, Bitstream, R, RemarkBlockName);
1288bcb0991SDimitry Andric 
1298bcb0991SDimitry Andric   // The header of a remark.
1308bcb0991SDimitry Andric   {
1318bcb0991SDimitry Andric     setRecordName(RECORD_REMARK_HEADER, Bitstream, R, RemarkHeaderName);
1328bcb0991SDimitry Andric 
1338bcb0991SDimitry Andric     auto Abbrev = std::make_shared<BitCodeAbbrev>();
1348bcb0991SDimitry Andric     Abbrev->Add(BitCodeAbbrevOp(RECORD_REMARK_HEADER));
1358bcb0991SDimitry Andric     Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 3)); // Type
1368bcb0991SDimitry Andric     Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6));   // Remark Name
1378bcb0991SDimitry Andric     Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6));   // Pass name
1388bcb0991SDimitry Andric     Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8));   // Function name
1398bcb0991SDimitry Andric     RecordRemarkHeaderAbbrevID =
1408bcb0991SDimitry Andric         Bitstream.EmitBlockInfoAbbrev(REMARK_BLOCK_ID, Abbrev);
1418bcb0991SDimitry Andric   }
1428bcb0991SDimitry Andric 
1438bcb0991SDimitry Andric   // The location of a remark.
1448bcb0991SDimitry Andric   {
1458bcb0991SDimitry Andric     setRecordName(RECORD_REMARK_DEBUG_LOC, Bitstream, R, RemarkDebugLocName);
1468bcb0991SDimitry Andric 
1478bcb0991SDimitry Andric     auto Abbrev = std::make_shared<BitCodeAbbrev>();
1488bcb0991SDimitry Andric     Abbrev->Add(BitCodeAbbrevOp(RECORD_REMARK_DEBUG_LOC));
1498bcb0991SDimitry Andric     Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 7));    // File
1508bcb0991SDimitry Andric     Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // Line
1518bcb0991SDimitry Andric     Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // Column
1528bcb0991SDimitry Andric     RecordRemarkDebugLocAbbrevID =
1538bcb0991SDimitry Andric         Bitstream.EmitBlockInfoAbbrev(REMARK_BLOCK_ID, Abbrev);
1548bcb0991SDimitry Andric   }
1558bcb0991SDimitry Andric 
1568bcb0991SDimitry Andric   // The hotness of a remark.
1578bcb0991SDimitry Andric   {
1588bcb0991SDimitry Andric     setRecordName(RECORD_REMARK_HOTNESS, Bitstream, R, RemarkHotnessName);
1598bcb0991SDimitry Andric 
1608bcb0991SDimitry Andric     auto Abbrev = std::make_shared<BitCodeAbbrev>();
1618bcb0991SDimitry Andric     Abbrev->Add(BitCodeAbbrevOp(RECORD_REMARK_HOTNESS));
1628bcb0991SDimitry Andric     Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // Hotness
1638bcb0991SDimitry Andric     RecordRemarkHotnessAbbrevID =
1648bcb0991SDimitry Andric         Bitstream.EmitBlockInfoAbbrev(REMARK_BLOCK_ID, Abbrev);
1658bcb0991SDimitry Andric   }
1668bcb0991SDimitry Andric 
1678bcb0991SDimitry Andric   // An argument entry with a debug location attached.
1688bcb0991SDimitry Andric   {
1698bcb0991SDimitry Andric     setRecordName(RECORD_REMARK_ARG_WITH_DEBUGLOC, Bitstream, R,
1708bcb0991SDimitry Andric                   RemarkArgWithDebugLocName);
1718bcb0991SDimitry Andric 
1728bcb0991SDimitry Andric     auto Abbrev = std::make_shared<BitCodeAbbrev>();
1738bcb0991SDimitry Andric     Abbrev->Add(BitCodeAbbrevOp(RECORD_REMARK_ARG_WITH_DEBUGLOC));
1748bcb0991SDimitry Andric     Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 7));    // Key
1758bcb0991SDimitry Andric     Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 7));    // Value
1768bcb0991SDimitry Andric     Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 7));    // File
1778bcb0991SDimitry Andric     Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // Line
1788bcb0991SDimitry Andric     Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // Column
1798bcb0991SDimitry Andric     RecordRemarkArgWithDebugLocAbbrevID =
1808bcb0991SDimitry Andric         Bitstream.EmitBlockInfoAbbrev(REMARK_BLOCK_ID, Abbrev);
1818bcb0991SDimitry Andric   }
1828bcb0991SDimitry Andric 
1838bcb0991SDimitry Andric   // An argument entry with no debug location attached.
1848bcb0991SDimitry Andric   {
1858bcb0991SDimitry Andric     setRecordName(RECORD_REMARK_ARG_WITHOUT_DEBUGLOC, Bitstream, R,
1868bcb0991SDimitry Andric                   RemarkArgWithoutDebugLocName);
1878bcb0991SDimitry Andric 
1888bcb0991SDimitry Andric     auto Abbrev = std::make_shared<BitCodeAbbrev>();
1898bcb0991SDimitry Andric     Abbrev->Add(BitCodeAbbrevOp(RECORD_REMARK_ARG_WITHOUT_DEBUGLOC));
1908bcb0991SDimitry Andric     Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 7)); // Key
1918bcb0991SDimitry Andric     Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 7)); // Value
1928bcb0991SDimitry Andric     RecordRemarkArgWithoutDebugLocAbbrevID =
1938bcb0991SDimitry Andric         Bitstream.EmitBlockInfoAbbrev(REMARK_BLOCK_ID, Abbrev);
1948bcb0991SDimitry Andric   }
1958bcb0991SDimitry Andric }
1968bcb0991SDimitry Andric 
setupBlockInfo()1978bcb0991SDimitry Andric void BitstreamRemarkSerializerHelper::setupBlockInfo() {
1988bcb0991SDimitry Andric   // Emit magic number.
1998bcb0991SDimitry Andric   for (const char C : ContainerMagic)
2008bcb0991SDimitry Andric     Bitstream.Emit(static_cast<unsigned>(C), 8);
2018bcb0991SDimitry Andric 
2028bcb0991SDimitry Andric   Bitstream.EnterBlockInfoBlock();
2038bcb0991SDimitry Andric 
2048bcb0991SDimitry Andric   // Setup the main metadata. Depending on the container type, we'll setup the
2058bcb0991SDimitry Andric   // required records next.
2068bcb0991SDimitry Andric   setupMetaBlockInfo();
2078bcb0991SDimitry Andric 
2088bcb0991SDimitry Andric   switch (ContainerType) {
2098bcb0991SDimitry Andric   case BitstreamRemarkContainerType::SeparateRemarksMeta:
2108bcb0991SDimitry Andric     // Needs a string table that the separate remark file is using.
2118bcb0991SDimitry Andric     setupMetaStrTab();
2128bcb0991SDimitry Andric     // Needs to know where the external remarks file is.
2138bcb0991SDimitry Andric     setupMetaExternalFile();
2148bcb0991SDimitry Andric     break;
2158bcb0991SDimitry Andric   case BitstreamRemarkContainerType::SeparateRemarksFile:
2168bcb0991SDimitry Andric     // Contains remarks: emit the version.
2178bcb0991SDimitry Andric     setupMetaRemarkVersion();
2188bcb0991SDimitry Andric     // Contains remarks: emit the remark abbrevs.
2198bcb0991SDimitry Andric     setupRemarkBlockInfo();
2208bcb0991SDimitry Andric     break;
2218bcb0991SDimitry Andric   case BitstreamRemarkContainerType::Standalone:
2228bcb0991SDimitry Andric     // Contains remarks: emit the version.
2238bcb0991SDimitry Andric     setupMetaRemarkVersion();
2248bcb0991SDimitry Andric     // Needs a string table.
2258bcb0991SDimitry Andric     setupMetaStrTab();
2268bcb0991SDimitry Andric     // Contains remarks: emit the remark abbrevs.
2278bcb0991SDimitry Andric     setupRemarkBlockInfo();
2288bcb0991SDimitry Andric     break;
2298bcb0991SDimitry Andric   }
2308bcb0991SDimitry Andric 
2318bcb0991SDimitry Andric   Bitstream.ExitBlock();
2328bcb0991SDimitry Andric }
2338bcb0991SDimitry Andric 
emitMetaBlock(uint64_t ContainerVersion,std::optional<uint64_t> RemarkVersion,std::optional<const StringTable * > StrTab,std::optional<StringRef> Filename)2348bcb0991SDimitry Andric void BitstreamRemarkSerializerHelper::emitMetaBlock(
235*bdd1243dSDimitry Andric     uint64_t ContainerVersion, std::optional<uint64_t> RemarkVersion,
236*bdd1243dSDimitry Andric     std::optional<const StringTable *> StrTab,
237*bdd1243dSDimitry Andric     std::optional<StringRef> Filename) {
2388bcb0991SDimitry Andric   // Emit the meta block
2398bcb0991SDimitry Andric   Bitstream.EnterSubblock(META_BLOCK_ID, 3);
2408bcb0991SDimitry Andric 
2418bcb0991SDimitry Andric   // The container version and type.
2428bcb0991SDimitry Andric   R.clear();
2438bcb0991SDimitry Andric   R.push_back(RECORD_META_CONTAINER_INFO);
2448bcb0991SDimitry Andric   R.push_back(ContainerVersion);
2458bcb0991SDimitry Andric   R.push_back(static_cast<uint64_t>(ContainerType));
2468bcb0991SDimitry Andric   Bitstream.EmitRecordWithAbbrev(RecordMetaContainerInfoAbbrevID, R);
2478bcb0991SDimitry Andric 
2488bcb0991SDimitry Andric   switch (ContainerType) {
2498bcb0991SDimitry Andric   case BitstreamRemarkContainerType::SeparateRemarksMeta:
250*bdd1243dSDimitry Andric     assert(StrTab != std::nullopt && *StrTab != nullptr);
2518bcb0991SDimitry Andric     emitMetaStrTab(**StrTab);
252*bdd1243dSDimitry Andric     assert(Filename != std::nullopt);
2538bcb0991SDimitry Andric     emitMetaExternalFile(*Filename);
2548bcb0991SDimitry Andric     break;
2558bcb0991SDimitry Andric   case BitstreamRemarkContainerType::SeparateRemarksFile:
256*bdd1243dSDimitry Andric     assert(RemarkVersion != std::nullopt);
2578bcb0991SDimitry Andric     emitMetaRemarkVersion(*RemarkVersion);
2588bcb0991SDimitry Andric     break;
2598bcb0991SDimitry Andric   case BitstreamRemarkContainerType::Standalone:
260*bdd1243dSDimitry Andric     assert(RemarkVersion != std::nullopt);
2618bcb0991SDimitry Andric     emitMetaRemarkVersion(*RemarkVersion);
262*bdd1243dSDimitry Andric     assert(StrTab != std::nullopt && *StrTab != nullptr);
2638bcb0991SDimitry Andric     emitMetaStrTab(**StrTab);
2648bcb0991SDimitry Andric     break;
2658bcb0991SDimitry Andric   }
2668bcb0991SDimitry Andric 
2678bcb0991SDimitry Andric   Bitstream.ExitBlock();
2688bcb0991SDimitry Andric }
2698bcb0991SDimitry Andric 
emitRemarkBlock(const Remark & Remark,StringTable & StrTab)2708bcb0991SDimitry Andric void BitstreamRemarkSerializerHelper::emitRemarkBlock(const Remark &Remark,
2718bcb0991SDimitry Andric                                                       StringTable &StrTab) {
2728bcb0991SDimitry Andric   Bitstream.EnterSubblock(REMARK_BLOCK_ID, 4);
2738bcb0991SDimitry Andric 
2748bcb0991SDimitry Andric   R.clear();
2758bcb0991SDimitry Andric   R.push_back(RECORD_REMARK_HEADER);
2768bcb0991SDimitry Andric   R.push_back(static_cast<uint64_t>(Remark.RemarkType));
2778bcb0991SDimitry Andric   R.push_back(StrTab.add(Remark.RemarkName).first);
2788bcb0991SDimitry Andric   R.push_back(StrTab.add(Remark.PassName).first);
2798bcb0991SDimitry Andric   R.push_back(StrTab.add(Remark.FunctionName).first);
2808bcb0991SDimitry Andric   Bitstream.EmitRecordWithAbbrev(RecordRemarkHeaderAbbrevID, R);
2818bcb0991SDimitry Andric 
282*bdd1243dSDimitry Andric   if (const std::optional<RemarkLocation> &Loc = Remark.Loc) {
2838bcb0991SDimitry Andric     R.clear();
2848bcb0991SDimitry Andric     R.push_back(RECORD_REMARK_DEBUG_LOC);
2858bcb0991SDimitry Andric     R.push_back(StrTab.add(Loc->SourceFilePath).first);
2868bcb0991SDimitry Andric     R.push_back(Loc->SourceLine);
2878bcb0991SDimitry Andric     R.push_back(Loc->SourceColumn);
2888bcb0991SDimitry Andric     Bitstream.EmitRecordWithAbbrev(RecordRemarkDebugLocAbbrevID, R);
2898bcb0991SDimitry Andric   }
2908bcb0991SDimitry Andric 
291*bdd1243dSDimitry Andric   if (std::optional<uint64_t> Hotness = Remark.Hotness) {
2928bcb0991SDimitry Andric     R.clear();
2938bcb0991SDimitry Andric     R.push_back(RECORD_REMARK_HOTNESS);
2948bcb0991SDimitry Andric     R.push_back(*Hotness);
2958bcb0991SDimitry Andric     Bitstream.EmitRecordWithAbbrev(RecordRemarkHotnessAbbrevID, R);
2968bcb0991SDimitry Andric   }
2978bcb0991SDimitry Andric 
2988bcb0991SDimitry Andric   for (const Argument &Arg : Remark.Args) {
2998bcb0991SDimitry Andric     R.clear();
3008bcb0991SDimitry Andric     unsigned Key = StrTab.add(Arg.Key).first;
3018bcb0991SDimitry Andric     unsigned Val = StrTab.add(Arg.Val).first;
302*bdd1243dSDimitry Andric     bool HasDebugLoc = Arg.Loc != std::nullopt;
3038bcb0991SDimitry Andric     R.push_back(HasDebugLoc ? RECORD_REMARK_ARG_WITH_DEBUGLOC
3048bcb0991SDimitry Andric                             : RECORD_REMARK_ARG_WITHOUT_DEBUGLOC);
3058bcb0991SDimitry Andric     R.push_back(Key);
3068bcb0991SDimitry Andric     R.push_back(Val);
3078bcb0991SDimitry Andric     if (HasDebugLoc) {
3088bcb0991SDimitry Andric       R.push_back(StrTab.add(Arg.Loc->SourceFilePath).first);
3098bcb0991SDimitry Andric       R.push_back(Arg.Loc->SourceLine);
3108bcb0991SDimitry Andric       R.push_back(Arg.Loc->SourceColumn);
3118bcb0991SDimitry Andric     }
3128bcb0991SDimitry Andric     Bitstream.EmitRecordWithAbbrev(HasDebugLoc
3138bcb0991SDimitry Andric                                        ? RecordRemarkArgWithDebugLocAbbrevID
3148bcb0991SDimitry Andric                                        : RecordRemarkArgWithoutDebugLocAbbrevID,
3158bcb0991SDimitry Andric                                    R);
3168bcb0991SDimitry Andric   }
3178bcb0991SDimitry Andric   Bitstream.ExitBlock();
3188bcb0991SDimitry Andric }
3198bcb0991SDimitry Andric 
flushToStream(raw_ostream & OS)3208bcb0991SDimitry Andric void BitstreamRemarkSerializerHelper::flushToStream(raw_ostream &OS) {
3218bcb0991SDimitry Andric   OS.write(Encoded.data(), Encoded.size());
3228bcb0991SDimitry Andric   Encoded.clear();
3238bcb0991SDimitry Andric }
3248bcb0991SDimitry Andric 
getBuffer()3258bcb0991SDimitry Andric StringRef BitstreamRemarkSerializerHelper::getBuffer() {
3268bcb0991SDimitry Andric   return StringRef(Encoded.data(), Encoded.size());
3278bcb0991SDimitry Andric }
3288bcb0991SDimitry Andric 
BitstreamRemarkSerializer(raw_ostream & OS,SerializerMode Mode)3298bcb0991SDimitry Andric BitstreamRemarkSerializer::BitstreamRemarkSerializer(raw_ostream &OS,
3308bcb0991SDimitry Andric                                                      SerializerMode Mode)
3318bcb0991SDimitry Andric     : RemarkSerializer(Format::Bitstream, OS, Mode),
3328bcb0991SDimitry Andric       Helper(BitstreamRemarkContainerType::SeparateRemarksFile) {
3338bcb0991SDimitry Andric   assert(Mode == SerializerMode::Separate &&
3348bcb0991SDimitry Andric          "For SerializerMode::Standalone, a pre-filled string table needs to "
3358bcb0991SDimitry Andric          "be provided.");
3368bcb0991SDimitry Andric   // We always use a string table with bitstream.
3378bcb0991SDimitry Andric   StrTab.emplace();
3388bcb0991SDimitry Andric }
3398bcb0991SDimitry Andric 
BitstreamRemarkSerializer(raw_ostream & OS,SerializerMode Mode,StringTable StrTabIn)3408bcb0991SDimitry Andric BitstreamRemarkSerializer::BitstreamRemarkSerializer(raw_ostream &OS,
3418bcb0991SDimitry Andric                                                      SerializerMode Mode,
3428bcb0991SDimitry Andric                                                      StringTable StrTabIn)
3438bcb0991SDimitry Andric     : RemarkSerializer(Format::Bitstream, OS, Mode),
3448bcb0991SDimitry Andric       Helper(Mode == SerializerMode::Separate
3458bcb0991SDimitry Andric                  ? BitstreamRemarkContainerType::SeparateRemarksFile
3468bcb0991SDimitry Andric                  : BitstreamRemarkContainerType::Standalone) {
3478bcb0991SDimitry Andric   StrTab = std::move(StrTabIn);
3488bcb0991SDimitry Andric }
3498bcb0991SDimitry Andric 
emit(const Remark & Remark)3508bcb0991SDimitry Andric void BitstreamRemarkSerializer::emit(const Remark &Remark) {
3518bcb0991SDimitry Andric   if (!DidSetUp) {
3528bcb0991SDimitry Andric     // Emit the metadata that is embedded in the remark file.
3538bcb0991SDimitry Andric     // If we're in standalone mode, serialize the string table as well.
3548bcb0991SDimitry Andric     bool IsStandalone =
3558bcb0991SDimitry Andric         Helper.ContainerType == BitstreamRemarkContainerType::Standalone;
3568bcb0991SDimitry Andric     BitstreamMetaSerializer MetaSerializer(
3578bcb0991SDimitry Andric         OS, Helper,
358*bdd1243dSDimitry Andric         IsStandalone ? &*StrTab
359*bdd1243dSDimitry Andric                      : std::optional<const StringTable *>(std::nullopt));
3608bcb0991SDimitry Andric     MetaSerializer.emit();
3618bcb0991SDimitry Andric     DidSetUp = true;
3628bcb0991SDimitry Andric   }
3638bcb0991SDimitry Andric 
3648bcb0991SDimitry Andric   assert(DidSetUp &&
3658bcb0991SDimitry Andric          "The Block info block and the meta block were not emitted yet.");
3668bcb0991SDimitry Andric   Helper.emitRemarkBlock(Remark, *StrTab);
3678bcb0991SDimitry Andric 
3688bcb0991SDimitry Andric   Helper.flushToStream(OS);
3698bcb0991SDimitry Andric }
3708bcb0991SDimitry Andric 
metaSerializer(raw_ostream & OS,std::optional<StringRef> ExternalFilename)3718bcb0991SDimitry Andric std::unique_ptr<MetaSerializer> BitstreamRemarkSerializer::metaSerializer(
372*bdd1243dSDimitry Andric     raw_ostream &OS, std::optional<StringRef> ExternalFilename) {
3738bcb0991SDimitry Andric   assert(Helper.ContainerType !=
3748bcb0991SDimitry Andric          BitstreamRemarkContainerType::SeparateRemarksMeta);
3758bcb0991SDimitry Andric   bool IsStandalone =
3768bcb0991SDimitry Andric       Helper.ContainerType == BitstreamRemarkContainerType::Standalone;
3778bcb0991SDimitry Andric   return std::make_unique<BitstreamMetaSerializer>(
3788bcb0991SDimitry Andric       OS,
3798bcb0991SDimitry Andric       IsStandalone ? BitstreamRemarkContainerType::Standalone
3808bcb0991SDimitry Andric                    : BitstreamRemarkContainerType::SeparateRemarksMeta,
3818bcb0991SDimitry Andric       &*StrTab, ExternalFilename);
3828bcb0991SDimitry Andric }
3838bcb0991SDimitry Andric 
emit()3848bcb0991SDimitry Andric void BitstreamMetaSerializer::emit() {
3858bcb0991SDimitry Andric   Helper->setupBlockInfo();
3868bcb0991SDimitry Andric   Helper->emitMetaBlock(CurrentContainerVersion, CurrentRemarkVersion, StrTab,
3878bcb0991SDimitry Andric                         ExternalFilename);
3888bcb0991SDimitry Andric   Helper->flushToStream(OS);
3898bcb0991SDimitry Andric }
390