[clang][WebAssembly] Implement support for table types and builtins

This commit implements support for WebAssembly table types and
respective builtins. Table tables are WebAssembly objects to store
reference types. They have a large amount of semantic restrictions
including, but not limited to, only being allowed to be declared
at the top-level as static arrays of zero-length. Not being arguments
or result of functions, not being stored ot memory, etc.

This commit introduces the __attribute__((wasm_table)) to attach to
arrays of WebAssembly reference types. And the following builtins to
manage tables:

* ref   __builtin_wasm_table_get(table, idx)
* void  __builtin_wasm_table_set(table, idx, ref)
* uint  __builtin_wasm_table_size(table)
* uint  __builtin_wasm_table_grow(table, ref, uint)
* void  __builtin_wasm_table_fill(table, idx, ref, uint)
* void  __builtin_wasm_table_copy(table, table, uint, uint, uint)

This commit also enables reference-types feature at bleeding-edge.

This is joint work with Alex Bradbury (@asb).

Reviewed By: aaron.ballman

Differential Revision: https://reviews.llvm.org/D139010
This commit is contained in:
Paulo Matos 2023-06-10 15:51:05 +02:00
parent 5b657f50b8
commit 55aeb23fe0
31 changed files with 1094 additions and 244 deletions

View File

@ -2313,6 +2313,138 @@ targets.
atomic_add(a, 1);
}
WebAssembly Features
====================
Clang supports the WebAssembly features documented below. For further
information related to the semantics of the builtins, please refer to the `WebAssembly Specification <https://webassembly.github.io/spec/core/>`_.
In this section, when we refer to reference types, we are referring to
WebAssembly reference types, not C++ reference types unless stated
otherwise.
``__builtin_wasm_table_set``
----------------------------
This builtin function stores a value in a WebAssembly table.
It takes three arguments.
The first argument is the table to store a value into, the second
argument is the index to which to store the value into, and the
third argument is a value of reference type to store in the table.
It returns nothing.
.. code-block:: c++
static __externref_t table[0];
extern __externref_t JSObj;
void store(int index) {
__builtin_wasm_table_set(table, index, JSObj);
}
``__builtin_wasm_table_get``
----------------------------
This builtin function is the counterpart to ``__builtin_wasm_table_set``
and loads a value from a WebAssembly table of reference typed values.
It takes 2 arguments.
The first argument is a table of reference typed values and the
second argument is an index from which to load the value. It returns
the loaded reference typed value.
.. code-block:: c++
static __externref_t table[0];
__externref_t load(int index) {
__externref_t Obj = __builtin_wasm_table_get(table, index);
return Obj;
}
``__builtin_wasm_table_size``
-----------------------------
This builtin function returns the size of the WebAssembly table.
Takes the table as an argument and returns an unsigned integer (``size_t``)
with the current table size.
.. code-block:: c++
typedef void (*__funcref funcref_t)();
static __funcref table[0];
size_t getSize() {
return __builtin_wasm_table_size(table);
}
``__builtin_wasm_table_grow``
-----------------------------
This builtin function grows the WebAssembly table by a certain amount.
Currently, as all WebAssembly tables created in C/C++ are zero-sized,
this always needs to be called to grow the table.
It takes three arguments. The first argument is the WebAssembly table
to grow. The second argument is the reference typed value to store in
the new table entries (the initialization value), and the third argument
is the amound to grow the table by. It returns the previous table size
or -1. It will return -1 if not enough space could be allocated.
.. code-block:: c++
typedef void (*__funcref funcref_t)();
static __funcref table[0];
// grow returns the new table size or -1 on error.
int grow(__funcref fn, int delta) {
int prevSize = __builtin_wasm_table_grow(table, fn, delta);
if (prevSize == -1)
return -1;
return prevSize + delta;
}
``__builtin_wasm_table_fill``
-----------------------------
This builtin function sets all the entries of a WebAssembly table to a given
reference typed value. It takes four arguments. The first argument is
the WebAssembly table, the second argument is the index that starts the
range, the third argument is the value to set in the new entries, and
the fourth and the last argument is the size of the range. It returns
nothing.
.. code-block:: c++
static __externref_t table[0];
// resets a table by setting all of its entries to a given value.
void reset(__externref_t Obj) {
int Size = __builtin_wasm_table_size(table);
__builtin_wasm_table_fill(table, 0, Obj, Size);
}
``__builtin_wasm_table_copy``
-----------------------------
This builtin function copies elements from a source WebAssembly table
to a possibly overlapping destination region. It takes five arguments.
The first argument is the destination WebAssembly table, and the second
argument is the source WebAssembly table. The third argument is the
destination index from where the copy starts, the fourth argument is the
source index from there the copy starts, and the fifth and last argument
is the number of elements to copy. It returns nothing.
.. code-block:: c++
static __externref_t tableSrc[0];
static __externref_t tableDst[0];
// Copy nelem elements from [src, src + nelem - 1] in tableSrc to
// [dst, dst + nelem - 1] in tableDst
void copy(int dst, int src, int nelem) {
__builtin_wasm_table_copy(tableDst, tableSrc, dst, src, nelem);
}
Builtin Functions
=================

View File

@ -908,6 +908,15 @@ public:
/// Returns true if it is not a class or if the class might not be dynamic.
bool mayBeNotDynamicClass() const;
/// Returns true if it is a WebAssembly Reference Type.
bool isWebAssemblyReferenceType() const;
/// Returns true if it is a WebAssembly Externref Type.
bool isWebAssemblyExternrefType() const;
/// Returns true if it is a WebAssembly Funcref Type.
bool isWebAssemblyFuncrefType() const;
// Don't promise in the API that anything besides 'const' can be
// easily added.
@ -2035,10 +2044,14 @@ public:
/// Returns true for RVV scalable vector types.
bool isRVVSizelessBuiltinType() const;
/// Check if this is a WebAssembly Reference Type.
bool isWebAssemblyReferenceType() const;
/// Check if this is a WebAssembly Externref Type.
bool isWebAssemblyExternrefType() const;
/// Returns true if this is a WebAssembly table type: either an array of
/// reference types, or a pointer to a reference type (which can only be
/// created by array to pointer decay).
bool isWebAssemblyTableType() const;
/// Determines if this is a sizeless type supported by the
/// 'arm_sve_vector_bits' type attribute, which can be applied to a single
/// SVE vector or predicate, excluding tuple types such as svint32x4_t.

View File

@ -201,5 +201,13 @@ TARGET_BUILTIN(__builtin_wasm_ref_null_extern, "i", "nct", "reference-types")
// return type.
TARGET_BUILTIN(__builtin_wasm_ref_null_func, "i", "nct", "reference-types")
// Table builtins
TARGET_BUILTIN(__builtin_wasm_table_set, "viii", "t", "reference-types")
TARGET_BUILTIN(__builtin_wasm_table_get, "iii", "t", "reference-types")
TARGET_BUILTIN(__builtin_wasm_table_size, "zi", "nt", "reference-types")
TARGET_BUILTIN(__builtin_wasm_table_grow, "iiii", "nt", "reference-types")
TARGET_BUILTIN(__builtin_wasm_table_fill, "viiii", "t", "reference-types")
TARGET_BUILTIN(__builtin_wasm_table_copy, "viiiii", "t", "reference-types")
#undef BUILTIN
#undef TARGET_BUILTIN

View File

@ -11864,4 +11864,34 @@ 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">;
def err_wasm_table_pr : Error<
"cannot form a %select{pointer|reference}0 to a WebAssembly table">;
def err_typecheck_wasm_table_must_have_zero_length : Error<
"only zero-length WebAssembly tables are currently supported">;
def err_wasm_table_in_function : Error<
"WebAssembly table cannot be declared within a function">;
def err_wasm_table_as_function_parameter : Error<
"cannot use WebAssembly table as a function parameter">;
def err_wasm_table_invalid_uett_operand : Error<
"invalid application of '%0' to WebAssembly table">;
def err_wasm_cast_table : Error<
"cannot cast %select{to|from}0 a WebAssembly table">;
def err_wasm_table_conditional_expression : Error<
"cannot use a WebAssembly table within a branch of a conditional expression">;
def err_wasm_table_art : Error<
"cannot %select{assign|return|throw|subscript}0 a WebAssembly table">;
def err_wasm_reftype_tc : Error<
"cannot %select{throw|catch}0 a WebAssembly reference type">;
def err_wasm_reftype_exception_spec : Error<
"WebAssembly reference type not allowed in exception specification">;
def err_wasm_table_must_be_static : Error<
"WebAssembly table must be static">;
def err_wasm_reftype_multidimensional_array : Error<
"multi-dimensional arrays of WebAssembly references are not allowed">;
def err_wasm_builtin_arg_must_be_table_type : Error <
"%ordinal0 argument must be a WebAssembly table">;
def err_wasm_builtin_arg_must_match_table_element_type : Error <
"%ordinal0 argument must match the element type of the WebAssembly table in the %ordinal1 argument">;
def err_wasm_builtin_arg_must_be_integer_type : Error <
"%ordinal0 argument must be an integer">;
} // end of sema component.

View File

