[llvm] 2fd634a - [WebAssembly] Implement table instruction intrinsics

Paulo Matos via llvm-commits llvm-commits at lists.llvm.org
Tue Dec 7 04:26:38 PST 2021


Author: Paulo Matos
Date: 2021-12-07T13:25:59+01:00
New Revision: 2fd634a5e307fc21ea7d05ab7c7fe9689f14fe25

URL: https://github.com/llvm/llvm-project/commit/2fd634a5e307fc21ea7d05ab7c7fe9689f14fe25
DIFF: https://github.com/llvm/llvm-project/commit/2fd634a5e307fc21ea7d05ab7c7fe9689f14fe25.diff

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

Added: 
    llvm/test/CodeGen/WebAssembly/table-copy.ll
    llvm/test/CodeGen/WebAssembly/table-fill.ll
    llvm/test/CodeGen/WebAssembly/table-grow.ll
    llvm/test/CodeGen/WebAssembly/table-size.ll

Modified: 
    llvm/include/llvm/IR/IntrinsicsWebAssembly.td
    llvm/lib/CodeGen/ValueTypes.cpp
    llvm/lib/Target/WebAssembly/WebAssemblyInstrTable.td
    llvm/test/CodeGen/WebAssembly/funcref-call.ll
    llvm/test/CodeGen/WebAssembly/funcref-globalget.ll
    llvm/test/CodeGen/WebAssembly/funcref-globalset.ll
    llvm/test/CodeGen/WebAssembly/funcref-table_call.ll
    llvm/test/CodeGen/WebAssembly/funcref-tableget.ll
    llvm/test/CodeGen/WebAssembly/funcref-tableset.ll

Removed: 
    


################################################################################
diff  --git a/llvm/include/llvm/IR/IntrinsicsWebAssembly.td b/llvm/include/llvm/IR/IntrinsicsWebAssembly.td
index 850b6500028b2..aecc3d91fae74 100644
--- a/llvm/include/llvm/IR/IntrinsicsWebAssembly.td
+++ b/llvm/include/llvm/IR/IntrinsicsWebAssembly.td
@@ -11,6 +11,9 @@
 ///
 //===----------------------------------------------------------------------===//
 
