xref: /llvm-project/llvm/lib/CGData/CodeGenData.cpp (revision ffcf3c8688f57acaf6a404a1238673c9d197ba9a)
19bb55568SKyungwoo Lee //===-- CodeGenData.cpp ---------------------------------------------------===//
29bb55568SKyungwoo Lee //
39bb55568SKyungwoo Lee // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
49bb55568SKyungwoo Lee // See https://llvm.org/LICENSE.txt for license information.
59bb55568SKyungwoo Lee // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
69bb55568SKyungwoo Lee //
79bb55568SKyungwoo Lee //===----------------------------------------------------------------------===//
89bb55568SKyungwoo Lee //
99bb55568SKyungwoo Lee // This file contains support for codegen data that has stable summary which
109bb55568SKyungwoo Lee // can be used to optimize the code in the subsequent codegen.
119bb55568SKyungwoo Lee //
129bb55568SKyungwoo Lee //===----------------------------------------------------------------------===//
139bb55568SKyungwoo Lee 
149bb55568SKyungwoo Lee #include "llvm/Bitcode/BitcodeWriter.h"
159bb55568SKyungwoo Lee #include "llvm/CGData/CodeGenDataReader.h"
169bb55568SKyungwoo Lee #include "llvm/CGData/OutlinedHashTreeRecord.h"
17*ffcf3c86SKyungwoo Lee #include "llvm/CGData/StableFunctionMapRecord.h"
189bb55568SKyungwoo Lee #include "llvm/Object/ObjectFile.h"
19dc85d526SKyungwoo Lee #include "llvm/Support/Caching.h"
209bb55568SKyungwoo Lee #include "llvm/Support/CommandLine.h"
219bb55568SKyungwoo Lee #include "llvm/Support/FileSystem.h"
22dc85d526SKyungwoo Lee #include "llvm/Support/Path.h"
239bb55568SKyungwoo Lee #include "llvm/Support/WithColor.h"
249bb55568SKyungwoo Lee 
259bb55568SKyungwoo Lee #define DEBUG_TYPE "cg-data"
269bb55568SKyungwoo Lee 
279bb55568SKyungwoo Lee using namespace llvm;
289bb55568SKyungwoo Lee using namespace cgdata;
299bb55568SKyungwoo Lee 
300f525452SKyungwoo Lee cl::opt<bool>
310f525452SKyungwoo Lee     CodeGenDataGenerate("codegen-data-generate", cl::init(false), cl::Hidden,
320f525452SKyungwoo Lee                         cl::desc("Emit CodeGen Data into custom sections"));
330f525452SKyungwoo Lee cl::opt<std::string>
340f525452SKyungwoo Lee     CodeGenDataUsePath("codegen-data-use-path", cl::init(""), cl::Hidden,
350f525452SKyungwoo Lee                        cl::desc("File path to where .cgdata file is read"));
36dc85d526SKyungwoo Lee cl::opt<bool> CodeGenDataThinLTOTwoRounds(
37dc85d526SKyungwoo Lee     "codegen-data-thinlto-two-rounds", cl::init(false), cl::Hidden,
38dc85d526SKyungwoo Lee     cl::desc("Enable two-round ThinLTO code generation. The first round "
39dc85d526SKyungwoo Lee              "emits codegen data, while the second round uses the emitted "
40dc85d526SKyungwoo Lee              "codegen data for further optimizations."));
410f525452SKyungwoo Lee 
429bb55568SKyungwoo Lee static std::string getCGDataErrString(cgdata_error Err,
439bb55568SKyungwoo Lee                                       const std::string &ErrMsg = "") {
449bb55568SKyungwoo Lee   std::string Msg;
459bb55568SKyungwoo Lee   raw_string_ostream OS(Msg);
469bb55568SKyungwoo Lee 
479bb55568SKyungwoo Lee   switch (Err) {
489bb55568SKyungwoo Lee   case cgdata_error::success:
499bb55568SKyungwoo Lee     OS << "success";
509bb55568SKyungwoo Lee     break;
519bb55568SKyungwoo Lee   case cgdata_error::eof:
529bb55568SKyungwoo Lee     OS << "end of File";
539bb55568SKyungwoo Lee     break;
549bb55568SKyungwoo Lee   case cgdata_error::bad_magic:
559bb55568SKyungwoo Lee     OS << "invalid codegen data (bad magic)";
569bb55568SKyungwoo Lee     break;
579bb55568SKyungwoo Lee   case cgdata_error::bad_header:
589bb55568SKyungwoo Lee     OS << "invalid codegen data (file header is corrupt)";
599bb55568SKyungwoo Lee     break;
609bb55568SKyungwoo Lee   case cgdata_error::empty_cgdata:
619bb55568SKyungwoo Lee     OS << "empty codegen data";
629bb55568SKyungwoo Lee     break;
639bb55568SKyungwoo Lee   case cgdata_error::malformed:
649bb55568SKyungwoo Lee     OS << "malformed codegen data";
659bb55568SKyungwoo Lee     break;
669bb55568SKyungwoo Lee   case cgdata_error::unsupported_version:
679bb55568SKyungwoo Lee     OS << "unsupported codegen data version";
689bb55568SKyungwoo Lee     break;
699bb55568SKyungwoo Lee   }
709bb55568SKyungwoo Lee 
719bb55568SKyungwoo Lee   // If optional error message is not empty, append it to the message.
729bb55568SKyungwoo Lee   if (!ErrMsg.empty())
739bb55568SKyungwoo Lee     OS << ": " << ErrMsg;
749bb55568SKyungwoo Lee 
759bb55568SKyungwoo Lee   return OS.str();
769bb55568SKyungwoo Lee }
779bb55568SKyungwoo Lee 
789bb55568SKyungwoo Lee namespace {
799bb55568SKyungwoo Lee 
809bb55568SKyungwoo Lee // FIXME: This class is only here to support the transition to llvm::Error. It
819bb55568SKyungwoo Lee // will be removed once this transition is complete. Clients should prefer to
829bb55568SKyungwoo Lee // deal with the Error value directly, rather than converting to error_code.
839bb55568SKyungwoo Lee class CGDataErrorCategoryType : public std::error_category {
849bb55568SKyungwoo Lee   const char *name() const noexcept override { return "llvm.cgdata"; }
859bb55568SKyungwoo Lee 
869bb55568SKyungwoo Lee   std::string message(int IE) const override {
879bb55568SKyungwoo Lee     return getCGDataErrString(static_cast<cgdata_error>(IE));
889bb55568SKyungwoo Lee   }
899bb55568SKyungwoo Lee };
909bb55568SKyungwoo Lee 
919bb55568SKyungwoo Lee } // end anonymous namespace
929bb55568SKyungwoo Lee 
939bb55568SKyungwoo Lee const std::error_category &llvm::cgdata_category() {
949bb55568SKyungwoo Lee   static CGDataErrorCategoryType ErrorCategory;
959bb55568SKyungwoo Lee   return ErrorCategory;
969bb55568SKyungwoo Lee }
979bb55568SKyungwoo Lee 
989bb55568SKyungwoo Lee std::string CGDataError::message() const {
999bb55568SKyungwoo Lee   return getCGDataErrString(Err, Msg);
1009bb55568SKyungwoo Lee }
1019bb55568SKyungwoo Lee 
1029bb55568SKyungwoo Lee char CGDataError::ID = 0;
1039bb55568SKyungwoo Lee 
1049bb55568SKyungwoo Lee namespace {
1059bb55568SKyungwoo Lee 
1069bb55568SKyungwoo Lee const char *CodeGenDataSectNameCommon[] = {
1079bb55568SKyungwoo Lee #define CG_DATA_SECT_ENTRY(Kind, SectNameCommon, SectNameCoff, Prefix)         \
1089bb55568SKyungwoo Lee   SectNameCommon,
1099bb55568SKyungwoo Lee #include "llvm/CGData/CodeGenData.inc"
1109bb55568SKyungwoo Lee };
1119bb55568SKyungwoo Lee 
1129bb55568SKyungwoo Lee const char *CodeGenDataSectNameCoff[] = {
1139bb55568SKyungwoo Lee #define CG_DATA_SECT_ENTRY(Kind, SectNameCommon, SectNameCoff, Prefix)         \
1149bb55568SKyungwoo Lee   SectNameCoff,
1159bb55568SKyungwoo Lee #include "llvm/CGData/CodeGenData.inc"
1169bb55568SKyungwoo Lee };
1179bb55568SKyungwoo Lee 
1189bb55568SKyungwoo Lee const char *CodeGenDataSectNamePrefix[] = {
1199bb55568SKyungwoo Lee #define CG_DATA_SECT_ENTRY(Kind, SectNameCommon, SectNameCoff, Prefix) Prefix,
1209bb55568SKyungwoo Lee #include "llvm/CGData/CodeGenData.inc"
1219bb55568SKyungwoo Lee };
1229bb55568SKyungwoo Lee 
1239bb55568SKyungwoo Lee } // namespace
1249bb55568SKyungwoo Lee 
1259bb55568SKyungwoo Lee namespace llvm {
1269bb55568SKyungwoo Lee 
1279bb55568SKyungwoo Lee std::string getCodeGenDataSectionName(CGDataSectKind CGSK,
1289bb55568SKyungwoo Lee                                       Triple::ObjectFormatType OF,
1299bb55568SKyungwoo Lee                                       bool AddSegmentInfo) {
1309bb55568SKyungwoo Lee   std::string SectName;
1319bb55568SKyungwoo Lee 
1329bb55568SKyungwoo Lee   if (OF == Triple::MachO && AddSegmentInfo)
1339bb55568SKyungwoo Lee     SectName = CodeGenDataSectNamePrefix[CGSK];
1349bb55568SKyungwoo Lee 
1359bb55568SKyungwoo Lee   if (OF == Triple::COFF)
1369bb55568SKyungwoo Lee     SectName += CodeGenDataSectNameCoff[CGSK];
1379bb55568SKyungwoo Lee   else
1389bb55568SKyungwoo Lee     SectName += CodeGenDataSectNameCommon[CGSK];
1399bb55568SKyungwoo Lee 
1409bb55568SKyungwoo Lee   return SectName;
1419bb55568SKyungwoo Lee }
1429bb55568SKyungwoo Lee 
1439bb55568SKyungwoo Lee std::unique_ptr<CodeGenData> CodeGenData::Instance = nullptr;
1449bb55568SKyungwoo Lee std::once_flag CodeGenData::OnceFlag;
1459bb55568SKyungwoo Lee 
1469bb55568SKyungwoo Lee CodeGenData &CodeGenData::getInstance() {
1479bb55568SKyungwoo Lee   std::call_once(CodeGenData::OnceFlag, []() {
1489bb55568SKyungwoo Lee     Instance = std::unique_ptr<CodeGenData>(new CodeGenData());
1499bb55568SKyungwoo Lee 
150dc85d526SKyungwoo Lee     if (CodeGenDataGenerate || CodeGenDataThinLTOTwoRounds)
1510f525452SKyungwoo Lee       Instance->EmitCGData = true;
1520f525452SKyungwoo Lee     else if (!CodeGenDataUsePath.empty()) {
1530f525452SKyungwoo Lee       // Initialize the global CGData if the input file name is given.
1540f525452SKyungwoo Lee       // We do not error-out when failing to parse the input file.
1550f525452SKyungwoo Lee       // Instead, just emit an warning message and fall back as if no CGData
1560f525452SKyungwoo Lee       // were available.
1570f525452SKyungwoo Lee       auto FS = vfs::getRealFileSystem();
1580f525452SKyungwoo Lee       auto ReaderOrErr = CodeGenDataReader::create(CodeGenDataUsePath, *FS);
1590f525452SKyungwoo Lee       if (Error E = ReaderOrErr.takeError()) {
1600f525452SKyungwoo Lee         warn(std::move(E), CodeGenDataUsePath);
1610f525452SKyungwoo Lee         return;
1620f525452SKyungwoo Lee       }
1630f525452SKyungwoo Lee       // Publish each CGData based on the data type in the header.
1640f525452SKyungwoo Lee       auto Reader = ReaderOrErr->get();
1650f525452SKyungwoo Lee       if (Reader->hasOutlinedHashTree())
1660f525452SKyungwoo Lee         Instance->publishOutlinedHashTree(Reader->releaseOutlinedHashTree());
167*ffcf3c86SKyungwoo Lee       if (Reader->hasStableFunctionMap())
168*ffcf3c86SKyungwoo Lee         Instance->publishStableFunctionMap(Reader->releaseStableFunctionMap());
1690f525452SKyungwoo Lee     }
1709bb55568SKyungwoo Lee   });
171141574baSKazu Hirata   return *Instance;
1729bb55568SKyungwoo Lee }
1739bb55568SKyungwoo Lee 
1749bb55568SKyungwoo Lee namespace IndexedCGData {
1759bb55568SKyungwoo Lee 
1769bb55568SKyungwoo Lee Expected<Header> Header::readFromBuffer(const unsigned char *Curr) {
1779bb55568SKyungwoo Lee   using namespace support;
1789bb55568SKyungwoo Lee 
1799bb55568SKyungwoo Lee   static_assert(std::is_standard_layout_v<llvm::IndexedCGData::Header>,
1809bb55568SKyungwoo Lee                 "The header should be standard layout type since we use offset "
1819bb55568SKyungwoo Lee                 "of fields to read.");
1829bb55568SKyungwoo Lee   Header H;
1839bb55568SKyungwoo Lee   H.Magic = endian::readNext<uint64_t, endianness::little, unaligned>(Curr);
1849bb55568SKyungwoo Lee   if (H.Magic != IndexedCGData::Magic)
1859bb55568SKyungwoo Lee     return make_error<CGDataError>(cgdata_error::bad_magic);
1869bb55568SKyungwoo Lee   H.Version = endian::readNext<uint32_t, endianness::little, unaligned>(Curr);
1879bb55568SKyungwoo Lee   if (H.Version > IndexedCGData::CGDataVersion::CurrentVersion)
1889bb55568SKyungwoo Lee     return make_error<CGDataError>(cgdata_error::unsupported_version);
1899bb55568SKyungwoo Lee   H.DataKind = endian::readNext<uint32_t, endianness::little, unaligned>(Curr);
1909bb55568SKyungwoo Lee 
191*ffcf3c86SKyungwoo Lee   static_assert(IndexedCGData::CGDataVersion::CurrentVersion == Version2,
192*ffcf3c86SKyungwoo Lee                 "Please update the offset computation below if a new field has "
193*ffcf3c86SKyungwoo Lee                 "been added to the header.");
1949bb55568SKyungwoo Lee   H.OutlinedHashTreeOffset =
1959bb55568SKyungwoo Lee       endian::readNext<uint64_t, endianness::little, unaligned>(Curr);
196*ffcf3c86SKyungwoo Lee   if (H.Version >= 2)
197*ffcf3c86SKyungwoo Lee     H.StableFunctionMapOffset =
198*ffcf3c86SKyungwoo Lee         endian::readNext<uint64_t, endianness::little, unaligned>(Curr);
1999bb55568SKyungwoo Lee 
2009bb55568SKyungwoo Lee   return H;
2019bb55568SKyungwoo Lee }
2029bb55568SKyungwoo Lee 
2039bb55568SKyungwoo Lee } // end namespace IndexedCGData
2049bb55568SKyungwoo Lee 
2059bb55568SKyungwoo Lee namespace cgdata {
2069bb55568SKyungwoo Lee 
2079bb55568SKyungwoo Lee void warn(Twine Message, std::string Whence, std::string Hint) {
2089bb55568SKyungwoo Lee   WithColor::warning();
2099bb55568SKyungwoo Lee   if (!Whence.empty())
2109bb55568SKyungwoo Lee     errs() << Whence << ": ";
2119bb55568SKyungwoo Lee   errs() << Message << "\n";
2129bb55568SKyungwoo Lee   if (!Hint.empty())
2139bb55568SKyungwoo Lee     WithColor::note() << Hint << "\n";
2149bb55568SKyungwoo Lee }
2159bb55568SKyungwoo Lee 
2169bb55568SKyungwoo Lee void warn(Error E, StringRef Whence) {
2179bb55568SKyungwoo Lee   if (E.isA<CGDataError>()) {
2189bb55568SKyungwoo Lee     handleAllErrors(std::move(E), [&](const CGDataError &IPE) {
2199bb55568SKyungwoo Lee       warn(IPE.message(), Whence.str(), "");
2209bb55568SKyungwoo Lee     });
2219bb55568SKyungwoo Lee   }
2229bb55568SKyungwoo Lee }
2239bb55568SKyungwoo Lee 
224dc85d526SKyungwoo Lee void saveModuleForTwoRounds(const Module &TheModule, unsigned Task,
225dc85d526SKyungwoo Lee                             AddStreamFn AddStream) {
226dc85d526SKyungwoo Lee   LLVM_DEBUG(dbgs() << "Saving module: " << TheModule.getModuleIdentifier()
227dc85d526SKyungwoo Lee                     << " in Task " << Task << "\n");
228dc85d526SKyungwoo Lee   Expected<std::unique_ptr<CachedFileStream>> StreamOrErr =
229dc85d526SKyungwoo Lee       AddStream(Task, TheModule.getModuleIdentifier());
230dc85d526SKyungwoo Lee   if (Error Err = StreamOrErr.takeError())
231dc85d526SKyungwoo Lee     report_fatal_error(std::move(Err));
232dc85d526SKyungwoo Lee   std::unique_ptr<CachedFileStream> &Stream = *StreamOrErr;
233dc85d526SKyungwoo Lee 
234dc85d526SKyungwoo Lee   WriteBitcodeToFile(TheModule, *Stream->OS,
235dc85d526SKyungwoo Lee                      /*ShouldPreserveUseListOrder=*/true);
236dc85d526SKyungwoo Lee }
237dc85d526SKyungwoo Lee 
238dc85d526SKyungwoo Lee std::unique_ptr<Module> loadModuleForTwoRounds(BitcodeModule &OrigModule,
239dc85d526SKyungwoo Lee                                                unsigned Task,
240dc85d526SKyungwoo Lee                                                LLVMContext &Context,
241dc85d526SKyungwoo Lee                                                ArrayRef<StringRef> IRFiles) {
242dc85d526SKyungwoo Lee   LLVM_DEBUG(dbgs() << "Loading module: " << OrigModule.getModuleIdentifier()
243dc85d526SKyungwoo Lee                     << " in Task " << Task << "\n");
244dc85d526SKyungwoo Lee   auto FileBuffer = MemoryBuffer::getMemBuffer(
245dc85d526SKyungwoo Lee       IRFiles[Task], "in-memory IR file", /*RequiresNullTerminator=*/false);
246dc85d526SKyungwoo Lee   auto RestoredModule = parseBitcodeFile(*FileBuffer, Context);
247dc85d526SKyungwoo Lee   if (!RestoredModule)
248dc85d526SKyungwoo Lee     report_fatal_error(
249dc85d526SKyungwoo Lee         Twine("Failed to parse optimized bitcode loaded for Task: ") +
250dc85d526SKyungwoo Lee         Twine(Task) + "\n");
251dc85d526SKyungwoo Lee 
252dc85d526SKyungwoo Lee   // Restore the original module identifier.
253dc85d526SKyungwoo Lee   (*RestoredModule)->setModuleIdentifier(OrigModule.getModuleIdentifier());
254dc85d526SKyungwoo Lee   return std::move(*RestoredModule);
255dc85d526SKyungwoo Lee }
256dc85d526SKyungwoo Lee 
257dc85d526SKyungwoo Lee Expected<stable_hash> mergeCodeGenData(ArrayRef<StringRef> ObjFiles) {
258dc85d526SKyungwoo Lee   OutlinedHashTreeRecord GlobalOutlineRecord;
259*ffcf3c86SKyungwoo Lee   StableFunctionMapRecord GlobalStableFunctionMapRecord;
260dc85d526SKyungwoo Lee   stable_hash CombinedHash = 0;
261dc85d526SKyungwoo Lee   for (auto File : ObjFiles) {
262dc85d526SKyungwoo Lee     if (File.empty())
263dc85d526SKyungwoo Lee       continue;
264dc85d526SKyungwoo Lee     std::unique_ptr<MemoryBuffer> Buffer = MemoryBuffer::getMemBuffer(
265dc85d526SKyungwoo Lee         File, "in-memory object file", /*RequiresNullTerminator=*/false);
266dc85d526SKyungwoo Lee     Expected<std::unique_ptr<object::ObjectFile>> BinOrErr =
267dc85d526SKyungwoo Lee         object::ObjectFile::createObjectFile(Buffer->getMemBufferRef());
268dc85d526SKyungwoo Lee     if (!BinOrErr)
269dc85d526SKyungwoo Lee       return BinOrErr.takeError();
270dc85d526SKyungwoo Lee 
271dc85d526SKyungwoo Lee     std::unique_ptr<object::ObjectFile> &Obj = BinOrErr.get();
272dc85d526SKyungwoo Lee     if (auto E = CodeGenDataReader::mergeFromObjectFile(
273*ffcf3c86SKyungwoo Lee             Obj.get(), GlobalOutlineRecord, GlobalStableFunctionMapRecord,
274*ffcf3c86SKyungwoo Lee             &CombinedHash))
275dc85d526SKyungwoo Lee       return E;
276dc85d526SKyungwoo Lee   }
277dc85d526SKyungwoo Lee 
278*ffcf3c86SKyungwoo Lee   GlobalStableFunctionMapRecord.finalize();
279*ffcf3c86SKyungwoo Lee 
280dc85d526SKyungwoo Lee   if (!GlobalOutlineRecord.empty())
281dc85d526SKyungwoo Lee     cgdata::publishOutlinedHashTree(std::move(GlobalOutlineRecord.HashTree));
282*ffcf3c86SKyungwoo Lee   if (!GlobalStableFunctionMapRecord.empty())
283*ffcf3c86SKyungwoo Lee     cgdata::publishStableFunctionMap(
284*ffcf3c86SKyungwoo Lee         std::move(GlobalStableFunctionMapRecord.FunctionMap));
285dc85d526SKyungwoo Lee 
286dc85d526SKyungwoo Lee   return CombinedHash;
287dc85d526SKyungwoo Lee }
288dc85d526SKyungwoo Lee 
2899bb55568SKyungwoo Lee } // end namespace cgdata
2909bb55568SKyungwoo Lee 
2919bb55568SKyungwoo Lee } // end namespace llvm
292