LLVM 24.0.0git
CodeGenDataReader.cpp
Go to the documentation of this file.
1//===- CodeGenDataReader.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 reading codegen data.
10//
11//===----------------------------------------------------------------------===//
12
14#include "CGDataOptions.h"
18
19#define DEBUG_TYPE "cg-data-reader"
20
21using namespace llvm;
22
23namespace llvm {
24
27 auto BufferOrErr = Filename.str() == "-" ? MemoryBuffer::getSTDIN()
28 : FS.getBufferForFile(Filename);
29 if (std::error_code EC = BufferOrErr.getError())
30 return errorCodeToError(EC);
31 return std::move(BufferOrErr.get());
32}
33
35 const object::ObjectFile *Obj, OutlinedHashTreeRecord &GlobalOutlineRecord,
36 StableFunctionMapRecord &GlobalFunctionMapRecord,
37 stable_hash *CombinedHash) {
38 Triple::ObjectFormatType OF = Obj->getTripleObjectFormat();
39 auto CGOutlineName =
40 getCodeGenDataSectionName(CG_outline, OF, /*AddSegmentInfo=*/false);
41 auto CGMergeName =
42 getCodeGenDataSectionName(CG_merge, OF, /*AddSegmentInfo=*/false);
43
44 auto processSectionContents = [&](const StringRef &Name,
45 const StringRef &Contents) {
46 if (Name != CGOutlineName && Name != CGMergeName)
47 return;
48 if (CombinedHash)
49 *CombinedHash = stable_hash_combine(*CombinedHash, xxh3_64bits(Contents));
50 auto *Data = reinterpret_cast<const unsigned char *>(Contents.data());
51 auto *EndData = Data + Contents.size();
52 // In case dealing with an executable that has concatenated cgdata,
53 // we want to merge them into a single cgdata.
54 // Although it's not a typical workflow, we support this scenario
55 // by looping over all data in the sections.
56 if (Name == CGOutlineName) {
57 while (Data != EndData) {
58 OutlinedHashTreeRecord LocalOutlineRecord;
59 LocalOutlineRecord.deserialize(Data);
60 GlobalOutlineRecord.merge(LocalOutlineRecord);
61 }
62 } else if (Name == CGMergeName) {
63 while (Data != EndData) {
64 StableFunctionMapRecord LocalFunctionMapRecord;
65 LocalFunctionMapRecord.deserialize(Data);
66 GlobalFunctionMapRecord.merge(LocalFunctionMapRecord);
67 }
68 }
69 };
70
71 for (auto &Section : Obj->sections()) {
72 Expected<StringRef> NameOrErr = Section.getName();
73 if (!NameOrErr)
74 return NameOrErr.takeError();
75 Expected<StringRef> ContentsOrErr = Section.getContents();
76 if (!ContentsOrErr)
77 return ContentsOrErr.takeError();
78 processSectionContents(*NameOrErr, *ContentsOrErr);
79 }
80
81 return Error::success();
82}
83
85 using namespace support;
86
87 // The smallest header with the version 1 is 24 bytes.
88 // Do not update this value even with the new version of the header.
89 const unsigned MinHeaderSize = 24;
90 if (DataBuffer->getBufferSize() < MinHeaderSize)
92
93 auto *Start =
94 reinterpret_cast<const unsigned char *>(DataBuffer->getBufferStart());
95 auto *End =
96 reinterpret_cast<const unsigned char *>(DataBuffer->getBufferEnd());
97 if (auto E = IndexedCGData::Header::readFromBuffer(Start).moveInto(Header))
98 return E;
99
100 if (hasOutlinedHashTree()) {
101 const unsigned char *Ptr = Start + Header.OutlinedHashTreeOffset;
102 if (Ptr >= End)
103 return error(cgdata_error::eof);
104 HashTreeRecord.deserialize(Ptr);
105 }
106
107 // TODO: lazy loading support for outlined hash tree.
108 std::shared_ptr<MemoryBuffer> SharedDataBuffer = std::move(DataBuffer);
109 if (hasStableFunctionMap()) {
110 const unsigned char *Ptr = Start + Header.StableFunctionMapOffset;
111 if (Ptr >= End)
112 return error(cgdata_error::eof);
113 FunctionMapRecord.setReadStableFunctionMapNames(ReadStableFunctionMapNames);
114 if (LazyLoading)
115 FunctionMapRecord.lazyDeserialize(std::move(SharedDataBuffer),
116 Header.StableFunctionMapOffset);
117 else
118 FunctionMapRecord.deserialize(Ptr);
119 }
120
121 return success();
122}
123
126 const Twine &Path, vfs::FileSystem &FS,
127 bool LazyLoading) {
128 // Set up the buffer to read.
129 auto BufferOrError = setupMemoryBuffer(Path, FS);
130 if (Error E = BufferOrError.takeError())
131 return std::move(E);
132 return CodeGenDataReader::create(LibraryOptions,
133 std::move(BufferOrError.get()), LazyLoading);
134}
135
138 std::unique_ptr<MemoryBuffer> Buffer,
139 bool LazyLoading) {
140 if (Buffer->getBufferSize() == 0)
142
143 std::unique_ptr<CodeGenDataReader> Reader;
144 // Create the reader.
146 Reader = std::make_unique<IndexedCodeGenDataReader>(
147 LibraryOptions.get<CGDataOptions>()
148 .indexed_codegen_data_read_function_map_names,
149 std::move(Buffer), LazyLoading);
150 else if (TextCodeGenDataReader::hasFormat(*Buffer))
151 Reader = std::make_unique<TextCodeGenDataReader>(std::move(Buffer));
152 else
154
155 // Initialize the reader and return the result.
156 if (Error E = Reader->read())
157 return std::move(E);
158
159 return std::move(Reader);
160}
161
163 using namespace support;
164 if (DataBuffer.getBufferSize() < sizeof(IndexedCGData::Magic))
165 return false;
166
167 uint64_t Magic = endian::read<uint64_t, aligned>(DataBuffer.getBufferStart(),
169 // Verify that it's magical.
170 return Magic == IndexedCGData::Magic;
171}
172
174 // Verify that this really looks like plain ASCII text by checking a
175 // 'reasonable' number of characters (up to the magic size).
176 StringRef Prefix = Buffer.getBuffer().take_front(sizeof(uint64_t));
177 return llvm::all_of(Prefix, [](char c) { return isPrint(c) || isSpace(c); });
178}
180 using namespace support;
181
182 // Parse the custom header line by line.
183 for (; !Line.is_at_eof(); ++Line) {
184 // Skip empty or whitespace-only lines
185 if (Line->trim().empty())
186 continue;
187
188 if (!Line->starts_with(":"))
189 break;
190 StringRef Str = Line->drop_front().rtrim();
191 if (Str.equals_insensitive("outlined_hash_tree"))
193 else if (Str.equals_insensitive("stable_function_map"))
195 else
197 }
198
199 // We treat an empty header (that is a comment # only) as a valid header.
200 if (Line.is_at_eof()) {
201 if (DataKind == CGDataKind::Unknown)
202 return Error::success();
204 }
205
206 // The YAML docs follow after the header.
207 const char *Pos = Line->data();
208 size_t Size = reinterpret_cast<size_t>(DataBuffer->getBufferEnd()) -
209 reinterpret_cast<size_t>(Pos);
210 yaml::Input YOS(StringRef(Pos, Size));
212 HashTreeRecord.deserializeYAML(YOS);
214 FunctionMapRecord.deserializeYAML(YOS);
215
216 return Error::success();
217}
218} // end namespace llvm
static constexpr StringLiteral Filename
#define error(X)
Error success()
Clear the current error and return a successful one.
OutlinedHashTreeRecord HashTreeRecord
The outlined hash tree that has been read.
StableFunctionMapRecord FunctionMapRecord
The stable function map that has been read. When it's released by.
static LLVM_ABI Expected< std::unique_ptr< CodeGenDataReader > > create(const cl::LibraryOptionsContext &LibraryOptions, const Twine &Path, vfs::FileSystem &FS, bool LazyLoading=false)
Factory method to create an appropriately typed reader for the given codegen data file path and file ...
static LLVM_ABI Error mergeFromObjectFile(const object::ObjectFile *Obj, OutlinedHashTreeRecord &GlobalOutlineRecord, StableFunctionMapRecord &GlobalFunctionMapRecord, stable_hash *CombinedHash=nullptr)
Extract the cgdata embedded in sections from the given object file and merge them into the GlobalOutl...
Lightweight error class with error context and mandatory checking.
Definition Error.h:159
static ErrorSuccess success()
Create a success value.
Definition Error.h:336
Tagged union holding either a T or a Error.
Definition Error.h:485
Error takeError()
Take ownership of the stored error.
Definition Error.h:612
static bool hasFormat(const MemoryBuffer &Buffer)
Return true if the given buffer is in binary codegen data format.
Error read() override
Read the contents including the header.
bool hasStableFunctionMap() const override
Return true if the header indicates the data has a stable function map.
bool hasOutlinedHashTree() const override
Return true if the header indicates the data has an outlined hash tree.
This interface provides simple read-only access to a block of memory, and provides simple methods for...
StringRef getBuffer() const
static ErrorOr< std::unique_ptr< MemoryBuffer > > getSTDIN()
Read all of stdin into a file buffer, and return it.
Represent a constant reference to a string, i.e.
Definition StringRef.h:56
StringRef drop_front(size_t N=1) const
Return a StringRef equal to 'this' but with the first N elements dropped.
Definition StringRef.h:635
StringRef rtrim(char Char) const
Return string with consecutive Char characters starting from the right removed.
Definition StringRef.h:838
StringRef take_front(size_t N=1) const
Return a StringRef equal to 'this' but with only the first N elements remaining.
Definition StringRef.h:606
static bool hasFormat(const MemoryBuffer &Buffer)
Return true if the given buffer is in text codegen data format.
bool hasStableFunctionMap() const override
Return true if the header indicates the data has a stable function map.
bool hasOutlinedHashTree() const override
Return true if the header indicates the data has an outlined hash tree.
Error read() override
Read the contents including the header.
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
Definition Twine.h:82
This class is the base class for all object file types.
Definition ObjectFile.h:231
The virtual file system interface.
The Input class is used to parse a yaml document into in-memory structs and vectors.
const uint64_t Magic
value_type read(const void *memory, endianness endian)
Read a value of a particular endianness from memory.
Definition Endian.h:53
This is an optimization pass for GlobalISel generic memory operations.
static Expected< std::unique_ptr< MemoryBuffer > > setupMemoryBuffer(const Twine &Filename, vfs::FileSystem &FS)
bool all_of(R &&range, UnaryPredicate P)
Provide wrappers to std::all_of which take ranges instead of having to pass begin/end explicitly.
Definition STLExtras.h:1755
uint64_t xxh3_64bits(ArrayRef< uint8_t > data)
Inline ArrayRef overloads of the xxhash entry points declared out-of-line in llvm/Support/xxhash....
Definition ArrayRef.h:558
uint64_t stable_hash
An opaque object representing a stable hash code.
Error make_error(ArgTs &&... Args)
Make a Error instance representing failure using the given error info type.
Definition Error.h:340
bool isPrint(char C)
Checks whether character C is printable.
bool isSpace(char C)
Checks whether character C is whitespace in the "C" locale.
LLVM_ABI Error errorCodeToError(std::error_code EC)
Helper for converting an std::error_code to a Error.
Definition Error.cpp:107
stable_hash stable_hash_combine(ArrayRef< stable_hash > Buffer)
@ End
Run the machine verifier once, at the end of the pipeline.
Definition CodeGen.h:267
LLVM_ABI std::string getCodeGenDataSectionName(CGDataSectKind CGSK, Triple::ObjectFormatType OF, bool AddSegmentInfo=true)
static LLVM_ABI Expected< Header > readFromBuffer(const unsigned char *Curr)
LLVM_ABI void deserialize(const unsigned char *&Ptr)
Deserialize the outlined hash tree from a raw_ostream.
void merge(const OutlinedHashTreeRecord &Other)
Merge the other outlined hash tree into this one.
The structure of the serialized stable function map is as follows:
void merge(const StableFunctionMapRecord &Other)
Merge the stable function map into this one.
LLVM_ABI void deserialize(const unsigned char *&Ptr)
Deserialize the stable function map from a raw_ostream.