Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions clang/include/clang-c/Index.h
Original file line number Diff line number Diff line change
Expand Up @@ -3086,6 +3086,7 @@ enum CXCallingConv {
CXCallingConv_RISCVVLSCall_16384 = 31,
CXCallingConv_RISCVVLSCall_32768 = 32,
CXCallingConv_RISCVVLSCall_65536 = 33,
CXCallingConv_WasmMultivalue = 34,

CXCallingConv_Invalid = 100,
CXCallingConv_Unexposed = 200
Expand Down
6 changes: 6 additions & 0 deletions clang/include/clang/Basic/Attr.td
Original file line number Diff line number Diff line change
Expand Up @@ -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">];
Expand Down
15 changes: 15 additions & 0 deletions clang/include/clang/Basic/AttrDocs.td
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
5 changes: 4 additions & 1 deletion clang/include/clang/Basic/DiagnosticSemaKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -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<
Expand Down Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions clang/include/clang/Basic/Specifiers.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions clang/lib/AST/ItaniumMangle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
3 changes: 3 additions & 0 deletions clang/lib/AST/Type.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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:
Expand Down
6 changes: 6 additions & 0 deletions clang/lib/AST/TypePrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down
1 change: 1 addition & 0 deletions clang/lib/Basic/Targets/WebAssembly.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
2 changes: 2 additions & 0 deletions clang/lib/CodeGen/CGCall.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 2 additions & 0 deletions clang/lib/CodeGen/CGDebugInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
76 changes: 70 additions & 6 deletions clang/lib/CodeGen/Targets/WebAssembly.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,17 +28,18 @@ 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,
Expand Down Expand Up @@ -95,8 +96,56 @@ 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)) {
Expand All @@ -113,6 +162,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();
Expand All @@ -132,7 +187,9 @@ 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.
Expand All @@ -145,6 +202,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();
Expand Down
13 changes: 13 additions & 0 deletions clang/lib/Sema/SemaDeclAttr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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:
Expand Down
5 changes: 4 additions & 1 deletion clang/lib/Sema/SemaType.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 \
Expand Down Expand Up @@ -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:
Expand Down
Loading
Loading