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