sbc100 created this revision.
Herald added subscribers: cfe-commits, sunfish, aheejin, hiraditya, 
jgravelle-google, dschuff.
Herald added a project: clang.
sbc100 added reviewers: sunfish, kripken.

This matches the existing export-name attribute but exports that symbol
but its llvm symbol name.  This corresponds directly to the existing
WASM_SYMBOL_EXPORTED symbol flag.

This allows the existing emscripgten macro `EMSCERIPTEN_KEEPALIVE` to be
implemented in terms of this attribute rather then the current
workaround which uses the `used` attribute.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D76547

Files:
  clang/include/clang/Basic/Attr.td
  clang/include/clang/Basic/AttrDocs.td
  clang/lib/CodeGen/TargetInfo.cpp
  clang/lib/Sema/SemaDeclAttr.cpp
  clang/test/CodeGen/wasm-export.c
  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
  llvm/test/CodeGen/WebAssembly/export.ll

Index: llvm/test/CodeGen/WebAssembly/export.ll
===================================================================
--- /dev/null
+++ llvm/test/CodeGen/WebAssembly/export.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-exported" }
+attributes #1 = { "wasm-exported" }
+
+; CHECK: .export test
+; CHECK: .export test2
Index: llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp
===================================================================
--- llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp
+++ llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp
@@ -134,6 +134,12 @@
       }
     }
 
+    if (F.hasFnAttribute("wasm-exported")) {
+      auto *Sym = cast<MCSymbolWasm>(getSymbol(&F));
+      Sym->setExported();
+      getTargetStreamer()->emitExport(Sym);
+    }
+
     if (F.hasFnAttribute("wasm-export-name")) {
       auto *Sym = cast<MCSymbolWasm>(getSymbol(&F));
       StringRef Name = F.getFnAttribute("wasm-export-name").getValueAsString();
Index: llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.h
===================================================================
--- llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.h
+++ llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.h
@@ -51,6 +51,8 @@
   /// .export_name
   virtual void emitExportName(const MCSymbolWasm *Sym,
                               StringRef ExportName) = 0;
+  /// .export
+  virtual void emitExport(const MCSymbolWasm *Sym) = 0;
 
 protected:
   void emitValueType(wasm::ValType Type);
@@ -72,6 +74,7 @@
   void emitImportModule(const MCSymbolWasm *Sym, StringRef ImportModule) override;
   void emitImportName(const MCSymbolWasm *Sym, StringRef ImportName) override;
   void emitExportName(const MCSymbolWasm *Sym, StringRef ExportName) override;
+  void emitExport(const MCSymbolWasm *Sym) override;
 };
 
 /// This part is for Wasm object output
@@ -91,6 +94,7 @@
                       StringRef ImportName) override {}
   void emitExportName(const MCSymbolWasm *Sym,
                       StringRef ExportName) override {}
+  void emitExport(const MCSymbolWasm *Sym) override {}
 };
 
 /// This part is for null output
@@ -108,6 +112,7 @@
   void emitImportModule(const MCSymbolWasm *, StringRef) override {}
   void emitImportName(const MCSymbolWasm *, StringRef) override {}
   void emitExportName(const MCSymbolWasm *, StringRef) override {}
+  void emitExport(const MCSymbolWasm *) override {}
 };
 
 } // end namespace llvm
Index: llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.cpp
===================================================================
--- llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.cpp
+++ llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.cpp
@@ -100,6 +100,10 @@
                            << ExportName << '\n';
 }
 
+void WebAssemblyTargetAsmStreamer::emitExport(const MCSymbolWasm *Sym) {
+  OS << "\t.export\t" << Sym->getName() << '\n';
+}
+
 void WebAssemblyTargetAsmStreamer::emitIndIdx(const MCExpr *Value) {
   OS << "\t.indidx  \t" << *Value << '\n';
 }
Index: llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp
===================================================================
--- llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp
+++ llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp
@@ -717,6 +717,15 @@
       return expect(AsmToken::EndOfStatement, "EOL");
     }
 
+    if (DirectiveID.getString() == ".export") {
+      auto SymName = expectIdent();
+      if (SymName.empty())
+        return true;
+      auto WasmSym = cast<MCSymbolWasm>(Ctx.getOrCreateSymbol(SymName));
+      WasmSym->setExported();
+      TOut.emitExport(WasmSym);
+    }
+
     if (DirectiveID.getString() == ".export_name") {
       auto SymName = expectIdent();
       if (SymName.empty())
Index: clang/test/CodeGen/wasm-export.c
===================================================================
--- /dev/null
+++ clang/test/CodeGen/wasm-export.c
@@ -0,0 +1,13 @@
+// RUN: %clang_cc1 -triple wasm32-unknown-unknown-wasm -emit-llvm -o - %s | FileCheck %s
+
+int __attribute__((exported)) foo(void);
+
+int foo(void) {
+  return 43;
+}
+
+// CHECK: @llvm.used = appending global [1 x i8*] [i8* bitcast (i32 ()* @foo to i8*)]
+
+// CHECK: define i32 @foo() [[A:#[0-9]+]]
+
+// CHECK: attributes [[A]] = {{{.*}} "wasm-export" {{.*}}}
Index: clang/lib/Sema/SemaDeclAttr.cpp
===================================================================
--- clang/lib/Sema/SemaDeclAttr.cpp
+++ clang/lib/Sema/SemaDeclAttr.cpp
@@ -5845,6 +5845,23 @@
   D->addAttr(UsedAttr::CreateImplicit(S.Context));
 }
 
+static void handleWebAssemblyExportedAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
+  if (!isFunctionOrMethod(D)) {
+    S.Diag(D->getLocation(), diag::warn_attribute_wrong_decl_type)
+        << "'exported'" << ExpectedFunction;
+    return;
+  }
+
+  auto *FD = cast<FunctionDecl>(D);
+  if (FD->isThisDeclarationADefinition()) {
+    S.Diag(D->getLocation(), diag::err_alias_is_definition) << FD << 0;
+    return;
+  }
+
+  D->addAttr(::new (S.Context) WebAssemblyExportedAttr(S.Context, AL));
+  D->addAttr(UsedAttr::CreateImplicit(S.Context));
+}
+
 static void handleWebAssemblyImportModuleAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
   if (!isFunctionOrMethod(D)) {
     S.Diag(D->getLocation(), diag::warn_attribute_wrong_decl_type)
@@ -6807,6 +6824,9 @@
   case ParsedAttr::AT_WebAssemblyExportName:
     handleWebAssemblyExportNameAttr(S, D, AL);
     break;
+  case ParsedAttr::AT_WebAssemblyExported:
+    handleWebAssemblyExportedAttr(S, D, AL);
+    break;
   case ParsedAttr::AT_WebAssemblyImportModule:
     handleWebAssemblyImportModuleAttr(S, D, AL);
     break;
Index: clang/lib/CodeGen/TargetInfo.cpp
===================================================================
--- clang/lib/CodeGen/TargetInfo.cpp
+++ clang/lib/CodeGen/TargetInfo.cpp
@@ -777,24 +777,25 @@
                            CodeGen::CodeGenModule &CGM) const override {
     TargetCodeGenInfo::setTargetAttributes(D, GV, CGM);
     if (const auto *FD = dyn_cast_or_null<FunctionDecl>(D)) {
+      llvm::Function *Fn = cast<llvm::Function>(GV);
       if (const auto *Attr = FD->getAttr<WebAssemblyImportModuleAttr>()) {
-        llvm::Function *Fn = cast<llvm::Function>(GV);
         llvm::AttrBuilder B;
         B.addAttribute("wasm-import-module", Attr->getImportModule());
         Fn->addAttributes(llvm::AttributeList::FunctionIndex, B);
       }
       if (const auto *Attr = FD->getAttr<WebAssemblyImportNameAttr>()) {
-        llvm::Function *Fn = cast<llvm::Function>(GV);
         llvm::AttrBuilder B;
         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 (const auto *Attr = FD->getAttr<WebAssemblyExportedAttr>()) {
+        Fn->addFnAttr("wasm-exported");
+      }
     }
 
     if (auto *FD = dyn_cast_or_null<FunctionDecl>(D)) {
Index: clang/include/clang/Basic/AttrDocs.td
===================================================================
--- clang/include/clang/Basic/AttrDocs.td
+++ clang/include/clang/Basic/AttrDocs.td
@@ -4165,6 +4165,16 @@
   }];
 }
 
+def WebAssemblyExportedDocs : Documentation {
+  let Category = DocCatFunction;
+  let Content = [{
+Clang supports the ``__attribute__((exported))``
+attribute for the WebAssembly target. This attribute may be attached to a
+function declaration, where it causes the be exported from the linked
+WebAssembly module.
+  }];
+}
+
 def WebAssemblyImportModuleDocs : Documentation {
   let Category = DocCatFunction;
   let Content = [{
Index: clang/include/clang/Basic/Attr.td
===================================================================
--- clang/include/clang/Basic/Attr.td
+++ clang/include/clang/Basic/Attr.td
@@ -1646,6 +1646,13 @@
   let Subjects = SubjectList<[Function], ErrorDiag>;
 }
 
+def WebAssemblyExported : InheritableAttr,
+                          TargetSpecificAttr<TargetWebAssembly> {
+  let Spellings = [Clang<"exported">];
+  let Documentation = [WebAssemblyExportedDocs];
+  let Subjects = SubjectList<[Function], ErrorDiag>;
+}
+
 def WebAssemblyImportModule : InheritableAttr,
                               TargetSpecificAttr<TargetWebAssembly> {
   let Spellings = [Clang<"import_module">];
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to