diff --git a/include/llvm/MC/MCSymbolWasm.h b/include/llvm/MC/MCSymbolWasm.h index 49d57919f6f..14b3a5d8e94 100644 --- a/include/llvm/MC/MCSymbolWasm.h +++ b/include/llvm/MC/MCSymbolWasm.h @@ -26,7 +26,7 @@ class MCSymbolWasm : public MCSymbol { Optional ExportName; wasm::WasmSignature *Signature = nullptr; Optional GlobalType; - Optional TableType; + Optional TableType; Optional EventType; /// An expression describing how to calculate the size of a symbol. If a @@ -108,7 +108,7 @@ public: bool isFunctionTable() const { return isTable() && hasTableType() && - getTableType() == wasm::ValType::FUNCREF; + getTableType().ElemType == wasm::WASM_TYPE_FUNCREF; } void setFunctionTable() { setType(wasm::WASM_SYMBOL_TYPE_TABLE); @@ -131,11 +131,17 @@ public: void setGlobalType(wasm::WasmGlobalType GT) { GlobalType = GT; } bool hasTableType() const { return TableType.hasValue(); } - wasm::ValType getTableType() const { + const wasm::WasmTableType &getTableType() const { assert(hasTableType()); return TableType.getValue(); } - void setTableType(wasm::ValType TT) { TableType = TT; } + void setTableType(wasm::WasmTableType TT) { TableType = TT; } + void setTableType(wasm::ValType VT) { + // Declare a table with element type VT and no limits (min size 0, no max + // size). + wasm::WasmLimits Limits = {wasm::WASM_LIMITS_FLAG_NONE, 0, 0}; + setTableType({uint8_t(VT), Limits}); + } const wasm::WasmEventType &getEventType() const { assert(EventType.hasValue()); diff --git a/lib/MC/WasmObjectWriter.cpp b/lib/MC/WasmObjectWriter.cpp index 2a679ca687d..0eda8b5a323 100644 --- a/lib/MC/WasmObjectWriter.cpp +++ b/lib/MC/WasmObjectWriter.cpp @@ -1338,12 +1338,7 @@ void WasmObjectWriter::prepareImports( Import.Module = WS.getImportModule(); Import.Field = WS.getImportName(); Import.Kind = wasm::WASM_EXTERNAL_TABLE; - wasm::ValType ElemType = WS.getTableType(); - Import.Table.ElemType = uint8_t(ElemType); - // FIXME: Extend table type to include limits? For now we don't specify - // a min or max which does not place any restrictions on the size of the - // imported table. - Import.Table.Limits = {wasm::WASM_LIMITS_FLAG_NONE, 0, 0}; + Import.Table = WS.getTableType(); Imports.push_back(Import); assert(WasmIndices.count(&WS) == 0); WasmIndices[&WS] = NumTableImports++; @@ -1626,9 +1621,7 @@ uint64_t WasmObjectWriter::writeOneObject(MCAssembler &Asm, if (WS.isDefined()) { wasm::WasmTable Table; Table.Index = NumTableImports + Tables.size(); - Table.Type.ElemType = static_cast(WS.getTableType()); - // FIXME: Work on custom limits is ongoing - Table.Type.Limits = {wasm::WASM_LIMITS_FLAG_NONE, 0, 0}; + Table.Type = WS.getTableType(); assert(WasmIndices.count(&WS) == 0); WasmIndices[&WS] = Table.Index; Tables.push_back(Table); diff --git a/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp b/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp index c1706735115..d57c7ec1718 100644 --- a/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp +++ b/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp @@ -169,6 +169,11 @@ struct WebAssemblyOperand : public MCParsedAsmOperand { } }; +// Perhaps this should go somewhere common. +static wasm::WasmLimits DefaultLimits() { + return {wasm::WASM_LIMITS_FLAG_NONE, 0, 0}; +} + static MCSymbolWasm *GetOrCreateFunctionTableSymbol(MCContext &Ctx, const StringRef &Name) { MCSymbolWasm *Sym = cast_or_null(Ctx.lookupSymbol(Name)); @@ -487,6 +492,28 @@ public: WebAssemblyOperand::IntOp{static_cast(BT)})); } + bool parseLimits(wasm::WasmLimits *Limits) { + auto Tok = Lexer.getTok(); + if (!Tok.is(AsmToken::Integer)) + return error("Expected integer constant, instead got: ", Tok); + int64_t Val = Tok.getIntVal(); + assert(Val >= 0); + Limits->Minimum = Val; + Parser.Lex(); + + if (isNext(AsmToken::Comma)) { + Limits->Flags |= wasm::WASM_LIMITS_FLAG_HAS_MAX; + auto Tok = Lexer.getTok(); + if (!Tok.is(AsmToken::Integer)) + return error("Expected integer constant, instead got: ", Tok); + int64_t Val = Tok.getIntVal(); + assert(Val >= 0); + Limits->Maximum = Val; + Parser.Lex(); + } + return false; + } + bool parseFunctionTableOperand(std::unique_ptr *Op) { if (STI->checkFeatures("+reference-types")) { // If the reference-types feature is enabled, there is an explicit table @@ -819,24 +846,31 @@ public: } if (DirectiveID.getString() == ".tabletype") { + // .tabletype SYM, ELEMTYPE[, MINSIZE[, MAXSIZE]] auto SymName = expectIdent(); if (SymName.empty()) return true; if (expect(AsmToken::Comma, ",")) return true; - auto TypeTok = Lexer.getTok(); - auto TypeName = expectIdent(); - if (TypeName.empty()) + + auto ElemTypeTok = Lexer.getTok(); + auto ElemTypeName = expectIdent(); + if (ElemTypeName.empty()) + return true; + Optional ElemType = parseType(ElemTypeName); + if (!ElemType) + return error("Unknown type in .tabletype directive: ", ElemTypeTok); + + wasm::WasmLimits Limits = DefaultLimits(); + if (isNext(AsmToken::Comma) && parseLimits(&Limits)) return true; - auto Type = parseType(TypeName); - if (!Type) - return error("Unknown type in .tabletype directive: ", TypeTok); // Now that we have the name and table type, we can actually create the // symbol auto WasmSym = cast(Ctx.getOrCreateSymbol(SymName)); WasmSym->setType(wasm::WASM_SYMBOL_TYPE_TABLE); - WasmSym->setTableType(Type.getValue()); + wasm::WasmTableType Type = {uint8_t(ElemType.getValue()), Limits}; + WasmSym->setTableType(Type); TOut.emitTableType(WasmSym); return expect(AsmToken::EndOfStatement, "EOL"); } diff --git a/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.cpp b/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.cpp index 652d7a00a63..3dd961efca4 100644 --- a/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.cpp +++ b/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.cpp @@ -79,8 +79,15 @@ void WebAssemblyTargetAsmStreamer::emitGlobalType(const MCSymbolWasm *Sym) { void WebAssemblyTargetAsmStreamer::emitTableType(const MCSymbolWasm *Sym) { assert(Sym->isTable()); + const wasm::WasmTableType &Type = Sym->getTableType(); OS << "\t.tabletype\t" << Sym->getName() << ", " - << WebAssembly::typeToString(Sym->getTableType()); + << WebAssembly::typeToString(static_cast(Type.ElemType)); + bool HasMaximum = Type.Limits.Flags & wasm::WASM_LIMITS_FLAG_HAS_MAX; + if (Type.Limits.Minimum != 0 || HasMaximum) { + OS << ", " << Type.Limits.Minimum; + if (HasMaximum) + OS << ", " << Type.Limits.Maximum; + } OS << '\n'; } diff --git a/test/MC/WebAssembly/tables.s b/test/MC/WebAssembly/tables.s index b1bf1a98864..a682a738445 100644 --- a/test/MC/WebAssembly/tables.s +++ b/test/MC/WebAssembly/tables.s @@ -16,9 +16,9 @@ bar: .tabletype bar, funcref table1: - .tabletype table1, funcref + .tabletype table1, funcref, 42 table2: - .tabletype table2, funcref + .tabletype table2, funcref, 42, 100 # Table instructions @@ -132,11 +132,13 @@ table_fill: # BIN-NEXT: - Index: 2 # BIN-NEXT: ElemType: FUNCREF # BIN-NEXT: Limits: -# BIN-NEXT: Minimum: 0x0 +# BIN-NEXT: Minimum: 0x2A # BIN-NEXT: - Index: 3 # BIN-NEXT: ElemType: FUNCREF # BIN-NEXT: Limits: -# BIN-NEXT: Minimum: 0x0 +# BIN-NEXT: Flags: [ HAS_MAX ] +# BIN-NEXT: Minimum: 0x2A +# BIN-NEXT: Maximum: 0x64 # BIN: - Type: CODE # BIN-NEXT: Relocations: