[clang] 55aeb23 - [clang][WebAssembly] Implement support for table types and builtins

Paulo Matos via cfe-commits cfe-commits at lists.llvm.org
Sat Jun 10 06:53:37 PDT 2023


Author: Paulo Matos
Date: 2023-06-10T15:53:13+02:00
New Revision: 55aeb23fe0084d930ecd7335092d712bd71694c7

URL: https://github.com/llvm/llvm-project/commit/55aeb23fe0084d930ecd7335092d712bd71694c7
DIFF: https://github.com/llvm/llvm-project/commit/55aeb23fe0084d930ecd7335092d712bd71694c7.diff

LOG: [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

Added: 
    clang/test/CodeGen/WebAssembly/builtins-table.c
    clang/test/Sema/builtins-wasm.c
    clang/test/Sema/wasm-refs-and-table-ped.c
    clang/test/Sema/wasm-refs-and-tables.c
    clang/test/SemaCXX/wasm-refs-and-tables.cpp
    llvm/include/llvm/CodeGen/WasmAddressSpaces.h

Modified: 
    clang/docs/LanguageExtensions.rst
    clang/include/clang/AST/Type.h
    clang/include/clang/Basic/BuiltinsWebAssembly.def
    clang/include/clang/Basic/DiagnosticSemaKinds.td
    clang/include/clang/Sema/Sema.h
    clang/lib/AST/Type.cpp
    clang/lib/Basic/Targets/WebAssembly.cpp
    clang/lib/CodeGen/CGBuiltin.cpp
    clang/lib/CodeGen/CGExpr.cpp
    clang/lib/Sema/SemaCast.cpp
    clang/lib/Sema/SemaChecking.cpp
    clang/lib/Sema/SemaDecl.cpp
    clang/lib/Sema/SemaDeclCXX.cpp
    clang/lib/Sema/SemaExceptionSpec.cpp
    clang/lib/Sema/SemaExpr.cpp
    clang/lib/Sema/SemaExprCXX.cpp
    clang/lib/Sema/SemaOverload.cpp
    clang/lib/Sema/SemaStmt.cpp
    clang/lib/Sema/SemaType.cpp
    llvm/lib/Target/WebAssembly/Utils/WebAssemblyTypeUtilities.cpp
    llvm/lib/Target/WebAssembly/Utils/WebAssemblyTypeUtilities.h
    llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp
    llvm/lib/Target/WebAssembly/WebAssemblyLowerRefTypesIntPtrConv.cpp

Removed: 
    clang/test/Sema/wasm-refs.c
    clang/test/SemaCXX/wasm-refs.cpp


################################################################################
diff  --git a/clang/docs/LanguageExtensions.rst b/clang/docs/LanguageExtensions.rst
index b36f2f8e3e45f..f37db774a0f7b 100644
--- a/clang/docs/LanguageExtensions.rst
+++ b/clang/docs/LanguageExtensions.rst
@@ -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
 =================
 

diff  --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h
index 8261d1c3a9685..eea60d7c9831e 100644
--- a/clang/include/clang/AST/Type.h
+++ b/clang/include/clang/AST/Type.h
@@ -908,6 +908,15 @@ class QualType {
   /// 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 @@ class alignas(8) Type : public ExtQualsTypeCommonBase {
   /// 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.

diff  --git a/clang/include/clang/Basic/BuiltinsWebAssembly.def b/clang/include/clang/Basic/BuiltinsWebAssembly.def
index de897386e296f..7e950914ad946 100644
--- a/clang/include/clang/Basic/BuiltinsWebAssembly.def
+++ b/clang/include/clang/Basic/BuiltinsWebAssembly.def
@@ -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

diff  --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 43fa732217a48..5f8853715a6e8 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -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.

diff  --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 18da1ffb9402e..7d54452e72a3c 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -13653,6 +13653,12 @@ class Sema final {
   // 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 {

diff  --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp
index 167091593a592..f16c024c044b7 100644
--- a/clang/lib/AST/Type.cpp
+++ b/clang/lib/AST/Type.cpp
@@ -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 =

diff  --git a/clang/lib/Basic/Targets/WebAssembly.cpp b/clang/lib/Basic/Targets/WebAssembly.cpp
index 3a5e0350192eb..e9b77e03c0311 100644
--- a/clang/lib/Basic/Targets/WebAssembly.cpp
+++ b/clang/lib/Basic/Targets/WebAssembly.cpp
@@ -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;

diff  --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index d958198c5aef3..852d6f056a2c2 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -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;
   }

diff  --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp
index 35d4a1a62682a..2afdc6abb104a 100644
--- a/clang/lib/CodeGen/CGExpr.cpp
+++ b/clang/lib/CodeGen/CGExpr.cpp
@@ -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"

diff  --git a/clang/lib/Sema/SemaCast.cpp b/clang/lib/Sema/SemaCast.cpp
index 54f811678a70d..42373ddd69e83 100644
--- a/clang/lib/Sema/SemaCast.cpp
+++ b/clang/lib/Sema/SemaCast.cpp
@@ -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);

diff  --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index 3d72c9f359ea9..d5c046377632f 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -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

diff  --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 4d4be343b9826..b1436ba50892a 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -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

diff  --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index 566b0e67f4098..1b4beec2e93b7 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -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;

diff  --git a/clang/lib/Sema/SemaExceptionSpec.cpp b/clang/lib/Sema/SemaExceptionSpec.cpp
index a5a57c38bb487..9b7ff5ff82519 100644
--- a/clang/lib/Sema/SemaExceptionSpec.cpp
+++ b/clang/lib/Sema/SemaExceptionSpec.cpp
@@ -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) {

diff  --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 7db8ee6d31f7d..b41dd0785dc80 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -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;
   }

