Index: include/llvm/MC/MCSymbolWasm.h =================================================================== --- include/llvm/MC/MCSymbolWasm.h +++ include/llvm/MC/MCSymbolWasm.h @@ -31,11 +31,12 @@ const MCExpr *SymbolSize = nullptr; public: - // Use a module name of "env" for now, for compatibility with existing tools. - // This is temporary, and may change, as the ABI is not yet stable. + // A module name of "__unresolved" means that the symbol is to be + // resolved by the the linker, either to a definition in the module + // or to a definition in another library. MCSymbolWasm(const StringMapEntry *Name, bool isTemporary) : MCSymbol(SymbolKindWasm, Name, isTemporary), - ModuleName("env") {} + ModuleName("__linker_resolve") {} static bool classof(const MCSymbol *S) { return S->isWasm(); } const MCExpr *getSize() const { return SymbolSize; } @@ -54,6 +55,7 @@ void setComdat(bool isComdat) { IsComdat = isComdat; } const StringRef getModuleName() const { return ModuleName; } + void setModuleName(StringRef Name) { ModuleName = Name; } const SmallVector &getReturns() const { assert(ReturnsSet); Index: lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.h =================================================================== --- lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.h +++ lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.h @@ -24,6 +24,7 @@ class MCELFStreamer; class MCWasmStreamer; +class MCSymbolWasm; /// WebAssembly-specific streamer interface, to implement support /// WebAssembly-specific assembly directives. @@ -49,6 +50,8 @@ virtual void emitIndIdx(const MCExpr *Value) = 0; /// .import_global virtual void emitGlobalImport(StringRef name) = 0; + /// .import_module + virtual void emitImportModule(MCSymbolWasm *Sym, StringRef ModuleName) = 0; protected: void emitValueType(wasm::ValType Type); @@ -71,6 +74,7 @@ SmallVectorImpl &Results) override; void emitIndIdx(const MCExpr *Value) override; void emitGlobalImport(StringRef name) override; + void emitImportModule(MCSymbolWasm *Sym, StringRef ModuleName) override; }; /// This part is for ELF object output @@ -88,6 +92,7 @@ SmallVectorImpl &Results) override; void emitIndIdx(const MCExpr *Value) override; void emitGlobalImport(StringRef name) override; + void emitImportModule(MCSymbolWasm *Sym, StringRef ModuleName) override; }; /// This part is for Wasm object output @@ -105,6 +110,7 @@ SmallVectorImpl &Results) override; void emitIndIdx(const MCExpr *Value) override; void emitGlobalImport(StringRef name) override; + void emitImportModule(MCSymbolWasm *Sym, StringRef ModuleName) override; }; } // end namespace llvm Index: lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.cpp =================================================================== --- lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.cpp +++ lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.cpp @@ -128,6 +128,11 @@ OS << "\t.import_global\t" << name << '\n'; } +void WebAssemblyTargetAsmStreamer::emitImportModule(MCSymbolWasm *Sym, + StringRef ModuleName) { + OS << "\t.import_module\t" << Sym->getName() << ", " << ModuleName << '\n'; +} + void WebAssemblyTargetAsmStreamer::emitIndIdx(const MCExpr *Value) { OS << "\t.indidx \t" << *Value << '\n'; } @@ -170,6 +175,11 @@ void WebAssemblyTargetELFStreamer::emitGlobalImport(StringRef name) { } +void WebAssemblyTargetELFStreamer::emitImportModule(MCSymbolWasm *Sym, + StringRef ModuleName) { + llvm_unreachable(".import_module encoding not yet implemented"); +} + void WebAssemblyTargetWasmStreamer::emitParam(MCSymbol *Symbol, ArrayRef Types) { SmallVector Params; @@ -262,3 +272,8 @@ void WebAssemblyTargetWasmStreamer::emitGlobalImport(StringRef name) { llvm_unreachable(".global_import is not needed for direct wasm output"); } + +void WebAssemblyTargetWasmStreamer::emitImportModule(MCSymbolWasm *Sym, + StringRef ModuleName) { + Sym->setModuleName(ModuleName); +} Index: lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp =================================================================== --- lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp +++ lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp @@ -84,8 +84,14 @@ SmallVector Results; SmallVector Params; ComputeSignatureVTs(F, TM, Params, Results); - getTargetStreamer()->emitIndirectFunctionType(getSymbol(&F), Params, - Results); + MCSymbolWasm *Sym = cast(getSymbol(&F)); + getTargetStreamer()->emitIndirectFunctionType(Sym, Params, Results); + + if (F.hasFnAttribute("wasm-import-module")) { + StringRef Name = F.getFnAttribute("wasm-import-module") + .getValueAsString(); + getTargetStreamer()->emitImportModule(Sym, Name); + } } } for (const auto &G : M.globals()) { Index: test/CodeGen/WebAssembly/import-module.ll =================================================================== --- test/CodeGen/WebAssembly/import-module.ll +++ test/CodeGen/WebAssembly/import-module.ll @@ -0,0 +1,19 @@ +; RUN: llc < %s -asm-verbose=false | FileCheck %s + +target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128" +target triple = "wasm32-unknown-unknown-wasm" + +define void @test() { + call void @foo() + call void @plain() + ret void +} + +declare void @foo() #0 +declare void @plain() + +attributes #0 = { "wasm-import-module"="bar" } + +; CHECK-NOT: .import_module plain +; CHECK: .import_module foo, bar +; CHECK-NOT: .import_module plain Index: test/MC/WebAssembly/comdat.ll =================================================================== --- test/MC/WebAssembly/comdat.ll +++ test/MC/WebAssembly/comdat.ll @@ -30,19 +30,19 @@ ; CHECK-NEXT: ParamTypes: ; CHECK-NEXT: - Type: IMPORT ; CHECK-NEXT: Imports: -; CHECK-NEXT: - Module: env +; CHECK-NEXT: - Module: __linker_resolve ; CHECK-NEXT: Field: __linear_memory ; CHECK-NEXT: Kind: MEMORY ; CHECK-NEXT: Memory: ; CHECK-NEXT: Initial: 0x00000001 -; CHECK-NEXT: - Module: env +; CHECK-NEXT: - Module: __linker_resolve ; CHECK-NEXT: Field: __indirect_function_table ; CHECK-NEXT: Kind: TABLE ; CHECK-NEXT: Table: ; CHECK-NEXT: ElemType: ANYFUNC ; CHECK-NEXT: Limits: ; CHECK-NEXT: Initial: 0x00000000 -; CHECK-NEXT: - Module: env +; CHECK-NEXT: - Module: __linker_resolve ; CHECK-NEXT: Field: funcImport ; CHECK-NEXT: Kind: FUNCTION ; CHECK-NEXT: SigIndex: 0 Index: test/MC/WebAssembly/external-func-address.ll =================================================================== --- test/MC/WebAssembly/external-func-address.ll +++ test/MC/WebAssembly/external-func-address.ll @@ -2,6 +2,11 @@ ; Verify that addresses of external functions generate correctly typed ; imports and relocations or type R_TABLE_INDEX_I32. +declare void @f0(i32) #0 +@ptr_to_f0 = hidden global void (i32)* @f0, align 4 + +attributes #0 = { "wasm-import-module"="somewhere" } + declare void @f1(i32) #1 @ptr_to_f1 = hidden global void (i32)* @f1, align 4 @@ -17,11 +22,13 @@ ; CHECK-NEXT: - I32 ; CHECK: - Type: IMPORT ; CHECK-NEXT: Imports: -; CHECK: - Module: env +; CHECK: - Module: __linker_resolve ; CHECK-NEXT: Field: __linear_memory -; CHECK: - Module: env +; CHECK: - Module: __linker_resolve ; CHECK-NEXT: Field: __indirect_function_table -; CHECK: - Module: env +; CHECK: - Module: somewhere +; CHECK-NEXT: Field: f0 +; CHECK: - Module: __linker_resolve ; CHECK-NEXT: Field: f1 ; CHECK-NEXT: Kind: FUNCTION ; CHECK-NEXT: SigIndex: 0 @@ -30,7 +37,7 @@ ; CHECK-NEXT: - Offset: ; CHECK-NEXT: Opcode: I32_CONST ; CHECK-NEXT: Value: 1 -; CHECK-NEXT: Functions: [ 0 ] +; CHECK-NEXT: Functions: [ 0, 1 ] ; CHECK: - Type: DATA ; CHECK-NEXT: Relocations: ; CHECK-NEXT: - Type: R_WEBASSEMBLY_TABLE_INDEX_I32 Index: test/MC/WebAssembly/global-ctor-dtor.ll =================================================================== --- test/MC/WebAssembly/global-ctor-dtor.ll +++ test/MC/WebAssembly/global-ctor-dtor.ll @@ -19,40 +19,40 @@ ; CHECK: - Type: IMPORT ; CHECK-NEXT: Imports: -; CHECK-NEXT: - Module: env +; CHECK-NEXT: - Module: __linker_resolve ; CHECK-NEXT: Field: __linear_memory ; CHECK-NEXT: Kind: MEMORY ; CHECK-NEXT: Memory: ; CHECK-NEXT: Initial: 0x00000001 -; CHECK-NEXT: - Module: env +; CHECK-NEXT: - Module: __linker_resolve ; CHECK-NEXT: Field: __indirect_function_table ; CHECK-NEXT: Kind: TABLE ; CHECK-NEXT: Table: ; CHECK-NEXT: ElemType: ANYFUNC ; CHECK-NEXT: Limits: ; CHECK-NEXT: Initial: 0x00000002 -; CHECK-NEXT: - Module: env +; CHECK-NEXT: - Module: __linker_resolve ; CHECK-NEXT: Field: func3 ; CHECK-NEXT: Kind: FUNCTION ; CHECK-NEXT: SigIndex: 1 -; CHECK-NEXT: - Module: env +; CHECK-NEXT: - Module: __linker_resolve ; CHECK-NEXT: Field: __dso_handle ; CHECK-NEXT: Kind: GLOBAL ; CHECK-NEXT: GlobalType: I32 ; CHECK-NEXT: GlobalMutable: false -; CHECK-NEXT: - Module: env +; CHECK-NEXT: - Module: __linker_resolve ; CHECK-NEXT: Field: __cxa_atexit ; CHECK-NEXT: Kind: FUNCTION ; CHECK-NEXT: SigIndex: 2 -; CHECK-NEXT: - Module: env +; CHECK-NEXT: - Module: __linker_resolve ; CHECK-NEXT: Field: func2 ; CHECK-NEXT: Kind: FUNCTION ; CHECK-NEXT: SigIndex: 1 -; CHECK-NEXT: - Module: env +; CHECK-NEXT: - Module: __linker_resolve ; CHECK-NEXT: Field: func1 ; CHECK-NEXT: Kind: FUNCTION ; CHECK-NEXT: SigIndex: 1 -; CHECK-NEXT: - Module: env +; CHECK-NEXT: - Module: __linker_resolve ; CHECK-NEXT: Field: func0 ; CHECK-NEXT: Kind: FUNCTION ; CHECK-NEXT: SigIndex: 1 Index: test/MC/WebAssembly/stack-ptr.ll =================================================================== --- test/MC/WebAssembly/stack-ptr.ll +++ test/MC/WebAssembly/stack-ptr.ll @@ -10,7 +10,7 @@ ; CHECK: - Type: IMPORT ; CHECK: Imports: -; CHECK: - Module: env +; CHECK: - Module: __linker_resolve ; CHECK: Field: __stack_pointer ; CHECK: Kind: GLOBAL ; CHECK: GlobalType: I32 Index: test/MC/WebAssembly/weak-alias.ll =================================================================== --- test/MC/WebAssembly/weak-alias.ll +++ test/MC/WebAssembly/weak-alias.ll @@ -51,23 +51,23 @@ ; CHECK-NEXT: ParamTypes: ; CHECK-NEXT: - Type: IMPORT ; CHECK-NEXT: Imports: -; CHECK-NEXT: - Module: env +; CHECK-NEXT: - Module: __linker_resolve ; CHECK-NEXT: Field: __linear_memory ; CHECK-NEXT: Kind: MEMORY ; CHECK-NEXT: Memory: ; CHECK-NEXT: Initial: 0x00000001 -; CHECK-NEXT: - Module: env +; CHECK-NEXT: - Module: __linker_resolve ; CHECK-NEXT: Field: __indirect_function_table ; CHECK-NEXT: Kind: TABLE ; CHECK-NEXT: Table: ; CHECK-NEXT: ElemType: ANYFUNC ; CHECK-NEXT: Limits: ; CHECK-NEXT: Initial: 0x00000002 -; CHECK-NEXT: - Module: env +; CHECK-NEXT: - Module: __linker_resolve ; CHECK-NEXT: Field: foo_alias ; CHECK-NEXT: Kind: FUNCTION ; CHECK-NEXT: SigIndex: 0 -; CHECK-NEXT: - Module: env +; CHECK-NEXT: - Module: __linker_resolve ; CHECK-NEXT: Field: bar_alias ; CHECK-NEXT: Kind: GLOBAL ; CHECK-NEXT: GlobalType: I32 Index: test/MC/WebAssembly/weak.ll =================================================================== --- test/MC/WebAssembly/weak.ll +++ test/MC/WebAssembly/weak.ll @@ -12,11 +12,11 @@ ; CHECK: - Type: IMPORT ; CHECK-NEXT: Imports: -; CHECK: - Module: env +; CHECK: - Module: __linker_resolve ; CHECK-NEXT: Field: __linear_memory -; CHECK: - Module: env +; CHECK: - Module: __linker_resolve ; CHECK-NEXT: Field: __indirect_function_table -; CHECK: - Module: env +; CHECK: - Module: __linker_resolve ; CHECK-NEXT: Field: weak_external_data ; CHECK-NEXT: Kind: GLOBAL ; CHECK-NEXT: GlobalType: I32 Index: tools/clang/include/clang/Basic/Attr.td =================================================================== --- tools/clang/include/clang/Basic/Attr.td +++ tools/clang/include/clang/Basic/Attr.td @@ -296,6 +296,7 @@ def TargetMSP430 : TargetArch<["msp430"]>; def TargetX86 : TargetArch<["x86"]>; def TargetAnyX86 : TargetArch<["x86", "x86_64"]>; +def TargetWebAssembly : TargetArch<["wasm32", "wasm64"]>; def TargetWindows : TargetArch<["x86", "x86_64", "arm", "thumb", "aarch64"]> { let OSes = ["Win32"]; } @@ -1359,6 +1360,13 @@ let Subjects = SubjectList<[Function], ErrorDiag, "kernel functions">; } +def WebAssemblyImportModule : InheritableAttr, + TargetSpecificAttr { + let Spellings = [Clang<"import_module">]; + let Args = [StringArgument<"ImportModuleName">]; + let Documentation = [Undocumented]; +} + def NoSplitStack : InheritableAttr { let Spellings = [GCC<"no_split_stack">]; let Subjects = SubjectList<[Function], ErrorDiag>; Index: tools/clang/lib/CodeGen/TargetInfo.cpp =================================================================== --- tools/clang/lib/CodeGen/TargetInfo.cpp +++ tools/clang/lib/CodeGen/TargetInfo.cpp @@ -730,6 +730,20 @@ public: explicit WebAssemblyTargetCodeGenInfo(CodeGen::CodeGenTypes &CGT) : TargetCodeGenInfo(new WebAssemblyABIInfo(CGT)) {} + + void setTargetAttributes(const Decl *D, llvm::GlobalValue *GV, + CodeGen::CodeGenModule &CGM, + ForDefinition_t IsForDefinition) const override { + TargetCodeGenInfo::setTargetAttributes(D, GV, CGM, IsForDefinition); + if (auto *FD = dyn_cast_or_null(D)) { + if (auto *Attr = FD->getAttr()) { + llvm::Function *Fn = cast(GV); + llvm::AttrBuilder B; + B.addAttribute("wasm-import-module", Attr->getImportModuleName()); + Fn->addAttributes(llvm::AttributeList::FunctionIndex, B); + } + } + } }; /// \brief Classify argument of given type \p Ty. Index: tools/clang/lib/Sema/SemaDeclAttr.cpp =================================================================== --- tools/clang/lib/Sema/SemaDeclAttr.cpp +++ tools/clang/lib/Sema/SemaDeclAttr.cpp @@ -5433,6 +5433,28 @@ handleSimpleAttribute(S, D, Attr); } +static void handleWebAssemblyImportModuleAttr(Sema &S, Decl *D, const AttributeList &Attr) { + if (!isFunctionOrMethod(D)) { + S.Diag(D->getLocation(), diag::warn_attribute_wrong_decl_type) + << "'import_module'" << ExpectedFunction; + return; + } + + auto *FD = cast(D); + if (FD->isThisDeclarationADefinition()) { + S.Diag(Attr.getLoc(), diag::err_alias_is_definition) << FD << 0; + return; + } + + StringRef Str; + if (!S.checkStringLiteralArgumentAttr(Attr, 0, Str)) + return; + + FD->addAttr(::new (S.Context) WebAssemblyImportModuleAttr( + Attr.getRange(), S.Context, Str, + Attr.getAttributeSpellingListIndex())); +} + static void handleInterruptAttr(Sema &S, Decl *D, const AttributeList &Attr) { // Dispatch the interrupt attribute based on the current target. switch (S.Context.getTargetInfo().getTriple().getArch()) { @@ -6030,6 +6052,9 @@ case AttributeList::AT_AVRSignal: handleAVRSignalAttr(S, D, Attr); break; + case AttributeList::AT_WebAssemblyImportModule: + handleWebAssemblyImportModuleAttr(S, D, Attr); + break; case AttributeList::AT_IBAction: handleSimpleAttribute(S, D, Attr); break; Index: tools/clang/test/CodeGen/wasm-import-module.c =================================================================== --- tools/clang/test/CodeGen/wasm-import-module.c +++ tools/clang/test/CodeGen/wasm-import-module.c @@ -0,0 +1,11 @@ +// RUN: %clang_cc1 -triple wasm32-unknown-unknown-wasm -emit-llvm -o - %s | FileCheck %s + +void __attribute__((import_module("bar"))) foo(void); + +void call(void) { + foo(); +} + +// CHECK: declare void @foo() [[A:#[0-9]+]] + +// CHECK: attributes [[A]] = {{{.*}} "wasm-import-module"="bar" {{.*}}}