Skip to content

Commit

Permalink
[WebAssembly] Initial support for reference type funcref in clang
Browse files Browse the repository at this point in the history
This is the funcref counterpart to 104bad5a. 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
  • Loading branch information
pmatos committed Nov 23, 2022
1 parent 84bcf5b commit 51984e4
Show file tree
Hide file tree
Showing 29 changed files with 300 additions and 7 deletions.
2 changes: 2 additions & 0 deletions clang/include/clang/AST/Type.h
Original file line number Diff line number Diff line change
Expand Up @@ -4922,6 +4922,8 @@ class AttributedType : public Type, public llvm::FoldingSetNode {

bool isMSTypeSpec() const;

bool isWebAssemblyFuncrefSpec() const;

bool isCallingConv() const;

llvm::Optional<NullabilityKind> getImmediateNullability() const;
Expand Down
3 changes: 3 additions & 0 deletions clang/include/clang/Basic/AddressSpaces.h
Original file line number Diff line number Diff line change
Expand Up @@ -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))).
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 @@ -4096,3 +4096,9 @@ 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<[TypedefName], ErrorDiag>;
}
9 changes: 9 additions & 0 deletions clang/include/clang/Basic/AttrDocs.td
Original file line number Diff line number Diff line change
Expand Up @@ -6770,3 +6770,12 @@ The symbol used for ``thunk-extern`` is target specific:
As such, this function attribute is currently only supported on X86 targets.
}];
}

