diff options
21 files changed, 217 insertions, 15 deletions
diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td index 40e180f343e..47d9e641b17 100644 --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -1600,6 +1600,14 @@ def BPFPreserveAccessIndex : InheritableAttr,    let LangOpts = [COnly];  } +def WebAssemblyExportName : InheritableAttr, +                            TargetSpecificAttr<TargetWebAssembly> { +  let Spellings = [Clang<"export_name">]; +  let Args = [StringArgument<"ExportName">]; +  let Documentation = [WebAssemblyExportNameDocs]; +  let Subjects = SubjectList<[Function], ErrorDiag>; +} +  def WebAssemblyImportModule : InheritableAttr,                                TargetSpecificAttr<TargetWebAssembly> {    let Spellings = [Clang<"import_module">]; diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td index 764ac248535..c632e52b28d 100644 --- a/clang/include/clang/Basic/AttrDocs.td +++ b/clang/include/clang/Basic/AttrDocs.td @@ -4101,6 +4101,21 @@ For more information see  or `msvc documentation <https://docs.microsoft.com/pl-pl/cpp/cpp/selectany>`_.  }]; } +def WebAssemblyExportNameDocs : Documentation { +  let Category = DocCatFunction; +  let Content = [{ +Clang supports the ``__attribute__((export_name(<name>)))`` +attribute for the WebAssembly target. This attribute may be attached to a +function declaration, where it modifies how the symbol is to be exported +from the linked WebAssembly. + +WebAssembly functions are exported via string name. By default when a symbol +is exported, the export name for C/C++ symbols are the same as their C/C++ +symbol names. This attribute can be used to override the default behavior, and +request a specific string name be used instead. +  }]; +} +  def WebAssemblyImportModuleDocs : Documentation {    let Category = DocCatFunction;    let Content = [{ diff --git a/clang/lib/CodeGen/TargetInfo.cpp b/clang/lib/CodeGen/TargetInfo.cpp index 33e7b18d839..9fd4a5fb17a 100644 --- a/clang/lib/CodeGen/TargetInfo.cpp +++ b/clang/lib/CodeGen/TargetInfo.cpp @@ -779,6 +779,12 @@ public:          B.addAttribute("wasm-import-name", Attr->getImportName());          Fn->addAttributes(llvm::AttributeList::FunctionIndex, B);        } +      if (const auto *Attr = FD->getAttr<WebAssemblyExportNameAttr>()) { +        llvm::Function *Fn = cast<llvm::Function>(GV); +        llvm::AttrBuilder B; +        B.addAttribute("wasm-export-name", Attr->getExportName()); +        Fn->addAttributes(llvm::AttributeList::FunctionIndex, B); +      }      }      if (auto *FD = dyn_cast_or_null<FunctionDecl>(D)) { diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index 60a99803689..e83688c46be 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -5754,6 +5754,28 @@ static void handleBPFPreserveAccessIndexAttr(Sema &S, Decl *D,    Rec->addAttr(::new (S.Context) BPFPreserveAccessIndexAttr(S.Context, AL));  } +static void handleWebAssemblyExportNameAttr(Sema &S, Decl *D, const ParsedAttr &AL) { +  if (!isFunctionOrMethod(D)) { +    S.Diag(D->getLocation(), diag::warn_attribute_wrong_decl_type) +        << "'export_name'" << ExpectedFunction; +    return; +  } + +  auto *FD = cast<FunctionDecl>(D); +  if (FD->isThisDeclarationADefinition()) { +    S.Diag(D->getLocation(), diag::err_alias_is_definition) << FD << 0; +    return; +  } + +  StringRef Str; +  SourceLocation ArgLoc; +  if (!S.checkStringLiteralArgumentAttr(AL, 0, Str, &ArgLoc)) +    return; + +  FD->addAttr(::new (S.Context) +                  WebAssemblyExportNameAttr(S.Context, AL, Str)); +} +  static void handleWebAssemblyImportModuleAttr(Sema &S, Decl *D, const ParsedAttr &AL) {    if (!isFunctionOrMethod(D)) {      S.Diag(D->getLocation(), diag::warn_attribute_wrong_decl_type) @@ -6672,6 +6694,9 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,    case ParsedAttr::AT_BPFPreserveAccessIndex:      handleBPFPreserveAccessIndexAttr(S, D, AL);      break; +  case ParsedAttr::AT_WebAssemblyExportName: +    handleWebAssemblyExportNameAttr(S, D, AL); +    break;    case ParsedAttr::AT_WebAssemblyImportModule:      handleWebAssemblyImportModuleAttr(S, D, AL);      break; diff --git a/clang/test/CodeGen/wasm-export-name.c b/clang/test/CodeGen/wasm-export-name.c new file mode 100644 index 00000000000..b662a272cba --- /dev/null +++ b/clang/test/CodeGen/wasm-export-name.c @@ -0,0 +1,11 @@ +// RUN: %clang_cc1 -triple wasm32-unknown-unknown-wasm -emit-llvm -o - %s | FileCheck %s + +int __attribute__((export_name("bar"))) foo(void); + +int foo(void) { +  return 43; +} + +// CHECK: define i32 @foo() [[A:#[0-9]+]] + +// CHECK: attributes [[A]] = {{{.*}} "wasm-export-name"="bar" {{.*}}} diff --git a/clang/test/Misc/pragma-attribute-supported-attributes-list.test b/clang/test/Misc/pragma-attribute-supported-attributes-list.test index 2effc52eb98..dc2d668aaa1 100644 --- a/clang/test/Misc/pragma-attribute-supported-attributes-list.test +++ b/clang/test/Misc/pragma-attribute-supported-attributes-list.test @@ -151,6 +151,7 @@  // CHECK-NEXT: WarnUnusedResult (SubjectMatchRule_objc_method, SubjectMatchRule_enum, SubjectMatchRule_record, SubjectMatchRule_hasType_functionType)  // CHECK-NEXT: Weak (SubjectMatchRule_variable, SubjectMatchRule_function, SubjectMatchRule_record)  // CHECK-NEXT: WeakRef (SubjectMatchRule_variable, SubjectMatchRule_function) +// CHECK-NEXT: WebAssemblyExportName (SubjectMatchRule_function)  // CHECK-NEXT: WebAssemblyImportModule (SubjectMatchRule_function)  // CHECK-NEXT: WebAssemblyImportName (SubjectMatchRule_function)  // CHECK-NEXT: WorkGroupSizeHint (SubjectMatchRule_function) diff --git a/lld/docs/WebAssembly.rst b/lld/docs/WebAssembly.rst index 6384a929d23..92bae2aea32 100644 --- a/lld/docs/WebAssembly.rst +++ b/lld/docs/WebAssembly.rst @@ -42,8 +42,8 @@ WebAssembly-specific options:  .. option:: --export-dynamic    When building an executable, export any non-hidden symbols.  By default only -  the entry point and any symbols marked with --export/--export-all are -  exported. +  the entry point and any symbols marked as exports (either via the command line +  or via the `export-name` source attribute) are exported.  .. option:: --global-base=<value> @@ -116,16 +116,18 @@ Imports and Exports  ~~~~~~~~~~~~~~~~~~~  When building a shared library any symbols marked as ``visibility=default`` will -be exported.  When building an executable, only the entry point and symbols -flagged as ``WASM_SYMBOL_EXPORTED`` are exported by default.  In LLVM the -``WASM_SYMBOL_EXPORTED`` flag is applied to any symbol in the ``llvm.used`` list -which corresponds to ``__attribute__((used))`` in C/C++ sources. +be exported. + +When building an executable, only the entry point (``_start``) and symbols with +the ``WASM_SYMBOL_EXPORTED`` flag are exported by default.  In LLVM the +``WASM_SYMBOL_EXPORTED`` flag is set by the ``wasm-export-name`` attribute which +in turn can be set using ``__attribute__((export_name))`` clang attribute.  In addition, symbols can be exported via the linker command line using  ``--export``.  Finally, just like with native ELF linker the ``--export-dynamic`` flag can be -used to export symbol in the executable which are marked as +used to export symbols in the executable which are marked as  ``visibility=default``.  Garbage Collection diff --git a/lld/test/wasm/export-name.ll b/lld/test/wasm/export-name.ll new file mode 100644 index 00000000000..83a8bd907c7 --- /dev/null +++ b/lld/test/wasm/export-name.ll @@ -0,0 +1,28 @@ +; RUN: llc -filetype=obj %s -o %t.o +; RUN: wasm-ld -o %t.wasm %t.o +; RUN: obj2yaml %t.wasm | FileCheck %s + +target triple = "wasm32-unknown-unknown" + +define void @foo() #0 { +    ret void +} + +define void @_start() { +    call void @foo() +    ret void +} + +attributes #0 = { "wasm-export-name"="bar" } + +; CHECK:       - Type:            EXPORT +; CHECK-NEXT:    Exports: +; CHECK-NEXT:      - Name:            memory +; CHECK-NEXT:        Kind:            MEMORY +; CHECK-NEXT:        Index:           0 +; CHECK-NEXT:      - Name:            bar +; CHECK-NEXT:        Kind:            FUNCTION +; CHECK-NEXT:        Index:           0 +; CHECK-NEXT:      - Name:            _start +; CHECK-NEXT:        Kind:            FUNCTION +; CHECK-NEXT:        Index:           1 diff --git a/lld/wasm/InputChunks.h b/lld/wasm/InputChunks.h index 2d3eb40f807..5d4aebd2902 100644 --- a/lld/wasm/InputChunks.h +++ b/lld/wasm/InputChunks.h @@ -130,6 +130,9 @@ public:    void writeTo(uint8_t *sectionStart) const override;    StringRef getName() const override { return function->SymbolName; }    StringRef getDebugName() const override { return function->DebugName; } +  StringRef getExportName() const { +    return function ? function->ExportName : ""; +  }    uint32_t getComdat() const override { return function->Comdat; }    uint32_t getFunctionInputOffset() const { return getInputSectionOffset(); }    uint32_t getFunctionCodeOffset() const { return function->CodeOffset; } diff --git a/lld/wasm/Writer.cpp b/lld/wasm/Writer.cpp index 5df3ae68e30..bd7bd7e6f7e 100644 --- a/lld/wasm/Writer.cpp +++ b/lld/wasm/Writer.cpp @@ -519,6 +519,10 @@ void Writer::calculateExports() {      StringRef name = sym->getName();      WasmExport export_;      if (auto *f = dyn_cast<DefinedFunction>(sym)) { +      StringRef exportName = f->function->getExportName(); +      if (!exportName.empty()) { +        name = exportName; +      }        export_ = {name, WASM_EXTERNAL_FUNCTION, f->getFunctionIndex()};      } else if (auto *g = dyn_cast<DefinedGlobal>(sym)) {        // TODO(sbc): Remove this check once to mutable global proposal is diff --git a/llvm/include/llvm/BinaryFormat/Wasm.h b/llvm/include/llvm/BinaryFormat/Wasm.h index f550d880f68..59f99cc8cd3 100644 --- a/llvm/include/llvm/BinaryFormat/Wasm.h +++ b/llvm/include/llvm/BinaryFormat/Wasm.h @@ -131,6 +131,7 @@ struct WasmFunction {    uint32_t CodeSectionOffset;    uint32_t Size;    uint32_t CodeOffset;  // start of Locals and Body +  StringRef ExportName; // from the "export" section    StringRef SymbolName; // from the "linking" section    StringRef DebugName;  // from the "name" section    uint32_t Comdat;      // from the "comdat info" section @@ -179,6 +180,7 @@ struct WasmSymbolInfo {    uint32_t Flags;    StringRef ImportModule; // For undefined symbols the module of the import    StringRef ImportName;   // For undefined symbols the name of the import +  StringRef ExportName;   // For symbols to be exported from the final module    union {      // For function or global symbols, the index in function or global index      // space. diff --git a/llvm/include/llvm/MC/MCSymbolWasm.h b/llvm/include/llvm/MC/MCSymbolWasm.h index c60d4069a55..ba2068a4607 100644 --- a/llvm/include/llvm/MC/MCSymbolWasm.h +++ b/llvm/include/llvm/MC/MCSymbolWasm.h @@ -21,6 +21,7 @@ class MCSymbolWasm : public MCSymbol {    mutable bool IsUsedInGOT = false;    Optional<std::string> ImportModule;    Optional<std::string> ImportName; +  Optional<std::string> ExportName;    wasm::WasmSignature *Signature = nullptr;    Optional<wasm::WasmGlobalType> GlobalType;    Optional<wasm::WasmEventType> EventType; @@ -87,6 +88,10 @@ public:    }    void setImportName(StringRef Name) { ImportName = Name; } +  bool hasExportName() const { return ExportName.hasValue(); } +  const StringRef getExportName() const { return ExportName.getValue(); } +  void setExportName(StringRef Name) { ExportName = Name; } +    void setUsedInGOT() const { IsUsedInGOT = true; }    bool isUsedInGOT() const { return IsUsedInGOT; } diff --git a/llvm/include/llvm/Object/Wasm.h b/llvm/include/llvm/Object/Wasm.h index e130ea32ed2..8af94c4963b 100644 --- a/llvm/include/llvm/Object/Wasm.h +++ b/llvm/include/llvm/Object/Wasm.h @@ -280,6 +280,7 @@ private:    uint32_t StartFunction = -1;    bool HasLinkingSection = false;    bool HasDylinkSection = false; +  bool SeenCodeSection = false;    wasm::WasmLinkingData LinkingData;    uint32_t NumImportedGlobals = 0;    uint32_t NumImportedFunctions = 0; diff --git a/llvm/lib/MC/WasmObjectWriter.cpp b/llvm/lib/MC/WasmObjectWriter.cpp index b22a393fcd4..321f93d7609 100644 --- a/llvm/lib/MC/WasmObjectWriter.cpp +++ b/llvm/lib/MC/WasmObjectWriter.cpp @@ -1324,6 +1324,14 @@ uint64_t WasmObjectWriter::writeObject(MCAssembler &Asm,            Comdats[C->getName()].emplace_back(                WasmComdatEntry{wasm::WASM_COMDAT_FUNCTION, Index});          } + +        if (WS.hasExportName()) { +          wasm::WasmExport Export; +          Export.Name = WS.getExportName(); +          Export.Kind = wasm::WASM_EXTERNAL_FUNCTION; +          Export.Index = Index; +          Exports.push_back(Export); +        }        } else {          // An import; the index was assigned above.          Index = WasmIndices.find(&WS)->second; @@ -1454,6 +1462,8 @@ uint64_t WasmObjectWriter::writeObject(MCAssembler &Asm,      }      if (WS.hasImportName())        Flags |= wasm::WASM_SYMBOL_EXPLICIT_NAME; +    if (WS.hasExportName()) +      Flags |= wasm::WASM_SYMBOL_EXPORTED;      wasm::WasmSymbolInfo Info;      Info.Name = WS.getName(); diff --git a/llvm/lib/Object/WasmObjectFile.cpp b/llvm/lib/Object/WasmObjectFile.cpp index 014b403556d..ab8918ce191 100644 --- a/llvm/lib/Object/WasmObjectFile.cpp +++ b/llvm/lib/Object/WasmObjectFile.cpp @@ -343,7 +343,7 @@ Error WasmObjectFile::parseDylinkSection(ReadContext &Ctx) {  Error WasmObjectFile::parseNameSection(ReadContext &Ctx) {    llvm::DenseSet<uint64_t> Seen; -  if (Functions.size() != FunctionTypes.size()) { +  if (FunctionTypes.size() && !SeenCodeSection) {      return make_error<GenericBinaryError>("Names must come after code section",                                            object_error::parse_failed);    } @@ -389,7 +389,7 @@ Error WasmObjectFile::parseNameSection(ReadContext &Ctx) {  Error WasmObjectFile::parseLinkingSection(ReadContext &Ctx) {    HasLinkingSection = true; -  if (Functions.size() != FunctionTypes.size()) { +  if (FunctionTypes.size() && !SeenCodeSection) {      return make_error<GenericBinaryError>(          "Linking data must come after code section",          object_error::parse_failed); @@ -940,6 +940,7 @@ Error WasmObjectFile::parseImportSection(ReadContext &Ctx) {  Error WasmObjectFile::parseFunctionSection(ReadContext &Ctx) {    uint32_t Count = readVaruint32(Ctx);    FunctionTypes.reserve(Count); +  Functions.resize(Count);    uint32_t NumTypes = Signatures.size();    while (Count--) {      uint32_t Type = readVaruint32(Ctx); @@ -1029,9 +1030,11 @@ Error WasmObjectFile::parseExportSection(ReadContext &Ctx) {      Ex.Index = readVaruint32(Ctx);      switch (Ex.Kind) {      case wasm::WASM_EXTERNAL_FUNCTION: -      if (!isValidFunctionIndex(Ex.Index)) + +      if (!isDefinedFunctionIndex(Ex.Index))          return make_error<GenericBinaryError>("Invalid function export",                                                object_error::parse_failed); +      getDefinedFunction(Ex.Index).ExportName = Ex.Name;        break;      case wasm::WASM_EXTERNAL_GLOBAL:        if (!isValidGlobalIndex(Ex.Index)) @@ -1132,6 +1135,7 @@ Error WasmObjectFile::parseStartSection(ReadContext &Ctx) {  }  Error WasmObjectFile::parseCodeSection(ReadContext &Ctx) { +  SeenCodeSection = true;    CodeSection = Sections.size();    uint32_t FunctionCount = readVaruint32(Ctx);    if (FunctionCount != FunctionTypes.size()) { @@ -1139,14 +1143,14 @@ Error WasmObjectFile::parseCodeSection(ReadContext &Ctx) {                                            object_error::parse_failed);    } -  while (FunctionCount--) { -    wasm::WasmFunction Function; +  for (uint32_t i = 0; i < FunctionCount; i++) { +    wasm::WasmFunction& Function = Functions[i];      const uint8_t *FunctionStart = Ctx.Ptr;      uint32_t Size = readVaruint32(Ctx);      const uint8_t *FunctionEnd = Ctx.Ptr + Size;      Function.CodeOffset = Ctx.Ptr - FunctionStart; -    Function.Index = NumImportedFunctions + Functions.size(); +    Function.Index = NumImportedFunctions + i;      Function.CodeSectionOffset = FunctionStart - Ctx.Start;      Function.Size = FunctionEnd - FunctionStart; @@ -1165,7 +1169,6 @@ Error WasmObjectFile::parseCodeSection(ReadContext &Ctx) {      Function.Comdat = UINT32_MAX;      Ctx.Ptr += BodySize;      assert(Ctx.Ptr == FunctionEnd); -    Functions.push_back(Function);    }    if (Ctx.Ptr != Ctx.End)      return make_error<GenericBinaryError>("Code section ended prematurely", diff --git a/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp b/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp index 138ce85a23f..1f0bdde0c93 100644 --- a/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp +++ b/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp @@ -712,6 +712,18 @@ public:        return expect(AsmToken::EndOfStatement, "EOL");      } +    if (DirectiveID.getString() == ".export_name") { +      auto SymName = expectIdent(); +      if (SymName.empty()) +        return true; +      if (expect(AsmToken::Comma, ",")) +        return true; +      auto ExportName = expectIdent(); +      auto WasmSym = cast<MCSymbolWasm>(Ctx.getOrCreateSymbol(SymName)); +      WasmSym->setExportName(ExportName); +      TOut.emitExportName(WasmSym, ExportName); +    } +      if (DirectiveID.getString() == ".import_module") {        auto SymName = expectIdent();        if (SymName.empty()) diff --git a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.cpp b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.cpp index 40926201931..7c21ed5f974 100644 --- a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.cpp +++ b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.cpp @@ -94,6 +94,12 @@ void WebAssemblyTargetAsmStreamer::emitImportName(const MCSymbolWasm *Sym,                             << ImportName << '\n';  } +void WebAssemblyTargetAsmStreamer::emitExportName(const MCSymbolWasm *Sym, +                                                  StringRef ExportName) { +  OS << "\t.export_name\t" << Sym->getName() << ", " +                           << ExportName << '\n'; +} +  void WebAssemblyTargetAsmStreamer::emitIndIdx(const MCExpr *Value) {    OS << "\t.indidx  \t" << *Value << '\n';  } diff --git a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.h b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.h index 0164f8e572e..9aee1a06c95 100644 --- a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.h +++ b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.h @@ -48,6 +48,9 @@ public:    /// .import_name    virtual void emitImportName(const MCSymbolWasm *Sym,                                StringRef ImportName) = 0; +  /// .export_name +  virtual void emitExportName(const MCSymbolWasm *Sym, +                              StringRef ExportName) = 0;  protected:    void emitValueType(wasm::ValType Type); @@ -68,6 +71,7 @@ public:    void emitEventType(const MCSymbolWasm *Sym) override;    void emitImportModule(const MCSymbolWasm *Sym, StringRef ImportModule) override;    void emitImportName(const MCSymbolWasm *Sym, StringRef ImportName) override; +  void emitExportName(const MCSymbolWasm *Sym, StringRef ExportName) override;  };  /// This part is for Wasm object output @@ -85,6 +89,8 @@ public:                          StringRef ImportModule) override {}    void emitImportName(const MCSymbolWasm *Sym,                        StringRef ImportName) override {} +  void emitExportName(const MCSymbolWasm *Sym, +                      StringRef ExportName) override {}  };  /// This part is for null output @@ -101,6 +107,7 @@ public:    void emitEventType(const MCSymbolWasm *) override {}    void emitImportModule(const MCSymbolWasm *, StringRef) override {}    void emitImportName(const MCSymbolWasm *, StringRef) override {} +  void emitExportName(const MCSymbolWasm *, StringRef) override {}  };  } // end namespace llvm diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp index 5d8b873ce23..cb95d5dbfc0 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp @@ -96,8 +96,11 @@ void WebAssemblyAsmPrinter::EmitEndOfAsmFile(Module &M) {    }    for (const auto &F : M) { +    if (F.isIntrinsic()) +      continue; +      // Emit function type info for all undefined functions -    if (F.isDeclarationForLinker() && !F.isIntrinsic()) { +    if (F.isDeclarationForLinker()) {        SmallVector<MVT, 4> Results;        SmallVector<MVT, 4> Params;        computeSignatureVTs(F.getFunctionType(), F, TM, Params, Results); @@ -130,6 +133,13 @@ void WebAssemblyAsmPrinter::EmitEndOfAsmFile(Module &M) {          getTargetStreamer()->emitImportName(Sym, Name);        }      } + +    if (F.hasFnAttribute("wasm-export-name")) { +      auto *Sym = cast<MCSymbolWasm>(getSymbol(&F)); +      StringRef Name = F.getFnAttribute("wasm-export-name").getValueAsString(); +      Sym->setExportName(Name); +      getTargetStreamer()->emitExportName(Sym, Name); +    }    }    for (const auto &G : M.globals()) { diff --git a/llvm/test/CodeGen/WebAssembly/export-name.ll b/llvm/test/CodeGen/WebAssembly/export-name.ll new file mode 100644 index 00000000000..d1d4c2115eb --- /dev/null +++ b/llvm/test/CodeGen/WebAssembly/export-name.ll @@ -0,0 +1,17 @@ +; RUN: llc < %s -asm-verbose=false -wasm-keep-registers | FileCheck %s + +target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128" +target triple = "wasm32-unknown-unknown" + +define void @test() #0 { +  ret void +} + +declare void @test2() #1 + + +attributes #0 = { "wasm-export-name"="foo" } +attributes #1 = { "wasm-export-name"="bar" } + +; CHECK: .export_name test, foo +; CHECK: .export_name test2, bar diff --git a/llvm/test/MC/WebAssembly/export-name.s b/llvm/test/MC/WebAssembly/export-name.s new file mode 100644 index 00000000000..51e1bcf73db --- /dev/null +++ b/llvm/test/MC/WebAssembly/export-name.s @@ -0,0 +1,26 @@ +# RUN: llvm-mc -triple=wasm32-unknown-unknown < %s | FileCheck %s +# Check that it also comiled to object for format. +# RUN: llvm-mc -triple=wasm32-unknown-unknown -filetype=obj -o - < %s | obj2yaml | FileCheck -check-prefix=CHECK-OBJ %s + +foo: +    .globl foo +    .functype foo () -> () +    .export_name foo, bar +    end_function + +# CHECK: .export_name foo, bar + +# CHECK-OBJ:        - Type:            EXPORT +# CHECK-OBJ-NEXT:     Exports: +# CHECK-OBJ-NEXT:       - Name:            bar +# CHECK-OBJ-NEXT:         Kind:            FUNCTION +# CHECK-OBJ-NEXT:         Index:           0 + +# CHECK-OBJ:          Name:            linking +# CHECK-OBJ-NEXT:     Version:         2 +# CHECK-OBJ-NEXT:     SymbolTable: +# CHECK-OBJ-NEXT:       - Index:           0 +# CHECK-OBJ-NEXT:         Kind:            FUNCTION +# CHECK-OBJ-NEXT:         Name:            foo +# CHECK-OBJ-NEXT:         Flags:           [ EXPORTED ] +# CHECK-OBJ-NEXT:         Function:        0  | 

