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 @@ -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,35 @@ [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. +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 --- a/llvm/lib/CodeGen/ValueTypes.cpp +++ b/llvm/lib/CodeGen/ValueTypes.cpp @@ -201,9 +201,11 @@ 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 @@ -927,25 +927,25 @@ enum IIT_Info { // Common values should be encoded with 0-15. IIT_Done = 0, - IIT_I1 = 1, - IIT_I8 = 2, - IIT_I16 = 3, - IIT_I32 = 4, - IIT_I64 = 5, - IIT_F16 = 6, - IIT_F32 = 7, - IIT_F64 = 8, - IIT_V2 = 9, - IIT_V4 = 10, - IIT_V8 = 11, - IIT_V16 = 12, - IIT_V32 = 13, - IIT_PTR = 14, - IIT_ARG = 15, + IIT_I1 = 1, + IIT_I8 = 2, + IIT_I16 = 3, + IIT_I32 = 4, + IIT_I64 = 5, + IIT_F16 = 6, + IIT_F32 = 7, + IIT_F64 = 8, + IIT_V2 = 9, + IIT_V4 = 10, + IIT_V8 = 11, + IIT_V16 = 12, + IIT_V32 = 13, + IIT_PTR = 14, + IIT_ARG = 15, // Values from 16+ are only encodable with the inefficient encoding. - IIT_V64 = 16, - IIT_MMX = 17, + IIT_V64 = 16, + IIT_MMX = 17, IIT_TOKEN = 18, IIT_METADATA = 19, IIT_EMPTYSTRUCT = 20, @@ -956,7 +956,7 @@ IIT_EXTEND_ARG = 25, IIT_TRUNC_ARG = 26, IIT_ANYPTR = 27, - IIT_V1 = 28, + IIT_V1 = 28, IIT_VARARG = 29, IIT_HALF_VEC_ARG = 30, IIT_SAME_VEC_WIDTH_ARG = 31, @@ -979,8 +979,10 @@ IIT_BF16 = 48, IIT_STRUCT9 = 49, IIT_V256 = 50, - IIT_AMX = 51, - IIT_PPCF128 = 52 + IIT_AMX = 51, + 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); diff --git a/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp b/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp --- a/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp +++ b/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp @@ -571,7 +571,6 @@ // proper nesting. bool ExpectBlockType = false; bool ExpectFuncType = false; - bool ExpectHeapType = false; std::unique_ptr FunctionTable; if (Name == "block") { push(Block); @@ -624,8 +623,6 @@ if (parseFunctionTableOperand(&FunctionTable)) return true; ExpectFuncType = true; - } else if (Name == "ref.null") { - ExpectHeapType = true; } if (ExpectFuncType || (ExpectBlockType && Lexer.is(AsmToken::LParen))) { @@ -670,15 +667,6 @@ return error("Unknown block type: ", Id); addBlockTypeOperand(Operands, NameLoc, BT); Parser.Lex(); - } else if (ExpectHeapType) { - auto HeapType = WebAssembly::parseHeapType(Id.getString()); - if (HeapType == WebAssembly::HeapType::Invalid) { - return error("Expected a heap type: ", Id); - } - Operands.push_back(std::make_unique( - WebAssemblyOperand::Integer, Id.getLoc(), Id.getEndLoc(), - WebAssemblyOperand::IntOp{static_cast(HeapType)})); - Parser.Lex(); } else { // Assume this identifier is a label. const MCExpr *Val; diff --git a/llvm/lib/Target/WebAssembly/Disassembler/WebAssemblyDisassembler.cpp b/llvm/lib/Target/WebAssembly/Disassembler/WebAssemblyDisassembler.cpp --- a/llvm/lib/Target/WebAssembly/Disassembler/WebAssemblyDisassembler.cpp +++ b/llvm/lib/Target/WebAssembly/Disassembler/WebAssemblyDisassembler.cpp @@ -241,28 +241,6 @@ } break; } - // heap_type operands, for e.g. ref.null: - case WebAssembly::OPERAND_HEAPTYPE: { - int64_t Val; - uint64_t PrevSize = Size; - if (!nextLEB(Val, Bytes, Size, true)) - return MCDisassembler::Fail; - if (Val < 0 && Size == PrevSize + 1) { - // The HeapType encoding is like BlockType, in that encodings that - // decode as negative values indicate ValTypes. In practice we expect - // either wasm::ValType::EXTERNREF or wasm::ValType::FUNCREF here. - // - // The positive SLEB values are reserved for future expansion and are - // expected to be type indices in the typed function references - // proposal, and should disassemble as MCSymbolRefExpr as in BlockType - // above. - MI.addOperand(MCOperand::createImm(Val & 0x7f)); - } else { - MI.addOperand( - MCOperand::createImm(int64_t(WebAssembly::HeapType::Invalid))); - } - break; - } // FP operands. case WebAssembly::OPERAND_F32IMM: { if (!parseImmediate(MI, Size, Bytes)) diff --git a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyInstPrinter.h b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyInstPrinter.h --- a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyInstPrinter.h +++ b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyInstPrinter.h @@ -47,8 +47,6 @@ raw_ostream &O); void printWebAssemblySignatureOperand(const MCInst *MI, unsigned OpNo, raw_ostream &O); - void printWebAssemblyHeapTypeOperand(const MCInst *MI, unsigned OpNo, - raw_ostream &O); // Autogenerated by tblgen. std::pair getMnemonic(const MCInst *MI) override; diff --git a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyInstPrinter.cpp b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyInstPrinter.cpp --- a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyInstPrinter.cpp +++ b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyInstPrinter.cpp @@ -366,26 +366,3 @@ } } } - -void WebAssemblyInstPrinter::printWebAssemblyHeapTypeOperand(const MCInst *MI, - unsigned OpNo, - raw_ostream &O) { - const MCOperand &Op = MI->getOperand(OpNo); - if (Op.isImm()) { - switch (Op.getImm()) { - case long(wasm::ValType::EXTERNREF): - O << "extern"; - break; - case long(wasm::ValType::FUNCREF): - O << "func"; - break; - default: - O << "unsupported_heap_type_value"; - break; - } - } else { - // Typed function references and other subtypes of funcref and externref - // currently unimplemented. - O << "unsupported_heap_type_operand"; - } -} diff --git a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCCodeEmitter.cpp b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCCodeEmitter.cpp --- a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCCodeEmitter.cpp +++ b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCCodeEmitter.cpp @@ -84,6 +84,15 @@ MI.getOpcode() == WebAssembly::BR_TABLE_I64) encodeULEB128(MI.getNumOperands() - 2, OS); + // For REF_NULL, which has no HeapType explicit argument we just explicitly + // emit the encoding for the operand manually + if (MI.getOpcode() == WebAssembly::REF_NULL_FUNCREF || + MI.getOpcode() == WebAssembly::REF_NULL_FUNCREF_S) + OS << uint8_t(0x70); + if (MI.getOpcode() == WebAssembly::REF_NULL_EXTERNREF || + MI.getOpcode() == WebAssembly::REF_NULL_EXTERNREF_S) + OS << uint8_t(0x6f); + const MCInstrDesc &Desc = MCII.get(MI.getOpcode()); for (unsigned I = 0, E = MI.getNumOperands(); I < E; ++I) { const MCOperand &MO = MI.getOperand(I); @@ -106,9 +115,6 @@ encodeSLEB128(int64_t(MO.getImm()), OS); break; case WebAssembly::OPERAND_SIGNATURE: - case WebAssembly::OPERAND_HEAPTYPE: - OS << uint8_t(MO.getImm()); - break; case WebAssembly::OPERAND_VEC_I8IMM: support::endian::write(OS, MO.getImm(), support::little); break; diff --git a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.h b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.h --- a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.h +++ b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.h @@ -78,8 +78,6 @@ OPERAND_BRLIST, /// 32-bit unsigned table number. OPERAND_TABLE, - /// heap type immediate for ref.null. - OPERAND_HEAPTYPE, }; } // end namespace WebAssembly diff --git a/llvm/lib/Target/WebAssembly/Utils/WebAssemblyTypeUtilities.h b/llvm/lib/Target/WebAssembly/Utils/WebAssemblyTypeUtilities.h --- a/llvm/lib/Target/WebAssembly/Utils/WebAssemblyTypeUtilities.h +++ b/llvm/lib/Target/WebAssembly/Utils/WebAssemblyTypeUtilities.h @@ -41,17 +41,9 @@ Multivalue = 0xffff, }; -/// Used as immediate MachineOperands for heap types, e.g. for ref.null. -enum class HeapType : unsigned { - Invalid = 0x00, - Externref = unsigned(wasm::ValType::EXTERNREF), - Funcref = unsigned(wasm::ValType::FUNCREF), -}; - // Convert StringRef to ValType / HealType / BlockType Optional parseType(StringRef Type); -HeapType parseHeapType(StringRef Type); BlockType parseBlockType(StringRef Type); MVT parseMVT(StringRef Type); diff --git a/llvm/lib/Target/WebAssembly/Utils/WebAssemblyTypeUtilities.cpp b/llvm/lib/Target/WebAssembly/Utils/WebAssemblyTypeUtilities.cpp --- a/llvm/lib/Target/WebAssembly/Utils/WebAssemblyTypeUtilities.cpp +++ b/llvm/lib/Target/WebAssembly/Utils/WebAssemblyTypeUtilities.cpp @@ -41,13 +41,6 @@ return Optional(); } -WebAssembly::HeapType WebAssembly::parseHeapType(StringRef Type) { - return StringSwitch(Type) - .Case("extern", WebAssembly::HeapType::Externref) - .Case("func", WebAssembly::HeapType::Funcref) - .Default(WebAssembly::HeapType::Invalid); -} - WebAssembly::BlockType WebAssembly::parseBlockType(StringRef Type) { // Multivalue block types are handled separately in parseSignature return StringSwitch(Type) 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/WebAssemblyInstrInfo.td b/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.td --- a/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.td +++ b/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.td @@ -202,11 +202,6 @@ let PrintMethod = "printWebAssemblySignatureOperand"; } -let OperandType = "OPERAND_HEAPTYPE" in -def HeapType : Operand { - let PrintMethod = "printWebAssemblyHeapTypeOperand"; -} - let OperandType = "OPERAND_TYPEINDEX" in def TypeIndex : Operand; 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,12 @@ /// //===----------------------------------------------------------------------===// -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_" # ht # "$dst", + "ref.null_" # ht, 0xd0>, Requires<[HasReferenceTypes]>; defm SELECT_#rc: I<(outs rc:$dst), (ins rc:$lhs, rc:$rhs, I32:$cond), @@ -28,8 +28,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 { 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 @@ 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) (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("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 @@ } } -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 (WebAssemblyWrapper tglobaladdr:$table)))], "table.size\t$sz, $table", "table.size\t$table", 0xfc10>, @@ -80,7 +80,9 @@ 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/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp --- a/llvm/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp @@ -275,11 +275,6 @@ SmallVector()); break; } - } else if (Info.OperandType == WebAssembly::OPERAND_HEAPTYPE) { - assert(static_cast(MO.getImm()) != - WebAssembly::HeapType::Invalid); - // With typed function references, this will need a case for type - // index operands. Otherwise, fall through. } } MCOp = MCOperand::createImm(MO.getImm()); 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 } @@ -18,7 +19,7 @@ ; CHECK-NEXT: i32.const 0 ; CHECK-NEXT: call_indirect __funcref_call_table, () -> () ; CHECK-NEXT: i32.const 0 -; CHECK-NEXT: ref.null func +; CHECK-NEXT: ref.null_func ; CHECK-NEXT: table.set __funcref_call_table ; CHECK-NEXT: end_function 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 } @@ -23,7 +24,7 @@ ; CHECK-NEXT: i32.const 0 ; CHECK-NEXT: call_indirect __funcref_call_table, () -> () ; CHECK-NEXT: i32.const 0 -; CHECK-NEXT: ref.null func +; CHECK-NEXT: ref.null_func ; CHECK-NEXT: table.set __funcref_call_table ; CHECK-NEXT: end_function 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-copy.ll b/llvm/test/CodeGen/WebAssembly/table-copy.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/WebAssembly/table-copy.ll @@ -0,0 +1,25 @@ +; 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_table1 = local_unnamed_addr addrspace(1) global [0 x %externref] undef +@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 +} diff --git a/llvm/test/CodeGen/WebAssembly/table-fill.ll b/llvm/test/CodeGen/WebAssembly/table-fill.ll new file mode 100644 --- /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 + +@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 --- /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 + +@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 --- /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/test/MC/WebAssembly/reference-types.s b/llvm/test/MC/WebAssembly/reference-types.s --- a/llvm/test/MC/WebAssembly/reference-types.s +++ b/llvm/test/MC/WebAssembly/reference-types.s @@ -2,13 +2,13 @@ # RUN: llvm-mc -show-encoding -triple=wasm64-unknown-unknown -mattr=+reference-types < %s | FileCheck %s # CHECK-LABEL: ref_null_test: -# CHECK: ref.null func # encoding: [0xd0,0x70] -# CHECK: ref.null extern # encoding: [0xd0,0x6f] +# CHECK: ref.null_func # encoding: [0xd0,0x70] +# CHECK: ref.null_extern # encoding: [0xd0,0x6f] ref_null_test: .functype ref_null_test () -> () - ref.null func + ref.null_func drop - ref.null extern + ref.null_extern drop end_function @@ -31,13 +31,13 @@ # CHECK: externref.select # encoding: [0x1b] ref_select_test: .functype ref_select_test () -> () - ref.null func - ref.null func + ref.null_func + ref.null_func i32.const 0 funcref.select drop - ref.null extern - ref.null extern + ref.null_extern + ref.null_extern i32.const 0 externref.select drop @@ -50,8 +50,8 @@ .functype ref_block_test () -> (externref, funcref) block funcref block externref - ref.null extern + ref.null_extern end_block - ref.null func + ref.null_func end_block end_function 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 @@ -197,25 +197,25 @@ enum IIT_Info { // Common values should be encoded with 0-15. IIT_Done = 0, - IIT_I1 = 1, - IIT_I8 = 2, - IIT_I16 = 3, - IIT_I32 = 4, - IIT_I64 = 5, - IIT_F16 = 6, - IIT_F32 = 7, - IIT_F64 = 8, - IIT_V2 = 9, - IIT_V4 = 10, - IIT_V8 = 11, - IIT_V16 = 12, - IIT_V32 = 13, - IIT_PTR = 14, - IIT_ARG = 15, + IIT_I1 = 1, + IIT_I8 = 2, + IIT_I16 = 3, + IIT_I32 = 4, + IIT_I64 = 5, + IIT_F16 = 6, + IIT_F32 = 7, + IIT_F64 = 8, + IIT_V2 = 9, + IIT_V4 = 10, + IIT_V8 = 11, + IIT_V16 = 12, + IIT_V32 = 13, + IIT_PTR = 14, + IIT_ARG = 15, // Values from 16+ are only encodable with the inefficient encoding. - IIT_V64 = 16, - IIT_MMX = 17, + IIT_V64 = 16, + IIT_MMX = 17, IIT_TOKEN = 18, IIT_METADATA = 19, IIT_EMPTYSTRUCT = 20, @@ -226,7 +226,7 @@ IIT_EXTEND_ARG = 25, IIT_TRUNC_ARG = 26, IIT_ANYPTR = 27, - IIT_V1 = 28, + IIT_V1 = 28, IIT_VARARG = 29, IIT_HALF_VEC_ARG = 30, IIT_SAME_VEC_WIDTH_ARG = 31, @@ -249,8 +249,10 @@ IIT_BF16 = 48, IIT_STRUCT9 = 49, IIT_V256 = 50, - IIT_AMX = 51, - IIT_PPCF128 = 52 + IIT_AMX = 51, + IIT_PPCF128 = 52, + IIT_EXTERNREF = 53, + IIT_FUNCREF = 54 }; static void EncodeFixedValueType(MVT::SimpleValueType VT, @@ -284,6 +286,10 @@ 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); } }