[clang] 6d0c7bc - [WebAssembly] Implementation of table.get/set for reftypes in LLVM IR

Paulo Matos via cfe-commits cfe-commits at lists.llvm.org
Wed Oct 20 01:38:26 PDT 2021


Author: Paulo Matos
Date: 2021-10-20T10:31:31+02:00
New Revision: 6d0c7bc17de85807c286f78571235b6658999faf

URL: https://github.com/llvm/llvm-project/commit/6d0c7bc17de85807c286f78571235b6658999faf
DIFF: https://github.com/llvm/llvm-project/commit/6d0c7bc17de85807c286f78571235b6658999faf.diff

LOG: [WebAssembly] Implementation of table.get/set for reftypes in LLVM IR

This change implements new DAG nodes TABLE_GET/TABLE_SET, and lowering
methods for load and stores of reference types from IR arrays. These
global LLVM IR arrays represent tables at the Wasm level.

Differential Revision: https://reviews.llvm.org/D111154

Added: 
    llvm/test/CodeGen/WebAssembly/externref-tableget.ll
    llvm/test/CodeGen/WebAssembly/externref-tableset.ll
    llvm/test/CodeGen/WebAssembly/funcref-table_call.ll
    llvm/test/CodeGen/WebAssembly/funcref-tableget.ll
    llvm/test/CodeGen/WebAssembly/funcref-tableset.ll

Modified: 
    clang/lib/Basic/Targets/WebAssembly.h
    clang/test/CodeGen/target-data.c
    lld/test/wasm/lto/Inputs/archive.ll
    lld/test/wasm/lto/Inputs/cache.ll
    lld/test/wasm/lto/Inputs/libcall-archive.ll
    lld/test/wasm/lto/Inputs/libcall-truncsfhf2.ll
    lld/test/wasm/lto/Inputs/save-temps.ll
    lld/test/wasm/lto/Inputs/thinlto.ll
    lld/test/wasm/lto/Inputs/used.ll
    lld/test/wasm/lto/archive.ll
    lld/test/wasm/lto/atomics.ll
    lld/test/wasm/lto/cache.ll
    lld/test/wasm/lto/comdat.ll
    lld/test/wasm/lto/diagnostics.ll
    lld/test/wasm/lto/export.ll
    lld/test/wasm/lto/import-attributes.ll
    lld/test/wasm/lto/internalize-basic.ll
    lld/test/wasm/lto/libcall-archive.ll
    lld/test/wasm/lto/libcall-truncsfhf2.ll
    lld/test/wasm/lto/lto-start.ll
    lld/test/wasm/lto/new-pass-manager.ll
    lld/test/wasm/lto/opt-level.ll
    lld/test/wasm/lto/parallel.ll
    lld/test/wasm/lto/relocatable-undefined.ll
    lld/test/wasm/lto/relocatable.ll
    lld/test/wasm/lto/save-temps.ll
    lld/test/wasm/lto/thinlto.ll
    lld/test/wasm/lto/tls.ll
    lld/test/wasm/lto/undef.ll
    lld/test/wasm/lto/used.ll
    lld/test/wasm/lto/verify-invalid.ll
    lld/test/wasm/lto/weak-undefined.ll
    lld/test/wasm/lto/weak.ll
    llvm/lib/Target/WebAssembly/WebAssemblyISD.def
    llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp
    llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.h
    llvm/lib/Target/WebAssembly/WebAssemblyInstrTable.td
    llvm/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp
    llvm/lib/Target/WebAssembly/WebAssemblyRegStackify.cpp
    llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp

Removed: 
    


################################################################################
diff  --git a/clang/lib/Basic/Targets/WebAssembly.h b/clang/lib/Basic/Targets/WebAssembly.h
index 27b6576e4b7a..16534d3ef99b 100644
--- a/clang/lib/Basic/Targets/WebAssembly.h
+++ b/clang/lib/Basic/Targets/WebAssembly.h
@@ -151,9 +151,11 @@ class LLVM_LIBRARY_VISIBILITY WebAssembly32TargetInfo
                                    const TargetOptions &Opts)
       : WebAssemblyTargetInfo(T, Opts) {
     if (T.isOSEmscripten())
-      resetDataLayout("e-m:e-p:32:32-i64:64-f128:64-n32:64-S128-ni:1:10:20");
+      resetDataLayout("e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-f128:64-n32:64-"
+                      "S128-ni:1:10:20");
     else
-      resetDataLayout("e-m:e-p:32:32-i64:64-n32:64-S128-ni:1:10:20");
+      resetDataLayout(
+          "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-n32:64-S128-ni:1:10:20");
   }
 
 protected:
@@ -173,9 +175,11 @@ class LLVM_LIBRARY_VISIBILITY WebAssembly64TargetInfo
     PtrDiffType = SignedLong;
     IntPtrType = SignedLong;
     if (T.isOSEmscripten())
-      resetDataLayout("e-m:e-p:64:64-i64:64-f128:64-n32:64-S128-ni:1:10:20");
+      resetDataLayout("e-m:e-p:64:64-p10:8:8-p20:8:8-i64:64-f128:64-n32:64-"
+                      "S128-ni:1:10:20");
     else
-      resetDataLayout("e-m:e-p:64:64-i64:64-n32:64-S128-ni:1:10:20");
+      resetDataLayout(
+          "e-m:e-p:64:64-p10:8:8-p20:8:8-i64:64-n32:64-S128-ni:1:10:20");
   }
 
 protected:

diff  --git a/clang/test/CodeGen/target-data.c b/clang/test/CodeGen/target-data.c
index 0749493d788f..d702f845112b 100644
--- a/clang/test/CodeGen/target-data.c
+++ b/clang/test/CodeGen/target-data.c
@@ -108,11 +108,11 @@
 
 // RUN: %clang_cc1 -triple wasm32-unknown-unknown -o - -emit-llvm %s | \
 // RUN: FileCheck %s -check-prefix=WEBASSEMBLY32
-// WEBASSEMBLY32: target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128-ni:1:10:20"
+// WEBASSEMBLY32: target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-n32:64-S128-ni:1:10:20"
 
 // RUN: %clang_cc1 -triple wasm64-unknown-unknown -o - -emit-llvm %s | \
 // RUN: FileCheck %s -check-prefix=WEBASSEMBLY64
-// WEBASSEMBLY64: target datalayout = "e-m:e-p:64:64-i64:64-n32:64-S128-ni:1:10:20"
+// WEBASSEMBLY64: target datalayout = "e-m:e-p:64:64-p10:8:8-p20:8:8-i64:64-n32:64-S128-ni:1:10:20"
 
 // RUN: %clang_cc1 -triple lanai-unknown-unknown -o - -emit-llvm %s | \
 // RUN: FileCheck %s -check-prefix=LANAI

