llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-llvm-ir Author: Alex Crichton (alexcrichton) <details> <summary>Changes</summary> This is an implementation of WebAssembly/tool-conventions#<!-- -->268 here in LLVM. This adds a new calling convention to Clang, named `wasm_multivalue`, which is intended to be used on WebAssembly targets to configure multiple return values and slightly tweak the ABI. Changes here are: * Parsing/validation of `__attribute__((wasm_multivalue))`. Note that validation here means that it's not only well-formed but on wasm targets the `multivalue` target feature is additionally enabled. * Clang-level ABI adjustments for the `wasm_multivalue` calling convention. These are defined by WebAssembly/tool-conventions#<!-- -->268 and notably includes expanding structs with exactly 2 scalar fields in parameter-position and directly returning structs with any number of scalar fields in return-position. * A new `wasm_multivaluecc` keyword/calling convention for LLVM IR. This is what Clang lowers to when using the `wasm_multivalue` calling convention. * Adjustments at the LLVM ABI layer to support returning multiple values with the `wasm_multivaluecc` calling convention. My goal after this would be to start integrating this into Rust next, under and unstable feature, and then further continue testing/vetting/etc for component model usage. --- Patch is 39.14 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/200076.diff 30 Files Affected: - (modified) clang/include/clang/Basic/Attr.td (+6) - (modified) clang/include/clang/Basic/AttrDocs.td (+15) - (modified) clang/include/clang/Basic/DiagnosticSemaKinds.td (+4-1) - (modified) clang/include/clang/Basic/Specifiers.h (+1) - (modified) clang/lib/AST/ItaniumMangle.cpp (+1) - (modified) clang/lib/AST/Type.cpp (+3) - (modified) clang/lib/AST/TypePrinter.cpp (+6) - (modified) clang/lib/Basic/Targets/WebAssembly.h (+1) - (modified) clang/lib/CodeGen/CGCall.cpp (+2) - (modified) clang/lib/CodeGen/CGDebugInfo.cpp (+2) - (modified) clang/lib/CodeGen/Targets/WebAssembly.cpp (+68-6) - (modified) clang/lib/Sema/SemaDeclAttr.cpp (+13) - (modified) clang/lib/Sema/SemaType.cpp (+4-1) - (added) clang/test/CodeGen/WebAssembly/wasm-multivalue-abi.c (+77) - (added) clang/test/CodeGen/WebAssembly/wasm-multivalue-functype.c (+45) - (added) clang/test/Sema/attr-wasm-multivalue.c (+33) - (modified) llvm/include/llvm/AsmParser/LLToken.h (+1) - (modified) llvm/include/llvm/BinaryFormat/Dwarf.def (+1) - (modified) llvm/include/llvm/IR/CallingConv.h (+4) - (modified) llvm/lib/AsmParser/LLLexer.cpp (+1) - (modified) llvm/lib/AsmParser/LLParser.cpp (+4) - (modified) llvm/lib/IR/AsmWriter.cpp (+3) - (modified) llvm/lib/IR/Function.cpp (+1) - (modified) llvm/lib/Target/WebAssembly/GISel/WebAssemblyCallLowering.cpp (+3-2) - (modified) llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp (+5-3) - (modified) llvm/lib/Target/WebAssembly/WebAssemblyMachineFunctionInfo.cpp (+1-1) - (modified) llvm/lib/Target/WebAssembly/WebAssemblyRuntimeLibcallSignatures.cpp (+13-13) - (modified) llvm/lib/Target/WebAssembly/WebAssemblyUtilities.cpp (+9-4) - (modified) llvm/lib/Target/WebAssembly/WebAssemblyUtilities.h (+8-4) - (added) llvm/test/CodeGen/WebAssembly/wasm-multivalue-cc.ll (+38) ``````````diff diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td index 70b5773f95b08..42a68ff02975d 100644 --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -3559,6 +3559,12 @@ def M68kRTD: DeclOrTypeAttr { let Documentation = [M68kRTDDocs]; } +def WasmMultivalue : DeclOrTypeAttr, + TargetSpecificAttr<TargetWebAssembly> { + let Spellings = [Clang<"wasm_multivalue">]; + let Documentation = [WasmMultivalueDocs]; +} + def PreserveNone : DeclOrTypeAttr, TargetSpecificAttr<TargetArch<!listconcat(TargetAArch64.Arches, TargetAnyX86.Arches)>> { let Spellings = [Clang<"preserve_none">]; diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td index 87b9053be7cb6..dafba0108506d 100644 --- a/clang/include/clang/Basic/AttrDocs.td +++ b/clang/include/clang/Basic/AttrDocs.td @@ -3732,6 +3732,21 @@ using the `rtd` instruction. }]; } +def WasmMultivalueDocs : Documentation { + let Category = DocCatCallingConvs; + let Content = [{ +On WebAssembly targets, this attribute selects the ``wasm-multivalue`` calling +convention as defined in the WebAssembly/tool-conventions repository. Relative +to the default calling convention this takes advantage of the multi-value +proposal in its ABI definition. + +This calling convention requires the ``multivalue`` target feature. Using the +attribute without this feature enabled is a compile-time error. Enabling +``multivalue`` does not change the default calling convention; this attribute +must be used to opt in to the new behavior on a per-function basis. + }]; +} + def DocCatConsumed : DocumentationCategory<"Consumed Annotation Checking"> { let Content = [{ Clang supports additional attributes for checking basic resource management diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index e330ea03d0544..71df166089342 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -13828,7 +13828,7 @@ def err_builtin_pass_in_regs_non_class : Error< "argument %0 is not an unqualified class type">; -// WebAssembly reference type and table diagnostics. +// WebAssembly-related diagnostics. def err_wasm_reference_pr : Error< "%select{pointer|reference}0 to WebAssembly reference type is not allowed">; def err_wasm_ca_reference : Error< @@ -13871,6 +13871,9 @@ def err_wasm_builtin_test_fp_sig_cannot_include_struct_or_union : Error<"not supported with the multivalue ABI for " "function pointers with a struct/union as %select{return " "value|parameter}0">; +def err_wasm_multivalue_requires_feature : Error< + "the 'wasm_multivalue' calling convention requires the 'multivalue' target " + "feature to be enabled">; // OpenACC diagnostics. def warn_acc_routine_unimplemented diff --git a/clang/include/clang/Basic/Specifiers.h b/clang/include/clang/Basic/Specifiers.h index 8da6fd4cf454a..b50deb91eef2c 100644 --- a/clang/include/clang/Basic/Specifiers.h +++ b/clang/include/clang/Basic/Specifiers.h @@ -313,6 +313,7 @@ namespace clang { CC_RISCVVLSCall_16384, // __attribute__((riscv_vls_cc(16384))) CC_RISCVVLSCall_32768, // __attribute__((riscv_vls_cc(32768))) CC_RISCVVLSCall_65536, // __attribute__((riscv_vls_cc(65536))) + CC_WasmMultivalue, // __attribute__((wasm_multivalue)) }; /// Checks whether the given calling convention supports variadic diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp index 1cb6fa05f22ac..743dc390866d6 100644 --- a/clang/lib/AST/ItaniumMangle.cpp +++ b/clang/lib/AST/ItaniumMangle.cpp @@ -3534,6 +3534,7 @@ StringRef CXXNameMangler::getCallingConvQualifierName(CallingConv CC) { case CC_PreserveMost: case CC_PreserveAll: case CC_M68kRTD: + case CC_WasmMultivalue: case CC_PreserveNone: case CC_RISCVVectorCall: #define CC_VLS_CASE(ABI_VLEN) case CC_RISCVVLSCall_##ABI_VLEN: diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp index 96a398aa21dad..fa66c146b1d87 100644 --- a/clang/lib/AST/Type.cpp +++ b/clang/lib/AST/Type.cpp @@ -3741,6 +3741,8 @@ StringRef FunctionType::getNameForCallConv(CallingConv CC) { return "preserve_all"; case CC_M68kRTD: return "m68k_rtd"; + case CC_WasmMultivalue: + return "wasm_multivalue"; case CC_PreserveNone: return "preserve_none"; // clang-format off @@ -4552,6 +4554,7 @@ bool AttributedType::isCallingConv() const { case attr::PreserveMost: case attr::PreserveAll: case attr::M68kRTD: + case attr::WasmMultivalue: case attr::PreserveNone: case attr::RISCVVectorCC: case attr::RISCVVLSCC: diff --git a/clang/lib/AST/TypePrinter.cpp b/clang/lib/AST/TypePrinter.cpp index 80f5b90ba35c4..273e12168ac97 100644 --- a/clang/lib/AST/TypePrinter.cpp +++ b/clang/lib/AST/TypePrinter.cpp @@ -1173,6 +1173,9 @@ void TypePrinter::printFunctionAfter(const FunctionType::ExtInfo &Info, case CC_M68kRTD: OS << " __attribute__((m68k_rtd))"; break; + case CC_WasmMultivalue: + OS << " __attribute__((wasm_multivalue))"; + break; case CC_PreserveNone: OS << " __attribute__((preserve_none))"; break; @@ -2081,6 +2084,9 @@ void TypePrinter::printAttributedAfter(const AttributedType *T, case attr::M68kRTD: OS << "m68k_rtd"; break; + case attr::WasmMultivalue: + OS << "wasm_multivalue"; + break; case attr::RISCVVectorCC: OS << "riscv_vector_cc"; break; diff --git a/clang/lib/Basic/Targets/WebAssembly.h b/clang/lib/Basic/Targets/WebAssembly.h index 6085197498163..165acaabe96df 100644 --- a/clang/lib/Basic/Targets/WebAssembly.h +++ b/clang/lib/Basic/Targets/WebAssembly.h @@ -184,6 +184,7 @@ class LLVM_LIBRARY_VISIBILITY WebAssemblyTargetInfo : public TargetInfo { switch (CC) { case CC_C: case CC_Swift: + case CC_WasmMultivalue: return CCCR_OK; case CC_SwiftAsync: return CCCR_Error; diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp index 40cc275d40273..2dad85ec71e30 100644 --- a/clang/lib/CodeGen/CGCall.cpp +++ b/clang/lib/CodeGen/CGCall.cpp @@ -103,6 +103,8 @@ unsigned CodeGenTypes::ClangCallConvToLLVMCallConv(CallingConv CC) { return llvm::CallingConv::SwiftTail; case CC_M68kRTD: return llvm::CallingConv::M68k_RTD; + case CC_WasmMultivalue: + return llvm::CallingConv::WASM_Multivalue; case CC_PreserveNone: return llvm::CallingConv::PreserveNone; // clang-format off diff --git a/clang/lib/CodeGen/CGDebugInfo.cpp b/clang/lib/CodeGen/CGDebugInfo.cpp index 0d45df02a2a21..090741c1ff992 100644 --- a/clang/lib/CodeGen/CGDebugInfo.cpp +++ b/clang/lib/CodeGen/CGDebugInfo.cpp @@ -1838,6 +1838,8 @@ static unsigned getDwarfCC(CallingConv CC) { return llvm::dwarf::DW_CC_LLVM_X86RegCall; case CC_M68kRTD: return llvm::dwarf::DW_CC_LLVM_M68kRTD; + case CC_WasmMultivalue: + return llvm::dwarf::DW_CC_LLVM_WasmMultivalue; case CC_PreserveNone: return llvm::dwarf::DW_CC_LLVM_PreserveNone; case CC_RISCVVectorCall: diff --git a/clang/lib/CodeGen/Targets/WebAssembly.cpp b/clang/lib/CodeGen/Targets/WebAssembly.cpp index ebe996a4edd8d..8942e3e78b6de 100644 --- a/clang/lib/CodeGen/Targets/WebAssembly.cpp +++ b/clang/lib/CodeGen/Targets/WebAssembly.cpp @@ -28,17 +28,19 @@ class WebAssemblyABIInfo final : public ABIInfo { : ABIInfo(CGT), defaultInfo(CGT), Kind(Kind) {} private: - ABIArgInfo classifyReturnType(QualType RetTy) const; - ABIArgInfo classifyArgumentType(QualType Ty) const; + ABIArgInfo classifyReturnType(QualType RetTy, llvm::CallingConv::ID CC) const; + ABIArgInfo classifyArgumentType(QualType Ty, llvm::CallingConv::ID CC) const; // DefaultABIInfo's classifyReturnType and classifyArgumentType are // non-virtual, but computeInfo and EmitVAArg are virtual, so we // overload them. void computeInfo(CGFunctionInfo &FI) const override { + llvm::CallingConv::ID CC = FI.getCallingConvention(); if (!getCXXABI().classifyReturnType(FI)) - FI.getReturnInfo() = classifyReturnType(FI.getReturnType()); + FI.getReturnInfo() = + classifyReturnType(FI.getReturnType(), CC); for (auto &Arg : FI.arguments()) - Arg.info = classifyArgumentType(Arg.type); + Arg.info = classifyArgumentType(Arg.type, CC); } RValue EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, QualType Ty, @@ -95,8 +97,54 @@ class WebAssemblyTargetCodeGenInfo final : public TargetCodeGenInfo { } }; +/// Count the number of "scalar fields" in the given record type, as defined by +/// WebAssembly/tool-conventions for the "wasm-multivalue" calling convention +/// primarily. A scalar field is a field that recursively, through nested +/// structs, unions, and arrays, contains just a single scalar value. +/// +/// Returns the number of scalar fields, or std::nullopt if the record contains +/// a field that is not a scalar field (e.g., a sub-aggregate with multiple +/// scalars, a bit-field, or a flexible array member). +/// +/// Note that this is similar to `isSingleElementStruct` in structure. +static std::optional<unsigned> countScalarFields(ASTContext &Context, QualType T) { + const auto *RD = T->getAsRecordDecl(); + if (!RD) + return std::nullopt; + if (RD->hasFlexibleArrayMember()) + return std::nullopt; + + unsigned Count = 0; + + // Check bases first for C++ records. + if (const auto *CXXRD = dyn_cast<CXXRecordDecl>(RD)) { + for (const auto &Base : CXXRD->bases()) { + auto SubCount = countScalarFields(Context, Base.getType()); + if (!SubCount) + return std::nullopt; + Count += *SubCount; + } + } + + for (const auto *FD : RD->fields()) { + if (FD->isBitField()) + return std::nullopt; + if (isEmptyField(Context, FD, true)) + continue; + + QualType T = FD->getType(); + if (isAggregateTypeForABI(T) && !isSingleElementStruct(T, Context)) + return std::nullopt; + + ++Count; + } + + return Count; +} + /// Classify argument of given type \p Ty. -ABIArgInfo WebAssemblyABIInfo::classifyArgumentType(QualType Ty) const { +ABIArgInfo WebAssemblyABIInfo::classifyArgumentType(QualType Ty, + llvm::CallingConv::ID CC) const { Ty = useFirstFieldIfTransparentUnion(Ty); if (isAggregateTypeForABI(Ty)) { @@ -113,6 +161,12 @@ ABIArgInfo WebAssemblyABIInfo::classifyArgumentType(QualType Ty) const { // though watch out for things like bitfields. if (const Type *SeltTy = isSingleElementStruct(Ty, getContext())) return ABIArgInfo::getDirect(CGT.ConvertType(QualType(SeltTy, 0))); + // For the wasm-multivalue calling convention, structs with exactly two + // scalar fields are passed directly as two arguments. + if (CC == llvm::CallingConv::WASM_Multivalue) { + if (auto N = countScalarFields(getContext(), Ty); N && *N == 2) + return ABIArgInfo::getExpand(); + } // For the experimental multivalue ABI, fully expand all other aggregates if (Kind == WebAssemblyABIKind::ExperimentalMV) { const auto *RD = Ty->castAsRecordDecl(); @@ -132,7 +186,8 @@ ABIArgInfo WebAssemblyABIInfo::classifyArgumentType(QualType Ty) const { return defaultInfo.classifyArgumentType(Ty); } -ABIArgInfo WebAssemblyABIInfo::classifyReturnType(QualType RetTy) const { +ABIArgInfo WebAssemblyABIInfo::classifyReturnType(QualType RetTy, + llvm::CallingConv::ID CC) const { if (isAggregateTypeForABI(RetTy)) { // Records with non-trivial destructors/copy-constructors should not be // returned by value. @@ -145,6 +200,13 @@ ABIArgInfo WebAssemblyABIInfo::classifyReturnType(QualType RetTy) const { // ABIArgInfo::getDirect(). if (const Type *SeltTy = isSingleElementStruct(RetTy, getContext())) return ABIArgInfo::getDirect(CGT.ConvertType(QualType(SeltTy, 0))); + // For the wasm-multivalue calling convention, structs whose fields are + // (recursively) scalars are returned directly via the multivalue + // proposal. + if (CC == llvm::CallingConv::WASM_Multivalue) { + if (auto N = countScalarFields(getContext(), RetTy); N && *N > 0) + return ABIArgInfo::getDirect(); + } // For the experimental multivalue ABI, return all other aggregates if (Kind == WebAssemblyABIKind::ExperimentalMV) return ABIArgInfo::getDirect(); diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index ae04d3855f01c..ac21210bd7112 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -5543,6 +5543,9 @@ static void handleCallConvAttr(Sema &S, Decl *D, const ParsedAttr &AL) { case ParsedAttr::AT_M68kRTD: D->addAttr(::new (S.Context) M68kRTDAttr(S.Context, AL)); return; + case ParsedAttr::AT_WasmMultivalue: + D->addAttr(::new (S.Context) WasmMultivalueAttr(S.Context, AL)); + return; case ParsedAttr::AT_PreserveNone: D->addAttr(::new (S.Context) PreserveNoneAttr(S.Context, AL)); return; @@ -5814,6 +5817,15 @@ bool Sema::CheckCallingConvAttr(const ParsedAttr &Attrs, CallingConv &CC, case ParsedAttr::AT_M68kRTD: CC = CC_M68kRTD; break; + case ParsedAttr::AT_WasmMultivalue: + CC = CC_WasmMultivalue; + if (Context.getTargetInfo().getTriple().isWasm() && + !Context.getTargetInfo().hasFeature("multivalue")) { + Attrs.setInvalid(); + Diag(Attrs.getLoc(), diag::err_wasm_multivalue_requires_feature); + return true; + } + break; case ParsedAttr::AT_PreserveNone: CC = CC_PreserveNone; break; @@ -8068,6 +8080,7 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL, case ParsedAttr::AT_PreserveNone: case ParsedAttr::AT_RISCVVectorCC: case ParsedAttr::AT_RISCVVLSCC: + case ParsedAttr::AT_WasmMultivalue: handleCallConvAttr(S, D, AL); break; case ParsedAttr::AT_DeviceKernel: diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index 44ac4f6630690..2811cb0ee95d4 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -143,7 +143,8 @@ static void diagnoseBadTypeAttribute(Sema &S, const ParsedAttr &attr, case ParsedAttr::AT_M68kRTD: \ case ParsedAttr::AT_PreserveNone: \ case ParsedAttr::AT_RISCVVectorCC: \ - case ParsedAttr::AT_RISCVVLSCC + case ParsedAttr::AT_RISCVVLSCC: \ + case ParsedAttr::AT_WasmMultivalue // Function type attributes. #define FUNCTION_TYPE_ATTRS_CASELIST \ @@ -7803,6 +7804,8 @@ static Attr *getCCTypeAttr(ASTContext &Ctx, ParsedAttr &Attr) { return createSimpleAttr<PreserveAllAttr>(Ctx, Attr); case ParsedAttr::AT_M68kRTD: return createSimpleAttr<M68kRTDAttr>(Ctx, Attr); + case ParsedAttr::AT_WasmMultivalue: + return createSimpleAttr<WasmMultivalueAttr>(Ctx, Attr); case ParsedAttr::AT_PreserveNone: return createSimpleAttr<PreserveNoneAttr>(Ctx, Attr); case ParsedAttr::AT_RISCVVectorCC: diff --git a/clang/test/CodeGen/WebAssembly/wasm-multivalue-abi.c b/clang/test/CodeGen/WebAssembly/wasm-multivalue-abi.c new file mode 100644 index 0000000000000..5194616a13733 --- /dev/null +++ b/clang/test/CodeGen/WebAssembly/wasm-multivalue-abi.c @@ -0,0 +1,77 @@ +// RUN: %clang_cc1 -triple wasm32-unknown-unknown -target-feature +multivalue \ +// RUN: %s -emit-llvm -o - | FileCheck %s +// RUN: %clang_cc1 -triple wasm64-unknown-unknown -target-feature +multivalue \ +// RUN: %s -emit-llvm -o - | FileCheck %s + +// Verify that the `wasm_multivalue` calling convention produces the function +// signatures described in the WebAssembly tool conventions PR. + +// CHECK-LABEL: define wasm_multivaluecc void @f1() +__attribute__((wasm_multivalue)) +void f1(void) {} + +// CHECK-LABEL: define wasm_multivaluecc i32 @f2(float {{.*}}, double {{.*}}) +__attribute__((wasm_multivalue)) +int f2(float a, double b) { return (int)(a + b); } + +// CHECK-LABEL: define wasm_multivaluecc i128 @f3(fp128 +__attribute__((wasm_multivalue)) +__int128 f3(long double x) { return (__int128)x; } + +struct Foo4 { }; +union Bar4 { }; + +// CHECK-LABEL: define wasm_multivaluecc void @f4() +__attribute__((wasm_multivalue)) +union Bar4 f4(struct Foo4 x) { union Bar4 r; return r; } + +struct Foo5 { int a; }; +union Bar5 { int a; }; + +// CHECK-LABEL: define wasm_multivaluecc i32 @f5(i32 +__attribute__((wasm_multivalue)) +union Bar5 f5(struct Foo5 x) { union Bar5 r; r.a = x.a; return r; } + +struct Foo6 { int a; int b; }; + +// CHECK-LABEL: define wasm_multivaluecc %struct.Foo6 @f6(i32 {{.*}}, i32 {{.*}}) +__attribute__((wasm_multivalue)) +struct Foo6 f6(struct Foo6 x) { return x; } + +// CHECK-LABEL: define wasm_multivaluecc i128 @f7() +__attribute__((wasm_multivalue)) +__int128 f7(void) { return 1; } + +struct Foo8 { int a; int b; int c; }; +// CHECK-LABEL: define wasm_multivaluecc %struct.Foo8 @f8(ptr +__attribute__((wasm_multivalue)) +struct Foo8 f8(struct Foo8 x) { return x; } + +struct Foo9 { + struct Foo6 inner; +}; +// CHECK-LABEL: define wasm_multivaluecc void @f9(ptr {{.*}} sret +__attribute__((wasm_multivalue)) +struct Foo9 f9(void) { struct Foo9 r = {{0, 0}}; return r; } + +// bitfields force pointers +struct Foo10 { + int a : 4; + int b : 4; +}; +// CHECK-LABEL: define wasm_multivaluecc void @f10(ptr +__attribute__((wasm_multivalue)) +struct Foo10 f10(void) { struct Foo10 r = {0, 0}; return r; } + +// The default calling convention isn't changed from `+multivalue` +// CHECK-LABEL: define void @f11(ptr{{.*}}sret(%struct.Foo6){{.*}}, ptr {{.*}}byval(%struct.Foo6) +struct Foo6 f11(struct Foo6 x) { return x; } + +// Test cross-calling-convention indierct calls +typedef __attribute__((wasm_multivalue)) struct Foo6 (*mv_ptr)(struct Foo6); + +// CHECK-LABEL: define void @f12( +// CHECK: call wasm_multivaluecc {{(noundef )?}}%struct.Foo6 %0(i32{{.*}}, i32 +struct Foo6 f12(mv_ptr fn, struct Foo6 x) { + return fn(x); +} diff --git a/clang/test/CodeGen/WebAssembly/wasm-multivalue-functype.c b/clang/test/CodeGen/WebAssembly/wasm-multivalue-functype.c new file mode 100644 index 0000000000000..c522640901473 --- /dev/null +++ b/clang/test/CodeGen/WebAssembly/wasm-multivalue-functype.c @@ -0,0 +1,45 @@ +// RUN: %clang_cc1 -triple wasm32-unknown-unknown -target-feature +multivalue %s -S -O2 -o - | FileCheck %s + +// CHECK: .functype f1 () -> () +void f1(void) {} +// CHECK: .functype f1mv () -> () +__attribute__((wasm_multivalue)) +void f1mv(void) {} + +// CHECK: .functype f2 (f32, f64) -> (i32) +int f2(float a, double b) { return (int)(a + b); } +// CHECK: .functype f2mv (f32, f64) -> (i32) +__attribute__((wasm_multivalue)) +int f2mv(float a, double b) { return (int)(a + b); } + +// CHECK: .functype f3 (i32, i64, i64) -> () +__int128 f3(long double x) { return (__int128)x; } +// CHECK: .functype f3mv (i64, i64) -> (i64, i64) +__attribute__((wasm_multivalue)) +__int128 f3mv(long double x) { return (__int128)x; } + +struct Foo4 { }; +union Bar4 { }; + +// CHECK: .functype f4 () -> () +union Bar4 f4(struct Foo4 x) { union Bar4 r; return r; } +// CHECK: .functype f4mv () -> () +__attribute__((wasm_multivalue)) +union Bar4 f4mv(struct Foo4 x) { union Bar4 r; return r; } + +struct Foo5 { int a; }; +union Bar5 { int a; }; + +// CHECK: .functype f5 (i32) -> (i32) +union Bar5 f5(struct Foo5 x) { union Bar5 r; r.a = x.a; return r; } +// CHECK: .functype f5mv (i32) -> (i32) +__attribute__((wasm_multivalue)) +union Bar5 f5mv(struct Foo5 x) { union Bar5 r; r.a = x.a; return r; } + +struct Foo6 { int a; int b; }; + +// CHECK: .functype f6 (i32, i32) -> () +struct Foo6 f6(struct Foo6 x) { return x; } +// CHECK: .functype f6mv (i32, i32) -> (i32, i32) +__attribute__((wasm_multivalue)) +struct Foo6 f6mv(struct Foo6 x) { return x; } diff --git a/clang/test/Sema/attr-wasm-multivalue.c b/clang/test/Sema/attr-wasm-multivalue.c new file mode 100644 index 0000000000000..51e9f494b657d --- /dev/null +++ b/clang/test/Sema/attr-wasm-multivalue.c @@ -0,0 +1,33 @@ +// RUN: %clang_cc1 -triple wasm32-unknown-unknown -target-feature +multivalue -fsyntax-only -verify=enabled %s... [truncated] `````````` </details> https://github.com/llvm/llvm-project/pull/200076 _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
