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 @@ -182,6 +182,10 @@ return "f64"; case ValType::V128: return "v128"; + case ValType::FUNCREF: + return "func"; + 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 @@ -224,6 +224,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 @@ -300,6 +301,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. @@ -334,6 +336,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 @@ -247,7 +247,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)); } @@ -1036,7 +1036,7 @@ const bool OptForSize = SI->getParent()->getParent()->hasOptSize(); const unsigned MinDensity = getMinimumJumpTableDensity(OptForSize); const unsigned MaxJumpTableSize = getMaximumJumpTableSize(); - + // Check whether the number of cases is small enough and // the range is dense enough for a jump table. if ((OptForSize || Range <= MaxJumpTableSize) && 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 @@ -161,6 +161,7 @@ def isVoid : ValueType<0 , 127>; // Produces no value def untyped: ValueType<8 , 128>; // Produces an untyped value def exnref: ValueType<0, 129>; // WebAssembly's exnref type +def anyref: ValueType<0, 130>; // 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 @@ -292,9 +292,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 @@ -208,9 +208,10 @@ // will be determined by the opcode. exnref = 129, // WebAssembly's exnref type + anyref = 130, // WebAssembly's anyref type FIRST_VALUETYPE = 1, // This is always the beginning of the list. - LAST_VALUETYPE = 130, // This always remains at the end of the list. + LAST_VALUETYPE = 131, // 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 @@ -777,7 +778,8 @@ case v1024f32: return 32768; case v2048i32: case v2048f32: return 65536; - case exnref: return 0; // opaque type + case exnref: + case anyref: return 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 @@ -1856,7 +1856,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; @@ -5733,6 +5733,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 @@ -4064,10 +4064,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 @@ -250,6 +250,7 @@ case MVT::Metadata:return "Metadata"; case MVT::Untyped: return "Untyped"; case MVT::exnref : return "exnref"; + case MVT::anyref : return "anyref"; } } @@ -344,91 +345,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 @@ -310,6 +310,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"; @@ -427,6 +428,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. @@ -584,6 +585,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]; @@ -681,6 +683,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: @@ -974,6 +977,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) @@ -1166,6 +1170,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 @@ -1220,6 +1225,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++; } } } @@ -1416,7 +1430,16 @@ } LLVM_DEBUG(dbgs() << " -> event index: " << WasmIndices.find(&WS)->second << "\n"); - + } else if (WS.isTable()) { + unsigned Index; + 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: @@ -918,8 +948,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; @@ -962,7 +994,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); } @@ -1085,6 +1119,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(); } @@ -1097,6 +1139,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/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); @@ -546,6 +548,7 @@ ECase(GLOBAL); ECase(SECTION); ECase(EVENT); + ECase(TABLE); #undef ECase } @@ -558,6 +561,7 @@ ECase(F64); ECase(V128); ECase(FUNCREF); + ECase(ANYREF); ECase(FUNC); ECase(NORESULT); #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/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 @@ -196,6 +196,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 @@ -290,6 +290,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 @@ -154,6 +154,7 @@ case WebAssembly::OPERAND_OFFSET32: 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 @@ -131,6 +136,7 @@ F64 = 0x7C, V128 = 0x7B, Exnref = 0x68, + Anyref = 0x6F, Invalid = 0x00 }; @@ -387,6 +393,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; @@ -407,6 +415,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; @@ -427,6 +437,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; @@ -459,6 +471,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; @@ -493,6 +507,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; @@ -536,6 +552,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: @@ -556,6 +574,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 @@ -148,6 +148,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 @@ -72,6 +72,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; @@ -98,6 +100,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/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 { @@ -43,6 +44,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; @@ -88,6 +101,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()); @@ -941,6 +946,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()) { @@ -1083,8 +1096,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 1 address space"); unsigned OperandFlags = 0; if (isPositionIndependent()) { @@ -1116,6 +1130,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; @@ -171,6 +172,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/WebAssemblyInstrControl.td b/llvm/lib/Target/WebAssembly/WebAssemblyInstrControl.td --- a/llvm/lib/Target/WebAssembly/WebAssemblyInstrControl.td +++ b/llvm/lib/Target/WebAssembly/WebAssemblyInstrControl.td @@ -115,6 +115,7 @@ defm "": RETURN; defm "": RETURN; defm "": RETURN; + defm "": RETURN; defm "": SIMD_RETURN; defm "": SIMD_RETURN; defm "": SIMD_RETURN; 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. //===----------------------------------------------------------------------===// @@ -140,6 +144,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; @@ -225,6 +232,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. @@ -295,6 +303,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), @@ -347,3 +356,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/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 @@ -109,8 +109,9 @@ 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", + TT.isArch64Bit() + ? "e-m:e-p:64:64-i64:64-n32:64-S128-ni:256" + : "e-m:e-p:32:32-i64:64-n32:64-S128-ni:256", TT, CPU, FS, Options, getEffectiveRelocModel(RM, TT), getEffectiveCodeModel(CM, CodeModel::Large), OL), TLOF(new WebAssemblyTargetObjectFile()) { diff --git a/llvm/tools/yaml2obj/yaml2wasm.cpp b/llvm/tools/yaml2obj/yaml2wasm.cpp --- a/llvm/tools/yaml2obj/yaml2wasm.cpp +++ b/llvm/tools/yaml2obj/yaml2wasm.cpp @@ -174,6 +174,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/utils/TableGen/CodeGenTarget.cpp b/llvm/utils/TableGen/CodeGenTarget.cpp --- a/llvm/utils/TableGen/CodeGenTarget.cpp +++ b/llvm/utils/TableGen/CodeGenTarget.cpp @@ -192,6 +192,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!"); } }