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(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 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::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 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 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 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