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