diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -1979,6 +1979,13 @@ let Subjects = SubjectList<[Function], ErrorDiag>; } +def WebAssemblyAsync : InheritableAttr, + TargetSpecificAttr { + let Spellings = [Clang<"wasm_async">]; + let Documentation = [WebAssemblyAsyncDocs]; + 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 --- a/clang/include/clang/Basic/AttrDocs.td +++ b/clang/include/clang/Basic/AttrDocs.td @@ -5602,6 +5602,17 @@ }]; } +def WebAssemblyAsyncDocs : Documentation { + let Category = DocCatFunction; + let Content = [{ +Clang supports the ``__attribute__((wasm_async))`` +attribute for the WebAssembly target. This attribute may be attached to a +function definition, which indicates the function will be used with JavaScript +promise integration (JSPI). The attribute will cause the creation of a custom +section named "async" that contains each wasm_async function's index value. + }]; +} + def ArtificialDocs : Documentation { let Category = DocCatFunction; let Content = [{ diff --git a/clang/lib/CodeGen/TargetInfo.cpp b/clang/lib/CodeGen/TargetInfo.cpp --- a/clang/lib/CodeGen/TargetInfo.cpp +++ b/clang/lib/CodeGen/TargetInfo.cpp @@ -894,6 +894,12 @@ B.addAttribute("wasm-export-name", Attr->getExportName()); Fn->addFnAttrs(B); } + if (FD->getAttr()) { + llvm::Function *Fn = cast(GV); + llvm::AttrBuilder B(GV->getContext()); + B.addAttribute("wasm-async"); + Fn->addFnAttrs(B); + } } if (auto *FD = dyn_cast_or_null(D)) { diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -7633,6 +7633,23 @@ FD->addAttr(::new (S.Context) WebAssemblyImportNameAttr(S.Context, AL, Str)); } +static void handleWebAssemblyAsyncAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + if (!isFunctionOrMethod(D)) { + S.Diag(D->getLocation(), diag::warn_attribute_wrong_decl_type) + << "'wasm_async'" << ExpectedFunction; + return; + } + + auto *FD = cast(D); + if (FD->isThisDeclarationADefinition()) { + S.Diag(D->getLocation(), diag::err_alias_is_definition) << FD << 0; + return; + } + + D->addAttr(::new (S.Context) WebAssemblyAsyncAttr(S.Context, AL)); + D->addAttr(UsedAttr::CreateImplicit(S.Context)); +} + static void handleRISCVInterruptAttr(Sema &S, Decl *D, const ParsedAttr &AL) { // Warn about repeated attributes. @@ -8739,6 +8756,9 @@ case ParsedAttr::AT_WebAssemblyImportName: handleWebAssemblyImportNameAttr(S, D, AL); break; + case ParsedAttr::AT_WebAssemblyAsync: + handleWebAssemblyAsyncAttr(S, D, AL); + break; case ParsedAttr::AT_IBOutlet: handleIBOutlet(S, D, AL); break; diff --git a/clang/test/CodeGen/WebAssembly/wasm-async.c b/clang/test/CodeGen/WebAssembly/wasm-async.c new file mode 100644 --- /dev/null +++ b/clang/test/CodeGen/WebAssembly/wasm-async.c @@ -0,0 +1,9 @@ +// RUN: %clang_cc1 -triple wasm32-unknown-unknown-wasm -emit-llvm -o - %s | FileCheck %s + +__attribute__((wasm_async)) int foo(void) { + return 43; +} + +// CHECK: define i32 @foo() [[A:#[0-9]+]] + +// CHECK: attributes [[A]] = {{{.*}} "wasm-async" {{.*}}} diff --git a/clang/test/Misc/pragma-attribute-supported-attributes-list.test b/clang/test/Misc/pragma-attribute-supported-attributes-list.test --- a/clang/test/Misc/pragma-attribute-supported-attributes-list.test +++ b/clang/test/Misc/pragma-attribute-supported-attributes-list.test @@ -196,6 +196,7 @@ // CHECK-NEXT: WarnUnusedResult (SubjectMatchRule_objc_method, SubjectMatchRule_enum, SubjectMatchRule_record, SubjectMatchRule_hasType_functionType, SubjectMatchRule_type_alias) // CHECK-NEXT: Weak (SubjectMatchRule_variable, SubjectMatchRule_function, SubjectMatchRule_record) // CHECK-NEXT: WeakRef (SubjectMatchRule_variable, SubjectMatchRule_function) +// CHECK-NEXT: WebAssemblyAsync (SubjectMatchRule_function) // CHECK-NEXT: WebAssemblyExportName (SubjectMatchRule_function) // CHECK-NEXT: WebAssemblyImportModule (SubjectMatchRule_function) // CHECK-NEXT: WebAssemblyImportName (SubjectMatchRule_function) diff --git a/lld/test/wasm/async.ll b/lld/test/wasm/async.ll new file mode 100644 --- /dev/null +++ b/lld/test/wasm/async.ll @@ -0,0 +1,26 @@ +; 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 @bar() #1 { + ret void +} + +define void @_start() { + call void @foo() + call void @bar() + ret void +} + +attributes #0 = { "wasm-async" } +attributes #1 = { "wasm-async" } + +; CHECK: - Type: CUSTOM +; CHECK-NEXT: Name: async +; CHECK-NEXT: Payload: '0000000001000000' diff --git a/lld/test/wasm/merge-async-section.ll b/lld/test/wasm/merge-async-section.ll new file mode 100644 --- /dev/null +++ b/lld/test/wasm/merge-async-section.ll @@ -0,0 +1,49 @@ +; RUN: split-file %s %t +; RUN: llc -filetype=obj %t/a.ll -o %t1.o +; RUN: llc -filetype=obj %t/b.ll -o %t2.o +; RUN: wasm-ld -o %t.wasm %t1.o %t2.o +; RUN: obj2yaml %t.wasm | FileCheck %s + +; Ensure two async sections are concatenated together. + +; CHECK: - Type: CUSTOM +; CHECK-NEXT: Name: async +; CHECK-NEXT: Payload: '000000000100000003000000' + +;--- a.ll + +target triple = "wasm32-unknown-unknown" + +; Function index 3 (after linking) +declare void @baz() + +; Function index 0 +define void @foo() #0 { + ret void +} + +; Function index 1 +define void @bar() #1 { + ret void +} + +; Function index 2 +define void @_start() { + call void @foo() + call void @bar() + call void @baz() + ret void +} + +attributes #0 = { "wasm-async" } +attributes #1 = { "wasm-async" } + +;--- b.ll + +target triple = "wasm32-unknown-unknown" + +define void @baz() #0 { + ret void +} + +attributes #0 = { "wasm-async" } diff --git a/lld/wasm/InputChunks.cpp b/lld/wasm/InputChunks.cpp --- a/lld/wasm/InputChunks.cpp +++ b/lld/wasm/InputChunks.cpp @@ -150,6 +150,7 @@ case R_WASM_TABLE_INDEX_I32: case R_WASM_MEMORY_ADDR_I32: case R_WASM_FUNCTION_OFFSET_I32: + case R_WASM_FUNCTION_INDEX_I32: case R_WASM_SECTION_OFFSET_I32: case R_WASM_GLOBAL_INDEX_I32: case R_WASM_MEMORY_ADDR_LOCREL_I32: diff --git a/lld/wasm/InputFiles.cpp b/lld/wasm/InputFiles.cpp --- a/lld/wasm/InputFiles.cpp +++ b/lld/wasm/InputFiles.cpp @@ -193,6 +193,7 @@ case R_WASM_TYPE_INDEX_LEB: return typeMap[reloc.Index]; case R_WASM_FUNCTION_INDEX_LEB: + case R_WASM_FUNCTION_INDEX_I32: return getFunctionSymbol(reloc.Index)->getFunctionIndex(); case R_WASM_GLOBAL_INDEX_LEB: case R_WASM_GLOBAL_INDEX_I32: diff --git a/llvm/include/llvm/BinaryFormat/WasmRelocs.def b/llvm/include/llvm/BinaryFormat/WasmRelocs.def --- a/llvm/include/llvm/BinaryFormat/WasmRelocs.def +++ b/llvm/include/llvm/BinaryFormat/WasmRelocs.def @@ -28,3 +28,4 @@ WASM_RELOC(R_WASM_MEMORY_ADDR_LOCREL_I32, 23) WASM_RELOC(R_WASM_TABLE_INDEX_REL_SLEB64, 24) WASM_RELOC(R_WASM_MEMORY_ADDR_TLS_SLEB64, 25) +WASM_RELOC(R_WASM_FUNCTION_INDEX_I32, 26) diff --git a/llvm/include/llvm/MC/MCExpr.h b/llvm/include/llvm/MC/MCExpr.h --- a/llvm/include/llvm/MC/MCExpr.h +++ b/llvm/include/llvm/MC/MCExpr.h @@ -330,6 +330,7 @@ VK_WASM_MBREL, // Memory address relative to __memory_base VK_WASM_TBREL, // Table index relative to __table_base VK_WASM_GOT_TLS, // Wasm global index of TLS symbol. + VK_WASM_FUNCINDEX, // Wasm function index. VK_AMDGPU_GOTPCREL32_LO, // symbol@gotpcrel32@lo VK_AMDGPU_GOTPCREL32_HI, // symbol@gotpcrel32@hi diff --git a/llvm/lib/MC/MCExpr.cpp b/llvm/lib/MC/MCExpr.cpp --- a/llvm/lib/MC/MCExpr.cpp +++ b/llvm/lib/MC/MCExpr.cpp @@ -360,6 +360,8 @@ case VK_WASM_TLSREL: return "TLSREL"; case VK_WASM_TBREL: return "TBREL"; case VK_WASM_GOT_TLS: return "GOT@TLS"; + case VK_WASM_FUNCINDEX: + return "FUNCINDEX"; case VK_AMDGPU_GOTPCREL32_LO: return "gotpcrel32@lo"; case VK_AMDGPU_GOTPCREL32_HI: return "gotpcrel32@hi"; case VK_AMDGPU_REL32_LO: return "rel32@lo"; @@ -388,143 +390,144 @@ MCSymbolRefExpr::VariantKind MCSymbolRefExpr::getVariantKindForName(StringRef Name) { return StringSwitch(Name.lower()) - .Case("dtprel", VK_DTPREL) - .Case("dtpoff", VK_DTPOFF) - .Case("got", VK_GOT) - .Case("gotoff", VK_GOTOFF) - .Case("gotrel", VK_GOTREL) - .Case("pcrel", VK_PCREL) - .Case("gotpcrel", VK_GOTPCREL) - .Case("gotpcrel_norelax", VK_GOTPCREL_NORELAX) - .Case("gottpoff", VK_GOTTPOFF) - .Case("indntpoff", VK_INDNTPOFF) - .Case("ntpoff", VK_NTPOFF) - .Case("gotntpoff", VK_GOTNTPOFF) - .Case("plt", VK_PLT) - .Case("tlscall", VK_TLSCALL) - .Case("tlsdesc", VK_TLSDESC) - .Case("tlsgd", VK_TLSGD) - .Case("tlsld", VK_TLSLD) - .Case("tlsldm", VK_TLSLDM) - .Case("tpoff", VK_TPOFF) - .Case("tprel", VK_TPREL) - .Case("tlvp", VK_TLVP) - .Case("tlvppage", VK_TLVPPAGE) - .Case("tlvppageoff", VK_TLVPPAGEOFF) - .Case("page", VK_PAGE) - .Case("pageoff", VK_PAGEOFF) - .Case("gotpage", VK_GOTPAGE) - .Case("gotpageoff", VK_GOTPAGEOFF) - .Case("imgrel", VK_COFF_IMGREL32) - .Case("secrel32", VK_SECREL) - .Case("size", VK_SIZE) - .Case("abs8", VK_X86_ABS8) - .Case("pltoff", VK_X86_PLTOFF) - .Case("l", VK_PPC_LO) - .Case("h", VK_PPC_HI) - .Case("ha", VK_PPC_HA) - .Case("high", VK_PPC_HIGH) - .Case("higha", VK_PPC_HIGHA) - .Case("higher", VK_PPC_HIGHER) - .Case("highera", VK_PPC_HIGHERA) - .Case("highest", VK_PPC_HIGHEST) - .Case("highesta", VK_PPC_HIGHESTA) - .Case("got@l", VK_PPC_GOT_LO) - .Case("got@h", VK_PPC_GOT_HI) - .Case("got@ha", VK_PPC_GOT_HA) - .Case("local", VK_PPC_LOCAL) - .Case("tocbase", VK_PPC_TOCBASE) - .Case("toc", VK_PPC_TOC) - .Case("toc@l", VK_PPC_TOC_LO) - .Case("toc@h", VK_PPC_TOC_HI) - .Case("toc@ha", VK_PPC_TOC_HA) - .Case("u", VK_PPC_U) - .Case("l", VK_PPC_L) - .Case("tls", VK_PPC_TLS) - .Case("dtpmod", VK_PPC_DTPMOD) - .Case("tprel@l", VK_PPC_TPREL_LO) - .Case("tprel@h", VK_PPC_TPREL_HI) - .Case("tprel@ha", VK_PPC_TPREL_HA) - .Case("tprel@high", VK_PPC_TPREL_HIGH) - .Case("tprel@higha", VK_PPC_TPREL_HIGHA) - .Case("tprel@higher", VK_PPC_TPREL_HIGHER) - .Case("tprel@highera", VK_PPC_TPREL_HIGHERA) - .Case("tprel@highest", VK_PPC_TPREL_HIGHEST) - .Case("tprel@highesta", VK_PPC_TPREL_HIGHESTA) - .Case("dtprel@l", VK_PPC_DTPREL_LO) - .Case("dtprel@h", VK_PPC_DTPREL_HI) - .Case("dtprel@ha", VK_PPC_DTPREL_HA) - .Case("dtprel@high", VK_PPC_DTPREL_HIGH) - .Case("dtprel@higha", VK_PPC_DTPREL_HIGHA) - .Case("dtprel@higher", VK_PPC_DTPREL_HIGHER) - .Case("dtprel@highera", VK_PPC_DTPREL_HIGHERA) - .Case("dtprel@highest", VK_PPC_DTPREL_HIGHEST) - .Case("dtprel@highesta", VK_PPC_DTPREL_HIGHESTA) - .Case("got@tprel", VK_PPC_GOT_TPREL) - .Case("got@tprel@l", VK_PPC_GOT_TPREL_LO) - .Case("got@tprel@h", VK_PPC_GOT_TPREL_HI) - .Case("got@tprel@ha", VK_PPC_GOT_TPREL_HA) - .Case("got@dtprel", VK_PPC_GOT_DTPREL) - .Case("got@dtprel@l", VK_PPC_GOT_DTPREL_LO) - .Case("got@dtprel@h", VK_PPC_GOT_DTPREL_HI) - .Case("got@dtprel@ha", VK_PPC_GOT_DTPREL_HA) - .Case("got@tlsgd", VK_PPC_GOT_TLSGD) - .Case("got@tlsgd@l", VK_PPC_GOT_TLSGD_LO) - .Case("got@tlsgd@h", VK_PPC_GOT_TLSGD_HI) - .Case("got@tlsgd@ha", VK_PPC_GOT_TLSGD_HA) - .Case("got@tlsld", VK_PPC_GOT_TLSLD) - .Case("got@tlsld@l", VK_PPC_GOT_TLSLD_LO) - .Case("got@tlsld@h", VK_PPC_GOT_TLSLD_HI) - .Case("got@tlsld@ha", VK_PPC_GOT_TLSLD_HA) - .Case("got@pcrel", VK_PPC_GOT_PCREL) - .Case("got@tlsgd@pcrel", VK_PPC_GOT_TLSGD_PCREL) - .Case("got@tlsld@pcrel", VK_PPC_GOT_TLSLD_PCREL) - .Case("got@tprel@pcrel", VK_PPC_GOT_TPREL_PCREL) - .Case("tls@pcrel", VK_PPC_TLS_PCREL) - .Case("notoc", VK_PPC_NOTOC) - .Case("gdgot", VK_Hexagon_GD_GOT) - .Case("gdplt", VK_Hexagon_GD_PLT) - .Case("iegot", VK_Hexagon_IE_GOT) - .Case("ie", VK_Hexagon_IE) - .Case("ldgot", VK_Hexagon_LD_GOT) - .Case("ldplt", VK_Hexagon_LD_PLT) - .Case("none", VK_ARM_NONE) - .Case("got_prel", VK_ARM_GOT_PREL) - .Case("target1", VK_ARM_TARGET1) - .Case("target2", VK_ARM_TARGET2) - .Case("prel31", VK_ARM_PREL31) - .Case("sbrel", VK_ARM_SBREL) - .Case("tlsldo", VK_ARM_TLSLDO) - .Case("lo8", VK_AVR_LO8) - .Case("hi8", VK_AVR_HI8) - .Case("hlo8", VK_AVR_HLO8) - .Case("typeindex", VK_WASM_TYPEINDEX) - .Case("tbrel", VK_WASM_TBREL) - .Case("mbrel", VK_WASM_MBREL) - .Case("tlsrel", VK_WASM_TLSREL) - .Case("got@tls", VK_WASM_GOT_TLS) - .Case("gotpcrel32@lo", VK_AMDGPU_GOTPCREL32_LO) - .Case("gotpcrel32@hi", VK_AMDGPU_GOTPCREL32_HI) - .Case("rel32@lo", VK_AMDGPU_REL32_LO) - .Case("rel32@hi", VK_AMDGPU_REL32_HI) - .Case("rel64", VK_AMDGPU_REL64) - .Case("abs32@lo", VK_AMDGPU_ABS32_LO) - .Case("abs32@hi", VK_AMDGPU_ABS32_HI) - .Case("hi", VK_VE_HI32) - .Case("lo", VK_VE_LO32) - .Case("pc_hi", VK_VE_PC_HI32) - .Case("pc_lo", VK_VE_PC_LO32) - .Case("got_hi", VK_VE_GOT_HI32) - .Case("got_lo", VK_VE_GOT_LO32) - .Case("gotoff_hi", VK_VE_GOTOFF_HI32) - .Case("gotoff_lo", VK_VE_GOTOFF_LO32) - .Case("plt_hi", VK_VE_PLT_HI32) - .Case("plt_lo", VK_VE_PLT_LO32) - .Case("tls_gd_hi", VK_VE_TLS_GD_HI32) - .Case("tls_gd_lo", VK_VE_TLS_GD_LO32) - .Case("tpoff_hi", VK_VE_TPOFF_HI32) - .Case("tpoff_lo", VK_VE_TPOFF_LO32) - .Default(VK_Invalid); + .Case("dtprel", VK_DTPREL) + .Case("dtpoff", VK_DTPOFF) + .Case("got", VK_GOT) + .Case("gotoff", VK_GOTOFF) + .Case("gotrel", VK_GOTREL) + .Case("pcrel", VK_PCREL) + .Case("gotpcrel", VK_GOTPCREL) + .Case("gotpcrel_norelax", VK_GOTPCREL_NORELAX) + .Case("gottpoff", VK_GOTTPOFF) + .Case("indntpoff", VK_INDNTPOFF) + .Case("ntpoff", VK_NTPOFF) + .Case("gotntpoff", VK_GOTNTPOFF) + .Case("plt", VK_PLT) + .Case("tlscall", VK_TLSCALL) + .Case("tlsdesc", VK_TLSDESC) + .Case("tlsgd", VK_TLSGD) + .Case("tlsld", VK_TLSLD) + .Case("tlsldm", VK_TLSLDM) + .Case("tpoff", VK_TPOFF) + .Case("tprel", VK_TPREL) + .Case("tlvp", VK_TLVP) + .Case("tlvppage", VK_TLVPPAGE) + .Case("tlvppageoff", VK_TLVPPAGEOFF) + .Case("page", VK_PAGE) + .Case("pageoff", VK_PAGEOFF) + .Case("gotpage", VK_GOTPAGE) + .Case("gotpageoff", VK_GOTPAGEOFF) + .Case("imgrel", VK_COFF_IMGREL32) + .Case("secrel32", VK_SECREL) + .Case("size", VK_SIZE) + .Case("abs8", VK_X86_ABS8) + .Case("pltoff", VK_X86_PLTOFF) + .Case("l", VK_PPC_LO) + .Case("h", VK_PPC_HI) + .Case("ha", VK_PPC_HA) + .Case("high", VK_PPC_HIGH) + .Case("higha", VK_PPC_HIGHA) + .Case("higher", VK_PPC_HIGHER) + .Case("highera", VK_PPC_HIGHERA) + .Case("highest", VK_PPC_HIGHEST) + .Case("highesta", VK_PPC_HIGHESTA) + .Case("got@l", VK_PPC_GOT_LO) + .Case("got@h", VK_PPC_GOT_HI) + .Case("got@ha", VK_PPC_GOT_HA) + .Case("local", VK_PPC_LOCAL) + .Case("tocbase", VK_PPC_TOCBASE) + .Case("toc", VK_PPC_TOC) + .Case("toc@l", VK_PPC_TOC_LO) + .Case("toc@h", VK_PPC_TOC_HI) + .Case("toc@ha", VK_PPC_TOC_HA) + .Case("u", VK_PPC_U) + .Case("l", VK_PPC_L) + .Case("tls", VK_PPC_TLS) + .Case("dtpmod", VK_PPC_DTPMOD) + .Case("tprel@l", VK_PPC_TPREL_LO) + .Case("tprel@h", VK_PPC_TPREL_HI) + .Case("tprel@ha", VK_PPC_TPREL_HA) + .Case("tprel@high", VK_PPC_TPREL_HIGH) + .Case("tprel@higha", VK_PPC_TPREL_HIGHA) + .Case("tprel@higher", VK_PPC_TPREL_HIGHER) + .Case("tprel@highera", VK_PPC_TPREL_HIGHERA) + .Case("tprel@highest", VK_PPC_TPREL_HIGHEST) + .Case("tprel@highesta", VK_PPC_TPREL_HIGHESTA) + .Case("dtprel@l", VK_PPC_DTPREL_LO) + .Case("dtprel@h", VK_PPC_DTPREL_HI) + .Case("dtprel@ha", VK_PPC_DTPREL_HA) + .Case("dtprel@high", VK_PPC_DTPREL_HIGH) + .Case("dtprel@higha", VK_PPC_DTPREL_HIGHA) + .Case("dtprel@higher", VK_PPC_DTPREL_HIGHER) + .Case("dtprel@highera", VK_PPC_DTPREL_HIGHERA) + .Case("dtprel@highest", VK_PPC_DTPREL_HIGHEST) + .Case("dtprel@highesta", VK_PPC_DTPREL_HIGHESTA) + .Case("got@tprel", VK_PPC_GOT_TPREL) + .Case("got@tprel@l", VK_PPC_GOT_TPREL_LO) + .Case("got@tprel@h", VK_PPC_GOT_TPREL_HI) + .Case("got@tprel@ha", VK_PPC_GOT_TPREL_HA) + .Case("got@dtprel", VK_PPC_GOT_DTPREL) + .Case("got@dtprel@l", VK_PPC_GOT_DTPREL_LO) + .Case("got@dtprel@h", VK_PPC_GOT_DTPREL_HI) + .Case("got@dtprel@ha", VK_PPC_GOT_DTPREL_HA) + .Case("got@tlsgd", VK_PPC_GOT_TLSGD) + .Case("got@tlsgd@l", VK_PPC_GOT_TLSGD_LO) + .Case("got@tlsgd@h", VK_PPC_GOT_TLSGD_HI) + .Case("got@tlsgd@ha", VK_PPC_GOT_TLSGD_HA) + .Case("got@tlsld", VK_PPC_GOT_TLSLD) + .Case("got@tlsld@l", VK_PPC_GOT_TLSLD_LO) + .Case("got@tlsld@h", VK_PPC_GOT_TLSLD_HI) + .Case("got@tlsld@ha", VK_PPC_GOT_TLSLD_HA) + .Case("got@pcrel", VK_PPC_GOT_PCREL) + .Case("got@tlsgd@pcrel", VK_PPC_GOT_TLSGD_PCREL) + .Case("got@tlsld@pcrel", VK_PPC_GOT_TLSLD_PCREL) + .Case("got@tprel@pcrel", VK_PPC_GOT_TPREL_PCREL) + .Case("tls@pcrel", VK_PPC_TLS_PCREL) + .Case("notoc", VK_PPC_NOTOC) + .Case("gdgot", VK_Hexagon_GD_GOT) + .Case("gdplt", VK_Hexagon_GD_PLT) + .Case("iegot", VK_Hexagon_IE_GOT) + .Case("ie", VK_Hexagon_IE) + .Case("ldgot", VK_Hexagon_LD_GOT) + .Case("ldplt", VK_Hexagon_LD_PLT) + .Case("none", VK_ARM_NONE) + .Case("got_prel", VK_ARM_GOT_PREL) + .Case("target1", VK_ARM_TARGET1) + .Case("target2", VK_ARM_TARGET2) + .Case("prel31", VK_ARM_PREL31) + .Case("sbrel", VK_ARM_SBREL) + .Case("tlsldo", VK_ARM_TLSLDO) + .Case("lo8", VK_AVR_LO8) + .Case("hi8", VK_AVR_HI8) + .Case("hlo8", VK_AVR_HLO8) + .Case("typeindex", VK_WASM_TYPEINDEX) + .Case("tbrel", VK_WASM_TBREL) + .Case("mbrel", VK_WASM_MBREL) + .Case("tlsrel", VK_WASM_TLSREL) + .Case("got@tls", VK_WASM_GOT_TLS) + .Case("funcindex", VK_WASM_FUNCINDEX) + .Case("gotpcrel32@lo", VK_AMDGPU_GOTPCREL32_LO) + .Case("gotpcrel32@hi", VK_AMDGPU_GOTPCREL32_HI) + .Case("rel32@lo", VK_AMDGPU_REL32_LO) + .Case("rel32@hi", VK_AMDGPU_REL32_HI) + .Case("rel64", VK_AMDGPU_REL64) + .Case("abs32@lo", VK_AMDGPU_ABS32_LO) + .Case("abs32@hi", VK_AMDGPU_ABS32_HI) + .Case("hi", VK_VE_HI32) + .Case("lo", VK_VE_LO32) + .Case("pc_hi", VK_VE_PC_HI32) + .Case("pc_lo", VK_VE_PC_LO32) + .Case("got_hi", VK_VE_GOT_HI32) + .Case("got_lo", VK_VE_GOT_LO32) + .Case("gotoff_hi", VK_VE_GOTOFF_HI32) + .Case("gotoff_lo", VK_VE_GOTOFF_LO32) + .Case("plt_hi", VK_VE_PLT_HI32) + .Case("plt_lo", VK_VE_PLT_LO32) + .Case("tls_gd_hi", VK_VE_TLS_GD_HI32) + .Case("tls_gd_lo", VK_VE_TLS_GD_LO32) + .Case("tpoff_hi", VK_VE_TPOFF_HI32) + .Case("tpoff_lo", VK_VE_TPOFF_LO32) + .Default(VK_Invalid); } /* *** */ diff --git a/llvm/lib/MC/WasmObjectWriter.cpp b/llvm/lib/MC/WasmObjectWriter.cpp --- a/llvm/lib/MC/WasmObjectWriter.cpp +++ b/llvm/lib/MC/WasmObjectWriter.cpp @@ -671,6 +671,7 @@ // Provisional value is same as the index return getRelocationIndexValue(RelEntry); case wasm::R_WASM_FUNCTION_INDEX_LEB: + case wasm::R_WASM_FUNCTION_INDEX_I32: case wasm::R_WASM_GLOBAL_INDEX_LEB: case wasm::R_WASM_GLOBAL_INDEX_I32: case wasm::R_WASM_TAG_INDEX_LEB: @@ -791,6 +792,7 @@ case wasm::R_WASM_TABLE_INDEX_I32: case wasm::R_WASM_MEMORY_ADDR_I32: case wasm::R_WASM_FUNCTION_OFFSET_I32: + case wasm::R_WASM_FUNCTION_INDEX_I32: case wasm::R_WASM_SECTION_OFFSET_I32: case wasm::R_WASM_GLOBAL_INDEX_I32: case wasm::R_WASM_MEMORY_ADDR_LOCREL_I32: diff --git a/llvm/lib/Object/WasmObjectFile.cpp b/llvm/lib/Object/WasmObjectFile.cpp --- a/llvm/lib/Object/WasmObjectFile.cpp +++ b/llvm/lib/Object/WasmObjectFile.cpp @@ -948,6 +948,7 @@ Reloc.Index = readVaruint32(Ctx); switch (type) { case wasm::R_WASM_FUNCTION_INDEX_LEB: + case wasm::R_WASM_FUNCTION_INDEX_I32: case wasm::R_WASM_TABLE_INDEX_SLEB: case wasm::R_WASM_TABLE_INDEX_SLEB64: case wasm::R_WASM_TABLE_INDEX_I32: @@ -1045,6 +1046,7 @@ Reloc.Type == wasm::R_WASM_MEMORY_ADDR_LOCREL_I32 || Reloc.Type == wasm::R_WASM_SECTION_OFFSET_I32 || Reloc.Type == wasm::R_WASM_FUNCTION_OFFSET_I32 || + Reloc.Type == wasm::R_WASM_FUNCTION_INDEX_I32 || Reloc.Type == wasm::R_WASM_GLOBAL_INDEX_I32) Size = 4; if (Reloc.Type == wasm::R_WASM_TABLE_INDEX_I64 || diff --git a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyWasmObjectWriter.cpp b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyWasmObjectWriter.cpp --- a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyWasmObjectWriter.cpp +++ b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyWasmObjectWriter.cpp @@ -91,6 +91,8 @@ return wasm::R_WASM_TYPE_INDEX_LEB; case MCSymbolRefExpr::VK_None: break; + case MCSymbolRefExpr::VK_WASM_FUNCINDEX: + return wasm::R_WASM_FUNCTION_INDEX_I32; default: report_fatal_error("unknown VariantKind"); break; diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.h b/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.h --- a/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.h +++ b/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.h @@ -66,6 +66,7 @@ void emitEndOfAsmFile(Module &M) override; void EmitProducerInfo(Module &M); void EmitTargetFeatures(Module &M); + void EmitAsync(Module &M); void emitSymbolType(const MCSymbolWasm *Sym); void emitGlobalVariable(const GlobalVariable *GV) override; void emitJumpTableInfo() override; diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp --- a/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp @@ -438,6 +438,7 @@ EmitProducerInfo(M); EmitTargetFeatures(M); + EmitAsync(M); } void WebAssemblyAsmPrinter::EmitProducerInfo(Module &M) { @@ -556,6 +557,33 @@ OutStreamer->popSection(); } +void WebAssemblyAsmPrinter::EmitAsync(Module &M) { + SmallVector EmittedAsyncs; + + for (const auto &F : M) { + auto *Sym = cast(getSymbol(&F)); + if (F.hasFnAttribute("wasm-async")) { + EmittedAsyncs.push_back(Sym); + } + } + if (EmittedAsyncs.size() == 0) + return; + + MCSectionWasm *AsyncSection = OutContext.getWasmSection( + ".custom_section.async", SectionKind::getMetadata()); + OutStreamer->pushSection(); + OutStreamer->switchSection(AsyncSection); + + for (auto &Sym : EmittedAsyncs) { + OutStreamer->emitValue( + MCSymbolRefExpr::create(Sym, MCSymbolRefExpr::VK_WASM_FUNCINDEX, + OutContext), + 4); + } + + OutStreamer->popSection(); +} + void WebAssemblyAsmPrinter::emitConstantPool() { emitDecls(*MMI->getModule()); assert(MF->getConstantPool()->getConstants().empty() && diff --git a/llvm/test/CodeGen/WebAssembly/async.ll b/llvm/test/CodeGen/WebAssembly/async.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/WebAssembly/async.ll @@ -0,0 +1,18 @@ +; RUN: llc < %s -asm-verbose=false -wasm-keep-registers | FileCheck %s + +target triple = "wasm32-unknown-unknown" + +define void @test0() #0 { + ret void +} + +define void @test1() #1 { + ret void +} + +attributes #0 = { "wasm-async" } +attributes #1 = { "wasm-async" } + +; CHECK: .section .custom_section.async,"",@ +; CHECK-NEXT: .int32 test0@FUNCINDEX +; CHECK-NEXT: .int32 test1@FUNCINDEX diff --git a/llvm/test/MC/WebAssembly/async.s b/llvm/test/MC/WebAssembly/async.s new file mode 100644 --- /dev/null +++ b/llvm/test/MC/WebAssembly/async.s @@ -0,0 +1,21 @@ +# 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 () -> () + end_function + +.section .custom_section.async,"",@ + .int32 foo@FUNCINDEX + +# CHECK: .section .custom_section.async,"",@ +# CHECK-NEXT: .int32 foo@FUNCINDEX + +# CHECK-OBJ: - Type: CUSTOM +# CHECK-OBJ-NEXT: Relocations: +# CHECK-OBJ-NEXT: - Type: R_WASM_FUNCTION_INDEX_I32 +# CHECK-OBJ-NEXT: Index: 0 +# CHECK-OBJ-NEXT: Offset: 0x0 +# CHECK-OBJ-NEXT: Name: async