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
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(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
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 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
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(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
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 header
153
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 order
169
170 return Error::success();
171}
172