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-exception
6 //
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
17 using namespace llvm;
18
patch(ArrayRef<CGDataPatchItem> P)19 void 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 users
32 // don't accidentally overwrite data. This makes it consistent with
33 // 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 flush
40 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, llvm::endianness::little>(K.D[I]);
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, llvm::endianness::little>(K.D[I]);
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
addRecord(OutlinedHashTreeRecord & Record)65 void 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
addRecord(StableFunctionMapRecord & Record)72 void 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
write(raw_fd_ostream & OS)79 Error CodeGenDataWriter::write(raw_fd_ostream &OS) {
80 CGDataOStream COS(OS);
81 return writeImpl(COS);
82 }
83
writeHeader(CGDataOStream & COS)84 Error 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 the
102 // 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
writeImpl(CGDataOStream & COS)122 Error 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
writeHeaderText(raw_fd_ostream & OS)145 Error 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 header
153
154 return Error::success();
155 }
156
writeText(raw_fd_ostream & OS)157 Error 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 order
169
170 return Error::success();
171 }
172