def WebAssemblyFuncrefDocs : Documentation {
let Category = DocCatFunction;
let Content = [{
Clang supports the ``__funcref`` attribute for the WebAssembly target.
This attribute may be attached to a function pointer declaration, where it modifies
its underlying representation to be a WebAssembly ``funcref``.
}];
}
7 changes: 7 additions & 0 deletions clang/include/clang/Basic/BuiltinsWebAssembly.def
Original file line number Diff line number Diff line change
Expand Up @@ -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
2 changes: 2 additions & 0 deletions clang/include/clang/Basic/DiagnosticSemaKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -7365,6 +7365,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 - "
Expand Down
3 changes: 3 additions & 0 deletions clang/include/clang/Basic/TokenKinds.def
Original file line number Diff line number Diff line change
Expand Up @@ -678,6 +678,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)
Expand Down
1 change: 1 addition & 0 deletions clang/include/clang/Parse/Parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -2922,6 +2922,7 @@ class Parser : public CodeCompletionHandler {
SourceLocation AttrNameLoc,
ParsedAttributes &Attrs);
void ParseMicrosoftTypeAttributes(ParsedAttributes &attrs);
void ParseWebAssemblyFuncrefTypeAttribute(ParsedAttributes &Attrs);
void DiagnoseAndSkipExtendedMicrosoftTypeAttributes();
SourceLocation SkipExtendedMicrosoftTypeAttributes();
void ParseMicrosoftInheritanceClassAttributes(ParsedAttributes &attrs);
Expand Down
1 change: 1 addition & 0 deletions clang/include/clang/Sema/Sema.h
Original file line number Diff line number Diff line change
Expand Up @@ -13454,6 +13454,7 @@ class Sema final {

// WebAssembly builtin handling.
bool BuiltinWasmRefNullExtern(CallExpr *TheCall);
bool BuiltinWasmRefNullFunc(CallExpr *TheCall);

public:
enum FormatStringType {
Expand Down
2 changes: 2 additions & 0 deletions clang/lib/AST/ASTContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -955,6 +955,8 @@ static const LangASMap *getAddressSpaceMap(const TargetInfo &T,
11, // ptr32_uptr
12, // ptr64
13, // hlsl_groupshared
// Wasm address space values for this map are dummy
20, // wasm_funcref
};
return &FakeAddrSpaceMap;
} else {
Expand Down
4 changes: 4 additions & 0 deletions clang/lib/AST/Type.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3619,6 +3619,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()) {
Expand Down
12 changes: 10 additions & 2 deletions clang/lib/AST/TypePrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1649,6 +1649,11 @@ void TypePrinter::printAttributedBefore(const AttributedType *T,
spaceBeforePlaceHolder(OS);
}

if (T->isWebAssemblyFuncrefSpec()) {
assert(T->getAttrKind() == attr::WebAssemblyFuncref);
OS << "__funcref";
}

// Print nullability type specifiers.
if (T->getImmediateNullability()) {
if (T->getAttrKind() == attr::TypeNonNull)
Expand Down Expand Up @@ -1682,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.
Expand Down Expand Up @@ -1755,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:
Expand Down Expand Up @@ -2230,6 +2236,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:
Expand Down
2 changes: 2 additions & 0 deletions clang/lib/Basic/Targets/DirectX.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ static const unsigned DirectXAddrSpaceMap[] = {
0, // ptr32_uptr
0, // ptr64
3, // hlsl_groupshared
// Wasm address space values for this map are dummy
20, // wasm_funcref
};

class LLVM_LIBRARY_VISIBILITY DirectXTargetInfo : public TargetInfo {
Expand Down
2 changes: 2 additions & 0 deletions clang/lib/Basic/Targets/NVPTX.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ static const unsigned NVPTXAddrSpaceMap[] = {
0, // ptr32_uptr
0, // ptr64
0, // hlsl_groupshared
// Wasm address space values for this map are dummy
20, // wasm_funcref
};

/// The DWARF address class. Taken from
Expand Down
4 changes: 4 additions & 0 deletions clang/lib/Basic/Targets/SPIR.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ static const unsigned SPIRDefIsPrivMap[] = {
0, // ptr32_uptr
0, // ptr64
0, // hlsl_groupshared
// Wasm address space values for this map are dummy
20, // wasm_funcref
};

// Used by both the SPIR and SPIR-V targets.
Expand Down Expand Up @@ -74,6 +76,8 @@ static const unsigned SPIRDefIsGenMap[] = {
0, // ptr32_uptr
0, // ptr64
0, // hlsl_groupshared
// Wasm address space values for this map are dummy
20, // wasm_funcref
};

// Base class for SPIR and SPIR-V target info.
Expand Down
2 changes: 2 additions & 0 deletions clang/lib/Basic/Targets/TCE.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ static const unsigned TCEOpenCLAddrSpaceMap[] = {
0, // ptr32_uptr
0, // ptr64
0, // hlsl_groupshared
// Wasm address space values for this map are dummy
20, // wasm_funcref
};

class LLVM_LIBRARY_VISIBILITY TCETargetInfo : public TargetInfo {
Expand Down
25 changes: 25 additions & 0 deletions clang/lib/Basic/Targets/WebAssembly.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
10, // wasm_externref,
20, // wasm_funcref
};

class LLVM_LIBRARY_VISIBILITY WebAssemblyTargetInfo : public TargetInfo {
static const Builtin::Info BuiltinInfo[];

Expand All @@ -46,6 +70,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;
Expand Down
2 changes: 2 additions & 0 deletions clang/lib/Basic/Targets/X86.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ static const unsigned X86AddrSpaceMap[] = {
271, // ptr32_uptr
272, // ptr64
0, // hlsl_groupshared
// Wasm address space values for this map are dummy
20, // wasm_funcref
};

// X86 target abstract base class; x86-32 and x86-64 are very close, so
Expand Down
4 changes: 4 additions & 0 deletions clang/lib/CodeGen/CGBuiltin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18798,6 +18798,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));
Expand Down
4 changes: 4 additions & 0 deletions clang/lib/CodeGen/TargetInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -904,6 +904,10 @@ class WebAssemblyTargetCodeGenInfo final : public TargetCodeGenInfo {
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.
Expand Down
3 changes: 3 additions & 0 deletions clang/lib/CodeGen/TargetInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -365,6 +365,9 @@ class TargetCodeGenInfo {
/// 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,
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/Format/FormatToken.h
Original file line number Diff line number Diff line change
Expand Up @@ -596,7 +596,7 @@ struct FormatToken {
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.
Expand Down
24 changes: 23 additions & 1 deletion clang/lib/Parse/ParseDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -840,6 +840,15 @@ void Parser::ParseMicrosoftTypeAttributes(ParsedAttributes &attrs) {
}
}

void Parser::ParseWebAssemblyFuncrefTypeAttribute(ParsedAttributes &attrs) {
if (Tok.is(tok::kw___funcref)) {
IdentifierInfo *AttrName = Tok.getIdentifierInfo();
SourceLocation AttrNameLoc = ConsumeToken();
attrs.addNew(AttrName, AttrNameLoc, nullptr, AttrNameLoc, nullptr, 0,
ParsedAttr::AS_Keyword);
}
}

void Parser::DiagnoseAndSkipExtendedMicrosoftTypeAttributes() {
SourceLocation StartLoc = Tok.getLocation();
SourceLocation EndLoc = SkipExtendedMicrosoftTypeAttributes();
Expand Down Expand Up @@ -3811,6 +3820,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());
Expand Down Expand Up @@ -5368,7 +5381,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;

Expand Down Expand Up @@ -5612,6 +5625,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;

Expand Down Expand Up @@ -5873,6 +5887,14 @@ void Parser::ParseTypeQualifierListOpt(
continue;
}
goto DoneWithTypeQuals;

case tok::kw___funcref:
if (AttrReqs & AR_DeclspecAttributesParsed) {
ParseWebAssemblyFuncrefTypeAttribute(DS.getAttributes());
continue;
}
goto DoneWithTypeQuals;

case tok::kw___pascal:
if (AttrReqs & AR_VendorAttributesParsed) {
ParseBorlandTypeAttributes(DS.getAttributes());
Expand Down
4 changes: 4 additions & 0 deletions clang/lib/Parse/ParseTentative.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1472,6 +1472,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;
Expand Down
28 changes: 28 additions & 0 deletions clang/lib/Sema/SemaChecking.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4592,6 +4592,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;
Expand Down Expand Up @@ -6628,6 +6630,32 @@ bool Sema::BuiltinWasmRefNullExtern(CallExpr *TheCall) {
return false;
}

bool Sema::BuiltinWasmRefNullFunc(CallExpr *TheCall) {
if (TheCall->getNumArgs() != 0)
return true;

// The call we get looks like
// CallExpr
// `- ImplicitCastExpr
// `- DeclRefExpr
//
// Therefore we need to change the types of the DeclRefExpr (stored in FDecl)
// and regenerate a straight up CallExpr on the modified FDecl.
// returning
// CallExpr
// `- FunctionDecl

// Prepare FDecl type
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
Expand Down
Loading

0 comments on commit 51984e4

Please sign in to comment.