[llvm] 9261ee3 - [WebAssembly] Make EH work with dynamic linking

Heejin Ahn via llvm-commits llvm-commits at lists.llvm.org
Tue Oct 12 23:28:51 PDT 2021


Author: Heejin Ahn
Date: 2021-10-12T23:28:27-07:00
New Revision: 9261ee32dc41ae6f2ebf0608c3cec22daf5ec494

URL: https://github.com/llvm/llvm-project/commit/9261ee32dc41ae6f2ebf0608c3cec22daf5ec494
DIFF: https://github.com/llvm/llvm-project/commit/9261ee32dc41ae6f2ebf0608c3cec22daf5ec494.diff

LOG: [WebAssembly] Make EH work with dynamic linking

This makes Wasm EH work with dynamic linking. So far we were only able
to handle destructors, which do not use any tags or LSDA info.

1. This uses `TargetExternalSymbol` for `GCC_except_tableN` symbols,
   which points to the address of per-function LSDA info. It is more
   convenient to use than `MCSymbol` because it can take additional
   target flags.

2. When lowering `wasm_lsda` intrinsic, if PIC is enabled, make the
   symbol relative to `__memory_base` and generate the `add` node. If
   PIC is disabled, continue to use the absolute address.

3. Make tag symbols (`__cpp_exception` and `__c_longjmp`) undefined in
   the backend, because it is hard to make it work with dynamic
   linking's loading order. Instead, we make all tag symbols undefined
   in the LLVM backend and import it from JS.

4. Add support for undefined tags to the linker.

Companion patches:
- https://github.com/WebAssembly/binaryen/pull/4223
- https://github.com/emscripten-core/emscripten/pull/15266

Reviewed By: sbc100

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

Added: 
    

Modified: 
    lld/test/wasm/Inputs/tag-section1.ll
    lld/test/wasm/Inputs/tag-section2.ll
    lld/test/wasm/tag-section.ll
    lld/wasm/InputFiles.cpp
    lld/wasm/SymbolTable.cpp
    lld/wasm/SymbolTable.h
    lld/wasm/Symbols.cpp
    lld/wasm/Symbols.h
    lld/wasm/SyntheticSections.cpp
    lld/wasm/SyntheticSections.h
    llvm/lib/CodeGen/AsmPrinter/WasmException.cpp
    llvm/lib/Object/WasmObjectFile.cpp
    llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp
    llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp
    llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.td
    llvm/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp
    llvm/test/CodeGen/WebAssembly/eh-lsda.ll

Removed: 
    


################################################################################
diff  --git a/lld/test/wasm/Inputs/tag-section1.ll b/lld/test/wasm/Inputs/tag-section1.ll
index 89d9e87162f5a..253fc4a4480bf 100644
--- a/lld/test/wasm/Inputs/tag-section1.ll
+++ b/lld/test/wasm/Inputs/tag-section1.ll
@@ -1,5 +1,5 @@
 target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
-target triple = "wasm32-unknown-unknown"
+target triple = "wasm32-unknown-emscripten"
 
 declare void @llvm.wasm.throw(i32, i8*)
 

diff  --git a/lld/test/wasm/Inputs/tag-section2.ll b/lld/test/wasm/Inputs/tag-section2.ll
index 3499db9298afa..6b82c858bcc85 100644
--- a/lld/test/wasm/Inputs/tag-section2.ll
+++ b/lld/test/wasm/Inputs/tag-section2.ll
@@ -1,5 +1,5 @@
 target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
-target triple = "wasm32-unknown-unknown"
+target triple = "wasm32-unknown-emscripten"
 
 declare void @llvm.wasm.throw(i32, i8*)
 

