[lld] 9cd9858 - [lld][WebAssembly] Add libcall symbols to the link when LTO is being used.

Sam Clegg via llvm-commits llvm-commits at lists.llvm.org
Fri Jan 10 11:03:25 PST 2020


Author: Sam Clegg
Date: 2020-01-10T11:01:05-08:00
New Revision: 9cd985815abf88bd77bb67f7b9cc80f2032cbbc7

URL: https://github.com/llvm/llvm-project/commit/9cd985815abf88bd77bb67f7b9cc80f2032cbbc7
DIFF: https://github.com/llvm/llvm-project/commit/9cd985815abf88bd77bb67f7b9cc80f2032cbbc7.diff

LOG: [lld][WebAssembly] Add libcall symbols to the link when LTO is being used.

This code is copied almost verbatim from the equivalent change to the
ELF linker:

- https://reviews.llvm.org/D50017
- https://reviews.llvm.org/D50475

The upshot is that libraries containing libcall (such as compiler-rt
and libc) can be compiled with LTO.

Fixes PR41384

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

Added: 
    lld/test/wasm/lto/Inputs/libcall-archive.ll
    lld/test/wasm/lto/libcall-archive.ll

Modified: 
    lld/wasm/Driver.cpp
    lld/wasm/InputFiles.h
    lld/wasm/Symbols.cpp
    lld/wasm/Symbols.h

Removed: 
    


################################################################################
diff  --git a/lld/test/wasm/lto/Inputs/libcall-archive.ll b/lld/test/wasm/lto/Inputs/libcall-archive.ll
new file mode 100644
index 000000000000..126075521b83
--- /dev/null
+++ b/lld/test/wasm/lto/Inputs/libcall-archive.ll
@@ -0,0 +1,6 @@
+target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
+target triple = "wasm32-unknown-unknown"
+
+define void @memcpy() {
+  ret void
+}

diff  --git a/lld/test/wasm/lto/libcall-archive.ll b/lld/test/wasm/lto/libcall-archive.ll
new file mode 100644
index 000000000000..b939d51744e4
--- /dev/null
+++ b/lld/test/wasm/lto/libcall-archive.ll
@@ -0,0 +1,25 @@
+; RUN: rm -f %t.a
+; RUN: llvm-as -o %t.o %s
+; RUN: llvm-as -o %t2.o %S/Inputs/libcall-archive.ll
+; RUN: llvm-ar rcs %t.a %t2.o
+; RUN: wasm-ld -o %t %t.o %t.a
+; RUN: obj2yaml %t | FileCheck %s
+
+target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
+target triple = "wasm32-unknown-unknown"
+
+define void @_start(i8* %a, i8* %b) {
+entry:
+  call void @llvm.memcpy.p0i8.p0i8.i64(i8* %a, i8* %b, i64 1024, i1 false)
+  ret void
+}
+
+declare void @llvm.memcpy.p0i8.p0i8.i64(i8* nocapture, i8* nocapture, i64, i1)
+
+; CHECK:       - Type:            CUSTOM
+; CHECK-NEXT:    Name:            name
+; CHECK-NEXT:    FunctionNames:
+; CHECK-NEXT:      - Index:           0
+; CHECK-NEXT:        Name:            _start
+; CHECK-NEXT:      - Index:           1
+; CHECK-NEXT:        Name:            memcpy

diff  --git a/lld/wasm/Driver.cpp b/lld/wasm/Driver.cpp
index 6628ecd7904f..90c26f8c8367 100644
--- a/lld/wasm/Driver.cpp
+++ b/lld/wasm/Driver.cpp
@@ -437,6 +437,18 @@ static Symbol *handleUndefined(StringRef name) {
   return sym;
 }
 
