xref: /llvm-project/llvm/lib/CGData/CodeGenDataWriter.cpp (revision ffcf3c8688f57acaf6a404a1238673c9d197ba9a)
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   if (IsFDOStream) {
23     raw_fd_ostream &FDOStream = static_cast<raw_fd_ostream &>(OS);
24     const uint64_t LastPos = FDOStream.tell();
25     for (const auto &K : P) {
26       FDOStream.seek(K.Pos);
27       for (int I = 0; I < K.N; I++)
28         write(K.D[I]);
29     }
30     // Reset the stream to the last position after patching so that users
31     // don't accidentally overwrite data. This makes it consistent with
32     // the string stream below which replaces the data directly.
33     FDOStream.seek(LastPos);
34   } else {
35     raw_string_ostream &SOStream = static_cast<raw_string_ostream &>(OS);
36     std::string &Data = SOStream.str(); // with flush
37     for (const auto &K : P) {
38       for (int I = 0; I < K.N; I++) {
39         uint64_t Bytes =
40             endian::byte_swap<uint64_t, llvm::endianness::little>(K.D[I]);
41         Data.replace(K.Pos + I * sizeof(uint64_t), sizeof(uint64_t),
42                      reinterpret_cast<const char *>(&Bytes), sizeof(uint64_t));
43       }
44     }
45   }
46 }
47 
48 void CodeGenDataWriter::addRecord(OutlinedHashTreeRecord &Record) {
49   assert(Record.HashTree && "empty hash tree in the record");
50   HashTreeRecord.HashTree = std::move(Record.HashTree);
51 
52   DataKind |= CGDataKind::FunctionOutlinedHashTree;
53 }
54 
55 void CodeGenDataWriter::addRecord(StableFunctionMapRecord &Record) {
56   assert(Record.FunctionMap && "empty function map in the record");
57   FunctionMapRecord.FunctionMap = std::move(Record.FunctionMap);
58 
59   DataKind |= CGDataKind::StableFunctionMergingMap;
60 }
61 
62 Error CodeGenDataWriter::write(raw_fd_ostream &OS) {
63   CGDataOStream COS(OS);
64   return writeImpl(COS);
65 }
66 
67 Error CodeGenDataWriter::writeHeader(CGDataOStream &COS) {
68   using namespace support;
69   IndexedCGData::Header Header;
70   Header.Magic = IndexedCGData::Magic;
71   Header.Version = IndexedCGData::Version;
72 
73   // Set the CGDataKind depending on the kind.
74   Header.DataKind = 0;
75   if (static_cast<bool>(DataKind & CGDataKind::FunctionOutlinedHashTree))
76     Header.DataKind |=
77         static_cast<uint32_t>(CGDataKind::FunctionOutlinedHashTree);
78   if (static_cast<bool>(DataKind & CGDataKind::StableFunctionMergingMap))
79     Header.DataKind |=
80         static_cast<uint32_t>(CGDataKind::StableFunctionMergingMap);
81   Header.OutlinedHashTreeOffset = 0;
82   Header.StableFunctionMapOffset = 0;
83 
84   // Only write up to the CGDataKind. We need to remember the offset of the
85   // remaining fields to allow back-patching later.
86   COS.write(Header.Magic);
87   COS.write32(Header.Version);
88   COS.write32(Header.DataKind);
89 
90   // Save the location of Header.OutlinedHashTreeOffset field in \c COS.
91   OutlinedHashTreeOffset = COS.tell();
92 
93   // Reserve the space for OutlinedHashTreeOffset field.
94   COS.write(0);
95 
96   // Save the location of Header.StableFunctionMapOffset field in \c COS.
97   StableFunctionMapOffset = COS.tell();
98 
99   // Reserve the space for StableFunctionMapOffset field.
100   COS.write(0);
101 
102   return Error::success();
103 }
104 
105 Error CodeGenDataWriter::writeImpl(CGDataOStream &COS) {
106   if (Error E = writeHeader(COS))
107     return E;
108 
109   uint64_t OutlinedHashTreeFieldStart = COS.tell();
110   if (hasOutlinedHashTree())
111     HashTreeRecord.serialize(COS.OS);
112   uint64_t StableFunctionMapFieldStart = COS.tell();
113   if (hasStableFunctionMap())
114     FunctionMapRecord.serialize(COS.OS);
115 
116   // Back patch the offsets.
117   CGDataPatchItem PatchItems[] = {
118       {OutlinedHashTreeOffset, &OutlinedHashTreeFieldStart, 1},
119       {StableFunctionMapOffset, &StableFunctionMapFieldStart, 1}};
120   COS.patch(PatchItems);
121 
122   return Error::success();
123 }
124 
125 Error CodeGenDataWriter::writeHeaderText(raw_fd_ostream &OS) {
126   if (hasOutlinedHashTree())
127     OS << "# Outlined stable hash tree\n:outlined_hash_tree\n";
128 
129   if (hasStableFunctionMap())
130     OS << "# Stable function map\n:stable_function_map\n";
131 
132   // TODO: Add more data types in this header
133 
134   return Error::success();
135 }
136 
137 Error CodeGenDataWriter::writeText(raw_fd_ostream &OS) {
138   if (Error E = writeHeaderText(OS))
139     return E;
140 
141   yaml::Output YOS(OS);
142   if (hasOutlinedHashTree())
143     HashTreeRecord.serializeYAML(YOS);
144 
145   if (hasStableFunctionMap())
146     FunctionMapRecord.serializeYAML(YOS);
147 
148   // TODO: Write more yaml cgdata in order
149 
150   return Error::success();
151 }
152