BitstreamRemarkSerializer.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389
  1. //===- BitstreamRemarkSerializer.cpp --------------------------------------===//
  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 the implementation of the LLVM bitstream remark serializer
  10. // using LLVM's bitstream writer.
  11. //
  12. //===----------------------------------------------------------------------===//
  13. #include "llvm/Remarks/BitstreamRemarkSerializer.h"
  14. #include "llvm/Remarks/Remark.h"
  15. #include <optional>
  16. using namespace llvm;
  17. using namespace llvm::remarks;
  18. BitstreamRemarkSerializerHelper::BitstreamRemarkSerializerHelper(
  19. BitstreamRemarkContainerType ContainerType)
  20. : Bitstream(Encoded), ContainerType(ContainerType) {}
  21. static void push(SmallVectorImpl<uint64_t> &R, StringRef Str) {
  22. append_range(R, Str);
  23. }
  24. static void setRecordName(unsigned RecordID, BitstreamWriter &Bitstream,
  25. SmallVectorImpl<uint64_t> &R, StringRef Str) {
  26. R.clear();
  27. R.push_back(RecordID);
  28. push(R, Str);
  29. Bitstream.EmitRecord(bitc::BLOCKINFO_CODE_SETRECORDNAME, R);
  30. }
  31. static void initBlock(unsigned BlockID, BitstreamWriter &Bitstream,
  32. SmallVectorImpl<uint64_t> &R, StringRef Str) {
  33. R.clear();
  34. R.push_back(BlockID);
  35. Bitstream.EmitRecord(bitc::BLOCKINFO_CODE_SETBID, R);
  36. R.clear();
  37. push(R, Str);
  38. Bitstream.EmitRecord(bitc::BLOCKINFO_CODE_BLOCKNAME, R);
  39. }
  40. void BitstreamRemarkSerializerHelper::setupMetaBlockInfo() {
  41. // Setup the metadata block.
  42. initBlock(META_BLOCK_ID, Bitstream, R, MetaBlockName);
  43. // The container information.
  44. setRecordName(RECORD_META_CONTAINER_INFO, Bitstream, R,
  45. MetaContainerInfoName);
  46. auto Abbrev = std::make_shared<BitCodeAbbrev>();
  47. Abbrev->Add(BitCodeAbbrevOp(RECORD_META_CONTAINER_INFO));
  48. Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // Version.
  49. Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 2)); // Type.
  50. RecordMetaContainerInfoAbbrevID =
  51. Bitstream.EmitBlockInfoAbbrev(META_BLOCK_ID, Abbrev);
  52. }
  53. void BitstreamRemarkSerializerHelper::setupMetaRemarkVersion() {
  54. setRecordName(RECORD_META_REMARK_VERSION, Bitstream, R,
  55. MetaRemarkVersionName);
  56. auto Abbrev = std::make_shared<BitCodeAbbrev>();
  57. Abbrev->Add(BitCodeAbbrevOp(RECORD_META_REMARK_VERSION));
  58. Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // Version.
  59. RecordMetaRemarkVersionAbbrevID =
  60. Bitstream.EmitBlockInfoAbbrev(META_BLOCK_ID, Abbrev);
  61. }
  62. void BitstreamRemarkSerializerHelper::emitMetaRemarkVersion(
  63. uint64_t RemarkVersion) {
  64. // The remark version is emitted only if we emit remarks.
  65. R.clear();
  66. R.push_back(RECORD_META_REMARK_VERSION);
  67. R.push_back(RemarkVersion);
  68. Bitstream.EmitRecordWithAbbrev(RecordMetaRemarkVersionAbbrevID, R);
  69. }
  70. void BitstreamRemarkSerializerHelper::setupMetaStrTab() {
  71. setRecordName(RECORD_META_STRTAB, Bitstream, R, MetaStrTabName);
  72. auto Abbrev = std::make_shared<BitCodeAbbrev>();
  73. Abbrev->Add(BitCodeAbbrevOp(RECORD_META_STRTAB));
  74. Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Raw table.
  75. RecordMetaStrTabAbbrevID =
  76. Bitstream.EmitBlockInfoAbbrev(META_BLOCK_ID, Abbrev);
  77. }
  78. void BitstreamRemarkSerializerHelper::emitMetaStrTab(
  79. const StringTable &StrTab) {
  80. // The string table is not emitted if we emit remarks separately.
  81. R.clear();
  82. R.push_back(RECORD_META_STRTAB);
  83. // Serialize to a blob.
  84. std::string Buf;
  85. raw_string_ostream OS(Buf);
  86. StrTab.serialize(OS);
  87. StringRef Blob = OS.str();
  88. Bitstream.EmitRecordWithBlob(RecordMetaStrTabAbbrevID, R, Blob);
  89. }
  90. void BitstreamRemarkSerializerHelper::setupMetaExternalFile() {
  91. setRecordName(RECORD_META_EXTERNAL_FILE, Bitstream, R, MetaExternalFileName);
  92. auto Abbrev = std::make_shared<BitCodeAbbrev>();
  93. Abbrev->Add(BitCodeAbbrevOp(RECORD_META_EXTERNAL_FILE));
  94. Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Filename.
  95. RecordMetaExternalFileAbbrevID =
  96. Bitstream.EmitBlockInfoAbbrev(META_BLOCK_ID, Abbrev);
  97. }
  98. void BitstreamRemarkSerializerHelper::emitMetaExternalFile(StringRef Filename) {
  99. // The external file is emitted only if we emit the separate metadata.
  100. R.clear();
  101. R.push_back(RECORD_META_EXTERNAL_FILE);
  102. Bitstream.EmitRecordWithBlob(RecordMetaExternalFileAbbrevID, R, Filename);
  103. }
  104. void BitstreamRemarkSerializerHelper::setupRemarkBlockInfo() {
  105. // Setup the remark block.
  106. initBlock(REMARK_BLOCK_ID, Bitstream, R, RemarkBlockName);
  107. // The header of a remark.
  108. {
  109. setRecordName(RECORD_REMARK_HEADER, Bitstream, R, RemarkHeaderName);
  110. auto Abbrev = std::make_shared<BitCodeAbbrev>();
  111. Abbrev->Add(BitCodeAbbrevOp(RECORD_REMARK_HEADER));
  112. Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 3)); // Type
  113. Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Remark Name
  114. Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Pass name
  115. Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // Function name
  116. RecordRemarkHeaderAbbrevID =
  117. Bitstream.EmitBlockInfoAbbrev(REMARK_BLOCK_ID, Abbrev);
  118. }
  119. // The location of a remark.
  120. {
  121. setRecordName(RECORD_REMARK_DEBUG_LOC, Bitstream, R, RemarkDebugLocName);
  122. auto Abbrev = std::make_shared<BitCodeAbbrev>();
  123. Abbrev->Add(BitCodeAbbrevOp(RECORD_REMARK_DEBUG_LOC));
  124. Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 7)); // File
  125. Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // Line
  126. Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // Column
  127. RecordRemarkDebugLocAbbrevID =
  128. Bitstream.EmitBlockInfoAbbrev(REMARK_BLOCK_ID, Abbrev);
  129. }
  130. // The hotness of a remark.
  131. {
  132. setRecordName(RECORD_REMARK_HOTNESS, Bitstream, R, RemarkHotnessName);
  133. auto Abbrev = std::make_shared<BitCodeAbbrev>();
  134. Abbrev->Add(BitCodeAbbrevOp(RECORD_REMARK_HOTNESS));
  135. Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // Hotness
  136. RecordRemarkHotnessAbbrevID =
  137. Bitstream.EmitBlockInfoAbbrev(REMARK_BLOCK_ID, Abbrev);
  138. }
  139. // An argument entry with a debug location attached.
  140. {
  141. setRecordName(RECORD_REMARK_ARG_WITH_DEBUGLOC, Bitstream, R,
  142. RemarkArgWithDebugLocName);
  143. auto Abbrev = std::make_shared<BitCodeAbbrev>();
  144. Abbrev->Add(BitCodeAbbrevOp(RECORD_REMARK_ARG_WITH_DEBUGLOC));
  145. Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 7)); // Key
  146. Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 7)); // Value
  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. RecordRemarkArgWithDebugLocAbbrevID =
  151. Bitstream.EmitBlockInfoAbbrev(REMARK_BLOCK_ID, Abbrev);
  152. }
  153. // An argument entry with no debug location attached.
  154. {
  155. setRecordName(RECORD_REMARK_ARG_WITHOUT_DEBUGLOC, Bitstream, R,
  156. RemarkArgWithoutDebugLocName);
  157. auto Abbrev = std::make_shared<BitCodeAbbrev>();
  158. Abbrev->Add(BitCodeAbbrevOp(RECORD_REMARK_ARG_WITHOUT_DEBUGLOC));
  159. Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 7)); // Key
  160. Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 7)); // Value
  161. RecordRemarkArgWithoutDebugLocAbbrevID =
  162. Bitstream.EmitBlockInfoAbbrev(REMARK_BLOCK_ID, Abbrev);
  163. }
  164. }
  165. void BitstreamRemarkSerializerHelper::setupBlockInfo() {
  166. // Emit magic number.
  167. for (const char C : ContainerMagic)
  168. Bitstream.Emit(static_cast<unsigned>(C), 8);
  169. Bitstream.EnterBlockInfoBlock();
  170. // Setup the main metadata. Depending on the container type, we'll setup the
  171. // required records next.
  172. setupMetaBlockInfo();
  173. switch (ContainerType) {
  174. case BitstreamRemarkContainerType::SeparateRemarksMeta:
  175. // Needs a string table that the separate remark file is using.
  176. setupMetaStrTab();
  177. // Needs to know where the external remarks file is.
  178. setupMetaExternalFile();
  179. break;
  180. case BitstreamRemarkContainerType::SeparateRemarksFile:
  181. // Contains remarks: emit the version.
  182. setupMetaRemarkVersion();
  183. // Contains remarks: emit the remark abbrevs.
  184. setupRemarkBlockInfo();
  185. break;
  186. case BitstreamRemarkContainerType::Standalone:
  187. // Contains remarks: emit the version.
  188. setupMetaRemarkVersion();
  189. // Needs a string table.
  190. setupMetaStrTab();
  191. // Contains remarks: emit the remark abbrevs.
  192. setupRemarkBlockInfo();
  193. break;
  194. }
  195. Bitstream.ExitBlock();
  196. }
  197. void BitstreamRemarkSerializerHelper::emitMetaBlock(
  198. uint64_t ContainerVersion, std::optional<uint64_t> RemarkVersion,
  199. std::optional<const StringTable *> StrTab,
  200. std::optional<StringRef> Filename) {
  201. // Emit the meta block
  202. Bitstream.EnterSubblock(META_BLOCK_ID, 3);
  203. // The container version and type.
  204. R.clear();
  205. R.push_back(RECORD_META_CONTAINER_INFO);
  206. R.push_back(ContainerVersion);
  207. R.push_back(static_cast<uint64_t>(ContainerType));
  208. Bitstream.EmitRecordWithAbbrev(RecordMetaContainerInfoAbbrevID, R);
  209. switch (ContainerType) {
  210. case BitstreamRemarkContainerType::SeparateRemarksMeta:
  211. assert(StrTab != std::nullopt && *StrTab != nullptr);
  212. emitMetaStrTab(**StrTab);
  213. assert(Filename != std::nullopt);
  214. emitMetaExternalFile(*Filename);
  215. break;
  216. case BitstreamRemarkContainerType::SeparateRemarksFile:
  217. assert(RemarkVersion != std::nullopt);
  218. emitMetaRemarkVersion(*RemarkVersion);
  219. break;
  220. case BitstreamRemarkContainerType::Standalone:
  221. assert(RemarkVersion != std::nullopt);
  222. emitMetaRemarkVersion(*RemarkVersion);
  223. assert(StrTab != std::nullopt && *StrTab != nullptr);
  224. emitMetaStrTab(**StrTab);
  225. break;
  226. }
  227. Bitstream.ExitBlock();
  228. }
  229. void BitstreamRemarkSerializerHelper::emitRemarkBlock(const Remark &Remark,
  230. StringTable &StrTab) {
  231. Bitstream.EnterSubblock(REMARK_BLOCK_ID, 4);
  232. R.clear();
  233. R.push_back(RECORD_REMARK_HEADER);
  234. R.push_back(static_cast<uint64_t>(Remark.RemarkType));
  235. R.push_back(StrTab.add(Remark.RemarkName).first);
  236. R.push_back(StrTab.add(Remark.PassName).first);
  237. R.push_back(StrTab.add(Remark.FunctionName).first);
  238. Bitstream.EmitRecordWithAbbrev(RecordRemarkHeaderAbbrevID, R);
  239. if (const std::optional<RemarkLocation> &Loc = Remark.Loc) {
  240. R.clear();
  241. R.push_back(RECORD_REMARK_DEBUG_LOC);
  242. R.push_back(StrTab.add(Loc->SourceFilePath).first);
  243. R.push_back(Loc->SourceLine);
  244. R.push_back(Loc->SourceColumn);
  245. Bitstream.EmitRecordWithAbbrev(RecordRemarkDebugLocAbbrevID, R);
  246. }
  247. if (std::optional<uint64_t> Hotness = Remark.Hotness) {
  248. R.clear();
  249. R.push_back(RECORD_REMARK_HOTNESS);
  250. R.push_back(*Hotness);
  251. Bitstream.EmitRecordWithAbbrev(RecordRemarkHotnessAbbrevID, R);
  252. }
  253. for (const Argument &Arg : Remark.Args) {
  254. R.clear();
  255. unsigned Key = StrTab.add(Arg.Key).first;
  256. unsigned Val = StrTab.add(Arg.Val).first;
  257. bool HasDebugLoc = Arg.Loc != std::nullopt;
  258. R.push_back(HasDebugLoc ? RECORD_REMARK_ARG_WITH_DEBUGLOC
  259. : RECORD_REMARK_ARG_WITHOUT_DEBUGLOC);
  260. R.push_back(Key);
  261. R.push_back(Val);
  262. if (HasDebugLoc) {
  263. R.push_back(StrTab.add(Arg.Loc->SourceFilePath).first);
  264. R.push_back(Arg.Loc->SourceLine);
  265. R.push_back(Arg.Loc->SourceColumn);
  266. }
  267. Bitstream.EmitRecordWithAbbrev(HasDebugLoc
  268. ? RecordRemarkArgWithDebugLocAbbrevID
  269. : RecordRemarkArgWithoutDebugLocAbbrevID,
  270. R);
  271. }
  272. Bitstream.ExitBlock();
  273. }
  274. void BitstreamRemarkSerializerHelper::flushToStream(raw_ostream &OS) {
  275. OS.write(Encoded.data(), Encoded.size());
  276. Encoded.clear();
  277. }
  278. StringRef BitstreamRemarkSerializerHelper::getBuffer() {
  279. return StringRef(Encoded.data(), Encoded.size());
  280. }
  281. BitstreamRemarkSerializer::BitstreamRemarkSerializer(raw_ostream &OS,
  282. SerializerMode Mode)
  283. : RemarkSerializer(Format::Bitstream, OS, Mode),
  284. Helper(BitstreamRemarkContainerType::SeparateRemarksFile) {
  285. assert(Mode == SerializerMode::Separate &&
  286. "For SerializerMode::Standalone, a pre-filled string table needs to "
  287. "be provided.");
  288. // We always use a string table with bitstream.
  289. StrTab.emplace();
  290. }
  291. BitstreamRemarkSerializer::BitstreamRemarkSerializer(raw_ostream &OS,
  292. SerializerMode Mode,
  293. StringTable StrTabIn)
  294. : RemarkSerializer(Format::Bitstream, OS, Mode),
  295. Helper(Mode == SerializerMode::Separate
  296. ? BitstreamRemarkContainerType::SeparateRemarksFile
  297. : BitstreamRemarkContainerType::Standalone) {
  298. StrTab = std::move(StrTabIn);
  299. }
  300. void BitstreamRemarkSerializer::emit(const Remark &Remark) {
  301. if (!DidSetUp) {
  302. // Emit the metadata that is embedded in the remark file.
  303. // If we're in standalone mode, serialize the string table as well.
  304. bool IsStandalone =
  305. Helper.ContainerType == BitstreamRemarkContainerType::Standalone;
  306. BitstreamMetaSerializer MetaSerializer(
  307. OS, Helper,
  308. IsStandalone ? &*StrTab
  309. : std::optional<const StringTable *>(std::nullopt));
  310. MetaSerializer.emit();
  311. DidSetUp = true;
  312. }
  313. assert(DidSetUp &&
  314. "The Block info block and the meta block were not emitted yet.");
  315. Helper.emitRemarkBlock(Remark, *StrTab);
  316. Helper.flushToStream(OS);
  317. }
  318. std::unique_ptr<MetaSerializer> BitstreamRemarkSerializer::metaSerializer(
  319. raw_ostream &OS, std::optional<StringRef> ExternalFilename) {
  320. assert(Helper.ContainerType !=
  321. BitstreamRemarkContainerType::SeparateRemarksMeta);
  322. bool IsStandalone =
  323. Helper.ContainerType == BitstreamRemarkContainerType::Standalone;
  324. return std::make_unique<BitstreamMetaSerializer>(
  325. OS,
  326. IsStandalone ? BitstreamRemarkContainerType::Standalone
  327. : BitstreamRemarkContainerType::SeparateRemarksMeta,
  328. &*StrTab, ExternalFilename);
  329. }
  330. void BitstreamMetaSerializer::emit() {
  331. Helper->setupBlockInfo();
  332. Helper->emitMetaBlock(CurrentContainerVersion, CurrentRemarkVersion, StrTab,
  333. ExternalFilename);
  334. Helper->flushToStream(OS);
  335. }