================
@@ -1,265 +1,311 @@
-//===- Dtlto.cpp - Distributed ThinLTO implementation --------------------===//
+//===- DTLTO.cpp - Distributed ThinLTO implementation 
---------------------===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.
 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 //
 
//===----------------------------------------------------------------------===//
-//
 // \file
 // This file implements support functions for Distributed ThinLTO, focusing on
-// preparing input files for distribution.
+// preparing complilation jobs for distribution.
 //
 
//===----------------------------------------------------------------------===//
 
 #include "llvm/DTLTO/DTLTO.h"
 
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/ScopeExit.h"
 #include "llvm/ADT/SmallString.h"
 #include "llvm/ADT/StringExtras.h"
 #include "llvm/ADT/StringRef.h"
-#include "llvm/BinaryFormat/Magic.h"
 #include "llvm/LTO/LTO.h"
-#include "llvm/Object/Archive.h"
 #include "llvm/Support/FileSystem.h"
 #include "llvm/Support/MemoryBufferRef.h"
 #include "llvm/Support/Path.h"
 #include "llvm/Support/Process.h"
-#include "llvm/Support/Signals.h"
 #include "llvm/Support/TimeProfiler.h"
 #include "llvm/Support/raw_ostream.h"
-#ifdef _WIN32
-#include "llvm/Support/Windows/WindowsSupport.h"
-#endif
 
 #include <string>
 
 using namespace llvm;
 
