diff --git a/.gitignore b/.gitignore --- a/.gitignore +++ b/.gitignore @@ -60,6 +60,7 @@ pythonenv* # clangd index. (".clangd" is a config file now, thus trailing slash) .clangd/ +.ccls-cache/ .cache # static analyzer regression testing project files /clang/utils/analyzer/projects/*/CachedSource diff --git a/llvm/include/llvm/CodeGen/ValueTypes.h b/llvm/include/llvm/CodeGen/ValueTypes.h --- a/llvm/include/llvm/CodeGen/ValueTypes.h +++ b/llvm/include/llvm/CodeGen/ValueTypes.h @@ -209,7 +209,7 @@ /// Return true if this is an overloaded type for TableGen. bool isOverloaded() const { - return (V==MVT::iAny || V==MVT::fAny || V==MVT::vAny || V==MVT::iPTRAny); + return (V==MVT::rAny || V==MVT::iAny || V==MVT::fAny || V==MVT::vAny || V==MVT::iPTRAny); } /// Return true if the bit size is a multiple of 8. diff --git a/llvm/include/llvm/CodeGen/ValueTypes.td b/llvm/include/llvm/CodeGen/ValueTypes.td --- a/llvm/include/llvm/CodeGen/ValueTypes.td +++ b/llvm/include/llvm/CodeGen/ValueTypes.td @@ -218,22 +218,24 @@ def x86amx : ValueType<8192, 177>; // X86 AMX value def i64x8 : ValueType<512, 178>; // 8 Consecutive GPRs (AArch64) - -def token : ValueType<0, 248>; // TokenTy -def MetadataVT : ValueType<0, 249>; // Metadata +def token : ValueType<0, 247>; // TokenTy +def MetadataVT : ValueType<0, 248>; // Metadata // Pseudo valuetype mapped to the current pointer size to any address space. // Should only be used in TableGen. -def iPTRAny : ValueType<0, 250>; +def iPTRAny : ValueType<0, 249>; // Pseudo valuetype to represent "vector of any size" -def vAny : ValueType<0, 251>; +def vAny : ValueType<0, 250>; // Pseudo valuetype to represent "float of any format" -def fAny : ValueType<0, 252>; +def fAny : ValueType<0, 251>; // Pseudo valuetype to represent "integer of any bit width" -def iAny : ValueType<0, 253>; +def iAny : ValueType<0, 252>; + +// Pseudo valuetype to represent "any reference type" +def rAny : ValueType<0, 253>; // Pseudo valuetype mapped to the current pointer size. def iPTR : ValueType<0, 254>; 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 @@ -92,9 +92,9 @@ /// it. /// /// The Tys parameter is for intrinsics with overloaded types (e.g., those - /// using iAny, fAny, vAny, or iPTRAny). For a declaration of an overloaded - /// intrinsic, Tys must provide exactly one type for each overloaded type in - /// the intrinsic. + /// using rAny, iAny, fAny, vAny, or iPTRAny). For a declaration of an + /// overloaded intrinsic, Tys must provide exactly one type for each + /// overloaded type in the intrinsic. Function *getDeclaration(Module *M, ID id, ArrayRef Tys = None); /// Looks up Name in NameTable via binary search. NameTable must be sorted @@ -159,6 +159,7 @@ AK_AnyFloat, AK_AnyVector, AK_AnyPointer, + AK_AnyRef, AK_MatchType = 7 }; 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 @@ -235,6 +235,7 @@ def llvm_anyint_ty : LLVMType; def llvm_anyfloat_ty : LLVMType; def llvm_anyvector_ty : LLVMType; + def llvm_anyref_ty : LLVMType; } def llvm_i1_ty : LLVMType; def llvm_i8_ty : LLVMType; @@ -331,6 +332,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 @@ -11,6 +11,9 @@ /// //===----------------------------------------------------------------------===// +// Type definition for a table in an intrinsic +def llvm_table_ty : LLVMQualPointerType; + let TargetPrefix = "wasm" in { // All intrinsics start with "llvm.wasm.". // Query the current memory size, and increase the current memory size. @@ -23,6 +26,25 @@ [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], + [llvm_table_ty], + [IntrReadMem]>; +def int_wasm_table_grow : Intrinsic<[llvm_i32_ty], + [llvm_table_ty, llvm_anyref_ty, llvm_i32_ty], + []>; + //===----------------------------------------------------------------------===// // Trapping float-to-int conversions //===----------------------------------------------------------------------===// diff --git a/llvm/include/llvm/IR/Type.h b/llvm/include/llvm/IR/Type.h --- a/llvm/include/llvm/IR/Type.h +++ b/llvm/include/llvm/IR/Type.h @@ -77,6 +77,38 @@ ScalableVectorTyID ///< Scalable SIMD vector type }; + ////////// FIXME: WASM EXPERIMENTAL + enum WasmAddressSpace : unsigned { + // Default address space, for pointers to linear memory (stack, heap, data). + WASM_ADDRESS_SPACE_DEFAULT = 0, + // A non-integral address space for pointers to named objects outside of + // linear memory: WebAssembly globals or WebAssembly locals. Loads and + // stores + // to these pointers are lowered to global.get / global.set or local.get / + // local.set, as appropriate. + WASM_ADDRESS_SPACE_VAR = 1, + // A non-integral address space for externref values + WASM_ADDRESS_SPACE_EXTERNREF = 10, + // A non-integral address space for funcref values + WASM_ADDRESS_SPACE_FUNCREF = 20, + }; + +public: + static bool IsWasmFuncrefType(const Type *Ty) { + return isa(Ty) && + Ty->getPointerAddressSpace() == + WasmAddressSpace::WASM_ADDRESS_SPACE_FUNCREF; + } + static bool IsWasmExternrefType(const Type *Ty) { + return isa(Ty) && + Ty->getPointerAddressSpace() == + WasmAddressSpace::WASM_ADDRESS_SPACE_EXTERNREF; + } + static bool IsWasmRefType(const Type *Ty) { + return IsWasmFuncrefType(Ty) || IsWasmExternrefType(Ty); + } + ////////// WASM EXPERIMENTAL + private: /// This refers to the LLVMContext in which this type was uniqued. LLVMContext &Context; diff --git a/llvm/include/llvm/Support/MachineValueType.h b/llvm/include/llvm/Support/MachineValueType.h --- a/llvm/include/llvm/Support/MachineValueType.h +++ b/llvm/include/llvm/Support/MachineValueType.h @@ -269,6 +269,10 @@ funcref = 175, // WebAssembly's funcref type externref = 176, // WebAssembly's externref type + + FIRST_REFTYPE_VALUETYPE = funcref, + LAST_REFTYPE_VALUETYPE = externref, + x86amx = 177, // This is an X86 AMX value i64x8 = 178, // 8 Consecutive GPRs (AArch64) @@ -280,32 +284,35 @@ // MVT::MAX_ALLOWED_VALUETYPE is used for asserts and to size bit vectors // This value must be a multiple of 32. MAX_ALLOWED_VALUETYPE = 192, - + // A value of type llvm::TokenTy - token = 248, + token = 247, // This is MDNode or MDString. - Metadata = 249, + Metadata = 248, // An int value the size of the pointer of the current // target to any address space. This must only be used internal to // tblgen. Other than for overloading, we treat iPTRAny the same as iPTR. - iPTRAny = 250, + iPTRAny = 249, // A vector with any length and element size. This is used // for intrinsics that have overloadings based on vector types. // This is only for tblgen's consumption! - vAny = 251, + vAny = 250, // Any floating-point or vector floating-point value. This is used // for intrinsics that have overloadings based on floating-point types. // This is only for tblgen's consumption! - fAny = 252, + fAny = 251, // An integer or vector integer value of any bit width. This is // used for intrinsics that have overloadings based on integer bit widths. // This is only for tblgen's consumption! - iAny = 253, + iAny = 252, + + // Any Wasm reference type + rAny = 253, // An int value the size of the pointer of the current // target. This should only be used internal to tblgen! @@ -451,7 +458,7 @@ bool isOverloaded() const { return (SimpleTy == MVT::Any || SimpleTy == MVT::iAny || SimpleTy == MVT::fAny || SimpleTy == MVT::vAny || - SimpleTy == MVT::iPTRAny); + SimpleTy == MVT::iPTRAny || SimpleTy == MVT::rAny); } /// Return a vector with the same number of elements as this vector, but @@ -870,6 +877,7 @@ case fAny: case vAny: case Any: + case rAny: llvm_unreachable("Value type is overloaded."); case token: llvm_unreachable("Token type is a sentinel that cannot be used " @@ -1408,7 +1416,13 @@ return enum_seq_inclusive(MVT::FIRST_VALUETYPE, MVT::LAST_VALUETYPE, force_iteration_on_noniterable_enum); } - + + static auto ref_valuetypes() { + return enum_seq_inclusive(MVT::FIRST_REFTYPE_VALUETYPE, + MVT::LAST_REFTYPE_VALUETYPE, + force_iteration_on_noniterable_enum); + } + static auto integer_valuetypes() { return enum_seq_inclusive(MVT::FIRST_INTEGER_VALUETYPE, MVT::LAST_INTEGER_VALUETYPE, 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 @@ -201,9 +201,9 @@ case MVT::x86amx: return Type::getX86_AMXTy(Context); case MVT::i64x8: return IntegerType::get(Context, 512); case MVT::externref: - return PointerType::get(StructType::create(Context), 10); + return PointerType::get(StructType::create(Context), 10); // opaque pointer to addrspace(10) case MVT::funcref: - return PointerType::get(StructType::create(Context), 20); + return PointerType::get(Type::getInt8Ty(Context), 20); // void 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 @@ -980,7 +980,9 @@ IIT_STRUCT9 = 49, IIT_V256 = 50, IIT_AMX = 51, - IIT_PPCF128 = 52 + IIT_PPCF128 = 52, + IIT_EXTERNREF = 53, + IIT_FUNCREF = 54 }; static void DecodeIITType(unsigned &NextElt, ArrayRef Infos, @@ -1092,6 +1094,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::Integer, 8)); + return; case IIT_PTR: OutputTable.push_back(IITDescriptor::get(IITDescriptor::Pointer, 0)); DecodeIITType(NextElt, Infos, Info, OutputTable); @@ -1449,16 +1459,16 @@ PointerType *PT = dyn_cast(Ty); if (!PT || PT->getAddressSpace() != D.Pointer_AddressSpace) return true; - if (!PT->isOpaque()) + if (!PT->isOpaque()) return matchIntrinsicType(PT->getElementType(), Infos, ArgTys, - DeferredChecks, IsDeferredCheck); - // Consume IIT descriptors relating to the pointer element type. + DeferredChecks, IsDeferredCheck); + // Consume IIT descriptors relating to the pointer element type while (Infos.front().Kind == IITDescriptor::Pointer) Infos = Infos.slice(1); Infos = Infos.slice(1); return false; } - + case IITDescriptor::Struct: { StructType *ST = dyn_cast(Ty); if (!ST || ST->getNumElements() != D.Struct_NumElements) @@ -1491,6 +1501,7 @@ case IITDescriptor::AK_AnyFloat: return !Ty->isFPOrFPVectorTy(); case IITDescriptor::AK_AnyVector: return !isa(Ty); case IITDescriptor::AK_AnyPointer: return !isa(Ty); + case IITDescriptor::AK_AnyRef: return !Type::IsWasmRefType(Ty); default: break; } llvm_unreachable("all argument kinds not covered"); diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyISelDAGToDAG.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyISelDAGToDAG.cpp --- a/llvm/lib/Target/WebAssembly/WebAssemblyISelDAGToDAG.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyISelDAGToDAG.cpp @@ -54,7 +54,7 @@ LLVM_DEBUG(dbgs() << "********** ISelDAGToDAG **********\n" "********** Function: " << MF.getName() << '\n'); - + Subtarget = &MF.getSubtarget(); return SelectionDAGISel::runOnMachineFunction(MF); diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp --- a/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp @@ -644,8 +644,7 @@ Register RegFuncref = MF.getRegInfo().createVirtualRegister(&WebAssembly::FUNCREFRegClass); MachineInstr *RefNull = - BuildMI(MF, DL, TII.get(WebAssembly::REF_NULL_FUNCREF), RegFuncref) - .addImm(static_cast(WebAssembly::HeapType::Funcref)); + BuildMI(MF, DL, TII.get(WebAssembly::REF_NULL_FUNCREF), RegFuncref); BB->insertAfter(Const0->getIterator(), RefNull); MachineInstr *TableSet = 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>; @@ -64,6 +65,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 +74,7 @@ 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>, diff --git a/llvm/test/CodeGen/WebAssembly/funcref-call.ll b/llvm/test/CodeGen/WebAssembly/funcref-call.ll --- a/llvm/test/CodeGen/WebAssembly/funcref-call.ll +++ b/llvm/test/CodeGen/WebAssembly/funcref-call.ll @@ -1,10 +1,11 @@ ; 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 define void @call_funcref(%funcref %ref) { - call addrspace(20) void %ref() + %f = bitcast %funcref %ref to %funcptr + call addrspace(20) void %f() ret void } diff --git a/llvm/test/CodeGen/WebAssembly/funcref-globalget.ll b/llvm/test/CodeGen/WebAssembly/funcref-globalget.ll --- 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 --- 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 --- 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 --- 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 --- 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/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,26 @@ +; 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 +%funcref = type i8 addrspace(20)* ;; addrspace 20 is nonintegral + +declare %externref @llvm.wasm.ref.null.extern() nounwind +declare %funcref @llvm.wasm.ref.null.func() 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-size.ll b/llvm/test/CodeGen/WebAssembly/table-size.ll new file mode 100644 --- /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 + +@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 +} diff --git a/llvm/tools/llc/llc.cpp b/llvm/tools/llc/llc.cpp --- a/llvm/tools/llc/llc.cpp +++ b/llvm/tools/llc/llc.cpp @@ -532,7 +532,7 @@ WithColor::error(errs(), argv[0]) << Error; exit(1); } - + // On AIX, setting the relocation model to anything other than PIC is // considered a user error. if (TheTriple.isOSAIX() && RM.hasValue() && *RM != Reloc::PIC_) diff --git a/llvm/utils/TableGen/CodeGenDAGPatterns.cpp b/llvm/utils/TableGen/CodeGenDAGPatterns.cpp --- a/llvm/utils/TableGen/CodeGenDAGPatterns.cpp +++ b/llvm/utils/TableGen/CodeGenDAGPatterns.cpp @@ -834,6 +834,11 @@ if (Legal.count(T)) Out.insert(T); return; + case MVT::rAny: + for (MVT T : MVT::ref_valuetypes()) + if (Legal.count(T)) + Out.insert(T); + return; case MVT::Any: for (MVT T : MVT::all_valuetypes()) if (Legal.count(T)) diff --git a/llvm/utils/TableGen/CodeGenTarget.cpp b/llvm/utils/TableGen/CodeGenTarget.cpp --- a/llvm/utils/TableGen/CodeGenTarget.cpp +++ b/llvm/utils/TableGen/CodeGenTarget.cpp @@ -68,6 +68,7 @@ case MVT::iAny: return "MVT::iAny"; case MVT::fAny: return "MVT::fAny"; case MVT::vAny: return "MVT::vAny"; + case MVT::rAny: return "MVT::rAny"; case MVT::f16: return "MVT::f16"; case MVT::bf16: return "MVT::bf16"; case MVT::f32: return "MVT::f32"; 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 @@ -250,7 +250,9 @@ IIT_STRUCT9 = 49, IIT_V256 = 50, IIT_AMX = 51, - IIT_PPCF128 = 52 + IIT_PPCF128 = 52, + IIT_EXTERNREF = 53, + IIT_FUNCREF = 54 }; static void EncodeFixedValueType(MVT::SimpleValueType VT, @@ -284,6 +286,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); } } @@ -338,9 +342,14 @@ MVT::SimpleValueType VT = getValueType(R->getValueAsDef("VT")); + // Note: The order in which these cases show up need + // to match the inverse order of the respective ArgKind in + // Intrinsics.h. The value of Tmp when it reaches MVT::Any needs + // to be the value of the respective ArgKind enum. unsigned Tmp = 0; switch (VT) { default: break; + case MVT::rAny: ++Tmp; LLVM_FALLTHROUGH; case MVT::iPTRAny: ++Tmp; LLVM_FALLTHROUGH; case MVT::vAny: ++Tmp; LLVM_FALLTHROUGH; case MVT::fAny: ++Tmp; LLVM_FALLTHROUGH; @@ -412,12 +421,19 @@ return; } + // Note: The order in which these cases show up need + // to match the inverse order of the respective ArgKind in + // Intrinsics.h. The value of Tmp when it reaches MVT::Any needs + // to be the value of the respective ArgKind enum. unsigned Tmp = 0; switch (getValueType(R->getValueAsDef("VT"))) { default: break; case MVT::iPTR: UpdateArgCodes(R->getValueAsDef("ElTy"), ArgCodes, NumInserted, Mapping); break; + case MVT::rAny: + ++Tmp; + LLVM_FALLTHROUGH; case MVT::iPTRAny: ++Tmp; LLVM_FALLTHROUGH;