diff  --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp
index ba11f883add77..f2ff924bc7dea 100644
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/lib/Sema/SemaExprCXX.cpp
@@ -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 
diff erent types, and
   //   either has (cv) class type [...] an attempt is made to convert each of

diff  --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp
index 14361d85cf182..68a7f81fffa56 100644
--- a/clang/lib/Sema/SemaOverload.cpp
+++ b/clang/lib/Sema/SemaOverload.cpp
@@ -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()});

diff  --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp
index a87b0d9501930..a97692af85721 100644
--- a/clang/lib/Sema/SemaStmt.cpp
+++ b/clang/lib/Sema/SemaStmt.cpp
@@ -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() &&

diff  --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp
index 2b2d17b469057..32118a370b9b3 100644
--- a/clang/lib/Sema/SemaType.cpp
+++ b/clang/lib/Sema/SemaType.cpp
@@ -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:

diff  --git a/clang/test/CodeGen/WebAssembly/builtins-table.c b/clang/test/CodeGen/WebAssembly/builtins-table.c
new file mode 100644
index 0000000000000..74bb2442fe552
--- /dev/null
+++ b/clang/test/CodeGen/WebAssembly/builtins-table.c
@@ -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);
+}

diff  --git a/clang/test/Sema/builtins-wasm.c b/clang/test/Sema/builtins-wasm.c
new file mode 100644
index 0000000000000..beb430616233a
--- /dev/null
+++ b/clang/test/Sema/builtins-wasm.c
@@ -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);
+}

diff  --git a/clang/test/Sema/wasm-refs-and-table-ped.c b/clang/test/Sema/wasm-refs-and-table-ped.c
new file mode 100644
index 0000000000000..19feca8cec5d3
--- /dev/null
+++ b/clang/test/Sema/wasm-refs-and-table-ped.c
@@ -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

diff  --git a/clang/test/Sema/wasm-refs-and-tables.c b/clang/test/Sema/wasm-refs-and-tables.c
new file mode 100644
index 0000000000000..1fee2f83b8e4c
--- /dev/null
+++ b/clang/test/Sema/wasm-refs-and-tables.c
@@ -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 at +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 at +2 {{cannot use WebAssembly table as a function parameter}}
+  // cpp-error at +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}}
+}

diff  --git a/clang/test/Sema/wasm-refs.c b/clang/test/Sema/wasm-refs.c
deleted file mode 100644
index 10aefc9aa04ee..0000000000000
--- a/clang/test/Sema/wasm-refs.c
+++ /dev/null
@@ -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 at +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;
-}

diff  --git a/clang/test/SemaCXX/wasm-refs-and-tables.cpp b/clang/test/SemaCXX/wasm-refs-and-tables.cpp
new file mode 100644
index 0000000000000..3d6ead07fd530
--- /dev/null
+++ b/clang/test/SemaCXX/wasm-refs-and-tables.cpp
@@ -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}}
+}

diff  --git a/clang/test/SemaCXX/wasm-refs.cpp b/clang/test/SemaCXX/wasm-refs.cpp
deleted file mode 100644
index 7f211c56b9a54..0000000000000
--- a/clang/test/SemaCXX/wasm-refs.cpp
+++ /dev/null
@@ -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'}}
-}

diff  --git a/llvm/include/llvm/CodeGen/WasmAddressSpaces.h b/llvm/include/llvm/CodeGen/WasmAddressSpaces.h
new file mode 100644
index 0000000000000..c47b05f88a0a6
--- /dev/null
+++ b/llvm/include/llvm/CodeGen/WasmAddressSpaces.h
@@ -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

diff  --git a/llvm/lib/Target/WebAssembly/Utils/WebAssemblyTypeUtilities.cpp b/llvm/lib/Target/WebAssembly/Utils/WebAssemblyTypeUtilities.cpp
index 81544e20a16ad..bf5db09e05def 100644
--- a/llvm/lib/Target/WebAssembly/Utils/WebAssemblyTypeUtilities.cpp
+++ b/llvm/lib/Target/WebAssembly/Utils/WebAssemblyTypeUtilities.cpp
@@ -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");

diff  --git a/llvm/lib/Target/WebAssembly/Utils/WebAssemblyTypeUtilities.h b/llvm/lib/Target/WebAssembly/Utils/WebAssemblyTypeUtilities.h
index ebf3849cd7bed..9f58d7582fabf 100644
--- a/llvm/lib/Target/WebAssembly/Utils/WebAssemblyTypeUtilities.h
+++ b/llvm/lib/Target/WebAssembly/Utils/WebAssemblyTypeUtilities.h
@@ -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,
-};
-
-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);
+/// 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 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;
+
+/// 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 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

diff  --git a/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp
index 4b0775d0d8425..d719ab1899ba1 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp
@@ -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

diff  --git a/llvm/lib/Target/WebAssembly/WebAssemblyLowerRefTypesIntPtrConv.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyLowerRefTypesIntPtrConv.cpp
index 6fd87f10150dd..94b6e41e87d06 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyLowerRefTypesIntPtrConv.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyLowerRefTypesIntPtrConv.cpp
@@ -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());


        


More information about the cfe-commits mailing list