xref: /freebsd/contrib/llvm-project/llvm/lib/CGData/CodeGenDataWriter.cpp (revision 700637cbb5e582861067a11aaca4d053546871d2)
1*700637cbSDimitry Andric //===- CodeGenDataWriter.cpp ----------------------------------------------===//
2*700637cbSDimitry Andric //
3*700637cbSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*700637cbSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*700637cbSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*700637cbSDimitry Andric //
7*700637cbSDimitry Andric //===----------------------------------------------------------------------===//
8*700637cbSDimitry Andric //
9*700637cbSDimitry Andric // This file contains support for writing codegen data.
10*700637cbSDimitry Andric //
11*700637cbSDimitry Andric //===----------------------------------------------------------------------===//
12*700637cbSDimitry Andric 
13*700637cbSDimitry Andric #include "llvm/CGData/CodeGenDataWriter.h"
14*700637cbSDimitry Andric 
15*700637cbSDimitry Andric #define DEBUG_TYPE "cg-data-writer"
16*700637cbSDimitry Andric 
17*700637cbSDimitry Andric using namespace llvm;
18*700637cbSDimitry Andric 
patch(ArrayRef<CGDataPatchItem> P)19*700637cbSDimitry Andric void CGDataOStream::patch(ArrayRef<CGDataPatchItem> P) {
20*700637cbSDimitry Andric   using namespace support;
21*700637cbSDimitry Andric 
22*700637cbSDimitry Andric   switch (Kind) {
23*700637cbSDimitry Andric   case OStreamKind::fd: {
24*700637cbSDimitry Andric     raw_fd_ostream &FDOStream = static_cast<raw_fd_ostream &>(OS);
25*700637cbSDimitry Andric     const uint64_t LastPos = FDOStream.tell();
26*700637cbSDimitry Andric     for (const auto &K : P) {
27*700637cbSDimitry Andric       FDOStream.seek(K.Pos);
28*700637cbSDimitry Andric       for (size_t I = 0; I < K.D.size(); ++I)
29*700637cbSDimitry Andric         write(K.D[I]);
30*700637cbSDimitry Andric     }
31*700637cbSDimitry Andric     // Reset the stream to the last position after patching so that users
32*700637cbSDimitry Andric     // don't accidentally overwrite data. This makes it consistent with
33*700637cbSDimitry Andric     // the string stream below which replaces the data directly.
34*700637cbSDimitry Andric     FDOStream.seek(LastPos);
35*700637cbSDimitry Andric     break;
36*700637cbSDimitry Andric   }
37*700637cbSDimitry Andric   case OStreamKind::string: {
38*700637cbSDimitry Andric     raw_string_ostream &SOStream = static_cast<raw_string_ostream &>(OS);
39*700637cbSDimitry Andric     std::string &Data = SOStream.str(); // with flush
40*700637cbSDimitry Andric     for (const auto &K : P) {
41*700637cbSDimitry Andric       for (size_t I = 0; I < K.D.size(); ++I) {
42*700637cbSDimitry Andric         uint64_t Bytes =
43*700637cbSDimitry Andric             endian::byte_swap<uint64_t, llvm::endianness::little>(K.D[I]);
44*700637cbSDimitry Andric         Data.replace(K.Pos + I * sizeof(uint64_t), sizeof(uint64_t),
45*700637cbSDimitry Andric                      reinterpret_cast<const char *>(&Bytes), sizeof(uint64_t));
46*700637cbSDimitry Andric       }
47*700637cbSDimitry Andric     }
48*700637cbSDimitry Andric     break;
49*700637cbSDimitry Andric   }
50*700637cbSDimitry Andric   case OStreamKind::svector: {
51*700637cbSDimitry Andric     raw_svector_ostream &VOStream = static_cast<raw_svector_ostream &>(OS);
52*700637cbSDimitry Andric     for (const auto &K : P) {
53*700637cbSDimitry Andric       for (size_t I = 0; I < K.D.size(); ++I) {
54*700637cbSDimitry Andric         uint64_t Bytes =
55*700637cbSDimitry Andric             endian::byte_swap<uint64_t, llvm::endianness::little>(K.D[I]);
56*700637cbSDimitry Andric         VOStream.pwrite(reinterpret_cast<const char *>(&Bytes),
57*700637cbSDimitry Andric                         sizeof(uint64_t), K.Pos + I * sizeof(uint64_t));
58*700637cbSDimitry Andric       }
59*700637cbSDimitry Andric     }
60*700637cbSDimitry Andric     break;
61*700637cbSDimitry Andric   }
62*700637cbSDimitry Andric   }
63*700637cbSDimitry Andric }
64*700637cbSDimitry Andric 
addRecord(OutlinedHashTreeRecord & Record)65*700637cbSDimitry Andric void CodeGenDataWriter::addRecord(OutlinedHashTreeRecord &Record) {
66*700637cbSDimitry Andric   assert(Record.HashTree && "empty hash tree in the record");
67*700637cbSDimitry Andric   HashTreeRecord.HashTree = std::move(Record.HashTree);
68*700637cbSDimitry Andric 
69*700637cbSDimitry Andric   DataKind |= CGDataKind::FunctionOutlinedHashTree;
70*700637cbSDimitry Andric }
71*700637cbSDimitry Andric 
addRecord(StableFunctionMapRecord & Record)72*700637cbSDimitry Andric void CodeGenDataWriter::addRecord(StableFunctionMapRecord &Record) {
73*700637cbSDimitry Andric   assert(Record.FunctionMap && "empty function map in the record");
74*700637cbSDimitry Andric   FunctionMapRecord.FunctionMap = std::move(Record.FunctionMap);
75*700637cbSDimitry Andric 
76*700637cbSDimitry Andric   DataKind |= CGDataKind::StableFunctionMergingMap;
77*700637cbSDimitry Andric }
78*700637cbSDimitry Andric 
write(raw_fd_ostream & OS)79*700637cbSDimitry Andric Error CodeGenDataWriter::write(raw_fd_ostream &OS) {
80*700637cbSDimitry Andric   CGDataOStream COS(OS);
81*700637cbSDimitry Andric   return writeImpl(COS);
82*700637cbSDimitry Andric }
83*700637cbSDimitry Andric 
writeHeader(CGDataOStream & COS)84*700637cbSDimitry Andric Error CodeGenDataWriter::writeHeader(CGDataOStream &COS) {
85*700637cbSDimitry Andric   using namespace support;
86*700637cbSDimitry Andric   IndexedCGData::Header Header;
87*700637cbSDimitry Andric   Header.Magic = IndexedCGData::Magic;
88*700637cbSDimitry Andric   Header.Version = IndexedCGData::Version;
89*700637cbSDimitry Andric 
90*700637cbSDimitry Andric   // Set the CGDataKind depending on the kind.
91*700637cbSDimitry Andric   Header.DataKind = 0;
92*700637cbSDimitry Andric   if (static_cast<bool>(DataKind & CGDataKind::FunctionOutlinedHashTree))
93*700637cbSDimitry Andric     Header.DataKind |=
94*700637cbSDimitry Andric         static_cast<uint32_t>(CGDataKind::FunctionOutlinedHashTree);
95*700637cbSDimitry Andric   if (static_cast<bool>(DataKind & CGDataKind::StableFunctionMergingMap))
96*700637cbSDimitry Andric     Header.DataKind |=
97*700637cbSDimitry Andric         static_cast<uint32_t>(CGDataKind::StableFunctionMergingMap);
98*700637cbSDimitry Andric   Header.OutlinedHashTreeOffset = 0;
99*700637cbSDimitry Andric   Header.StableFunctionMapOffset = 0;
100*700637cbSDimitry Andric 
101*700637cbSDimitry Andric   // Only write up to the CGDataKind. We need to remember the offset of the
102*700637cbSDimitry Andric   // remaining fields to allow back-patching later.
103*700637cbSDimitry Andric   COS.write(Header.Magic);
104*700637cbSDimitry Andric   COS.write32(Header.Version);
105*700637cbSDimitry Andric   COS.write32(Header.DataKind);
106*700637cbSDimitry Andric 
107*700637cbSDimitry Andric   // Save the location of Header.OutlinedHashTreeOffset field in \c COS.
108*700637cbSDimitry Andric   OutlinedHashTreeOffset = COS.tell();
109*700637cbSDimitry Andric 
110*700637cbSDimitry Andric   // Reserve the space for OutlinedHashTreeOffset field.
111*700637cbSDimitry Andric   COS.write(0);
112*700637cbSDimitry Andric 
113*700637cbSDimitry Andric   // Save the location of Header.StableFunctionMapOffset field in \c COS.
114*700637cbSDimitry Andric   StableFunctionMapOffset = COS.tell();
115*700637cbSDimitry Andric 
116*700637cbSDimitry Andric   // Reserve the space for StableFunctionMapOffset field.
117*700637cbSDimitry Andric   COS.write(0);
118*700637cbSDimitry Andric 
119*700637cbSDimitry Andric   return Error::success();
120*700637cbSDimitry Andric }
121*700637cbSDimitry Andric 
writeImpl(CGDataOStream & COS)122*700637cbSDimitry Andric Error CodeGenDataWriter::writeImpl(CGDataOStream &COS) {
123*700637cbSDimitry Andric   if (Error E = writeHeader(COS))
124*700637cbSDimitry Andric     return E;
125*700637cbSDimitry Andric 
126*700637cbSDimitry Andric   std::vector<CGDataPatchItem> PatchItems;
127*700637cbSDimitry Andric 
128*700637cbSDimitry Andric   uint64_t OutlinedHashTreeFieldStart = COS.tell();
129*700637cbSDimitry Andric   if (hasOutlinedHashTree())
130*700637cbSDimitry Andric     HashTreeRecord.serialize(COS.OS);
131*700637cbSDimitry Andric   uint64_t StableFunctionMapFieldStart = COS.tell();
132*700637cbSDimitry Andric   if (hasStableFunctionMap())
133*700637cbSDimitry Andric     FunctionMapRecord.serialize(COS.OS, PatchItems);
134*700637cbSDimitry Andric 
135*700637cbSDimitry Andric   // Back patch the offsets.
136*700637cbSDimitry Andric   PatchItems.emplace_back(OutlinedHashTreeOffset, &OutlinedHashTreeFieldStart,
137*700637cbSDimitry Andric                           1);
138*700637cbSDimitry Andric   PatchItems.emplace_back(StableFunctionMapOffset, &StableFunctionMapFieldStart,
139*700637cbSDimitry Andric                           1);
140*700637cbSDimitry Andric   COS.patch(PatchItems);
141*700637cbSDimitry Andric 
142*700637cbSDimitry Andric   return Error::success();
143*700637cbSDimitry Andric }
144*700637cbSDimitry Andric 
writeHeaderText(raw_fd_ostream & OS)145*700637cbSDimitry Andric Error CodeGenDataWriter::writeHeaderText(raw_fd_ostream &OS) {
146*700637cbSDimitry Andric   if (hasOutlinedHashTree())
147*700637cbSDimitry Andric     OS << "# Outlined stable hash tree\n:outlined_hash_tree\n";
148*700637cbSDimitry Andric 
149*700637cbSDimitry Andric   if (hasStableFunctionMap())
150*700637cbSDimitry Andric     OS << "# Stable function map\n:stable_function_map\n";
151*700637cbSDimitry Andric 
152*700637cbSDimitry Andric   // TODO: Add more data types in this header
153*700637cbSDimitry Andric 
154*700637cbSDimitry Andric   return Error::success();
155*700637cbSDimitry Andric }
156*700637cbSDimitry Andric 
writeText(raw_fd_ostream & OS)157*700637cbSDimitry Andric Error CodeGenDataWriter::writeText(raw_fd_ostream &OS) {
158*700637cbSDimitry Andric   if (Error E = writeHeaderText(OS))
159*700637cbSDimitry Andric     return E;
160*700637cbSDimitry Andric 
161*700637cbSDimitry Andric   yaml::Output YOS(OS);
162*700637cbSDimitry Andric   if (hasOutlinedHashTree())
163*700637cbSDimitry Andric     HashTreeRecord.serializeYAML(YOS);
164*700637cbSDimitry Andric 
165*700637cbSDimitry Andric   if (hasStableFunctionMap())
166*700637cbSDimitry Andric     FunctionMapRecord.serializeYAML(YOS);
167*700637cbSDimitry Andric 
168*700637cbSDimitry Andric   // TODO: Write more yaml cgdata in order
169*700637cbSDimitry Andric 
170*700637cbSDimitry Andric   return Error::success();
171*700637cbSDimitry Andric }
172