353 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8//9// This file provides the implementation of the LLVM bitstream remark serializer10// using LLVM's bitstream writer.11//12//===----------------------------------------------------------------------===//13 14#include "llvm/Remarks/BitstreamRemarkSerializer.h"15#include "llvm/ADT/ScopeExit.h"16#include "llvm/Remarks/Remark.h"17#include <cassert>18#include <optional>19 20using namespace llvm;21using namespace llvm::remarks;22 23BitstreamRemarkSerializerHelper::BitstreamRemarkSerializerHelper(24 BitstreamRemarkContainerType ContainerType, raw_ostream &OS)25 : Bitstream(OS), ContainerType(ContainerType) {}26 27static void setRecordName(unsigned RecordID, BitstreamWriter &Bitstream,28 SmallVectorImpl<uint64_t> &R, StringRef Str) {29 R.clear();30 R.push_back(RecordID);31 append_range(R, Str);32 Bitstream.EmitRecord(bitc::BLOCKINFO_CODE_SETRECORDNAME, R);33}34 35static void initBlock(unsigned BlockID, BitstreamWriter &Bitstream,36 SmallVectorImpl<uint64_t> &R, StringRef Str) {37 R.clear();38 R.push_back(BlockID);39 Bitstream.EmitRecord(bitc::BLOCKINFO_CODE_SETBID, R);40 41 R.clear();42 append_range(R, Str);43 Bitstream.EmitRecord(bitc::BLOCKINFO_CODE_BLOCKNAME, R);44}45 46void BitstreamRemarkSerializerHelper::setupMetaBlockInfo() {47 // Setup the metadata block.48 initBlock(META_BLOCK_ID, Bitstream, R, MetaBlockName);49 50 // The container information.51 setRecordName(RECORD_META_CONTAINER_INFO, Bitstream, R,52 MetaContainerInfoName);53 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);60}61 62void BitstreamRemarkSerializerHelper::setupMetaRemarkVersion() {63 setRecordName(RECORD_META_REMARK_VERSION, Bitstream, R,64 MetaRemarkVersionName);65 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);71}72 73void BitstreamRemarkSerializerHelper::emitMetaRemarkVersion(74 uint64_t RemarkVersion) {75 // The remark version is emitted only if we emit remarks.76 R.clear();77 R.push_back(RECORD_META_REMARK_VERSION);78 R.push_back(RemarkVersion);79 Bitstream.EmitRecordWithAbbrev(RecordMetaRemarkVersionAbbrevID, R);80}81 82void BitstreamRemarkSerializerHelper::setupMetaStrTab() {83 setRecordName(RECORD_META_STRTAB, Bitstream, R, MetaStrTabName);84 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);90}91 92void BitstreamRemarkSerializerHelper::emitMetaStrTab(93 const StringTable &StrTab) {94 // The string table is not emitted if we emit remarks separately.95 R.clear();96 R.push_back(RECORD_META_STRTAB);97 98 // Serialize to a blob.99 std::string Buf;100 raw_string_ostream OS(Buf);101 StrTab.serialize(OS);102 StringRef Blob = OS.str();103 Bitstream.EmitRecordWithBlob(RecordMetaStrTabAbbrevID, R, Blob);104}105 106void BitstreamRemarkSerializerHelper::setupMetaExternalFile() {107 setRecordName(RECORD_META_EXTERNAL_FILE, Bitstream, R, MetaExternalFileName);108 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);114}115 116void BitstreamRemarkSerializerHelper::emitMetaExternalFile(StringRef Filename) {117 // The external file is emitted only if we emit the separate metadata.118 R.clear();119 R.push_back(RECORD_META_EXTERNAL_FILE);120 Bitstream.EmitRecordWithBlob(RecordMetaExternalFileAbbrevID, R, Filename);121}122 123void BitstreamRemarkSerializerHelper::setupRemarkBlockInfo() {124 // Setup the remark block.125 initBlock(REMARK_BLOCK_ID, Bitstream, R, RemarkBlockName);126 127 // The header of a remark.128 {129 setRecordName(RECORD_REMARK_HEADER, Bitstream, R, RemarkHeaderName);130 131 auto Abbrev = std::make_shared<BitCodeAbbrev>();132 Abbrev->Add(BitCodeAbbrevOp(RECORD_REMARK_HEADER));133 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 3)); // Type134 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Remark Name135 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Pass name136 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // Function name137 RecordRemarkHeaderAbbrevID =138 Bitstream.EmitBlockInfoAbbrev(REMARK_BLOCK_ID, Abbrev);139 }140 141 // The location of a remark.142 {143 setRecordName(RECORD_REMARK_DEBUG_LOC, Bitstream, R, RemarkDebugLocName);144 145 auto Abbrev = std::make_shared<BitCodeAbbrev>();146 Abbrev->Add(BitCodeAbbrevOp(RECORD_REMARK_DEBUG_LOC));147 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 7)); // File148 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // Line149 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // Column150 RecordRemarkDebugLocAbbrevID =151 Bitstream.EmitBlockInfoAbbrev(REMARK_BLOCK_ID, Abbrev);152 }153 154 // The hotness of a remark.155 {156 setRecordName(RECORD_REMARK_HOTNESS, Bitstream, R, RemarkHotnessName);157 158 auto Abbrev = std::make_shared<BitCodeAbbrev>();159 Abbrev->Add(BitCodeAbbrevOp(RECORD_REMARK_HOTNESS));160 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // Hotness161 RecordRemarkHotnessAbbrevID =162 Bitstream.EmitBlockInfoAbbrev(REMARK_BLOCK_ID, Abbrev);163 }164 165 // An argument entry with a debug location attached.166 {167 setRecordName(RECORD_REMARK_ARG_WITH_DEBUGLOC, Bitstream, R,168 RemarkArgWithDebugLocName);169 170 auto Abbrev = std::make_shared<BitCodeAbbrev>();171 Abbrev->Add(BitCodeAbbrevOp(RECORD_REMARK_ARG_WITH_DEBUGLOC));172 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 7)); // Key173 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 7)); // Value174 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 7)); // File175 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // Line176 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // Column177 RecordRemarkArgWithDebugLocAbbrevID =178 Bitstream.EmitBlockInfoAbbrev(REMARK_BLOCK_ID, Abbrev);179 }180 181 // An argument entry with no debug location attached.182 {183 setRecordName(RECORD_REMARK_ARG_WITHOUT_DEBUGLOC, Bitstream, R,184 RemarkArgWithoutDebugLocName);185 186 auto Abbrev = std::make_shared<BitCodeAbbrev>();187 Abbrev->Add(BitCodeAbbrevOp(RECORD_REMARK_ARG_WITHOUT_DEBUGLOC));188 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 7)); // Key189 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 7)); // Value190 RecordRemarkArgWithoutDebugLocAbbrevID =191 Bitstream.EmitBlockInfoAbbrev(REMARK_BLOCK_ID, Abbrev);192 }193}194 195void BitstreamRemarkSerializerHelper::setupBlockInfo() {196 // Emit magic number.197 for (const char C : ContainerMagic)198 Bitstream.Emit(static_cast<unsigned>(C), 8);199 200 Bitstream.EnterBlockInfoBlock();201 auto ExitBlock = make_scope_exit([&] { Bitstream.ExitBlock(); });202 203 // Setup the main metadata. Depending on the container type, we'll setup the204 // required records next.205 setupMetaBlockInfo();206 207 switch (ContainerType) {208 case BitstreamRemarkContainerType::RemarksFileExternal:209 // Needs to know where the external remarks file is.210 setupMetaExternalFile();211 return;212 case BitstreamRemarkContainerType::RemarksFile:213 // Contains remarks: emit the version.214 setupMetaRemarkVersion();215 // Needs a string table.216 setupMetaStrTab();217 // Contains remarks: emit the remark abbrevs.218 setupRemarkBlockInfo();219 return;220 }221 llvm_unreachable("Unexpected BitstreamRemarkContainerType");222}223 224void BitstreamRemarkSerializerHelper::emitMetaBlock(225 std::optional<StringRef> Filename) {226 // Emit the meta block227 Bitstream.EnterSubblock(META_BLOCK_ID, 3);228 auto ExitBlock = make_scope_exit([&] { Bitstream.ExitBlock(); });229 230 // The container version and type.231 R.clear();232 R.push_back(RECORD_META_CONTAINER_INFO);233 R.push_back(CurrentContainerVersion);234 R.push_back(static_cast<uint64_t>(ContainerType));235 Bitstream.EmitRecordWithAbbrev(RecordMetaContainerInfoAbbrevID, R);236 237 switch (ContainerType) {238 case BitstreamRemarkContainerType::RemarksFileExternal:239 assert(Filename != std::nullopt);240 emitMetaExternalFile(*Filename);241 return;242 case BitstreamRemarkContainerType::RemarksFile:243 emitMetaRemarkVersion(CurrentRemarkVersion);244 return;245 }246 llvm_unreachable("Unexpected BitstreamRemarkContainerType");247}248 249void BitstreamRemarkSerializerHelper::emitLateMetaBlock(250 const StringTable &StrTab) {251 // Emit the late meta block (after all remarks are serialized)252 Bitstream.EnterSubblock(META_BLOCK_ID, 3);253 emitMetaStrTab(StrTab);254 Bitstream.ExitBlock();255}256 257void BitstreamRemarkSerializerHelper::emitRemark(const Remark &Remark,258 StringTable &StrTab) {259 Bitstream.EnterSubblock(REMARK_BLOCK_ID, 4);260 261 R.clear();262 R.push_back(RECORD_REMARK_HEADER);263 R.push_back(static_cast<uint64_t>(Remark.RemarkType));264 R.push_back(StrTab.add(Remark.RemarkName).first);265 R.push_back(StrTab.add(Remark.PassName).first);266 R.push_back(StrTab.add(Remark.FunctionName).first);267 Bitstream.EmitRecordWithAbbrev(RecordRemarkHeaderAbbrevID, R);268 269 if (const std::optional<RemarkLocation> &Loc = Remark.Loc) {270 R.clear();271 R.push_back(RECORD_REMARK_DEBUG_LOC);272 R.push_back(StrTab.add(Loc->SourceFilePath).first);273 R.push_back(Loc->SourceLine);274 R.push_back(Loc->SourceColumn);275 Bitstream.EmitRecordWithAbbrev(RecordRemarkDebugLocAbbrevID, R);276 }277 278 if (std::optional<uint64_t> Hotness = Remark.Hotness) {279 R.clear();280 R.push_back(RECORD_REMARK_HOTNESS);281 R.push_back(*Hotness);282 Bitstream.EmitRecordWithAbbrev(RecordRemarkHotnessAbbrevID, R);283 }284 285 for (const Argument &Arg : Remark.Args) {286 R.clear();287 unsigned Key = StrTab.add(Arg.Key).first;288 unsigned Val = StrTab.add(Arg.Val).first;289 bool HasDebugLoc = Arg.Loc != std::nullopt;290 R.push_back(HasDebugLoc ? RECORD_REMARK_ARG_WITH_DEBUGLOC291 : RECORD_REMARK_ARG_WITHOUT_DEBUGLOC);292 R.push_back(Key);293 R.push_back(Val);294 if (HasDebugLoc) {295 R.push_back(StrTab.add(Arg.Loc->SourceFilePath).first);296 R.push_back(Arg.Loc->SourceLine);297 R.push_back(Arg.Loc->SourceColumn);298 }299 Bitstream.EmitRecordWithAbbrev(HasDebugLoc300 ? RecordRemarkArgWithDebugLocAbbrevID301 : RecordRemarkArgWithoutDebugLocAbbrevID,302 R);303 }304 Bitstream.ExitBlock();305}306 307BitstreamRemarkSerializer::BitstreamRemarkSerializer(raw_ostream &OS)308 : RemarkSerializer(Format::Bitstream, OS) {309 StrTab.emplace();310}311 312BitstreamRemarkSerializer::BitstreamRemarkSerializer(raw_ostream &OS,313 StringTable StrTabIn)314 : RemarkSerializer(Format::Bitstream, OS) {315 StrTab = std::move(StrTabIn);316}317 318BitstreamRemarkSerializer::~BitstreamRemarkSerializer() { finalize(); }319 320void BitstreamRemarkSerializer::setup() {321 if (Helper)322 return;323 Helper.emplace(BitstreamRemarkContainerType::RemarksFile, OS);324 Helper->setupBlockInfo();325 Helper->emitMetaBlock();326}327 328void BitstreamRemarkSerializer::finalize() {329 if (!Helper)330 return;331 Helper->emitLateMetaBlock(*StrTab);332 Helper = std::nullopt;333}334 335void BitstreamRemarkSerializer::emit(const Remark &Remark) {336 setup();337 Helper->emitRemark(Remark, *StrTab);338}339 340std::unique_ptr<MetaSerializer>341BitstreamRemarkSerializer::metaSerializer(raw_ostream &OS,342 StringRef ExternalFilename) {343 return std::make_unique<BitstreamMetaSerializer>(344 OS, BitstreamRemarkContainerType::RemarksFileExternal, ExternalFilename);345}346 347void BitstreamMetaSerializer::emit() {348 assert(Helper && "BitstreamMetaSerializer emitted multiple times");349 Helper->setupBlockInfo();350 Helper->emitMetaBlock(ExternalFilename);351 Helper = std::nullopt;352}353