+static void handleLibcall(StringRef name) {
+  Symbol *sym = symtab->find(name);
+  if (!sym)
+    return;
+
+  if (auto *lazySym = dyn_cast<LazySymbol>(sym)) {
+    MemoryBufferRef mb = lazySym->getMemberBuffer();
+    if (isBitcode(mb))
+      lazySym->fetch();
+  }
+}
+
 static UndefinedGlobal *
 createUndefinedGlobal(StringRef name, llvm::wasm::WasmGlobalType *type) {
   auto *sym = cast<UndefinedGlobal>(symtab->addUndefinedGlobal(
@@ -742,6 +754,21 @@ void LinkerDriver::link(ArrayRef<const char *> argsArr) {
   // Create wrapped symbols for -wrap option.
   std::vector<WrappedSymbol> wrapped = addWrappedSymbols(args);
 
+  // If any of our inputs are bitcode files, the LTO code generator may create
+  // references to certain library functions that might not be explicit in the
+  // bitcode file's symbol table. If any of those library functions are defined
+  // in a bitcode file in an archive member, we need to arrange to use LTO to
+  // compile those archive members by adding them to the link beforehand.
+  //
+  // We only need to add libcall symbols to the link before LTO if the symbol's
+  // definition is in bitcode. Any other required libcall symbols will be added
+  // to the link after LTO when we add the LTO object file to the link.
+  if (!symtab->bitcodeFiles.empty())
+    for (auto *s : lto::LTO::getRuntimeLibcallSymbols())
+      handleLibcall(s);
+  if (errorCount())
+    return;
+
   // Do link-time optimization if given files are LLVM bitcode files.
   // This compiles bitcode files into real object files.
   symtab->addCombinedLTOObject();

diff  --git a/lld/wasm/InputFiles.h b/lld/wasm/InputFiles.h
index 4a445a718352..077c14d6aaaa 100644
--- a/lld/wasm/InputFiles.h
+++ b/lld/wasm/InputFiles.h
@@ -162,6 +162,10 @@ class BitcodeFile : public InputFile {
   std::unique_ptr<llvm::lto::InputFile> obj;
 };
 
+inline bool isBitcode(MemoryBufferRef mb) {
+  return identify_magic(mb.getBuffer()) == llvm::file_magic::bitcode;
+}
+
 // Will report a fatal() error if the input buffer is not a valid bitcode
 // or wasm object file.
 InputFile *createObjectFile(MemoryBufferRef mb, StringRef archiveName = "");

diff  --git a/lld/wasm/Symbols.cpp b/lld/wasm/Symbols.cpp
index ae3736021c6b..e43ecc6ecbd2 100644
--- a/lld/wasm/Symbols.cpp
+++ b/lld/wasm/Symbols.cpp
@@ -20,6 +20,7 @@
 #define DEBUG_TYPE "lld"
 
 using namespace llvm;
+using namespace llvm::object;
 using namespace llvm::wasm;
 
 namespace lld {
@@ -334,6 +335,16 @@ const OutputSectionSymbol *SectionSymbol::getOutputSectionSymbol() const {
 
 void LazySymbol::fetch() { cast<ArchiveFile>(file)->addMember(&archiveSymbol); }
 
+MemoryBufferRef LazySymbol::getMemberBuffer() {
+  Archive::Child c =
+      CHECK(archiveSymbol.getMember(),
+            "could not get the member for symbol " + toString(*this));
+
+  return CHECK(c.getMemoryBufferRef(),
+               "could not get the buffer for the member defining symbol " +
+                   toString(*this));
+}
+
 void printTraceSymbolUndefined(StringRef name, const InputFile* file) {
   message(toString(file) + ": reference to " + name);
 }

diff  --git a/lld/wasm/Symbols.h b/lld/wasm/Symbols.h
index e621dbc8f273..ec3c72dd988e 100644
--- a/lld/wasm/Symbols.h
+++ b/lld/wasm/Symbols.h
@@ -410,6 +410,7 @@ class LazySymbol : public Symbol {
 
   static bool classof(const Symbol *s) { return s->kind() == LazyKind; }
   void fetch();
+  MemoryBufferRef getMemberBuffer();
 
   // Lazy symbols can have a signature because they can replace an
   // UndefinedFunction which which case we need to be able to preserve the


        


More information about the llvm-commits mailing list