diff --git a/llvm/include/llvm/IR/Intrinsics.td b/llvm/include/llvm/IR/Intrinsics.td --- a/llvm/include/llvm/IR/Intrinsics.td +++ b/llvm/include/llvm/IR/Intrinsics.td @@ -331,6 +331,9 @@ def llvm_vararg_ty : LLVMType; // this means vararg here +def llvm_externref_ty : LLVMType; +def llvm_funcref_ty : LLVMType; + //===----------------------------------------------------------------------===// // Intrinsic Definitions. //===----------------------------------------------------------------------===// diff --git a/llvm/include/llvm/IR/IntrinsicsWebAssembly.td b/llvm/include/llvm/IR/IntrinsicsWebAssembly.td --- a/llvm/include/llvm/IR/IntrinsicsWebAssembly.td +++ b/llvm/include/llvm/IR/IntrinsicsWebAssembly.td @@ -23,6 +23,28 @@ [llvm_i32_ty, LLVMMatchType<0>], []>; +//===----------------------------------------------------------------------===// +// Table intrinsics +//===----------------------------------------------------------------------===// +def int_wasm_ref_null_externref : Intrinsic<[llvm_externref_ty], [], []>; +def int_wasm_ref_null_funcref : Intrinsic<[llvm_funcref_ty], [], []>; + +//===----------------------------------------------------------------------===// +// Table intrinsics +//===----------------------------------------------------------------------===// +// Query the current table size, and increase the current table size. +// Note that memory.size is not IntrNoMem because it must be sequenced with +// respect to memory.grow calls. +def int_wasm_table_size : Intrinsic<[llvm_i32_ty], + [LLVMPointerType], + [IntrReadMem]>; +def int_wasm_table_grow_externref : Intrinsic<[llvm_i32_ty], + [llvm_i32_ty, llvm_i32_ty, llvm_externref_ty], + []>; +def int_wasm_table_grow_funcref : Intrinsic<[llvm_i32_ty], + [llvm_i32_ty, llvm_i32_ty, llvm_funcref_ty], + []>; + //===----------------------------------------------------------------------===// // Trapping float-to-int conversions //===----------------------------------------------------------------------===// diff --git a/llvm/lib/IR/Function.cpp b/llvm/lib/IR/Function.cpp --- a/llvm/lib/IR/Function.cpp +++ b/llvm/lib/IR/Function.cpp @@ -979,7 +979,9 @@ IIT_BF16 = 48, IIT_STRUCT9 = 49, IIT_V256 = 50, - IIT_AMX = 51 + IIT_AMX = 51, + IIT_EXTERNREF = 52, + IIT_FUNCREF = 53 }; static void DecodeIITType(unsigned &NextElt, ArrayRef Infos, diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyInstrTable.td b/llvm/lib/Target/WebAssembly/WebAssemblyInstrTable.td --- a/llvm/lib/Target/WebAssembly/WebAssemblyInstrTable.td +++ b/llvm/lib/Target/WebAssembly/WebAssemblyInstrTable.td @@ -20,7 +20,7 @@ [SDNPHasChain, SDNPMayLoad, SDNPMemOperand]>; -multiclass TABLE { +multiclass TABLE { let mayLoad = 1 in defm TABLE_GET_#rc : I<(outs rc:$res), (ins table32_op:$table, I32:$i), (outs), (ins table32_op:$table), @@ -39,7 +39,7 @@ 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("int_wasm_table_grow_" # suffix) table32_op:$table, rc:$val, I32:$n))], "table.grow\t$sz, $table, $val, $n", "table.grow\t$table", 0xfc0f>; @@ -62,8 +62,8 @@ } } -defm "" : TABLE, Requires<[HasReferenceTypes]>; -defm "" : TABLE, Requires<[HasReferenceTypes]>; +defm "" : TABLE, Requires<[HasReferenceTypes]>; +defm "" : TABLE, Requires<[HasReferenceTypes]>; def : Pat<(WebAssemblyTableSet mcsym:$table, i32:$idx, funcref:$r), (TABLE_SET_FUNCREF mcsym:$table, i32:$idx, funcref:$r)>, @@ -71,7 +71,7 @@ defm TABLE_SIZE : I<(outs I32:$sz), (ins table32_op:$table), (outs), (ins table32_op:$table), - [], + [(set I32:$sz, (int_wasm_table_size table32_op:$table))], "table.size\t$sz, $table", "table.size\t$table", 0xfc10>, diff --git a/llvm/test/CodeGen/WebAssembly/table-grow.ll b/llvm/test/CodeGen/WebAssembly/table-grow.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/WebAssembly/table-grow.ll @@ -0,0 +1,27 @@ +; RUN: llc < %s -asm-verbose=false -O2 | FileCheck --check-prefix=CHECK %s +; RUN: llc < %s -asm-verbose=false -O2 --filetype=obj | obj2yaml | FileCheck --check-prefix=OBJ %s + +; Test that compilation units with call_indirect but without any +; function pointer declarations still get a table. + +target triple = "wasm32-unknown-unknown" + +; CHECK-LABEL: call_indirect_void: +; CHECK-NEXT: .functype call_indirect_void (i32) -> () +; CHECK-NEXT: local.get 0 +; CHECK-NEXT: call_indirect () -> () +; CHECK-NEXT: end_function +define void @call_indirect_void(void ()* %callee) { + call void %callee() + ret void +} + +; OBJ: Imports: +; OBJ-NEXT: - Module: env +; OBJ-NEXT: Field: __linear_memory +; OBJ-NEXT: Kind: MEMORY +; OBJ-NEXT: Memory: +; OBJ-NEXT: Minimum: 0x0 +; OBJ-NEXT: - Module: env +; OBJ-NEXT: Field: __indirect_function_table +; OBJ-NEXT: Kind: TABLE diff --git a/llvm/utils/TableGen/IntrinsicEmitter.cpp b/llvm/utils/TableGen/IntrinsicEmitter.cpp --- a/llvm/utils/TableGen/IntrinsicEmitter.cpp +++ b/llvm/utils/TableGen/IntrinsicEmitter.cpp @@ -249,7 +249,9 @@ IIT_BF16 = 48, IIT_STRUCT9 = 49, IIT_V256 = 50, - IIT_AMX = 51 + IIT_AMX = 51, + IIT_EXTERNREF = 52, + IIT_FUNCREF = 53 }; static void EncodeFixedValueType(MVT::SimpleValueType VT, @@ -282,6 +284,8 @@ case MVT::Other: return Sig.push_back(IIT_EMPTYSTRUCT); // MVT::isVoid is used to represent varargs here. case MVT::isVoid: return Sig.push_back(IIT_VARARG); + case MVT::externref: return Sig.push_back(IIT_EXTERNREF); + case MVT::funcref: return Sig.push_back(IIT_FUNCREF); } }