mirror of
https://github.com/llvm/llvm-project.git
synced 2025-04-19 13:26:45 +00:00
[clang][WebAssembly] Initial support for reference type funcref in clang
This is the funcref counterpart to 890146b. We introduce a new attribute that marks a function pointer as a funcref. It also implements builtin __builtin_wasm_ref_null_func(), that returns a null funcref value. Differential Revision: https://reviews.llvm.org/D128440
This commit is contained in:
parent
d875838e8b
commit
8d0c889752
@ -1227,6 +1227,10 @@ public:
|
||||
/// have a FunctionType.
|
||||
const FunctionType *getFunctionType(bool BlocksToo = true) const;
|
||||
|
||||
// Looks through the Decl's underlying type to determine if it's a
|
||||
// function pointer type.
|
||||
bool isFunctionPointerType() const;
|
||||
|
||||
private:
|
||||
void setAttrsImpl(const AttrVec& Attrs, ASTContext &Ctx);
|
||||
void setDeclContextsImpl(DeclContext *SemaDC, DeclContext *LexicalDC,
|
||||
|
@ -4934,6 +4934,8 @@ public:
|
||||
|
||||
bool isMSTypeSpec() const;
|
||||
|
||||
bool isWebAssemblyFuncrefSpec() const;
|
||||
|
||||
bool isCallingConv() const;
|
||||
|
||||
std::optional<NullabilityKind> getImmediateNullability() const;
|
||||
|
@ -59,6 +59,9 @@ enum class LangAS : unsigned {
|
||||
// HLSL specific address spaces.
|
||||
hlsl_groupshared,
|
||||
|
||||
// Wasm specific address spaces.
|
||||
wasm_funcref,
|
||||
|
||||
// This denotes the count of language-specific address spaces and also
|
||||
// the offset added to the target-specific address spaces, which are usually
|
||||
// specified by address space attributes __attribute__(address_space(n))).
|
||||
|
@ -168,6 +168,12 @@ def FunctionLike : SubsetSubject<DeclBase,
|
||||
[{S->getFunctionType(false) != nullptr}],
|
||||
"functions, function pointers">;
|
||||
|
||||
// Function Pointer is a stricter version of FunctionLike that only allows function
|
||||
// pointers.
|
||||
def FunctionPointer : SubsetSubject<DeclBase,
|
||||
[{S->isFunctionPointerType()}],
|
||||
"functions pointers">;
|
||||
|
||||
def OpenCLKernelFunction
|
||||
: SubsetSubject<Function, [{S->hasAttr<OpenCLKernelAttr>()}],
|
||||
"kernel functions">;
|
||||
@ -4131,6 +4137,13 @@ def FunctionReturnThunks : InheritableAttr,
|
||||
let Subjects = SubjectList<[Function]>;
|
||||
let Documentation = [FunctionReturnThunksDocs];
|
||||
}
|
||||
|
||||
def WebAssemblyFuncref : TypeAttr, TargetSpecificAttr<TargetWebAssembly> {
|
||||
let Spellings = [Keyword<"__funcref">];
|
||||
let Documentation = [WebAssemblyExportNameDocs];
|
||||
let Subjects = SubjectList<[FunctionPointer], ErrorDiag>;
|
||||
}
|
||||
|
||||
def ReadOnlyPlacement : InheritableAttr {
|
||||
let Spellings = [Clang<"enforce_read_only_placement">];
|
||||
let Subjects = SubjectList<[Record]>;
|
||||
|
@ -6938,3 +6938,12 @@ def ReadOnlyPlacementDocs : Documentation {
|
||||
``enforce_read_only_placement`` attribute.
|
||||
}];
|
||||
}
|
||||
|
||||
def WebAssemblyFuncrefDocs : Documentation {
|
||||
let Category = DocCatType;
|
||||
let Content = [{
|
||||
Clang supports the ``__funcref`` attribute for the WebAssembly target.
|
||||
This attribute may be attached to a function pointer type, where it modifies
|
||||
its underlying representation to be a WebAssembly ``funcref``.
|
||||
}];
|
||||
}
|
||||
|
@ -191,8 +191,15 @@ TARGET_BUILTIN(__builtin_wasm_relaxed_dot_i8x16_i7x16_add_s_i32x4, "V4iV16ScV16S
|
||||
TARGET_BUILTIN(__builtin_wasm_relaxed_dot_bf16x8_add_f32_f32x4, "V4fV8UsV8UsV4f", "nc", "relaxed-simd")
|
||||
|
||||
// Reference Types builtins
|
||||
// Some builtins are custom type-checked - see 't' as part of the third argument,
|
||||
// in which case the argument spec (second argument) is unused.
|
||||
|
||||
TARGET_BUILTIN(__builtin_wasm_ref_null_extern, "i", "nct", "reference-types")
|
||||
|
||||
// A funcref represented as a function pointer with the funcref attribute
|
||||
// attached to the type, therefore SemaChecking will check for the right
|
||||
// return type.
|
||||
TARGET_BUILTIN(__builtin_wasm_ref_null_func, "i", "nct", "reference-types")
|
||||
|
||||
#undef BUILTIN
|
||||
#undef TARGET_BUILTIN
|
||||
|
@ -7385,6 +7385,8 @@ def err_attribute_arm_builtin_alias : Error<
|
||||
"'__clang_arm_builtin_alias' attribute can only be applied to an ARM builtin">;
|
||||
def err_attribute_arm_mve_polymorphism : Error<
|
||||
"'__clang_arm_mve_strict_polymorphism' attribute can only be applied to an MVE/NEON vector type">;
|
||||
def err_attribute_webassembly_funcref : Error<
|
||||
"'__funcref' attribute can only be applied to a function pointer type">;
|
||||
|
||||
def warn_setter_getter_impl_required : Warning<
|
||||
"property %0 requires method %1 to be defined - "
|
||||
@ -11798,4 +11800,6 @@ def err_wasm_reference_pr : Error<
|
||||
"%select{pointer|reference}0 to WebAssembly reference type is not allowed">;
|
||||
def err_wasm_ca_reference : Error<
|
||||
"cannot %select{capture|take address of}0 WebAssembly reference">;
|
||||
def err_wasm_funcref_not_wasm : Error<
|
||||
"invalid use of '__funcref' keyword outside the WebAssembly triple">;
|
||||
} // end of sema component.
|
||||
|
@ -680,6 +680,9 @@ KEYWORD(_Nullable , KEYALL)
|
||||
KEYWORD(_Nullable_result , KEYALL)
|
||||
KEYWORD(_Null_unspecified , KEYALL)
|
||||
|
||||
// WebAssembly Type Extension
|
||||
KEYWORD(__funcref , KEYALL)
|
||||
|
||||
// Microsoft extensions which should be disabled in strict conformance mode
|
||||
KEYWORD(__ptr64 , KEYMS)
|
||||
KEYWORD(__ptr32 , KEYMS)
|
||||
|
@ -2930,6 +2930,7 @@ private:
|
||||
SourceLocation AttrNameLoc,
|
||||
ParsedAttributes &Attrs);
|
||||
void ParseMicrosoftTypeAttributes(ParsedAttributes &attrs);
|
||||
void ParseWebAssemblyFuncrefTypeAttribute(ParsedAttributes &Attrs);
|
||||
void DiagnoseAndSkipExtendedMicrosoftTypeAttributes();
|
||||
SourceLocation SkipExtendedMicrosoftTypeAttributes();
|
||||
void ParseMicrosoftInheritanceClassAttributes(ParsedAttributes &attrs);
|
||||
|
@ -13594,6 +13594,7 @@ private:
|
||||
|
||||
// WebAssembly builtin handling.
|
||||
bool BuiltinWasmRefNullExtern(CallExpr *TheCall);
|
||||
bool BuiltinWasmRefNullFunc(CallExpr *TheCall);
|
||||
|
||||
public:
|
||||
enum FormatStringType {
|
||||
|
@ -1048,6 +1048,18 @@ const FunctionType *Decl::getFunctionType(bool BlocksToo) const {
|
||||
return Ty->getAs<FunctionType>();
|
||||
}
|
||||
|
||||
bool Decl::isFunctionPointerType() const {
|
||||
QualType Ty;
|
||||
if (const auto *D = dyn_cast<ValueDecl>(this))
|
||||
Ty = D->getType();
|
||||
else if (const auto *D = dyn_cast<TypedefNameDecl>(this))
|
||||
Ty = D->getUnderlyingType();
|
||||
else
|
||||
return false;
|
||||
|
||||
return Ty.getCanonicalType()->isFunctionPointerType();
|
||||
}
|
||||
|
||||
DeclContext *Decl::getNonTransparentDeclContext() {
|
||||
assert(getDeclContext());
|
||||
return getDeclContext()->getNonTransparentContext();
|
||||
|
@ -3674,6 +3674,10 @@ bool AttributedType::isMSTypeSpec() const {
|
||||
llvm_unreachable("invalid attr kind");
|
||||
}
|
||||
|
||||
bool AttributedType::isWebAssemblyFuncrefSpec() const {
|
||||
return getAttrKind() == attr::WebAssemblyFuncref;
|
||||
}
|
||||
|
||||
bool AttributedType::isCallingConv() const {
|
||||
// FIXME: Generate this with TableGen.
|
||||
switch (getAttrKind()) {
|
||||
|
@ -1651,6 +1651,9 @@ void TypePrinter::printAttributedBefore(const AttributedType *T,
|
||||
spaceBeforePlaceHolder(OS);
|
||||
}
|
||||
|
||||
if (T->isWebAssemblyFuncrefSpec())
|
||||
OS << "__funcref";
|
||||
|
||||
// Print nullability type specifiers.
|
||||
if (T->getImmediateNullability()) {
|
||||
if (T->getAttrKind() == attr::TypeNonNull)
|
||||
@ -1684,8 +1687,8 @@ void TypePrinter::printAttributedAfter(const AttributedType *T,
|
||||
|
||||
// Some attributes are printed as qualifiers before the type, so we have
|
||||
// nothing left to do.
|
||||
if (T->getAttrKind() == attr::ObjCKindOf ||
|
||||
T->isMSTypeSpec() || T->getImmediateNullability())
|
||||
if (T->getAttrKind() == attr::ObjCKindOf || T->isMSTypeSpec() ||
|
||||
T->getImmediateNullability() || T->isWebAssemblyFuncrefSpec())
|
||||
return;
|
||||
|
||||
// Don't print the inert __unsafe_unretained attribute at all.
|
||||
@ -1757,6 +1760,7 @@ void TypePrinter::printAttributedAfter(const AttributedType *T,
|
||||
case attr::AddressSpace:
|
||||
case attr::CmseNSCall:
|
||||
case attr::AnnotateType:
|
||||
case attr::WebAssemblyFuncref:
|
||||
llvm_unreachable("This attribute should have been handled already");
|
||||
|
||||
case attr::NSReturnsRetained:
|
||||
@ -2259,6 +2263,8 @@ std::string Qualifiers::getAddrSpaceAsString(LangAS AS) {
|
||||
return "__uptr __ptr32";
|
||||
case LangAS::ptr64:
|
||||
return "__ptr64";
|
||||
case LangAS::wasm_funcref:
|
||||
return "__funcref";
|
||||
case LangAS::hlsl_groupshared:
|
||||
return "groupshared";
|
||||
default:
|
||||
|
@ -47,6 +47,7 @@ static const LangASMap FakeAddrSpaceMap = {
|
||||
11, // ptr32_uptr
|
||||
12, // ptr64
|
||||
13, // hlsl_groupshared
|
||||
20, // wasm_funcref
|
||||
};
|
||||
|
||||
// TargetInfo Constructor.
|
||||
|
@ -42,6 +42,9 @@ static const unsigned DirectXAddrSpaceMap[] = {
|
||||
0, // ptr32_uptr
|
||||
0, // ptr64
|
||||
3, // hlsl_groupshared
|
||||
// Wasm address space values for this target are dummy values,
|
||||
// as it is only enabled for Wasm targets.
|
||||
20, // wasm_funcref
|
||||
};
|
||||
|
||||
class LLVM_LIBRARY_VISIBILITY DirectXTargetInfo : public TargetInfo {
|
||||
|
@ -45,6 +45,9 @@ static const unsigned NVPTXAddrSpaceMap[] = {
|
||||
0, // ptr32_uptr
|
||||
0, // ptr64
|
||||
0, // hlsl_groupshared
|
||||
// Wasm address space values for this target are dummy values,
|
||||
// as it is only enabled for Wasm targets.
|
||||
20, // wasm_funcref
|
||||
};
|
||||
|
||||
/// The DWARF address class. Taken from
|
||||
|
@ -46,6 +46,9 @@ static const unsigned SPIRDefIsPrivMap[] = {
|
||||
0, // ptr32_uptr
|
||||
0, // ptr64
|
||||
0, // hlsl_groupshared
|
||||
// Wasm address space values for this target are dummy values,
|
||||
// as it is only enabled for Wasm targets.
|
||||
20, // wasm_funcref
|
||||
};
|
||||
|
||||
// Used by both the SPIR and SPIR-V targets.
|
||||
@ -76,6 +79,9 @@ static const unsigned SPIRDefIsGenMap[] = {
|
||||
0, // ptr32_uptr
|
||||
0, // ptr64
|
||||
0, // hlsl_groupshared
|
||||
// Wasm address space values for this target are dummy values,
|
||||
// as it is only enabled for Wasm targets.
|
||||
20, // wasm_funcref
|
||||
};
|
||||
|
||||
// Base class for SPIR and SPIR-V target info.
|
||||
|
@ -51,6 +51,9 @@ static const unsigned TCEOpenCLAddrSpaceMap[] = {
|
||||
0, // ptr32_uptr
|
||||
0, // ptr64
|
||||
0, // hlsl_groupshared
|
||||
// Wasm address space values for this target are dummy values,
|
||||
// as it is only enabled for Wasm targets.
|
||||
20, // wasm_funcref
|
||||
};
|
||||
|
||||
class LLVM_LIBRARY_VISIBILITY TCETargetInfo : public TargetInfo {
|
||||
|
@ -21,6 +21,30 @@
|
||||
namespace clang {
|
||||
namespace targets {
|
||||
|
||||
static const unsigned WebAssemblyAddrSpaceMap[] = {
|
||||
0, // Default
|
||||
0, // opencl_global
|
||||
0, // opencl_local
|
||||
0, // opencl_constant
|
||||
0, // opencl_private
|
||||
0, // opencl_generic
|
||||
0, // opencl_global_device
|
||||
0, // opencl_global_host
|
||||
0, // cuda_device
|
||||
0, // cuda_constant
|
||||
0, // cuda_shared
|
||||
0, // sycl_global
|
||||
0, // sycl_global_device
|
||||
0, // sycl_global_host
|
||||
0, // sycl_local
|
||||
0, // sycl_private
|
||||
0, // ptr32_sptr
|
||||
0, // ptr32_uptr
|
||||
0, // ptr64
|
||||
0, // hlsl_groupshared
|
||||
20, // wasm_funcref
|
||||
};
|
||||
|
||||
class LLVM_LIBRARY_VISIBILITY WebAssemblyTargetInfo : public TargetInfo {
|
||||
|
||||
enum SIMDEnum {
|
||||
@ -45,6 +69,7 @@ class LLVM_LIBRARY_VISIBILITY WebAssemblyTargetInfo : public TargetInfo {
|
||||
public:
|
||||
explicit WebAssemblyTargetInfo(const llvm::Triple &T, const TargetOptions &)
|
||||
: TargetInfo(T) {
|
||||
AddrSpaceMap = &WebAssemblyAddrSpaceMap;
|
||||
NoAsmVariants = true;
|
||||
SuitableAlign = 128;
|
||||
LargeArrayMinWidth = 128;
|
||||
|
@ -46,6 +46,9 @@ static const unsigned X86AddrSpaceMap[] = {
|
||||
271, // ptr32_uptr
|
||||
272, // ptr64
|
||||
0, // hlsl_groupshared
|
||||
// Wasm address space values for this target are dummy values,
|
||||
// as it is only enabled for Wasm targets.
|
||||
20, // wasm_funcref
|
||||
};
|
||||
|
||||
// X86 target abstract base class; x86-32 and x86-64 are very close, so
|
||||
|
@ -18955,6 +18955,10 @@ Value *CodeGenFunction::EmitWebAssemblyBuiltinExpr(unsigned BuiltinID,
|
||||
Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_ref_null_extern);
|
||||
return Builder.CreateCall(Callee);
|
||||
}
|
||||
case WebAssembly::BI__builtin_wasm_ref_null_func: {
|
||||
Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_ref_null_func);
|
||||
return Builder.CreateCall(Callee);
|
||||
}
|
||||
case WebAssembly::BI__builtin_wasm_swizzle_i8x16: {
|
||||
Value *Src = EmitScalarExpr(E->getArg(0));
|
||||
Value *Indices = EmitScalarExpr(E->getArg(1));
|
||||
|
@ -900,6 +900,10 @@ public:
|
||||
virtual llvm::Type *getWasmExternrefReferenceType() const override {
|
||||
return llvm::Type::getWasm_ExternrefTy(getABIInfo().getVMContext());
|
||||
}
|
||||
/// Return the WebAssembly funcref reference type.
|
||||
virtual llvm::Type *getWasmFuncrefReferenceType() const override {
|
||||
return llvm::Type::getWasm_FuncrefTy(getABIInfo().getVMContext());
|
||||
}
|
||||
};
|
||||
|
||||
/// Classify argument of given type \p Ty.
|
||||
|
@ -365,6 +365,9 @@ public:
|
||||
/// Return the WebAssembly externref reference type.
|
||||
virtual llvm::Type *getWasmExternrefReferenceType() const { return nullptr; }
|
||||
|
||||
/// Return the WebAssembly funcref reference type.
|
||||
virtual llvm::Type *getWasmFuncrefReferenceType() const { return nullptr; }
|
||||
|
||||
/// Emit the device-side copy of the builtin surface type.
|
||||
virtual bool emitCUDADeviceBuiltinSurfaceDeviceCopy(CodeGenFunction &CGF,
|
||||
LValue Dst,
|
||||
|
@ -612,7 +612,7 @@ public:
|
||||
return isOneOf(tok::kw_const, tok::kw_restrict, tok::kw_volatile,
|
||||
tok::kw___attribute, tok::kw__Nonnull, tok::kw__Nullable,
|
||||
tok::kw__Null_unspecified, tok::kw___ptr32, tok::kw___ptr64,
|
||||
TT_AttributeMacro);
|
||||
tok::kw___funcref, TT_AttributeMacro);
|
||||
}
|
||||
|
||||
/// Determine whether the token is a simple-type-specifier.
|
||||
|
@ -852,6 +852,22 @@ void Parser::ParseMicrosoftTypeAttributes(ParsedAttributes &attrs) {
|
||||
}
|
||||
}
|
||||
|
||||
void Parser::ParseWebAssemblyFuncrefTypeAttribute(ParsedAttributes &attrs) {
|
||||
assert(Tok.is(tok::kw___funcref));
|
||||
SourceLocation StartLoc = Tok.getLocation();
|
||||
if (!getTargetInfo().getTriple().isWasm()) {
|
||||
ConsumeToken();
|
||||
Diag(StartLoc, diag::err_wasm_funcref_not_wasm);
|
||||
return;
|
||||
}
|
||||
|
||||
IdentifierInfo *AttrName = Tok.getIdentifierInfo();
|
||||
SourceLocation AttrNameLoc = ConsumeToken();
|
||||
attrs.addNew(AttrName, AttrNameLoc, /*ScopeName=*/nullptr,
|
||||
/*ScopeLoc=*/SourceLocation{}, /*Args=*/nullptr, /*numArgs=*/0,
|
||||
ParsedAttr::AS_Keyword);
|
||||
}
|
||||
|
||||
void Parser::DiagnoseAndSkipExtendedMicrosoftTypeAttributes() {
|
||||
SourceLocation StartLoc = Tok.getLocation();
|
||||
SourceLocation EndLoc = SkipExtendedMicrosoftTypeAttributes();
|
||||
@ -3845,6 +3861,10 @@ void Parser::ParseDeclarationSpecifiers(
|
||||
ParseMicrosoftTypeAttributes(DS.getAttributes());
|
||||
continue;
|
||||
|
||||
case tok::kw___funcref:
|
||||
ParseWebAssemblyFuncrefTypeAttribute(DS.getAttributes());
|
||||
continue;
|
||||
|
||||
// Borland single token adornments.
|
||||
case tok::kw___pascal:
|
||||
ParseBorlandTypeAttributes(DS.getAttributes());
|
||||
@ -5409,7 +5429,7 @@ bool Parser::isTypeSpecifierQualifier() {
|
||||
case tok::kw___read_only:
|
||||
case tok::kw___read_write:
|
||||
case tok::kw___write_only:
|
||||
|
||||
case tok::kw___funcref:
|
||||
case tok::kw_groupshared:
|
||||
return true;
|
||||
|
||||
@ -5674,6 +5694,7 @@ bool Parser::isDeclarationSpecifier(
|
||||
#define GENERIC_IMAGE_TYPE(ImgType, Id) case tok::kw_##ImgType##_t:
|
||||
#include "clang/Basic/OpenCLImageTypes.def"
|
||||
|
||||
case tok::kw___funcref:
|
||||
case tok::kw_groupshared:
|
||||
return true;
|
||||
|
||||
@ -5939,6 +5960,12 @@ void Parser::ParseTypeQualifierListOpt(
|
||||
continue;
|
||||
}
|
||||
goto DoneWithTypeQuals;
|
||||
|
||||
case tok::kw___funcref:
|
||||
ParseWebAssemblyFuncrefTypeAttribute(DS.getAttributes());
|
||||
continue;
|
||||
goto DoneWithTypeQuals;
|
||||
|
||||
case tok::kw___pascal:
|
||||
if (AttrReqs & AR_VendorAttributesParsed) {
|
||||
ParseBorlandTypeAttributes(DS.getAttributes());
|
||||
|
@ -1511,6 +1511,10 @@ Parser::isCXXDeclarationSpecifier(ImplicitTypenameContext AllowImplicitTypename,
|
||||
case tok::kw___kindof:
|
||||
return TPResult::True;
|
||||
|
||||
// WebAssemblyFuncref
|
||||
case tok::kw___funcref:
|
||||
return TPResult::True;
|
||||
|
||||
// Borland
|
||||
case tok::kw___pascal:
|
||||
return TPResult::True;
|
||||
|
@ -4733,6 +4733,8 @@ bool Sema::CheckWebAssemblyBuiltinFunctionCall(const TargetInfo &TI,
|
||||
switch (BuiltinID) {
|
||||
case WebAssembly::BI__builtin_wasm_ref_null_extern:
|
||||
return BuiltinWasmRefNullExtern(TheCall);
|
||||
case WebAssembly::BI__builtin_wasm_ref_null_func:
|
||||
return BuiltinWasmRefNullFunc(TheCall);
|
||||
}
|
||||
|
||||
return false;
|
||||
@ -6767,6 +6769,25 @@ bool Sema::BuiltinWasmRefNullExtern(CallExpr *TheCall) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Sema::BuiltinWasmRefNullFunc(CallExpr *TheCall) {
|
||||
if (TheCall->getNumArgs() != 0) {
|
||||
Diag(TheCall->getBeginLoc(), diag::err_typecheck_call_too_many_args)
|
||||
<< 0 /*function call*/ << 0 << TheCall->getNumArgs();
|
||||
return true;
|
||||
}
|
||||
|
||||
// This custom type checking code ensures that the nodes are as expected
|
||||
// in order to later on generate the necessary builtin.
|
||||
QualType Pointee = Context.getFunctionType(Context.VoidTy, {}, {});
|
||||
QualType Type = Context.getPointerType(Pointee);
|
||||
Pointee = Context.getAddrSpaceQualType(Pointee, LangAS::wasm_funcref);
|
||||
Type = Context.getAttributedType(attr::WebAssemblyFuncref, Type,
|
||||
Context.getPointerType(Pointee));
|
||||
TheCall->setType(Type);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// We have a call to a function like __sync_fetch_and_add, which is an
|
||||
/// overloaded function based on the pointer type of its first argument.
|
||||
/// The main BuildCallExpr routines have already promoted the types of
|
||||
|
@ -14845,7 +14845,11 @@ ParmVarDecl *Sema::CheckParameter(DeclContext *DC, SourceLocation StartLoc,
|
||||
// OpenCL allows function arguments declared to be an array of a type
|
||||
// to be qualified with an address space.
|
||||
!(getLangOpts().OpenCL &&
|
||||
(T->isArrayType() || T.getAddressSpace() == LangAS::opencl_private))) {
|
||||
(T->isArrayType() || T.getAddressSpace() == LangAS::opencl_private)) &&
|
||||
// WebAssembly allows reference types as parameters. Funcref in particular
|
||||
// lives in a different address space.
|
||||
!(T->isFunctionPointerType() &&
|
||||
T.getAddressSpace() == LangAS::wasm_funcref)) {
|
||||
Diag(NameLoc, diag::err_arg_with_address_space);
|
||||
New->setInvalidDecl();
|
||||
}
|
||||
|
@ -7346,6 +7346,37 @@ static bool handleMSPointerTypeQualifierAttr(TypeProcessingState &State,
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool HandleWebAssemblyFuncrefAttr(TypeProcessingState &State,
|
||||
QualType &QT, ParsedAttr &PAttr) {
|
||||
assert(PAttr.getKind() == ParsedAttr::AT_WebAssemblyFuncref);
|
||||
|
||||
Sema &S = State.getSema();
|
||||
Attr *A = createSimpleAttr<WebAssemblyFuncrefAttr>(S.Context, PAttr);
|
||||
|
||||
std::bitset<attr::LastAttr> Attrs;
|
||||
attr::Kind NewAttrKind = A->getKind();
|
||||
const auto *AT = dyn_cast<AttributedType>(QT);
|
||||
while (AT) {
|
||||
Attrs[AT->getAttrKind()] = true;
|
||||
AT = dyn_cast<AttributedType>(AT->getModifiedType());
|
||||
}
|
||||
|
||||
// You cannot specify duplicate type attributes, so if the attribute has
|
||||
// already been applied, flag it.
|
||||
if (Attrs[NewAttrKind]) {
|
||||
S.Diag(PAttr.getLoc(), diag::warn_duplicate_attribute_exact) << PAttr;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Add address space to type based on its attributes.
|
||||
LangAS ASIdx = LangAS::wasm_funcref;
|
||||
QualType Pointee = QT->getPointeeType();
|
||||
Pointee = S.Context.getAddrSpaceQualType(
|
||||
S.Context.removeAddrSpaceQualType(Pointee), ASIdx);
|
||||
QT = State.getAttributedType(A, QT, S.Context.getPointerType(Pointee));
|
||||
return false;
|
||||
}
|
||||
|
||||
/// Map a nullability attribute kind to a nullability kind.
|
||||
static NullabilityKind mapNullabilityAttrKind(ParsedAttr::Kind kind) {
|
||||
switch (kind) {
|
||||
@ -8503,6 +8534,12 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type,
|
||||
attr.setUsedAsTypeAttr();
|
||||
break;
|
||||
|
||||
case ParsedAttr::AT_WebAssemblyFuncref: {
|
||||
if (!HandleWebAssemblyFuncrefAttr(state, type, attr))
|
||||
attr.setUsedAsTypeAttr();
|
||||
break;
|
||||
}
|
||||
|
||||
MS_TYPE_ATTRS_CASELIST:
|
||||
if (!handleMSPointerTypeQualifierAttr(state, attr, type))
|
||||
attr.setUsedAsTypeAttr();
|
||||
|
99
clang/test/CodeGen/WebAssembly/wasm-funcref.c
Normal file
99
clang/test/CodeGen/WebAssembly/wasm-funcref.c
Normal file
@ -0,0 +1,99 @@
|
||||
// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py
|
||||
// RUN: %clang_cc1 -triple wasm32 -target-feature +reference-types -o - -emit-llvm %s | FileCheck %s
|
||||
|
||||
typedef void (*__funcref funcref_t)();
|
||||
typedef int (*__funcref fn_funcref_t)(int);
|
||||
typedef int (*fn_t)(int);
|
||||
|
||||
// Null funcref builtin call
|
||||
// CHECK-LABEL: @get_null(
|
||||
// CHECK-NEXT: entry:
|
||||
// CHECK-NEXT: [[TMP0:%.*]] = call ptr addrspace(20) @llvm.wasm.ref.null.func()
|
||||
// CHECK-NEXT: ret ptr addrspace(20) [[TMP0]]
|
||||
//
|
||||
funcref_t get_null() {
|
||||
return __builtin_wasm_ref_null_func();
|
||||
}
|
||||
|
||||
// Call to null funcref builtin but requires cast since
|
||||
// default return value for builtin is a funcref with function type () -> ().
|
||||
// CHECK-LABEL: @get_null_ii(
|
||||
// CHECK-NEXT: entry:
|
||||
// CHECK-NEXT: [[TMP0:%.*]] = call ptr addrspace(20) @llvm.wasm.ref.null.func()
|
||||
// CHECK-NEXT: ret ptr addrspace(20) [[TMP0]]
|
||||
//
|
||||
fn_funcref_t get_null_ii() {
|
||||
return (fn_funcref_t) __builtin_wasm_ref_null_func();
|
||||
}
|
||||
|
||||
// Identity function for funcref.
|
||||
// CHECK-LABEL: @identity(
|
||||
// CHECK-NEXT: entry:
|
||||
// CHECK-NEXT: [[FN_ADDR:%.*]] = alloca ptr addrspace(20), align 4
|
||||
// CHECK-NEXT: store ptr addrspace(20) [[FN:%.*]], ptr [[FN_ADDR]], align 4
|
||||
// CHECK-NEXT: [[TMP0:%.*]] = load ptr addrspace(20), ptr [[FN_ADDR]], align 4
|
||||
// CHECK-NEXT: ret ptr addrspace(20) [[TMP0]]
|
||||
//
|
||||
funcref_t identity(funcref_t fn) {
|
||||
return fn;
|
||||
}
|
||||
|
||||
void helper(funcref_t);
|
||||
|
||||
// Pass funcref ref as an argument to a helper function.
|
||||
// CHECK-LABEL: @handle(
|
||||
// CHECK-NEXT: entry:
|
||||
// CHECK-NEXT: [[FN_ADDR:%.*]] = alloca ptr addrspace(20), align 4
|
||||
// CHECK-NEXT: store ptr addrspace(20) [[FN:%.*]], ptr [[FN_ADDR]], align 4
|
||||
// CHECK-NEXT: [[TMP0:%.*]] = load ptr addrspace(20), ptr [[FN_ADDR]], align 4
|
||||
// CHECK-NEXT: call void @helper(ptr addrspace(20) noundef [[TMP0]])
|
||||
// CHECK-NEXT: ret i32 0
|
||||
//
|
||||
int handle(funcref_t fn) {
|
||||
helper(fn);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Return funcref from function pointer.
|
||||
// CHECK-LABEL: @get_ref(
|
||||
// CHECK-NEXT: entry:
|
||||
// CHECK-NEXT: [[FNPTR_ADDR:%.*]] = alloca ptr, align 4
|
||||
// CHECK-NEXT: store ptr [[FNPTR:%.*]], ptr [[FNPTR_ADDR]], align 4
|
||||
// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[FNPTR_ADDR]], align 4
|
||||
// CHECK-NEXT: [[TMP1:%.*]] = addrspacecast ptr [[TMP0]] to ptr addrspace(20)
|
||||
// CHECK-NEXT: ret ptr addrspace(20) [[TMP1]]
|
||||
//
|
||||
fn_funcref_t get_ref(fn_t fnptr) {
|
||||
return (fn_funcref_t) fnptr;
|
||||
}
|
||||
|
||||
// Call funcref
|
||||
// CHECK-LABEL: @call_fn(
|
||||
// CHECK-NEXT: entry:
|
||||
// CHECK-NEXT: [[REF_ADDR:%.*]] = alloca ptr addrspace(20), align 4
|
||||
// CHECK-NEXT: [[X_ADDR:%.*]] = alloca i32, align 4
|
||||
// CHECK-NEXT: store ptr addrspace(20) [[REF:%.*]], ptr [[REF_ADDR]], align 4
|
||||
// CHECK-NEXT: store i32 [[X:%.*]], ptr [[X_ADDR]], align 4
|
||||
// CHECK-NEXT: [[TMP0:%.*]] = load ptr addrspace(20), ptr [[REF_ADDR]], align 4
|
||||
// CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr [[X_ADDR]], align 4
|
||||
// CHECK-NEXT: [[CALL:%.*]] = call addrspace(20) i32 [[TMP0]](i32 noundef [[TMP1]])
|
||||
// CHECK-NEXT: ret i32 [[CALL]]
|
||||
//
|
||||
int call_fn(fn_funcref_t ref, int x) {
|
||||
return ref(x);
|
||||
}
|
||||
|
||||
typedef fn_funcref_t (*builtin_refnull_t)();
|
||||
|
||||
// Calling ref.null through a function pointer.
|
||||
// CHECK-LABEL: @get_null_fptr(
|
||||
// CHECK-NEXT: entry:
|
||||
// CHECK-NEXT: [[REFNULL_ADDR:%.*]] = alloca ptr, align 4
|
||||
// CHECK-NEXT: store ptr [[REFNULL:%.*]], ptr [[REFNULL_ADDR]], align 4
|
||||
// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[REFNULL_ADDR]], align 4
|
||||
// CHECK-NEXT: [[CALL:%.*]] = call ptr addrspace(20) [[TMP0]]()
|
||||
// CHECK-NEXT: ret ptr addrspace(20) [[CALL]]
|
||||
//
|
||||
fn_funcref_t get_null_fptr(builtin_refnull_t refnull) {
|
||||
return refnull();
|
||||
}
|
9
clang/test/Parser/wasm-funcref.c
Normal file
9
clang/test/Parser/wasm-funcref.c
Normal file
@ -0,0 +1,9 @@
|
||||
// RUN: %clang_cc1 -triple powerpc-linux-gnu -fsyntax-only -verify %s
|
||||
|
||||
// Test that we trigger an error at parse time if using keyword funcref
|
||||
// while not using a wasm triple.
|
||||
typedef void (*__funcref funcref_t)(); // expected-error {{invalid use of '__funcref' keyword outside the WebAssembly triple}}
|
||||
typedef int (*__funcref fn_funcref_t)(int);// expected-error {{invalid use of '__funcref' keyword outside the WebAssembly triple}}
|
||||
typedef int (*fn_t)(int);
|
||||
|
||||
static fn_funcref_t nullFuncref = 0;
|
@ -46,6 +46,8 @@ __externref_t *illegal_return_1(); // expected-error {{pointer to WebAssembly
|
||||
__externref_t ***illegal_return_2(); // expected-error {{pointer to WebAssembly reference type is not allowed}}
|
||||
|
||||
void varargs(int, ...);
|
||||
typedef void (*__funcref funcref_t)();
|
||||
typedef void (*__funcref __funcref funcref_fail_t)(); // expected-warning {{attribute '__funcref' is already applied}}
|
||||
|
||||
__externref_t func(__externref_t ref) {
|
||||
&ref; // expected-error {{cannot take address of WebAssembly reference}}
|
||||
@ -67,5 +69,7 @@ __externref_t func(__externref_t ref) {
|
||||
_Alignof(__externref_t ***); // expected-error {{pointer to WebAssembly reference type is not allowed}};
|
||||
varargs(1, ref); // expected-error {{cannot pass expression of type '__externref_t' to variadic function}}
|
||||
|
||||
funcref_t func = __builtin_wasm_ref_null_func(0); // expected-error {{too many arguments to function call, expected 0, have 1}}
|
||||
|
||||
return ref;
|
||||
}
|
||||
|
13
clang/test/SemaCXX/wasm-funcref.cpp
Normal file
13
clang/test/SemaCXX/wasm-funcref.cpp
Normal file
@ -0,0 +1,13 @@
|
||||
// RUN: %clang_cc1 -std=c++11 -fcxx-exceptions -fexceptions -fsyntax-only -verify -triple wasm32 -Wno-unused-value -target-feature +reference-types %s
|
||||
|
||||
// Testing that funcrefs work on template aliases
|
||||
// expected-no-diagnostics
|
||||
|
||||
using IntIntFuncref = int(*)(int) __funcref;
|
||||
using DoubleQual = IntIntFuncref __funcref;
|
||||
|
||||
int get(int);
|
||||
|
||||
IntIntFuncref getFuncref() {
|
||||
return get;
|
||||
}
|
@ -43,7 +43,7 @@ void neg() {
|
||||
|
||||
template <long int I>
|
||||
void tooBig() {
|
||||
__attribute__((address_space(I))) int *bounds; // expected-error {{address space is larger than the maximum supported (8388587)}}
|
||||
__attribute__((address_space(I))) int *bounds; // expected-error {{address space is larger than the maximum supported (8388586)}}
|
||||
}
|
||||
|
||||
template <long int I>
|
||||
@ -101,7 +101,7 @@ int main() {
|
||||
car<1, 2, 3>(); // expected-note {{in instantiation of function template specialization 'car<1, 2, 3>' requested here}}
|
||||
HasASTemplateFields<1> HASTF;
|
||||
neg<-1>(); // expected-note {{in instantiation of function template specialization 'neg<-1>' requested here}}
|
||||
correct<0x7FFFEA>();
|
||||
correct<0x7FFFE9>();
|
||||
tooBig<8388650>(); // expected-note {{in instantiation of function template specialization 'tooBig<8388650L>' requested here}}
|
||||
|
||||
__attribute__((address_space(1))) char *x;
|
||||
|
Loading…
x
Reference in New Issue
Block a user