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