[lld] r319396 - [WebAssembly] Allow function signature checking at link time

Sam Clegg via llvm-commits llvm-commits at lists.llvm.org
Wed Nov 29 17:40:08 PST 2017


Author: sbc
Date: Wed Nov 29 17:40:08 2017
New Revision: 319396

URL: http://llvm.org/viewvc/llvm-project?rev=319396&view=rev
Log:
[WebAssembly] Allow function signature checking at link time

This change allows checking of function signatures but
does not yes enable it by default.  In this mode, linking
two objects that were compiled with a different signatures
for the same function will produce a link error.

New options for enabling and disabling this feature have been
added: (--check-signatures/--no-check-signatures).

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

Added:
    lld/trunk/test/wasm/signature-mismatch.ll
Modified:
    lld/trunk/wasm/Config.h
    lld/trunk/wasm/Driver.cpp
    lld/trunk/wasm/Options.td
    lld/trunk/wasm/SymbolTable.cpp
    lld/trunk/wasm/SymbolTable.h
    lld/trunk/wasm/Symbols.cpp
    lld/trunk/wasm/Symbols.h
    lld/trunk/wasm/Writer.cpp
    lld/trunk/wasm/WriterUtils.cpp
    lld/trunk/wasm/WriterUtils.h

Added: lld/trunk/test/wasm/signature-mismatch.ll
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/wasm/signature-mismatch.ll?rev=319396&view=auto
==============================================================================
--- lld/trunk/test/wasm/signature-mismatch.ll (added)
+++ lld/trunk/test/wasm/signature-mismatch.ll Wed Nov 29 17:40:08 2017
@@ -0,0 +1,19 @@
+; RUN: llc -filetype=obj %p/Inputs/ret32.ll -o %t.ret32.o
+; RUN: llc -filetype=obj %s -o %t.main.o
+; RUN: not lld -flavor wasm --check-signatures -o %t.wasm %t.main.o %t.ret32.o 2>&1 | FileCheck %s
+
+target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
+target triple = "wasm32-unknown-unknown-wasm"
+
+; Function Attrs: nounwind
+define hidden void @_start() local_unnamed_addr #0 {
+entry:
+  %call = tail call i32 @ret32(i32 1, i64 2, i32 3) #2
+  ret void
+}
+
+declare i32 @ret32(i32, i64, i32) local_unnamed_addr #1
+
+; CHECK: error: function signature mismatch: ret32
+; CHECK-NEXT: >>> defined as (I32, I64, I32) -> I32 in {{.*}}.main.o
+; CHECK-NEXT: >>> defined as (F32) -> I32 in {{.*}}.ret32.o

Modified: lld/trunk/wasm/Config.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/wasm/Config.h?rev=319396&r1=319395&r2=319396&view=diff
==============================================================================
--- lld/trunk/wasm/Config.h (original)
+++ lld/trunk/wasm/Config.h Wed Nov 29 17:40:08 2017
@@ -23,6 +23,7 @@ namespace wasm {
 
 struct Configuration {
   bool AllowUndefined;
+  bool CheckSignatures;
   bool Demangle;
   bool EmitRelocs;
   bool ImportMemory;

Modified: lld/trunk/wasm/Driver.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/wasm/Driver.cpp?rev=319396&r1=319395&r2=319396&view=diff
==============================================================================
--- lld/trunk/wasm/Driver.cpp (original)
+++ lld/trunk/wasm/Driver.cpp Wed Nov 29 17:40:08 2017
@@ -153,9 +153,10 @@ static void addSyntheticGlobal(StringRef
 
 // Inject a new undefined symbol into the link.  This will cause the link to
 // fail unless this symbol can be found.
-static void addSyntheticUndefinedFunction(StringRef Name) {
+static void addSyntheticUndefinedFunction(StringRef Name,
+                                          const WasmSignature *Type) {
   log("injecting undefined func: " + Name);
-  Symtab->addUndefinedFunction(Name);
+  Symtab->addUndefinedFunction(Name, Type);
 }
 
 static void printHelp(const char *Argv0) {
@@ -243,6 +244,8 @@ void LinkerDriver::link(ArrayRef<const c
   }
 
   Config->AllowUndefined = Args.hasArg(OPT_allow_undefined);
+  Config->CheckSignatures =
+      Args.hasFlag(OPT_check_signatures, OPT_no_check_signatures, false);
   Config->EmitRelocs = Args.hasArg(OPT_emit_relocs);
   Config->Entry = Args.getLastArgValue(OPT_entry);
   Config->ImportMemory = Args.hasArg(OPT_import_memory);
@@ -278,7 +281,8 @@ void LinkerDriver::link(ArrayRef<const c
   if (!Config->Relocatable) {
     if (Config->Entry.empty())
       Config->Entry = "_start";
-    addSyntheticUndefinedFunction(Config->Entry);
+    static WasmSignature Signature = { {}, WASM_TYPE_NORESULT };
+    addSyntheticUndefinedFunction(Config->Entry, &Signature);
 
     addSyntheticGlobal("__stack_pointer", 0);
   }

Modified: lld/trunk/wasm/Options.td
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/wasm/Options.td?rev=319396&r1=319395&r2=319396&view=diff
==============================================================================
--- lld/trunk/wasm/Options.td (original)
+++ lld/trunk/wasm/Options.td Wed Nov 29 17:40:08 2017
@@ -29,11 +29,15 @@ def no_threads: F<"no-threads">,
 def no_color_diagnostics: F<"no-color-diagnostics">,
   HelpText<"Do not use colors in diagnostics">;
 
+def no_check_signatures: F<"no-check-signatures">, HelpText<"Don't check function signatures">;
+
 def o: JoinedOrSeparate<["-"], "o">, MetaVarName<"<path>">,
   HelpText<"Path to file to write output">;
 
 def threads: F<"threads">, HelpText<"Run the linker multi-threaded">;
 
+def check_signatures: F<"check-signatures">, HelpText<"Check function signatures">;
+
 def v: Flag<["-"], "v">, HelpText<"Display the version number">;
 
 def version: F<"version">, HelpText<"Display the version number and exit">;

Modified: lld/trunk/wasm/SymbolTable.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/wasm/SymbolTable.cpp?rev=319396&r1=319395&r2=319396&view=diff
==============================================================================
--- lld/trunk/wasm/SymbolTable.cpp (original)
+++ lld/trunk/wasm/SymbolTable.cpp Wed Nov 29 17:40:08 2017
@@ -11,6 +11,7 @@
 
 #include "Config.h"
 #include "Strings.h"
+#include "WriterUtils.h"
 #include "lld/Common/ErrorHandler.h"
 #include "lld/Common/Memory.h"
 
@@ -76,20 +77,59 @@ void SymbolTable::reportDuplicate(Symbol
         toString(NewFile));
 }
 
-static void checkSymbolTypes(Symbol *Existing, InputFile *F,
-                             const WasmSymbol *New) {
-  if (Existing->isLazy())
+// Get the signature for a given function symbol, either by looking
+// it up in function sections (for defined functions), of the imports section
+// (for imported functions).
+static const WasmSignature *getFunctionSig(const ObjFile &Obj,
+                                           const WasmSymbol &Sym) {
+  DEBUG(dbgs() << "getFunctionSig: " << Sym.Name << "\n");
+  const WasmObjectFile *WasmObj = Obj.getWasmObj();
+  uint32_t FunctionType;
+  if (Obj.isImportedFunction(Sym.ElementIndex)) {
+    const WasmImport &Import = WasmObj->imports()[Sym.ImportIndex];
+    FunctionType = Import.SigIndex;
+  } else {
+    uint32_t FuntionIndex = Sym.ElementIndex - Obj.NumFunctionImports();
+    FunctionType = WasmObj->functionTypes()[FuntionIndex];
+  }
+  return &WasmObj->types()[FunctionType];
+}
+
+// Check the type of new symbol matches that of the symbol is replacing.
+// For functions this can also involve verifying that the signatures match.
+static void checkSymbolTypes(const Symbol &Existing, const InputFile &F,
+                             const WasmSymbol &New,
+                             const WasmSignature *NewSig) {
+  if (Existing.isLazy())
+    return;
+
+  bool NewIsFunction = New.Type == WasmSymbol::SymbolType::FUNCTION_EXPORT ||
+                       New.Type == WasmSymbol::SymbolType::FUNCTION_IMPORT;
+
+  // First check the symbol types match (i.e. either both are function
+  // symbols or both are data symbols).
+  if (Existing.isFunction() != NewIsFunction) {
+    error("symbol type mismatch: " + New.Name + "\n>>> defined as " +
+          (Existing.isFunction() ? "Function" : "Global") + " in " +
+          toString(Existing.getFile()) + "\n>>> defined as " +
+          (NewIsFunction ? "Function" : "Global") + " in " + F.getName());
+    return;
+  }
+
+  // For function symbols, optionally check the function signature matches too.
+  if (!NewIsFunction || !Config->CheckSignatures)
     return;
 
-  bool NewIsFunction = New->Type == WasmSymbol::SymbolType::FUNCTION_EXPORT ||
-                       New->Type == WasmSymbol::SymbolType::FUNCTION_IMPORT;
-  if (Existing->isFunction() == NewIsFunction)
+  DEBUG(dbgs() << "checkSymbolTypes: " << New.Name << "\n");
+  assert(NewSig);
+
+  const WasmSignature &OldSig = Existing.getFunctionType();
+  if (*NewSig == OldSig)
     return;
 
-  error("symbol type mismatch: " + New->Name + "\n>>> defined as " +
-        (Existing->isFunction() ? "Function" : "Global") + " in " +
-        toString(Existing->getFile()) + "\n>>> defined as " +
-        (NewIsFunction ? "Function" : "Global") + " in " + F->getName());
+  error("function signature mismatch: " + New.Name + "\n>>> defined as " +
+        toString(OldSig) + " in " + toString(Existing.getFile()) +
+        "\n>>> defined as " + toString(*NewSig) + " in " + F.getName());
 }
 
 Symbol *SymbolTable::addDefinedGlobal(StringRef Name) {
@@ -110,19 +150,27 @@ Symbol *SymbolTable::addDefined(InputFil
   Symbol *S;
   bool WasInserted;
   Symbol::Kind Kind = Symbol::DefinedFunctionKind;
+  const WasmSignature *NewSig = nullptr;
   if (Sym->Type == WasmSymbol::SymbolType::GLOBAL_EXPORT)
     Kind = Symbol::DefinedGlobalKind;
+  else
+    NewSig = getFunctionSig(*cast<ObjFile>(F), *Sym);
 
   std::tie(S, WasInserted) = insert(Sym->Name);
   if (WasInserted) {
-    S->update(Kind, F, Sym, Segment);
+    S->update(Kind, F, Sym, Segment, NewSig);
+  } else if (S->isLazy()) {
+    // The existing symbol is lazy. Replace it without checking types since
+    // lazy symbols don't have any type information.
+    DEBUG(dbgs() << "replacing existing lazy symbol: " << Sym->Name << "\n");
+    S->update(Kind, F, Sym, Segment, NewSig);
   } else if (!S->isDefined()) {
     // The existing symbol table entry is undefined. The new symbol replaces
-    // it
+    // it, after checkign the type matches
     DEBUG(dbgs() << "resolving existing undefined symbol: " << Sym->Name
                  << "\n");
-    checkSymbolTypes(S, F, Sym);
-    S->update(Kind, F, Sym, Segment);
+    checkSymbolTypes(*S, *F, *Sym, NewSig);
+    S->update(Kind, F, Sym, Segment, NewSig);
   } else if (Sym->isWeak()) {
     // the new symbol is weak we can ignore it
     DEBUG(dbgs() << "existing symbol takes precensence\n");
@@ -130,7 +178,8 @@ Symbol *SymbolTable::addDefined(InputFil
     // the new symbol is not weak and the existing symbol is, so we replace
     // it
     DEBUG(dbgs() << "replacing existing weak symbol\n");
-    S->update(Kind, F, Sym, Segment);
+    checkSymbolTypes(*S, *F, *Sym, NewSig);
+    S->update(Kind, F, Sym, Segment, NewSig);
   } else {
     // niether symbol is week. They conflict.
     reportDuplicate(S, F);
@@ -138,14 +187,16 @@ Symbol *SymbolTable::addDefined(InputFil
   return S;
 }
 
-Symbol *SymbolTable::addUndefinedFunction(StringRef Name) {
+Symbol *SymbolTable::addUndefinedFunction(StringRef Name,
+                                          const WasmSignature *Type) {
   Symbol *S;
   bool WasInserted;
   std::tie(S, WasInserted) = insert(Name);
-  if (WasInserted)
-    S->update(Symbol::UndefinedFunctionKind);
-  else if (!S->isFunction())
+  if (WasInserted) {
+    S->update(Symbol::UndefinedFunctionKind, nullptr, nullptr, nullptr, Type);
+  } else if (!S->isFunction()) {
     error("symbol type mismatch: " + Name);
+  }
   return S;
 }
 
@@ -154,18 +205,21 @@ Symbol *SymbolTable::addUndefined(InputF
   Symbol *S;
   bool WasInserted;
   Symbol::Kind Kind = Symbol::UndefinedFunctionKind;
+  const WasmSignature *NewSig = nullptr;
   if (Sym->Type == WasmSymbol::SymbolType::GLOBAL_IMPORT)
     Kind = Symbol::UndefinedGlobalKind;
+  else
+    NewSig = getFunctionSig(*cast<ObjFile>(F), *Sym);
   std::tie(S, WasInserted) = insert(Sym->Name);
   if (WasInserted) {
-    S->update(Kind, F, Sym);
+    S->update(Kind, F, Sym, nullptr, NewSig);
   } else if (S->isLazy()) {
     DEBUG(dbgs() << "resolved by existing lazy\n");
     auto *AF = cast<ArchiveFile>(S->getFile());
     AF->addMember(&S->getArchiveSymbol());
   } else if (S->isDefined()) {
     DEBUG(dbgs() << "resolved by existing\n");
-    checkSymbolTypes(S, F, Sym);
+    checkSymbolTypes(*S, *F, *Sym, NewSig);
   }
   return S;
 }

Modified: lld/trunk/wasm/SymbolTable.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/wasm/SymbolTable.h?rev=319396&r1=319395&r2=319396&view=diff
==============================================================================
--- lld/trunk/wasm/SymbolTable.h (original)
+++ lld/trunk/wasm/SymbolTable.h Wed Nov 29 17:40:08 2017
@@ -18,6 +18,7 @@
 #include "llvm/Support/raw_ostream.h"
 
 using llvm::object::WasmSymbol;
+using llvm::wasm::WasmSignature;
 
 namespace lld {
 namespace wasm {
@@ -51,7 +52,7 @@ public:
   Symbol *addDefined(InputFile *F, const WasmSymbol *Sym,
                      const InputSegment *Segment = nullptr);
   Symbol *addUndefined(InputFile *F, const WasmSymbol *Sym);
-  Symbol *addUndefinedFunction(StringRef Name);
+  Symbol *addUndefinedFunction(StringRef Name, const WasmSignature *Type);
   Symbol *addDefinedGlobal(StringRef Name);
   void addLazy(ArchiveFile *F, const Archive::Symbol *Sym);
 

Modified: lld/trunk/wasm/Symbols.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/wasm/Symbols.cpp?rev=319396&r1=319395&r2=319396&view=diff
==============================================================================
--- lld/trunk/wasm/Symbols.cpp (original)
+++ lld/trunk/wasm/Symbols.cpp Wed Nov 29 17:40:08 2017
@@ -31,19 +31,9 @@ uint32_t Symbol::getFunctionIndex() cons
   return Sym->ElementIndex;
 }
 
-uint32_t Symbol::getFunctionTypeIndex() const {
-  assert(Sym->isFunction());
-  ObjFile *Obj = cast<ObjFile>(File);
-  if (Obj->isImportedFunction(Sym->ElementIndex)) {
-    const WasmImport &Import = Obj->getWasmObj()->imports()[Sym->ImportIndex];
-    DEBUG(dbgs() << "getFunctionTypeIndex: import: " << Sym->ImportIndex
-                 << " -> " << Import.SigIndex << "\n");
-    return Import.SigIndex;
-  }
-  DEBUG(dbgs() << "getFunctionTypeIndex: non import: " << Sym->ElementIndex
-               << "\n");
-  uint32_t FuntionIndex = Sym->ElementIndex - Obj->NumFunctionImports();
-  return Obj->getWasmObj()->functionTypes()[FuntionIndex];
+const WasmSignature &Symbol::getFunctionType() const {
+  assert(FunctionType != nullptr);
+  return *FunctionType;
 }
 
 uint32_t Symbol::getVirtualAddress() const {
@@ -74,11 +64,12 @@ void Symbol::setOutputIndex(uint32_t Ind
 }
 
 void Symbol::update(Kind K, InputFile *F, const WasmSymbol *WasmSym,
-                    const InputSegment *Seg) {
+                    const InputSegment *Seg, const WasmSignature *Sig) {
   SymbolKind = K;
   File = F;
   Sym = WasmSym;
   Segment = Seg;
+  FunctionType = Sig;
 }
 
 bool Symbol::isWeak() const { return Sym && Sym->isWeak(); }

Modified: lld/trunk/wasm/Symbols.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/wasm/Symbols.h?rev=319396&r1=319395&r2=319396&view=diff
==============================================================================
--- lld/trunk/wasm/Symbols.h (original)
+++ lld/trunk/wasm/Symbols.h Wed Nov 29 17:40:08 2017
@@ -16,6 +16,7 @@
 
 using llvm::object::Archive;
 using llvm::object::WasmSymbol;
+using llvm::wasm::WasmSignature;
 using llvm::wasm::WasmImport;
 using llvm::wasm::WasmExport;
 
@@ -40,7 +41,7 @@ public:
   };
 
   Symbol(StringRef Name, bool IsLocal)
-      : WrittenToSymtab(0), WrittenToNameSec(0), Name(Name), IsLocal(IsLocal) {}
+      : WrittenToSymtab(0), WrittenToNameSec(0), IsLocal(IsLocal), Name(Name) {}
 
   Kind getKind() const { return SymbolKind; }
 
@@ -66,7 +67,8 @@ public:
 
   uint32_t getGlobalIndex() const;
   uint32_t getFunctionIndex() const;
-  uint32_t getFunctionTypeIndex() const;
+
+  const WasmSignature &getFunctionType() const;
   uint32_t getOutputIndex() const;
 
   // Returns the virtual address of a defined global.
@@ -81,7 +83,8 @@ public:
   void setOutputIndex(uint32_t Index);
 
   void update(Kind K, InputFile *F = nullptr, const WasmSymbol *Sym = nullptr,
-              const InputSegment *Segment = nullptr);
+              const InputSegment *Segment = nullptr,
+              const WasmSignature *Sig = nullptr);
 
   void setArchiveSymbol(const Archive::Symbol &Sym) { ArchiveSymbol = Sym; }
   const Archive::Symbol &getArchiveSymbol() { return ArchiveSymbol; }
@@ -92,14 +95,16 @@ public:
   unsigned WrittenToNameSec : 1;
 
 protected:
+  unsigned IsLocal : 1;
+
   StringRef Name;
-  bool IsLocal;
   Archive::Symbol ArchiveSymbol = {nullptr, 0, 0};
   Kind SymbolKind = InvalidKind;
   InputFile *File = nullptr;
   const WasmSymbol *Sym = nullptr;
   const InputSegment *Segment = nullptr;
   llvm::Optional<uint32_t> OutputIndex;
+  const WasmSignature* FunctionType;
 };
 
 } // namespace wasm

Modified: lld/trunk/wasm/Writer.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/wasm/Writer.cpp?rev=319396&r1=319395&r2=319396&view=diff
==============================================================================
--- lld/trunk/wasm/Writer.cpp (original)
+++ lld/trunk/wasm/Writer.cpp Wed Nov 29 17:40:08 2017
@@ -35,11 +35,6 @@ static constexpr int kStackAlignment = 1
 
 namespace {
 
-// Needed for WasmSignatureDenseMapInfo
-bool operator==(const WasmSignature &LHS, const WasmSignature &RHS) {
-  return LHS.ReturnType == RHS.ReturnType && LHS.ParamTypes == RHS.ParamTypes;
-}
-
 // Traits for using WasmSignature in a DenseMap.
 struct WasmSignatureDenseMapInfo {
   static WasmSignature getEmptyKey() {
@@ -72,6 +67,7 @@ public:
 private:
   void openFile();
 
+  uint32_t getTypeIndex(const WasmSignature &Sig);
   void assignSymbolIndexes();
   void calculateImports();
   void calculateOffsets();
@@ -158,8 +154,8 @@ void Writer::createImportSection() {
     Import.Module = "env";
     Import.Field = Sym->getName();
     Import.Kind = WASM_EXTERNAL_FUNCTION;
-    auto *Obj = cast<ObjFile>(Sym->getFile());
-    Import.SigIndex = Obj->relocateTypeIndex(Sym->getFunctionTypeIndex());
+    assert(TypeIndices.count(Sym->getFunctionType()) > 0);
+    Import.SigIndex = TypeIndices.lookup(Sym->getFunctionType());
     writeImport(OS, Import);
   }
 
@@ -179,9 +175,6 @@ void Writer::createImportSection() {
     Import.Field = Sym->getName();
     Import.Kind = WASM_EXTERNAL_GLOBAL;
     Import.Global.Mutable = false;
-    assert(isa<ObjFile>(Sym->getFile()));
-    // TODO(sbc): Set type of this import
-    // ObjFile* Obj = dyn_cast<ObjFile>(Sym->getFile());
     Import.Global.Type = WASM_TYPE_I32; // Sym->getGlobalType();
     writeImport(OS, Import);
   }
@@ -632,17 +625,18 @@ void Writer::calculateImports() {
   }
 }
 
+uint32_t Writer::getTypeIndex(const WasmSignature &Sig) {
+  auto Pair = TypeIndices.insert(std::make_pair(Sig, Types.size()));
+  if (Pair.second)
+    Types.push_back(&Sig);
+  return Pair.first->second;
+}
+
 void Writer::calculateTypes() {
   for (ObjFile *File : Symtab->ObjectFiles) {
     File->TypeMap.reserve(File->getWasmObj()->types().size());
-    for (const WasmSignature &Sig : File->getWasmObj()->types()) {
-      auto Pair = TypeIndices.insert(std::make_pair(Sig, Types.size()));
-      if (Pair.second)
-        Types.push_back(&Sig);
-
-      // Now we map the input files index to the index in the linked output
-      File->TypeMap.push_back(Pair.first->second);
-    }
+    for (const WasmSignature &Sig : File->getWasmObj()->types())
+      File->TypeMap.push_back(getTypeIndex(Sig));
   }
 }
 

Modified: lld/trunk/wasm/WriterUtils.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/wasm/WriterUtils.cpp?rev=319396&r1=319395&r2=319396&view=diff
==============================================================================
--- lld/trunk/wasm/WriterUtils.cpp (original)
+++ lld/trunk/wasm/WriterUtils.cpp Wed Nov 29 17:40:08 2017
@@ -184,3 +184,32 @@ void wasm::writeReloc(raw_ostream &OS, c
 }
 
 } // namespace lld
+
+std::string lld::toString(ValType Type) {
+  switch (Type) {
+  case ValType::I32:
+    return "I32";
+  case ValType::I64:
+    return "I64";
+  case ValType::F32:
+    return "F32";
+  case ValType::F64:
+    return "F64";
+  }
+  llvm_unreachable("Invalid wasm::ValType");
+}
+
+std::string lld::toString(const WasmSignature &Sig) {
+  SmallString<128> S("(");
+  for (uint32_t Type : Sig.ParamTypes) {
+    if (S.size() != 1)
+      S += ", ";
+    S += toString(static_cast<ValType>(Type));
+  }
+  S += ") -> ";
+  if (Sig.ReturnType == WASM_TYPE_NORESULT)
+    S += "void";
+  else
+    S += toString(static_cast<ValType>(Sig.ReturnType));
+  return S.str();
+}

Modified: lld/trunk/wasm/WriterUtils.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/wasm/WriterUtils.h?rev=319396&r1=319395&r2=319396&view=diff
==============================================================================
--- lld/trunk/wasm/WriterUtils.h (original)
+++ lld/trunk/wasm/WriterUtils.h Wed Nov 29 17:40:08 2017
@@ -16,6 +16,17 @@
 
 using llvm::raw_ostream;
 
+// Needed for WasmSignatureDenseMapInfo
+inline bool operator==(const llvm::wasm::WasmSignature &LHS,
+                       const llvm::wasm::WasmSignature &RHS) {
+  return LHS.ReturnType == RHS.ReturnType && LHS.ParamTypes == RHS.ParamTypes;
+}
+
+inline bool operator!=(const llvm::wasm::WasmSignature &LHS,
+                       const llvm::wasm::WasmSignature &RHS) {
+  return !(LHS == RHS);
+}
+
 namespace lld {
 namespace wasm {
 
@@ -58,6 +69,10 @@ void writeExport(raw_ostream &OS, const
 void writeReloc(raw_ostream &OS, const OutputRelocation &Reloc);
 
 } // namespace wasm
+
+std::string toString(const llvm::wasm::ValType Type);
+std::string toString(const llvm::wasm::WasmSignature &Sig);
+
 } // namespace lld
 
 #endif // LLD_WASM_WRITERUTILS_H




More information about the llvm-commits mailing list