diff  --git a/lld/test/wasm/tag-section.ll b/lld/test/wasm/tag-section.ll
index 1f6aa9d737892..4f55f881aedc2 100644
--- a/lld/test/wasm/tag-section.ll
+++ b/lld/test/wasm/tag-section.ll
@@ -1,13 +1,21 @@
+; Static code
 ; RUN: llc -filetype=obj -wasm-enable-eh -exception-model=wasm -mattr=+exception-handling %p/Inputs/tag-section1.ll -o %t1.o
 ; RUN: llc -filetype=obj -wasm-enable-eh -exception-model=wasm -mattr=+exception-handling %p/Inputs/tag-section2.ll -o %t2.o
 ; RUN: llc -filetype=obj -wasm-enable-eh -exception-model=wasm -mattr=+exception-handling %s -o %t.o
 ; RUN: wasm-ld -o %t.wasm %t.o %t1.o %t2.o
 ; RUN: wasm-ld --export-all -o %t-export-all.wasm %t.o %t1.o %t2.o
-; RUN: obj2yaml %t.wasm | FileCheck %s
-; RUN: obj2yaml %t-export-all.wasm | FileCheck %s --check-prefix=EXPORT-ALL
+; RUN: obj2yaml %t.wasm | FileCheck %s --check-prefix=NOPIC
+; RUN: obj2yaml %t-export-all.wasm | FileCheck %s --check-prefix=NOPIC-EXPORT-ALL
+
+; PIC code
+; RUN: llc -filetype=obj -wasm-enable-eh -exception-model=wasm -mattr=+exception-handling -relocation-model=pic %p/Inputs/tag-section1.ll -o %t1.o
+; RUN: llc -filetype=obj -wasm-enable-eh -exception-model=wasm -mattr=+exception-handling -relocation-model=pic %p/Inputs/tag-section2.ll -o %t2.o
+; RUN: llc -filetype=obj -wasm-enable-eh -exception-model=wasm -mattr=+exception-handling -relocation-model=pic %s -o %t.o
+; RUN: wasm-ld --import-undefined --experimental-pic -pie -o %t.wasm %t.o %t1.o %t2.o
+; RUN: obj2yaml %t.wasm | FileCheck %s --check-prefix=PIC
 
 target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
-target triple = "wasm32-unknown-unknown"
+target triple = "wasm32-unknown-emscripten"
 
 declare void @foo(i8*)
 declare void @bar(i8*)
@@ -18,25 +26,47 @@ define void @_start() {
   ret void
 }
 
-; CHECK:      Sections:
-; CHECK-NEXT:   - Type:            TYPE
-; CHECK-NEXT:     Signatures:
-; CHECK-NEXT:       - Index:           0
-; CHECK-NEXT:         ParamTypes:      []
-; CHECK-NEXT:         ReturnTypes:     []
-; CHECK-NEXT:       - Index:           1
-; CHECK-NEXT:         ParamTypes:
-; CHECK-NEXT:           - I32
-; CHECK-NEXT:         ReturnTypes:     []
+; NOPIC:      Sections:
+; NOPIC-NEXT:   - Type:            TYPE
+; NOPIC-NEXT:     Signatures:
+; NOPIC-NEXT:       - Index:           0
+; NOPIC-NEXT:         ParamTypes:      []
+; NOPIC-NEXT:         ReturnTypes:     []
+; NOPIC-NEXT:       - Index:           1
+; NOPIC-NEXT:         ParamTypes:
+; NOPIC-NEXT:           - I32
+; NOPIC-NEXT:         ReturnTypes:     []
 
-; CHECK:        - Type:            TAG
-; CHECK-NEXT:     TagTypes:        [ 1 ]
+; NOPIC:        - Type:            TAG
+; NOPIC-NEXT:     TagTypes:        [ 1 ]
 
 ; Global section has to come after tag section
-; CHECK:        - Type:            GLOBAL
+; NOPIC:        - Type:            GLOBAL
+
+; NOPIC-EXPORT-ALL:   - Type:            EXPORT
+; NOPIC-EXPORT-ALL-NEXT Exports:
+; NOPIC-EXPORT-ALL:       - Name:            __cpp_exception
+; NOPIC-EXPORT-ALL:         Kind:            TAG
+; NOPIC-EXPORT-ALL:         Index:           0
+
+; In PIC mode, tags are undefined and imported from JS.
+; PIC:        Sections:
+; PIC:         - Type:            TYPE
+; PIC-NEXT:      Signatures:
+; PIC-NEXT:        - Index:           0
+; PIC-NEXT:          ParamTypes:
+; PIC-NEXT:            - I32
+; PIC-NEXT:          ReturnTypes:     []
+; PIC-NEXT:        - Index:           1
+; PIC-NEXT:          ParamTypes:      []
+; PIC-NEXT:          ReturnTypes:     []
+
+; PIC:         - Type:            IMPORT
+; PIC-NEXT:      Imports:
+; PIC:             - Module:          env
+; PIC:               Field:           __cpp_exception
+; PIC-NEXT:          Kind:            TAG
+; PIC-NEXT:          SigIndex:        0
 
