diff --git a/llvm/include/llvm/IR/Intrinsics.h b/llvm/include/llvm/IR/Intrinsics.h --- a/llvm/include/llvm/IR/Intrinsics.h +++ b/llvm/include/llvm/IR/Intrinsics.h @@ -140,7 +140,8 @@ Subdivide2Argument, Subdivide4Argument, VecOfBitcastsToInt, - AMX + AMX, + Function } Kind; union { 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_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. +// 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/CodeGen/ValueTypes.cpp b/llvm/lib/CodeGen/ValueTypes.cpp --- a/llvm/lib/CodeGen/ValueTypes.cpp +++ b/llvm/lib/CodeGen/ValueTypes.cpp @@ -203,7 +203,8 @@ case MVT::externref: return PointerType::get(StructType::create(Context), 10); case MVT::funcref: - return PointerType::get(StructType::create(Context), 20); + // FIXME: unsure this correct but before it was definitely NOT! + return PointerType::get(0, 20); // opaque pointer to addrspace(20) case MVT::v1i1: return FixedVectorType::get(Type::getInt1Ty(Context), 1); case MVT::v2i1: 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, @@ -1088,6 +1090,14 @@ OutputTable.push_back(IITDescriptor::getVector(1024, IsScalableVector)); DecodeIITType(NextElt, Infos, Info, OutputTable); return; + case IIT_EXTERNREF: + OutputTable.push_back(IITDescriptor::get(IITDescriptor::Pointer, 10)); + OutputTable.push_back(IITDescriptor::get(IITDescriptor::Struct, 0)); + return; + case IIT_FUNCREF: + OutputTable.push_back(IITDescriptor::get(IITDescriptor::Pointer, 20)); + OutputTable.push_back(IITDescriptor::get(IITDescriptor::Function, 0)); + return; case IIT_PTR: OutputTable.push_back(IITDescriptor::get(IITDescriptor::Pointer, 0)); DecodeIITType(NextElt, Infos, Info, OutputTable); @@ -1250,6 +1260,8 @@ case IITDescriptor::Float: return Type::getFloatTy(Context); case IITDescriptor::Double: return Type::getDoubleTy(Context); case IITDescriptor::Quad: return Type::getFP128Ty(Context); + // FIXME: this definitely looks strange and might require a rethink of funcref representation + case IITDescriptor::Function: return FunctionType::get(0, false); case IITDescriptor::Integer: return IntegerType::get(Context, D.Integer_Width); @@ -1453,6 +1465,13 @@ return false; } + case IITDescriptor::Function: { + FunctionType *FTy = dyn_cast(Ty); + if (!FTy) + return true; + return false; + } + case IITDescriptor::Struct: { StructType *ST = dyn_cast(Ty); if (!ST || ST->getNumElements() != D.Struct_NumElements) diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyInstrRef.td b/llvm/lib/Target/WebAssembly/WebAssemblyInstrRef.td --- a/llvm/lib/Target/WebAssembly/WebAssemblyInstrRef.td +++ b/llvm/lib/Target/WebAssembly/WebAssemblyInstrRef.td @@ -11,12 +11,13 @@ /// //===----------------------------------------------------------------------===// -multiclass REF_I { - defm REF_NULL_#rc : I<(outs rc:$res), (ins HeapType:$heaptype), - (outs), (ins HeapType:$heaptype), - [], - "ref.null\t$res, $heaptype", - "ref.null\t$heaptype", +multiclass REF_I { + defm REF_NULL_#rc : I<(outs rc:$dst), (ins), + (outs), (ins), + [(set rc:$dst, + (!cast("int_wasm_ref_null_" # ht)))], + "ref.null\t$dst, " # ht, + "ref.null\t" # ht, 0xd0>, Requires<[HasReferenceTypes]>; defm SELECT_#rc: I<(outs rc:$dst), (ins rc:$lhs, rc:$rhs, I32:$cond), @@ -28,8 +29,8 @@ Requires<[HasReferenceTypes]>; } -defm "" : REF_I; -defm "" : REF_I; +defm "" : REF_I; +defm "" : REF_I; foreach rc = [FUNCREF, EXTERNREF] in { def : Pat<(select (i32 (setne I32:$cond, 0)), rc:$lhs, rc:$rhs), 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 {//, 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), @@ -40,6 +40,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,6 +63,8 @@ } } +//defm "" : TABLE, Requires<[HasReferenceTypes]>; +//defm "" : TABLE, Requires<[HasReferenceTypes]>; defm "" : TABLE, Requires<[HasReferenceTypes]>; defm "" : TABLE, Requires<[HasReferenceTypes]>; @@ -72,6 +75,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/ref-null.ll b/llvm/test/CodeGen/WebAssembly/ref-null.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/WebAssembly/ref-null.ll @@ -0,0 +1,30 @@ +; 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 + +%func = type void () +%funcref = type %func addrspace(20)* ;; addrspace 20 is nonintegral + +declare %funcref @llvm.wasm.ref.null.func() nounwind +declare %externref @llvm.wasm.ref.null.extern() nounwind + +define %externref @get_null_extern() { +; CHECK-LABEL: get_null_extern: +; CHECK-NEXT: .functype get_null_extern () -> (externref) +; CHECK-NEXT: ref.null extern +; CHECK-NEXT: end_function + %null = call %externref @llvm.wasm.ref.null.extern() + ret %externref %null +} + + + +define %funcref @get_null_func() { +; CHECK-LABEL: get_null_func: +; CHECK-NEXT: .functype get_null_func () -> (funcref) +; CHECK-NEXT: ref.null func +; CHECK-NEXT: end_function + %null = call %funcref @llvm.wasm.ref.null.func() + ret %funcref %null +} 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,13 @@ +; 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 + +@externref_table = local_unnamed_addr addrspace(1) global [0 x %externref] undef + +declare i32 @llvm.wasm.table.grow.externref([0 x %externref], i32, %externref) nounwind + +define void @table_grow(i32 sz) { + call i32 @llvm.wasm.table.grow.externref() + ret void +} 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); } }