diff  --git a/lld/test/wasm/lto/Inputs/archive.ll b/lld/test/wasm/lto/Inputs/archive.ll
index 75984793246c..5f4e3c00e0f0 100644
--- a/lld/test/wasm/lto/Inputs/archive.ll
+++ b/lld/test/wasm/lto/Inputs/archive.ll
@@ -1,4 +1,4 @@
-target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
+target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-n32:64-S128"
 target triple = "wasm32-unknown-unknown"
 
 define void @f() {

diff  --git a/lld/test/wasm/lto/Inputs/cache.ll b/lld/test/wasm/lto/Inputs/cache.ll
index a66f36aef9cb..914654ef5f82 100644
--- a/lld/test/wasm/lto/Inputs/cache.ll
+++ b/lld/test/wasm/lto/Inputs/cache.ll
@@ -1,4 +1,4 @@
-target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
+target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-n32:64-S128"
 target triple = "wasm32-unknown-unknown"
 
 define i32 @_start() {

diff  --git a/lld/test/wasm/lto/Inputs/libcall-archive.ll b/lld/test/wasm/lto/Inputs/libcall-archive.ll
index 126075521b83..def1452bdf35 100644
--- a/lld/test/wasm/lto/Inputs/libcall-archive.ll
+++ b/lld/test/wasm/lto/Inputs/libcall-archive.ll
@@ -1,4 +1,4 @@
-target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
+target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-n32:64-S128"
 target triple = "wasm32-unknown-unknown"
 
 define void @memcpy() {

diff  --git a/lld/test/wasm/lto/Inputs/libcall-truncsfhf2.ll b/lld/test/wasm/lto/Inputs/libcall-truncsfhf2.ll
index 839890ee1d9a..b8609af28795 100644
--- a/lld/test/wasm/lto/Inputs/libcall-truncsfhf2.ll
+++ b/lld/test/wasm/lto/Inputs/libcall-truncsfhf2.ll
@@ -1,4 +1,4 @@
-target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
+target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-n32:64-S128"
 target triple = "wasm32-unknown-unknown"
 
 define half @__truncsfhf2(float) {

diff  --git a/lld/test/wasm/lto/Inputs/save-temps.ll b/lld/test/wasm/lto/Inputs/save-temps.ll
index 6f4de417c380..b25b8d92441f 100644
--- a/lld/test/wasm/lto/Inputs/save-temps.ll
+++ b/lld/test/wasm/lto/Inputs/save-temps.ll
@@ -1,4 +1,4 @@
-target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
+target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-n32:64-S128"
 target triple = "wasm32-unknown-unknown"
 
 define void @bar() {

diff  --git a/lld/test/wasm/lto/Inputs/thinlto.ll b/lld/test/wasm/lto/Inputs/thinlto.ll
index 39e573b1c21e..2c4fe7177f56 100644
--- a/lld/test/wasm/lto/Inputs/thinlto.ll
+++ b/lld/test/wasm/lto/Inputs/thinlto.ll
@@ -1,4 +1,4 @@
-target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
+target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-n32:64-S128"
 target triple = "wasm32-unknown-unknown"
 
 define void @g() {

diff  --git a/lld/test/wasm/lto/Inputs/used.ll b/lld/test/wasm/lto/Inputs/used.ll
index d0250d518abc..93dd4acc5039 100644
--- a/lld/test/wasm/lto/Inputs/used.ll
+++ b/lld/test/wasm/lto/Inputs/used.ll
@@ -1,4 +1,4 @@
-target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
+target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-n32:64-S128"
 target triple = "wasm32-unknown-unknown"
 
 @foo = hidden global i32 1

diff  --git a/lld/test/wasm/lto/archive.ll b/lld/test/wasm/lto/archive.ll
index 89863bfea703..b5c9e459eb55 100644
--- a/lld/test/wasm/lto/archive.ll
+++ b/lld/test/wasm/lto/archive.ll
@@ -5,7 +5,7 @@
 ; RUN: wasm-ld --export-dynamic %t2.o %t.a -o %t3
 ; RUN: obj2yaml %t3 | FileCheck %s
 
-target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
+target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-n32:64-S128"
 target triple = "wasm32-unknown-unknown"
 
 define void @_start() {

diff  --git a/lld/test/wasm/lto/atomics.ll b/lld/test/wasm/lto/atomics.ll
index 00340f12b2b5..f231b3225fe8 100644
--- a/lld/test/wasm/lto/atomics.ll
+++ b/lld/test/wasm/lto/atomics.ll
@@ -4,7 +4,7 @@
 ; Atomic operations will not fail to compile if atomics are not
 ; enabled because LLVM atomics will be lowered to regular ops.
 
-target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
+target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-n32:64-S128"
 target triple = "wasm32-unknown-unknown-wasm"
 
 @foo = hidden global i32 1

diff  --git a/lld/test/wasm/lto/cache.ll b/lld/test/wasm/lto/cache.ll
index 02f475c50953..570b38948f66 100644
--- a/lld/test/wasm/lto/cache.ll
+++ b/lld/test/wasm/lto/cache.ll
@@ -36,7 +36,7 @@
 ; RUN: wasm-ld --thinlto-cache-dir=%t.cache --thinlto-cache-policy prune_after=0s:cache_size=0%:cache_size_files=1:prune_interval=0s -o %t.wasm %t2.o %t.o
 ; RUN: ls %t.cache | count 3
 
-target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
+target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-n32:64-S128"
 target triple = "wasm32-unknown-unknown-wasm"
 
 define void @globalfunc() #0 {

diff  --git a/lld/test/wasm/lto/comdat.ll b/lld/test/wasm/lto/comdat.ll
index 54c9f0f3b47b..d9f414a4dac0 100644
--- a/lld/test/wasm/lto/comdat.ll
+++ b/lld/test/wasm/lto/comdat.ll
@@ -6,7 +6,7 @@
 ; RUN: wasm-ld %t.bc %t.o -o %t.wasm
 ; RUN: wasm-ld %t.o %t.bc -o %t.wasm
 
-target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
+target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-n32:64-S128"
 target triple = "wasm32-unknown-unknown"
 
 $foo = comdat any

diff  --git a/lld/test/wasm/lto/diagnostics.ll b/lld/test/wasm/lto/diagnostics.ll
index 77f68fe93abb..2d170ee3ba86 100644
--- a/lld/test/wasm/lto/diagnostics.ll
+++ b/lld/test/wasm/lto/diagnostics.ll
@@ -4,7 +4,7 @@
 ; RUN: llvm-as %s -o %t.o
 ; RUN: not wasm-ld --lto-O0 %t.o -o %t2 2>&1 | FileCheck %s
 
-target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
+target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-n32:64-S128"
 target triple = "wasm32-unknown-unknown"
 
 define void @_start() {

diff  --git a/lld/test/wasm/lto/export.ll b/lld/test/wasm/lto/export.ll
index b6dba4de5833..ff5af8ccbbd3 100644
--- a/lld/test/wasm/lto/export.ll
+++ b/lld/test/wasm/lto/export.ll
@@ -3,7 +3,7 @@
 ; RUN: wasm-ld --export=hidden_function -o %t.wasm %t.bc
 ; RUN: obj2yaml %t.wasm | FileCheck %s
 
-target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
+target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-n32:64-S128"
 target triple = "wasm32-unknown-unknown"
 
 define hidden i32 @hidden_function() local_unnamed_addr {

diff  --git a/lld/test/wasm/lto/import-attributes.ll b/lld/test/wasm/lto/import-attributes.ll
index afbb8e15c001..72198fa8adb4 100644
--- a/lld/test/wasm/lto/import-attributes.ll
+++ b/lld/test/wasm/lto/import-attributes.ll
@@ -3,7 +3,7 @@
 ; RUN: obj2yaml %t.wasm | FileCheck %s
 
 target triple = "wasm32-unknown-unknown-wasm"
-target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
+target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-n32:64-S128"
 
 define void @_start() {
   call void @foo();

diff  --git a/lld/test/wasm/lto/internalize-basic.ll b/lld/test/wasm/lto/internalize-basic.ll
index 313a05ecbae4..95a1fa3e055c 100644
--- a/lld/test/wasm/lto/internalize-basic.ll
+++ b/lld/test/wasm/lto/internalize-basic.ll
@@ -2,7 +2,7 @@
 ; RUN: wasm-ld %t.o -o %t2 -save-temps
 ; RUN: llvm-dis < %t2.0.2.internalize.bc | FileCheck %s
 
-target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
+target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-n32:64-S128"
 target triple = "wasm32-unknown-unknown-wasm"
 
 define void @_start() {

diff  --git a/lld/test/wasm/lto/libcall-archive.ll b/lld/test/wasm/lto/libcall-archive.ll
index b939d51744e4..8623e878f97d 100644
--- a/lld/test/wasm/lto/libcall-archive.ll
+++ b/lld/test/wasm/lto/libcall-archive.ll
@@ -5,7 +5,7 @@
 ; RUN: wasm-ld -o %t %t.o %t.a
 ; RUN: obj2yaml %t | FileCheck %s
 
-target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
+target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-n32:64-S128"
 target triple = "wasm32-unknown-unknown"
 
 define void @_start(i8* %a, i8* %b) {

diff  --git a/lld/test/wasm/lto/libcall-truncsfhf2.ll b/lld/test/wasm/lto/libcall-truncsfhf2.ll
index a60af3b52f79..a3a461c83de7 100644
--- a/lld/test/wasm/lto/libcall-truncsfhf2.ll
+++ b/lld/test/wasm/lto/libcall-truncsfhf2.ll
@@ -4,7 +4,7 @@
 ; RUN: llvm-ar rcs %t.a %t.truncsfhf2.o
 ; RUN: not wasm-ld --export-all %t.o %t.a -o %t.wasm 2>&1 | FileCheck %s
 
-target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
+target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-n32:64-S128"
 target triple = "wasm32-unknown-unknown"
 
 @g_float = global float 0.0

diff  --git a/lld/test/wasm/lto/lto-start.ll b/lld/test/wasm/lto/lto-start.ll
index d21079577322..ebbfd8d53e4e 100644
--- a/lld/test/wasm/lto/lto-start.ll
+++ b/lld/test/wasm/lto/lto-start.ll
@@ -8,7 +8,7 @@
 ; CHECK-NEXT:       - Index:           0
 ; CHECK-NEXT:         Name:            _start
 
-target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
+target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-n32:64-S128"
 target triple = "wasm32-unknown-unknown-wasm"
 
 define void @_start() {

diff  --git a/lld/test/wasm/lto/new-pass-manager.ll b/lld/test/wasm/lto/new-pass-manager.ll
index 14440b5cfa6e..807c0aa34bea 100644
--- a/lld/test/wasm/lto/new-pass-manager.ll
+++ b/lld/test/wasm/lto/new-pass-manager.ll
@@ -5,7 +5,7 @@
 ; CHECK: Running pass: GlobalOptPass
 ; LPM-NOT: Running pass: GlobalOptPass
 
-target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
+target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-n32:64-S128"
 target triple = "wasm32-unknown-unknown"
 
 define void @_start() local_unnamed_addr {

diff  --git a/lld/test/wasm/lto/opt-level.ll b/lld/test/wasm/lto/opt-level.ll
index d2d552728b16..6556f2ef02b5 100644
--- a/lld/test/wasm/lto/opt-level.ll
+++ b/lld/test/wasm/lto/opt-level.ll
@@ -15,7 +15,7 @@
 ; RUN:   FileCheck --check-prefix=INVALIDNEGATIVE %s
 ; INVALIDNEGATIVE: invalid optimization level for LTO: 4294967295
 
-target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
+target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-n32:64-S128"
 target triple = "wasm32-unknown-unknown-wasm"
 
 ; CHECK-O0: Name: foo

diff  --git a/lld/test/wasm/lto/parallel.ll b/lld/test/wasm/lto/parallel.ll
index 261cf2ef7dae..e4ea35f60d89 100644
--- a/lld/test/wasm/lto/parallel.ll
+++ b/lld/test/wasm/lto/parallel.ll
@@ -4,7 +4,7 @@
 ; RUN: llvm-nm %t.lto.o | FileCheck --check-prefix=CHECK0 %s
 ; RUN: llvm-nm %t1.lto.o | FileCheck --check-prefix=CHECK1 %s
 
-target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
+target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-n32:64-S128"
 target triple = "wasm32-unknown-unknown-wasm"
 
 ; CHECK0-NOT: bar

diff  --git a/lld/test/wasm/lto/relocatable-undefined.ll b/lld/test/wasm/lto/relocatable-undefined.ll
index b9780ee0309b..8aa175b61cfd 100644
--- a/lld/test/wasm/lto/relocatable-undefined.ll
+++ b/lld/test/wasm/lto/relocatable-undefined.ll
@@ -2,7 +2,7 @@
 ; RUN: wasm-ld -r -o %t.wasm %t.o
 ; RUN: obj2yaml %t.wasm | FileCheck %s
 
-target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
+target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-n32:64-S128"
 target triple = "wasm32-unknown-unknown"
 
 @missing_data = external global i32

diff  --git a/lld/test/wasm/lto/relocatable.ll b/lld/test/wasm/lto/relocatable.ll
index aeca2fc227fe..a127db3663b3 100644
--- a/lld/test/wasm/lto/relocatable.ll
+++ b/lld/test/wasm/lto/relocatable.ll
@@ -12,7 +12,7 @@
 ; CHECK-NEXT:   }
 ; CHECK-NEXT: ]
 
-target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
+target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-n32:64-S128"
 target triple = "wasm32-unknown-unknown"
 
 define void @foo() {

diff  --git a/lld/test/wasm/lto/save-temps.ll b/lld/test/wasm/lto/save-temps.ll
index 2734d86815c7..bcc420178803 100644
--- a/lld/test/wasm/lto/save-temps.ll
+++ b/lld/test/wasm/lto/save-temps.ll
@@ -8,7 +8,7 @@
 ; RUN: llvm-nm a.out.lto.o | FileCheck %s
 ; RUN: llvm-dis a.out.0.0.preopt.bc
 
-target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
+target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-n32:64-S128"
 target triple = "wasm32-unknown-unknown"
 
 define void @foo() {

diff  --git a/lld/test/wasm/lto/thinlto.ll b/lld/test/wasm/lto/thinlto.ll
index 6c6fada01a3e..169b827fe308 100644
--- a/lld/test/wasm/lto/thinlto.ll
+++ b/lld/test/wasm/lto/thinlto.ll
@@ -52,7 +52,7 @@
 ; NM1: T f
 ; NM2: T g
 
-target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
+target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-n32:64-S128"
 target triple = "wasm32-unknown-unknown"
 
 declare void @g(...)

diff  --git a/lld/test/wasm/lto/tls.ll b/lld/test/wasm/lto/tls.ll
index 8d6185e72740..06c11067217b 100644
--- a/lld/test/wasm/lto/tls.ll
+++ b/lld/test/wasm/lto/tls.ll
@@ -7,7 +7,7 @@
 ; RUN: wasm-ld --export=tls_int --export=get_tls %t1.o -o %t
 ; RUN: obj2yaml %t | FileCheck %s
 
-target datalayout = "e-m:e-p:32:32-i64:64-f128:64-n32:64-S128-ni:1:10:20"
+target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-f128:64-n32:64-S128-ni:1:10:20"
 target triple = "wasm32-unknown-emscripten"
 
 @tls_int = dso_local thread_local global i32 99

diff  --git a/lld/test/wasm/lto/undef.ll b/lld/test/wasm/lto/undef.ll
index a5477cb3c3bd..6b6c046e9587 100644
--- a/lld/test/wasm/lto/undef.ll
+++ b/lld/test/wasm/lto/undef.ll
@@ -2,7 +2,7 @@
 ; RUN: wasm-ld %t.o -o %t.wasm --allow-undefined
 ; RUN: obj2yaml %t.wasm | FileCheck %s
 
-target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
+target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-n32:64-S128"
 target triple = "wasm32-unknown-unknown"
 
 declare i32 @bar()

diff  --git a/lld/test/wasm/lto/used.ll b/lld/test/wasm/lto/used.ll
index 15e6b41a73cf..324edbf01f52 100644
--- a/lld/test/wasm/lto/used.ll
+++ b/lld/test/wasm/lto/used.ll
@@ -5,7 +5,7 @@
 
 ; Verify that symbols references from regular objects are preserved by LTO
 
-target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
+target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-n32:64-S128"
 target triple = "wasm32-unknown-unknown"
 
 declare void @bar()

diff  --git a/lld/test/wasm/lto/verify-invalid.ll b/lld/test/wasm/lto/verify-invalid.ll
index 4cc8c6128640..fac3025998e4 100644
--- a/lld/test/wasm/lto/verify-invalid.ll
+++ b/lld/test/wasm/lto/verify-invalid.ll
@@ -8,7 +8,7 @@
 ; RUN: wasm-ld %t.o -o %t2 --no-lto-legacy-pass-manager --lto-debug-pass-manager \
 ; RUN:   -disable-verify 2>&1 | FileCheck -check-prefix=DISABLE-NPM %s
 
-target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
+target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-n32:64-S128"
 target triple = "wasm32-unknown-unknown"
 
 define void @_start() {

diff  --git a/lld/test/wasm/lto/weak-undefined.ll b/lld/test/wasm/lto/weak-undefined.ll
index 080e23cbbc15..36e422896f35 100644
--- a/lld/test/wasm/lto/weak-undefined.ll
+++ b/lld/test/wasm/lto/weak-undefined.ll
@@ -6,7 +6,7 @@
 ; We had a bug where stub function generation was failing because functions
 ; that are in bitcode (pre-LTO) don't have signatures assigned.
 
-target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
+target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-n32:64-S128"
 target triple = "wasm32-unknown-unknown"
 
 declare extern_weak i32 @foo()

diff  --git a/lld/test/wasm/lto/weak.ll b/lld/test/wasm/lto/weak.ll
index 571b79f9c0d8..6b83400b8e8a 100644
--- a/lld/test/wasm/lto/weak.ll
+++ b/lld/test/wasm/lto/weak.ll
@@ -2,7 +2,7 @@
 ; RUN: wasm-ld %t.o %t.o -o %t.wasm -r
 ; RUN: llvm-readobj --symbols %t.wasm | FileCheck %s
 
-target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
+target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-n32:64-S128"
 target triple = "wasm32-unknown-unknown-wasm"
 
 define weak void @f() {

diff  --git a/llvm/lib/Target/WebAssembly/WebAssemblyISD.def b/llvm/lib/Target/WebAssembly/WebAssemblyISD.def
index e5d4a1113b72..1fa0ea3867c7 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyISD.def
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyISD.def
@@ -48,4 +48,5 @@ HANDLE_NODETYPE(MEMORY_FILL)
 HANDLE_MEM_NODETYPE(LOAD_SPLAT)
 HANDLE_MEM_NODETYPE(GLOBAL_GET)
 HANDLE_MEM_NODETYPE(GLOBAL_SET)
+HANDLE_MEM_NODETYPE(TABLE_GET)
 HANDLE_MEM_NODETYPE(TABLE_SET)

diff  --git a/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp
index 8cf96f64d9d5..eb9116322fe0 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp
@@ -88,7 +88,9 @@ WebAssemblyTargetLowering::WebAssemblyTargetLowering(
     }
   }
   if (Subtarget->hasReferenceTypes()) {
-    for (auto T : {MVT::externref, MVT::funcref}) {
+    // We need custom load and store lowering for both externref, funcref and
+    // Other. The MVT::Other here represents tables of reference types.
+    for (auto T : {MVT::externref, MVT::funcref, MVT::Other}) {
       setOperationAction(ISD::LOAD, T, Custom);
       setOperationAction(ISD::STORE, T, Custom);
     }
@@ -1422,6 +1424,80 @@ static Optional<unsigned> IsWebAssemblyLocal(SDValue Op, SelectionDAG &DAG) {
   return WebAssemblyFrameLowering::getLocalForStackObject(MF, FI->getIndex());
 }
 
+static bool IsWebAssemblyTable(SDValue Op) {
+  const GlobalAddressSDNode *GA = dyn_cast<GlobalAddressSDNode>(Op);
+  if (GA && WebAssembly::isWasmVarAddressSpace(GA->getAddressSpace())) {
+    const GlobalValue *Value = GA->getGlobal();
+    const Type *Ty = Value->getValueType();
+
+    if (Ty->isArrayTy() && WebAssembly::isRefType(Ty->getArrayElementType()))
+      return true;
+  }
+  return false;
+}
+
+// This function will accept as Op any access to a table, so Op can
+// be the actual table or an offset into the table.
+static bool IsWebAssemblyTableWithOffset(SDValue Op) {
+  if (Op->getOpcode() == ISD::ADD && Op->getNumOperands() == 2)
+    return (Op->getOperand(1).getSimpleValueType() == MVT::i32 &&
+            IsWebAssemblyTableWithOffset(Op->getOperand(0))) ||
+           (Op->getOperand(0).getSimpleValueType() == MVT::i32 &&
+            IsWebAssemblyTableWithOffset(Op->getOperand(1)));
+
+  return IsWebAssemblyTable(Op);
+}
+
+// Helper for table pattern matching used in LowerStore and LowerLoad
+bool WebAssemblyTargetLowering::MatchTableForLowering(SelectionDAG &DAG,
+                                                      const SDLoc &DL,
+                                                      const SDValue &Base,
+                                                      GlobalAddressSDNode *&GA,
+                                                      SDValue &Idx) const {
+  // We expect the following graph for a load of the form:
+  // table[<var> + <constant offset>]
+  //
+  // Case 1:
+  // externref = load t1
+  // t1: i32 = add t2, i32:<constant offset>
+  // t2: i32 = add tX, table
+  //
+  // This is in some cases simplified to just:
+  // Case 2:
+  // externref = load t1
+  // t1: i32 = add t2, i32:tX
+  //
+  // So, unfortunately we need to check for both cases and if we are in the
+  // first case extract the table GlobalAddressNode and build a new node tY
+  // that's tY: i32 = add i32:<constant offset>, i32:tX
+  //
+  if (IsWebAssemblyTable(Base)) {
+    GA = cast<GlobalAddressSDNode>(Base);
+    Idx = DAG.getConstant(0, DL, MVT::i32);
+  } else {
+    GA = dyn_cast<GlobalAddressSDNode>(Base->getOperand(0));
+    if (GA) {
+      // We are in Case 2 above.
+      Idx = Base->getOperand(1);
+      if (!Idx || GA->getNumValues() != 1 || Idx->getNumValues() != 1)
+        return false;
+    } else {
+      // This might be Case 1 above (or an error)
+      SDValue V = Base->getOperand(0);
+      GA = dyn_cast<GlobalAddressSDNode>(V->getOperand(1));
+
+      if (V->getOpcode() != ISD::ADD || V->getNumOperands() != 2 || !GA)
+        return false;
+
+      SDValue IdxV = DAG.getNode(ISD::ADD, DL, MVT::i32, Base->getOperand(1),
+                                 V->getOperand(0));
+      Idx = IdxV;
+    }
+  }
+
+  return true;
+}
+
 SDValue WebAssemblyTargetLowering::LowerStore(SDValue Op,
                                               SelectionDAG &DAG) const {
   SDLoc DL(Op);
@@ -1430,6 +1506,26 @@ SDValue WebAssemblyTargetLowering::LowerStore(SDValue Op,
   const SDValue &Base = SN->getBasePtr();
   const SDValue &Offset = SN->getOffset();
 
+  if (IsWebAssemblyTableWithOffset(Base)) {
+    if (!Offset->isUndef())
+      report_fatal_error(
+          "unexpected offset when loading from webassembly table", false);
+
+    SDValue Idx;
+    GlobalAddressSDNode *GA;
+
+    if (!MatchTableForLowering(DAG, DL, Base, GA, Idx))
+      report_fatal_error("failed pattern matching for lowering table store",
+                         false);
+
+    SDVTList Tys = DAG.getVTList(MVT::Other);
+    SDValue TableSetOps[] = {SN->getChain(), SDValue(GA, 0), Idx, Value};
+    SDValue TableSet =
+        DAG.getMemIntrinsicNode(WebAssemblyISD::TABLE_SET, DL, Tys, TableSetOps,
+                                SN->getMemoryVT(), SN->getMemOperand());
+    return TableSet;
+  }
+
   if (IsWebAssemblyGlobal(Base)) {
     if (!Offset->isUndef())
       report_fatal_error("unexpected offset when storing to webassembly global",
@@ -1462,6 +1558,26 @@ SDValue WebAssemblyTargetLowering::LowerLoad(SDValue Op,
   const SDValue &Base = LN->getBasePtr();
   const SDValue &Offset = LN->getOffset();
 
+  if (IsWebAssemblyTableWithOffset(Base)) {
+    if (!Offset->isUndef())
+      report_fatal_error(
+          "unexpected offset when loading from webassembly table", false);
+
+    GlobalAddressSDNode *GA;
+    SDValue Idx;
+
+    if (!MatchTableForLowering(DAG, DL, Base, GA, Idx))
+      report_fatal_error("failed pattern matching for lowering table load",
+                         false);
+
+    SDVTList Tys = DAG.getVTList(LN->getValueType(0), MVT::Other);
+    SDValue TableGetOps[] = {LN->getChain(), SDValue(GA, 0), Idx};
+    SDValue TableGet =
+        DAG.getMemIntrinsicNode(WebAssemblyISD::TABLE_GET, DL, Tys, TableGetOps,
+                                LN->getMemoryVT(), LN->getMemOperand());
+    return TableGet;
+  }
+
   if (IsWebAssemblyGlobal(Base)) {
     if (!Offset->isUndef())
       report_fatal_error(

diff  --git a/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.h b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.h
index 5c9e1b4d47ed..f7b460f61dbb 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.h
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.h
@@ -136,6 +136,11 @@ class WebAssemblyTargetLowering final : public TargetLowering {
   SDValue LowerLoad(SDValue Op, SelectionDAG &DAG) const;
   SDValue LowerStore(SDValue Op, SelectionDAG &DAG) const;
 
+  // Helper for LoadLoad and LowerStore
+  bool MatchTableForLowering(SelectionDAG &DAG, const SDLoc &DL,
+                             const SDValue &Base, GlobalAddressSDNode *&GA,
+                             SDValue &Idx) const;
+
   // Custom DAG combine hooks
   SDValue
   PerformDAGCombine(SDNode *N,

diff  --git a/llvm/lib/Target/WebAssembly/WebAssemblyInstrTable.td b/llvm/lib/Target/WebAssembly/WebAssemblyInstrTable.td
index 2348bb165daf..e44c2073eaeb 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyInstrTable.td
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyInstrTable.td
@@ -11,9 +11,18 @@
 /// Instructions that handle tables
 //===----------------------------------------------------------------------===//
 
-multiclass TABLE<WebAssemblyRegClass rt> {
+def WebAssemblyTableSet_t : SDTypeProfile<0, 3, [SDTCisPtrTy<1>]>;
+def WebAssemblyTableSet : SDNode<"WebAssemblyISD::TABLE_SET", WebAssemblyTableSet_t,
+                                 [SDNPHasChain, SDNPMayStore, SDNPMemOperand]>;
+
+def WebAssemblyTableGet_t : SDTypeProfile<1, 2, [SDTCisPtrTy<1>]>;
+def WebAssemblyTableGet : SDNode<"WebAssemblyISD::TABLE_GET", WebAssemblyTableGet_t,
+                                 [SDNPHasChain, SDNPMayLoad, SDNPMemOperand]>;
+
+
+multiclass TABLE<WebAssemblyRegClass rc> {
   let mayLoad = 1 in
-  defm TABLE_GET_#rt : I<(outs rt:$res), (ins table32_op:$table, I32:$i),
+  defm TABLE_GET_#rc : I<(outs rc:$res), (ins table32_op:$table, I32:$i),
                          (outs), (ins table32_op:$table),
                          [],
                          "table.get\t$res, $table, $i",
@@ -21,41 +30,43 @@ multiclass TABLE<WebAssemblyRegClass rt> {
                          0x25>;
 
   let mayStore = 1 in
-  defm TABLE_SET_#rt : I<(outs), (ins table32_op:$table, I32:$i, rt:$val),
+  defm TABLE_SET_#rc : I<(outs), (ins table32_op:$table, I32:$i, rc:$val),
                          (outs), (ins table32_op:$table),
                          [],
                          "table.set\t$table, $i, $val",
                          "table.set\t$table",
                          0x26>;
 
-  defm TABLE_GROW_#rt : I<(outs I32:$sz), (ins table32_op:$table, rt:$val, I32:$n),
+  defm TABLE_GROW_#rc : I<(outs I32:$sz), (ins table32_op:$table, rc:$val, I32:$n),
                           (outs), (ins table32_op:$table),
                           [],
                           "table.grow\t$sz, $table, $val, $n",
                           "table.grow\t$table",
                           0xfc0f>;
 
-  defm TABLE_FILL_#rt : I<(outs), (ins table32_op:$table, I32:$i, rt:$val, I32:$n),
+  defm TABLE_FILL_#rc : I<(outs), (ins table32_op:$table, I32:$i, rc:$val, I32:$n),
                           (outs), (ins table32_op:$table),
                           [],
                           "table.fill\t$table, $i, $val, $n",
                           "table.fill\t$table",
                           0xfc11>;
 
+  foreach vt = rc.RegTypes in {
+    def : Pat<(vt (WebAssemblyTableGet (WebAssemblyWrapper tglobaladdr:$table), i32:$idx)),
+              (!cast<NI>("TABLE_GET_" # rc) tglobaladdr:$table, i32:$idx)>;
+    def : Pat<(WebAssemblyTableSet
+               (WebAssemblyWrapper tglobaladdr:$table),
+               i32:$idx,
+               vt:$src),
+              (!cast<NI>("TABLE_SET_" # rc) tglobaladdr:$table, i32:$idx, vt:$src)>;
+  }
 }
 
 defm "" : TABLE<FUNCREF>, Requires<[HasReferenceTypes]>;
 defm "" : TABLE<EXTERNREF>, Requires<[HasReferenceTypes]>;
 
-def wasm_table_set_t : SDTypeProfile<0, 3, []>;
-def wasm_table_set : SDNode<"WebAssemblyISD::TABLE_SET", wasm_table_set_t,
-                            [SDNPHasChain, SDNPMayStore, SDNPMemOperand]>;
-
-def : Pat<(wasm_table_set i32:$table, i32:$idx, funcref:$r),
-          (TABLE_SET_FUNCREF i32:$table, i32:$idx, funcref:$r)>,
-          Requires<[HasReferenceTypes]>;
-def : Pat<(wasm_table_set i32:$table, i32:$idx, externref:$r),
-          (TABLE_SET_EXTERNREF i32:$table, i32:$idx, externref:$r)>,
+def : Pat<(WebAssemblyTableSet mcsym:$table, i32:$idx, funcref:$r),
+          (TABLE_SET_FUNCREF mcsym:$table, i32:$idx, funcref:$r)>,
           Requires<[HasReferenceTypes]>;
 
 defm TABLE_SIZE : I<(outs I32:$sz), (ins table32_op:$table),

diff  --git a/llvm/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp
index 105c24ad8e46..0b953a90aeab 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp
@@ -17,6 +17,7 @@
 #include "Utils/WebAssemblyTypeUtilities.h"
 #include "Utils/WebAssemblyUtilities.h"
 #include "WebAssemblyAsmPrinter.h"
+#include "WebAssemblyISelLowering.h"
 #include "WebAssemblyMachineFunctionInfo.h"
 #include "llvm/CodeGen/AsmPrinter.h"
 #include "llvm/CodeGen/MachineFunction.h"
@@ -28,6 +29,7 @@
 #include "llvm/MC/MCSymbolWasm.h"
 #include "llvm/Support/ErrorHandling.h"
 #include "llvm/Support/raw_ostream.h"
+
 using namespace llvm;
 
 // This disables the removal of registers when lowering into MC, as required
@@ -56,15 +58,36 @@ WebAssemblyMCInstLower::GetGlobalAddressSymbol(const MachineOperand &MO) const {
       const MachineFunction &MF = *MO.getParent()->getParent()->getParent();
       const TargetMachine &TM = MF.getTarget();
       const Function &CurrentFunc = MF.getFunction();
+      Type *GlobalVT = Global->getValueType();
       SmallVector<MVT, 1> VTs;
-      computeLegalValueVTs(CurrentFunc, TM, Global->getValueType(), VTs);
-      if (VTs.size() != 1)
+      computeLegalValueVTs(CurrentFunc, TM, GlobalVT, VTs);
+
+      // Tables are represented as Arrays in LLVM IR therefore
+      // they reach this point as aggregate Array types with an element type
+      // that is a reference type.
+      wasm::ValType Type;
+      if (GlobalVT->isArrayTy() &&
+          WebAssembly::isRefType(GlobalVT->getArrayElementType())) {
+        MVT VT;
+        switch (GlobalVT->getArrayElementType()->getPointerAddressSpace()) {
+        case WebAssembly::WasmAddressSpace::WASM_ADDRESS_SPACE_FUNCREF:
+          VT = MVT::funcref;
+          break;
+        case WebAssembly::WasmAddressSpace::WASM_ADDRESS_SPACE_EXTERNREF:
+          VT = MVT::externref;
+          break;
+        default:
+          report_fatal_error("unhandled address space type");
+        }
+        Type = WebAssembly::toValType(VT);
+      } else if (VTs.size() == 1) {
+        Type = WebAssembly::toValType(VTs[0]);
+      } else
         report_fatal_error("Aggregate globals not yet implemented");
 
-      bool Mutable = true;
-      wasm::ValType Type = WebAssembly::toValType(VTs[0]);
       WasmSym->setType(wasm::WASM_SYMBOL_TYPE_GLOBAL);
-      WasmSym->setGlobalType(wasm::WasmGlobalType{uint8_t(Type), Mutable});
+      WasmSym->setGlobalType(
+          wasm::WasmGlobalType{uint8_t(Type), /*Mutable=*/true});
     }
     return WasmSym;
   }

diff  --git a/llvm/lib/Target/WebAssembly/WebAssemblyRegStackify.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyRegStackify.cpp
index d6adc2fd155c..42419259802e 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyRegStackify.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyRegStackify.cpp
@@ -497,6 +497,10 @@ static unsigned getTeeOpcode(const TargetRegisterClass *RC) {
     return WebAssembly::TEE_F64;
   if (RC == &WebAssembly::V128RegClass)
     return WebAssembly::TEE_V128;
+  if (RC == &WebAssembly::EXTERNREFRegClass)
+    return WebAssembly::TEE_EXTERNREF;
+  if (RC == &WebAssembly::FUNCREFRegClass)
+    return WebAssembly::TEE_FUNCREF;
   llvm_unreachable("Unexpected register class");
 }
 

diff  --git a/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp
index c78993b1d8f8..80abccd74782 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp
@@ -133,12 +133,14 @@ WebAssemblyTargetMachine::WebAssemblyTargetMachine(
     : LLVMTargetMachine(
           T,
           TT.isArch64Bit()
-              ? (TT.isOSEmscripten()
-                     ? "e-m:e-p:64:64-i64:64-f128:64-n32:64-S128-ni:1:10:20"
-                     : "e-m:e-p:64:64-i64:64-n32:64-S128-ni:1:10:20")
-              : (TT.isOSEmscripten()
-                     ? "e-m:e-p:32:32-i64:64-f128:64-n32:64-S128-ni:1:10:20"
-                     : "e-m:e-p:32:32-i64:64-n32:64-S128-ni:1:10:20"),
+              ? (TT.isOSEmscripten() ? "e-m:e-p:64:64-p10:8:8-p20:8:8-i64:64-"
+                                       "f128:64-n32:64-S128-ni:1:10:20"
+                                     : "e-m:e-p:64:64-p10:8:8-p20:8:8-i64:64-"
+                                       "n32:64-S128-ni:1:10:20")
+              : (TT.isOSEmscripten() ? "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-"
+                                       "f128:64-n32:64-S128-ni:1:10:20"
+                                     : "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-"
+                                       "n32:64-S128-ni:1:10:20"),
           TT, CPU, FS, Options, getEffectiveRelocModel(RM, TT),
           getEffectiveCodeModel(CM, CodeModel::Large), OL),
       TLOF(new WebAssemblyTargetObjectFile()) {

diff  --git a/llvm/test/CodeGen/WebAssembly/externref-tableget.ll b/llvm/test/CodeGen/WebAssembly/externref-tableget.ll
new file mode 100644
index 000000000000..e54e9e806094
--- /dev/null
+++ b/llvm/test/CodeGen/WebAssembly/externref-tableget.ll
@@ -0,0 +1,76 @@
+; RUN: llc < %s --mtriple=wasm32-unknown-unknown -asm-verbose=false -mattr=+reference-types | FileCheck %s
+
+%extern = type opaque
+%externref = type %extern addrspace(10)* ;; addrspace 10 is nonintegral
+
+ at externref_table = local_unnamed_addr addrspace(1) global [0 x %externref] undef
+
+define %externref @get_externref_from_table(i32 %i) {
+; CHECK-LABEL: get_externref_from_table:
+; CHECK-NEXT: .functype       get_externref_from_table (i32) -> (externref)
+; CHECK-NEXT: local.get 0
+; CHECK-NEXT: table.get externref_table
+; CHECK-NEXT: end_function
+  %p = getelementptr [0 x %externref], [0 x %externref] addrspace (1)* @externref_table, i32 0, i32 %i
+  %ref = load %externref, %externref addrspace(1)* %p
+  ret %externref %ref
+}
+
+define %externref @get_externref_from_table_const() {
+; CHECK-LABEL: get_externref_from_table_const:
+; CHECK-NEXT:  .functype      get_externref_from_table_const () -> (externref)
+; CHECK-NEXT:  i32.const      0
+; CHECK-NEXT:  table.get      externref_table
+; CHECK-NEXT:  end_function
+  %p = getelementptr [0 x %externref], [0 x %externref] addrspace (1)* @externref_table, i32 0, i32 0
+  %ref = load %externref, %externref addrspace(1)* %p
+  ret %externref %ref
+}
+
+define %externref @get_externref_from_table_with_offset(i32 %i) {
+; CHECK-LABEL: get_externref_from_table_with_offset:
+; CHECK-NEXT:  .functype       get_externref_from_table_with_offset (i32) -> (externref)
+; CHECK-NEXT:  local.get       0
+; CHECK-NEXT:  i32.const       2
+; CHECK-NEXT:  i32.add
+; CHECK-NEXT:  table.get       externref_table
+; CHECK-NEXT:  end_function
+  %off = add nsw i32 %i, 2
+  %p = getelementptr [0 x %externref], [0 x %externref] addrspace (1)* @externref_table, i32 0, i32 %off
+  %ref = load %externref, %externref addrspace(1)* %p
+  ret %externref %ref
+}
+
+
+define %externref @get_externref_from_table_with_var_offset(i32 %i, i32 %j) {
+; CHECK-LABEL: get_externref_from_table_with_var_offset:
+; CHECK-NEXT:  .functype       get_externref_from_table_with_var_offset (i32, i32) -> (externref)
+; CHECK-NEXT:  local.get       0
+; CHECK-NEXT:  local.get       1
+; CHECK-NEXT:  i32.add
+; CHECK-NEXT:  table.get       externref_table
+; CHECK-NEXT:  end_function
+  %off = add nsw i32 %i, %j
+  %p = getelementptr [0 x %externref], [0 x %externref] addrspace (1)* @externref_table, i32 0, i32 %off
+  %ref = load %externref, %externref addrspace(1)* %p
+  ret %externref %ref
+}
+
+declare i32 @get_offset()
+
+define %externref @get_externref_from_table_with_var_offset2(i32 %i) {
+; CHECK-LABEL: get_externref_from_table_with_var_offset2:
+; CHECK-NEXT:  .functype       get_externref_from_table_with_var_offset2 (i32) -> (externref)
+; CHECK-NEXT:  local.get       0
+; CHECK-NEXT:  call    get_offset
+; CHECK-NEXT:  i32.add
+; CHECK-NEXT:  table.get       externref_table
+; CHECK-NEXT:  end_function
+  %j = call i32 @get_offset()
+  %off = add nsw i32 %i, %j
+  %p = getelementptr [0 x %externref], [0 x %externref] addrspace (1)* @externref_table, i32 0, i32 %off
+  %ref = load %externref, %externref addrspace(1)* %p
+  ret %externref %ref
+}
+
+; CHECK: .globl externref_table

diff  --git a/llvm/test/CodeGen/WebAssembly/externref-tableset.ll b/llvm/test/CodeGen/WebAssembly/externref-tableset.ll
new file mode 100644
index 000000000000..206612372b75
--- /dev/null
+++ b/llvm/test/CodeGen/WebAssembly/externref-tableset.ll
@@ -0,0 +1,82 @@
+; RUN: llc --mtriple=wasm32-unknown-unknown -asm-verbose=false -mattr=+reference-types < %s | FileCheck %s
+
+%extern = type opaque
+%externref = type %extern addrspace(10)* ;; addrspace 10 is nonintegral
+
+ at externref_table = local_unnamed_addr addrspace(1) global [0 x %externref] undef
+
+define void @set_externref_table(%externref %g, i32 %i) {
+; CHECK-LABEL: set_externref_table:
+; CHECK-NEXT: .functype       set_externref_table (externref, i32) -> ()
+; CHECK-NEXT: local.get      1
+; CHECK-NEXT: local.get      0
+; CHECK-NEXT: table.set     externref_table
+; CHECK-NEXT: end_function
+
+;; this generates a table.set of @externref_table
+  %p = getelementptr [0 x %externref], [0 x %externref] addrspace (1)* @externref_table, i32 0, i32 %i
+  store %externref %g, %externref addrspace(1)* %p
+  ret void
+}
+
+define void @set_externref_table_const(%externref %g) {
+; CHECK-LABEL: set_externref_table_const:
+; CHECK-NEXT:  .functype      set_externref_table_const (externref) -> ()
+; CHECK-NEXT:  i32.const      0
+; CHECK-NEXT:  local.get      0
+; CHECK-NEXT:  table.set      externref_table
+; CHECK-NEXT:  end_function
+  %p = getelementptr [0 x %externref], [0 x %externref] addrspace (1)* @externref_table, i32 0, i32 0
+  store %externref %g, %externref addrspace(1)* %p
+  ret void
+}
+
+define void @set_externref_table_with_offset(%externref %g, i32 %i) {
+; CHECK-LABEL: set_externref_table_with_offset:
+; CHECK-NEXT:  .functype       set_externref_table_with_offset (externref, i32) -> ()
+; CHECK-NEXT:  local.get       1
+; CHECK-NEXT:  i32.const       2
+; CHECK-NEXT:  i32.add
+; CHECK-NEXT:  local.get       0
+; CHECK-NEXT:  table.set       externref_table
+; CHECK-NEXT:  end_function
+  %off = add nsw i32 %i, 2
+  %p = getelementptr [0 x %externref], [0 x %externref] addrspace (1)* @externref_table, i32 0, i32 %off
+  store %externref %g, %externref addrspace(1)* %p
+  ret void
+}
+
+define void @set_externref_table_with_var_offset(%externref %g, i32 %i, i32 %j) {
+; CHECK-LABEL: set_externref_table_with_var_offset:
+; CHECK-NEXT:  .functype       set_externref_table_with_var_offset (externref, i32, i32) -> ()
+; CHECK-NEXT:  local.get       1
+; CHECK-NEXT:  local.get       2
+; CHECK-NEXT:  i32.add
+; CHECK-NEXT:  local.get       0
+; CHECK-NEXT:  table.set       externref_table
+; CHECK-NEXT:  end_function
+  %off = add nsw i32 %i, %j
+  %p = getelementptr [0 x %externref], [0 x %externref] addrspace (1)* @externref_table, i32 0, i32 %off
+  store %externref %g, %externref addrspace(1)* %p
+  ret void
+}
+
+declare i32 @set_offset()
+
+define void @set_externref_table_with_var_offset2(%externref %g, i32 %i) {
+; CHECK-LABEL: set_externref_table_with_var_offset2:
+; CHECK-NEXT:  .functype       set_externref_table_with_var_offset2 (externref, i32) -> ()
+; CHECK-NEXT:  local.get       1
+; CHECK-NEXT:  call    set_offset
+; CHECK-NEXT:  i32.add
+; CHECK-NEXT:  local.get       0
+; CHECK-NEXT:  table.set       externref_table
+; CHECK-NEXT:  end_function
+  %j = call i32 @set_offset()
+  %off = add nsw i32 %i, %j
+  %p = getelementptr [0 x %externref], [0 x %externref] addrspace (1)* @externref_table, i32 0, i32 %off
+  store %externref %g, %externref addrspace(1)* %p
+  ret void
+}
+
+; CHECK: .globl externref_table

diff  --git a/llvm/test/CodeGen/WebAssembly/funcref-table_call.ll b/llvm/test/CodeGen/WebAssembly/funcref-table_call.ll
new file mode 100644
index 000000000000..e19749c24f40
--- /dev/null
+++ b/llvm/test/CodeGen/WebAssembly/funcref-table_call.ll
@@ -0,0 +1,32 @@
+; RUN: llc < %s --mtriple=wasm32-unknown-unknown -asm-verbose=false -mattr=+reference-types | FileCheck %s
+
+%func = type void ()
+%funcref = type %func addrspace(20)* ;; addrspace 20 is nonintegral
+
+ at funcref_table = local_unnamed_addr addrspace(1) global [0 x %funcref] undef
+
+define void @call_funcref_from_table(i32 %i) {
+  %p = getelementptr [0 x %funcref], [0 x %funcref] addrspace (1)* @funcref_table, i32 0, i32 %i
+  %ref = load %funcref, %funcref addrspace(1)* %p
+  call addrspace(20) void %ref()
+  ret void
+}
+
+; CHECK: .tabletype __funcref_call_table, funcref, 1
+
+; CHECK-LABEL: call_funcref_from_table:
+; CHECK-NEXT: .functype       call_funcref_from_table (i32) -> ()
+; CHECK-NEXT: i32.const       0
+; CHECK-NEXT: local.get       0
+; CHECK-NEXT: table.get       funcref_table
+; CHECK-NEXT: table.set       __funcref_call_table
+; CHECK-NEXT: i32.const       0
+; CHECK-NEXT: call_indirect    __funcref_call_table, () -> ()
+; CHECK-NEXT: i32.const       0
+; CHECK-NEXT: ref.null        func
+; CHECK-NEXT: table.set       __funcref_call_table
+; CHECK-NEXT: end_function
+
+
+; CHECK:     .globl funcref_table
+; CHECK-NEXT .globaltype     funcref_table, funcref

diff  --git a/llvm/test/CodeGen/WebAssembly/funcref-tableget.ll b/llvm/test/CodeGen/WebAssembly/funcref-tableget.ll
new file mode 100644
index 000000000000..f40c9e0c8972
--- /dev/null
+++ b/llvm/test/CodeGen/WebAssembly/funcref-tableget.ll
@@ -0,0 +1,76 @@
+; RUN: llc < %s --mtriple=wasm32-unknown-unknown -asm-verbose=false -mattr=+reference-types | FileCheck %s
+
+%func = type void ()
+%funcref = type %func addrspace(20)* ;; addrspace 20 is nonintegral
+
+ at funcref_table = local_unnamed_addr addrspace(1) global [0 x %funcref] undef
+
+define %funcref @get_funcref_from_table(i32 %i) {
+; CHECK-LABEL: get_funcref_from_table:
+; CHECK-NEXT: .functype       get_funcref_from_table (i32) -> (funcref)
+; CHECK-NEXT: local.get 0
+; CHECK-NEXT: table.get funcref_table
+; CHECK-NEXT: end_function
+  %p = getelementptr [0 x %funcref], [0 x %funcref] addrspace (1)* @funcref_table, i32 0, i32 %i
+  %ref = load %funcref, %funcref addrspace(1)* %p
+  ret %funcref %ref
+}
+
+define %funcref @get_funcref_from_table_const() {
+; CHECK-LABEL: get_funcref_from_table_const:
+; CHECK-NEXT:  .functype      get_funcref_from_table_const () -> (funcref)
+; CHECK-NEXT:  i32.const      0
+; CHECK-NEXT:  table.get      funcref_table
+; CHECK-NEXT:  end_function
+  %p = getelementptr [0 x %funcref], [0 x %funcref] addrspace (1)* @funcref_table, i32 0, i32 0
+  %ref = load %funcref, %funcref addrspace(1)* %p
+  ret %funcref %ref
+}
+
+define %funcref @get_funcref_from_table_with_offset(i32 %i) {
+; CHECK-LABEL: get_funcref_from_table_with_offset:
+; CHECK-NEXT:  .functype       get_funcref_from_table_with_offset (i32) -> (funcref)
+; CHECK-NEXT:  local.get       0
+; CHECK-NEXT:  i32.const       2
+; CHECK-NEXT:  i32.add
+; CHECK-NEXT:  table.get       funcref_table
+; CHECK-NEXT:  end_function
+  %off = add nsw i32 %i, 2
+  %p = getelementptr [0 x %funcref], [0 x %funcref] addrspace (1)* @funcref_table, i32 0, i32 %off
+  %ref = load %funcref, %funcref addrspace(1)* %p
+  ret %funcref %ref
+}
+
+
+define %funcref @get_funcref_from_table_with_var_offset(i32 %i, i32 %j) {
+; CHECK-LABEL: get_funcref_from_table_with_var_offset:
+; CHECK-NEXT:  .functype       get_funcref_from_table_with_var_offset (i32, i32) -> (funcref)
+; CHECK-NEXT:  local.get       0
+; CHECK-NEXT:  local.get       1
+; CHECK-NEXT:  i32.add
+; CHECK-NEXT:  table.get       funcref_table
+; CHECK-NEXT:  end_function
+  %off = add nsw i32 %i, %j
+  %p = getelementptr [0 x %funcref], [0 x %funcref] addrspace (1)* @funcref_table, i32 0, i32 %off
+  %ref = load %funcref, %funcref addrspace(1)* %p
+  ret %funcref %ref
+}
+
+declare i32 @get_offset()
+
+define %funcref @get_funcref_from_table_with_var_offset2(i32 %i) {
+; CHECK-LABEL: get_funcref_from_table_with_var_offset2:
+; CHECK-NEXT:  .functype       get_funcref_from_table_with_var_offset2 (i32) -> (funcref)
+; CHECK-NEXT:  local.get       0
+; CHECK-NEXT:  call    get_offset
+; CHECK-NEXT:  i32.add
+; CHECK-NEXT:  table.get       funcref_table
+; CHECK-NEXT:  end_function
+  %j = call i32 @get_offset()
+  %off = add nsw i32 %i, %j
+  %p = getelementptr [0 x %funcref], [0 x %funcref] addrspace (1)* @funcref_table, i32 0, i32 %off
+  %ref = load %funcref, %funcref addrspace(1)* %p
+  ret %funcref %ref
+}
+
+; CHECK: .globl funcref_table

diff  --git a/llvm/test/CodeGen/WebAssembly/funcref-tableset.ll b/llvm/test/CodeGen/WebAssembly/funcref-tableset.ll
new file mode 100644
index 000000000000..7d016f536c06
--- /dev/null
+++ b/llvm/test/CodeGen/WebAssembly/funcref-tableset.ll
@@ -0,0 +1,82 @@
+; RUN: llc --mtriple=wasm32-unknown-unknown -asm-verbose=false -mattr=+reference-types < %s | FileCheck %s
+
+%func = type void ()
+%funcref = type %func addrspace(20)* ;; addrspace 20 is nonintegral
+
+ at funcref_table = local_unnamed_addr addrspace(1) global [0 x %funcref] undef
+
+define void @set_funcref_table(%funcref %g, i32 %i) {
+; CHECK-LABEL: set_funcref_table:
+; CHECK-NEXT: .functype       set_funcref_table (funcref, i32) -> ()
+; CHECK-NEXT: local.get      1
+; CHECK-NEXT: local.get      0
+; CHECK-NEXT: table.set     funcref_table
+; CHECK-NEXT: end_function
+
+;; this generates a table.set of @funcref_table
+  %p = getelementptr [0 x %funcref], [0 x %funcref] addrspace (1)* @funcref_table, i32 0, i32 %i
+  store %funcref %g, %funcref addrspace(1)* %p
+  ret void
+}
+
+define void @set_funcref_table_const(%funcref %g) {
+; CHECK-LABEL: set_funcref_table_const:
+; CHECK-NEXT:  .functype      set_funcref_table_const (funcref) -> ()
+; CHECK-NEXT:  i32.const      0
+; CHECK-NEXT:  local.get      0
+; CHECK-NEXT:  table.set      funcref_table
+; CHECK-NEXT:  end_function
+  %p = getelementptr [0 x %funcref], [0 x %funcref] addrspace (1)* @funcref_table, i32 0, i32 0
+  store %funcref %g, %funcref addrspace(1)* %p
+  ret void
+}
+
+define void @set_funcref_table_with_offset(%funcref %g, i32 %i) {
+; CHECK-LABEL: set_funcref_table_with_offset:
+; CHECK-NEXT:  .functype       set_funcref_table_with_offset (funcref, i32) -> ()
+; CHECK-NEXT:  local.get       1
+; CHECK-NEXT:  i32.const       2
+; CHECK-NEXT:  i32.add
+; CHECK-NEXT:  local.get       0
+; CHECK-NEXT:  table.set       funcref_table
+; CHECK-NEXT:  end_function
+  %off = add nsw i32 %i, 2
+  %p = getelementptr [0 x %funcref], [0 x %funcref] addrspace (1)* @funcref_table, i32 0, i32 %off
+  store %funcref %g, %funcref addrspace(1)* %p
+  ret void
+}
+
+define void @set_funcref_table_with_var_offset(%funcref %g, i32 %i, i32 %j) {
+; CHECK-LABEL: set_funcref_table_with_var_offset:
+; CHECK-NEXT:  .functype       set_funcref_table_with_var_offset (funcref, i32, i32) -> ()
+; CHECK-NEXT:  local.get       1
+; CHECK-NEXT:  local.get       2
+; CHECK-NEXT:  i32.add
+; CHECK-NEXT:  local.get       0
+; CHECK-NEXT:  table.set       funcref_table
+; CHECK-NEXT:  end_function
+  %off = add nsw i32 %i, %j
+  %p = getelementptr [0 x %funcref], [0 x %funcref] addrspace (1)* @funcref_table, i32 0, i32 %off
+  store %funcref %g, %funcref addrspace(1)* %p
+  ret void
+}
+
+declare i32 @set_offset()
+
+define void @set_funcref_table_with_var_offset2(%funcref %g, i32 %i) {
+; CHECK-LABEL: set_funcref_table_with_var_offset2:
+; CHECK-NEXT:  .functype       set_funcref_table_with_var_offset2 (funcref, i32) -> ()
+; CHECK-NEXT:  local.get       1
+; CHECK-NEXT:  call    set_offset
+; CHECK-NEXT:  i32.add
+; CHECK-NEXT:  local.get       0
+; CHECK-NEXT:  table.set       funcref_table
+; CHECK-NEXT:  end_function
+  %j = call i32 @set_offset()
+  %off = add nsw i32 %i, %j
+  %p = getelementptr [0 x %funcref], [0 x %funcref] addrspace (1)* @funcref_table, i32 0, i32 %off
+  store %funcref %g, %funcref addrspace(1)* %p
+  ret void
+}
+
+; CHECK: .globl funcref_table


        


More information about the cfe-commits mailing list