[WebAssembly] Make EH work with dynamic linking
authorHeejin Ahn <aheejin@gmail.com>
Wed, 29 Sep 2021 21:17:14 +0000 (14:17 -0700)
committerHeejin Ahn <aheejin@gmail.com>
Wed, 13 Oct 2021 06:28:27 +0000 (23:28 -0700)
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

17 files changed:
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

index 89d9e87162f5a9a49829ce81f3d02bc6f921bc0c..253fc4a4480bf201e38f8d351aa9b590dce9a313 100644 (file)
@@ -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*)
 
index 3499db9298afa0250f59137c33accb3187e73e1f..6b82c858bcc852b7054277158d5bd036a7ba88cc 100644 (file)
@@ -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*)
 
index 1f6aa9d737892312c2805218c5c1719455279c19..4f55f881aedc2f98824834d07a719f8655265e58 100644 (file)
@@ -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
index 9e7f1ca18831fb6b22e9d07c13313bd8696725bf..29bc0b32d9658981a064b65f52d47ee2203957c4 100644 (file)
@@ -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");
   }
index 877909c23c5913ddf4bea77d564bbc626b2e16d3..b204fae451a94d4ab92ecf47d6ea308fe431c5b2 100644 (file)
@@ -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>();
index aea2f164928a55aa3088fc87db652487468a066e..c2a3ee34ac3f84984d898523941a55078996d1f5 100644 (file)
@@ -79,6 +79,10 @@ public:
                             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);
 
index 4658b8248b1332dbd50f7e10a869454eaa4be4e8..79bec1025a254fc67f15d31fad8d8172e35795f2 100644 (file)
@@ -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;
index 54f7b6100eed47ea3d7cd6da34340a5ed5d19f49..342ebcf1a6e9f22dea828a89bcce9d2d5dcca397 100644 (file)
@@ -55,6 +55,7 @@ public:
     UndefinedDataKind,
     UndefinedGlobalKind,
     UndefinedTableKind,
+    UndefinedTagKind,
     LazyKind,
   };
 
@@ -66,7 +67,7 @@ public:
     return symbolKind == UndefinedFunctionKind ||
            symbolKind == UndefinedDataKind ||
            symbolKind == UndefinedGlobalKind ||
-           symbolKind == UndefinedTableKind;
+           symbolKind == UndefinedTableKind || symbolKind == UndefinedTagKind;
   }
 
   bool isLazy() const { return symbolKind == LazyKind; }
@@ -437,7 +438,9 @@ public:
 // 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 @@ public:
   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.
index d70ade4a5a892b7eb230108f8e29a6d866ebacc9..be1a82b9f5d8c3138c652b6b0064b8b23afd6030 100644 (file)
@@ -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);
index 421bbabe0e1b26f5c2d5354eee7481f04e1d7ad9..4caab9d4a3c7f7d1ba52ba57f49219f7befc517d 100644 (file)
@@ -198,6 +198,7 @@ protected:
   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 {
index a833afd5c1d00956f3639c5a8efe9d366964f29d..a17a2ca2790e7ddeb89e8025b6f4057a33491cef 100644 (file)
@@ -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);
+      }
     }
   }
 }
index a6a47489b8d241741c196b38f111a8e6403fd326..ed23c5338124657917183e4de6eadd07f46cdb96 100644 (file)
@@ -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);
index 24146ca61d05f0d5303a42784bdd77f0cbff84da..66acd3519623ed1cecdcdbc3bd6a99b546a361f9 100644 (file)
@@ -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
index 6284a3c39b505834e6571571a39d56bbd5408262..7bc8ebcdcdb74fa949ac83d2709a7d5df08f3aa9 100644 (file)
@@ -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: {
index 55ebc220f4094e1e6e2fd1c609989e8005d64b1a..ee9247a8bef95a8b051617bf12c935b350f1d75c 100644 (file)
@@ -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.
index 8c6f57168341d5f52e0a7730fffc97cb073da5ec..105c24ad8e46e12a883a1c06f48330e3629dea8d 100644 (file)
@@ -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());
index 15cb4e9e7f19f105fc7e4956b20280f22882844e..78bfe5be2d967725dc1b5e8320e8ad7735029bb6 100644 (file)
@@ -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@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@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]+]]: