[lld] [ELF] Parallelize input file loading (PR #191690)

Fangrui Song via llvm-commits llvm-commits at lists.llvm.org
Fri Apr 17 23:27:40 PDT 2026


================
@@ -2160,8 +2111,103 @@ static bool isFormatBinary(Ctx &ctx, StringRef s) {
   return false;
 }
 
+// Expand LoadJob entries recorded by addFile(). Called in batch from
+// createFiles() (parallel), or immediately from addFile() for late additions
+// like dependent libraries (single job, runs inline).
+void LinkerDriver::loadFiles() {
+  // BitcodeFile / fatLTO constructors call ctx.saver which is not thread-safe.
+  // SharedFile and ObjFile constructors are safe without the mutex.
+  std::mutex mu;
+  auto makeFile = [&](MemoryBufferRef mb, file_magic magic, StringRef arPath,
+                      uint64_t offset,
+                      bool lazy) -> std::unique_ptr<InputFile> {
+    if (magic == file_magic::bitcode) {
+      std::lock_guard<std::mutex> lk(mu);
+      return std::make_unique<BitcodeFile>(ctx, mb, arPath, offset, lazy);
+    }
+    if (ctx.arg.fatLTOObjects) {
+      Expected<MemoryBufferRef> fatLTOData =
+          IRObjectFile::findBitcodeInMemBuffer(mb);
+      if (!errorToBool(fatLTOData.takeError())) {
+        std::lock_guard<std::mutex> lk(mu);
+        auto f = std::make_unique<BitcodeFile>(ctx, *fatLTOData, arPath, offset,
+                                               lazy);
+        f->obj->fatLTOObject(true);
+        return f;
+      }
+    }
+    return createObjFile(ctx, mb, arPath, lazy);
+  };
+
+  {
+    llvm::TimeTraceScope timeScope("Parallel load");
+    parallelFor(0, loadJobs.size(), [&](size_t i) {
+      LoadJob &job = loadJobs[i];
+      switch (job.kind) {
+      case LoadJob::Obj:
+      case LoadJob::Bitcode:
+        job.out.push_back(makeFile(job.mbref,
+                                   job.kind == LoadJob::Bitcode
+                                       ? file_magic::bitcode
+                                       : file_magic::elf_relocatable,
+                                   "", 0, job.lazy));
+        break;
+      case LoadJob::Archive: {
+        // Scan all archive members rather than using the archive symbol
----------------
MaskRay wrote:

I did prototype `parallelFor` over members inside each archive. On thin archive workloads, the per-archive barrier /synchronization overhead outweighs the load-balancing gain. 

For thick archives I think there is probably a minor opportunity.

https://github.com/llvm/llvm-project/pull/191690


More information about the llvm-commits mailing list