diff --git a/clang/lib/Basic/Targets/WebAssembly.h b/clang/lib/Basic/Targets/WebAssembly.h --- a/clang/lib/Basic/Targets/WebAssembly.h +++ b/clang/lib/Basic/Targets/WebAssembly.h @@ -38,6 +38,7 @@ bool HasMutableGlobals = false; bool HasMultivalue = false; bool HasTailCall = false; + bool HasReferenceTypes = false; public: explicit WebAssemblyTargetInfo(const llvm::Triple &T, const TargetOptions &) diff --git a/lld/wasm/WriterUtils.cpp b/lld/wasm/WriterUtils.cpp --- a/lld/wasm/WriterUtils.cpp +++ b/lld/wasm/WriterUtils.cpp @@ -30,6 +30,10 @@ return "f64"; case ValType::V128: return "v128"; + case ValType::FUNCREF: + return "funcref"; + case ValType::ANYREF: + return "anyref"; case ValType::EXNREF: return "exnref"; } diff --git a/llvm/include/llvm/BinaryFormat/Wasm.h b/llvm/include/llvm/BinaryFormat/Wasm.h --- a/llvm/include/llvm/BinaryFormat/Wasm.h +++ b/llvm/include/llvm/BinaryFormat/Wasm.h @@ -225,6 +225,7 @@ WASM_TYPE_F64 = 0x7C, WASM_TYPE_V128 = 0x7B, WASM_TYPE_FUNCREF = 0x70, + WASM_TYPE_ANYREF = 0x6F, WASM_TYPE_EXNREF = 0x68, WASM_TYPE_FUNC = 0x60, WASM_TYPE_NORESULT = 0x40, // for blocks with no result values @@ -313,6 +314,7 @@ WASM_SYMBOL_TYPE_GLOBAL = 0x2, WASM_SYMBOL_TYPE_SECTION = 0x3, WASM_SYMBOL_TYPE_EVENT = 0x4, + WASM_SYMBOL_TYPE_TABLE = 0x5, }; // Kinds of event attributes. @@ -348,6 +350,8 @@ F32 = WASM_TYPE_F32, F64 = WASM_TYPE_F64, V128 = WASM_TYPE_V128, + FUNCREF = WASM_TYPE_FUNCREF, + ANYREF = WASM_TYPE_ANYREF, EXNREF = WASM_TYPE_EXNREF, }; diff --git a/llvm/include/llvm/BinaryFormat/WasmRelocs.def b/llvm/include/llvm/BinaryFormat/WasmRelocs.def --- a/llvm/include/llvm/BinaryFormat/WasmRelocs.def +++ b/llvm/include/llvm/BinaryFormat/WasmRelocs.def @@ -15,3 +15,4 @@ WASM_RELOC(R_WASM_EVENT_INDEX_LEB, 10) WASM_RELOC(R_WASM_MEMORY_ADDR_REL_SLEB, 11) WASM_RELOC(R_WASM_TABLE_INDEX_REL_SLEB, 12) +WASM_RELOC(R_WASM_TABLE_INDEX_LEB, 13) diff --git a/llvm/include/llvm/CodeGen/TargetLowering.h b/llvm/include/llvm/CodeGen/TargetLowering.h --- a/llvm/include/llvm/CodeGen/TargetLowering.h +++ b/llvm/include/llvm/CodeGen/TargetLowering.h @@ -255,7 +255,7 @@ /// Return the in-memory pointer type for the given address space, defaults to /// the pointer type from the data layout. FIXME: The default needs to be /// removed once all the code is updated. - MVT getPointerMemTy(const DataLayout &DL, uint32_t AS = 0) const { + virtual MVT getPointerMemTy(const DataLayout &DL, uint32_t AS = 0) const { return MVT::getIntegerVT(DL.getPointerSizeInBits(AS)); } 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 @@ -166,6 +166,7 @@ def isVoid : ValueType<0 , 132>; // Produces no value def untyped: ValueType<8 , 133>; // Produces an untyped value def exnref: ValueType<0, 134>; // WebAssembly's exnref type +def anyref: ValueType<0, 135>; // WebAssembly's anyref type def token : ValueType<0 , 248>; // TokenTy def MetadataVT: ValueType<0, 249>; // Metadata diff --git a/llvm/include/llvm/MC/MCExpr.h b/llvm/include/llvm/MC/MCExpr.h --- a/llvm/include/llvm/MC/MCExpr.h +++ b/llvm/include/llvm/MC/MCExpr.h @@ -290,9 +290,10 @@ VK_Hexagon_IE, VK_Hexagon_IE_GOT, - VK_WASM_TYPEINDEX, // Reference to a symbol's type (signature) - VK_WASM_MBREL, // Memory address relative to memory base - VK_WASM_TBREL, // Table index relative to table bare + VK_WASM_TYPEINDEX, // Reference to a symbol's type (signature) + VK_WASM_TABLEINDEX, // Reference to a table + VK_WASM_MBREL, // Memory address relative to memory base + VK_WASM_TBREL, // Table index relative to table bare VK_AMDGPU_GOTPCREL32_LO, // symbol@gotpcrel32@lo VK_AMDGPU_GOTPCREL32_HI, // symbol@gotpcrel32@hi diff --git a/llvm/include/llvm/MC/MCSymbolWasm.h b/llvm/include/llvm/MC/MCSymbolWasm.h --- a/llvm/include/llvm/MC/MCSymbolWasm.h +++ b/llvm/include/llvm/MC/MCSymbolWasm.h @@ -44,6 +44,7 @@ bool isGlobal() const { return Type == wasm::WASM_SYMBOL_TYPE_GLOBAL; } bool isSection() const { return Type == wasm::WASM_SYMBOL_TYPE_SECTION; } bool isEvent() const { return Type == wasm::WASM_SYMBOL_TYPE_EVENT; } + bool isTable() const { return Type == wasm::WASM_SYMBOL_TYPE_TABLE; } wasm::WasmSymbolType getType() const { return Type; } void setType(wasm::WasmSymbolType type) { Type = type; } diff --git a/llvm/include/llvm/Object/Wasm.h b/llvm/include/llvm/Object/Wasm.h --- a/llvm/include/llvm/Object/Wasm.h +++ b/llvm/include/llvm/Object/Wasm.h @@ -63,6 +63,8 @@ bool isTypeEvent() const { return Info.Kind == wasm::WASM_SYMBOL_TYPE_EVENT; } + bool isTypeTable() const { return Info.Kind == wasm::WASM_SYMBOL_TYPE_TABLE; } + bool isDefined() const { return !isUndefined(); } bool isUndefined() const { @@ -217,9 +219,12 @@ bool isDefinedGlobalIndex(uint32_t Index) const; bool isValidEventIndex(uint32_t Index) const; bool isDefinedEventIndex(uint32_t Index) const; + bool isValidTableIndex(uint32_t Index) const; + bool isDefinedTableIndex(uint32_t Index) const; bool isValidFunctionSymbol(uint32_t Index) const; bool isValidGlobalSymbol(uint32_t Index) const; bool isValidEventSymbol(uint32_t Index) const; + bool isValidTableSymbol(uint32_t Index) const; bool isValidDataSymbol(uint32_t Index) const; bool isValidSectionSymbol(uint32_t Index) const; wasm::WasmFunction &getDefinedFunction(uint32_t Index); @@ -284,6 +289,7 @@ uint32_t NumImportedGlobals = 0; uint32_t NumImportedFunctions = 0; uint32_t NumImportedEvents = 0; + uint32_t NumImportedTables = 0; uint32_t CodeSection = 0; uint32_t DataSection = 0; uint32_t GlobalSection = 0; 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 @@ -218,9 +218,10 @@ // will be determined by the opcode. exnref = 134, // WebAssembly's exnref type + anyref = 135, // WebAssembly's anyref type FIRST_VALUETYPE = 1, // This is always the beginning of the list. - LAST_VALUETYPE = 135, // This always remains at the end of the list. + LAST_VALUETYPE = 136, // This always remains at the end of the list. // This is the current maximum for LAST_VALUETYPE. // MVT::MAX_ALLOWED_VALUETYPE is used for asserts and to size bit vectors @@ -824,6 +825,7 @@ case v1024f32: return TypeSize::Fixed(32768); case v2048i32: case v2048f32: return TypeSize::Fixed(65536); + case anyref: case exnref: return TypeSize::Fixed(0); // opaque type } } diff --git a/llvm/lib/BinaryFormat/Wasm.cpp b/llvm/lib/BinaryFormat/Wasm.cpp --- a/llvm/lib/BinaryFormat/Wasm.cpp +++ b/llvm/lib/BinaryFormat/Wasm.cpp @@ -20,6 +20,8 @@ return "WASM_SYMBOL_TYPE_SECTION"; case wasm::WASM_SYMBOL_TYPE_EVENT: return "WASM_SYMBOL_TYPE_EVENT"; + case wasm::WASM_SYMBOL_TYPE_TABLE: + return "WASM_SYMBOL_TYPE_TABLE"; } llvm_unreachable("unknown symbol type"); } diff --git a/llvm/lib/CodeGen/CodeGenPrepare.cpp b/llvm/lib/CodeGen/CodeGenPrepare.cpp --- a/llvm/lib/CodeGen/CodeGenPrepare.cpp +++ b/llvm/lib/CodeGen/CodeGenPrepare.cpp @@ -1952,7 +1952,7 @@ case Intrinsic::experimental_widenable_condition: { // Give up on future widening oppurtunties so that we can fold away dead // paths and merge blocks before going into block-local instruction - // selection. + // selection. if (II->use_empty()) { II->eraseFromParent(); return true; @@ -5812,6 +5812,9 @@ EVT LoadResultVT = TLI->getValueType(*DL, Load->getType()); unsigned BitWidth = LoadResultVT.getSizeInBits(); + if (!BitWidth) + return false; + APInt DemandBits(BitWidth, 0); APInt WidestAndBits(BitWidth, 0); diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp --- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp @@ -4086,10 +4086,12 @@ Root = Chain; ChainI = 0; } - SDValue A = DAG.getNode(ISD::ADD, dl, - PtrVT, Ptr, - DAG.getConstant(Offsets[i], dl, PtrVT), - Flags); + SDValue A = Ptr; + if (Offsets[i] != 0) + A = DAG.getNode(ISD::ADD, dl, + PtrVT, Ptr, + DAG.getConstant(Offsets[i], dl, PtrVT), + Flags); auto MMOFlags = MachineMemOperand::MONone; if (isVolatile) MMOFlags |= MachineMemOperand::MOVolatile; 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 @@ -256,6 +256,7 @@ case MVT::Metadata:return "Metadata"; case MVT::Untyped: return "Untyped"; case MVT::exnref : return "exnref"; + case MVT::anyref : return "anyref"; } } @@ -355,91 +356,94 @@ case MVT::v2f64: return VectorType::get(Type::getDoubleTy(Context), 2); case MVT::v4f64: return VectorType::get(Type::getDoubleTy(Context), 4); case MVT::v8f64: return VectorType::get(Type::getDoubleTy(Context), 8); - case MVT::nxv1i1: + case MVT::nxv1i1: return VectorType::get(Type::getInt1Ty(Context), 1, /*Scalable=*/ true); - case MVT::nxv2i1: + case MVT::nxv2i1: return VectorType::get(Type::getInt1Ty(Context), 2, /*Scalable=*/ true); - case MVT::nxv4i1: + case MVT::nxv4i1: return VectorType::get(Type::getInt1Ty(Context), 4, /*Scalable=*/ true); - case MVT::nxv8i1: + case MVT::nxv8i1: return VectorType::get(Type::getInt1Ty(Context), 8, /*Scalable=*/ true); - case MVT::nxv16i1: + case MVT::nxv16i1: return VectorType::get(Type::getInt1Ty(Context), 16, /*Scalable=*/ true); - case MVT::nxv32i1: + case MVT::nxv32i1: return VectorType::get(Type::getInt1Ty(Context), 32, /*Scalable=*/ true); - case MVT::nxv1i8: + case MVT::nxv1i8: return VectorType::get(Type::getInt8Ty(Context), 1, /*Scalable=*/ true); - case MVT::nxv2i8: + case MVT::nxv2i8: return VectorType::get(Type::getInt8Ty(Context), 2, /*Scalable=*/ true); - case MVT::nxv4i8: + case MVT::nxv4i8: return VectorType::get(Type::getInt8Ty(Context), 4, /*Scalable=*/ true); - case MVT::nxv8i8: + case MVT::nxv8i8: return VectorType::get(Type::getInt8Ty(Context), 8, /*Scalable=*/ true); - case MVT::nxv16i8: + case MVT::nxv16i8: return VectorType::get(Type::getInt8Ty(Context), 16, /*Scalable=*/ true); - case MVT::nxv32i8: + case MVT::nxv32i8: return VectorType::get(Type::getInt8Ty(Context), 32, /*Scalable=*/ true); - case MVT::nxv1i16: + case MVT::nxv1i16: return VectorType::get(Type::getInt16Ty(Context), 1, /*Scalable=*/ true); - case MVT::nxv2i16: + case MVT::nxv2i16: return VectorType::get(Type::getInt16Ty(Context), 2, /*Scalable=*/ true); - case MVT::nxv4i16: + case MVT::nxv4i16: return VectorType::get(Type::getInt16Ty(Context), 4, /*Scalable=*/ true); - case MVT::nxv8i16: + case MVT::nxv8i16: return VectorType::get(Type::getInt16Ty(Context), 8, /*Scalable=*/ true); case MVT::nxv16i16: return VectorType::get(Type::getInt16Ty(Context), 16, /*Scalable=*/ true); case MVT::nxv32i16: return VectorType::get(Type::getInt16Ty(Context), 32, /*Scalable=*/ true); - case MVT::nxv1i32: + case MVT::nxv1i32: return VectorType::get(Type::getInt32Ty(Context), 1, /*Scalable=*/ true); - case MVT::nxv2i32: + case MVT::nxv2i32: return VectorType::get(Type::getInt32Ty(Context), 2, /*Scalable=*/ true); - case MVT::nxv4i32: + case MVT::nxv4i32: return VectorType::get(Type::getInt32Ty(Context), 4, /*Scalable=*/ true); - case MVT::nxv8i32: + case MVT::nxv8i32: return VectorType::get(Type::getInt32Ty(Context), 8, /*Scalable=*/ true); case MVT::nxv16i32: return VectorType::get(Type::getInt32Ty(Context), 16,/*Scalable=*/ true); case MVT::nxv32i32: return VectorType::get(Type::getInt32Ty(Context), 32,/*Scalable=*/ true); - case MVT::nxv1i64: + case MVT::nxv1i64: return VectorType::get(Type::getInt64Ty(Context), 1, /*Scalable=*/ true); - case MVT::nxv2i64: + case MVT::nxv2i64: return VectorType::get(Type::getInt64Ty(Context), 2, /*Scalable=*/ true); - case MVT::nxv4i64: + case MVT::nxv4i64: return VectorType::get(Type::getInt64Ty(Context), 4, /*Scalable=*/ true); - case MVT::nxv8i64: + case MVT::nxv8i64: return VectorType::get(Type::getInt64Ty(Context), 8, /*Scalable=*/ true); case MVT::nxv16i64: return VectorType::get(Type::getInt64Ty(Context), 16, /*Scalable=*/ true); case MVT::nxv32i64: return VectorType::get(Type::getInt64Ty(Context), 32, /*Scalable=*/ true); - case MVT::nxv2f16: + case MVT::nxv2f16: return VectorType::get(Type::getHalfTy(Context), 2, /*Scalable=*/ true); - case MVT::nxv4f16: + case MVT::nxv4f16: return VectorType::get(Type::getHalfTy(Context), 4, /*Scalable=*/ true); - case MVT::nxv8f16: + case MVT::nxv8f16: return VectorType::get(Type::getHalfTy(Context), 8, /*Scalable=*/ true); - case MVT::nxv1f32: + case MVT::nxv1f32: return VectorType::get(Type::getFloatTy(Context), 1, /*Scalable=*/ true); - case MVT::nxv2f32: + case MVT::nxv2f32: return VectorType::get(Type::getFloatTy(Context), 2, /*Scalable=*/ true); - case MVT::nxv4f32: + case MVT::nxv4f32: return VectorType::get(Type::getFloatTy(Context), 4, /*Scalable=*/ true); - case MVT::nxv8f32: + case MVT::nxv8f32: return VectorType::get(Type::getFloatTy(Context), 8, /*Scalable=*/ true); case MVT::nxv16f32: return VectorType::get(Type::getFloatTy(Context), 16, /*Scalable=*/ true); - case MVT::nxv1f64: + case MVT::nxv1f64: return VectorType::get(Type::getDoubleTy(Context), 1, /*Scalable=*/ true); - case MVT::nxv2f64: + case MVT::nxv2f64: return VectorType::get(Type::getDoubleTy(Context), 2, /*Scalable=*/ true); - case MVT::nxv4f64: + case MVT::nxv4f64: return VectorType::get(Type::getDoubleTy(Context), 4, /*Scalable=*/ true); - case MVT::nxv8f64: + case MVT::nxv8f64: return VectorType::get(Type::getDoubleTy(Context), 8, /*Scalable=*/ true); case MVT::Metadata: return Type::getMetadataTy(Context); + case MVT::anyref: + return PointerType::get(Type::getInt8Ty(Context), + 256); // TODO: Fix AS for Webassembly } } diff --git a/llvm/lib/MC/MCExpr.cpp b/llvm/lib/MC/MCExpr.cpp --- a/llvm/lib/MC/MCExpr.cpp +++ b/llvm/lib/MC/MCExpr.cpp @@ -312,6 +312,7 @@ case VK_Hexagon_IE: return "IE"; case VK_Hexagon_IE_GOT: return "IEGOT"; case VK_WASM_TYPEINDEX: return "TYPEINDEX"; + case VK_WASM_TABLEINDEX: return "TABLEINDEX"; case VK_WASM_MBREL: return "MBREL"; case VK_WASM_TBREL: return "TBREL"; case VK_AMDGPU_GOTPCREL32_LO: return "gotpcrel32@lo"; @@ -431,6 +432,7 @@ .Case("hi8", VK_AVR_HI8) .Case("hlo8", VK_AVR_HLO8) .Case("typeindex", VK_WASM_TYPEINDEX) + .Case("tableindex", VK_WASM_TABLEINDEX) .Case("tbrel", VK_WASM_TBREL) .Case("mbrel", VK_WASM_MBREL) .Case("gotpcrel32@lo", VK_AMDGPU_GOTPCREL32_LO) diff --git a/llvm/lib/MC/WasmObjectWriter.cpp b/llvm/lib/MC/WasmObjectWriter.cpp --- a/llvm/lib/MC/WasmObjectWriter.cpp +++ b/llvm/lib/MC/WasmObjectWriter.cpp @@ -254,6 +254,7 @@ unsigned NumFunctionImports = 0; unsigned NumGlobalImports = 0; unsigned NumEventImports = 0; + unsigned NumTableImports = 0; uint32_t SectionCount = 0; // TargetObjectWriter wrappers. @@ -555,6 +556,7 @@ case wasm::R_WASM_FUNCTION_INDEX_LEB: case wasm::R_WASM_GLOBAL_INDEX_LEB: case wasm::R_WASM_EVENT_INDEX_LEB: + case wasm::R_WASM_TABLE_INDEX_LEB: // Provisional value is function/global/event Wasm index assert(WasmIndices.count(RelEntry.Symbol) > 0 && "symbol not found in wasm index space"); return WasmIndices[RelEntry.Symbol]; @@ -652,6 +654,7 @@ case wasm::R_WASM_GLOBAL_INDEX_LEB: case wasm::R_WASM_MEMORY_ADDR_LEB: case wasm::R_WASM_EVENT_INDEX_LEB: + case wasm::R_WASM_TABLE_INDEX_LEB: writePatchableLEB(Stream, Value, Offset); break; case wasm::R_WASM_TABLE_INDEX_I32: @@ -945,6 +948,7 @@ case wasm::WASM_SYMBOL_TYPE_FUNCTION: case wasm::WASM_SYMBOL_TYPE_GLOBAL: case wasm::WASM_SYMBOL_TYPE_EVENT: + case wasm::WASM_SYMBOL_TYPE_TABLE: encodeULEB128(Sym.ElementIndex, W.OS); if ((Sym.Flags & wasm::WASM_SYMBOL_UNDEFINED) == 0 || (Sym.Flags & wasm::WASM_SYMBOL_EXPLICIT_NAME) != 0) @@ -1137,6 +1141,7 @@ TableImport.Kind = wasm::WASM_EXTERNAL_TABLE; TableImport.Table.ElemType = wasm::WASM_TYPE_FUNCREF; Imports.push_back(TableImport); + NumTableImports++; // Populate SignatureIndices, and Imports and WasmIndices for undefined // symbols. This must be done before populating WasmIndices for defined @@ -1191,6 +1196,15 @@ Imports.push_back(Import); assert(WasmIndices.count(&WS) == 0); WasmIndices[&WS] = NumEventImports++; + } else if (WS.isTable()) { + wasm::WasmImport Import; + Import.Module = WS.getImportModule(); + Import.Field = WS.getImportName(); + Import.Kind = wasm::WASM_EXTERNAL_TABLE; + Import.Table.ElemType = wasm::WASM_TYPE_ANYREF; + Imports.push_back(Import); + assert(WasmIndices.count(&WS) == 0); + WasmIndices[&WS] = NumTableImports++; } } } @@ -1389,7 +1403,15 @@ } LLVM_DEBUG(dbgs() << " -> event index: " << WasmIndices.find(&WS)->second << "\n"); - + } else if (WS.isTable()) { + if (WS.isDefined()) { + report_fatal_error("Defined tables are not supported yet"); + } else { + // An import; the index was assigned above. + assert(WasmIndices.count(&WS) > 0); + } + LLVM_DEBUG(dbgs() << " -> table index: " << WasmIndices.find(&WS)->second + << "\n"); } else { assert(WS.isSection()); } diff --git a/llvm/lib/Object/WasmObjectFile.cpp b/llvm/lib/Object/WasmObjectFile.cpp --- a/llvm/lib/Object/WasmObjectFile.cpp +++ b/llvm/lib/Object/WasmObjectFile.cpp @@ -470,9 +470,11 @@ std::vector ImportedGlobals; std::vector ImportedFunctions; std::vector ImportedEvents; + std::vector ImportedTables; ImportedGlobals.reserve(Imports.size()); ImportedFunctions.reserve(Imports.size()); ImportedEvents.reserve(Imports.size()); + ImportedTables.reserve(Imports.size()); for (auto &I : Imports) { if (I.Kind == wasm::WASM_EXTERNAL_FUNCTION) ImportedFunctions.emplace_back(&I); @@ -480,6 +482,8 @@ ImportedGlobals.emplace_back(&I); else if (I.Kind == wasm::WASM_EXTERNAL_EVENT) ImportedEvents.emplace_back(&I); + else if (I.Kind == wasm::WASM_EXTERNAL_TABLE) + ImportedTables.emplace_back(&I); } while (Count--) { @@ -609,6 +613,27 @@ break; } + case wasm::WASM_SYMBOL_TYPE_TABLE: { + Info.ElementIndex = readVaruint32(Ctx); + if (!isValidTableIndex(Info.ElementIndex) || + IsDefined != isDefinedTableIndex(Info.ElementIndex)) + return make_error("invalid table symbol index", + object_error::parse_failed); + if (IsDefined) { + Info.Name = readString(Ctx); + unsigned TableIndex = Info.ElementIndex - NumImportedTables; + } else { + wasm::WasmImport &Import = *ImportedTables[Info.ElementIndex]; + if ((Info.Flags & wasm::WASM_SYMBOL_EXPLICIT_NAME) != 0) + Info.Name = readString(Ctx); + else + Info.Name = Import.Field; + Info.ImportName = Import.Field; + Info.ImportModule = Import.Module; + } + break; + } + default: return make_error("Invalid symbol type", object_error::parse_failed); @@ -793,6 +818,11 @@ return make_error("Bad relocation event index", object_error::parse_failed); break; + case wasm::R_WASM_TABLE_INDEX_LEB: + if (!isValidTableSymbol(Reloc.Index)) + return make_error("Bad relocation table index", + object_error::parse_failed); + break; case wasm::R_WASM_MEMORY_ADDR_LEB: case wasm::R_WASM_MEMORY_ADDR_SLEB: case wasm::R_WASM_MEMORY_ADDR_I32: @@ -915,8 +945,10 @@ Im.Memory = readLimits(Ctx); break; case wasm::WASM_EXTERNAL_TABLE: + NumImportedTables++; Im.Table = readTable(Ctx); - if (Im.Table.ElemType != wasm::WASM_TYPE_FUNCREF) + if (Im.Table.ElemType != wasm::WASM_TYPE_FUNCREF && + Im.Table.ElemType != wasm::WASM_TYPE_ANYREF) return make_error("Invalid table element type", object_error::parse_failed); break; @@ -959,7 +991,9 @@ Tables.reserve(Count); while (Count--) { Tables.push_back(readTable(Ctx)); - if (Tables.back().ElemType != wasm::WASM_TYPE_FUNCREF) { + if (Tables.back().ElemType != wasm::WASM_TYPE_FUNCREF && + // TODO: Only allow anyref here when reference-types is enabled? + Tables.back().ElemType != wasm::WASM_TYPE_ANYREF) { return make_error("Invalid table element type", object_error::parse_failed); } @@ -1082,6 +1116,14 @@ return Index >= NumImportedEvents && isValidEventIndex(Index); } +bool WasmObjectFile::isValidTableIndex(uint32_t Index) const { + return Index < NumImportedTables + Tables.size(); +} + +bool WasmObjectFile::isDefinedTableIndex(uint32_t Index) const { + return Index >= NumImportedTables && isValidTableIndex(Index); +} + bool WasmObjectFile::isValidFunctionSymbol(uint32_t Index) const { return Index < Symbols.size() && Symbols[Index].isTypeFunction(); } @@ -1094,6 +1136,10 @@ return Index < Symbols.size() && Symbols[Index].isTypeEvent(); } +bool WasmObjectFile::isValidTableSymbol(uint32_t Index) const { + return Index < Symbols.size() && Symbols[Index].isTypeTable(); +} + bool WasmObjectFile::isValidDataSymbol(uint32_t Index) const { return Index < Symbols.size() && Symbols[Index].isTypeData(); } diff --git a/llvm/lib/ObjectYAML/WasmEmitter.cpp b/llvm/lib/ObjectYAML/WasmEmitter.cpp --- a/llvm/lib/ObjectYAML/WasmEmitter.cpp +++ b/llvm/lib/ObjectYAML/WasmEmitter.cpp @@ -188,6 +188,7 @@ case wasm::WASM_SYMBOL_TYPE_FUNCTION: case wasm::WASM_SYMBOL_TYPE_GLOBAL: case wasm::WASM_SYMBOL_TYPE_EVENT: + case wasm::WASM_SYMBOL_TYPE_TABLE: encodeULEB128(Info.ElementIndex, SubSection.getStream()); if ((Info.Flags & wasm::WASM_SYMBOL_UNDEFINED) == 0 || (Info.Flags & wasm::WASM_SYMBOL_EXPLICIT_NAME) != 0) diff --git a/llvm/lib/ObjectYAML/WasmYAML.cpp b/llvm/lib/ObjectYAML/WasmYAML.cpp --- a/llvm/lib/ObjectYAML/WasmYAML.cpp +++ b/llvm/lib/ObjectYAML/WasmYAML.cpp @@ -493,6 +493,8 @@ IO.mapRequired("Global", Info.ElementIndex); } else if (Info.Kind == wasm::WASM_SYMBOL_TYPE_EVENT) { IO.mapRequired("Event", Info.ElementIndex); + } else if (Info.Kind == wasm::WASM_SYMBOL_TYPE_TABLE) { + IO.mapRequired("Table", Info.ElementIndex); } else if (Info.Kind == wasm::WASM_SYMBOL_TYPE_DATA) { if ((Info.Flags & wasm::WASM_SYMBOL_UNDEFINED) == 0) { IO.mapRequired("Segment", Info.DataRef.Segment); @@ -547,6 +549,7 @@ ECase(GLOBAL); ECase(SECTION); ECase(EVENT); + ECase(TABLE); #undef ECase } @@ -559,6 +562,7 @@ ECase(F64); ECase(V128); ECase(FUNCREF); + ECase(ANYREF); ECase(FUNC); #undef ECase } @@ -590,6 +594,7 @@ IO &IO, WasmYAML::TableType &Type) { #define ECase(X) IO.enumCase(Type, #X, wasm::WASM_TYPE_##X); ECase(FUNCREF); + ECase(ANYREF); #undef ECase } 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 @@ -310,6 +310,8 @@ return wasm::ValType::V128; if (Type == "exnref") return wasm::ValType::EXNREF; + if (Type == "anyref") + return wasm::ValType::ANYREF; return Optional(); } @@ -322,6 +324,7 @@ .Case("f64", WebAssembly::BlockType::F64) .Case("v128", WebAssembly::BlockType::V128) .Case("exnref", WebAssembly::BlockType::Exnref) + .Case("anyref", WebAssembly::BlockType::Anyref) .Case("void", WebAssembly::BlockType::Void) .Default(WebAssembly::BlockType::Invalid); } 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 @@ -197,6 +197,7 @@ case WebAssembly::OPERAND_BASIC_BLOCK: case WebAssembly::OPERAND_LOCAL: case WebAssembly::OPERAND_GLOBAL: + case WebAssembly::OPERAND_TABLE: case WebAssembly::OPERAND_FUNCTION32: case WebAssembly::OPERAND_OFFSET32: case WebAssembly::OPERAND_P2ALIGN: 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 @@ -305,6 +305,8 @@ return "v128"; case wasm::WASM_TYPE_FUNCREF: return "funcref"; + case wasm::WASM_TYPE_ANYREF: + return "anyref"; case wasm::WASM_TYPE_FUNC: return "func"; case wasm::WASM_TYPE_EXNREF: 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 @@ -155,6 +155,7 @@ case WebAssembly::OPERAND_SIGNATURE: case WebAssembly::OPERAND_TYPEINDEX: case WebAssembly::OPERAND_GLOBAL: + case WebAssembly::OPERAND_TABLE: case WebAssembly::OPERAND_EVENT: FixupKind = MCFixupKind(WebAssembly::fixup_uleb128_i32); 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 @@ -48,6 +48,8 @@ OPERAND_LOCAL, /// Global index. OPERAND_GLOBAL, + /// Table index. + OPERAND_TABLE, /// 32-bit integer immediates. OPERAND_I32IMM, /// 64-bit integer immediates. @@ -102,6 +104,9 @@ // address relative the __table_base wasm global. // Only applicable to function symbols. MO_TABLE_BASE_REL, + + // On a symbol operand this indicates that this operand is a table index. + MO_TABLE_INDEX, }; } // end namespace WebAssemblyII @@ -132,6 +137,7 @@ F64 = unsigned(wasm::ValType::F64), V128 = unsigned(wasm::ValType::V128), Exnref = unsigned(wasm::ValType::EXNREF), + Anyref = unsigned(wasm::ValType::ANYREF), // Multivalue blocks (and other non-void blocks) are only emitted when the // blocks will never be exited and are at the ends of functions (see // WebAssemblyCFGStackify::fixEndsAtEndOfFunction). They also are never made @@ -393,6 +399,8 @@ case WebAssembly::ARGUMENT_v2f64_S: case WebAssembly::ARGUMENT_exnref: case WebAssembly::ARGUMENT_exnref_S: + case WebAssembly::ARGUMENT_anyref: + case WebAssembly::ARGUMENT_anyref_S: return true; default: return false; @@ -413,6 +421,8 @@ case WebAssembly::COPY_V128_S: case WebAssembly::COPY_EXNREF: case WebAssembly::COPY_EXNREF_S: + case WebAssembly::COPY_ANYREF: + case WebAssembly::COPY_ANYREF_S: return true; default: return false; @@ -433,6 +443,8 @@ case WebAssembly::TEE_V128_S: case WebAssembly::TEE_EXNREF: case WebAssembly::TEE_EXNREF_S: + case WebAssembly::TEE_ANYREF: + case WebAssembly::TEE_ANYREF_S: return true; default: return false; @@ -465,6 +477,8 @@ case WebAssembly::CALL_v2f64_S: case WebAssembly::CALL_exnref: case WebAssembly::CALL_exnref_S: + case WebAssembly::CALL_anyref: + case WebAssembly::CALL_anyref_S: case WebAssembly::RET_CALL: case WebAssembly::RET_CALL_S: return true; @@ -499,6 +513,8 @@ case WebAssembly::CALL_INDIRECT_v2f64_S: case WebAssembly::CALL_INDIRECT_exnref: case WebAssembly::CALL_INDIRECT_exnref_S: + case WebAssembly::CALL_INDIRECT_anyref: + case WebAssembly::CALL_INDIRECT_anyref_S: case WebAssembly::RET_CALL_INDIRECT: case WebAssembly::RET_CALL_INDIRECT_S: return true; @@ -542,6 +558,8 @@ case WebAssembly::CALL_v2f64_S: case WebAssembly::CALL_exnref: case WebAssembly::CALL_exnref_S: + case WebAssembly::CALL_anyref: + case WebAssembly::CALL_anyref_S: case WebAssembly::CALL_INDIRECT_i32: case WebAssembly::CALL_INDIRECT_i32_S: case WebAssembly::CALL_INDIRECT_i64: @@ -562,6 +580,8 @@ case WebAssembly::CALL_INDIRECT_v4f32_S: case WebAssembly::CALL_INDIRECT_v2f64: case WebAssembly::CALL_INDIRECT_v2f64_S: + case WebAssembly::CALL_INDIRECT_anyref: + case WebAssembly::CALL_INDIRECT_anyref_S: case WebAssembly::CALL_INDIRECT_exnref: case WebAssembly::CALL_INDIRECT_exnref_S: return 1; diff --git a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.cpp b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.cpp --- a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.cpp +++ b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.cpp @@ -149,6 +149,8 @@ return wasm::ValType::V128; case MVT::exnref: return wasm::ValType::EXNREF; + case MVT::anyref: + return wasm::ValType::ANYREF; default: llvm_unreachable("unexpected type"); } diff --git a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyWasmObjectWriter.cpp b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyWasmObjectWriter.cpp --- a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyWasmObjectWriter.cpp +++ b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyWasmObjectWriter.cpp @@ -73,6 +73,8 @@ switch (Modifier) { case MCSymbolRefExpr::VK_GOT: return wasm::R_WASM_GLOBAL_INDEX_LEB; + case MCSymbolRefExpr::VK_WASM_TABLEINDEX: + return wasm::R_WASM_TABLE_INDEX_LEB; case MCSymbolRefExpr::VK_WASM_TBREL: assert(SymA.isFunction()); return wasm::R_WASM_TABLE_INDEX_REL_SLEB; @@ -99,6 +101,8 @@ return wasm::R_WASM_FUNCTION_INDEX_LEB; if (SymA.isEvent()) return wasm::R_WASM_EVENT_INDEX_LEB; + if (SymA.isTable()) + return wasm::R_WASM_TABLE_INDEX_LEB; return wasm::R_WASM_MEMORY_ADDR_LEB; case FK_Data_4: if (SymA.isFunction()) diff --git a/llvm/lib/Target/WebAssembly/WebAssembly.h b/llvm/lib/Target/WebAssembly/WebAssembly.h --- a/llvm/lib/Target/WebAssembly/WebAssembly.h +++ b/llvm/lib/Target/WebAssembly/WebAssembly.h @@ -81,4 +81,12 @@ } // end namespace llvm +namespace WebAssemblyAS { +enum : unsigned { + // The maxium value for custom address-spaces. + MAX_CUSTOM_ADDRESS = 255, + ANYREF_ADDRESS = 256, // Address space for anyref +}; +} + #endif diff --git a/llvm/lib/Target/WebAssembly/WebAssembly.td b/llvm/lib/Target/WebAssembly/WebAssembly.td --- a/llvm/lib/Target/WebAssembly/WebAssembly.td +++ b/llvm/lib/Target/WebAssembly/WebAssembly.td @@ -66,6 +66,10 @@ SubtargetFeature<"mutable-globals", "HasMutableGlobals", "true", "Enable mutable globals">; +def FeatureReferenceTypes : + SubtargetFeature<"reference-types", "HasReferenceTypes", "true", + "Enable referenceTypes">; + //===----------------------------------------------------------------------===// // Architectures. //===----------------------------------------------------------------------===// diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp --- a/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp @@ -329,6 +329,7 @@ case WebAssembly::ARGUMENT_v4f32_S: case WebAssembly::ARGUMENT_v2f64: case WebAssembly::ARGUMENT_v2f64_S: + case WebAssembly::ARGUMENT_anyref: // These represent values which are live into the function entry, so there's // no instruction to emit. break; diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyExplicitLocals.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyExplicitLocals.cpp --- a/llvm/lib/Target/WebAssembly/WebAssemblyExplicitLocals.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyExplicitLocals.cpp @@ -92,6 +92,8 @@ return WebAssembly::DROP_V128; if (RC == &WebAssembly::EXNREFRegClass) return WebAssembly::DROP_EXNREF; + if (RC == &WebAssembly::ANYREFRegClass) + return WebAssembly::DROP_ANYREF; llvm_unreachable("Unexpected register class"); } @@ -109,6 +111,8 @@ return WebAssembly::LOCAL_GET_V128; if (RC == &WebAssembly::EXNREFRegClass) return WebAssembly::LOCAL_GET_EXNREF; + if (RC == &WebAssembly::ANYREFRegClass) + return WebAssembly::LOCAL_GET_ANYREF; llvm_unreachable("Unexpected register class"); } @@ -126,6 +130,8 @@ return WebAssembly::LOCAL_SET_V128; if (RC == &WebAssembly::EXNREFRegClass) return WebAssembly::LOCAL_SET_EXNREF; + if (RC == &WebAssembly::EXNREFRegClass) + return WebAssembly::LOCAL_SET_ANYREF; llvm_unreachable("Unexpected register class"); } @@ -143,6 +149,8 @@ return WebAssembly::LOCAL_TEE_V128; if (RC == &WebAssembly::EXNREFRegClass) return WebAssembly::LOCAL_TEE_EXNREF; + if (RC == &WebAssembly::ANYREFRegClass) + return WebAssembly::LOCAL_TEE_ANYREF; llvm_unreachable("Unexpected register class"); } @@ -160,6 +168,8 @@ return MVT::v16i8; if (RC == &WebAssembly::EXNREFRegClass) return MVT::exnref; + if (RC == &WebAssembly::ANYREFRegClass) + return MVT::anyref; llvm_unreachable("unrecognized register class"); } diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyFastISel.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyFastISel.cpp --- a/llvm/lib/Target/WebAssembly/WebAssemblyFastISel.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyFastISel.cpp @@ -130,6 +130,7 @@ case MVT::f32: case MVT::f64: case MVT::exnref: + case MVT::anyref: return VT; case MVT::f16: return MVT::f32; @@ -706,6 +707,10 @@ Opc = WebAssembly::ARGUMENT_exnref; RC = &WebAssembly::EXNREFRegClass; break; + case MVT::anyref: + Opc = WebAssembly::ARGUMENT_anyref; + RC = &WebAssembly::ANYREFRegClass; + break; default: return false; } @@ -824,6 +829,11 @@ : WebAssembly::PCALL_INDIRECT_exnref; ResultReg = createResultReg(&WebAssembly::EXNREFRegClass); break; + case MVT::anyref: + Opc = IsDirect ? WebAssembly::CALL_anyref + : WebAssembly::PCALL_INDIRECT_anyref; + ResultReg = createResultReg(&WebAssembly::ANYREFRegClass); + break; default: return false; } @@ -1329,6 +1339,7 @@ case MVT::v4f32: case MVT::v2f64: case MVT::exnref: + case MVT::anyref: break; default: return false; diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.h b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.h --- a/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.h +++ b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.h @@ -15,6 +15,7 @@ #ifndef LLVM_LIB_TARGET_WEBASSEMBLY_WEBASSEMBLYISELLOWERING_H #define LLVM_LIB_TARGET_WEBASSEMBLY_WEBASSEMBLYISELLOWERING_H +#include "WebAssembly.h" #include "llvm/CodeGen/TargetLowering.h" namespace llvm { @@ -51,6 +52,18 @@ /// right decision when generating code for different targets. const WebAssemblySubtarget *Subtarget; + MVT getPointerTy(const DataLayout &DL, uint32_t AS = 0) const override { + return AS == WebAssemblyAS::ANYREF_ADDRESS + ? MVT::anyref + : MVT::getIntegerVT(DL.getPointerSizeInBits(AS)); + } + + MVT getPointerMemTy(const DataLayout &DL, uint32_t AS = 0) const override { + return AS == WebAssemblyAS::ANYREF_ADDRESS + ? MVT::anyref + : MVT::getIntegerVT(DL.getPointerSizeInBits(AS)); + } + AtomicExpansionKind shouldExpandAtomicRMWInIR(AtomicRMWInst *) const override; FastISel *createFastISel(FunctionLoweringInfo &FuncInfo, const TargetLibraryInfo *LibInfo) const override; @@ -96,6 +109,7 @@ void ReplaceNodeResults(SDNode *N, SmallVectorImpl &Results, SelectionDAG &DAG) const override; + bool isNoopAddrSpaceCast(unsigned SrcAS, unsigned DestAS) const override; const char *getClearCacheBuiltinName() const override { report_fatal_error("llvm.clear_cache is not supported on wasm"); 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 @@ -13,6 +13,7 @@ #include "WebAssemblyISelLowering.h" #include "MCTargetDesc/WebAssemblyMCTargetDesc.h" +#include "WebAssembly.h" #include "WebAssemblyMachineFunctionInfo.h" #include "WebAssemblySubtarget.h" #include "WebAssemblyTargetMachine.h" @@ -65,6 +66,10 @@ addRegisterClass(MVT::v2i64, &WebAssembly::V128RegClass); addRegisterClass(MVT::v2f64, &WebAssembly::V128RegClass); } + if (Subtarget->hasReferenceTypes()) { + addRegisterClass(MVT::anyref, &WebAssembly::ANYREFRegClass); + setOperationAction(ISD::GlobalAddress, MVT::anyref, Custom); + } // Compute derived properties from the register classes. computeRegisterProperties(Subtarget->getRegisterInfo()); @@ -958,6 +963,14 @@ return Chain; } +bool WebAssemblyTargetLowering::isNoopAddrSpaceCast(unsigned SrcAS, + unsigned DestAS) const { + assert(SrcAS != DestAS && "Expected different address spaces!"); + + return SrcAS <= WebAssemblyAS::MAX_CUSTOM_ADDRESS && + DestAS <= WebAssemblyAS::MAX_CUSTOM_ADDRESS; +} + void WebAssemblyTargetLowering::ReplaceNodeResults( SDNode *N, SmallVectorImpl &Results, SelectionDAG &DAG) const { switch (N->getOpcode()) { @@ -1103,8 +1116,9 @@ EVT VT = Op.getValueType(); assert(GA->getTargetFlags() == 0 && "Unexpected target flags on generic GlobalAddressSDNode"); - if (GA->getAddressSpace() != 0) - fail(DL, DAG, "WebAssembly only expects the 0 address space"); + if (GA->getAddressSpace() != 0 && + GA->getAddressSpace() != WebAssemblyAS::ANYREF_ADDRESS) + fail(DL, DAG, "WebAssembly only expects the 0 or 256 (anyref) address space"); unsigned OperandFlags = 0; if (isPositionIndependent()) { @@ -1136,6 +1150,10 @@ } } + if (GA->getAddressSpace() == WebAssemblyAS::ANYREF_ADDRESS) { + OperandFlags = WebAssemblyII::MO_TABLE_INDEX; + } + return DAG.getNode(WebAssemblyISD::Wrapper, DL, VT, DAG.getTargetGlobalAddress(GA->getGlobal(), DL, VT, GA->getOffset(), OperandFlags)); diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyInstrCall.td b/llvm/lib/Target/WebAssembly/WebAssemblyInstrCall.td --- a/llvm/lib/Target/WebAssembly/WebAssemblyInstrCall.td +++ b/llvm/lib/Target/WebAssembly/WebAssemblyInstrCall.td @@ -60,6 +60,7 @@ defm "" : CALL; defm "" : CALL; defm "" : CALL; +defm "" : CALL; defm "" : CALL; defm "" : CALL; defm "" : CALL; @@ -142,6 +143,9 @@ def : Pat<(exnref (WebAssemblycall1 (WebAssemblywrapper tglobaladdr:$callee))), (CALL_exnref tglobaladdr:$callee)>, Requires<[HasExceptionHandling]>; +def : Pat<(anyref (WebAssemblycall1 (WebAssemblywrapper tglobaladdr:$callee))), + (CALL_anyref tglobaladdr:$callee)>, + Requires<[HasReferenceTypes]>; def : Pat<(WebAssemblycall0 (WebAssemblywrapper tglobaladdr:$callee)), (CALL_VOID tglobaladdr:$callee)>; def : Pat<(WebAssemblyretcall (WebAssemblywrapper tglobaladdr:$callee)), @@ -171,6 +175,9 @@ def : Pat<(exnref (WebAssemblycall1 (WebAssemblywrapper texternalsym:$callee))), (CALL_exnref texternalsym:$callee)>, Requires<[HasExceptionHandling]>; +def : Pat<(anyref (WebAssemblycall1 (WebAssemblywrapper texternalsym:$callee))), + (CALL_anyref texternalsym:$callee)>, + Requires<[HasReferenceTypes]>; def : Pat<(WebAssemblycall0 (WebAssemblywrapper texternalsym:$callee)), (CALL_VOID texternalsym:$callee)>; def : Pat<(WebAssemblyretcall (WebAssemblywrapper texternalsym:$callee)), diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.cpp --- a/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.cpp @@ -77,6 +77,8 @@ CopyOpcode = WebAssembly::COPY_V128; else if (RC == &WebAssembly::EXNREFRegClass) CopyOpcode = WebAssembly::COPY_EXNREF; + else if (RC == &WebAssembly::ANYREFRegClass) + CopyOpcode = WebAssembly::COPY_ANYREF; else llvm_unreachable("Unexpected register class"); 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 @@ -62,6 +62,10 @@ Predicate<"Subtarget->hasBulkMemory()">, AssemblerPredicate<"FeatureBulkMemory", "bulk-memory">; +def HasReferenceTypes : + Predicate<"Subtarget->hasReferenceTypes()">, + AssemblerPredicate<"FeatureReferenceTypes", "reference-types">; + //===----------------------------------------------------------------------===// // WebAssembly-specific DAG Node Types. //===----------------------------------------------------------------------===// @@ -141,6 +145,9 @@ let OperandType = "OPERAND_GLOBAL" in def global_op : Operand; +let OperandType = "OPERAND_TABLE" in +def table_op : Operand; + let OperandType = "OPERAND_I32IMM" in def i32imm_op : Operand; @@ -226,6 +233,7 @@ defm "": ARGUMENT; defm "": ARGUMENT; defm "": ARGUMENT; +defm "": ARGUMENT; // local.get and local.set are not generated by instruction selection; they // are implied by virtual register uses and defs. @@ -296,6 +304,7 @@ defm "" : LOCAL; defm "" : LOCAL, Requires<[HasSIMD128]>; defm "" : LOCAL, Requires<[HasExceptionHandling]>; +defm "" : LOCAL, Requires<[HasReferenceTypes]>; let isMoveImm = 1, isAsCheapAsAMove = 1, isReMaterializable = 1 in { defm CONST_I32 : I<(outs I32:$res), (ins i32imm_op:$imm), @@ -348,3 +357,4 @@ include "WebAssemblyInstrSIMD.td" include "WebAssemblyInstrRef.td" include "WebAssemblyInstrBulkMemory.td" +include "WebAssemblyInstrTable.td" diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyInstrTable.td b/llvm/lib/Target/WebAssembly/WebAssemblyInstrTable.td new file mode 100644 --- /dev/null +++ b/llvm/lib/Target/WebAssembly/WebAssemblyInstrTable.td @@ -0,0 +1,12 @@ +multiclass WebAssemblyTableGet { + let mayLoad = 1, UseNamedOperandTable = 1 in + defm "": I<(outs rc:$dst), + (ins table_op: $table, I32:$offset), + (outs), (ins table_op: $table), + [], !strconcat(Name, "\t$dst, ${offset}(${table})"), + !strconcat(Name, "\t${table}"), Opcode>; +} + +defm TABLE_GET : WebAssemblyTableGet; + +def : Pat<(anyref (load (WebAssemblywrapper anyref:$addr))), (TABLE_GET anyref:$addr, (CONST_I32 0))>; 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 @@ -64,6 +64,11 @@ WasmSym->setType(wasm::WASM_SYMBOL_TYPE_FUNCTION); } + unsigned TargetFlags = MO.getTargetFlags(); + if (TargetFlags == WebAssemblyII::MO_TABLE_INDEX) { + WasmSym->setType(wasm::WASM_SYMBOL_TYPE_TABLE); + } + return WasmSym; } @@ -90,6 +95,12 @@ return WasmSym; } + unsigned TargetFlags = MO.getTargetFlags(); + if (TargetFlags == WebAssemblyII::MO_TABLE_INDEX) { + WasmSym->setType(wasm::WASM_SYMBOL_TYPE_TABLE); + return WasmSym; + } + SmallVector Returns; SmallVector Params; if (strcmp(Name, "__cpp_exception") == 0) { @@ -130,6 +141,9 @@ switch (TargetFlags) { case WebAssemblyII::MO_NO_FLAG: break; + case WebAssemblyII::MO_TABLE_INDEX: + Kind = MCSymbolRefExpr::VK_WASM_TABLEINDEX; + break; case WebAssemblyII::MO_GOT: Kind = MCSymbolRefExpr::VK_GOT; break; diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyPeephole.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyPeephole.cpp --- a/llvm/lib/Target/WebAssembly/WebAssemblyPeephole.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyPeephole.cpp @@ -114,6 +114,9 @@ case WebAssembly::EXNREFRegClassID: CopyLocalOpc = WebAssembly::COPY_EXNREF; break; + case WebAssembly::ANYREFRegClassID: + CopyLocalOpc = WebAssembly::COPY_ANYREF; + break; default: llvm_unreachable("Unexpected register class for return operand"); } diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyRegisterInfo.td b/llvm/lib/Target/WebAssembly/WebAssemblyRegisterInfo.td --- a/llvm/lib/Target/WebAssembly/WebAssemblyRegisterInfo.td +++ b/llvm/lib/Target/WebAssembly/WebAssemblyRegisterInfo.td @@ -44,6 +44,7 @@ def V128_0: WebAssemblyReg<"%v128">; def EXNREF_0 : WebAssemblyReg<"%exnref.0">; +def ANYREF_0 : WebAssemblyReg<"%anyref.0">; // The value stack "register". This is an opaque entity which serves to order // uses and defs that must remain in LIFO order. @@ -65,3 +66,4 @@ def V128 : WebAssemblyRegClass<[v4f32, v2f64, v2i64, v4i32, v16i8, v8i16], 128, (add V128_0)>; def EXNREF : WebAssemblyRegClass<[exnref], 0, (add EXNREF_0)>; +def ANYREF : WebAssemblyRegClass<[anyref], 0, (add ANYREF_0)>; diff --git a/llvm/lib/Target/WebAssembly/WebAssemblySubtarget.h b/llvm/lib/Target/WebAssembly/WebAssemblySubtarget.h --- a/llvm/lib/Target/WebAssembly/WebAssemblySubtarget.h +++ b/llvm/lib/Target/WebAssembly/WebAssemblySubtarget.h @@ -47,6 +47,7 @@ bool HasMultivalue = false; bool HasMutableGlobals = false; bool HasTailCall = false; + bool HasReferenceTypes = false; /// String name of used CPU. std::string CPUString; @@ -104,6 +105,7 @@ bool hasMultivalue() const { return HasMultivalue; } bool hasMutableGlobals() const { return HasMutableGlobals; } bool hasTailCall() const { return HasTailCall; } + bool hasReferenceTypes() const { return HasReferenceTypes; } /// Parses features string setting specified subtarget options. Definition of /// function is auto generated by tblgen. diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp --- a/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp @@ -102,15 +102,45 @@ return *RM; } +static bool HasReferenceTypes(StringRef FS) { + bool ReferenceTypes = false; + SmallVector Features; + + FS.split(Features, ',', -1, false /* KeepEmpty */); + for (auto &Feature : Features) { + if (Feature == "reference-types" || Feature == "+reference-types") + ReferenceTypes = true; + if (Feature == "-reference-types") + ReferenceTypes = false; + } + + return ReferenceTypes; +} + +static std::string computeDataLayout(const Triple &TT, StringRef FS) { + std::string Ret = "e-m:e"; + + if (TT.isArch64Bit()) { + Ret += "-p:64:64"; + } else { + Ret += "-p:32:32"; + } + + Ret += "-i64:64-n32:64-S128"; + + if (HasReferenceTypes(FS)) { + Ret += "-ni:256"; // anyref + } + return Ret; +} + /// Create an WebAssembly architecture model. /// WebAssemblyTargetMachine::WebAssemblyTargetMachine( const Target &T, const Triple &TT, StringRef CPU, StringRef FS, const TargetOptions &Options, Optional RM, Optional CM, CodeGenOpt::Level OL, bool JIT) - : LLVMTargetMachine(T, - TT.isArch64Bit() ? "e-m:e-p:64:64-i64:64-n32:64-S128" - : "e-m:e-p:32:32-i64:64-n32:64-S128", + : LLVMTargetMachine(T, computeDataLayout(TT, FS), TT, CPU, FS, Options, getEffectiveRelocModel(RM, TT), getEffectiveCodeModel(CM, CodeModel::Large), OL), TLOF(new WebAssemblyTargetObjectFile()) { diff --git a/llvm/test/CodeGen/WebAssembly/anyref.ll b/llvm/test/CodeGen/WebAssembly/anyref.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/WebAssembly/anyref.ll @@ -0,0 +1,29 @@ +; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-disable-explicit-locals -wasm-keep-registers -mattr=+reference-types | FileCheck %s + +target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128" +target triple = "wasm32-unknown-unknown" + +declare i8 addrspace(256)* @test(i8 addrspace(256)*) + + +; CHECK-LABEL: call_test: +; CHECK: .functype call_test (anyref) -> (anyref) +define i8 addrspace(256)* @call_test(i8 addrspace(256)*) { +; CHECK: anyref.call $push0=, test, $0 + %a = call i8 addrspace(256)* @test(i8 addrspace(256)* %0) + ret i8 addrspace(256)* %a +} + +; TODO: nullref? +; define i8 addrspace(256)* @null_test() { +; ret i8 addrspace(256)* null +; } + +; TODO: Loading a anyref from a pointer +; @glob = external global i8 addrspace(256)*, align 4 +; define i8 addrspace(256)* @global_test() { +; %a = load i8 addrspace(256)*, i8 addrspace(256)** @glob +; ret i8 addrspace(256)* %a +; } + +; CHECK: .functype test (anyref) -> (anyref) diff --git a/llvm/test/CodeGen/WebAssembly/reg-argument.mir b/llvm/test/CodeGen/WebAssembly/reg-argument.mir --- a/llvm/test/CodeGen/WebAssembly/reg-argument.mir +++ b/llvm/test/CodeGen/WebAssembly/reg-argument.mir @@ -57,3 +57,14 @@ %1:exnref = ARGUMENT_exnref 0, implicit $arguments RETURN implicit-def $arguments ... +--- +name: argument_anyref +# CHECK-LABEL: argument_anyref +body: | + ; CHECK-LABEL: bb.0: + ; CHECK-NEXT: %1:anyref = ARGUMENT_anyref 0 + bb.0: + %0:i32 = CONST_I32 0, implicit-def $arguments + %1:anyref = ARGUMENT_anyref 0, implicit $arguments + RETURN implicit-def $arguments +... diff --git a/llvm/test/CodeGen/WebAssembly/reg-copy.mir b/llvm/test/CodeGen/WebAssembly/reg-copy.mir --- a/llvm/test/CodeGen/WebAssembly/reg-copy.mir +++ b/llvm/test/CodeGen/WebAssembly/reg-copy.mir @@ -66,3 +66,14 @@ %0:exnref = COPY %1:exnref RETURN implicit-def $arguments ... +--- +name: copy_anyref +# CHECK-LABEL: copy_anyref +body: | + ; CHECK-LABEL: bb.0 + ; CHECK-NEXT: %0:anyref = COPY_ANYREF %1:anyref + ; CHECK-NEXT: RETURN + bb.0: + %0:anyref = COPY %1:anyref + RETURN implicit-def $arguments +... 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 @@ -196,6 +196,7 @@ case MVT::iPTRAny: return "MVT::iPTRAny"; case MVT::Untyped: return "MVT::Untyped"; case MVT::exnref: return "MVT::exnref"; + case MVT::anyref: return "MVT::anyref"; default: llvm_unreachable("ILLEGAL VALUE TYPE!"); } }