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 @@ -110,6 +110,12 @@ // address relative the __table_base wasm global. // Only applicable to function symbols. MO_TABLE_BASE_REL, + + // The symbol declares a externref table + MO_SYM_IS_EXTERNREF_TABLE, + + // The symbol declares a funcref table + MO_SYM_IS_FUNCREF_TABLE, }; } // end namespace WebAssemblyII 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 @@ -1517,6 +1517,7 @@ const SDValue &Offset = SN->getOffset(); if (IsWebAssemblyTableWithOffset(Base)) { + if (!Offset->isUndef()) report_fatal_error( "unexpected offset when loading from webassembly table", false); @@ -1528,6 +1529,19 @@ report_fatal_error("failed pattern matching for lowering table store", false); + // GA is a symbol referring to a table, therefore we need to set the + // type to be a table so that the proper .tabletype directives are + // generated. We cannot set TargetFlags on an existing GA, but we can create + // a new GA with the table flags set. + assert(GA->getNumValues() == 1); + GlobalAddressSDNode *NewGA = + cast(DAG.getTargetGlobalAddress( + GA->getGlobal(), DL, GA->getValueType(0), GA->getOffset(), + WebAssemblyII::MO_TABLE_BASE_REL)); + DAG.ReplaceAllUsesWith(GA, NewGA); + DAG.RemoveDeadNode(GA); + GA = NewGA; + SDVTList Tys = DAG.getVTList(MVT::Other); SDValue TableSetOps[] = {SN->getChain(), SDValue(GA, 0), Idx, Value}; SDValue TableSet = @@ -1580,6 +1594,16 @@ report_fatal_error("failed pattern matching for lowering table load", false); + // As in LowerStore, we need to recreate GA with the proper table flags + assert(GA->getNumValues() == 1); + GlobalAddressSDNode *NewGA = + cast(DAG.getTargetGlobalAddress( + GA->getGlobal(), DL, GA->getValueType(0), GA->getOffset(), + WebAssemblyII::MO_TABLE_BASE_REL)); + DAG.ReplaceAllUsesWith(GA, NewGA); + DAG.RemoveDeadNode(GA); + GA = NewGA; + SDVTList Tys = DAG.getVTList(LN->getValueType(0), MVT::Other); SDValue TableGetOps[] = {LN->getChain(), SDValue(GA, 0), Idx}; SDValue TableGet = diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyInstrTable.td b/llvm/lib/Target/WebAssembly/WebAssemblyInstrTable.td --- a/llvm/lib/Target/WebAssembly/WebAssemblyInstrTable.td +++ b/llvm/lib/Target/WebAssembly/WebAssemblyInstrTable.td @@ -52,12 +52,9 @@ 0xfc11>; foreach vt = rc.RegTypes in { - def : Pat<(vt (WebAssemblyTableGet (WebAssemblyWrapper tglobaladdr:$table), i32:$idx)), + def : Pat<(vt (WebAssemblyTableGet tglobaladdr:$table, i32:$idx)), (!cast("TABLE_GET_" # rc) tglobaladdr:$table, i32:$idx)>; - def : Pat<(WebAssemblyTableSet - (WebAssemblyWrapper tglobaladdr:$table), - i32:$idx, - vt:$src), + def : Pat<(WebAssemblyTableSet tglobaladdr:$table, i32:$idx, vt:$src), (!cast("TABLE_SET_" # rc) tglobaladdr:$table, i32:$idx, vt:$src)>; } } 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 @@ -120,6 +120,8 @@ MCOperand WebAssemblyMCInstLower::lowerSymbolOperand(const MachineOperand &MO, MCSymbol *Sym) const { MCSymbolRefExpr::VariantKind Kind = MCSymbolRefExpr::VK_None; + bool IsTable = false; + wasm::ValType TableType; unsigned TargetFlags = MO.getTargetFlags(); switch (TargetFlags) { @@ -140,6 +142,14 @@ case WebAssemblyII::MO_TABLE_BASE_REL: Kind = MCSymbolRefExpr::VK_WASM_TBREL; break; + case WebAssemblyII::MO_SYM_IS_EXTERNREF_TABLE: + IsTable = true; + TableType = wasm::ValType::EXTERNREF; + break; + case WebAssemblyII::MO_SYM_IS_FUNCREF_TABLE: + IsTable = true; + TableType = wasm::ValType::FUNCREF; + break; default: llvm_unreachable("Unknown target flag on GV operand"); } @@ -147,7 +157,7 @@ const MCExpr *Expr = MCSymbolRefExpr::create(Sym, Kind, Ctx); if (MO.getOffset() != 0) { - const auto *WasmSym = cast(Sym); + auto *WasmSym = cast(Sym); if (TargetFlags == WebAssemblyII::MO_GOT) report_fatal_error("GOT symbol references do not support offsets"); if (WasmSym->isFunction()) @@ -159,6 +169,11 @@ if (WasmSym->isTable()) report_fatal_error("Table indexes with offsets not supported"); + if (IsTable) { + WasmSym->setType(wasm::WASM_SYMBOL_TYPE_TABLE); + WasmSym->setTableType(TableType); + } + Expr = MCBinaryExpr::createAdd( Expr, MCConstantExpr::create(MO.getOffset(), Ctx), Ctx); } diff --git a/llvm/test/CodeGen/WebAssembly/externref-tableget.ll b/llvm/test/CodeGen/WebAssembly/externref-tableget.ll --- a/llvm/test/CodeGen/WebAssembly/externref-tableget.ll +++ b/llvm/test/CodeGen/WebAssembly/externref-tableget.ll @@ -73,4 +73,4 @@ ret %externref %ref } -; CHECK: .globl externref_table +; CHECK: .tabletype externref_table, externref diff --git a/llvm/test/CodeGen/WebAssembly/externref-tableset.ll b/llvm/test/CodeGen/WebAssembly/externref-tableset.ll --- a/llvm/test/CodeGen/WebAssembly/externref-tableset.ll +++ b/llvm/test/CodeGen/WebAssembly/externref-tableset.ll @@ -79,4 +79,4 @@ ret void } -; CHECK: .globl externref_table +; CHECK: .tabletype externref_table, externref diff --git a/llvm/test/CodeGen/WebAssembly/funcref-table_call.ll b/llvm/test/CodeGen/WebAssembly/funcref-table_call.ll --- a/llvm/test/CodeGen/WebAssembly/funcref-table_call.ll +++ b/llvm/test/CodeGen/WebAssembly/funcref-table_call.ll @@ -13,7 +13,7 @@ ret void } -; CHECK: .tabletype __funcref_call_table, funcref, 1 +; CHECK: .tabletype __funcref_call_table, funcref, 1 ; CHECK-LABEL: call_funcref_from_table: ; CHECK-NEXT: .functype call_funcref_from_table (i32) -> () @@ -28,6 +28,5 @@ ; CHECK-NEXT: table.set __funcref_call_table ; CHECK-NEXT: end_function +; CHECK: .tabletype funcref_table, funcref -; CHECK: .globl funcref_table -; CHECK-NEXT .globaltype funcref_table, funcref diff --git a/llvm/test/CodeGen/WebAssembly/funcref-tableget.ll b/llvm/test/CodeGen/WebAssembly/funcref-tableget.ll --- a/llvm/test/CodeGen/WebAssembly/funcref-tableget.ll +++ b/llvm/test/CodeGen/WebAssembly/funcref-tableget.ll @@ -72,4 +72,4 @@ ret %funcref %ref } -; CHECK: .globl funcref_table +; CHECK: .tabletype funcref_table, funcref diff --git a/llvm/test/CodeGen/WebAssembly/funcref-tableset.ll b/llvm/test/CodeGen/WebAssembly/funcref-tableset.ll --- a/llvm/test/CodeGen/WebAssembly/funcref-tableset.ll +++ b/llvm/test/CodeGen/WebAssembly/funcref-tableset.ll @@ -78,4 +78,4 @@ ret void } -; CHECK: .globl funcref_table +; CHECK: .tabletype funcref_table, funcref