[lld] 881d877 - [WebAssembly] Add new `export_name` clang attribute for controlling wasm export names
Sam Clegg via llvm-commits
llvm-commits at lists.llvm.org
Wed Dec 11 11:55:53 PST 2019
Author: Sam Clegg
Date: 2019-12-11T11:54:57-08:00
New Revision: 881d877846e2904c731d616731969421ce8cc825
URL: https://github.com/llvm/llvm-project/commit/881d877846e2904c731d616731969421ce8cc825
DIFF: https://github.com/llvm/llvm-project/commit/881d877846e2904c731d616731969421ce8cc825.diff
LOG: [WebAssembly] Add new `export_name` clang attribute for controlling wasm export names
This is equivalent to the existing `import_name` and `import_module`
attributes which control the import names in the final wasm binary
produced by lld.
This maps the existing
This attribute currently requires a string rather than using the
symbol name for a couple of reasons:
1. Avoid confusion with static and dynamic linking which is
based on symbol name. Exporting a function from a wasm module using
this directive is orthogonal to both static and dynamic linking.
2. Avoids name mangling.
Differential Revision: https://reviews.llvm.org/D70520
Added:
clang/test/CodeGen/wasm-export-name.c
lld/test/wasm/export-name.ll
llvm/test/CodeGen/WebAssembly/export-name.ll
llvm/test/MC/WebAssembly/export-name.s
Modified:
clang/include/clang/Basic/Attr.td
clang/include/clang/Basic/AttrDocs.td
clang/lib/CodeGen/TargetInfo.cpp
clang/lib/Sema/SemaDeclAttr.cpp
clang/test/Misc/pragma-attribute-supported-attributes-list.test
lld/docs/WebAssembly.rst
lld/wasm/InputChunks.h
lld/wasm/Writer.cpp
llvm/include/llvm/BinaryFormat/Wasm.h
llvm/include/llvm/MC/MCSymbolWasm.h
llvm/include/llvm/Object/Wasm.h
llvm/lib/MC/WasmObjectWriter.cpp
llvm/lib/Object/WasmObjectFile.cpp
llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp
llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.cpp
llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.h
llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp
Removed:
################################################################################
diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td
index 40e180f343e7..47d9e641b178 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 764ac2485350..c632e52b28d1 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 33e7b18d8393..9fd4a5fb17a7 100644
--- a/clang/lib/CodeGen/TargetInfo.cpp
+++ b/clang/lib/CodeGen/TargetInfo.cpp
@@ -779,6 +779,12 @@ class WebAssemblyTargetCodeGenInfo final : public TargetCodeGenInfo {
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 60a998036899..e83688c46be1 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 000000000000..b662a272cbac
--- /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 2effc52eb982..dc2d668aaa16 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 6384a929d23d..92bae2aea32c 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 000000000000..83a8bd907c79
--- /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 2d3eb40f807e..5d4aebd2902c 100644
--- a/lld/wasm/InputChunks.h
+++ b/lld/wasm/InputChunks.h
@@ -130,6 +130,9 @@ class InputFunction : public InputChunk {
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 5df3ae68e307..bd7bd7e6f7e6 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 f550d880f68a..59f99cc8cd37 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 c60d4069a559..ba2068a46071 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 @@ class MCSymbolWasm : public MCSymbol {
}
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 e130ea32ed21..8af94c4963b6 100644
--- a/llvm/include/llvm/Object/Wasm.h
+++ b/llvm/include/llvm/Object/Wasm.h
@@ -280,6 +280,7 @@ class WasmObjectFile : public ObjectFile {
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 b22a393fcd4d..321f93d76092 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 014b403556df..ab8918ce1919 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 138ce85a23fc..1f0bdde0c93e 100644
--- a/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp
+++ b/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp
@@ -712,6 +712,18 @@ class WebAssemblyAsmParser final : public MCTargetAsmParser {
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 40926201931a..7c21ed5f974e 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 0164f8e572ef..9aee1a06c956 100644
--- a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.h
+++ b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.h
@@ -48,6 +48,9 @@ class WebAssemblyTargetStreamer : public MCTargetStreamer {
/// .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 @@ class WebAssemblyTargetAsmStreamer final : public WebAssemblyTargetStreamer {
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 @@ class WebAssemblyTargetWasmStreamer final : public WebAssemblyTargetStreamer {
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 @@ class WebAssemblyTargetNullStreamer final : public WebAssemblyTargetStreamer {
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 5d8b873ce23b..cb95d5dbfc06 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 000000000000..d1d4c2115ebe
--- /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 000000000000..51e1bcf73dba
--- /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
More information about the llvm-commits
mailing list