mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2025-03-04 16:41:43 +00:00
[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:
parent
5b657f50b8
commit
55aeb23fe0
@ -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
|
||||
=================
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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 {
|
||||
|
@ -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 =
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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"
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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()});
|
||||
|
@ -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() &&
|
||||
|
@ -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:
|
||||
|
67
clang/test/CodeGen/WebAssembly/builtins-table.c
Normal file
67
clang/test/CodeGen/WebAssembly/builtins-table.c
Normal 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);
|
||||
}
|
52
clang/test/Sema/builtins-wasm.c
Normal file
52
clang/test/Sema/builtins-wasm.c
Normal 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);
|
||||
}
|
3
clang/test/Sema/wasm-refs-and-table-ped.c
Normal file
3
clang/test/Sema/wasm-refs-and-table-ped.c
Normal 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
|
133
clang/test/Sema/wasm-refs-and-tables.c
Normal file
133
clang/test/Sema/wasm-refs-and-tables.c
Normal 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}}
|
||||
}
|
@ -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;
|
||||
}
|
30
clang/test/SemaCXX/wasm-refs-and-tables.cpp
Normal file
30
clang/test/SemaCXX/wasm-refs-and-tables.cpp
Normal 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}}
|
||||
}
|
@ -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'}}
|
||||
}
|
48
llvm/include/llvm/CodeGen/WasmAddressSpaces.h
Normal file
48
llvm/include/llvm/CodeGen/WasmAddressSpaces.h
Normal 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
|
@ -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");
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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());
|
||||
|
Loading…
x
Reference in New Issue
Block a user