+// Type definition for a table in an intrinsic
+def llvm_table_ty : LLVMQualPointerType<llvm_i8_ty, 1>;
+
 let TargetPrefix = "wasm" in {  // All intrinsics start with "llvm.wasm.".
 
 // Query the current memory size, and increase the current memory size.
@@ -29,6 +32,29 @@ def int_wasm_memory_grow : Intrinsic<[llvm_anyint_ty],
 def int_wasm_ref_null_extern : Intrinsic<[llvm_externref_ty], [], [IntrNoMem]>;
 def int_wasm_ref_null_func : Intrinsic<[llvm_funcref_ty], [], [IntrNoMem]>;
 
+//===----------------------------------------------------------------------===//
+// Table intrinsics
+//===----------------------------------------------------------------------===//
+// Query the current table size, and increase the current table size.
+def int_wasm_table_size : Intrinsic<[llvm_i32_ty],
+                                    [llvm_table_ty],
+                                    [IntrReadMem]>;
+def int_wasm_table_copy : Intrinsic<[],
+                                    [llvm_table_ty, llvm_table_ty, llvm_i32_ty, llvm_i32_ty, llvm_i32_ty],
+                                    []>;
+def int_wasm_table_grow_externref : Intrinsic<[llvm_i32_ty],
+                                              [llvm_table_ty, llvm_externref_ty, llvm_i32_ty],
+                                              []>;
+def int_wasm_table_grow_funcref : Intrinsic<[llvm_i32_ty],
+                                            [llvm_table_ty, llvm_funcref_ty, llvm_i32_ty],
+                                            []>;
+def int_wasm_table_fill_externref : Intrinsic<[],
+                                              [llvm_table_ty, llvm_i32_ty, llvm_externref_ty, llvm_i32_ty],
+                                              []>;
+def int_wasm_table_fill_funcref : Intrinsic<[],
+                                            [llvm_table_ty, llvm_i32_ty, llvm_funcref_ty, llvm_i32_ty],
+                                            []>;
+
 //===----------------------------------------------------------------------===//
 // Trapping float-to-int conversions
 //===----------------------------------------------------------------------===//

diff  --git a/llvm/lib/CodeGen/ValueTypes.cpp b/llvm/lib/CodeGen/ValueTypes.cpp
index 4876b9e237176..0c42bef820051 100644
--- a/llvm/lib/CodeGen/ValueTypes.cpp
+++ b/llvm/lib/CodeGen/ValueTypes.cpp
@@ -201,9 +201,11 @@ Type *EVT::getTypeForEVT(LLVMContext &Context) const {
   case MVT::x86amx:  return Type::getX86_AMXTy(Context);
   case MVT::i64x8:   return IntegerType::get(Context, 512);
   case MVT::externref:
+    // pointer to opaque struct in addrspace(10)
     return PointerType::get(StructType::create(Context), 10);
   case MVT::funcref:
-    return PointerType::get(StructType::create(Context), 20);
+    // pointer to i8 addrspace(20)
+    return PointerType::get(Type::getInt8Ty(Context), 20);
   case MVT::v1i1:
     return FixedVectorType::get(Type::getInt1Ty(Context), 1);
   case MVT::v2i1:

diff  --git a/llvm/lib/Target/WebAssembly/WebAssemblyInstrTable.td b/llvm/lib/Target/WebAssembly/WebAssemblyInstrTable.td
index e44c2073eaebe..1fd00bf1cbc8f 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyInstrTable.td
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyInstrTable.td
@@ -20,7 +20,7 @@ def WebAssemblyTableGet : SDNode<"WebAssemblyISD::TABLE_GET", WebAssemblyTableGe
                                  [SDNPHasChain, SDNPMayLoad, SDNPMemOperand]>;
 
 
-multiclass TABLE<WebAssemblyRegClass rc> {
+multiclass TABLE<WebAssemblyRegClass rc, string suffix> {
   let mayLoad = 1 in
   defm TABLE_GET_#rc : I<(outs rc:$res), (ins table32_op:$table, I32:$i),
                          (outs), (ins table32_op:$table),
@@ -39,14 +39,14 @@ multiclass TABLE<WebAssemblyRegClass rc> {
 
   defm TABLE_GROW_#rc : I<(outs I32:$sz), (ins table32_op:$table, rc:$val, I32:$n),
                           (outs), (ins table32_op:$table),
-                          [],
+                          [(set I32:$sz, (!cast<Intrinsic>("int_wasm_table_grow_" # suffix) (WebAssemblyWrapper tglobaladdr:$table), rc:$val, I32:$n))],
                           "table.grow\t$sz, $table, $val, $n",
                           "table.grow\t$table",
                           0xfc0f>;
 
   defm TABLE_FILL_#rc : I<(outs), (ins table32_op:$table, I32:$i, rc:$val, I32:$n),
                           (outs), (ins table32_op:$table),
-                          [],
+                          [(!cast<Intrinsic>("int_wasm_table_fill_" # suffix) (WebAssemblyWrapper tglobaladdr:$table), I32:$i, rc:$val, I32:$n)],
                           "table.fill\t$table, $i, $val, $n",
                           "table.fill\t$table",
                           0xfc11>;
@@ -62,8 +62,8 @@ multiclass TABLE<WebAssemblyRegClass rc> {
   }
 }
 
-defm "" : TABLE<FUNCREF>, Requires<[HasReferenceTypes]>;
-defm "" : TABLE<EXTERNREF>, Requires<[HasReferenceTypes]>;
+defm "" : TABLE<FUNCREF, "funcref">, Requires<[HasReferenceTypes]>;
+defm "" : TABLE<EXTERNREF, "externref">, Requires<[HasReferenceTypes]>;
 
 def : Pat<(WebAssemblyTableSet mcsym:$table, i32:$idx, funcref:$r),
           (TABLE_SET_FUNCREF mcsym:$table, i32:$idx, funcref:$r)>,
@@ -71,7 +71,7 @@ def : Pat<(WebAssemblyTableSet mcsym:$table, i32:$idx, funcref:$r),
 
 defm TABLE_SIZE : I<(outs I32:$sz), (ins table32_op:$table),
                     (outs), (ins table32_op:$table),
-                    [],
+                    [(set I32:$sz, (int_wasm_table_size (WebAssemblyWrapper tglobaladdr:$table)))],
                     "table.size\t$sz, $table",
                     "table.size\t$table",
                     0xfc10>,
@@ -80,7 +80,9 @@ defm TABLE_SIZE : I<(outs I32:$sz), (ins table32_op:$table),
 
 defm TABLE_COPY : I<(outs), (ins table32_op:$table1, table32_op:$table2, I32:$d, I32:$s, I32:$n),
                     (outs), (ins table32_op:$table1, table32_op:$table2),
-                    [],
+                    [(int_wasm_table_copy (WebAssemblyWrapper tglobaladdr:$table1),
+                                          (WebAssemblyWrapper tglobaladdr:$table2),
+                                          I32:$d, I32:$s, I32:$n)],
                     "table.copy\t$table1, $table2, $d, $s, $n",
                     "table.copy\t$table1, $table2",
                     0xfc0e>,

diff  --git a/llvm/test/CodeGen/WebAssembly/funcref-call.ll b/llvm/test/CodeGen/WebAssembly/funcref-call.ll
index f65ea111e1aca..d568c817a1265 100644
--- a/llvm/test/CodeGen/WebAssembly/funcref-call.ll
+++ b/llvm/test/CodeGen/WebAssembly/funcref-call.ll
@@ -1,17 +1,13 @@
 ; 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
-
-define void @call_funcref(%funcref %ref) {
-  call addrspace(20) void %ref() 
-  ret void
-}
+%funcptr = type void () addrspace(20)*
+%funcref = type i8 addrspace(20)* ;; addrspace 20 is nonintegral
 
 ; CHECK: .tabletype __funcref_call_table, funcref, 1
 
+define void @call_funcref(%funcref %ref) {
 ; CHECK-LABEL: call_funcref:
-; CHECK-NEXT: functype       call_funcref (funcref) -> ()
+; CHECK-NEXT: .functype       call_funcref (funcref) -> ()
 ; CHECK-NEXT: i32.const 0
 ; CHECK-NEXT: local.get 0
 ; CHECK-NEXT: table.set __funcref_call_table
@@ -21,4 +17,26 @@ define void @call_funcref(%funcref %ref) {
 ; CHECK-NEXT: ref.null_func
 ; CHECK-NEXT: table.set __funcref_call_table
 ; CHECK-NEXT: end_function
+  %f = bitcast %funcref %ref to %funcptr
+  call addrspace(20) void %f() 
+  ret void
+}
+
+define void @call_funcptr(%funcptr %ref) {
+; CHECK-LABEL: call_funcptr:
+; CHECK-NEXT: .functype       call_funcptr (funcref) -> ()
+; CHECK-NEXT: i32.const	0
+; CHECK-NEXT: local.get	0
+; 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
+  call addrspace(20) void %ref()
+  ret void
+}
+
+
 

diff  --git a/llvm/test/CodeGen/WebAssembly/funcref-globalget.ll b/llvm/test/CodeGen/WebAssembly/funcref-globalget.ll
index 901404aafd717..37a72aba50b23 100644
--- a/llvm/test/CodeGen/WebAssembly/funcref-globalget.ll
+++ b/llvm/test/CodeGen/WebAssembly/funcref-globalget.ll
@@ -1,7 +1,6 @@
 ; RUN: llc < %s --mtriple=wasm32-unknown-unknown -asm-verbose=false -mattr=+reference-types | FileCheck %s
 
-%func = type opaque
-%funcref = type %func addrspace(20)* ;; addrspace 20 is nonintegral
+%funcref = type i8 addrspace(20)* ;; addrspace 20 is nonintegral
 
 @funcref_global = local_unnamed_addr addrspace(1) global %funcref undef
 

diff  --git a/llvm/test/CodeGen/WebAssembly/funcref-globalset.ll b/llvm/test/CodeGen/WebAssembly/funcref-globalset.ll
index 18b0e02cf7390..3c23abe49cbc9 100644
--- a/llvm/test/CodeGen/WebAssembly/funcref-globalset.ll
+++ b/llvm/test/CodeGen/WebAssembly/funcref-globalset.ll
@@ -1,7 +1,6 @@
 ; RUN: llc < %s --mtriple=wasm32-unknown-unknown -asm-verbose=false -mattr=+reference-types | FileCheck %s
 
-%func = type opaque
-%funcref = type %func addrspace(20)* ;; addrspace 20 is nonintegral
+%funcref = type i8 addrspace(20)* ;; addrspace 20 is nonintegral
 
 @funcref_global = local_unnamed_addr addrspace(1) global %funcref undef
 

diff  --git a/llvm/test/CodeGen/WebAssembly/funcref-table_call.ll b/llvm/test/CodeGen/WebAssembly/funcref-table_call.ll
index f87f38eae2aba..a9a317175e260 100644
--- a/llvm/test/CodeGen/WebAssembly/funcref-table_call.ll
+++ b/llvm/test/CodeGen/WebAssembly/funcref-table_call.ll
@@ -1,14 +1,15 @@
 ; 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
+%funcptr = type void () addrspace(20)*
+%funcref = type i8 addrspace(20)* ;; addrspace 20 is nonintegral
 
 @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()
+  %fn = bitcast %funcref %ref to %funcptr
+  call addrspace(20) void %fn()
   ret void
 }
 

diff  --git a/llvm/test/CodeGen/WebAssembly/funcref-tableget.ll b/llvm/test/CodeGen/WebAssembly/funcref-tableget.ll
index f40c9e0c89726..c374da7d1eb39 100644
--- a/llvm/test/CodeGen/WebAssembly/funcref-tableget.ll
+++ b/llvm/test/CodeGen/WebAssembly/funcref-tableget.ll
@@ -1,7 +1,6 @@
 ; 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
+%funcref = type i8 addrspace(20)* ;; addrspace 20 is nonintegral
 
 @funcref_table = local_unnamed_addr addrspace(1) global [0 x %funcref] undef
 

diff  --git a/llvm/test/CodeGen/WebAssembly/funcref-tableset.ll b/llvm/test/CodeGen/WebAssembly/funcref-tableset.ll
index 7d016f536c062..1bb50d16e3fef 100644
--- a/llvm/test/CodeGen/WebAssembly/funcref-tableset.ll
+++ b/llvm/test/CodeGen/WebAssembly/funcref-tableset.ll
@@ -1,7 +1,6 @@
 ; 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
+%funcref = type i8 addrspace(20)* ;; addrspace 20 is nonintegral
 
 @funcref_table = local_unnamed_addr addrspace(1) global [0 x %funcref] undef
 

diff  --git a/llvm/test/CodeGen/WebAssembly/table-copy.ll b/llvm/test/CodeGen/WebAssembly/table-copy.ll
new file mode 100644
index 0000000000000..7239a3f5febff
--- /dev/null
+++ b/llvm/test/CodeGen/WebAssembly/table-copy.ll
@@ -0,0 +1,44 @@
+; 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_table1 = local_unnamed_addr addrspace(1) global [0 x %externref] undef
+ at externref_table2 = local_unnamed_addr addrspace(1) global [0 x %externref] undef
+
+declare void @llvm.wasm.table.copy(i8 addrspace(1)*, i8 addrspace(1)*, i32, i32, i32) nounwind readonly
+
+define void @table_copy(i32 %dst, i32 %src, i32 %len) {
+; CHECK-LABEL: table_copy:
+; CHECK-NEXT:  .functype	table_copy (i32, i32, i32) -> ()
+; CHECK-NEXT:  local.get    0
+; CHECK-NEXT:  local.get    1
+; CHECK-NEXT:  local.get    2
+; CHECK-NEXT:  table.copy	externref_table1, externref_table2
+; CHECK-NEXT:  end_function
+  %tableptr1 = getelementptr [0 x %externref], [0 x %externref] addrspace(1)* @externref_table1, i32 0, i32 0
+  %tb1 = bitcast %externref addrspace(1)* %tableptr1 to i8 addrspace(1)*
+  %tableptr2 = getelementptr [0 x %externref], [0 x %externref] addrspace(1)* @externref_table2, i32 0, i32 0
+  %tb2 = bitcast %externref addrspace(1)* %tableptr2 to i8 addrspace(1)*
+  call void @llvm.wasm.table.copy(i8 addrspace(1)* %tb1, i8 addrspace(1)* %tb2, i32 %dst, i32 %src, i32 %len)
+  ret void
+}
+
+; Testing copying from a table to itself at 
diff erent offsets
+; Copies len items from table1 at src to table1 at src+off
+define void @self_table_copy(i32 %src, i32 %off, i32 %len) {
+; CHECK-LABEL: self_table_copy:
+; CHECK-NEXT:  .functype	self_table_copy (i32, i32, i32) -> ()
+; CHECK-NEXT:  local.get    0
+; CHECK-NEXT:  local.get    1
+; CHECK-NEXT:  i32.add
+; CHECK-NEXT:  local.get    0
+; CHECK-NEXT:  local.get    2
+; CHECK-NEXT:  table.copy	externref_table1, externref_table1
+; CHECK-NEXT:  end_function
+  %dst = add nsw i32 %src, %off
+  %tableptr1 = getelementptr [0 x %externref], [0 x %externref] addrspace(1)* @externref_table1, i32 0, i32 0
+  %tb1 = bitcast %externref addrspace(1)* %tableptr1 to i8 addrspace(1)*
+  call void @llvm.wasm.table.copy(i8 addrspace(1)* %tb1, i8 addrspace(1)* %tb1, i32 %dst, i32 %src, i32 %len)
+  ret void
+}

diff  --git a/llvm/test/CodeGen/WebAssembly/table-fill.ll b/llvm/test/CodeGen/WebAssembly/table-fill.ll
new file mode 100644
index 0000000000000..d547f2e8ac36c
--- /dev/null
+++ b/llvm/test/CodeGen/WebAssembly/table-fill.ll
@@ -0,0 +1,22 @@
+; 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
+
+declare void @llvm.wasm.table.fill.externref(i8 addrspace(1)*, i32, %externref, i32) nounwind readonly
+
+define void @table_fill(i32 %start, i32 %len, %externref %val) {
+; CHECK-LABEL: table_fill:
+; CHECK-NEXT:  .functype	table_fill (i32, i32, externref) -> ()
+; CHECK-NEXT:  local.get    0
+; CHECK-NEXT:  local.get    2
+; CHECK-NEXT:  local.get    1
+; CHECK-NEXT:  table.fill	externref_table
+; CHECK-NEXT:  end_function
+  %tableptr = getelementptr [0 x %externref], [0 x %externref] addrspace(1)* @externref_table, i32 0, i32 0
+  %tb = bitcast %externref addrspace(1)* %tableptr to i8 addrspace(1)*
+  call void @llvm.wasm.table.fill.externref(i8 addrspace(1)* %tb, i32 %start, %externref %val, i32 %len)
+  ret void
+}

diff  --git a/llvm/test/CodeGen/WebAssembly/table-grow.ll b/llvm/test/CodeGen/WebAssembly/table-grow.ll
new file mode 100644
index 0000000000000..de6ab83771acb
--- /dev/null
+++ b/llvm/test/CodeGen/WebAssembly/table-grow.ll
@@ -0,0 +1,23 @@
+; 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
+
+declare i32 @llvm.wasm.table.grow.externref(i8 addrspace(1)*, %externref, i32) nounwind readonly
+declare %externref @llvm.wasm.ref.null.extern() nounwind readonly
+
+define i32 @table_grow(i32 %sz) {
+; CHECK-LABEL: table_grow:
+; CHECK-NEXT:  .functype	table_grow (i32) -> (i32)
+; CHECK-NEXT:  ref.null_extern
+; CHECK-NEXT:  local.get	0
+; CHECK-NEXT:  table.grow	externref_table
+; CHECK-NEXT:  end_function
+  %null = call %externref @llvm.wasm.ref.null.extern()
+  %tableptr = getelementptr [0 x %externref], [0 x %externref] addrspace(1)* @externref_table, i32 0, i32 0
+  %tb = bitcast %externref addrspace(1)* %tableptr to i8 addrspace(1)*
+  %newsz = call i32 @llvm.wasm.table.grow.externref(i8 addrspace(1)* %tb, %externref %null, i32 %sz)
+  ret i32 %newsz
+}

diff  --git a/llvm/test/CodeGen/WebAssembly/table-size.ll b/llvm/test/CodeGen/WebAssembly/table-size.ll
new file mode 100644
index 0000000000000..267d22a96b09a
--- /dev/null
+++ b/llvm/test/CodeGen/WebAssembly/table-size.ll
@@ -0,0 +1,19 @@
+; 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
+
+declare i32 @llvm.wasm.table.size(i8 addrspace(1)*) nounwind readonly
+
+define i32 @table_size() {
+; CHECK-LABEL: table_size:
+; CHECK-NEXT:  .functype       table_size () -> (i32)
+; CHECK-NEXT:  table.size      externref_table
+; CHECK-NEXT:  end_function
+  %tableptr = getelementptr [0 x %externref], [0 x %externref] addrspace(1)* @externref_table, i32 0, i32 0
+  %tb = bitcast %externref addrspace(1)* %tableptr to i8 addrspace(1)*
+  %sz = call i32 @llvm.wasm.table.size(i8 addrspace(1)* %tb)
+  ret i32 %sz
+}


        


More information about the llvm-commits mailing list