Path: blob/main/contrib/llvm-project/llvm/lib/Remarks/BitstreamRemarkSerializer.cpp
35262 views
//===- BitstreamRemarkSerializer.cpp --------------------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// This file provides the implementation of the LLVM bitstream remark serializer9// using LLVM's bitstream writer.10//11//===----------------------------------------------------------------------===//1213#include "llvm/Remarks/BitstreamRemarkSerializer.h"14#include "llvm/Remarks/Remark.h"15#include <optional>1617using namespace llvm;18using namespace llvm::remarks;1920BitstreamRemarkSerializerHelper::BitstreamRemarkSerializerHelper(21BitstreamRemarkContainerType ContainerType)22: Bitstream(Encoded), ContainerType(ContainerType) {}2324static void push(SmallVectorImpl<uint64_t> &R, StringRef Str) {25append_range(R, Str);26}2728static void setRecordName(unsigned RecordID, BitstreamWriter &Bitstream,29SmallVectorImpl<uint64_t> &R, StringRef Str) {30R.clear();31R.push_back(RecordID);32push(R, Str);33Bitstream.EmitRecord(bitc::BLOCKINFO_CODE_SETRECORDNAME, R);34}3536static void initBlock(unsigned BlockID, BitstreamWriter &Bitstream,37SmallVectorImpl<uint64_t> &R, StringRef Str) {38R.clear();39R.push_back(BlockID);40Bitstream.EmitRecord(bitc::BLOCKINFO_CODE_SETBID, R);4142R.clear();43push(R, Str);44Bitstream.EmitRecord(bitc::BLOCKINFO_CODE_BLOCKNAME, R);45}4647void BitstreamRemarkSerializerHelper::setupMetaBlockInfo() {48// Setup the metadata block.49initBlock(META_BLOCK_ID, Bitstream, R, MetaBlockName);5051// The container information.52setRecordName(RECORD_META_CONTAINER_INFO, Bitstream, R,53MetaContainerInfoName);5455auto Abbrev = std::make_shared<BitCodeAbbrev>();56Abbrev->Add(BitCodeAbbrevOp(RECORD_META_CONTAINER_INFO));57Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // Version.58Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 2)); // Type.59RecordMetaContainerInfoAbbrevID =60Bitstream.EmitBlockInfoAbbrev(META_BLOCK_ID, Abbrev);61}6263void BitstreamRemarkSerializerHelper::setupMetaRemarkVersion() {64setRecordName(RECORD_META_REMARK_VERSION, Bitstream, R,65MetaRemarkVersionName);6667auto Abbrev = std::make_shared<BitCodeAbbrev>();68Abbrev->Add(BitCodeAbbrevOp(RECORD_META_REMARK_VERSION));69Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // Version.70RecordMetaRemarkVersionAbbrevID =71Bitstream.EmitBlockInfoAbbrev(META_BLOCK_ID, Abbrev);72}7374void BitstreamRemarkSerializerHelper::emitMetaRemarkVersion(75uint64_t RemarkVersion) {76// The remark version is emitted only if we emit remarks.77R.clear();78R.push_back(RECORD_META_REMARK_VERSION);79R.push_back(RemarkVersion);80Bitstream.EmitRecordWithAbbrev(RecordMetaRemarkVersionAbbrevID, R);81}8283void BitstreamRemarkSerializerHelper::setupMetaStrTab() {84setRecordName(RECORD_META_STRTAB, Bitstream, R, MetaStrTabName);8586auto Abbrev = std::make_shared<BitCodeAbbrev>();87Abbrev->Add(BitCodeAbbrevOp(RECORD_META_STRTAB));88Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Raw table.89RecordMetaStrTabAbbrevID =90Bitstream.EmitBlockInfoAbbrev(META_BLOCK_ID, Abbrev);91}9293void BitstreamRemarkSerializerHelper::emitMetaStrTab(94const StringTable &StrTab) {95// The string table is not emitted if we emit remarks separately.96R.clear();97R.push_back(RECORD_META_STRTAB);9899// Serialize to a blob.100std::string Buf;101raw_string_ostream OS(Buf);102StrTab.serialize(OS);103StringRef Blob = OS.str();104Bitstream.EmitRecordWithBlob(RecordMetaStrTabAbbrevID, R, Blob);105}106107void BitstreamRemarkSerializerHelper::setupMetaExternalFile() {108setRecordName(RECORD_META_EXTERNAL_FILE, Bitstream, R, MetaExternalFileName);109110auto Abbrev = std::make_shared<BitCodeAbbrev>();111Abbrev->Add(BitCodeAbbrevOp(RECORD_META_EXTERNAL_FILE));112Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Filename.113RecordMetaExternalFileAbbrevID =114Bitstream.EmitBlockInfoAbbrev(META_BLOCK_ID, Abbrev);115}116117void BitstreamRemarkSerializerHelper::emitMetaExternalFile(StringRef Filename) {118// The external file is emitted only if we emit the separate metadata.119R.clear();120R.push_back(RECORD_META_EXTERNAL_FILE);121Bitstream.EmitRecordWithBlob(RecordMetaExternalFileAbbrevID, R, Filename);122}123124void BitstreamRemarkSerializerHelper::setupRemarkBlockInfo() {125// Setup the remark block.126initBlock(REMARK_BLOCK_ID, Bitstream, R, RemarkBlockName);127128// The header of a remark.129{130setRecordName(RECORD_REMARK_HEADER, Bitstream, R, RemarkHeaderName);131132auto Abbrev = std::make_shared<BitCodeAbbrev>();133Abbrev->Add(BitCodeAbbrevOp(RECORD_REMARK_HEADER));134Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 3)); // Type135Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Remark Name136Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Pass name137Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // Function name138RecordRemarkHeaderAbbrevID =139Bitstream.EmitBlockInfoAbbrev(REMARK_BLOCK_ID, Abbrev);140}141142// The location of a remark.143{144setRecordName(RECORD_REMARK_DEBUG_LOC, Bitstream, R, RemarkDebugLocName);145146auto Abbrev = std::make_shared<BitCodeAbbrev>();147Abbrev->Add(BitCodeAbbrevOp(RECORD_REMARK_DEBUG_LOC));148Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 7)); // File149Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // Line150Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // Column151RecordRemarkDebugLocAbbrevID =152Bitstream.EmitBlockInfoAbbrev(REMARK_BLOCK_ID, Abbrev);153}154155// The hotness of a remark.156{157setRecordName(RECORD_REMARK_HOTNESS, Bitstream, R, RemarkHotnessName);158159auto Abbrev = std::make_shared<BitCodeAbbrev>();160Abbrev->Add(BitCodeAbbrevOp(RECORD_REMARK_HOTNESS));161Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // Hotness162RecordRemarkHotnessAbbrevID =163Bitstream.EmitBlockInfoAbbrev(REMARK_BLOCK_ID, Abbrev);164}165166// An argument entry with a debug location attached.167{168setRecordName(RECORD_REMARK_ARG_WITH_DEBUGLOC, Bitstream, R,169RemarkArgWithDebugLocName);170171auto Abbrev = std::make_shared<BitCodeAbbrev>();172Abbrev->Add(BitCodeAbbrevOp(RECORD_REMARK_ARG_WITH_DEBUGLOC));173Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 7)); // Key174Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 7)); // Value175Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 7)); // File176Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // Line177Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // Column178RecordRemarkArgWithDebugLocAbbrevID =179Bitstream.EmitBlockInfoAbbrev(REMARK_BLOCK_ID, Abbrev);180}181182// An argument entry with no debug location attached.183{184setRecordName(RECORD_REMARK_ARG_WITHOUT_DEBUGLOC, Bitstream, R,185RemarkArgWithoutDebugLocName);186187auto Abbrev = std::make_shared<BitCodeAbbrev>();188Abbrev->Add(BitCodeAbbrevOp(RECORD_REMARK_ARG_WITHOUT_DEBUGLOC));189Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 7)); // Key190Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 7)); // Value191RecordRemarkArgWithoutDebugLocAbbrevID =192Bitstream.EmitBlockInfoAbbrev(REMARK_BLOCK_ID, Abbrev);193}194}195196void BitstreamRemarkSerializerHelper::setupBlockInfo() {197// Emit magic number.198for (const char C : ContainerMagic)199Bitstream.Emit(static_cast<unsigned>(C), 8);200201Bitstream.EnterBlockInfoBlock();202203// Setup the main metadata. Depending on the container type, we'll setup the204// required records next.205setupMetaBlockInfo();206207switch (ContainerType) {208case BitstreamRemarkContainerType::SeparateRemarksMeta:209// Needs a string table that the separate remark file is using.210setupMetaStrTab();211// Needs to know where the external remarks file is.212setupMetaExternalFile();213break;214case BitstreamRemarkContainerType::SeparateRemarksFile:215// Contains remarks: emit the version.216setupMetaRemarkVersion();217// Contains remarks: emit the remark abbrevs.218setupRemarkBlockInfo();219break;220case BitstreamRemarkContainerType::Standalone:221// Contains remarks: emit the version.222setupMetaRemarkVersion();223// Needs a string table.224setupMetaStrTab();225// Contains remarks: emit the remark abbrevs.226setupRemarkBlockInfo();227break;228}229230Bitstream.ExitBlock();231}232233void BitstreamRemarkSerializerHelper::emitMetaBlock(234uint64_t ContainerVersion, std::optional<uint64_t> RemarkVersion,235std::optional<const StringTable *> StrTab,236std::optional<StringRef> Filename) {237// Emit the meta block238Bitstream.EnterSubblock(META_BLOCK_ID, 3);239240// The container version and type.241R.clear();242R.push_back(RECORD_META_CONTAINER_INFO);243R.push_back(ContainerVersion);244R.push_back(static_cast<uint64_t>(ContainerType));245Bitstream.EmitRecordWithAbbrev(RecordMetaContainerInfoAbbrevID, R);246247switch (ContainerType) {248case BitstreamRemarkContainerType::SeparateRemarksMeta:249assert(StrTab != std::nullopt && *StrTab != nullptr);250emitMetaStrTab(**StrTab);251assert(Filename != std::nullopt);252emitMetaExternalFile(*Filename);253break;254case BitstreamRemarkContainerType::SeparateRemarksFile:255assert(RemarkVersion != std::nullopt);256emitMetaRemarkVersion(*RemarkVersion);257break;258case BitstreamRemarkContainerType::Standalone:259assert(RemarkVersion != std::nullopt);260emitMetaRemarkVersion(*RemarkVersion);261assert(StrTab != std::nullopt && *StrTab != nullptr);262emitMetaStrTab(**StrTab);263break;264}265266Bitstream.ExitBlock();267}268269void BitstreamRemarkSerializerHelper::emitRemarkBlock(const Remark &Remark,270StringTable &StrTab) {271Bitstream.EnterSubblock(REMARK_BLOCK_ID, 4);272273R.clear();274R.push_back(RECORD_REMARK_HEADER);275R.push_back(static_cast<uint64_t>(Remark.RemarkType));276R.push_back(StrTab.add(Remark.RemarkName).first);277R.push_back(StrTab.add(Remark.PassName).first);278R.push_back(StrTab.add(Remark.FunctionName).first);279Bitstream.EmitRecordWithAbbrev(RecordRemarkHeaderAbbrevID, R);280281if (const std::optional<RemarkLocation> &Loc = Remark.Loc) {282R.clear();283R.push_back(RECORD_REMARK_DEBUG_LOC);284R.push_back(StrTab.add(Loc->SourceFilePath).first);285R.push_back(Loc->SourceLine);286R.push_back(Loc->SourceColumn);287Bitstream.EmitRecordWithAbbrev(RecordRemarkDebugLocAbbrevID, R);288}289290if (std::optional<uint64_t> Hotness = Remark.Hotness) {291R.clear();292R.push_back(RECORD_REMARK_HOTNESS);293R.push_back(*Hotness);294Bitstream.EmitRecordWithAbbrev(RecordRemarkHotnessAbbrevID, R);295}296297for (const Argument &Arg : Remark.Args) {298R.clear();299unsigned Key = StrTab.add(Arg.Key).first;300unsigned Val = StrTab.add(Arg.Val).first;301bool HasDebugLoc = Arg.Loc != std::nullopt;302R.push_back(HasDebugLoc ? RECORD_REMARK_ARG_WITH_DEBUGLOC303: RECORD_REMARK_ARG_WITHOUT_DEBUGLOC);304R.push_back(Key);305R.push_back(Val);306if (HasDebugLoc) {307R.push_back(StrTab.add(Arg.Loc->SourceFilePath).first);308R.push_back(Arg.Loc->SourceLine);309R.push_back(Arg.Loc->SourceColumn);310}311Bitstream.EmitRecordWithAbbrev(HasDebugLoc312? RecordRemarkArgWithDebugLocAbbrevID313: RecordRemarkArgWithoutDebugLocAbbrevID,314R);315}316Bitstream.ExitBlock();317}318319void BitstreamRemarkSerializerHelper::flushToStream(raw_ostream &OS) {320OS.write(Encoded.data(), Encoded.size());321Encoded.clear();322}323324StringRef BitstreamRemarkSerializerHelper::getBuffer() {325return StringRef(Encoded.data(), Encoded.size());326}327328BitstreamRemarkSerializer::BitstreamRemarkSerializer(raw_ostream &OS,329SerializerMode Mode)330: RemarkSerializer(Format::Bitstream, OS, Mode),331Helper(BitstreamRemarkContainerType::SeparateRemarksFile) {332assert(Mode == SerializerMode::Separate &&333"For SerializerMode::Standalone, a pre-filled string table needs to "334"be provided.");335// We always use a string table with bitstream.336StrTab.emplace();337}338339BitstreamRemarkSerializer::BitstreamRemarkSerializer(raw_ostream &OS,340SerializerMode Mode,341StringTable StrTabIn)342: RemarkSerializer(Format::Bitstream, OS, Mode),343Helper(Mode == SerializerMode::Separate344? BitstreamRemarkContainerType::SeparateRemarksFile345: BitstreamRemarkContainerType::Standalone) {346StrTab = std::move(StrTabIn);347}348349void BitstreamRemarkSerializer::emit(const Remark &Remark) {350if (!DidSetUp) {351// Emit the metadata that is embedded in the remark file.352// If we're in standalone mode, serialize the string table as well.353bool IsStandalone =354Helper.ContainerType == BitstreamRemarkContainerType::Standalone;355BitstreamMetaSerializer MetaSerializer(356OS, Helper,357IsStandalone ? &*StrTab358: std::optional<const StringTable *>(std::nullopt));359MetaSerializer.emit();360DidSetUp = true;361}362363assert(DidSetUp &&364"The Block info block and the meta block were not emitted yet.");365Helper.emitRemarkBlock(Remark, *StrTab);366367Helper.flushToStream(OS);368}369370std::unique_ptr<MetaSerializer> BitstreamRemarkSerializer::metaSerializer(371raw_ostream &OS, std::optional<StringRef> ExternalFilename) {372assert(Helper.ContainerType !=373BitstreamRemarkContainerType::SeparateRemarksMeta);374bool IsStandalone =375Helper.ContainerType == BitstreamRemarkContainerType::Standalone;376return std::make_unique<BitstreamMetaSerializer>(377OS,378IsStandalone ? BitstreamRemarkContainerType::Standalone379: BitstreamRemarkContainerType::SeparateRemarksMeta,380&*StrTab, ExternalFilename);381}382383void BitstreamMetaSerializer::emit() {384Helper->setupBlockInfo();385Helper->emitMetaBlock(CurrentContainerVersion, CurrentRemarkVersion, StrTab,386ExternalFilename);387Helper->flushToStream(OS);388}389390391