LLVM 22.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
22
23#define DEBUG_TYPE "cg-data"
24
25using namespace llvm;
26using namespace cgdata;
27
28static cl::opt<bool>
29 CodeGenDataGenerate("codegen-data-generate", cl::init(false), cl::Hidden,
30 cl::desc("Emit CodeGen Data into custom sections"));
32 CodeGenDataUsePath("codegen-data-use-path", cl::init(""), cl::Hidden,
33 cl::desc("File path to where .cgdata file is read"));
35 "codegen-data-thinlto-two-rounds", cl::init(false), cl::Hidden,
36 cl::desc("Enable two-round ThinLTO code generation. The first round "
37 "emits codegen data, while the second round uses the emitted "
38 "codegen data for further optimizations."));
39
40static std::string getCGDataErrString(cgdata_error Err,
41 const std::string &ErrMsg = "") {
42 std::string Msg;
44
45 switch (Err) {
46 case cgdata_error::success:
47 OS << "success";
48 break;
49 case cgdata_error::eof:
50 OS << "end of File";
51 break;
52 case cgdata_error::bad_magic:
53 OS << "invalid codegen data (bad magic)";
54 break;
55 case cgdata_error::bad_header:
56 OS << "invalid codegen data (file header is corrupt)";
57 break;
58 case cgdata_error::empty_cgdata:
59 OS << "empty codegen data";
60 break;
61 case cgdata_error::malformed:
62 OS << "malformed codegen data";
63 break;
64 case cgdata_error::unsupported_version:
65 OS << "unsupported codegen data version";
66 break;
67 }
68
69 // If optional error message is not empty, append it to the message.
70 if (!ErrMsg.empty())
71 OS << ": " << ErrMsg;
72
73 return OS.str();
74}
75
76namespace {
77
78// FIXME: This class is only here to support the transition to llvm::Error. It
79// will be removed once this transition is complete. Clients should prefer to
80// deal with the Error value directly, rather than converting to error_code.
81class CGDataErrorCategoryType : public std::error_category {
82 const char *name() const noexcept override { return "llvm.cgdata"; }
83
84 std::string message(int IE) const override {
85 return getCGDataErrString(static_cast<cgdata_error>(IE));
86 }
87};
88
89} // end anonymous namespace
90
91const std::error_category &llvm::cgdata_category() {
92 static CGDataErrorCategoryType ErrorCategory;
93 return ErrorCategory;
94}
95
96std::string CGDataError::message() const {
97 return getCGDataErrString(Err, Msg);
98}
99
100char CGDataError::ID = 0;
101
102namespace {
103
104const char *CodeGenDataSectNameCommon[] = {
105#define CG_DATA_SECT_ENTRY(Kind, SectNameCommon, SectNameCoff, Prefix) \
106 SectNameCommon,
108};
109
110const char *CodeGenDataSectNameCoff[] = {
111#define CG_DATA_SECT_ENTRY(Kind, SectNameCommon, SectNameCoff, Prefix) \
112 SectNameCoff,
114};
115
116const char *CodeGenDataSectNamePrefix[] = {
117#define CG_DATA_SECT_ENTRY(Kind, SectNameCommon, SectNameCoff, Prefix) Prefix,
119};
120
121} // namespace
122
123namespace llvm {
124
127 bool AddSegmentInfo) {
128 std::string SectName;
129
130 if (OF == Triple::MachO && AddSegmentInfo)
131 SectName = CodeGenDataSectNamePrefix[CGSK];
132
133 if (OF == Triple::COFF)
134 SectName += CodeGenDataSectNameCoff[CGSK];
135 else
136 SectName += CodeGenDataSectNameCommon[CGSK];
137
138 return SectName;
139}
140
141std::unique_ptr<CodeGenData> CodeGenData::Instance = nullptr;
142std::once_flag CodeGenData::OnceFlag;
143
145 std::call_once(CodeGenData::OnceFlag, []() {
146 Instance = std::unique_ptr<CodeGenData>(new CodeGenData());
147
149 Instance->EmitCGData = true;
150 else if (!CodeGenDataUsePath.empty()) {
151 // Initialize the global CGData if the input file name is given.
152 // We do not error-out when failing to parse the input file.
153 // Instead, just emit an warning message and fall back as if no CGData
154 // were available.
155 auto FS = vfs::getRealFileSystem();
156 auto ReaderOrErr = CodeGenDataReader::create(CodeGenDataUsePath, *FS);
157 if (Error E = ReaderOrErr.takeError()) {
158 warn(std::move(E), CodeGenDataUsePath);
159 return;
160 }
161 // Publish each CGData based on the data type in the header.
162 auto Reader = ReaderOrErr->get();
163 if (Reader->hasOutlinedHashTree())
164 Instance->publishOutlinedHashTree(Reader->releaseOutlinedHashTree());
165 if (Reader->hasStableFunctionMap())
166 Instance->publishStableFunctionMap(Reader->releaseStableFunctionMap());
167 }
168 });
169 return *Instance;
170}
171
172namespace IndexedCGData {
173
174Expected<Header> Header::readFromBuffer(const unsigned char *Curr) {
175 using namespace support;
176
177 static_assert(std::is_standard_layout_v<llvm::IndexedCGData::Header>,
178 "The header should be standard layout type since we use offset "
179 "of fields to read.");
180 Header H;
181 H.Magic = endian::readNext<uint64_t, endianness::little, unaligned>(Curr);
182 if (H.Magic != IndexedCGData::Magic)
183 return make_error<CGDataError>(cgdata_error::bad_magic);
184 H.Version = endian::readNext<uint32_t, endianness::little, unaligned>(Curr);
186 return make_error<CGDataError>(cgdata_error::unsupported_version);
187 H.DataKind = endian::readNext<uint32_t, endianness::little, unaligned>(Curr);
188
190 "Please update the offset computation below if a new field has "
191 "been added to the header.");
192 H.OutlinedHashTreeOffset =
193 endian::readNext<uint64_t, endianness::little, unaligned>(Curr);
194 if (H.Version >= 2)
195 H.StableFunctionMapOffset =
196 endian::readNext<uint64_t, endianness::little, unaligned>(Curr);
197
198 return H;
199}
200
201} // end namespace IndexedCGData
202
203namespace cgdata {
204
205void warn(Twine Message, StringRef Whence, StringRef Hint) {
207 if (!Whence.empty())
208 errs() << Whence << ": ";
209 errs() << Message << "\n";
210 if (!Hint.empty())
211 WithColor::note() << Hint << "\n";
212}
213
214void warn(Error E, StringRef Whence) {
215 if (E.isA<CGDataError>()) {
216 handleAllErrors(std::move(E), [&](const CGDataError &IPE) {
217 warn(IPE.message(), Whence, "");
218 });
219 }
220}
221
222void saveModuleForTwoRounds(const Module &TheModule, unsigned Task,
223 AddStreamFn AddStream) {
224 LLVM_DEBUG(dbgs() << "Saving module: " << TheModule.getModuleIdentifier()
225 << " in Task " << Task << "\n");
227 AddStream(Task, TheModule.getModuleIdentifier());
228 if (Error Err = StreamOrErr.takeError())
229 report_fatal_error(std::move(Err));
230 std::unique_ptr<CachedFileStream> &Stream = *StreamOrErr;
231
232 WriteBitcodeToFile(TheModule, *Stream->OS,
233 /*ShouldPreserveUseListOrder=*/true);
234
235 if (Error Err = Stream->commit())
236 report_fatal_error(std::move(Err));
237}
238
239std::unique_ptr<Module> loadModuleForTwoRounds(BitcodeModule &OrigModule,
240 unsigned Task,
241 LLVMContext &Context,
242 ArrayRef<StringRef> IRFiles) {
243 LLVM_DEBUG(dbgs() << "Loading module: " << OrigModule.getModuleIdentifier()
244 << " in Task " << Task << "\n");
245 auto FileBuffer = MemoryBuffer::getMemBuffer(
246 IRFiles[Task], "in-memory IR file", /*RequiresNullTerminator=*/false);
247 auto RestoredModule = parseBitcodeFile(*FileBuffer, Context);
248 if (!RestoredModule)
250 Twine("Failed to parse optimized bitcode loaded for Task: ") +
251 Twine(Task) + "\n");
252
253 // Restore the original module identifier.
254 (*RestoredModule)->setModuleIdentifier(OrigModule.getModuleIdentifier());
255 return std::move(*RestoredModule);
256}
257
259 OutlinedHashTreeRecord GlobalOutlineRecord;
260 StableFunctionMapRecord GlobalStableFunctionMapRecord;
261 stable_hash CombinedHash = 0;
262 for (auto File : ObjFiles) {
263 if (File.empty())
264 continue;
265 std::unique_ptr<MemoryBuffer> Buffer = MemoryBuffer::getMemBuffer(
266 File, "in-memory object file", /*RequiresNullTerminator=*/false);
268 object::ObjectFile::createObjectFile(Buffer->getMemBufferRef());
269 if (!BinOrErr)
270 return BinOrErr.takeError();
271
272 std::unique_ptr<object::ObjectFile> &Obj = BinOrErr.get();
274 Obj.get(), GlobalOutlineRecord, GlobalStableFunctionMapRecord,
275 &CombinedHash))
276 return E;
277 }
278
279 GlobalStableFunctionMapRecord.finalize();
280
281 if (!GlobalOutlineRecord.empty())
282 cgdata::publishOutlinedHashTree(std::move(GlobalOutlineRecord.HashTree));
283 if (!GlobalStableFunctionMapRecord.empty())
285 std::move(GlobalStableFunctionMapRecord.FunctionMap));
286
287 return CombinedHash;
288}
289
290} // end namespace cgdata
291
292} // end namespace llvm
aarch64 promote const
static std::string getCGDataErrString(cgdata_error Err, const std::string &ErrMsg="")
Definition: CodeGenData.cpp:40
cl::opt< bool > CodeGenDataThinLTOTwoRounds("codegen-data-thinlto-two-rounds", cl::init(false), cl::Hidden, cl::desc("Enable two-round ThinLTO code generation. The first round " "emits codegen data, while the second round uses the emitted " "codegen data for further optimizations."))
static cl::opt< std::string > CodeGenDataUsePath("codegen-data-use-path", cl::init(""), cl::Hidden, cl::desc("File path to where .cgdata file is read"))
static cl::opt< bool > CodeGenDataGenerate("codegen-data-generate", cl::init(false), cl::Hidden, cl::desc("Emit CodeGen Data into custom sections"))
#define H(x, y, z)
Definition: MD5.cpp:57
static const char * name
Definition: SMEABIPass.cpp:52
raw_pwrite_stream & OS
#define LLVM_DEBUG(...)
Definition: Debug.h:119
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition: ArrayRef.h:41
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.
Definition: CodeGenData.cpp:96
static LLVM_ABI Expected< std::unique_ptr< CodeGenDataReader > > create(const Twine &Path, vfs::FileSystem &FS)
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
bool isA() const
Check whether one error is a subclass of another.
Definition: Error.h:246
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:67
const std::string & getModuleIdentifier() const
Get the module identifier which is, essentially, the name of the module.
Definition: Module.h:252
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:55
constexpr bool empty() const
empty - Check if the string is empty.
Definition: StringRef.h:151
ObjectFormatType
Definition: Triple.h:314
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:85
static LLVM_ABI raw_ostream & note()
Convenience method for printing "note: " to stderr.
Definition: WithColor.cpp:87
static Expected< OwningBinary< ObjectFile > > createObjectFile(StringRef ObjectPath)
Definition: ObjectFile.cpp:211
A raw_ostream that writes to an std::string.
Definition: raw_ostream.h:662
const uint64_t Magic
Definition: CodeGenData.h:277
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)
Definition: CodeGenData.h:191
LLVM_ABI void warn(Error E, StringRef Whence="")
void publishStableFunctionMap(std::unique_ptr< StableFunctionMap > FunctionMap)
Definition: CodeGenData.h:196
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.
initializer< Ty > init(const Ty &Val)
Definition: CommandLine.h:444
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.
Definition: AddressRanges.h:18
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:990
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:60
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:207
LLVM_ABI void report_fatal_error(Error Err, bool gen_crash_diag=true)
Definition: Error.cpp:167
LLVM_ABI const std::error_category & cgdata_category()
Definition: CodeGenData.cpp:91
LLVM_ABI raw_fd_ostream & errs()
This returns a reference to a raw_ostream for standard error.
CGDataSectKind
Definition: CodeGenData.h:33
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