From cae8459ad2d4cce5806bc8d64ef0020bc20e3252 Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Fri, 1 Feb 2019 22:25:23 +0000 Subject: [PATCH] [WebAssembly] Add an import_field function attribute This is similar to import_module, but sets the import field name instead. By default, the import field name is the same as the C/asm/.o symbol name. However, there are situations where it's useful to have it be different. For example, suppose I have a wasm API with a module named "pwsix" and a field named "read". There's no risk of namespace collisions with user code at the wasm level because the generic name "read" is qualified by the module name "pwsix". However in the C/asm/.o namespaces, the module name is not used, so if I have a global function named "read", it is intruding on the user's namespace. With the import_field module, I can declare my function (in libc) to be "__read", and then set the wasm import module to be "pwsix" and the wasm import field to be "read". So at the C/asm/.o levels, my symbol is outside the user namespace. Differential Revision: https://reviews.llvm.org/D57602 llvm-svn: 352930 --- clang/include/clang/Basic/Attr.td | 10 ++++++++- clang/include/clang/Basic/AttrDocs.td | 17 ++++++++++++++ clang/lib/CodeGen/TargetInfo.cpp | 8 ++++++- clang/lib/Sema/SemaDeclAttr.cpp | 26 ++++++++++++++++++++++ clang/test/CodeGen/wasm-import-name.c | 11 +++++++++ ...pragma-attribute-supported-attributes-list.test | 1 + 6 files changed, 71 insertions(+), 2 deletions(-) create mode 100644 clang/test/CodeGen/wasm-import-name.c diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td index b0bc731..3b7b0b0 100644 --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -1514,11 +1514,19 @@ def AMDGPUNumVGPR : InheritableAttr { def WebAssemblyImportModule : InheritableAttr, TargetSpecificAttr { let Spellings = [Clang<"import_module">]; - let Args = [StringArgument<"ImportModuleName">]; + let Args = [StringArgument<"ImportModule">]; let Documentation = [WebAssemblyImportModuleDocs]; let Subjects = SubjectList<[Function], ErrorDiag>; } +def WebAssemblyImportName : InheritableAttr, + TargetSpecificAttr { + let Spellings = [Clang<"import_name">]; + let Args = [StringArgument<"ImportName">]; + let Documentation = [WebAssemblyImportNameDocs]; + let Subjects = SubjectList<[Function], ErrorDiag>; +} + def NoSplitStack : InheritableAttr { let Spellings = [GCC<"no_split_stack">]; let Subjects = SubjectList<[Function], ErrorDiag>; diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td index c9efa78..d316993 100644 --- a/clang/include/clang/Basic/AttrDocs.td +++ b/clang/include/clang/Basic/AttrDocs.td @@ -3730,6 +3730,23 @@ reuqest a specific module name be used instead. }]; } +def WebAssemblyImportNameDocs : Documentation { + let Category = DocCatFunction; + let Content = [{ +Clang supports the ``__attribute__((import_name()))`` +attribute for the WebAssembly target. This attribute may be attached to a +function declaration, where it modifies how the symbol is to be imported +within the WebAssembly linking environment. + +WebAssembly imports use a two-level namespace scheme, consisting of a module +name, which typically identifies a module from which to import, and a field +name, which typically identifies a field from that module to import. By +default, field names for C/C++ symbols are the same as their C/C++ symbol +names. This attribute can be used to override the default behavior, and +reuqest a specific field name be used instead. + }]; +} + def ArtificialDocs : Documentation { let Category = DocCatFunction; let Content = [{ diff --git a/clang/lib/CodeGen/TargetInfo.cpp b/clang/lib/CodeGen/TargetInfo.cpp index 675838e..d04a012 100644 --- a/clang/lib/CodeGen/TargetInfo.cpp +++ b/clang/lib/CodeGen/TargetInfo.cpp @@ -765,7 +765,13 @@ public: if (const auto *Attr = FD->getAttr()) { llvm::Function *Fn = cast(GV); llvm::AttrBuilder B; - B.addAttribute("wasm-import-module", Attr->getImportModuleName()); + B.addAttribute("wasm-import-module", Attr->getImportModule()); + Fn->addAttributes(llvm::AttributeList::FunctionIndex, B); + } + if (const auto *Attr = FD->getAttr()) { + llvm::Function *Fn = cast(GV); + llvm::AttrBuilder B; + B.addAttribute("wasm-import-name", Attr->getImportName()); Fn->addAttributes(llvm::AttributeList::FunctionIndex, B); } } diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index 24e0759..7eafdcc 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -5732,6 +5732,29 @@ static void handleWebAssemblyImportModuleAttr(Sema &S, Decl *D, const ParsedAttr AL.getAttributeSpellingListIndex())); } +static void handleWebAssemblyImportNameAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + if (!isFunctionOrMethod(D)) { + S.Diag(D->getLocation(), diag::warn_attribute_wrong_decl_type) + << "'import_name'" << ExpectedFunction; + return; + } + + auto *FD = cast(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) WebAssemblyImportNameAttr( + AL.getRange(), S.Context, Str, + AL.getAttributeSpellingListIndex())); +} + static void handleRISCVInterruptAttr(Sema &S, Decl *D, const ParsedAttr &AL) { // Warn about repeated attributes. @@ -6489,6 +6512,9 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, case ParsedAttr::AT_WebAssemblyImportModule: handleWebAssemblyImportModuleAttr(S, D, AL); break; + case ParsedAttr::AT_WebAssemblyImportName: + handleWebAssemblyImportNameAttr(S, D, AL); + break; case ParsedAttr::AT_IBAction: handleSimpleAttribute(S, D, AL); break; diff --git a/clang/test/CodeGen/wasm-import-name.c b/clang/test/CodeGen/wasm-import-name.c new file mode 100644 index 0000000..7c3b094 --- /dev/null +++ b/clang/test/CodeGen/wasm-import-name.c @@ -0,0 +1,11 @@ +// RUN: %clang_cc1 -triple wasm32-unknown-unknown-wasm -emit-llvm -o - %s | FileCheck %s + +void __attribute__((import_name("bar"))) foo(void); + +void call(void) { + foo(); +} + +// CHECK: declare void @foo() [[A:#[0-9]+]] + +// CHECK: attributes [[A]] = {{{.*}} "wasm-import-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 f381e7a..05b9294 100644 --- a/clang/test/Misc/pragma-attribute-supported-attributes-list.test +++ b/clang/test/Misc/pragma-attribute-supported-attributes-list.test @@ -138,6 +138,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: WebAssemblyImportName (SubjectMatchRule_function) // CHECK-NEXT: WebAssemblyImportModule (SubjectMatchRule_function) // CHECK-NEXT: WorkGroupSizeHint (SubjectMatchRule_function) // CHECK-NEXT: XRayInstrument (SubjectMatchRule_function, SubjectMatchRule_objc_method) -- 2.7.4