[llvm] 66b4095 - llvm-link: Add support for archive files as inputs

Jan Sjodin via llvm-commits llvm-commits at lists.llvm.org
Tue Jul 14 12:31:16 PDT 2020


Author: Jan Sjodin
Date: 2020-07-14T15:30:59-04:00
New Revision: 66b409582a1d349a3ce5480237aeab92dd5ebde1

URL: https://github.com/llvm/llvm-project/commit/66b409582a1d349a3ce5480237aeab92dd5ebde1
DIFF: https://github.com/llvm/llvm-project/commit/66b409582a1d349a3ce5480237aeab92dd5ebde1.diff

LOG: llvm-link: Add support for archive files as inputs

This patch adds support for archive files as inputs to llvm-link. One
of the use-cases is for OpenMP, where device specific libraries need
to be extracted from libraries containing bundled object files. The
clang-offload-bundler will support extracting these archives, which
will be passed into llvm-link, see https://reviews.llvm.org/D80816.

Reviewed By: jdoerfert

Differential Revision: https://reviews.llvm.org/D81109

Added: 
    llvm/test/tools/llvm-link/Inputs/f.ll
    llvm/test/tools/llvm-link/Inputs/g.ll
    llvm/test/tools/llvm-link/Inputs/h.ll
    llvm/test/tools/llvm-link/archive-bad.ll
    llvm/test/tools/llvm-link/archive.ll
    llvm/test/tools/llvm-link/archivell.ll

Modified: 
    llvm/tools/llvm-link/llvm-link.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/test/tools/llvm-link/Inputs/f.ll b/llvm/test/tools/llvm-link/Inputs/f.ll
new file mode 100644
index 000000000000..a7cdacea82fb
--- /dev/null
+++ b/llvm/test/tools/llvm-link/Inputs/f.ll
@@ -0,0 +1,6 @@
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @f() {
+entry:
+  ret void
+}

diff  --git a/llvm/test/tools/llvm-link/Inputs/g.ll b/llvm/test/tools/llvm-link/Inputs/g.ll
new file mode 100644
index 000000000000..b81de922b4da
--- /dev/null
+++ b/llvm/test/tools/llvm-link/Inputs/g.ll
@@ -0,0 +1,6 @@
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @g() {
+entry:
+  ret void
+}

diff  --git a/llvm/test/tools/llvm-link/Inputs/h.ll b/llvm/test/tools/llvm-link/Inputs/h.ll
new file mode 100644
index 000000000000..c2bda1712a40
--- /dev/null
+++ b/llvm/test/tools/llvm-link/Inputs/h.ll
@@ -0,0 +1,6 @@
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @h() {
+entry:
+  ret void
+}

diff  --git a/llvm/test/tools/llvm-link/archive-bad.ll b/llvm/test/tools/llvm-link/archive-bad.ll
new file mode 100644
index 000000000000..80ce6fc1fe0d
--- /dev/null
+++ b/llvm/test/tools/llvm-link/archive-bad.ll
@@ -0,0 +1,7 @@
+# RUN: cp %S/Inputs/f.ll %t.fg.a
+# RUN: not llvm-link %S/Inputs/h.ll %t.fg.a -o %t.linked.bc 2>&1 | FileCheck %s
+
+# RUN: rm -f %t.fg.a
+# RUN: rm -f %t.linked.bc
+
+# CHECK: file too small to be an archive

diff  --git a/llvm/test/tools/llvm-link/archive.ll b/llvm/test/tools/llvm-link/archive.ll
new file mode 100644
index 000000000000..10ab83a3d5be
--- /dev/null
+++ b/llvm/test/tools/llvm-link/archive.ll
@@ -0,0 +1,17 @@
+# RUN: llvm-as %S/Inputs/f.ll -o %t.f.bc
+# RUN: llvm-as %S/Inputs/g.ll -o %t.g.bc
+# RUN: llvm-ar cr %t.fg.a %t.f.bc %t.g.bc
+# RUN: llvm-ar cr %t.empty.a
+# RUN: llvm-link %S/Inputs/h.ll %t.fg.a %t.empty.a -o %t.linked.bc
+
+# RUN: llvm-nm %t.linked.bc | FileCheck %s
+
+# RUN: rm -f %t.f.bc
+# RUN: rm -f %t.g.bc
+# RUN: rm -f %t.fg.a
+# RUN: rm -f %t.empty.a
+# RUN: rm -f %t.linked.bc
+
+# CHECK: -------- T f
+# CHECK: -------- T g
+# CHECK: -------- T h

