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 | |
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(off: K.Pos); |
28 | for (size_t I = 0; I < K.D.size(); ++I) |
29 | write(V: 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(off: 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>(value: K.D[I]); |
44 | Data.replace(pos: K.Pos + I * sizeof(uint64_t), n1: sizeof(uint64_t), |
45 | s: reinterpret_cast<const char *>(&Bytes), n2: 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>(value: K.D[I]); |
56 | VOStream.pwrite(Ptr: reinterpret_cast<const char *>(&Bytes), |
57 | Size: sizeof(uint64_t), Offset: K.Pos + I * sizeof(uint64_t)); |
58 | } |
59 | } |
60 | break; |
61 | } |
62 | } |
63 | } |
64 | |
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 | |
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 | |
79 | Error CodeGenDataWriter::write(raw_fd_ostream &OS) { |
80 | CGDataOStream COS(OS); |
81 | return writeImpl(COS); |
82 | } |
83 | |
84 | Error CodeGenDataWriter::(CGDataOStream &COS) { |
85 | using namespace support; |
86 | IndexedCGData::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(V: Header.Magic); |
104 | COS.write32(V: Header.Version); |
105 | COS.write32(V: 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(V: 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(V: 0); |
118 | |
119 | return Error::success(); |
120 | } |
121 | |
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(OS&: COS.OS); |
131 | uint64_t StableFunctionMapFieldStart = COS.tell(); |
132 | if (hasStableFunctionMap()) |
133 | FunctionMapRecord.serialize(OS&: COS.OS, PatchItems); |
134 | |
135 | // Back patch the offsets. |
136 | PatchItems.emplace_back(args&: OutlinedHashTreeOffset, args: &OutlinedHashTreeFieldStart, |
137 | args: 1); |
138 | PatchItems.emplace_back(args&: StableFunctionMapOffset, args: &StableFunctionMapFieldStart, |
139 | args: 1); |
140 | COS.patch(P: PatchItems); |
141 | |
142 | return Error::success(); |
143 | } |
144 | |
145 | Error CodeGenDataWriter::(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 | |
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 | |