BitstreamRemarkSerializer.cpp 14 KB

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