-; EXPORT-ALL:   - Type:            EXPORT
-; EXPORT-ALL-NEXT Exports:
-; EXPORT-ALL:       - Name:            __cpp_exception
-; EXPORT-ALL:         Kind:            TAG
-; EXPORT-ALL:         Index:           0
+; In PIC mode, tags should NOT be defined in the module; they are imported.
+; PIC-NOT:     - Type:            TAG

diff  --git a/lld/wasm/InputFiles.cpp b/lld/wasm/InputFiles.cpp
index 9e7f1ca18831f..29bc0b32d9658 100644
--- a/lld/wasm/InputFiles.cpp
+++ b/lld/wasm/InputFiles.cpp
@@ -663,6 +663,14 @@ Symbol *ObjFile::createUndefined(const WasmSymbol &sym, bool isCalledDirectly) {
     return symtab->addUndefinedTable(name, sym.Info.ImportName,
                                      sym.Info.ImportModule, flags, this,
                                      sym.TableType);
+  case WASM_SYMBOL_TYPE_TAG:
+    if (sym.isBindingLocal())
+      return make<UndefinedTag>(name, sym.Info.ImportName,
+                                sym.Info.ImportModule, flags, this,
+                                sym.Signature);
+    return symtab->addUndefinedTag(name, sym.Info.ImportName,
+                                   sym.Info.ImportModule, flags, this,
+                                   sym.Signature);
   case WASM_SYMBOL_TYPE_SECTION:
     llvm_unreachable("section symbols cannot be undefined");
   }

diff  --git a/lld/wasm/SymbolTable.cpp b/lld/wasm/SymbolTable.cpp
index 877909c23c591..b204fae451a94 100644
--- a/lld/wasm/SymbolTable.cpp
+++ b/lld/wasm/SymbolTable.cpp
@@ -625,6 +625,30 @@ Symbol *SymbolTable::addUndefinedTable(StringRef name,
   return s;
 }
 
