[WebAssembly] Preserve function signatures during LTO
authorSam Clegg <sbc@chromium.org>
Fri, 28 Sep 2018 16:50:14 +0000 (16:50 +0000)
committerSam Clegg <sbc@chromium.org>
Fri, 28 Sep 2018 16:50:14 +0000 (16:50 +0000)
With LTO when and undefined function (with a known signature)
in replaced by a defined bitcode function we were loosing the
signature information (since bitcode functions don't have
signatures).

With this change we preserve the original signature from the
undefined function and verify that the post LTO compiled
function has the correct signature.

This change improves the error handling in the case where
there is a signature mismatch with a function defined in
a bitcode file.

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

llvm-svn: 343340

lld/test/wasm/lto/signature-mismatch.ll [new file with mode: 0644]
lld/wasm/LTO.cpp
lld/wasm/SymbolTable.cpp

diff --git a/lld/test/wasm/lto/signature-mismatch.ll b/lld/test/wasm/lto/signature-mismatch.ll
new file mode 100644 (file)
index 0000000..4b6b3b8
--- /dev/null
@@ -0,0 +1,19 @@
+; RUN: llc -filetype=obj -o %t.o %s
+; RUN: llvm-as %S/Inputs/archive.ll -o %t1.o
+; RUN: not wasm-ld --fatal-warnings %t.o %t1.o -o %t.wasm 2>&1 | FileCheck %s
+
+; Test that functions defined in bitcode correctly report signature
+; mistmaches with existing undefined sybmols in normal objects.
+
+target triple = "wasm32-unknown-unknown"
+
+; f is defined to take no argument in archive.ll which is compiled to bitcode
+declare void @f(i32);
+
+define void @_start() {
+  call void @f(i32 0)
+  ret void
+}
+
+; CHECK: >>> defined as (I32) -> void in {{.*}}signature-mismatch.ll.tmp1.o
+; CHECK: >>> defined as () -> void in lto.tmp
index f15551d..933607a 100644 (file)
@@ -72,10 +72,11 @@ BitcodeCompiler::BitcodeCompiler() : LTOObj(createLTO()) {}
 BitcodeCompiler::~BitcodeCompiler() = default;
 
 static void undefine(Symbol *S) {
-  if (isa<DefinedFunction>(S))
-    replaceSymbol<UndefinedFunction>(S, S->getName(), 0);
+  if (auto F = dyn_cast<DefinedFunction>(S))
+    replaceSymbol<UndefinedFunction>(F, F->getName(), 0, F->getFile(),
+                                     F->FunctionType);
   else if (isa<DefinedData>(S))
-    replaceSymbol<UndefinedData>(S, S->getName(), 0);
+    replaceSymbol<UndefinedData>(S, S->getName(), 0, S->getFile());
   else
     llvm_unreachable("unexpected symbol kind");
 }
index 2a4249e..d1e9c05 100644 (file)
@@ -201,7 +201,9 @@ static bool shouldReplace(const Symbol *Existing, InputFile *NewFile,
 Symbol *SymbolTable::addDefinedFunction(StringRef Name, uint32_t Flags,
                                         InputFile *File,
                                         InputFunction *Function) {
-  LLVM_DEBUG(dbgs() << "addDefinedFunction: " << Name << "\n");
+  LLVM_DEBUG(dbgs() << "addDefinedFunction: " << Name << " ["
+                    << (Function ? toString(Function->Signature) : "none")
+                    << "]\n");
   Symbol *S;
   bool WasInserted;
   std::tie(S, WasInserted) = insert(Name, File);
@@ -214,8 +216,16 @@ Symbol *SymbolTable::addDefinedFunction(StringRef Name, uint32_t Flags,
   if (Function)
     checkFunctionType(S, File, &Function->Signature);
 
-  if (shouldReplace(S, File, Flags))
-    replaceSymbol<DefinedFunction>(S, Name, Flags, File, Function);
+  if (shouldReplace(S, File, Flags)) {
+    // If the new defined function doesn't have signture (i.e. bitcode
+    // functions) but the old symbols does then preserve the old signature
+    const WasmSignature *OldSig = nullptr;
+    if (auto* F = dyn_cast<FunctionSymbol>(S))
+      OldSig = F->FunctionType;
+    auto NewSym = replaceSymbol<DefinedFunction>(S, Name, Flags, File, Function);
+    if (!NewSym->FunctionType)
+      NewSym->FunctionType = OldSig;
+  }
   return S;
 }
 
@@ -263,7 +273,8 @@ Symbol *SymbolTable::addDefinedGlobal(StringRef Name, uint32_t Flags,
 Symbol *SymbolTable::addUndefinedFunction(StringRef Name, uint32_t Flags,
                                           InputFile *File,
                                           const WasmSignature *Sig) {
-  LLVM_DEBUG(dbgs() << "addUndefinedFunction: " << Name << "\n");
+  LLVM_DEBUG(dbgs() << "addUndefinedFunction: " << Name <<
+             " [" << (Sig ? toString(*Sig) : "none") << "]\n");
 
   Symbol *S;
   bool WasInserted;