diff  --git a/llvm/test/tools/llvm-link/archivell.ll b/llvm/test/tools/llvm-link/archivell.ll
new file mode 100644
index 000000000000..7474df14e907
--- /dev/null
+++ b/llvm/test/tools/llvm-link/archivell.ll
@@ -0,0 +1,7 @@
+# RUN: llvm-ar cr %t.fg.a %S/Inputs/f.ll llvm-as %S/Inputs/g.ll
+# RUN: not llvm-link %S/Inputs/h.ll %t.fg.a -o %t.linked.bc 2>&1 | FileCheck %s
+
+# RUN: rm -f %t.fg.a
+# RUN: rm -f %t.linked.bc
+
+# CHECK: error: member of archive is not a bitcode file

diff  --git a/llvm/tools/llvm-link/llvm-link.cpp b/llvm/tools/llvm-link/llvm-link.cpp
index a7cda24bbe0a..7141bd1ca7a1 100644
--- a/llvm/tools/llvm-link/llvm-link.cpp
+++ b/llvm/tools/llvm-link/llvm-link.cpp
@@ -11,6 +11,7 @@
 //
 //===----------------------------------------------------------------------===//
 
+#include "llvm/Object/Archive.h"
 #include "llvm/ADT/STLExtras.h"
 #include "llvm/Bitcode/BitcodeReader.h"
 #include "llvm/Bitcode/BitcodeWriter.h"
@@ -139,6 +140,73 @@ static std::unique_ptr<Module> loadFile(const char *argv0,
   return Result;
 }
 
+static std::unique_ptr<Module> loadArFile(const char *Argv0,
+                                          const std::string &ArchiveName,
+                                          LLVMContext &Context, Linker &L,
+                                          unsigned OrigFlags,
+                                          unsigned ApplicableFlags) {
+  std::unique_ptr<Module> Result(new Module("ArchiveModule", Context));
+  if (Verbose)
+    errs() << "Reading library archive file '" << ArchiveName
+           << "' to memory\n";
+  ErrorOr<std::unique_ptr<MemoryBuffer>> Buf =
+    MemoryBuffer::getFile(ArchiveName, -1, false);
+  ExitOnErr(errorCodeToError(Buf.getError()));
+  Error Err = Error::success();
+  object::Archive Archive(Buf.get()->getMemBufferRef(), Err);
+  ExitOnErr(std::move(Err));
+  for (const object::Archive::Child &C : Archive.children(Err)) {
+    Expected<StringRef> Ename = C.getName();
+    if (Error E = Ename.takeError()) {
+      errs() << Argv0 << ": ";
+      WithColor::error()
+          << " failed to read name of archive member"
+          << ArchiveName << "'\n";
+      return nullptr;
+    };
+    std::string ChildName = Ename.get().str();
+    if (Verbose)
+      errs() << "Parsing member '" << ChildName
+             << "' of archive library to module.\n";
+    SMDiagnostic ParseErr;
+    Expected<MemoryBufferRef> MemBuf = C.getMemoryBufferRef();
+    if (Error E = MemBuf.takeError()) {
+      errs() << Argv0 << ": ";
+      WithColor::error() << " loading memory for member '" << ChildName
+                         << "' of archive library failed'" << ArchiveName
+                         << "'\n";
+      return nullptr;
+    };
+
+    if (!isBitcode(reinterpret_cast<const unsigned char *>
+                   (MemBuf.get().getBufferStart()),
+                   reinterpret_cast<const unsigned char *>
+                   (MemBuf.get().getBufferEnd()))) {
+      errs() << Argv0 << ": ";
+      WithColor::error() << "  member of archive is not a bitcode file: '"
+                         << ChildName << "'\n";
+      return nullptr;
+    }
+
+    std::unique_ptr<Module> M = parseIR(MemBuf.get(), ParseErr, Context);
+
+    if (!M.get()) {
+      errs() << Argv0 << ": ";
+      WithColor::error() << " parsing member '" << ChildName
+                         << "' of archive library failed'" << ArchiveName
+                         << "'\n";
+      return nullptr;
+    }
+    if (Verbose)
+      errs() << "Linking member '" << ChildName << "' of archive library.\n";
+    if (L.linkModules(*Result, std::move(M), ApplicableFlags))
+      return nullptr;
+    ApplicableFlags = OrigFlags;
+  } // end for each child
+  ExitOnErr(std::move(Err));
+  return Result;
+}
+
 namespace {
 
 /// Helper to load on demand a Module from file and cache it for subsequent
@@ -281,7 +349,10 @@ static bool linkFiles(const char *argv0, LLVMContext &Context, Linker &L,
   // Similar to some flags, internalization doesn't apply to the first file.
   bool InternalizeLinkedSymbols = false;
   for (const auto &File : Files) {
-    std::unique_ptr<Module> M = loadFile(argv0, File, Context);
+    std::unique_ptr<Module> M =
+      (llvm::sys::path::extension(File) == ".a")
+          ? loadArFile(argv0, File, Context, L, Flags, ApplicableFlags)
+          : loadFile(argv0, File, Context);
     if (!M.get()) {
       errs() << argv0 << ": ";
       WithColor::error() << " loading file '" << File << "'\n";


        


More information about the llvm-commits mailing list