LLVM 24.0.0git
CodeGenData.cpp
Go to the documentation of this file.
1//===-- CodeGenData.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 codegen data that has stable summary which
10// can be used to optimize the code in the subsequent codegen.
11//
12//===----------------------------------------------------------------------===//
13
14#include "CGDataOptions.h"
22
23#define DEBUG_TYPE "cg-data"
24
25using namespace llvm;
26using namespace cgdata;
27
28static std::string getCGDataErrString(cgdata_error Err,
29 const std::string &ErrMsg = "") {
30 std::string Msg;
32
33 switch (Err) {
35 OS << "success";
36 break;
38 OS << "end of File";
39 break;
41 OS << "invalid codegen data (bad magic)";
42 break;
44 OS << "invalid codegen data (file header is corrupt)";
45 break;
47 OS << "empty codegen data";
48 break;
50 OS << "malformed codegen data";
51 break;
53 OS << "unsupported codegen data version";
54 break;
55 }
56
57 // If optional error message is not empty, append it to the message.
58 if (!ErrMsg.empty())
59 OS << ": " << ErrMsg;
60
61 return OS.str();
62}
63
64namespace {
65
66// FIXME: This class is only here to support the transition to llvm::Error. It
67// will be removed once this transition is complete. Clients should prefer to
68// deal with the Error value directly, rather than converting to error_code.
69class CGDataErrorCategoryType : public std::error_category {
70 const char *name() const noexcept override { return "llvm.cgdata"; }
71
72 std::string message(int IE) const override {
73 return getCGDataErrString(static_cast<cgdata_error>(IE));
74 }
75};
76
77} // end anonymous namespace
78
79const std::error_category &llvm::cgdata_category() {
80 static CGDataErrorCategoryType ErrorCategory;
81 return ErrorCategory;
82}
83
84std::string CGDataError::message() const {
85 return getCGDataErrString(Err, Msg);
86}
87
88char CGDataError::ID = 0;
89
90namespace {
91
92const char *CodeGenDataSectNameCommon[] = {
93#define CG_DATA_SECT_ENTRY(Kind, SectNameCommon, SectNameCoff, Prefix) \
94 SectNameCommon,
96};
97
98const char *CodeGenDataSectNameCoff[] = {
99#define CG_DATA_SECT_ENTRY(Kind, SectNameCommon, SectNameCoff, Prefix) \
100 SectNameCoff,
102};
103
104const char *CodeGenDataSectNamePrefix[] = {
105#define CG_DATA_SECT_ENTRY(Kind, SectNameCommon, SectNameCoff, Prefix) Prefix,
107};
108
109} // namespace
110
112 return CGDataOptions::Global.codegen_data_thinlto_two_rounds;
113}
114
115namespace llvm {
116
119 bool AddSegmentInfo) {
120 std::string SectName;
121
122 if (OF == Triple::MachO && AddSegmentInfo)
123 SectName = CodeGenDataSectNamePrefix[CGSK];
124
125 if (OF == Triple::COFF)
126 SectName += CodeGenDataSectNameCoff[CGSK];
127 else
128 SectName += CodeGenDataSectNameCommon[CGSK];
129
130 return SectName;
131}
132
133std::unique_ptr<CodeGenData> CodeGenData::Instance = nullptr;
134std::once_flag CodeGenData::OnceFlag;
135
137 std::call_once(CodeGenData::OnceFlag, []() {
138 Instance = std::unique_ptr<CodeGenData>(new CodeGenData());
139
140 const CGDataOptions &Opts = CGDataOptions::Global;
141 if (Opts.codegen_data_generate || Opts.codegen_data_thinlto_two_rounds)
142 Instance->EmitCGData = true;
143 else if (!Opts.codegen_data_use_path.empty()) {
144 // Initialize the global CGData if the input file name is given.
145 // We do not error-out when failing to parse the input file.
146 // Instead, just emit an warning message and fall back as if no CGData
147 // were available.
148 auto FS = vfs::getRealFileSystem();
149 auto ReaderOrErr =
150 CodeGenDataReader::create(Opts.codegen_data_use_path, *FS,
151 Opts.indexed_codegen_data_lazy_loading);
152 if (Error E = ReaderOrErr.takeError()) {
153 warn(std::move(E), Opts.codegen_data_use_path);
154 return;
155 }
156 // Publish each CGData based on the data type in the header.
157 auto Reader = ReaderOrErr->get();
158 if (Reader->hasOutlinedHashTree())
159 Instance->publishOutlinedHashTree(Reader->releaseOutlinedHashTree());
160 if (Reader->hasStableFunctionMap())
161 Instance->publishStableFunctionMap(Reader->releaseStableFunctionMap());
162 }
163 });
164 return *Instance;
165}
166
167namespace IndexedCGData {
168
169Expected<Header> Header::readFromBuffer(const unsigned char *Curr) {
170 using namespace support;
171
172 static_assert(std::is_standard_layout_v<llvm::IndexedCGData::Header>,
173 "The header should be standard layout type since we use offset "
174 "of fields to read.");
175 Header H;
177 if (H.Magic != IndexedCGData::Magic)
183
185 "Please update the offset computation below if a new field has "
186 "been added to the header.");
187 H.OutlinedHashTreeOffset =
189 if (H.Version >= 2)
190 H.StableFunctionMapOffset =
192
193 return H;
194}
195
196} // end namespace IndexedCGData
197
198namespace cgdata {
199
200void warn(Twine Message, StringRef Whence, StringRef Hint) {
202 if (!Whence.empty())
203 errs() << Whence << ": ";
204 errs() << Message << "\n";
205 if (!Hint.empty())
206 WithColor::note() << Hint << "\n";
207}
208
209void warn(Error E, StringRef Whence) {
210 if (E.isA<CGDataError>()) {
211 handleAllErrors(std::move(E), [&](const CGDataError &IPE) {
212 warn(IPE.message(), Whence, "");
213 });
214 }
215}
216
217void saveModuleForTwoRounds(const Module &TheModule, unsigned Task,
218 AddStreamFn AddStream) {
219 LLVM_DEBUG(dbgs() << "Saving module: " << TheModule.getModuleIdentifier()
220 << " in Task " << Task << "\n");
222 AddStream(Task, TheModule.getModuleIdentifier());
223 if (Error Err = StreamOrErr.takeError())
224 report_fatal_error(std::move(Err));
225 std::unique_ptr<CachedFileStream> &Stream = *StreamOrErr;
226
227 WriteBitcodeToFile(TheModule, *Stream->OS,
228 /*ShouldPreserveUseListOrder=*/true);
229
230 if (Error Err = Stream->commit())
231 report_fatal_error(std::move(Err));
232}
233
234std::unique_ptr<Module> loadModuleForTwoRounds(BitcodeModule &OrigModule,
235 unsigned Task,
236 LLVMContext &Context,
237 ArrayRef<StringRef> IRFiles) {
238 LLVM_DEBUG(dbgs() << "Loading module: " << OrigModule.getModuleIdentifier()
239 << " in Task " << Task << "\n");
240 auto FileBuffer = MemoryBuffer::getMemBuffer(
241 IRFiles[Task], "in-memory IR file", /*RequiresNullTerminator=*/false);
242 auto RestoredModule = parseBitcodeFile(*FileBuffer, Context);
243 if (!RestoredModule)
245 Twine("Failed to parse optimized bitcode loaded for Task: ") +
246 Twine(Task) + "\n");
247
248 // Restore the original module identifier.
249 (*RestoredModule)->setModuleIdentifier(OrigModule.getModuleIdentifier());
250 return std::move(*RestoredModule);
251}
252
254 OutlinedHashTreeRecord GlobalOutlineRecord;
255 StableFunctionMapRecord GlobalStableFunctionMapRecord;
256 stable_hash CombinedHash = 0;
257 for (auto File : ObjFiles) {
258 if (File.empty())
259 continue;
260 std::unique_ptr<MemoryBuffer> Buffer = MemoryBuffer::getMemBuffer(
261 File, "in-memory object file", /*RequiresNullTerminator=*/false);
263 object::ObjectFile::createObjectFile(Buffer->getMemBufferRef());
264 if (!BinOrErr)
265 return BinOrErr.takeError();
266
267 std::unique_ptr<object::ObjectFile> &Obj = BinOrErr.get();
269 Obj.get(), GlobalOutlineRecord, GlobalStableFunctionMapRecord,
270 &CombinedHash))
271 return E;
272 }
273
274 GlobalStableFunctionMapRecord.finalize();
275
276 if (!GlobalOutlineRecord.empty())
277 cgdata::publishOutlinedHashTree(std::move(GlobalOutlineRecord.HashTree));
278 if (!GlobalStableFunctionMapRecord.empty())
280 std::move(GlobalStableFunctionMapRecord.FunctionMap));
281
282 return CombinedHash;
283}
284
285} // end namespace cgdata
286
287} // end namespace llvm
aarch64 promote const
static std::string getCGDataErrString(cgdata_error Err, const std::string &ErrMsg="")
#define H(x, y, z)
Definition MD5.cpp:56
const char * Msg
static const char * name
#define LLVM_DEBUG(...)
Definition Debug.h:119
Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition ArrayRef.h:40
Represents a module in a bitcode file.
StringRef getModuleIdentifier() const
static char ID
Definition CodeGenData.h:99
std::string message() const override
Return the error message as a string.
static LLVM_ABI Expected< std::unique_ptr< CodeGenDataReader > > create(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...
static LLVM_ABI CodeGenData & getInstance()
Lightweight error class with error context and mandatory checking.
Definition Error.h:159
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
reference get()
Returns a reference to the stored T value.
Definition Error.h:582
This is an important class for using LLVM in a threaded context.
Definition LLVMContext.h:68
static std::unique_ptr< MemoryBuffer > getMemBuffer(StringRef InputData, StringRef BufferName="", bool RequiresNullTerminator=true)
Open the specified memory range as a MemoryBuffer.
A Module instance is used to store all the information related to an LLVM module.
Definition Module.h:68
const std::string & getModuleIdentifier() const
Get the module identifier which is, essentially, the name of the module.
Definition Module.h:299
Represent a constant reference to a string, i.e.
Definition StringRef.h:56
constexpr bool empty() const
Check if the string is empty.
Definition StringRef.h:141
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
Definition Twine.h:82
static LLVM_ABI raw_ostream & warning()
Convenience method for printing "warning: " to stderr.
Definition WithColor.cpp:86
static LLVM_ABI raw_ostream & note()
Convenience method for printing "note: " to stderr.
Definition WithColor.cpp:88
static Expected< OwningBinary< ObjectFile > > createObjectFile(StringRef ObjectPath)
A raw_ostream that writes to an std::string.
std::string & str()
Returns the string's reference.
const uint64_t Magic
LLVM_ABI Expected< stable_hash > mergeCodeGenData(ArrayRef< StringRef > ObjectFiles)
Merge the codegen data from the scratch objects ObjectFiles from the first codegen round.
void publishOutlinedHashTree(std::unique_ptr< OutlinedHashTree > HashTree)
LLVM_ABI void warn(Error E, StringRef Whence="")
LLVM_ABI bool thinLTOTwoRounds()
Returns whether ThinLTO runs two rounds of code generation (-codegen-data-thinlto-two-rounds).
void publishStableFunctionMap(std::unique_ptr< StableFunctionMap > FunctionMap)
LLVM_ABI void saveModuleForTwoRounds(const Module &TheModule, unsigned Task, AddStreamFn AddStream)
Save TheModule before the first codegen round.
LLVM_ABI std::unique_ptr< Module > loadModuleForTwoRounds(BitcodeModule &OrigModule, unsigned Task, LLVMContext &Context, ArrayRef< StringRef > IRFiles)
Load the optimized bitcode module for the second codegen round.
value_type readNext(const CharT *&memory, endianness endian)
Read a value of a particular endianness from a buffer, and increment the buffer past that value.
Definition Endian.h:67
LLVM_ABI IntrusiveRefCntPtr< FileSystem > getRealFileSystem()
Gets an vfs::FileSystem for the 'real' file system, as seen by the operating system.
This is an optimization pass for GlobalISel generic memory operations.
LLVM_ABI Expected< std::unique_ptr< Module > > parseBitcodeFile(MemoryBufferRef Buffer, LLVMContext &Context, ParserCallbacks Callbacks={})
Read the specified bitcode file, returning the module.
LLVM_ABI void WriteBitcodeToFile(const Module &M, raw_ostream &Out, bool ShouldPreserveUseListOrder=false, const ModuleSummaryIndex *Index=nullptr, bool GenerateHash=false, ModuleHash *ModHash=nullptr)
Write the specified module to the specified raw output stream.
void handleAllErrors(Error E, HandlerTs &&... Handlers)
Behaves the same as handleErrors, except that by contract all errors must be handled by the given han...
Definition Error.h:1013
uint64_t stable_hash
An opaque object representing a stable hash code.
cgdata_error
Definition CodeGenData.h:53
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition Debug.cpp:209
LLVM_ABI void report_fatal_error(Error Err, bool gen_crash_diag=true)
Definition Error.cpp:163
LLVM_ABI const std::error_category & cgdata_category()
Error make_error(ArgTs &&... Args)
Make a Error instance representing failure using the given error info type.
Definition Error.h:340
LLVM_ABI raw_fd_ostream & errs()
This returns a reference to a raw_ostream for standard error.
CGDataSectKind
Definition CodeGenData.h:33
std::function< Expected< std::unique_ptr< CachedFileStream > >( unsigned Task, const Twine &ModuleName)> AddStreamFn
This type defines the callback to add a file that is generated on the fly.
Definition Caching.h:62
LLVM_ABI std::string getCodeGenDataSectionName(CGDataSectKind CGSK, Triple::ObjectFormatType OF, bool AddSegmentInfo=true)
static LLVM_ABI Expected< Header > readFromBuffer(const unsigned char *Curr)
std::unique_ptr< OutlinedHashTree > HashTree
The structure of the serialized stable function map is as follows:
void finalize(bool SkipTrim=false)
Finalize the stable function map by trimming content.
std::unique_ptr< StableFunctionMap > FunctionMap