[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