+Symbol *SymbolTable::addUndefinedTag(StringRef name,
+                                     Optional<StringRef> importName,
+                                     Optional<StringRef> importModule,
+                                     uint32_t flags, InputFile *file,
+                                     const WasmSignature *sig) {
+  LLVM_DEBUG(dbgs() << "addUndefinedTag: " << name << "\n");
+  assert(flags & WASM_SYMBOL_UNDEFINED);
+
+  Symbol *s;
+  bool wasInserted;
+  std::tie(s, wasInserted) = insert(name, file);
+  if (s->traced)
+    printTraceSymbolUndefined(name, file);
+
+  if (wasInserted)
+    replaceSymbol<UndefinedTag>(s, name, importName, importModule, flags, file,
+                                sig);
+  else if (auto *lazy = dyn_cast<LazySymbol>(s))
+    lazy->fetch();
+  else if (s->isDefined())
+    checkTagType(s, file, sig);
+  return s;
+}
+
 TableSymbol *SymbolTable::createUndefinedIndirectFunctionTable(StringRef name) {
   WasmLimits limits{0, 0, 0}; // Set by the writer.
   WasmTableType *type = make<WasmTableType>();

diff  --git a/lld/wasm/SymbolTable.h b/lld/wasm/SymbolTable.h
index aea2f164928a5..c2a3ee34ac3f8 100644
--- a/lld/wasm/SymbolTable.h
+++ b/lld/wasm/SymbolTable.h
@@ -79,6 +79,10 @@ class SymbolTable {
                             llvm::Optional<StringRef> importModule,
                             uint32_t flags, InputFile *file,
                             const WasmTableType *type);
+  Symbol *addUndefinedTag(StringRef name, llvm::Optional<StringRef> importName,
+                          llvm::Optional<StringRef> importModule,
+                          uint32_t flags, InputFile *file,
+                          const WasmSignature *sig);
 
   TableSymbol *resolveIndirectFunctionTable(bool required);
 

diff  --git a/lld/wasm/Symbols.cpp b/lld/wasm/Symbols.cpp
index 4658b8248b133..79bec1025a254 100644
--- a/lld/wasm/Symbols.cpp
+++ b/lld/wasm/Symbols.cpp
@@ -58,6 +58,8 @@ std::string toString(wasm::Symbol::Kind kind) {
     return "UndefinedGlobal";
   case wasm::Symbol::UndefinedTableKind:
     return "UndefinedTable";
+  case wasm::Symbol::UndefinedTagKind:
+    return "UndefinedTag";
   case wasm::Symbol::LazyKind:
     return "LazyKind";
   case wasm::Symbol::SectionKind:
@@ -113,6 +115,8 @@ WasmSymbolType Symbol::getWasmType() const {
 const WasmSignature *Symbol::getSignature() const {
   if (auto* f = dyn_cast<FunctionSymbol>(this))
     return f->signature;
+  if (auto *t = dyn_cast<TagSymbol>(this))
+    return t->signature;
   if (auto *l = dyn_cast<LazySymbol>(this))
     return l->signature;
   return nullptr;

diff  --git a/lld/wasm/Symbols.h b/lld/wasm/Symbols.h
index 54f7b6100eed4..342ebcf1a6e9f 100644
--- a/lld/wasm/Symbols.h
+++ b/lld/wasm/Symbols.h
@@ -55,6 +55,7 @@ class Symbol {
     UndefinedDataKind,
     UndefinedGlobalKind,
     UndefinedTableKind,
+    UndefinedTagKind,
     LazyKind,
   };
 
@@ -66,7 +67,7 @@ class Symbol {
     return symbolKind == UndefinedFunctionKind ||
            symbolKind == UndefinedDataKind ||
            symbolKind == UndefinedGlobalKind ||
-           symbolKind == UndefinedTableKind;
+           symbolKind == UndefinedTableKind || symbolKind == UndefinedTagKind;
   }
 
   bool isLazy() const { return symbolKind == LazyKind; }
@@ -437,7 +438,9 @@ class UndefinedTable : public TableSymbol {
 // and is named '__cpp_exception' for linking.
 class TagSymbol : public Symbol {
 public:
-  static bool classof(const Symbol *s) { return s->kind() == DefinedTagKind; }
+  static bool classof(const Symbol *s) {
+    return s->kind() == DefinedTagKind || s->kind() == UndefinedTagKind;
+  }
 
   // Get/set the tag index
   uint32_t getTagIndex() const;
@@ -463,6 +466,19 @@ class DefinedTag : public TagSymbol {
   InputTag *tag;
 };
 
+class UndefinedTag : public TagSymbol {
+public:
+  UndefinedTag(StringRef name, llvm::Optional<StringRef> importName,
+               llvm::Optional<StringRef> importModule, uint32_t flags,
+               InputFile *file = nullptr, const WasmSignature *sig = nullptr)
+      : TagSymbol(name, UndefinedTagKind, flags, file, sig) {
+    this->importName = importName;
+    this->importModule = importModule;
+  }
+
+  static bool classof(const Symbol *s) { return s->kind() == UndefinedTagKind; }
+};
+
 // LazySymbol represents a symbol that is not yet in the link, but we know where
 // to find it if needed. If the resolver finds both Undefined and Lazy for the
 // same name, it will ask the Lazy to load a file.

diff  --git a/lld/wasm/SyntheticSections.cpp b/lld/wasm/SyntheticSections.cpp
index d70ade4a5a892..be1a82b9f5d8c 100644
--- a/lld/wasm/SyntheticSections.cpp
+++ b/lld/wasm/SyntheticSections.cpp
@@ -170,10 +170,14 @@ void ImportSection::addImport(Symbol *sym) {
       g->setGlobalIndex(entry.first->second);
     }
   } else if (auto *t = dyn_cast<TagSymbol>(sym)) {
-    // NB: There's currently only one possible kind of tag, and no
-    // `UndefinedTag`, so we don't bother de-duplicating tag imports.
-    importedSymbols.emplace_back(sym);
-    t->setTagIndex(numImportedTags++);
+    ImportKey<WasmSignature> key(*(t->getSignature()), module, name);
+    auto entry = importedTags.try_emplace(key, numImportedTags);
+    if (entry.second) {
+      importedSymbols.emplace_back(sym);
+      t->setTagIndex(numImportedTags++);
+    } else {
+      t->setTagIndex(entry.first->second);
+    }
   } else {
     assert(TableSymbol::classof(sym));
     auto *table = cast<TableSymbol>(sym);

diff  --git a/lld/wasm/SyntheticSections.h b/lld/wasm/SyntheticSections.h
index 421bbabe0e1b2..4caab9d4a3c7f 100644
--- a/lld/wasm/SyntheticSections.h
+++ b/lld/wasm/SyntheticSections.h
@@ -198,6 +198,7 @@ class ImportSection : public SyntheticSection {
   llvm::DenseMap<ImportKey<WasmGlobalType>, uint32_t> importedGlobals;
   llvm::DenseMap<ImportKey<WasmSignature>, uint32_t> importedFunctions;
   llvm::DenseMap<ImportKey<WasmTableType>, uint32_t> importedTables;
+  llvm::DenseMap<ImportKey<WasmSignature>, uint32_t> importedTags;
 };
 
 class FunctionSection : public SyntheticSection {

diff  --git a/llvm/lib/CodeGen/AsmPrinter/WasmException.cpp b/llvm/lib/CodeGen/AsmPrinter/WasmException.cpp
index a833afd5c1d00..a17a2ca2790e7 100644
--- a/llvm/lib/CodeGen/AsmPrinter/WasmException.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/WasmException.cpp
@@ -23,12 +23,19 @@ void WasmException::endModule() {
   // the symbols has already been created, i.e., we have at least one 'throw' or
   // 'catch' instruction with the symbol in the module, and emit the symbol only
   // if so.
-  for (const char *SymName : {"__cpp_exception", "__c_longjmp"}) {
-    SmallString<60> NameStr;
-    Mangler::getNameWithPrefix(NameStr, SymName, Asm->getDataLayout());
-    if (Asm->OutContext.lookupSymbol(NameStr)) {
-      MCSymbol *ExceptionSym = Asm->GetExternalSymbolSymbol(SymName);
-      Asm->OutStreamer->emitLabel(ExceptionSym);
+  //
+  // But in dynamic linking, it is in general not possible to come up with a
+  // module instantiating order in which tag-defining modules are loaded before
+  // the importing modules. So we make them undefined symbols here, define tags
+  // in the JS side, and feed them to each importing module.
+  if (!Asm->isPositionIndependent()) {
+    for (const char *SymName : {"__cpp_exception", "__c_longjmp"}) {
+      SmallString<60> NameStr;
+      Mangler::getNameWithPrefix(NameStr, SymName, Asm->getDataLayout());
+      if (Asm->OutContext.lookupSymbol(NameStr)) {
+        MCSymbol *ExceptionSym = Asm->GetExternalSymbolSymbol(SymName);
+        Asm->OutStreamer->emitLabel(ExceptionSym);
+      }
     }
   }
 }

diff  --git a/llvm/lib/Object/WasmObjectFile.cpp b/llvm/lib/Object/WasmObjectFile.cpp
index a6a47489b8d24..ed23c53381246 100644
--- a/llvm/lib/Object/WasmObjectFile.cpp
+++ b/llvm/lib/Object/WasmObjectFile.cpp
@@ -1124,6 +1124,9 @@ Error WasmObjectFile::parseImportSection(ReadContext &Ctx) {
     }
     case wasm::WASM_EXTERNAL_TAG:
       NumImportedTags++;
+      if (readUint8(Ctx) != 0) // Reserved 'attribute' field
+        return make_error<GenericBinaryError>("invalid attribute",
+                                              object_error::parse_failed);
       Im.SigIndex = readVaruint32(Ctx);
       if (Im.SigIndex >= NumTypes)
         return make_error<GenericBinaryError>("invalid tag type",
@@ -1203,8 +1206,7 @@ Error WasmObjectFile::parseTagSection(ReadContext &Ctx) {
   Tags.reserve(Count);
   uint32_t NumTypes = Signatures.size();
   while (Count--) {
-    char Attr = readUint8(Ctx); // Reserved 'attribute' field
-    if (Attr != 0)
+    if (readUint8(Ctx) != 0) // Reserved 'attribute' field
       return make_error<GenericBinaryError>("invalid attribute",
                                             object_error::parse_failed);
     uint32_t Type = readVaruint32(Ctx);

diff  --git a/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp
index 24146ca61d05f..66acd3519623e 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp
@@ -234,14 +234,22 @@ MCSymbol *WebAssemblyAsmPrinter::getOrCreateWasmSymbol(StringRef Name) {
     return WasmSym;
   }
 
+  if (Name.startswith("GCC_except_table")) {
+    WasmSym->setType(wasm::WASM_SYMBOL_TYPE_DATA);
+    return WasmSym;
+  }
+
   SmallVector<wasm::ValType, 4> Returns;
   SmallVector<wasm::ValType, 4> Params;
   if (Name == "__cpp_exception" || Name == "__c_longjmp") {
     WasmSym->setType(wasm::WASM_SYMBOL_TYPE_TAG);
-    // We may have multiple C++ compilation units to be linked together, each of
-    // which defines the exception symbol. To resolve them, we declare them as
-    // weak.
-    WasmSym->setWeak(true);
+    // In static linking we define tag symbols in WasmException::endModule().
+    // But we may have multiple objects to be linked together, each of which
+    // defines the tag symbols. To resolve them, we declare them as weak. In
+    // dynamic linking we make tag symbols undefined in the backend, define it
+    // in JS, and feed them to each importing module.
+    if (!isPositionIndependent())
+      WasmSym->setWeak(true);
     WasmSym->setExternal(true);
 
     // Currently both C++ exceptions and C longjmps have a single pointer type

diff  --git a/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp
index 6284a3c39b505..7bc8ebcdcdb74 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp
@@ -1751,14 +1751,22 @@ SDValue WebAssemblyTargetLowering::LowerIntrinsic(SDValue Op,
     return SDValue(); // Don't custom lower most intrinsics.
 
   case Intrinsic::wasm_lsda: {
-    EVT VT = Op.getValueType();
-    const TargetLowering &TLI = DAG.getTargetLoweringInfo();
-    MVT PtrVT = TLI.getPointerTy(DAG.getDataLayout());
-    auto &Context = MF.getMMI().getContext();
-    MCSymbol *S = Context.getOrCreateSymbol(Twine("GCC_except_table") +
-                                            Twine(MF.getFunctionNumber()));
-    return DAG.getNode(WebAssemblyISD::Wrapper, DL, VT,
-                       DAG.getMCSymbol(S, PtrVT));
+    auto PtrVT = getPointerTy(MF.getDataLayout());
+    const char *SymName = MF.createExternalSymbolName(
+        "GCC_except_table" + std::to_string(MF.getFunctionNumber()));
+    if (isPositionIndependent()) {
+      SDValue Node = DAG.getTargetExternalSymbol(
+          SymName, PtrVT, WebAssemblyII::MO_MEMORY_BASE_REL);
+      const char *BaseName = MF.createExternalSymbolName("__memory_base");
+      SDValue BaseAddr =
+          DAG.getNode(WebAssemblyISD::Wrapper, DL, PtrVT,
+                      DAG.getTargetExternalSymbol(BaseName, PtrVT));
+      SDValue SymAddr =
+          DAG.getNode(WebAssemblyISD::WrapperREL, DL, PtrVT, Node);
+      return DAG.getNode(ISD::ADD, DL, PtrVT, BaseAddr, SymAddr);
+    }
+    SDValue Node = DAG.getTargetExternalSymbol(SymName, PtrVT);
+    return DAG.getNode(WebAssemblyISD::Wrapper, DL, PtrVT, Node);
   }
 
   case Intrinsic::wasm_shuffle: {

diff  --git a/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.td b/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.td
index 55ebc220f4094..ee9247a8bef95 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.td
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.td
@@ -417,8 +417,10 @@ def : Pat<(i32 (WebAssemblyWrapper texternalsym:$addr)),
 def : Pat<(i64 (WebAssemblyWrapper texternalsym:$addr)),
           (CONST_I64 texternalsym:$addr)>, Requires<[IsNotPIC, HasAddr64]>;
 
-def : Pat<(i32 (WebAssemblyWrapper mcsym:$sym)), (CONST_I32 mcsym:$sym)>;
-def : Pat<(i64 (WebAssemblyWrapper mcsym:$sym)), (CONST_I64 mcsym:$sym)>;
+def : Pat<(i32 (WebAssemblyWrapperREL texternalsym:$addr)),
+          (CONST_I32 texternalsym:$addr)>, Requires<[IsPIC, HasAddr32]>;
+def : Pat<(i64 (WebAssemblyWrapperREL texternalsym:$addr)),
+          (CONST_I64 texternalsym:$addr)>, Requires<[IsPIC, HasAddr64]>;
 
 //===----------------------------------------------------------------------===//
 // Additional sets of instructions.

diff  --git a/llvm/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp
index 8c6f57168341d..105c24ad8e46e 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp
@@ -278,15 +278,9 @@ void WebAssemblyMCInstLower::lower(const MachineInstr *MI,
       MCOp = lowerSymbolOperand(MO, GetGlobalAddressSymbol(MO));
       break;
     case MachineOperand::MO_ExternalSymbol:
-      // The target flag indicates whether this is a symbol for a
-      // variable or a function.
-      assert(MO.getTargetFlags() == 0 &&
-             "WebAssembly uses only symbol flags on ExternalSymbols");
       MCOp = lowerSymbolOperand(MO, GetExternalSymbolSymbol(MO));
       break;
     case MachineOperand::MO_MCSymbol:
-      // This is currently used only for LSDA symbols (GCC_except_table),
-      // because global addresses or other external symbols are handled above.
       assert(MO.getTargetFlags() == 0 &&
              "WebAssembly does not use target flags on MCSymbol");
       MCOp = lowerSymbolOperand(MO, MO.getMCSymbol());

diff  --git a/llvm/test/CodeGen/WebAssembly/eh-lsda.ll b/llvm/test/CodeGen/WebAssembly/eh-lsda.ll
index 15cb4e9e7f19f..78bfe5be2d967 100644
--- a/llvm/test/CodeGen/WebAssembly/eh-lsda.ll
+++ b/llvm/test/CodeGen/WebAssembly/eh-lsda.ll
@@ -1,6 +1,9 @@
-; RUN: llc < %s -disable-wasm-fallthrough-return-opt -wasm-keep-registers -wasm-enable-eh -exception-model=wasm -mattr=+exception-handling | FileCheck -allow-deprecated-dag-overlap %s
-
-target triple = "wasm32-unknown-unknown"
+; RUN: llc < %s --mtriple=wasm32-unknown-unknown -wasm-disable-explicit-locals -wasm-keep-registers -wasm-enable-eh -exception-model=wasm -mattr=+exception-handling | FileCheck %s -check-prefixes=CHECK,NOPIC -DPTR=32
+; RUN: llc < %s --mtriple=wasm64-unknown-unknown -wasm-disable-explicit-locals -wasm-keep-registers -wasm-enable-eh -exception-model=wasm -mattr=+exception-handling | FileCheck %s -check-prefixes=CHECK,NOPIC -DPTR=64
+; RUN: llc < %s --mtriple=wasm32-unknown-emscripten -wasm-disable-explicit-locals -wasm-keep-registers -wasm-enable-eh -exception-model=wasm -mattr=+exception-handling | FileCheck %s -check-prefixes=CHECK,NOPIC -DPTR=32
+; RUN: llc < %s --mtriple=wasm64-unknown-emscripten -wasm-disable-explicit-locals -wasm-keep-registers -wasm-enable-eh -exception-model=wasm -mattr=+exception-handling | FileCheck %s -check-prefixes=CHECK,NOPIC -DPTR=64
+; RUN: llc < %s --mtriple=wasm32-unknown-emscripten -wasm-disable-explicit-locals -wasm-keep-registers -wasm-enable-eh -exception-model=wasm -mattr=+exception-handling -relocation-model=pic | FileCheck %s -check-prefixes=CHECK,PIC -DPTR=32
+; RUN: llc < %s --mtriple=wasm64-unknown-emscripten -wasm-disable-explicit-locals -wasm-keep-registers -wasm-enable-eh -exception-model=wasm -mattr=+exception-handling -relocation-model=pic | FileCheck %s -check-prefixes=CHECK,PIC -DPTR=64
 
 @_ZTIi = external constant i8*
 @_ZTIf = external constant i8*
@@ -60,7 +63,22 @@ try.cont:                                         ; preds = %entry, %catch.start
 ; entries with the first landing pad because they end with the same sequence
 ; (double -> ...). But the third landing table cannot share action table entries
 ; with others, so it should create its own entries.
+
 ; CHECK-LABEL: test1:
+; In static linking, we load GCC_except_table as a constant directly.
+; NOPIC:      i[[PTR]].const  $push[[CONTEXT:.*]]=, __wasm_lpad_context
+; NOPIC-NEXT: i[[PTR]].const  $push[[EXCEPT_TABLE:.*]]=, GCC_except_table1
+; NOPIC-NEXT: i[[PTR]].store  {{[48]}}($pop[[CONTEXT]]), $pop[[EXCEPT_TABLE]]
+
+; In case of PIC, we make GCC_except_table symbols a relative on based on
+; __memory_base.
+; PIC:        global.get  $push[[CONTEXT:.*]]=, __wasm_lpad_context at GOT
+; PIC-NEXT:   local.tee  $push{{.*}}=, $[[CONTEXT_LOCAL:.*]]=, $pop[[CONTEXT]]
+; PIC:        global.get  $push[[MEMORY_BASE:.*]]=, __memory_base
+; PIC-NEXT:   i[[PTR]].const  $push[[EXCEPT_TABLE_REL:.*]]=, GCC_except_table1 at MBREL
+; PIC-NEXT:   i[[PTR]].add   $push[[EXCEPT_TABLE:.*]]=, $pop[[MEMORY_BASE]], $pop[[EXCEPT_TABLE_REL]]
+; PIC-NEXT:   i[[PTR]].store  {{[48]}}($[[CONTEXT_LOCAL]]), $pop[[EXCEPT_TABLE]]
+
 ; CHECK: .section  .rodata.gcc_except_table,"",@
 ; CHECK-NEXT:   .p2align  2
 ; CHECK-NEXT: GCC_except_table[[START:[0-9]+]]:
@@ -102,10 +120,10 @@ try.cont:                                         ; preds = %entry, %catch.start
 ; CHECK-NEXT:   .int8  125                     #   Continue to action 5
 ; CHECK-NEXT:   .p2align  2
 ; CHECK-NEXT:                                  # >> Catch TypeInfos <<
-; CHECK-NEXT:   .int32  _ZTIi                  # TypeInfo 4
-; CHECK-NEXT:   .int32  _ZTIf                  # TypeInfo 3
-; CHECK-NEXT:   .int32  _ZTId                  # TypeInfo 2
-; CHECK-NEXT:   .int32  0                      # TypeInfo 1
+; CHECK-NEXT:   .int[[PTR]]  _ZTIi             # TypeInfo 4
+; CHECK-NEXT:   .int[[PTR]]  _ZTIf             # TypeInfo 3
+; CHECK-NEXT:   .int[[PTR]]  _ZTId             # TypeInfo 2
+; CHECK-NEXT:   .int[[PTR]]  0                 # TypeInfo 1
 ; CHECK-NEXT: .Lttbase0:
 ; CHECK-NEXT:   .p2align  2
 ; CHECK-NEXT: .LGCC_except_table_end[[END:[0-9]+]]:


        


More information about the llvm-commits mailing list