@ -13653,6 +13653,12 @@ private:
// WebAssembly builtin handling.
bool BuiltinWasmRefNullExtern(CallExpr *TheCall);
bool BuiltinWasmRefNullFunc(CallExpr *TheCall);
bool BuiltinWasmTableGet(CallExpr *TheCall);
bool BuiltinWasmTableSet(CallExpr *TheCall);
bool BuiltinWasmTableSize(CallExpr *TheCall);
bool BuiltinWasmTableGrow(CallExpr *TheCall);
bool BuiltinWasmTableFill(CallExpr *TheCall);
bool BuiltinWasmTableCopy(CallExpr *TheCall);
public:
enum FormatStringType {

View File

@ -2367,16 +2367,22 @@ bool Type::isSizelessBuiltinType() const {
return false;
}
bool Type::isWebAssemblyReferenceType() const {
return isWebAssemblyExternrefType();
}
bool Type::isWebAssemblyExternrefType() const {
if (const auto *BT = getAs<BuiltinType>())
return BT->getKind() == BuiltinType::WasmExternRef;
return false;
}
bool Type::isWebAssemblyTableType() const {
if (const auto *ATy = dyn_cast<ArrayType>(this))
return ATy->getElementType().isWebAssemblyReferenceType();
if (const auto *PTy = dyn_cast<PointerType>(this))
return PTy->getPointeeType().isWebAssemblyReferenceType();
return false;
}
bool Type::isSizelessType() const { return isSizelessBuiltinType(); }
bool Type::isSVESizelessBuiltinType() const {
@ -2708,6 +2714,19 @@ bool QualType::hasNonTrivialToPrimitiveCopyCUnion(const RecordDecl *RD) {
return RD->hasNonTrivialToPrimitiveCopyCUnion();
}
bool QualType::isWebAssemblyReferenceType() const {
return isWebAssemblyExternrefType() || isWebAssemblyFuncrefType();
}
bool QualType::isWebAssemblyExternrefType() const {
return getTypePtr()->isWebAssemblyExternrefType();
}
bool QualType::isWebAssemblyFuncrefType() const {
return getTypePtr()->isFunctionPointerType() &&
getAddressSpace() == LangAS::wasm_funcref;
}
QualType::PrimitiveDefaultInitializeKind
QualType::isNonTrivialToPrimitiveDefaultInitialize() const {
if (const auto *RT =

View File

@ -151,6 +151,7 @@ bool WebAssemblyTargetInfo::initFeatureMap(
Features["atomics"] = true;
Features["mutable-globals"] = true;
Features["tail-call"] = true;
Features["reference-types"] = true;
setSIMDLevel(Features, SIMD128, true);
} else if (CPU == "generic") {
Features["sign-ext"] = true;

View File

@ -19756,6 +19756,95 @@ Value *CodeGenFunction::EmitWebAssemblyBuiltinExpr(unsigned BuiltinID,
CGM.getIntrinsic(Intrinsic::wasm_relaxed_dot_bf16x8_add_f32);
return Builder.CreateCall(Callee, {LHS, RHS, Acc});
}
case WebAssembly::BI__builtin_wasm_table_get: {
assert(E->getArg(0)->getType()->isArrayType());
Value *Table =
EmitCastToVoidPtr(EmitArrayToPointerDecay(E->getArg(0)).getPointer());
Value *Index = EmitScalarExpr(E->getArg(1));
Function *Callee;
if (E->getType().isWebAssemblyExternrefType())
Callee = CGM.getIntrinsic(Intrinsic::wasm_table_get_externref);
else if (E->getType().isWebAssemblyFuncrefType())
Callee = CGM.getIntrinsic(Intrinsic::wasm_table_get_funcref);
else
llvm_unreachable(
"Unexpected reference type for __builtin_wasm_table_get");
return Builder.CreateCall(Callee, {Table, Index});
}
case WebAssembly::BI__builtin_wasm_table_set: {
assert(E->getArg(0)->getType()->isArrayType());
Value *Table =
EmitCastToVoidPtr(EmitArrayToPointerDecay(E->getArg(0)).getPointer());
Value *Index = EmitScalarExpr(E->getArg(1));
Value *Val = EmitScalarExpr(E->getArg(2));
Function *Callee;
if (E->getArg(2)->getType().isWebAssemblyExternrefType())
Callee = CGM.getIntrinsic(Intrinsic::wasm_table_set_externref);
else if (E->getArg(2)->getType().isWebAssemblyFuncrefType())
Callee = CGM.getIntrinsic(Intrinsic::wasm_table_set_funcref);
else
llvm_unreachable(
"Unexpected reference type for __builtin_wasm_table_set");
return Builder.CreateCall(Callee, {Table, Index, Val});
}
case WebAssembly::BI__builtin_wasm_table_size: {
assert(E->getArg(0)->getType()->isArrayType());
Value *Value =
EmitCastToVoidPtr(EmitArrayToPointerDecay(E->getArg(0)).getPointer());
Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_table_size);
return Builder.CreateCall(Callee, Value);
}
case WebAssembly::BI__builtin_wasm_table_grow: {
assert(E->getArg(0)->getType()->isArrayType());
Value *Table =
EmitCastToVoidPtr(EmitArrayToPointerDecay(E->getArg(0)).getPointer());
Value *Val = EmitScalarExpr(E->getArg(1));
Value *NElems = EmitScalarExpr(E->getArg(2));
Function *Callee;
if (E->getArg(1)->getType().isWebAssemblyExternrefType())
Callee = CGM.getIntrinsic(Intrinsic::wasm_table_grow_externref);
else if (E->getArg(2)->getType().isWebAssemblyFuncrefType())
Callee = CGM.getIntrinsic(Intrinsic::wasm_table_fill_funcref);
else
llvm_unreachable(
"Unexpected reference type for __builtin_wasm_table_grow");
return Builder.CreateCall(Callee, {Table, Val, NElems});
}
case WebAssembly::BI__builtin_wasm_table_fill: {
assert(E->getArg(0)->getType()->isArrayType());
Value *Table =
EmitCastToVoidPtr(EmitArrayToPointerDecay(E->getArg(0)).getPointer());
Value *Index = EmitScalarExpr(E->getArg(1));
Value *Val = EmitScalarExpr(E->getArg(2));
Value *NElems = EmitScalarExpr(E->getArg(3));
Function *Callee;
if (E->getArg(2)->getType().isWebAssemblyExternrefType())
Callee = CGM.getIntrinsic(Intrinsic::wasm_table_fill_externref);
else if (E->getArg(2)->getType().isWebAssemblyFuncrefType())
Callee = CGM.getIntrinsic(Intrinsic::wasm_table_fill_funcref);
else
llvm_unreachable(
"Unexpected reference type for __builtin_wasm_table_fill");
return Builder.CreateCall(Callee, {Table, Index, Val, NElems});
}
case WebAssembly::BI__builtin_wasm_table_copy: {
assert(E->getArg(0)->getType()->isArrayType());
Value *TableX =
EmitCastToVoidPtr(EmitArrayToPointerDecay(E->getArg(0)).getPointer());
Value *TableY =
EmitCastToVoidPtr(EmitArrayToPointerDecay(E->getArg(1)).getPointer());
Value *DstIdx = EmitScalarExpr(E->getArg(2));
Value *SrcIdx = EmitScalarExpr(E->getArg(3));
Value *NElems = EmitScalarExpr(E->getArg(4));
Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_table_copy);
return Builder.CreateCall(Callee, {TableX, TableY, SrcIdx, DstIdx, NElems});
}
default:
return nullptr;
}

View File

@ -33,9 +33,11 @@
#include "llvm/ADT/StringExtras.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/Intrinsics.h"
#include "llvm/IR/IntrinsicsWebAssembly.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/MDBuilder.h"
#include "llvm/IR/MatrixBuilder.h"
#include "llvm/Passes/OptimizationLevel.h"
#include "llvm/Support/ConvertUTF.h"
#include "llvm/Support/MathExtras.h"
#include "llvm/Support/Path.h"

View File

@ -2746,6 +2746,15 @@ void CastOperation::CheckCXXCStyleCast(bool FunctionalStyle,
}
}
// WebAssembly tables cannot be cast.
QualType SrcType = SrcExpr.get()->getType();
if (SrcType->isWebAssemblyTableType()) {
Self.Diag(OpRange.getBegin(), diag::err_wasm_cast_table)
<< 1 << SrcExpr.get()->getSourceRange();
SrcExpr = ExprError();
return;
}
// C++ [expr.cast]p5: The conversions performed by
// - a const_cast,
// - a static_cast,
@ -2921,6 +2930,13 @@ void CastOperation::CheckCStyleCast() {
return;
QualType SrcType = SrcExpr.get()->getType();
if (SrcType->isWebAssemblyTableType()) {
Self.Diag(OpRange.getBegin(), diag::err_wasm_cast_table)
<< 1 << SrcExpr.get()->getSourceRange();
SrcExpr = ExprError();
return;
}
assert(!SrcType->isPlaceholderType());
checkAddressSpaceCast(SrcType, DestType);

View File

@ -4830,6 +4830,18 @@ bool Sema::CheckWebAssemblyBuiltinFunctionCall(const TargetInfo &TI,
return BuiltinWasmRefNullExtern(TheCall);
case WebAssembly::BI__builtin_wasm_ref_null_func:
return BuiltinWasmRefNullFunc(TheCall);
case WebAssembly::BI__builtin_wasm_table_get:
return BuiltinWasmTableGet(TheCall);
case WebAssembly::BI__builtin_wasm_table_set:
return BuiltinWasmTableSet(TheCall);
case WebAssembly::BI__builtin_wasm_table_size:
return BuiltinWasmTableSize(TheCall);
case WebAssembly::BI__builtin_wasm_table_grow:
return BuiltinWasmTableGrow(TheCall);
case WebAssembly::BI__builtin_wasm_table_fill:
return BuiltinWasmTableFill(TheCall);
case WebAssembly::BI__builtin_wasm_table_copy:
return BuiltinWasmTableCopy(TheCall);
}
return false;
@ -12330,6 +12342,10 @@ Sema::CheckReturnValExpr(Expr *RetValExp, QualType lhsType,
}
}
if (RetValExp && RetValExp->getType()->isWebAssemblyTableType()) {
Diag(ReturnLoc, diag::err_wasm_table_art) << 1;
}
// PPC MMA non-pointer types are not allowed as return type. Checking the type
// here prevent the user from using a PPC MMA type as trailing return type.
if (Context.getTargetInfo().getTriple().isPPC64())
@ -16063,6 +16079,13 @@ bool Sema::CheckParmsForFunctionDef(ArrayRef<ParmVarDecl *> Parameters,
RD, /*DeclIsField*/ false);
}
}
if (!Param->isInvalidDecl() &&
Param->getOriginalType()->isWebAssemblyTableType()) {
Param->setInvalidDecl();
HasInvalidParm = true;
Diag(Param->getLocation(), diag::err_wasm_table_as_function_parameter);
}
}
return HasInvalidParm;
@ -18345,6 +18368,168 @@ ExprResult Sema::SemaBuiltinMatrixColumnMajorStore(CallExpr *TheCall,
return CallResult;
}
/// Checks the argument at the given index is a WebAssembly table and if it
/// is, sets ElTy to the element type.
static bool CheckWasmBuiltinArgIsTable(Sema &S, CallExpr *E, unsigned ArgIndex,
QualType &ElTy) {
Expr *ArgExpr = E->getArg(ArgIndex);
const auto *ATy = dyn_cast<ArrayType>(ArgExpr->getType());
if (!ATy || !ATy->getElementType().isWebAssemblyReferenceType()) {
return S.Diag(ArgExpr->getBeginLoc(),
diag::err_wasm_builtin_arg_must_be_table_type)
<< ArgIndex + 1 << ArgExpr->getSourceRange();
}
ElTy = ATy->getElementType();
return false;
}
/// Checks the argument at the given index is an integer.
static bool CheckWasmBuiltinArgIsInteger(Sema &S, CallExpr *E,
unsigned ArgIndex) {
Expr *ArgExpr = E->getArg(ArgIndex);
if (!ArgExpr->getType()->isIntegerType()) {
return S.Diag(ArgExpr->getBeginLoc(),
diag::err_wasm_builtin_arg_must_be_integer_type)
<< ArgIndex + 1 << ArgExpr->getSourceRange();
}
return false;
}
/// Check that the first argument is a WebAssembly table, and the second
/// is an index to use as index into the table.
bool Sema::BuiltinWasmTableGet(CallExpr *TheCall) {
if (checkArgCount(*this, TheCall, 2))
return true;
QualType ElTy;
if (CheckWasmBuiltinArgIsTable(*this, TheCall, 0, ElTy))
return true;
if (CheckWasmBuiltinArgIsInteger(*this, TheCall, 1))
return true;
// If all is well, we set the type of TheCall to be the type of the
// element of the table.
// i.e. a table.get on an externref table has type externref,
// or whatever the type of the table element is.
TheCall->setType(ElTy);
return false;
}
/// Check that the first argumnet is a WebAssembly table, the second is
/// an index to use as index into the table and the third is the reference
/// type to set into the table.
bool Sema::BuiltinWasmTableSet(CallExpr *TheCall) {
if (checkArgCount(*this, TheCall, 3))
return true;
QualType ElTy;
if (CheckWasmBuiltinArgIsTable(*this, TheCall, 0, ElTy))
return true;
if (CheckWasmBuiltinArgIsInteger(*this, TheCall, 1))
return true;
if (!Context.hasSameType(ElTy, TheCall->getArg(2)->getType()))
return true;
return false;
}
/// Check that the argument is a WebAssembly table.
bool Sema::BuiltinWasmTableSize(CallExpr *TheCall) {
if (checkArgCount(*this, TheCall, 1))
return true;
QualType ElTy;
if (CheckWasmBuiltinArgIsTable(*this, TheCall, 0, ElTy))
return true;
return false;
}
/// Check that the first argument is a WebAssembly table, the second is the
/// value to use for new elements (of a type matching the table type), the
/// third value is an integer.
bool Sema::BuiltinWasmTableGrow(CallExpr *TheCall) {
if (checkArgCount(*this, TheCall, 3))
return true;
QualType ElTy;
if (CheckWasmBuiltinArgIsTable(*this, TheCall, 0, ElTy))
return true;
Expr *NewElemArg = TheCall->getArg(1);
if (!Context.hasSameType(ElTy, NewElemArg->getType())) {
return Diag(NewElemArg->getBeginLoc(),
diag::err_wasm_builtin_arg_must_match_table_element_type)
<< 2 << 1 << NewElemArg->getSourceRange();
}
if (CheckWasmBuiltinArgIsInteger(*this, TheCall, 2))
return true;
return false;
}
/// Check that the first argument is a WebAssembly table, the second is an
/// integer, the third is the value to use to fill the table (of a type
/// matching the table type), and the fourth is an integer.
bool Sema::BuiltinWasmTableFill(CallExpr *TheCall) {
if (checkArgCount(*this, TheCall, 4))
return true;
QualType ElTy;
if (CheckWasmBuiltinArgIsTable(*this, TheCall, 0, ElTy))
return true;
if (CheckWasmBuiltinArgIsInteger(*this, TheCall, 1))
return true;
Expr *NewElemArg = TheCall->getArg(2);
if (!Context.hasSameType(ElTy, NewElemArg->getType())) {
return Diag(NewElemArg->getBeginLoc(),
diag::err_wasm_builtin_arg_must_match_table_element_type)
<< 3 << 1 << NewElemArg->getSourceRange();
}
if (CheckWasmBuiltinArgIsInteger(*this, TheCall, 3))
return true;
return false;
}
/// Check that the first argument is a WebAssembly table, the second is also a
/// WebAssembly table (of the same element type), and the third to fifth
/// arguments are integers.
bool Sema::BuiltinWasmTableCopy(CallExpr *TheCall) {
if (checkArgCount(*this, TheCall, 5))
return true;
QualType XElTy;
if (CheckWasmBuiltinArgIsTable(*this, TheCall, 0, XElTy))
return true;
QualType YElTy;
if (CheckWasmBuiltinArgIsTable(*this, TheCall, 1, YElTy))
return true;
Expr *TableYArg = TheCall->getArg(1);
if (!Context.hasSameType(XElTy, YElTy)) {
return Diag(TableYArg->getBeginLoc(),
diag::err_wasm_builtin_arg_must_match_table_element_type)
<< 2 << 1 << TableYArg->getSourceRange();
}
for (int I = 2; I <= 4; I++) {
if (CheckWasmBuiltinArgIsInteger(*this, TheCall, I))
return true;
}
return false;
}
/// \brief Enforce the bounds of a TCB
/// CheckTCBEnforcement - Enforces that every function in a named TCB only
/// directly calls other functions in the same TCB as marked by the enforce_tcb

View File

@ -7855,6 +7855,18 @@ NamedDecl *Sema::ActOnVariableDeclarator(
}
}
// WebAssembly tables are always in address space 1 (wasm_var). Don't apply
// address space if the table has local storage (semantic checks elsewhere
// will produce an error anyway).
if (const auto *ATy = dyn_cast<ArrayType>(NewVD->getType())) {
if (ATy && ATy->getElementType().isWebAssemblyReferenceType() &&
!NewVD->hasLocalStorage()) {
QualType Type = Context.getAddrSpaceQualType(
NewVD->getType(), Context.getLangASForBuiltinAddressSpace(1));
NewVD->setType(Type);
}
}
// Handle attributes prior to checking for duplicates in MergeVarDecl
ProcessDeclAttributes(S, NewVD, D);
@ -8011,6 +8023,13 @@ NamedDecl *Sema::ActOnVariableDeclarator(
if (!IsVariableTemplateSpecialization)
D.setRedeclaration(CheckVariableDeclaration(NewVD, Previous));
// CheckVariableDeclaration will set NewVD as invalid if something is in
// error like WebAssembly tables being declared as arrays with a non-zero
// size, but then parsing continues and emits further errors on that line.
// To avoid that we check here if it happened and return nullptr.
if (NewVD->getType()->isWebAssemblyTableType() && NewVD->isInvalidDecl())
return nullptr;
if (NewTemplate) {
VarTemplateDecl *PrevVarTemplate =
NewVD->getPreviousDecl()
@ -8617,6 +8636,28 @@ void Sema::CheckVariableDeclarationType(VarDecl *NewVD) {
}
}
// WebAssembly tables must be static with a zero length and can't be
// declared within functions.
if (T->isWebAssemblyTableType()) {
if (getCurScope()->getParent()) { // Parent is null at top-level
Diag(NewVD->getLocation(), diag::err_wasm_table_in_function);
NewVD->setInvalidDecl();
return;
}
if (NewVD->getStorageClass() != SC_Static) {
Diag(NewVD->getLocation(), diag::err_wasm_table_must_be_static);
NewVD->setInvalidDecl();
return;
}
const auto *ATy = dyn_cast<ConstantArrayType>(T.getTypePtr());
if (!ATy || ATy->getSize().getSExtValue() != 0) {
Diag(NewVD->getLocation(),
diag::err_typecheck_wasm_table_must_have_zero_length);
NewVD->setInvalidDecl();
return;
}
}
bool isVM = T->isVariablyModifiedType();
if (isVM || NewVD->hasAttr<CleanupAttr>() ||
NewVD->hasAttr<BlocksAttr>())
@ -8688,7 +8729,7 @@ void Sema::CheckVariableDeclarationType(VarDecl *NewVD) {
}
if (!NewVD->hasLocalStorage() && T->isSizelessType() &&
!T->isWebAssemblyReferenceType()) {
!T.isWebAssemblyReferenceType()) {
Diag(NewVD->getLocation(), diag::err_sizeless_nonlocal) << T;
NewVD->setInvalidDecl();
return;
@ -10687,6 +10728,14 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
}
}
}
// WebAssembly tables can't be used as function parameters.
if (Context.getTargetInfo().getTriple().isWasm()) {
if (PT->getUnqualifiedDesugaredType()->isWebAssemblyTableType()) {
Diag(Param->getTypeSpecStartLoc(),
diag::err_wasm_table_as_function_parameter);
D.setInvalidType();
}
}
}
// Here we have an function template explicit specialization at class scope.
@ -13074,6 +13123,14 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, bool DirectInit) {
return;
}
// WebAssembly tables can't be used to initialise a variable.
if (Init && !Init->getType().isNull() &&
Init->getType()->isWebAssemblyTableType()) {
Diag(Init->getExprLoc(), diag::err_wasm_table_art) << 0;
VDecl->setInvalidDecl();
return;
}
// C++11 [decl.spec.auto]p6. Deduce the type which 'auto' stands in for.
if (VDecl->getType()->isUndeducedType()) {
// Attempt typo correction early so that the type of the init expression can

View File

@ -16595,6 +16595,11 @@ VarDecl *Sema::BuildExceptionDeclaration(Scope *S,
!BaseType->isDependentType() && RequireCompleteType(Loc, BaseType, DK))
Invalid = true;
if (!Invalid && BaseType.isWebAssemblyReferenceType()) {
Diag(Loc, diag::err_wasm_reftype_tc) << 1;
Invalid = true;
}
if (!Invalid && Mode != 1 && BaseType->isSizelessType()) {
Diag(Loc, diag::err_catch_sizeless) << (Mode == 2 ? 1 : 0) << BaseType;
Invalid = true;

View File

@ -172,6 +172,12 @@ bool Sema::CheckSpecifiedExceptionType(QualType &T, SourceRange Range) {
RequireCompleteType(Range.getBegin(), PointeeT, DiagID, Kind, Range))
return ReturnValueOnError;
// WebAssembly reference types can't be used in exception specifications.
if (PointeeT.isWebAssemblyReferenceType()) {
Diag(Range.getBegin(), diag::err_wasm_reftype_exception_spec);
return true;
}
// The MSVC compatibility mode doesn't extend to sizeless types,
// so diagnose them separately.
if (PointeeT->isSizelessType() && Kind != 1) {

View File

@ -940,7 +940,7 @@ Sema::VarArgKind Sema::isValidVarArgType(const QualType &Ty) {
return VAK_Invalid;
if (Context.getTargetInfo().getTriple().isWasm() &&
Ty->isWebAssemblyReferenceType()) {
Ty.isWebAssemblyReferenceType()) {
return VAK_Invalid;
}
@ -4356,6 +4356,15 @@ bool Sema::CheckUnaryExprOrTypeTraitOperand(Expr *E,
E->getSourceRange(), ExprKind))
return false;
// WebAssembly tables are always illegal operands to unary expressions and
// type traits.
if (Context.getTargetInfo().getTriple().isWasm() &&
E->getType()->isWebAssemblyTableType()) {
Diag(E->getExprLoc(), diag::err_wasm_table_invalid_uett_operand)
<< getTraitSpelling(ExprKind);
return true;
}
// 'alignof' applied to an expression only requires the base element type of
// the expression to be complete. 'sizeof' requires the expression's type to
// be complete (and will attempt to complete it if it's an array of unknown
@ -4648,6 +4657,15 @@ bool Sema::CheckUnaryExprOrTypeTraitOperand(QualType ExprType,
return true;
}
// WebAssembly tables are always illegal operands to unary expressions and
// type traits.
if (Context.getTargetInfo().getTriple().isWasm() &&
ExprType->isWebAssemblyTableType()) {
Diag(OpLoc, diag::err_wasm_table_invalid_uett_operand)
<< getTraitSpelling(ExprKind);
return true;
}
if (CheckObjCTraitOperandConstraints(*this, ExprType, OpLoc, ExprRange,
ExprKind))
return true;
@ -4957,6 +4975,11 @@ ExprResult Sema::ActOnArraySubscriptExpr(Scope *S, Expr *base,
matSubscriptE->getRowIdx(),
ArgExprs.front(), rbLoc);
}
if (base->getType()->isWebAssemblyTableType()) {
Diag(base->getExprLoc(), diag::err_wasm_table_art)
<< SourceRange(base->getBeginLoc(), rbLoc) << 3;
return ExprError();
}
// Handle any non-overload placeholder types in the base and index
// expressions. We can't handle overloads here because the other
@ -5915,6 +5938,7 @@ Sema::CreateBuiltinArraySubscriptExpr(Expr *Base, SourceLocation LLoc,
if (!ResultType.hasQualifiers())
VK = VK_PRValue;
} else if (!ResultType->isDependentType() &&
!ResultType.isWebAssemblyReferenceType() &&
RequireCompleteSizedType(
LLoc, ResultType,
diag::err_subscript_incomplete_or_sizeless_type, BaseExpr))
@ -7459,6 +7483,16 @@ ExprResult Sema::BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl,
TheCall->setType(FuncT->getCallResultType(Context));
TheCall->setValueKind(Expr::getValueKindForType(FuncT->getReturnType()));
// WebAssembly tables can't be used as arguments.
if (Context.getTargetInfo().getTriple().isWasm()) {
for (const Expr *Arg : Args) {
if (Arg && Arg->getType()->isWebAssemblyTableType()) {
return ExprError(Diag(Arg->getExprLoc(),
diag::err_wasm_table_as_function_parameter));
}
}
}
if (Proto) {
if (ConvertArgumentsForCall(TheCall, Fn, FDecl, Proto, Args, RParenLoc,
IsExecConfig))
@ -9051,8 +9085,14 @@ QualType Sema::CheckConditionalOperands(ExprResult &Cond, ExprResult &LHS,
if (LHS.isInvalid() || RHS.isInvalid())
return QualType();
// WebAssembly tables are not allowed as conditional LHS or RHS.
QualType LHSTy = LHS.get()->getType();
QualType RHSTy = RHS.get()->getType();
if (LHSTy->isWebAssemblyTableType() || RHSTy->isWebAssemblyTableType()) {
Diag(QuestionLoc, diag::err_wasm_table_conditional_expression)
<< LHS.get()->getSourceRange() << RHS.get()->getSourceRange();
return QualType();
}
// Diagnose attempts to convert between __ibm128, __float128 and long double
// where such conversions currently can't be handled.
@ -12526,6 +12566,11 @@ static void diagnoseTautologicalComparison(Sema &S, SourceLocation Loc,
S.inTemplateInstantiation())
return;
// WebAssembly Tables cannot be compared, therefore shouldn't emit
// Tautological diagnostics.
if (LHSType->isWebAssemblyTableType() || RHSType->isWebAssemblyTableType())
return;
// Comparisons between two array types are ill-formed for operator<=>, so
// we shouldn't emit any additional warnings about it.
if (Opc == BO_Cmp && LHSType->isArrayType() && RHSType->isArrayType())
@ -12912,6 +12957,12 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS,
(RHSType->isArithmeticType() || RHSType->isEnumeralType()))
return checkArithmeticOrEnumeralCompare(*this, LHS, RHS, Loc, Opc);
if ((LHSType->isPointerType() &&
LHSType->getPointeeType().isWebAssemblyReferenceType()) ||
(RHSType->isPointerType() &&
RHSType->getPointeeType().isWebAssemblyReferenceType()))
return InvalidOperands(Loc, LHS, RHS);
const Expr::NullPointerConstantKind LHSNullKind =
LHS.get()->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull);
const Expr::NullPointerConstantKind RHSNullKind =
@ -13830,6 +13881,16 @@ inline QualType Sema::CheckLogicalOperands(ExprResult &LHS, ExprResult &RHS,
if (EnumConstantInBoolContext)
Diag(Loc, diag::warn_enum_constant_in_bool_context);
// WebAssembly tables can't be used with logical operators.
QualType LHSTy = LHS.get()->getType();
QualType RHSTy = RHS.get()->getType();
const auto *LHSATy = dyn_cast<ArrayType>(LHSTy);
const auto *RHSATy = dyn_cast<ArrayType>(RHSTy);
if ((LHSATy && LHSATy->getElementType().isWebAssemblyReferenceType()) ||
(RHSATy && RHSATy->getElementType().isWebAssemblyReferenceType())) {
return InvalidOperands(Loc, LHS, RHS);
}
// Diagnose cases where the user write a logical and/or but probably meant a
// bitwise one. We do this when the LHS is a non-bool integer and the RHS
// is a constant.
@ -14371,6 +14432,12 @@ QualType Sema::CheckAssignmentOperands(Expr *LHSExpr, ExprResult &RHS,
return QualType();
}
// WebAssembly tables can't be used on RHS of an assignment expression.
if (RHSType->isWebAssemblyTableType()) {
Diag(Loc, diag::err_wasm_table_art) << 0;
return QualType();
}
AssignConvertType ConvTy;
if (CompoundType.isNull()) {
Expr *RHSCheck = RHS.get();
@ -14978,11 +15045,19 @@ QualType Sema::CheckAddressOfOperand(ExprResult &OrigOp, SourceLocation OpLoc) {
if (op->getType()->isObjCObjectType())
return Context.getObjCObjectPointerType(op->getType());
if (Context.getTargetInfo().getTriple().isWasm() &&
op->getType()->isWebAssemblyReferenceType()) {
Diag(OpLoc, diag::err_wasm_ca_reference)
<< 1 << OrigOp.get()->getSourceRange();
return QualType();
// Cannot take the address of WebAssembly references or tables.
if (Context.getTargetInfo().getTriple().isWasm()) {
QualType OpTy = op->getType();
if (OpTy.isWebAssemblyReferenceType()) {
Diag(OpLoc, diag::err_wasm_ca_reference)
<< 1 << OrigOp.get()->getSourceRange();
return QualType();
}
if (OpTy->isWebAssemblyTableType()) {
Diag(OpLoc, diag::err_wasm_table_pr)
<< 1 << OrigOp.get()->getSourceRange();
return QualType();
}
}
CheckAddressOfPackedMember(op);
@ -16167,6 +16242,13 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc,
resultType = Context.FloatTy;
}
// WebAsembly tables can't be used in unary expressions.
if (resultType->isPointerType() &&
resultType->getPointeeType().isWebAssemblyReferenceType()) {
return ExprError(Diag(OpLoc, diag::err_typecheck_unary_expr)
<< resultType << Input.get()->getSourceRange());
}
if (resultType->isDependentType())
break;
if (resultType->isScalarType() && !isScopedEnumerationType(resultType)) {
@ -19203,7 +19285,7 @@ static bool captureInLambda(LambdaScopeInfo *LSI, ValueDecl *Var,
}
if (BuildAndDiagnose && S.Context.getTargetInfo().getTriple().isWasm() &&
CaptureType.getNonReferenceType()->isWebAssemblyReferenceType()) {
CaptureType.getNonReferenceType().isWebAssemblyReferenceType()) {
S.Diag(Loc, diag::err_wasm_ca_reference) << 0;
Invalid = true;
}

View File

@ -976,6 +976,19 @@ bool Sema::CheckCXXThrowOperand(SourceLocation ThrowLoc,
Ty = Ptr->getPointeeType();
isPointer = true;
}
// Cannot throw WebAssembly reference type.
if (Ty.isWebAssemblyReferenceType()) {
Diag(ThrowLoc, diag::err_wasm_reftype_tc) << 0 << E->getSourceRange();
return true;
}
// Cannot throw WebAssembly table.
if (isPointer && Ty.isWebAssemblyReferenceType()) {
Diag(ThrowLoc, diag::err_wasm_table_art) << 2 << E->getSourceRange();
return true;
}
if (!isPointer || !Ty->isVoidType()) {
if (RequireCompleteType(ThrowLoc, Ty,
isPointer ? diag::err_throw_incomplete_ptr
@ -6577,6 +6590,13 @@ QualType Sema::CXXCheckConditionalOperands(ExprResult &Cond, ExprResult &LHS,
if (IsSizelessVectorConditional)
return CheckSizelessVectorConditionalTypes(Cond, LHS, RHS, QuestionLoc);
// WebAssembly tables are not allowed as conditional LHS or RHS.
if (LTy->isWebAssemblyTableType() || RTy->isWebAssemblyTableType()) {
Diag(QuestionLoc, diag::err_wasm_table_conditional_expression)
<< LHS.get()->getSourceRange() << RHS.get()->getSourceRange();
return QualType();
}
// C++11 [expr.cond]p3
// Otherwise, if the second and third operand have different types, and
// either has (cv) class type [...] an attempt is made to convert each of

View File

@ -12019,7 +12019,16 @@ void OverloadCandidateSet::NoteCandidates(
S.Diag(PD.first, PD.second, shouldDeferDiags(S, Args, OpLoc));
NoteCandidates(S, Args, Cands, Opc, OpLoc);
// In WebAssembly we don't want to emit further diagnostics if a table is
// passed as an argument to a function.
bool NoteCands = true;
for (const Expr *Arg : Args) {
if (Arg->getType()->isWebAssemblyTableType())
NoteCands = false;
}
if (NoteCands)
NoteCandidates(S, Args, Cands, Opc, OpLoc);
if (OCD == OCD_AmbiguousCandidates)
MaybeDiagnoseAmbiguousConstraints(S, {begin(), end()});

View File

@ -3978,6 +3978,14 @@ StmtResult Sema::BuildReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp,
} else // If we don't have a function/method context, bail.
return StmtError();
if (RetValExp) {
const auto *ATy = dyn_cast<ArrayType>(RetValExp->getType());
if (ATy && ATy->getElementType().isWebAssemblyReferenceType()) {
Diag(ReturnLoc, diag::err_wasm_table_art) << 1;
return StmtError();
}
}
// C++1z: discarded return statements are not considered when deducing a
// return type.
if (ExprEvalContexts.back().isDiscardedStatementContext() &&

View File

@ -2201,11 +2201,19 @@ QualType Sema::BuildPointerType(QualType T,
if (getLangOpts().OpenCL)
T = deduceOpenCLPointeeAddrSpace(*this, T);
// In WebAssembly, pointers to reference types are illegal.
if (getASTContext().getTargetInfo().getTriple().isWasm() &&
T->isWebAssemblyReferenceType()) {
Diag(Loc, diag::err_wasm_reference_pr) << 0;
return QualType();
// In WebAssembly, pointers to reference types and pointers to tables are
// illegal.
if (getASTContext().getTargetInfo().getTriple().isWasm()) {
if (T.isWebAssemblyReferenceType()) {
Diag(Loc, diag::err_wasm_reference_pr) << 0;
return QualType();
}
// We need to desugar the type here in case T is a ParenType.
if (T->getUnqualifiedDesugaredType()->isWebAssemblyTableType()) {
Diag(Loc, diag::err_wasm_table_pr) << 0;
return QualType();
}
}
// Build the pointer type.
@ -2283,12 +2291,16 @@ QualType Sema::BuildReferenceType(QualType T, bool SpelledAsLValue,
if (getLangOpts().OpenCL)
T = deduceOpenCLPointeeAddrSpace(*this, T);
// In WebAssembly, references to reference types are illegal.
// In WebAssembly, references to reference types and tables are illegal.
if (getASTContext().getTargetInfo().getTriple().isWasm() &&
T->isWebAssemblyReferenceType()) {
T.isWebAssemblyReferenceType()) {
Diag(Loc, diag::err_wasm_reference_pr) << 1;
return QualType();
}
if (T->isWebAssemblyTableType()) {
Diag(Loc, diag::err_wasm_table_pr) << 1;
return QualType();
}
// Handle restrict on references.
if (LValueRef)
@ -2493,12 +2505,22 @@ QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM,
} else {
// C99 6.7.5.2p1: If the element type is an incomplete or function type,
// reject it (e.g. void ary[7], struct foo ary[7], void ary[7]())
if (RequireCompleteSizedType(Loc, T,
if (!T.isWebAssemblyReferenceType() &&
RequireCompleteSizedType(Loc, T,
diag::err_array_incomplete_or_sizeless_type))
return QualType();
}
if (T->isSizelessType()) {
// Multi-dimensional arrays of WebAssembly references are not allowed.
if (Context.getTargetInfo().getTriple().isWasm() && T->isArrayType()) {
const auto *ATy = dyn_cast<ArrayType>(T);
if (ATy && ATy->getElementType().isWebAssemblyReferenceType()) {
Diag(Loc, diag::err_wasm_reftype_multidimensional_array);
return QualType();
}
}
if (T->isSizelessType() && !T.isWebAssemblyReferenceType()) {
Diag(Loc, diag::err_array_incomplete_or_sizeless_type) << 1 << T;
return QualType();
}
@ -2617,7 +2639,7 @@ QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM,
<< ArraySize->getSourceRange();
return QualType();
}
if (ConstVal == 0) {
if (ConstVal == 0 && !T.isWebAssemblyReferenceType()) {
// GCC accepts zero sized static arrays. We allow them when
// we're not in a SFINAE context.
Diag(ArraySize->getBeginLoc(),
@ -3006,6 +3028,9 @@ QualType Sema::BuildFunctionType(QualType T,
Diag(Loc, diag::err_parameters_retval_cannot_have_fp16_type) << 0 <<
FixItHint::CreateInsertion(Loc, "*");
Invalid = true;
} else if (ParamType->isWebAssemblyTableType()) {
Diag(Loc, diag::err_wasm_table_as_function_parameter);
Invalid = true;
}
// C++2a [dcl.fct]p4:

View File

@ -0,0 +1,67 @@
// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --function-signature
// RUN: %clang_cc1 -triple wasm32 -target-feature +reference-types -disable-O0-optnone -emit-llvm %s -o - | opt -S -passes=mem2reg | FileCheck %s
// REQUIRES: webassembly-registered-target
static __externref_t table[0];
// CHECK-LABEL: define {{[^@]+}}@test_builtin_wasm_table_get
// CHECK-SAME: (i32 noundef [[INDEX:%.*]]) #[[ATTR0:[0-9]+]] {
// CHECK-NEXT: entry:
// CHECK-NEXT: [[TMP0:%.*]] = call ptr addrspace(10) @llvm.wasm.table.get.externref(ptr addrspace(1) @table, i32 [[INDEX]])
// CHECK-NEXT: ret ptr addrspace(10) [[TMP0]]
//
__externref_t test_builtin_wasm_table_get(int index) {
return __builtin_wasm_table_get(table, index);
}
// CHECK-LABEL: define {{[^@]+}}@test_builtin_wasm_table_set
// CHECK-SAME: (i32 noundef [[INDEX:%.*]], ptr addrspace(10) [[REF:%.*]]) #[[ATTR0]] {
// CHECK-NEXT: entry:
// CHECK-NEXT: call void @llvm.wasm.table.set.externref(ptr addrspace(1) @table, i32 [[INDEX]], ptr addrspace(10) [[REF]])
// CHECK-NEXT: ret void
//
void test_builtin_wasm_table_set(int index, __externref_t ref) {
return __builtin_wasm_table_set(table, index, ref);
}
// CHECK-LABEL: define {{[^@]+}}@test_builtin_wasm_table_size
// CHECK-SAME: () #[[ATTR0]] {
// CHECK-NEXT: entry:
// CHECK-NEXT: [[TMP0:%.*]] = call i32 @llvm.wasm.table.size(ptr addrspace(1) @table)
// CHECK-NEXT: ret i32 [[TMP0]]
//
int test_builtin_wasm_table_size() {
return __builtin_wasm_table_size(table);
}
// CHECK-LABEL: define {{[^@]+}}@test_builtin_wasm_table_grow
// CHECK-SAME: (ptr addrspace(10) [[REF:%.*]], i32 noundef [[NELEM:%.*]]) #[[ATTR0]] {
// CHECK-NEXT: entry:
// CHECK-NEXT: [[TMP0:%.*]] = call i32 @llvm.wasm.table.grow.externref(ptr addrspace(1) @table, ptr addrspace(10) [[REF]], i32 [[NELEM]])
// CHECK-NEXT: ret i32 [[TMP0]]
//
int test_builtin_wasm_table_grow(__externref_t ref, int nelem) {
return __builtin_wasm_table_grow(table, ref, nelem);
}
// CHECK-LABEL: define {{[^@]+}}@test_builtin_wasm_table_fill
// CHECK-SAME: (i32 noundef [[INDEX:%.*]], ptr addrspace(10) [[REF:%.*]], i32 noundef [[NELEM:%.*]]) #[[ATTR0]] {
// CHECK-NEXT: entry:
// CHECK-NEXT: call void @llvm.wasm.table.fill.externref(ptr addrspace(1) @table, i32 [[INDEX]], ptr addrspace(10) [[REF]], i32 [[NELEM]])
// CHECK-NEXT: ret void
//
void test_builtin_wasm_table_fill(int index, __externref_t ref, int nelem) {
__builtin_wasm_table_fill(table, index, ref, nelem);
}
static __externref_t other_table[0];
// CHECK-LABEL: define {{[^@]+}}@test_table_copy
// CHECK-SAME: (i32 noundef [[DST_IDX:%.*]], i32 noundef [[SRC_IDX:%.*]], i32 noundef [[NELEM:%.*]]) #[[ATTR0]] {
// CHECK-NEXT: entry:
// CHECK-NEXT: call void @llvm.wasm.table.copy(ptr addrspace(1) @table, ptr addrspace(1) @other_table, i32 [[SRC_IDX]], i32 [[DST_IDX]], i32 [[NELEM]])
// CHECK-NEXT: ret void
//
void test_table_copy(int dst_idx, int src_idx, int nelem) {
__builtin_wasm_table_copy(table, other_table, dst_idx, src_idx, nelem);
}

View File

@ -0,0 +1,52 @@
// RUN: %clang_cc1 -fsyntax-only -verify -triple wasm32 -target-feature +reference-types %s
#define EXPR_HAS_TYPE(expr, type) _Generic((expr), type : 1, default : 0)
static __externref_t table[0];
typedef void (*__funcref funcref_t)();
void test_ref_null() {
funcref_t func = __builtin_wasm_ref_null_func(0); // expected-error {{too many arguments to function call, expected 0, have 1}}
}
void test_table_size(__externref_t ref, void *ptr, int arr[]) {
__builtin_wasm_table_size(); // expected-error {{too few arguments to function call, expected 1, have 0}}
__builtin_wasm_table_size(1); // expected-error {{1st argument must be a WebAssembly table}}
__builtin_wasm_table_size(ref); // expected-error {{1st argument must be a WebAssembly table}}
__builtin_wasm_table_size(ptr); // expected-error {{1st argument must be a WebAssembly table}}
__builtin_wasm_table_size(arr); // expected-error {{1st argument must be a WebAssembly table}}
__builtin_wasm_table_size(table, table); // expected-error {{too many arguments to function call, expected 1, have 2}}
_Static_assert(EXPR_HAS_TYPE(__builtin_wasm_table_size(table), unsigned long), "");
}
void test_table_grow(__externref_t ref, int size) {
__builtin_wasm_table_grow(); // expected-error {{too few arguments to function call, expected 3, have 0}}
__builtin_wasm_table_grow(table, table, table, table); // expected-error {{too many arguments to function call, expected 3, have 4}}
__builtin_wasm_table_grow(ref, ref, size); // expected-error {{1st argument must be a WebAssembly table}}
__builtin_wasm_table_grow(table, table, size); // expected-error {{2nd argument must match the element type of the WebAssembly table in the 1st argument}}
__builtin_wasm_table_grow(table, ref, table); // expected-error {{3rd argument must be an integer}}
_Static_assert(EXPR_HAS_TYPE(__builtin_wasm_table_grow(table, ref, size), int), "");
}
void test_table_fill(int index, __externref_t ref, int nelem) {
__builtin_wasm_table_fill(); // expected-error {{too few arguments to function call, expected 4, have 0}}
__builtin_wasm_table_fill(table, table, table, table, table); // expected-error {{too many arguments to function call, expected 4, have 5}}
__builtin_wasm_table_fill(index, index, ref, nelem); // expected-error {{1st argument must be a WebAssembly table}}
__builtin_wasm_table_fill(table, table, ref, nelem); // expected-error {{2nd argument must be an integer}}
__builtin_wasm_table_fill(table, index, index, ref); // expected-error {{3rd argument must match the element type of the WebAssembly table in the 1st argument}}
__builtin_wasm_table_fill(table, index, ref, table); // expected-error {{4th argument must be an integer}}
__builtin_wasm_table_fill(table, index, ref, nelem);
}
void test_table_copy(int dst_idx, int src_idx, int nelem) {
__builtin_wasm_table_copy(); // expected-error {{too few arguments to function call, expected 5, have 0}}
__builtin_wasm_table_copy(table, table, table, table, table, table); // expected-error {{too many arguments to function call, expected 5, have 6}}
__builtin_wasm_table_copy(src_idx, table, dst_idx, src_idx, nelem); // expected-error {{1st argument must be a WebAssembly table}}
__builtin_wasm_table_copy(table, src_idx, dst_idx, src_idx, nelem); // expected-error {{2nd argument must be a WebAssembly table}}
__builtin_wasm_table_copy(table, table, table, src_idx, nelem); // expected-error {{3rd argument must be an integer}}
__builtin_wasm_table_copy(table, table, dst_idx, table, nelem); // expected-error {{4th argument must be an integer}}
__builtin_wasm_table_copy(table, table, dst_idx, src_idx, table); // expected-error {{5th argument must be an integer}}
__builtin_wasm_table_copy(table, table, dst_idx, src_idx, nelem);
}

View File

@ -0,0 +1,3 @@
// RUN: %clang_cc1 -fsyntax-only -pedantic -verify=expected -triple wasm32 -Wno-unused-value -target-feature +reference-types %s
// No error should be emitted.
static __externref_t table[0]; // expected-no-diagnostics

View File

@ -0,0 +1,133 @@
// RUN: %clang_cc1 -fsyntax-only -verify=expected,conly -triple wasm32 -Wno-unused-value -target-feature +reference-types %s
// RUN: %clang_cc1 -x c++ -std=c++17 -fsyntax-only -verify=expected,cpp -triple wasm32 -Wno-unused-value -target-feature +reference-types %s
// Note: As WebAssembly references are sizeless types, we don't exhaustively
// test for cases covered by sizeless-1.c and similar tests.
// Unlike standard sizeless types, reftype globals are supported.
__externref_t r1;
extern __externref_t r2;
static __externref_t r3;
__externref_t *t1; // expected-error {{pointer to WebAssembly reference type is not allowed}}
__externref_t **t2; // expected-error {{pointer to WebAssembly reference type is not allowed}}
__externref_t ******t3; // expected-error {{pointer to WebAssembly reference type is not allowed}}
static __externref_t t4[3]; // expected-error {{only zero-length WebAssembly tables are currently supported}}
static __externref_t t5[]; // expected-error {{only zero-length WebAssembly tables are currently supported}}
static __externref_t t6[] = {0}; // expected-error {{only zero-length WebAssembly tables are currently supported}}
__externref_t t7[0]; // expected-error {{WebAssembly table must be static}}
static __externref_t t8[0][0]; // expected-error {{multi-dimensional arrays of WebAssembly references are not allowed}}
static __externref_t (*t9)[0]; // expected-error {{cannot form a pointer to a WebAssembly table}}
static __externref_t table[0];
static __externref_t other_table[0] = {};
static __externref_t another_table[] = {}; // expected-error {{only zero-length WebAssembly tables are currently supported}}
struct s {
__externref_t f1; // expected-error {{field has sizeless type '__externref_t'}}
__externref_t f2[0]; // expected-error {{field has sizeless type '__externref_t'}}
__externref_t f3[]; // expected-error {{field has sizeless type '__externref_t'}}
__externref_t f4[0][0]; // expected-error {{multi-dimensional arrays of WebAssembly references are not allowed}}
__externref_t *f5; // expected-error {{pointer to WebAssembly reference type is not allowed}}
__externref_t ****f6; // expected-error {{pointer to WebAssembly reference type is not allowed}}
__externref_t (*f7)[0]; // expected-error {{cannot form a pointer to a WebAssembly table}}
};
union u {
__externref_t f1; // expected-error {{field has sizeless type '__externref_t'}}
__externref_t f2[0]; // expected-error {{field has sizeless type '__externref_t'}}
__externref_t f3[]; // expected-error {{field has sizeless type '__externref_t'}}
__externref_t f4[0][0]; // expected-error {{multi-dimensional arrays of WebAssembly references are not allowed}}
__externref_t *f5; // expected-error {{pointer to WebAssembly reference type is not allowed}}
__externref_t ****f6; // expected-error {{pointer to WebAssembly reference type is not allowed}}
__externref_t (*f7)[0]; // expected-error {{cannot form a pointer to a WebAssembly table}}
};
void illegal_argument_1(__externref_t table[]); // expected-error {{cannot use WebAssembly table as a function parameter}}
void illegal_argument_2(__externref_t table[0][0]); // expected-error {{multi-dimensional arrays of WebAssembly references are not allowed}}
void illegal_argument_3(__externref_t *table); // expected-error {{pointer to WebAssembly reference type is not allowed}}
void illegal_argument_4(__externref_t ***table); // expected-error {{pointer to WebAssembly reference type is not allowed}}
void illegal_argument_5(__externref_t (*table)[0]); // expected-error {{cannot form a pointer to a WebAssembly table}}
void illegal_argument_6(__externref_t table[0]); // expected-error {{cannot use WebAssembly table as a function parameter}}
__externref_t *illegal_return_1(); // expected-error {{pointer to WebAssembly reference type is not allowed}}
__externref_t ***illegal_return_2(); // expected-error {{pointer to WebAssembly reference type is not allowed}}
__externref_t (*illegal_return_3())[0]; // expected-error {{cannot form a pointer to a WebAssembly table}}
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}}
int foo = 40;
(__externref_t *)(&foo); // expected-error {{pointer to WebAssembly reference type is not allowed}}
(__externref_t ****)(&foo); // expected-error {{pointer to WebAssembly reference type is not allowed}}
sizeof(ref); // expected-error {{invalid application of 'sizeof' to sizeless type '__externref_t'}}
sizeof(__externref_t); // expected-error {{invalid application of 'sizeof' to sizeless type '__externref_t'}}
sizeof(__externref_t[0]); // expected-error {{invalid application of 'sizeof' to WebAssembly table}}
sizeof(table); // expected-error {{invalid application of 'sizeof' to WebAssembly table}}
sizeof(__externref_t[0][0]); // expected-error {{multi-dimensional arrays of WebAssembly references are not allowed}}
sizeof(__externref_t *); // expected-error {{pointer to WebAssembly reference type is not allowed}}
sizeof(__externref_t ***); // expected-error {{pointer to WebAssembly reference type is not allowed}};
// expected-warning@+1 {{'_Alignof' applied to an expression is a GNU extension}}
_Alignof(ref); // expected-error {{invalid application of 'alignof' to sizeless type '__externref_t'}}
_Alignof(__externref_t); // expected-error {{invalid application of 'alignof' to sizeless type '__externref_t'}}
_Alignof(__externref_t[]); // expected-error {{invalid application of 'alignof' to sizeless type '__externref_t'}}
_Alignof(__externref_t[0]); // expected-error {{invalid application of 'alignof' to sizeless type '__externref_t'}}
_Alignof(table); // expected-warning {{'_Alignof' applied to an expression is a GNU extension}} expected-error {{invalid application of 'alignof' to WebAssembly table}}
_Alignof(__externref_t[0][0]); // expected-error {{multi-dimensional arrays of WebAssembly references are not allowed}}
_Alignof(__externref_t *); // expected-error {{pointer to WebAssembly reference type is not allowed}}
_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}}
__externref_t lt1[0]; // expected-error {{WebAssembly table cannot be declared within a function}}
static __externref_t lt2[0]; // expected-error {{WebAssembly table cannot be declared within a function}}
static __externref_t lt3[0][0]; // expected-error {{multi-dimensional arrays of WebAssembly references are not allowed}}
static __externref_t(*lt4)[0]; // expected-error {{cannot form a pointer to a WebAssembly table}}
// conly-error@+2 {{cannot use WebAssembly table as a function parameter}}
// cpp-error@+1 {{no matching function for call to 'illegal_argument_1'}}
illegal_argument_1(table);
varargs(1, table); // expected-error {{cannot use WebAssembly table as a function parameter}}
table == 1; // expected-error {{invalid operands to binary expression ('__attribute__((address_space(1))) __externref_t[0]' and 'int')}}
1 >= table; // expected-error {{invalid operands to binary expression ('int' and '__attribute__((address_space(1))) __externref_t[0]')}}
table == other_table; // expected-error {{invalid operands to binary expression ('__attribute__((address_space(1))) __externref_t[0]' and '__attribute__((address_space(1))) __externref_t[0]')}}
table !=- table; // expected-error {{invalid argument type '__attribute__((address_space(1))) __externref_t *' to unary expression}}
!table; // expected-error {{invalid argument type '__attribute__((address_space(1))) __externref_t *' to unary expression}}
1 && table; // expected-error {{invalid operands to binary expression ('int' and '__attribute__((address_space(1))) __externref_t[0]')}}
table || 1; // expected-error {{invalid operands to binary expression ('__attribute__((address_space(1))) __externref_t[0]' and 'int')}}
1 ? table : table; // expected-error {{cannot use a WebAssembly table within a branch of a conditional expression}}
table ? : other_table; // expected-error {{cannot use a WebAssembly table within a branch of a conditional expression}}
(void *)table; // expected-error {{cannot cast from a WebAssembly table}}
void *u;
u = table; // expected-error {{cannot assign a WebAssembly table}}
void *v = table; // expected-error {{cannot assign a WebAssembly table}}
&table; // expected-error {{cannot form a reference to a WebAssembly table}}
(void)table;
table[0]; // expected-error {{cannot subscript a WebAssembly table}}
table[0] = ref; // expected-error {{cannot subscript a WebAssembly table}}
int i = 0;
__externref_t oh_no_vlas[i]; // expected-error {{WebAssembly table cannot be declared within a function}}
return ref;
}
void foo() {
static __externref_t t[0]; // expected-error {{WebAssembly table cannot be declared within a function}}
{
static __externref_t t2[0]; // expected-error {{WebAssembly table cannot be declared within a function}}
for (;;) {
static __externref_t t3[0]; // expected-error {{WebAssembly table cannot be declared within a function}}
}
}
int i = ({
static __externref_t t4[0]; // expected-error {{WebAssembly table cannot be declared within a function}}
1;
});
}
void *ret_void_ptr() {
return table; // expected-error {{cannot return a WebAssembly table}}
}

View File

@ -1,75 +0,0 @@
// RUN: %clang_cc1 -fsyntax-only -verify -triple wasm32 -target-feature +reference-types %s
// Note: As WebAssembly references are sizeless types, we don't exhaustively
// test for cases covered by sizeless-1.c and similar tests.
// Unlike standard sizeless types, reftype globals are supported.
__externref_t r1;
extern __externref_t r2;
static __externref_t r3;
__externref_t *t1; // expected-error {{pointer to WebAssembly reference type is not allowed}}
__externref_t **t2; // expected-error {{pointer to WebAssembly reference type is not allowed}}
__externref_t ******t3; // expected-error {{pointer to WebAssembly reference type is not allowed}}
static __externref_t t4[3]; // expected-error {{array has sizeless element type '__externref_t'}}
static __externref_t t5[]; // expected-error {{array has sizeless element type '__externref_t'}}
static __externref_t t6[] = {0}; // expected-error {{array has sizeless element type '__externref_t'}}
__externref_t t7[0]; // expected-error {{array has sizeless element type '__externref_t'}}
static __externref_t t8[0][0]; // expected-error {{array has sizeless element type '__externref_t'}}
static __externref_t table[0]; // expected-error {{array has sizeless element type '__externref_t'}}
struct s {
__externref_t f1; // expected-error {{field has sizeless type '__externref_t'}}
__externref_t f2[0]; // expected-error {{array has sizeless element type '__externref_t'}}
__externref_t f3[]; // expected-error {{array has sizeless element type '__externref_t'}}
__externref_t f4[0][0]; // expected-error {{array has sizeless element type '__externref_t'}}
__externref_t *f5; // expected-error {{pointer to WebAssembly reference type is not allowed}}
__externref_t ****f6; // expected-error {{pointer to WebAssembly reference type is not allowed}}
};
union u {
__externref_t f1; // expected-error {{field has sizeless type '__externref_t'}}
__externref_t f2[0]; // expected-error {{array has sizeless element type '__externref_t'}}
__externref_t f3[]; // expected-error {{array has sizeless element type '__externref_t'}}
__externref_t f4[0][0]; // expected-error {{array has sizeless element type '__externref_t'}}
__externref_t *f5; // expected-error {{pointer to WebAssembly reference type is not allowed}}
__externref_t ****f6; // expected-error {{pointer to WebAssembly reference type is not allowed}}
};
void illegal_argument_1(__externref_t table[]); // expected-error {{array has sizeless element type '__externref_t'}}
void illegal_argument_2(__externref_t table[0][0]); // expected-error {{array has sizeless element type '__externref_t'}}
void illegal_argument_3(__externref_t *table); // expected-error {{pointer to WebAssembly reference type is not allowed}}
void illegal_argument_4(__externref_t ***table); // expected-error {{pointer to WebAssembly reference type is not allowed}}
__externref_t *illegal_return_1(); // expected-error {{pointer to WebAssembly reference type is not allowed}}
__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}}
int foo = 40;
(__externref_t *)(&foo); // expected-error {{pointer to WebAssembly reference type is not allowed}}
(__externref_t ****)(&foo); // expected-error {{pointer to WebAssembly reference type is not allowed}}
sizeof(ref); // expected-error {{invalid application of 'sizeof' to sizeless type '__externref_t'}}
sizeof(__externref_t); // expected-error {{invalid application of 'sizeof' to sizeless type '__externref_t'}}
sizeof(__externref_t[0]); // expected-error {{array has sizeless element type '__externref_t'}}
sizeof(__externref_t[0][0]); // expected-error {{array has sizeless element type '__externref_t'}}
sizeof(__externref_t *); // expected-error {{pointer to WebAssembly reference type is not allowed}}
sizeof(__externref_t ***); // expected-error {{pointer to WebAssembly reference type is not allowed}};
// expected-warning@+1 {{'_Alignof' applied to an expression is a GNU extension}}
_Alignof(ref); // expected-error {{invalid application of 'alignof' to sizeless type '__externref_t'}}
_Alignof(__externref_t); // expected-error {{invalid application of 'alignof' to sizeless type '__externref_t'}}
_Alignof(__externref_t[]); // expected-error {{array has sizeless element type '__externref_t'}}
_Alignof(__externref_t[0][0]); // expected-error {{array has sizeless element type '__externref_t'}}
_Alignof(__externref_t *); // expected-error {{pointer to WebAssembly reference type is not allowed}}
_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;
}

View File

@ -0,0 +1,30 @@
// RUN: %clang_cc1 -std=c++11 -fcxx-exceptions -fexceptions -fsyntax-only -verify -triple wasm32 -Wno-unused-value -target-feature +reference-types %s
// RUN: %clang_cc1 -std=c++20 -fcxx-exceptions -fexceptions -fsyntax-only -verify -triple wasm32 -Wno-unused-value -target-feature +reference-types %s
//
// Note: As WebAssembly references are sizeless types, we don't exhaustively
// test for cases covered by sizeless-1.c and similar tests.
// Using c++11 to test dynamic exception specifications (which are not
// allowed in c++17).
// Unlike standard sizeless types, reftype globals are supported.
__externref_t r1;
static __externref_t table[0];
#if (_cplusplus == 201103L)
__externref_t func(__externref_t ref) throw(__externref_t) { // expected-error {{WebAssembly reference type not allowed in exception specification}}
return ref;
}
#endif
void *ret_void_ptr() {
throw table; // expected-error {{cannot throw a WebAssembly reference type}}
throw r1; // expected-error {{cannot throw a WebAssembly reference type}}
try {}
catch (__externref_t T) { // expected-error {{cannot catch a WebAssembly reference type}}
(void)0;
}
return table; // expected-error {{cannot return a WebAssembly table}}
}

View File

@ -1,103 +0,0 @@
// RUN: %clang_cc1 -fcxx-exceptions -fsyntax-only -verify -std=gnu++11 -triple wasm32 -Wno-unused-value -target-feature +reference-types %s
// This file tests C++ specific constructs with WebAssembly references and
// tables. See wasm-refs-and-tables.c for C constructs.
__externref_t ref;
__externref_t &ref_ref1 = ref; // expected-error {{reference to WebAssembly reference type is not allowed}}
__externref_t &ref_ref2(ref); // expected-error {{reference to WebAssembly reference type is not allowed}}
static __externref_t table[0]; // expected-error {{array has sizeless element type '__externref_t'}}
static __externref_t (&ref_to_table1)[0] = table; // expected-error {{array has sizeless element type '__externref_t'}}
static __externref_t (&ref_to_table2)[0](table); // expected-error {{array has sizeless element type '__externref_t'}}
void illegal_argument_1(__externref_t &r); // expected-error {{reference to WebAssembly reference type is not allowed}}
void illegal_argument_2(__externref_t (&t)[0]); // expected-error {{array has sizeless element type '__externref_t'}}
__externref_t &illegal_return_1(); // expected-error {{reference to WebAssembly reference type is not allowed}}
__externref_t (&illegal_return_2())[0]; // expected-error {{array has sizeless element type '__externref_t'}}
void illegal_throw1() throw(__externref_t); // expected-error {{sizeless type '__externref_t' is not allowed in exception specification}}
void illegal_throw2() throw(__externref_t *); // expected-error {{pointer to WebAssembly reference type is not allowed}}
void illegal_throw3() throw(__externref_t &); // expected-error {{reference to WebAssembly reference type is not allowed}}
void illegal_throw4() throw(__externref_t[0]); // expected-error {{array has sizeless element type '__externref_t'}}
class RefClass {
__externref_t f1; // expected-error {{field has sizeless type '__externref_t'}}
__externref_t f2[0]; // expected-error {{array has sizeless element type '__externref_t'}}
__externref_t f3[]; // expected-error {{array has sizeless element type '__externref_t'}}
__externref_t f4[0][0]; // expected-error {{array has sizeless element type '__externref_t'}}
__externref_t *f5; // expected-error {{pointer to WebAssembly reference type is not allowed}}
__externref_t ****f6; // expected-error {{pointer to WebAssembly reference type is not allowed}}
__externref_t (*f7)[0]; // expected-error {{array has sizeless element type '__externref_t'}}
};
struct AStruct {};
template <typename T>
struct TemplatedStruct {
T f; // expected-error {{field has sizeless type '__externref_t'}}
void foo(T);
T bar(void);
T arr[0]; // expected-error {{array has sizeless element type '__externref_t'}}
T *ptr; // expected-error {{pointer to WebAssembly reference type is not allowed}}
};
void func() {
int foo = 40;
static_cast<__externref_t>(foo); // expected-error {{static_cast from 'int' to '__externref_t' is not allowed}}
static_cast<__externref_t *>(&foo); // expected-error {{pointer to WebAssembly reference type is not allowed}}
static_cast<int>(ref); // expected-error {{static_cast from '__externref_t' to 'int' is not allowed}}
__externref_t(10); // expected-error {{functional-style cast from 'int' to '__externref_t' is not allowed}}
int i(ref); // expected-error {{cannot initialize a variable of type 'int' with an lvalue of type '__externref_t'}}
const_cast<__externref_t[0]>(table); // expected-error {{array has sizeless element type '__externref_t'}}
const_cast<__externref_t *>(table); // expected-error {{pointer to WebAssembly reference type is not allowed}}
reinterpret_cast<__externref_t>(foo); // expected-error {{reinterpret_cast from 'int' to '__externref_t' is not allowed}}
reinterpret_cast<int>(ref); // expected-error {{reinterpret_cast from '__externref_t' to 'int' is not allowed}}
int iarr[0];
reinterpret_cast<__externref_t[0]>(iarr); // expected-error {{array has sizeless element type '__externref_t'}}
reinterpret_cast<__externref_t *>(iarr); // expected-error {{pointer to WebAssembly reference type is not allowed}}
dynamic_cast<__externref_t>(foo); // expected-error {{invalid target type '__externref_t' for dynamic_cast; target type must be a reference or pointer type to a defined class}}
dynamic_cast<__externref_t *>(&foo); // expected-error {{pointer to WebAssembly reference type is not allowed}}
TemplatedStruct<__externref_t> ts1; // expected-note {{in instantiation}}
TemplatedStruct<__externref_t *> ts2; // expected-error {{pointer to WebAssembly reference type is not allowed}}
TemplatedStruct<__externref_t &> ts3; // expected-error {{reference to WebAssembly reference type is not allowed}}
TemplatedStruct<__externref_t[0]> ts4; // expected-error {{array has sizeless element type '__externref_t'}}
auto auto_ref = ref;
auto fn1 = [](__externref_t x) { return x; };
auto fn2 = [](__externref_t *x) { return x; }; // expected-error {{pointer to WebAssembly reference type is not allowed}}
auto fn3 = [](__externref_t &x) { return x; }; // expected-error {{reference to WebAssembly reference type is not allowed}}
auto fn4 = [](__externref_t x[0]) { return x; }; // expected-error {{array has sizeless element type '__externref_t'}}
auto fn5 = [&auto_ref](void) { return true; }; // expected-error {{cannot capture WebAssembly reference}}
auto fn6 = [auto_ref](void) { return true; }; // expected-error {{cannot capture WebAssembly reference}}
auto fn7 = [&](void) { auto_ref; return true; }; // expected-error {{cannot capture WebAssembly reference}}
auto fn8 = [=](void) { auto_ref; return true; }; // expected-error {{cannot capture WebAssembly reference}}
alignof(__externref_t); // expected-error {{invalid application of 'alignof' to sizeless type '__externref_t'}}
alignof(ref); // expected-warning {{'alignof' applied to an expression is a GNU extension}} expected-error {{invalid application of 'alignof' to sizeless type '__externref_t'}}
alignof(__externref_t[0]); // expected-error {{array has sizeless element type '__externref_t'}}
throw ref; // expected-error {{cannot throw object of sizeless type '__externref_t'}}
throw &ref; // expected-error {{cannot take address of WebAssembly reference}}
try {
} catch (__externref_t) { // expected-error {{cannot catch sizeless type '__externref_t'}}
}
try {
} catch (__externref_t *) { // expected-error {{pointer to WebAssembly reference type is not allowed}}
}
try {
} catch (__externref_t &) { // expected-error {{reference to WebAssembly reference type is not allowed}}
}
try {
} catch (__externref_t[0]) { // expected-error {{array has sizeless element type '__externref_t'}}
}
new __externref_t; // expected-error {{allocation of sizeless type '__externref_t'}}
new __externref_t[0]; // expected-error {{allocation of sizeless type '__externref_t'}}
delete ref; // expected-error {{cannot delete expression of type '__externref_t'}}
}

View File

@ -0,0 +1,48 @@
//===--- llvm/CodeGen/WasmAddressSpaces.h -----------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// Address Spaces for WebAssembly Type Handling
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_CODEGEN_WASM_ADDRESS_SPACES_H
#define LLVM_CODEGEN_WASM_ADDRESS_SPACES_H
namespace llvm {
namespace WebAssembly {
enum WasmAddressSpace : unsigned {
// Default address space, for pointers to linear memory (stack, heap, data).
WASM_ADDRESS_SPACE_DEFAULT = 0,
// A non-integral address space for pointers to named objects outside of
// linear memory: WebAssembly globals or WebAssembly locals. Loads and stores
// to these pointers are lowered to global.get / global.set or local.get /
// local.set, as appropriate.
WASM_ADDRESS_SPACE_VAR = 1,
// A non-integral address space for externref values
WASM_ADDRESS_SPACE_EXTERNREF = 10,
// A non-integral address space for funcref values
WASM_ADDRESS_SPACE_FUNCREF = 20,
};
inline bool isDefaultAddressSpace(unsigned AS) {
return AS == WASM_ADDRESS_SPACE_DEFAULT;
}
inline bool isWasmVarAddressSpace(unsigned AS) {
return AS == WASM_ADDRESS_SPACE_VAR;
}
inline bool isValidAddressSpace(unsigned AS) {
return isDefaultAddressSpace(AS) || isWasmVarAddressSpace(AS);
}
} // namespace WebAssembly
} // namespace llvm
#endif // LLVM_CODEGEN_WASM_ADDRESS_SPACES_H

View File

@ -77,13 +77,13 @@ void WebAssembly::wasmSymbolSetType(MCSymbolWasm *Sym, const Type *GlobalVT,
// that is a reference type.
wasm::ValType ValTy;
bool IsTable = false;
if (GlobalVT->isArrayTy() &&
WebAssembly::isRefType(GlobalVT->getArrayElementType())) {
if (GlobalVT->isArrayTy() && WebAssembly::isWebAssemblyReferenceType(
GlobalVT->getArrayElementType())) {
IsTable = true;
const Type *ElTy = GlobalVT->getArrayElementType();
if (WebAssembly::isExternrefType(ElTy))
if (WebAssembly::isWebAssemblyExternrefType(ElTy))
ValTy = wasm::ValType::EXTERNREF;
else if (WebAssembly::isFuncrefType(ElTy))
else if (WebAssembly::isWebAssemblyFuncrefType(ElTy))
ValTy = wasm::ValType::FUNCREF;
else
report_fatal_error("unhandled reference type");

View File

@ -18,6 +18,7 @@
#include "MCTargetDesc/WebAssemblyMCTypeUtilities.h"
#include "llvm/BinaryFormat/Wasm.h"
#include "llvm/CodeGen/MachineValueType.h"
#include "llvm/CodeGen/WasmAddressSpaces.h"
#include "llvm/IR/DerivedTypes.h"
#include "llvm/MC/MCSymbolWasm.h"
@ -27,41 +28,21 @@ class TargetRegisterClass;
namespace WebAssembly {
enum WasmAddressSpace : unsigned {
// Default address space, for pointers to linear memory (stack, heap, data).
WASM_ADDRESS_SPACE_DEFAULT = 0,
// A non-integral address space for pointers to named objects outside of
// linear memory: WebAssembly globals or WebAssembly locals. Loads and stores
// to these pointers are lowered to global.get / global.set or local.get /
// local.set, as appropriate.
WASM_ADDRESS_SPACE_VAR = 1,
// A non-integral address space for externref values
WASM_ADDRESS_SPACE_EXTERNREF = 10,
// A non-integral address space for funcref values
WASM_ADDRESS_SPACE_FUNCREF = 20,
};
/// Return true if this is a WebAssembly Externref Type.
inline bool isWebAssemblyExternrefType(const Type *Ty) {
return Ty->getPointerAddressSpace() ==
WebAssembly::WasmAddressSpace::WASM_ADDRESS_SPACE_EXTERNREF;
}
inline bool isDefaultAddressSpace(unsigned AS) {
return AS == WASM_ADDRESS_SPACE_DEFAULT;
/// Return true if this is a WebAssembly Funcref Type.
inline bool isWebAssemblyFuncrefType(const Type *Ty) {
return Ty->getPointerAddressSpace() ==
WebAssembly::WasmAddressSpace::WASM_ADDRESS_SPACE_FUNCREF;
}
inline bool isWasmVarAddressSpace(unsigned AS) {
return AS == WASM_ADDRESS_SPACE_VAR;
}
inline bool isValidAddressSpace(unsigned AS) {
return isDefaultAddressSpace(AS) || isWasmVarAddressSpace(AS);
}
inline bool isFuncrefType(const Type *Ty) {
return isa<PointerType>(Ty) &&
Ty->getPointerAddressSpace() ==
WasmAddressSpace::WASM_ADDRESS_SPACE_FUNCREF;
}
inline bool isExternrefType(const Type *Ty) {
return isa<PointerType>(Ty) &&
Ty->getPointerAddressSpace() ==
WasmAddressSpace::WASM_ADDRESS_SPACE_EXTERNREF;
}
inline bool isRefType(const Type *Ty) {
return isFuncrefType(Ty) || isExternrefType(Ty);
/// Return true if this is a WebAssembly Reference Type.
inline bool isWebAssemblyReferenceType(const Type *Ty) {
return isWebAssemblyExternrefType(Ty) || isWebAssemblyFuncrefType(Ty);
}
// Convert StringRef to ValType / HealType / BlockType

View File

@ -1214,8 +1214,8 @@ WebAssemblyTargetLowering::LowerCall(CallLoweringInfo &CLI,
// Lastly, if this is a call to a funcref we need to add an instruction
// table.set to the chain and transform the call.
if (CLI.CB &&
WebAssembly::isFuncrefType(CLI.CB->getCalledOperand()->getType())) {
if (CLI.CB && WebAssembly::isWebAssemblyFuncrefType(
CLI.CB->getCalledOperand()->getType())) {
// In the absence of function references proposal where a funcref call is
// lowered to call_ref, using reference types we generate a table.set to set
// the funcref to a special table used solely for this purpose, followed by

View File

@ -62,8 +62,9 @@ bool WebAssemblyLowerRefTypesIntPtrConv::runOnFunction(Function &F) {
for (inst_iterator I = inst_begin(F), E = inst_end(F); I != E; ++I) {
PtrToIntInst *PTI = dyn_cast<PtrToIntInst>(&*I);
IntToPtrInst *ITP = dyn_cast<IntToPtrInst>(&*I);
if (!(PTI && WebAssembly::isRefType(PTI->getPointerOperand()->getType())) &&
!(ITP && WebAssembly::isRefType(ITP->getDestTy())))
if (!(PTI && WebAssembly::isWebAssemblyReferenceType(
PTI->getPointerOperand()->getType())) &&
!(ITP && WebAssembly::isWebAssemblyReferenceType(ITP->getDestTy())))
continue;
UndefValue *U = UndefValue::get(I->getType());