xref: /freebsd/contrib/llvm-project/llvm/lib/CGData/CodeGenDataWriter.cpp (revision 700637cbb5e582861067a11aaca4d053546871d2)
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