Skip to content

Commit 2fd634a

Browse files
committed
[WebAssembly] Implement table instruction intrinsics
This change implements intrinsics for table.grow, table.fill, table.size, and table.copy. Differential Revision: https://reviews.llvm.org/D113420
1 parent ed43aab commit 2fd634a

File tree

13 files changed

+180
-27
lines changed

13 files changed

+180
-27
lines changed

llvm/include/llvm/IR/IntrinsicsWebAssembly.td

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@
1111
///
1212
//===----------------------------------------------------------------------===//
1313

14+
// Type definition for a table in an intrinsic
15+
def llvm_table_ty : LLVMQualPointerType<llvm_i8_ty, 1>;
16+
1417
let TargetPrefix = "wasm" in { // All intrinsics start with "llvm.wasm.".
1518

1619
// Query the current memory size, and increase the current memory size.
@@ -29,6 +32,29 @@ def int_wasm_memory_grow : Intrinsic<[llvm_anyint_ty],
2932
def int_wasm_ref_null_extern : Intrinsic<[llvm_externref_ty], [], [IntrNoMem]>;
3033
def int_wasm_ref_null_func : Intrinsic<[llvm_funcref_ty], [], [IntrNoMem]>;
3134

35+
//===----------------------------------------------------------------------===//
36+
// Table intrinsics
37+
//===----------------------------------------------------------------------===//
38+
// Query the current table size, and increase the current table size.
39+
def int_wasm_table_size : Intrinsic<[llvm_i32_ty],
40+
[llvm_table_ty],
41+
[IntrReadMem]>;
42+
def int_wasm_table_copy : Intrinsic<[],
43+
[llvm_table_ty, llvm_table_ty, llvm_i32_ty, llvm_i32_ty, llvm_i32_ty],
44+
[]>;
45+
def int_wasm_table_grow_externref : Intrinsic<[llvm_i32_ty],
46+
[llvm_table_ty, llvm_externref_ty, llvm_i32_ty],
47+
[]>;
48+
def int_wasm_table_grow_funcref : Intrinsic<[llvm_i32_ty],
49+
[llvm_table_ty, llvm_funcref_ty, llvm_i32_ty],
50+
[]>;
51+
def int_wasm_table_fill_externref : Intrinsic<[],
52+
[llvm_table_ty, llvm_i32_ty, llvm_externref_ty, llvm_i32_ty],
53+
[]>;
54+
def int_wasm_table_fill_funcref : Intrinsic<[],
55+
[llvm_table_ty, llvm_i32_ty, llvm_funcref_ty, llvm_i32_ty],
56+
[]>;
57+
3258
//===----------------------------------------------------------------------===//
3359
// Trapping float-to-int conversions
3460
//===----------------------------------------------------------------------===//

llvm/lib/CodeGen/ValueTypes.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -201,9 +201,11 @@ Type *EVT::getTypeForEVT(LLVMContext &Context) const {
201201
case MVT::x86amx: return Type::getX86_AMXTy(Context);
202202
case MVT::i64x8: return IntegerType::get(Context, 512);
203203
case MVT::externref:
204+
// pointer to opaque struct in addrspace(10)
204205
return PointerType::get(StructType::create(Context), 10);
205206
case MVT::funcref:
206-
return PointerType::get(StructType::create(Context), 20);
207+
// pointer to i8 addrspace(20)
208+
return PointerType::get(Type::getInt8Ty(Context), 20);
207209
case MVT::v1i1:
208210
return FixedVectorType::get(Type::getInt1Ty(Context), 1);
209211
case MVT::v2i1:

llvm/lib/Target/WebAssembly/WebAssemblyInstrTable.td

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ def WebAssemblyTableGet : SDNode<"WebAssemblyISD::TABLE_GET", WebAssemblyTableGe
2020
[SDNPHasChain, SDNPMayLoad, SDNPMemOperand]>;
2121

2222

23-
multiclass TABLE<WebAssemblyRegClass rc> {
23+
multiclass TABLE<WebAssemblyRegClass rc, string suffix> {
2424
let mayLoad = 1 in
2525
defm TABLE_GET_#rc : I<(outs rc:$res), (ins table32_op:$table, I32:$i),
2626
(outs), (ins table32_op:$table),
@@ -39,14 +39,14 @@ multiclass TABLE<WebAssemblyRegClass rc> {
3939

4040
defm TABLE_GROW_#rc : I<(outs I32:$sz), (ins table32_op:$table, rc:$val, I32:$n),
4141
(outs), (ins table32_op:$table),
42-
[],
42+
[(set I32:$sz, (!cast<Intrinsic>("int_wasm_table_grow_" # suffix) (WebAssemblyWrapper tglobaladdr:$table), rc:$val, I32:$n))],
4343
"table.grow\t$sz, $table, $val, $n",
4444
"table.grow\t$table",
4545
0xfc0f>;
4646

4747
defm TABLE_FILL_#rc : I<(outs), (ins table32_op:$table, I32:$i, rc:$val, I32:$n),
4848
(outs), (ins table32_op:$table),
49-
[],
49+
[(!cast<Intrinsic>("int_wasm_table_fill_" # suffix) (WebAssemblyWrapper tglobaladdr:$table), I32:$i, rc:$val, I32:$n)],
5050
"table.fill\t$table, $i, $val, $n",
5151
"table.fill\t$table",
5252
0xfc11>;
@@ -62,16 +62,16 @@ multiclass TABLE<WebAssemblyRegClass rc> {
6262
}
6363
}
6464

65-
defm "" : TABLE<FUNCREF>, Requires<[HasReferenceTypes]>;
66-
defm "" : TABLE<EXTERNREF>, Requires<[HasReferenceTypes]>;
65+
defm "" : TABLE<FUNCREF, "funcref">, Requires<[HasReferenceTypes]>;
66+
defm "" : TABLE<EXTERNREF, "externref">, Requires<[HasReferenceTypes]>;
6767

6868
def : Pat<(WebAssemblyTableSet mcsym:$table, i32:$idx, funcref:$r),
6969
(TABLE_SET_FUNCREF mcsym:$table, i32:$idx, funcref:$r)>,
7070
Requires<[HasReferenceTypes]>;
7171

7272
defm TABLE_SIZE : I<(outs I32:$sz), (ins table32_op:$table),
7373
(outs), (ins table32_op:$table),
74-
[],
74+
[(set I32:$sz, (int_wasm_table_size (WebAssemblyWrapper tglobaladdr:$table)))],
7575
"table.size\t$sz, $table",
7676
"table.size\t$table",
7777
0xfc10>,
@@ -80,7 +80,9 @@ defm TABLE_SIZE : I<(outs I32:$sz), (ins table32_op:$table),
8080

8181
defm TABLE_COPY : I<(outs), (ins table32_op:$table1, table32_op:$table2, I32:$d, I32:$s, I32:$n),
8282
(outs), (ins table32_op:$table1, table32_op:$table2),
83-
[],
83+
[(int_wasm_table_copy (WebAssemblyWrapper tglobaladdr:$table1),
84+
(WebAssemblyWrapper tglobaladdr:$table2),
85+
I32:$d, I32:$s, I32:$n)],
8486
"table.copy\t$table1, $table2, $d, $s, $n",
8587
"table.copy\t$table1, $table2",
8688
0xfc0e>,
Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,13 @@
11
; RUN: llc < %s --mtriple=wasm32-unknown-unknown -asm-verbose=false -mattr=+reference-types | FileCheck %s
22

3-
%func = type void ()
4-
%funcref = type %func addrspace(20)* ;; addrspace 20 is nonintegral
5-
6-
define void @call_funcref(%funcref %ref) {
7-
call addrspace(20) void %ref()
8-
ret void
9-
}
3+
%funcptr = type void () addrspace(20)*
4+
%funcref = type i8 addrspace(20)* ;; addrspace 20 is nonintegral
105

116
; CHECK: .tabletype __funcref_call_table, funcref, 1
127

8+
define void @call_funcref(%funcref %ref) {
139
; CHECK-LABEL: call_funcref:
14-
; CHECK-NEXT: functype call_funcref (funcref) -> ()
10+
; CHECK-NEXT: .functype call_funcref (funcref) -> ()
1511
; CHECK-NEXT: i32.const 0
1612
; CHECK-NEXT: local.get 0
1713
; CHECK-NEXT: table.set __funcref_call_table
@@ -21,4 +17,26 @@ define void @call_funcref(%funcref %ref) {
2117
; CHECK-NEXT: ref.null_func
2218
; CHECK-NEXT: table.set __funcref_call_table
2319
; CHECK-NEXT: end_function
20+
%f = bitcast %funcref %ref to %funcptr
21+
call addrspace(20) void %f()
22+
ret void
23+
}
24+
25+
define void @call_funcptr(%funcptr %ref) {
26+
; CHECK-LABEL: call_funcptr:
27+
; CHECK-NEXT: .functype call_funcptr (funcref) -> ()
28+
; CHECK-NEXT: i32.const 0
29+
; CHECK-NEXT: local.get 0
30+
; CHECK-NEXT: table.set __funcref_call_table
31+
; CHECK-NEXT: i32.const 0
32+
; CHECK-NEXT: call_indirect __funcref_call_table, () -> ()
33+
; CHECK-NEXT: i32.const 0
34+
; CHECK-NEXT: ref.null_func
35+
; CHECK-NEXT: table.set __funcref_call_table
36+
; CHECK-NEXT: end_function
37+
call addrspace(20) void %ref()
38+
ret void
39+
}
40+
41+
2442

llvm/test/CodeGen/WebAssembly/funcref-globalget.ll

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
; RUN: llc < %s --mtriple=wasm32-unknown-unknown -asm-verbose=false -mattr=+reference-types | FileCheck %s
22

3-
%func = type opaque
4-
%funcref = type %func addrspace(20)* ;; addrspace 20 is nonintegral
3+
%funcref = type i8 addrspace(20)* ;; addrspace 20 is nonintegral
54

65
@funcref_global = local_unnamed_addr addrspace(1) global %funcref undef
76

llvm/test/CodeGen/WebAssembly/funcref-globalset.ll

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
; RUN: llc < %s --mtriple=wasm32-unknown-unknown -asm-verbose=false -mattr=+reference-types | FileCheck %s
22

3-
%func = type opaque
4-
%funcref = type %func addrspace(20)* ;; addrspace 20 is nonintegral
3+
%funcref = type i8 addrspace(20)* ;; addrspace 20 is nonintegral
54

65
@funcref_global = local_unnamed_addr addrspace(1) global %funcref undef
76

llvm/test/CodeGen/WebAssembly/funcref-table_call.ll

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
; RUN: llc < %s --mtriple=wasm32-unknown-unknown -asm-verbose=false -mattr=+reference-types | FileCheck %s
22

3-
%func = type void ()
4-
%funcref = type %func addrspace(20)* ;; addrspace 20 is nonintegral
3+
%funcptr = type void () addrspace(20)*
4+
%funcref = type i8 addrspace(20)* ;; addrspace 20 is nonintegral
55

66
@funcref_table = local_unnamed_addr addrspace(1) global [0 x %funcref] undef
77

88
define void @call_funcref_from_table(i32 %i) {
99
%p = getelementptr [0 x %funcref], [0 x %funcref] addrspace (1)* @funcref_table, i32 0, i32 %i
1010
%ref = load %funcref, %funcref addrspace(1)* %p
11-
call addrspace(20) void %ref()
11+
%fn = bitcast %funcref %ref to %funcptr
12+
call addrspace(20) void %fn()
1213
ret void
1314
}
1415

llvm/test/CodeGen/WebAssembly/funcref-tableget.ll

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
; RUN: llc < %s --mtriple=wasm32-unknown-unknown -asm-verbose=false -mattr=+reference-types | FileCheck %s
22

3-
%func = type void ()
4-
%funcref = type %func addrspace(20)* ;; addrspace 20 is nonintegral
3+
%funcref = type i8 addrspace(20)* ;; addrspace 20 is nonintegral
54

65
@funcref_table = local_unnamed_addr addrspace(1) global [0 x %funcref] undef
76

llvm/test/CodeGen/WebAssembly/funcref-tableset.ll

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
; RUN: llc --mtriple=wasm32-unknown-unknown -asm-verbose=false -mattr=+reference-types < %s | FileCheck %s
22

3-
%func = type void ()
4-
%funcref = type %func addrspace(20)* ;; addrspace 20 is nonintegral
3+
%funcref = type i8 addrspace(20)* ;; addrspace 20 is nonintegral
54

65
@funcref_table = local_unnamed_addr addrspace(1) global [0 x %funcref] undef
76

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
; RUN: llc --mtriple=wasm32-unknown-unknown -asm-verbose=false -mattr=+reference-types < %s | FileCheck %s
2+
3+
%extern = type opaque
4+
%externref = type %extern addrspace(10)* ;; addrspace 10 is nonintegral
5+
6+
@externref_table1 = local_unnamed_addr addrspace(1) global [0 x %externref] undef
7+
@externref_table2 = local_unnamed_addr addrspace(1) global [0 x %externref] undef
8+
9+
declare void @llvm.wasm.table.copy(i8 addrspace(1)*, i8 addrspace(1)*, i32, i32, i32) nounwind readonly
10+
11+
define void @table_copy(i32 %dst, i32 %src, i32 %len) {
12+
; CHECK-LABEL: table_copy:
13+
; CHECK-NEXT: .functype table_copy (i32, i32, i32) -> ()
14+
; CHECK-NEXT: local.get 0
15+
; CHECK-NEXT: local.get 1
16+
; CHECK-NEXT: local.get 2
17+
; CHECK-NEXT: table.copy externref_table1, externref_table2
18+
; CHECK-NEXT: end_function
19+
%tableptr1 = getelementptr [0 x %externref], [0 x %externref] addrspace(1)* @externref_table1, i32 0, i32 0
20+
%tb1 = bitcast %externref addrspace(1)* %tableptr1 to i8 addrspace(1)*
21+
%tableptr2 = getelementptr [0 x %externref], [0 x %externref] addrspace(1)* @externref_table2, i32 0, i32 0
22+
%tb2 = bitcast %externref addrspace(1)* %tableptr2 to i8 addrspace(1)*
23+
call void @llvm.wasm.table.copy(i8 addrspace(1)* %tb1, i8 addrspace(1)* %tb2, i32 %dst, i32 %src, i32 %len)
24+
ret void
25+
}
26+
27+
; Testing copying from a table to itself at different offsets
28+
; Copies len items from table1 at src to table1 at src+off
29+
define void @self_table_copy(i32 %src, i32 %off, i32 %len) {
30+
; CHECK-LABEL: self_table_copy:
31+
; CHECK-NEXT: .functype self_table_copy (i32, i32, i32) -> ()
32+
; CHECK-NEXT: local.get 0
33+
; CHECK-NEXT: local.get 1
34+
; CHECK-NEXT: i32.add
35+
; CHECK-NEXT: local.get 0
36+
; CHECK-NEXT: local.get 2
37+
; CHECK-NEXT: table.copy externref_table1, externref_table1
38+
; CHECK-NEXT: end_function
39+
%dst = add nsw i32 %src, %off
40+
%tableptr1 = getelementptr [0 x %externref], [0 x %externref] addrspace(1)* @externref_table1, i32 0, i32 0
41+
%tb1 = bitcast %externref addrspace(1)* %tableptr1 to i8 addrspace(1)*
42+
call void @llvm.wasm.table.copy(i8 addrspace(1)* %tb1, i8 addrspace(1)* %tb1, i32 %dst, i32 %src, i32 %len)
43+
ret void
44+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
; RUN: llc --mtriple=wasm32-unknown-unknown -asm-verbose=false -mattr=+reference-types < %s | FileCheck %s
2+
3+
%extern = type opaque
4+
%externref = type %extern addrspace(10)* ;; addrspace 10 is nonintegral
5+
6+
@externref_table = local_unnamed_addr addrspace(1) global [0 x %externref] undef
7+
8+
declare void @llvm.wasm.table.fill.externref(i8 addrspace(1)*, i32, %externref, i32) nounwind readonly
9+
10+
define void @table_fill(i32 %start, i32 %len, %externref %val) {
11+
; CHECK-LABEL: table_fill:
12+
; CHECK-NEXT: .functype table_fill (i32, i32, externref) -> ()
13+
; CHECK-NEXT: local.get 0
14+
; CHECK-NEXT: local.get 2
15+
; CHECK-NEXT: local.get 1
16+
; CHECK-NEXT: table.fill externref_table
17+
; CHECK-NEXT: end_function
18+
%tableptr = getelementptr [0 x %externref], [0 x %externref] addrspace(1)* @externref_table, i32 0, i32 0
19+
%tb = bitcast %externref addrspace(1)* %tableptr to i8 addrspace(1)*
20+
call void @llvm.wasm.table.fill.externref(i8 addrspace(1)* %tb, i32 %start, %externref %val, i32 %len)
21+
ret void
22+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
; RUN: llc --mtriple=wasm32-unknown-unknown -asm-verbose=false -mattr=+reference-types < %s | FileCheck %s
2+
3+
%extern = type opaque
4+
%externref = type %extern addrspace(10)* ;; addrspace 10 is nonintegral
5+
6+
@externref_table = local_unnamed_addr addrspace(1) global [0 x %externref] undef
7+
8+
declare i32 @llvm.wasm.table.grow.externref(i8 addrspace(1)*, %externref, i32) nounwind readonly
9+
declare %externref @llvm.wasm.ref.null.extern() nounwind readonly
10+
11+
define i32 @table_grow(i32 %sz) {
12+
; CHECK-LABEL: table_grow:
13+
; CHECK-NEXT: .functype table_grow (i32) -> (i32)
14+
; CHECK-NEXT: ref.null_extern
15+
; CHECK-NEXT: local.get 0
16+
; CHECK-NEXT: table.grow externref_table
17+
; CHECK-NEXT: end_function
18+
%null = call %externref @llvm.wasm.ref.null.extern()
19+
%tableptr = getelementptr [0 x %externref], [0 x %externref] addrspace(1)* @externref_table, i32 0, i32 0
20+
%tb = bitcast %externref addrspace(1)* %tableptr to i8 addrspace(1)*
21+
%newsz = call i32 @llvm.wasm.table.grow.externref(i8 addrspace(1)* %tb, %externref %null, i32 %sz)
22+
ret i32 %newsz
23+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
; RUN: llc --mtriple=wasm32-unknown-unknown -asm-verbose=false -mattr=+reference-types < %s | FileCheck %s
2+
3+
%extern = type opaque
4+
%externref = type %extern addrspace(10)* ;; addrspace 10 is nonintegral
5+
6+
@externref_table = local_unnamed_addr addrspace(1) global [0 x %externref] undef
7+
8+
declare i32 @llvm.wasm.table.size(i8 addrspace(1)*) nounwind readonly
9+
10+
define i32 @table_size() {
11+
; CHECK-LABEL: table_size:
12+
; CHECK-NEXT: .functype table_size () -> (i32)
13+
; CHECK-NEXT: table.size externref_table
14+
; CHECK-NEXT: end_function
15+
%tableptr = getelementptr [0 x %externref], [0 x %externref] addrspace(1)* @externref_table, i32 0, i32 0
16+
%tb = bitcast %externref addrspace(1)* %tableptr to i8 addrspace(1)*
17+
%sz = call i32 @llvm.wasm.table.size(i8 addrspace(1)* %tb)
18+
ret i32 %sz
19+
}

0 commit comments

Comments
 (0)