172 lines · cpp
1//===- CodeGenDataWriter.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 contains support for writing codegen data.10//11//===----------------------------------------------------------------------===//12 13#include "llvm/CGData/CodeGenDataWriter.h"14 15#define DEBUG_TYPE "cg-data-writer"16 17using namespace llvm;18 19void CGDataOStream::patch(ArrayRef<CGDataPatchItem> P) {20 using namespace support;21 22 switch (Kind) {23 case OStreamKind::fd: {24 raw_fd_ostream &FDOStream = static_cast<raw_fd_ostream &>(OS);25 const uint64_t LastPos = FDOStream.tell();26 for (const auto &K : P) {27 FDOStream.seek(K.Pos);28 for (size_t I = 0; I < K.D.size(); ++I)29 write(K.D[I]);30 }31 // Reset the stream to the last position after patching so that users32 // don't accidentally overwrite data. This makes it consistent with33 // the string stream below which replaces the data directly.34 FDOStream.seek(LastPos);35 break;36 }37 case OStreamKind::string: {38 raw_string_ostream &SOStream = static_cast<raw_string_ostream &>(OS);39 std::string &Data = SOStream.str(); // with flush40 for (const auto &K : P) {41 for (size_t I = 0; I < K.D.size(); ++I) {42 uint64_t Bytes =43 endian::byte_swap<uint64_t>(K.D[I], llvm::endianness::little);44 Data.replace(K.Pos + I * sizeof(uint64_t), sizeof(uint64_t),45 reinterpret_cast<const char *>(&Bytes), sizeof(uint64_t));46 }47 }48 break;49 }50 case OStreamKind::svector: {51 raw_svector_ostream &VOStream = static_cast<raw_svector_ostream &>(OS);52 for (const auto &K : P) {53 for (size_t I = 0; I < K.D.size(); ++I) {54 uint64_t Bytes =55 endian::byte_swap<uint64_t>(K.D[I], llvm::endianness::little);56 VOStream.pwrite(reinterpret_cast<const char *>(&Bytes),57 sizeof(uint64_t), K.Pos + I * sizeof(uint64_t));58 }59 }60 break;61 }62 }63}64 65void CodeGenDataWriter::addRecord(OutlinedHashTreeRecord &Record) {66 assert(Record.HashTree && "empty hash tree in the record");67 HashTreeRecord.HashTree = std::move(Record.HashTree);68 69 DataKind |= CGDataKind::FunctionOutlinedHashTree;70}71 72void CodeGenDataWriter::addRecord(StableFunctionMapRecord &Record) {73 assert(Record.FunctionMap && "empty function map in the record");74 FunctionMapRecord.FunctionMap = std::move(Record.FunctionMap);75 76 DataKind |= CGDataKind::StableFunctionMergingMap;77}78 79Error CodeGenDataWriter::write(raw_fd_ostream &OS) {80 CGDataOStream COS(OS);81 return writeImpl(COS);82}83 84Error CodeGenDataWriter::writeHeader(CGDataOStream &COS) {85 using namespace support;86 IndexedCGData::Header Header;87 Header.Magic = IndexedCGData::Magic;88 Header.Version = IndexedCGData::Version;89 90 // Set the CGDataKind depending on the kind.91 Header.DataKind = 0;92 if (static_cast<bool>(DataKind & CGDataKind::FunctionOutlinedHashTree))93 Header.DataKind |=94 static_cast<uint32_t>(CGDataKind::FunctionOutlinedHashTree);95 if (static_cast<bool>(DataKind & CGDataKind::StableFunctionMergingMap))96 Header.DataKind |=97 static_cast<uint32_t>(CGDataKind::StableFunctionMergingMap);98 Header.OutlinedHashTreeOffset = 0;99 Header.StableFunctionMapOffset = 0;100 101 // Only write up to the CGDataKind. We need to remember the offset of the102 // remaining fields to allow back-patching later.103 COS.write(Header.Magic);104 COS.write32(Header.Version);105 COS.write32(Header.DataKind);106 107 // Save the location of Header.OutlinedHashTreeOffset field in \c COS.108 OutlinedHashTreeOffset = COS.tell();109 110 // Reserve the space for OutlinedHashTreeOffset field.111 COS.write(0);112 113 // Save the location of Header.StableFunctionMapOffset field in \c COS.114 StableFunctionMapOffset = COS.tell();115 116 // Reserve the space for StableFunctionMapOffset field.117 COS.write(0);118 119 return Error::success();120}121 122Error CodeGenDataWriter::writeImpl(CGDataOStream &COS) {123 if (Error E = writeHeader(COS))124 return E;125 126 std::vector<CGDataPatchItem> PatchItems;127 128 uint64_t OutlinedHashTreeFieldStart = COS.tell();129 if (hasOutlinedHashTree())130 HashTreeRecord.serialize(COS.OS);131 uint64_t StableFunctionMapFieldStart = COS.tell();132 if (hasStableFunctionMap())133 FunctionMapRecord.serialize(COS.OS, PatchItems);134 135 // Back patch the offsets.136 PatchItems.emplace_back(OutlinedHashTreeOffset, &OutlinedHashTreeFieldStart,137 1);138 PatchItems.emplace_back(StableFunctionMapOffset, &StableFunctionMapFieldStart,139 1);140 COS.patch(PatchItems);141 142 return Error::success();143}144 145Error CodeGenDataWriter::writeHeaderText(raw_fd_ostream &OS) {146 if (hasOutlinedHashTree())147 OS << "# Outlined stable hash tree\n:outlined_hash_tree\n";148 149 if (hasStableFunctionMap())150 OS << "# Stable function map\n:stable_function_map\n";151 152 // TODO: Add more data types in this header153 154 return Error::success();155}156 157Error CodeGenDataWriter::writeText(raw_fd_ostream &OS) {158 if (Error E = writeHeaderText(OS))159 return E;160 161 yaml::Output YOS(OS);162 if (hasOutlinedHashTree())163 HashTreeRecord.serializeYAML(YOS);164 165 if (hasStableFunctionMap())166 FunctionMapRecord.serializeYAML(YOS);167 168 // TODO: Write more yaml cgdata in order169 170 return Error::success();171}172