
Names are used for debugging purpose and have no impact on codegen. For a non-trivial project, reading them consumes a lot of memory and slows down the compilation significantly. This patch adds a field in the indexed CGData to remember the total size of Names, and creates a command-line option to skip reading Names by advancing the pointer when deserializing the indexed CGData.
172 lines
5.4 KiB
C++
172 lines
5.4 KiB
C++
//===- CodeGenDataWriter.cpp ----------------------------------------------===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This file contains support for writing codegen data.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "llvm/CGData/CodeGenDataWriter.h"
|
|
|
|
#define DEBUG_TYPE "cg-data-writer"
|
|
|
|
using namespace llvm;
|
|
|
|
void CGDataOStream::patch(ArrayRef<CGDataPatchItem> P) {
|
|
using namespace support;
|
|
|
|
switch (Kind) {
|
|
case OStreamKind::fd: {
|
|
raw_fd_ostream &FDOStream = static_cast<raw_fd_ostream &>(OS);
|
|
const uint64_t LastPos = FDOStream.tell();
|
|
for (const auto &K : P) {
|
|
FDOStream.seek(K.Pos);
|
|
for (size_t I = 0; I < K.D.size(); ++I)
|
|
write(K.D[I]);
|
|
}
|
|
// Reset the stream to the last position after patching so that users
|
|
// don't accidentally overwrite data. This makes it consistent with
|
|
// the string stream below which replaces the data directly.
|
|
FDOStream.seek(LastPos);
|
|
break;
|
|
}
|
|
case OStreamKind::string: {
|
|
raw_string_ostream &SOStream = static_cast<raw_string_ostream &>(OS);
|
|
std::string &Data = SOStream.str(); // with flush
|
|
for (const auto &K : P) {
|
|
for (size_t I = 0; I < K.D.size(); ++I) {
|
|
uint64_t Bytes =
|
|
endian::byte_swap<uint64_t, llvm::endianness::little>(K.D[I]);
|
|
Data.replace(K.Pos + I * sizeof(uint64_t), sizeof(uint64_t),
|
|
reinterpret_cast<const char *>(&Bytes), sizeof(uint64_t));
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case OStreamKind::svector: {
|
|
raw_svector_ostream &VOStream = static_cast<raw_svector_ostream &>(OS);
|
|
for (const auto &K : P) {
|
|
for (size_t I = 0; I < K.D.size(); ++I) {
|
|
uint64_t Bytes =
|
|
endian::byte_swap<uint64_t, llvm::endianness::little>(K.D[I]);
|
|
VOStream.pwrite(reinterpret_cast<const char *>(&Bytes),
|
|
sizeof(uint64_t), K.Pos + I * sizeof(uint64_t));
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void CodeGenDataWriter::addRecord(OutlinedHashTreeRecord &Record) {
|
|
assert(Record.HashTree && "empty hash tree in the record");
|
|
HashTreeRecord.HashTree = std::move(Record.HashTree);
|
|
|
|
DataKind |= CGDataKind::FunctionOutlinedHashTree;
|
|
}
|
|
|
|
void CodeGenDataWriter::addRecord(StableFunctionMapRecord &Record) {
|
|
assert(Record.FunctionMap && "empty function map in the record");
|
|
FunctionMapRecord.FunctionMap = std::move(Record.FunctionMap);
|
|
|
|
DataKind |= CGDataKind::StableFunctionMergingMap;
|
|
}
|
|
|
|
Error CodeGenDataWriter::write(raw_fd_ostream &OS) {
|
|
CGDataOStream COS(OS);
|
|
return writeImpl(COS);
|
|
}
|
|
|
|
Error CodeGenDataWriter::writeHeader(CGDataOStream &COS) {
|
|
using namespace support;
|
|
IndexedCGData::Header Header;
|
|
Header.Magic = IndexedCGData::Magic;
|
|
Header.Version = IndexedCGData::Version;
|
|
|
|
// Set the CGDataKind depending on the kind.
|
|
Header.DataKind = 0;
|
|
if (static_cast<bool>(DataKind & CGDataKind::FunctionOutlinedHashTree))
|
|
Header.DataKind |=
|
|
static_cast<uint32_t>(CGDataKind::FunctionOutlinedHashTree);
|
|
if (static_cast<bool>(DataKind & CGDataKind::StableFunctionMergingMap))
|
|
Header.DataKind |=
|
|
static_cast<uint32_t>(CGDataKind::StableFunctionMergingMap);
|
|
Header.OutlinedHashTreeOffset = 0;
|
|
Header.StableFunctionMapOffset = 0;
|
|
|
|
// Only write up to the CGDataKind. We need to remember the offset of the
|
|
// remaining fields to allow back-patching later.
|
|
COS.write(Header.Magic);
|
|
COS.write32(Header.Version);
|
|
COS.write32(Header.DataKind);
|
|
|
|
// Save the location of Header.OutlinedHashTreeOffset field in \c COS.
|
|
OutlinedHashTreeOffset = COS.tell();
|
|
|
|
// Reserve the space for OutlinedHashTreeOffset field.
|
|
COS.write(0);
|
|
|
|
// Save the location of Header.StableFunctionMapOffset field in \c COS.
|
|
StableFunctionMapOffset = COS.tell();
|
|
|
|
// Reserve the space for StableFunctionMapOffset field.
|
|
COS.write(0);
|
|
|
|
return Error::success();
|
|
}
|
|
|
|
Error CodeGenDataWriter::writeImpl(CGDataOStream &COS) {
|
|
if (Error E = writeHeader(COS))
|
|
return E;
|
|
|
|
std::vector<CGDataPatchItem> PatchItems;
|
|
|
|
uint64_t OutlinedHashTreeFieldStart = COS.tell();
|
|
if (hasOutlinedHashTree())
|
|
HashTreeRecord.serialize(COS.OS);
|
|
uint64_t StableFunctionMapFieldStart = COS.tell();
|
|
if (hasStableFunctionMap())
|
|
FunctionMapRecord.serialize(COS.OS, PatchItems);
|
|
|
|
// Back patch the offsets.
|
|
PatchItems.emplace_back(OutlinedHashTreeOffset, &OutlinedHashTreeFieldStart,
|
|
1);
|
|
PatchItems.emplace_back(StableFunctionMapOffset, &StableFunctionMapFieldStart,
|
|
1);
|
|
COS.patch(PatchItems);
|
|
|
|
return Error::success();
|
|
}
|
|
|
|
Error CodeGenDataWriter::writeHeaderText(raw_fd_ostream &OS) {
|
|
if (hasOutlinedHashTree())
|
|
OS << "# Outlined stable hash tree\n:outlined_hash_tree\n";
|
|
|
|
if (hasStableFunctionMap())
|
|
OS << "# Stable function map\n:stable_function_map\n";
|
|
|
|
// TODO: Add more data types in this header
|
|
|
|
return Error::success();
|
|
}
|
|
|
|
Error CodeGenDataWriter::writeText(raw_fd_ostream &OS) {
|
|
if (Error E = writeHeaderText(OS))
|
|
return E;
|
|
|
|
yaml::Output YOS(OS);
|
|
if (hasOutlinedHashTree())
|
|
HashTreeRecord.serializeYAML(YOS);
|
|
|
|
if (hasStableFunctionMap())
|
|
FunctionMapRecord.serializeYAML(YOS);
|
|
|
|
// TODO: Write more yaml cgdata in order
|
|
|
|
return Error::success();
|
|
}
|