diff --git a/clang/lib/Basic/Targets/WebAssembly.cpp b/clang/lib/Basic/Targets/WebAssembly.cpp --- a/clang/lib/Basic/Targets/WebAssembly.cpp +++ b/clang/lib/Basic/Targets/WebAssembly.cpp @@ -232,6 +232,7 @@ } if (Feature == "+reference-types") { HasReferenceTypes = true; + resetDataLayout("e-m:e-p:32:32-i64:64-n32:64-S128-ni:256"); continue; } if (Feature == "-reference-types") { diff --git a/lld/wasm/WriterUtils.cpp b/lld/wasm/WriterUtils.cpp --- a/lld/wasm/WriterUtils.cpp +++ b/lld/wasm/WriterUtils.cpp @@ -30,10 +30,12 @@ return "f64"; case ValType::V128: return "v128"; - case ValType::EXNREF: - return "exnref"; + case ValType::FUNCREF: + return "funcref"; case ValType::EXTERNREF: return "externref"; + case ValType::EXNREF: + return "exnref"; } llvm_unreachable("Invalid wasm::ValType"); } 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 @@ -325,6 +325,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. @@ -360,8 +361,9 @@ F32 = WASM_TYPE_F32, F64 = WASM_TYPE_F64, V128 = WASM_TYPE_V128, - EXNREF = WASM_TYPE_EXNREF, + FUNCREF = WASM_TYPE_FUNCREF, EXTERNREF = WASM_TYPE_EXTERNREF, + EXNREF = WASM_TYPE_EXNREF, }; struct WasmSignature { 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,10 +15,11 @@ 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_GLOBAL_INDEX_I32, 13) -WASM_RELOC(R_WASM_MEMORY_ADDR_LEB64, 14) -WASM_RELOC(R_WASM_MEMORY_ADDR_SLEB64, 15) -WASM_RELOC(R_WASM_MEMORY_ADDR_I64, 16) -WASM_RELOC(R_WASM_MEMORY_ADDR_REL_SLEB64, 17) -WASM_RELOC(R_WASM_TABLE_INDEX_SLEB64, 18) -WASM_RELOC(R_WASM_TABLE_INDEX_I64, 19) +WASM_RELOC(R_WASM_TABLE_INDEX_LEB, 13) +WASM_RELOC(R_WASM_GLOBAL_INDEX_I32, 14) +WASM_RELOC(R_WASM_MEMORY_ADDR_LEB64, 15) +WASM_RELOC(R_WASM_MEMORY_ADDR_SLEB64, 16) +WASM_RELOC(R_WASM_MEMORY_ADDR_I64, 17) +WASM_RELOC(R_WASM_MEMORY_ADDR_REL_SLEB64, 18) +WASM_RELOC(R_WASM_TABLE_INDEX_SLEB64, 19) +WASM_RELOC(R_WASM_TABLE_INDEX_I64, 20) 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 @@ -346,7 +346,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 @@ -188,6 +188,7 @@ def isVoid : ValueType<0 , 153>; // Produces no value def untyped: ValueType<8 , 154>; // Produces an untyped value def exnref : ValueType<0 , 155>; // WebAssembly's exnref type +def externref: ValueType<0, 156>; // WebAssembly's externref 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 @@ -316,9 +316,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 @@ -62,6 +62,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); @@ -287,6 +292,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 EventSection = 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 @@ -238,10 +238,11 @@ // unspecified type. The register class // will be determined by the opcode. - exnref = 155, // WebAssembly's exnref type + exnref = 155, // WebAssembly's exnref type + externref = 156, // WebAssembly's externref type - FIRST_VALUETYPE = 1, // This is always the beginning of the list. - LAST_VALUETYPE = 156, // This always remains at the end of the list. + FIRST_VALUETYPE = 1, // This is always the beginning of the list. + LAST_VALUETYPE = 157, // 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 @@ -919,6 +920,7 @@ case v1024f32: return TypeSize::Fixed(32768); case v2048i32: case v2048f32: return TypeSize::Fixed(65536); + case externref: 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 @@ -6232,6 +6232,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 @@ -4035,10 +4035,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); SDValue L = DAG.getLoad(MemVTs[i], dl, Root, A, MachinePointerInfo(SV, Offsets[i]), Alignment, 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 @@ -168,6 +168,7 @@ case MVT::Metadata:return "Metadata"; case MVT::Untyped: return "Untyped"; case MVT::exnref : return "exnref"; + case MVT::externref : return "externref"; } } @@ -467,6 +468,9 @@ case MVT::nxv8f64: return ScalableVectorType::get(Type::getDoubleTy(Context), 8); case MVT::Metadata: return Type::getMetadataTy(Context); + case MVT::externref: + 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 @@ -337,6 +337,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"; @@ -472,6 +473,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 @@ -258,6 +258,7 @@ unsigned NumFunctionImports = 0; unsigned NumGlobalImports = 0; unsigned NumEventImports = 0; + unsigned NumTableImports = 0; uint32_t SectionCount = 0; // TargetObjectWriter wrappers. @@ -575,6 +576,7 @@ case wasm::R_WASM_GLOBAL_INDEX_LEB: case wasm::R_WASM_GLOBAL_INDEX_I32: 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]; @@ -678,6 +680,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<5>(Stream, Value, Offset); break; case wasm::R_WASM_MEMORY_ADDR_LEB64: @@ -1023,6 +1026,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) @@ -1215,6 +1219,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 @@ -1271,6 +1276,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_EXTERNREF; + Imports.push_back(Import); + assert(WasmIndices.count(&WS) == 0); + WasmIndices[&WS] = NumTableImports++; } } } @@ -1500,7 +1514,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 @@ -483,9 +483,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); @@ -493,6 +495,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--) { @@ -632,6 +636,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); @@ -823,6 +848,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: @@ -964,8 +994,10 @@ HasMemory64 = true; 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_EXTERNREF) return make_error("Invalid table element type", object_error::parse_failed); break; @@ -1009,7 +1041,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 externref here when reference-types is enabled? + Tables.back().ElemType != wasm::WASM_TYPE_EXTERNREF) { return make_error("Invalid table element type", object_error::parse_failed); } @@ -1137,6 +1171,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(); } @@ -1149,6 +1191,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 @@ -498,6 +498,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); @@ -553,6 +555,7 @@ ECase(GLOBAL); ECase(SECTION); ECase(EVENT); + ECase(TABLE); #undef ECase } @@ -599,6 +602,7 @@ IO &IO, WasmYAML::TableType &Type) { #define ECase(X) IO.enumCase(Type, #X, wasm::WASM_TYPE_##X); ECase(FUNCREF); + ECase(EXTERNREF); #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 @@ -336,6 +336,7 @@ .Case("f64", WebAssembly::BlockType::F64) .Case("v128", WebAssembly::BlockType::V128) .Case("exnref", WebAssembly::BlockType::Exnref) + .Case("externref", WebAssembly::BlockType::Externref) .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_OFFSET64: 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 @@ -318,6 +318,8 @@ return "v128"; case wasm::WASM_TYPE_FUNCREF: return "funcref"; + case wasm::WASM_TYPE_EXTERNREF: + return "externref"; 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 @@ -44,6 +44,8 @@ OPERAND_LOCAL, /// Global index. OPERAND_GLOBAL, + /// Table index. + OPERAND_TABLE, /// 32-bit integer immediates. OPERAND_I32IMM, /// 64-bit integer immediates. @@ -100,6 +102,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 @@ -130,6 +135,7 @@ F64 = unsigned(wasm::ValType::F64), V128 = unsigned(wasm::ValType::V128), Exnref = unsigned(wasm::ValType::EXNREF), + Externref = unsigned(wasm::ValType::EXTERNREF), // 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 @@ -296,6 +302,8 @@ case WebAssembly::ARGUMENT_v2f64_S: case WebAssembly::ARGUMENT_exnref: case WebAssembly::ARGUMENT_exnref_S: + case WebAssembly::ARGUMENT_externref: + case WebAssembly::ARGUMENT_externref_S: return true; default: return false; @@ -316,6 +324,8 @@ case WebAssembly::COPY_V128_S: case WebAssembly::COPY_EXNREF: case WebAssembly::COPY_EXNREF_S: + case WebAssembly::COPY_EXTERNREF: + case WebAssembly::COPY_EXTERNREF_S: return true; default: return false; @@ -336,6 +346,8 @@ case WebAssembly::TEE_V128_S: case WebAssembly::TEE_EXNREF: case WebAssembly::TEE_EXNREF_S: + case WebAssembly::TEE_EXTERNREF: + case WebAssembly::TEE_EXTERNREF_S: return true; default: return false; 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::externref: + return wasm::ValType::EXTERNREF; 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; @@ -102,6 +104,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 WebAssembly::fixup_uleb128_i64: assert(SymA.isData()); 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 @@ -96,4 +96,12 @@ } // end namespace llvm +namespace WebAssemblyAS { +enum : unsigned { + // The maxium value for custom address-spaces. + MAX_CUSTOM_ADDRESS = 255, + EXTERNREF_ADDRESS = 256, // Address space for externref +}; +} + #endif 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 @@ -346,6 +346,7 @@ case WebAssembly::ARGUMENT_v4f32_S: case WebAssembly::ARGUMENT_v2f64: case WebAssembly::ARGUMENT_v2f64_S: + case WebAssembly::ARGUMENT_externref: // 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 @@ -98,6 +98,8 @@ return WebAssembly::DROP_V128; if (RC == &WebAssembly::EXNREFRegClass) return WebAssembly::DROP_EXNREF; + if (RC == &WebAssembly::EXTERNREFRegClass) + return WebAssembly::DROP_EXTERNREF; llvm_unreachable("Unexpected register class"); } @@ -115,6 +117,8 @@ return WebAssembly::LOCAL_GET_V128; if (RC == &WebAssembly::EXNREFRegClass) return WebAssembly::LOCAL_GET_EXNREF; + if (RC == &WebAssembly::EXTERNREFRegClass) + return WebAssembly::LOCAL_GET_EXTERNREF; llvm_unreachable("Unexpected register class"); } @@ -132,6 +136,8 @@ return WebAssembly::LOCAL_SET_V128; if (RC == &WebAssembly::EXNREFRegClass) return WebAssembly::LOCAL_SET_EXNREF; + if (RC == &WebAssembly::EXNREFRegClass) + return WebAssembly::LOCAL_SET_EXTERNREF; llvm_unreachable("Unexpected register class"); } @@ -149,6 +155,8 @@ return WebAssembly::LOCAL_TEE_V128; if (RC == &WebAssembly::EXNREFRegClass) return WebAssembly::LOCAL_TEE_EXNREF; + if (RC == &WebAssembly::EXTERNREFRegClass) + return WebAssembly::LOCAL_TEE_EXTERNREF; llvm_unreachable("Unexpected register class"); } @@ -166,6 +174,8 @@ return MVT::v16i8; if (RC == &WebAssembly::EXNREFRegClass) return MVT::exnref; + if (RC == &WebAssembly::EXTERNREFRegClass) + return MVT::externref; 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::externref: return VT; case MVT::f16: return MVT::f32; @@ -709,6 +710,10 @@ Opc = WebAssembly::ARGUMENT_exnref; RC = &WebAssembly::EXNREFRegClass; break; + case MVT::externref: + Opc = WebAssembly::ARGUMENT_externref; + RC = &WebAssembly::EXTERNREFRegClass; + break; default: return false; } @@ -810,6 +815,9 @@ case MVT::exnref: ResultReg = createResultReg(&WebAssembly::EXNREFRegClass); break; + case MVT::externref: + ResultReg = createResultReg(&WebAssembly::EXTERNREFRegClass); + break; default: return false; } @@ -1323,6 +1331,7 @@ case MVT::v4f32: case MVT::v2f64: case MVT::exnref: + case MVT::externref: 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 { @@ -50,6 +51,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::EXTERNREF_ADDRESS + ? MVT::externref + : MVT::getIntegerVT(DL.getPointerSizeInBits(AS)); + } + + MVT getPointerMemTy(const DataLayout &DL, uint32_t AS = 0) const override { + return AS == WebAssemblyAS::EXTERNREF_ADDRESS + ? MVT::externref + : MVT::getIntegerVT(DL.getPointerSizeInBits(AS)); + } + AtomicExpansionKind shouldExpandAtomicRMWInIR(AtomicRMWInst *) const override; FastISel *createFastISel(FunctionLoweringInfo &FuncInfo, const TargetLibraryInfo *LibInfo) const override; @@ -95,6 +108,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" @@ -64,6 +65,10 @@ addRegisterClass(MVT::v2i64, &WebAssembly::V128RegClass); addRegisterClass(MVT::v2f64, &WebAssembly::V128RegClass); } + if (Subtarget->hasReferenceTypes()) { + addRegisterClass(MVT::externref, &WebAssembly::EXTERNREFRegClass); + setOperationAction(ISD::GlobalAddress, MVT::externref, Custom); + } // Compute derived properties from the register classes. computeRegisterProperties(Subtarget->getRegisterInfo()); @@ -1080,6 +1085,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()) { @@ -1225,8 +1238,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::EXTERNREF_ADDRESS) + fail(DL, DAG, "WebAssembly only expects the 0 or 256 (externref) address space"); unsigned OperandFlags = 0; if (isPositionIndependent()) { @@ -1258,6 +1272,10 @@ } } + if (GA->getAddressSpace() == WebAssemblyAS::EXTERNREF_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/WebAssemblyInstrInfo.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.cpp --- a/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.cpp @@ -78,6 +78,8 @@ CopyOpcode = WebAssembly::COPY_V128; else if (RC == &WebAssembly::EXNREFRegClass) CopyOpcode = WebAssembly::COPY_EXNREF; + else if (RC == &WebAssembly::EXTERNREFRegClass) + CopyOpcode = WebAssembly::COPY_EXTERNREF; 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 @@ -136,6 +136,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; @@ -237,6 +240,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. @@ -307,6 +311,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), @@ -365,3 +370,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<(externref (load (WebAssemblywrapper externref:$addr))), (TABLE_GET externref:$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 @@ -61,6 +61,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; } @@ -88,6 +93,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) { @@ -128,6 +139,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::EXTERNREFRegClassID: + CopyLocalOpc = WebAssembly::COPY_EXTERNREF; + 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 EXTERNREF_0 : WebAssemblyReg<"%externref.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 EXTERNREF : WebAssemblyRegClass<[externref], 0, (add EXTERNREF_0)>; 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 @@ -112,15 +112,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"; // little endian, mangling elf + + if (TT.isArch64Bit()) { + Ret += "-p:64:64"; + } else { + Ret += "-p:32:32"; + } + + Ret += "-i64:64-n32:64-S128"; + + if (HasReferenceTypes(FS)) { + Ret += "-ni:256"; // externref + } + 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/externref.ll b/llvm/test/CodeGen/WebAssembly/externref.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/WebAssembly/externref.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-ni:256" +target triple = "wasm32-unknown-unknown" + +declare i8 addrspace(256)* @test(i8 addrspace(256)*) + + +; CHECK-LABEL: call_test: +; CHECK: .functype call_test (externref) -> (externref) +define i8 addrspace(256)* @call_test(i8 addrspace(256)*) { +; CHECK: 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 externref 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 (externref) -> (externref) 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_externref +# CHECK-LABEL: argument_externref +body: | + ; CHECK-LABEL: bb.0: + ; CHECK-NEXT: %1:externref = ARGUMENT_externref 0 + bb.0: + %0:i32 = CONST_I32 0, implicit-def $arguments + %1:externref = ARGUMENT_externref 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_externref +# CHECK-LABEL: copy_externref +body: | + ; CHECK-LABEL: bb.0 + ; CHECK-NEXT: %0:externref = COPY_EXTERNREF %1:externref + ; CHECK-NEXT: RETURN + bb.0: + %0:externref = COPY %1:externref + 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 @@ -219,6 +219,7 @@ case MVT::iPTRAny: return "MVT::iPTRAny"; case MVT::Untyped: return "MVT::Untyped"; case MVT::exnref: return "MVT::exnref"; + case MVT::externref: return "MVT::externref"; default: llvm_unreachable("ILLEGAL VALUE TYPE!"); } }