-namespace {
-
-// Saves the content of Buffer to Path overwriting any existing file.
-Error save(StringRef Buffer, StringRef Path) {
-  std::error_code EC;
-  raw_fd_ostream OS(Path.str(), EC, sys::fs::OpenFlags::OF_None);
-  if (EC)
-    return createStringError(inconvertibleErrorCode(),
-                             "Failed to create file %s: %s", Path.data(),
-                             EC.message().c_str());
-  OS.write(Buffer.data(), Buffer.size());
-  if (OS.has_error())
-    return createStringError(inconvertibleErrorCode(),
-                             "Failed writing to file %s", Path.data());
-  return Error::success();
-}
+// Remove temporary files created to enable distribution.
+void lto::DTLTO::cleanup() {
+  if (!SaveTemps) {
+    // Remove one file, report error if any.
+    auto removeFile = [](StringRef FileName) -> void {
+      std::error_code EC = sys::fs::remove(FileName, true);
+      if (EC &&
+          EC != std::make_error_code(std::errc::no_such_file_or_directory))
+        errs() << "warning: could not remove the file '" << FileName
+               << "': " << EC.message() << "\n";
+    };
 
-// Saves the content of Input to Path overwriting any existing file.
-Error save(lto::InputFile *Input, StringRef Path) {
-  MemoryBufferRef MB = Input->getFileBuffer();
-  return save(MB.getBuffer(), Path);
+    TimeTraceScope JobScope("Remove DTLTO temporary files");
+    for (const auto &Name : CleanupList)
+      removeFile(Name);
+  }
+  Base::cleanup();
 }
 
-// Normalize and save a path. Aside from expanding Windows 8.3 short paths,
-// no other normalization is currently required here. These paths are
-// machine-local and break distribution systems; other normalization is
-// handled by the DTLTO distributors.
-Expected<StringRef> normalizePath(StringRef Path, StringSaver &Saver) {
-#if defined(_WIN32)
-  if (Path.empty())
-    return Path;
-  SmallString<256> Expanded;
-  if (std::error_code EC = llvm::sys::windows::makeLongFormPath(Path, 
Expanded))
-    return createStringError(inconvertibleErrorCode(),
-                             "Normalization failed for path %s: %s",
-                             Path.str().c_str(), EC.message().c_str());
-  return Saver.save(Expanded.str());
-#else
-  return Saver.save(Path);
-#endif
-}
+// Runs the DTLTO thin link phase, producing per-module summary indices,
+// import lists, and cache keys for distribution.
+Error lto::DTLTO::performThinLink() {
+  auto ThinIndexBackend = lto::createWriteIndexesThinBackend(
+      hardware_concurrency(), "", "", "", true, nullptr, nullptr);
+  setThinBackend(ThinIndexBackend);
+  setLTOMode(lto::LTO::LTOKind::LTOK_UnifiedThin);
 
-// Compute the file path for a thin archive member.
-//
-// For thin archives, an archive member name is typically a file path relative
-// to the archive file's directory. This function resolves that path.
-SmallString<256> computeThinArchiveMemberPath(StringRef ArchivePath,
-                                              StringRef MemberName) {
-  assert(!ArchivePath.empty() && "An archive file path must be non empty.");
-  SmallString<256> MemberPath;
-  if (sys::path::is_relative(MemberName)) {
-    MemberPath = sys::path::parent_path(ArchivePath);
-    sys::path::append(MemberPath, MemberName);
-  } else
-    MemberPath = MemberName;
-  sys::path::remove_dots(MemberPath, /*remove_dot_dot=*/true);
-  return MemberPath;
+  size_t NumTasks = getMaxTasks();
+  SummaryIndexFiles.resize(NumTasks);
+  ImportsFilesLists.resize(NumTasks);
+  CacheKeysList.resize(NumTasks);
+
+  lto::Config &Cfg = getConfig();
+  Cfg.OnSummaryIndexStoreCb =
+      [&](size_t task) -> std::unique_ptr<raw_svector_ostream> {
+    return std::make_unique<raw_svector_ostream>(SummaryIndexFiles[task]);
+  };
+  Cfg.OnCacheKeyStoreCb = [&](size_t task) -> std::string & {
+    return CacheKeysList[task];
+  };
+  Cfg.OnImportsListStoreCb = [&](size_t task) -> std::vector<std::string> & {
+    return ImportsFilesLists[task];
+  };
+
+  return Base::run(AddStreamFunc, {});
 }
 
-} // namespace
+// Runs the DTLTO pipeline.
+LLVM_ABI Error lto::DTLTO::run(AddStreamFn AddStream, FileCache CacheParam) {
+  scope_exit CleanUp([this]() { cleanup(); });
 
-// Determines if a file at the given path is a thin archive file.
-//
-// This function uses a cache to avoid repeatedly reading the same file.
-// It reads only the header portion (magic bytes) of the file to identify
-// the archive type.
-Expected<bool> lto::DTLTO::isThinArchive(const StringRef ArchivePath) {
-  // Return cached result if available.
-  auto Cached = ArchiveIsThinCache.find(ArchivePath);
-  if (Cached != ArchiveIsThinCache.end())
-    return Cached->second;
-
-  uint64_t FileSize = -1;
-  std::error_code EC = sys::fs::file_size(ArchivePath, FileSize);
-  if (EC)
-    return createStringError(inconvertibleErrorCode(),
-                             "Failed to get file size from archive %s: %s",
-                             ArchivePath.data(), EC.message().c_str());
-  if (FileSize < sizeof(object::ThinArchiveMagic))
-    return createStringError(inconvertibleErrorCode(),
-                             "Archive file size is too small %s",
-                             ArchivePath.data());
-
-  // Read only the first few bytes containing the magic signature.
-  ErrorOr<std::unique_ptr<MemoryBuffer>> MBOrErr = MemoryBuffer::getFileSlice(
-      ArchivePath, sizeof(object::ThinArchiveMagic), 0);
-  if ((EC = MBOrErr.getError()))
-    return createStringError(inconvertibleErrorCode(),
-                             "Failed to read from archive %s: %s",
-                             ArchivePath.data(), EC.message().c_str());
-
-  StringRef Buf = (*MBOrErr)->getBuffer();
-  if (file_magic::archive != identify_magic(Buf))
-    return createStringError(inconvertibleErrorCode(),
-                             "Unknown format for archive %s",
-                             ArchivePath.data());
-
-  bool IsThin = Buf.starts_with(object::ThinArchiveMagic);
-
-  // Cache the result.
-  ArchiveIsThinCache[ArchivePath] = IsThin;
-
-  return IsThin;
+  AddStreamFunc = AddStream;
+  Cache = std::move(CacheParam);
+  Conf.Dtlto = 1;
+  UID = itostr(sys::Process::getProcessId());
+
+  if (Error Err = performThinLink())
+    return Err;
+
+  ThinLTOTaskOffset = RegularLTO.ParallelCodeGenParallelismLevel;
+  DistributorParams.TargetTriple = 
RegularLTO.CombinedModule->getTargetTriple();
+
+  if (Error Err = prepareDtltoJobs())
+    return Err;
+  if (Error Err = handleArchiveInputs())
+    return Err;
+  if (Error Err = performCodegen())
+    return Err;
+  if (Error Err = addObjectFilesToLink())
+    return Err;
+  return Error::success();
 }
 
-// Add an input file and prepare it for distribution.
-//
-// This function performs the following tasks:
-// 1. Add the input file to the LTO object's list of input files.
-// 2. For individual bitcode file inputs on Windows only, overwrite the module
-//    ID with a normalized path to remove short 8.3 form components.
-// 3. For thin archive members, overwrite the module ID with the path
-//    (normalized on Windows) to the member file on disk.
-// 4. For archive members and FatLTO objects, overwrite the module ID with a
-//    unique path (normalized on Windows) naming a file that will contain the
-//    member content. The file is created and populated later (see
-//    serializeInputs()).
-Expected<std::shared_ptr<lto::InputFile>>
-lto::DTLTO::addInput(std::unique_ptr<InputFile> InputPtr) {
-  TimeTraceScope TimeScope("Add input for DTLTO");
-
-  // Add the input file to the LTO object.
-  InputFiles.emplace_back(InputPtr.release());
-  auto &Input = InputFiles.back();
-  BitcodeModule &BM = Input->getPrimaryBitcodeModule();
-
-  auto setIdFromPath = [&](StringRef Path) -> Error {
-    auto N = normalizePath(Path, Saver);
-    if (!N)
-      return N.takeError();
-    BM.setModuleIdentifier(*N);
+// Probes the LTO cache for a compiled native object for the given job.
+Error lto::DTLTO::checkCacheHit(Job &J) {
+  if (!Cache.isValid())
     return Error::success();
-  };
 
-  StringRef ArchivePath = Input->getArchivePath();
-
-  // In most cases, the module ID already points to an individual bitcode file
-  // on disk, so no further preparation for distribution is required. However,
-  // on Windows we overwite the module ID to expand Windows 8.3 short form
-  // paths. These paths are machine-local and break distribution systems; other
-  // normalization is handled by the DTLTO distributors.
-  if (ArchivePath.empty() && !Input->isFatLTOObject()) {
-#if defined(_WIN32)
-    if (Error E = setIdFromPath(Input->getName()))
-      return std::move(E);
-#endif
-    return Input;
+  auto CacheAddStreamExp = Cache(J.Task, J.CacheKey, J.ModuleID);
+  if (Error Err = CacheAddStreamExp.takeError())
+    return Err;
+  AddStreamFn &CacheAddStream = *CacheAddStreamExp;
+  // If CacheAddStream is null, we have a cache hit and at this point
+  // object file is already passed back to the linker.
+  if (!CacheAddStream) {
+    J.Cached = true; // Cache hit, mark the job as cached.
+    CachedJobs.fetch_add(1);
+  } else {
+    // If CacheAddStream is not null, we have a cache miss and we need to
+    // run the backend for codegen. Save cache 'add stream'
+    // function for a later use.
+    J.CacheAddStream = std::move(CacheAddStream);
   }
+  return Error::success();
+}
 
-  // For a member of a thin archive that is not a FatLTO object, there is an
-  // existing file on disk that can be used, so we can avoid having to
-  // serialize.
-  Expected<bool> UseThinMember =
-      Input->isFatLTOObject() ? false : isThinArchive(ArchivePath);
-  if (!UseThinMember)
-    return UseThinMember.takeError();
-  if (*UseThinMember) {
-    // For thin archives, use the path to the actual member file on disk.
-    auto MemberPath =
-        computeThinArchiveMemberPath(ArchivePath, Input->getMemberName());
-    if (Error E = setIdFromPath(MemberPath))
-      return std::move(E);
-    return Input;
-  }
+// Prepares a single DTLTO backend compilation job for a ThinLTO module.
+Error lto::DTLTO::prepareDtltoJob(StringRef ModulePath, unsigned Task) {
+  assert(Task >= ThinLTOTaskOffset && Task - ThinLTOTaskOffset < Jobs.size() &&
+         "Task index out of range for Jobs");
+  assert(Task < SummaryIndexFiles.size() && "Task index out of range");
+
+  SString ObjFilePath =
+      sys::path::parent_path(DistributorParams.LinkerOutputFile);
+  sys::path::append(ObjFilePath, sys::path::stem(ModulePath) + "." +
+                                     itostr(Task) + "." + UID + ".native.o");
+
+  SString SummaryIndexPathStr = ObjFilePath;
+  SummaryIndexPathStr += ".thinlto.bc";
+  SString ImportsPathStr = ModulePath;
+  ImportsPathStr += ".imports";
 
-  // A new file on disk will be needed for archive members and FatLTO objects.
-  Input->setSerializeForDistribution(true);
+  Job &J = Jobs[Task - ThinLTOTaskOffset];
+  J = {Task,
+       ModulePath,
+       Saver.save(ObjFilePath.str()),
+       Saver.save(SummaryIndexPathStr.str()),
+       Saver.save(ImportsPathStr.str()),
+       ImportsFilesLists[Task],
+       CacheKeysList[Task],
+       nullptr,
+       false};
 
-  // Get the normalized output directory, if we haven't already.
-  if (LinkerOutputDir.empty()) {
-    auto N = normalizePath(sys::path::parent_path(LinkerOutputFile), Saver);
-    if (!N)
-      return N.takeError();
-    LinkerOutputDir = *N;
+  if (Error Err = checkCacheHit(J))
+    return Err;
+  if (!J.Cached) {
+    TimeTraceScope JobScope("Emit individual index for DTLTO",
+                            J.SummaryIndexPath);
+    if (Error Err = save(SummaryIndexFiles[Task], J.SummaryIndexPath))
+      return Err;
   }
+  if (OnWriteCb)
----------------
kbelochapka wrote:

Renamed into `OnIndexWriteCb`

https://github.com/llvm/llvm-project/pull/192629
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to