diff --git a/llvm/include/llvm/IR/IntrinsicsWebAssembly.td b/llvm/include/llvm/IR/IntrinsicsWebAssembly.td --- a/llvm/include/llvm/IR/IntrinsicsWebAssembly.td +++ b/llvm/include/llvm/IR/IntrinsicsWebAssembly.td @@ -39,6 +39,20 @@ //===----------------------------------------------------------------------===// // Table intrinsics //===----------------------------------------------------------------------===// +def int_wasm_table_set_externref : Intrinsic<[], + [llvm_table_ty, llvm_i32_ty, llvm_externref_ty], + [IntrWriteMem]>; +def int_wasm_table_set_funcref : Intrinsic<[], + [llvm_table_ty, llvm_i32_ty, llvm_funcref_ty], + [IntrWriteMem]>; + +def int_wasm_table_get_externref : Intrinsic<[llvm_externref_ty], + [llvm_table_ty, llvm_i32_ty], + [IntrReadMem]>; +def int_wasm_table_get_funcref : Intrinsic<[llvm_funcref_ty], + [llvm_table_ty, llvm_i32_ty], + [IntrReadMem]>; + // Query the current table size, and increase the current table size. def int_wasm_table_size : Intrinsic<[llvm_i32_ty], [llvm_table_ty], 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 @@ -1458,79 +1458,6 @@ return WebAssemblyFrameLowering::getLocalForStackObject(MF, FI->getIndex()); } -static bool IsWebAssemblyTable(SDValue Op) { - const GlobalAddressSDNode *GA = dyn_cast(Op); - if (GA && WebAssembly::isWasmVarAddressSpace(GA->getAddressSpace())) { - const GlobalValue *Value = GA->getGlobal(); - const Type *Ty = Value->getValueType(); - - if (Ty->isArrayTy() && WebAssembly::isRefType(Ty->getArrayElementType())) - return true; - } - return false; -} - -// This function will accept as Op any access to a table, so Op can -// be the actual table or an offset into the table. -static bool IsWebAssemblyTableWithOffset(SDValue Op) { - if (Op->getOpcode() == ISD::ADD && Op->getNumOperands() == 2) - return (Op->getOperand(1).getSimpleValueType() == MVT::i32 && - IsWebAssemblyTableWithOffset(Op->getOperand(0))) || - (Op->getOperand(0).getSimpleValueType() == MVT::i32 && - IsWebAssemblyTableWithOffset(Op->getOperand(1))); - - return IsWebAssemblyTable(Op); -} - -// Helper for table pattern matching used in LowerStore and LowerLoad -bool WebAssemblyTargetLowering::MatchTableForLowering(SelectionDAG &DAG, - const SDLoc &DL, - const SDValue &Base, - GlobalAddressSDNode *&GA, - SDValue &Idx) const { - // We expect the following graph for a load of the form: - // table[ + ] - // - // Case 1: - // externref = load t1 - // t1: i32 = add t2, i32: - // t2: i32 = add tX, table - // - // This is in some cases simplified to just: - // Case 2: - // externref = load t1 - // t1: i32 = add t2, i32:tX - // - // So, unfortunately we need to check for both cases and if we are in the - // first case extract the table GlobalAddressNode and build a new node tY - // that's tY: i32 = add i32:, i32:tX - // - if (IsWebAssemblyTable(Base)) { - GA = cast(Base); - Idx = DAG.getConstant(0, DL, MVT::i32); - } else { - GA = dyn_cast(Base->getOperand(0)); - if (GA) { - // We are in Case 2 above. - Idx = Base->getOperand(1); - assert(GA->getNumValues() == 1); - } else { - // This might be Case 1 above (or an error) - SDValue V = Base->getOperand(0); - GA = dyn_cast(V->getOperand(1)); - - if (V->getOpcode() != ISD::ADD || V->getNumOperands() != 2 || !GA) - return false; - - SDValue IdxV = DAG.getNode(ISD::ADD, DL, MVT::i32, Base->getOperand(1), - V->getOperand(0)); - Idx = IdxV; - } - } - - return true; -} - SDValue WebAssemblyTargetLowering::LowerStore(SDValue Op, SelectionDAG &DAG) const { SDLoc DL(Op); @@ -1539,26 +1466,6 @@ const SDValue &Base = SN->getBasePtr(); const SDValue &Offset = SN->getOffset(); - if (IsWebAssemblyTableWithOffset(Base)) { - if (!Offset->isUndef()) - report_fatal_error( - "unexpected offset when loading from webassembly table", false); - - SDValue Idx; - GlobalAddressSDNode *GA; - - if (!MatchTableForLowering(DAG, DL, Base, GA, Idx)) - report_fatal_error("failed pattern matching for lowering table store", - false); - - SDVTList Tys = DAG.getVTList(MVT::Other); - SDValue TableSetOps[] = {SN->getChain(), SDValue(GA, 0), Idx, Value}; - SDValue TableSet = - DAG.getMemIntrinsicNode(WebAssemblyISD::TABLE_SET, DL, Tys, TableSetOps, - SN->getMemoryVT(), SN->getMemOperand()); - return TableSet; - } - if (IsWebAssemblyGlobal(Base)) { if (!Offset->isUndef()) report_fatal_error("unexpected offset when storing to webassembly global", @@ -1596,26 +1503,6 @@ const SDValue &Base = LN->getBasePtr(); const SDValue &Offset = LN->getOffset(); - if (IsWebAssemblyTableWithOffset(Base)) { - if (!Offset->isUndef()) - report_fatal_error( - "unexpected offset when loading from webassembly table", false); - - GlobalAddressSDNode *GA; - SDValue Idx; - - if (!MatchTableForLowering(DAG, DL, Base, GA, Idx)) - report_fatal_error("failed pattern matching for lowering table load", - false); - - SDVTList Tys = DAG.getVTList(LN->getValueType(0), MVT::Other); - SDValue TableGetOps[] = {LN->getChain(), SDValue(GA, 0), Idx}; - SDValue TableGet = - DAG.getMemIntrinsicNode(WebAssemblyISD::TABLE_GET, DL, Tys, TableGetOps, - LN->getMemoryVT(), LN->getMemOperand()); - return TableGet; - } - if (IsWebAssemblyGlobal(Base)) { if (!Offset->isUndef()) report_fatal_error( 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 @@ -24,7 +24,7 @@ let mayLoad = 1 in defm TABLE_GET_#rc : I<(outs rc:$res), (ins table32_op:$table, I32:$i), (outs), (ins table32_op:$table), - [], + [(set rc:$res, (!cast("int_wasm_table_get_" # suffix) (WebAssemblyWrapper tglobaladdr:$table), I32:$i))], "table.get\t$res, $table, $i", "table.get\t$table", 0x25>; @@ -32,7 +32,7 @@ let mayStore = 1 in defm TABLE_SET_#rc : I<(outs), (ins table32_op:$table, I32:$i, rc:$val), (outs), (ins table32_op:$table), - [], + [(!cast("int_wasm_table_set_" # suffix) (WebAssemblyWrapper tglobaladdr:$table), I32:$i, rc:$val)], "table.set\t$table, $i, $val", "table.set\t$table", 0x26>; 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 @@ -4,14 +4,15 @@ @externref_table = local_unnamed_addr addrspace(1) global [0 x %externref] undef +declare %externref @llvm.wasm.table.get.externref(ptr addrspace(1), i32) nounwind + define %externref @get_externref_from_table(i32 %i) { ; CHECK-LABEL: get_externref_from_table: ; CHECK-NEXT: .functype get_externref_from_table (i32) -> (externref) ; CHECK-NEXT: local.get 0 ; CHECK-NEXT: table.get externref_table ; CHECK-NEXT: end_function - %p = getelementptr [0 x %externref], ptr addrspace(1) @externref_table, i32 0, i32 %i - %ref = load %externref, ptr addrspace(1) %p + %ref = call %externref @llvm.wasm.table.get.externref(ptr addrspace(1) @externref_table, i32 %i) ret %externref %ref } @@ -21,8 +22,7 @@ ; CHECK-NEXT: i32.const 0 ; CHECK-NEXT: table.get externref_table ; CHECK-NEXT: end_function - %p = getelementptr [0 x %externref], ptr addrspace (1) @externref_table, i32 0, i32 0 - %ref = load %externref, ptr addrspace(1) %p + %ref = call %externref @llvm.wasm.table.get.externref(ptr addrspace(1) @externref_table, i32 0) ret %externref %ref } @@ -35,8 +35,7 @@ ; CHECK-NEXT: table.get externref_table ; CHECK-NEXT: end_function %off = add nsw i32 %i, 2 - %p = getelementptr [0 x %externref], ptr addrspace (1) @externref_table, i32 0, i32 %off - %ref = load %externref, ptr addrspace(1) %p + %ref = call %externref @llvm.wasm.table.get.externref(ptr addrspace(1) @externref_table, i32 %off) ret %externref %ref } @@ -50,8 +49,7 @@ ; CHECK-NEXT: table.get externref_table ; CHECK-NEXT: end_function %off = add nsw i32 %i, %j - %p = getelementptr [0 x %externref], ptr addrspace (1) @externref_table, i32 0, i32 %off - %ref = load %externref, ptr addrspace(1) %p + %ref = call %externref @llvm.wasm.table.get.externref(ptr addrspace(1) @externref_table, i32 %off) ret %externref %ref } @@ -67,8 +65,7 @@ ; CHECK-NEXT: end_function %j = call i32 @get_offset() %off = add nsw i32 %i, %j - %p = getelementptr [0 x %externref], ptr addrspace (1) @externref_table, i32 0, i32 %off - %ref = load %externref, ptr addrspace(1) %p + %ref = call %externref @llvm.wasm.table.get.externref(ptr addrspace(1) @externref_table, i32 %off) ret %externref %ref } 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 @@ -4,6 +4,8 @@ @externref_table = local_unnamed_addr addrspace(1) global [0 x %externref] undef +declare void @llvm.wasm.table.set.externref(ptr addrspace(1), i32, %externref) nounwind + define void @set_externref_table(%externref %g, i32 %i) { ; CHECK-LABEL: set_externref_table: ; CHECK-NEXT: .functype set_externref_table (externref, i32) -> () @@ -13,8 +15,7 @@ ; CHECK-NEXT: end_function ;; this generates a table.set of @externref_table - %p = getelementptr [0 x %externref], ptr addrspace (1) @externref_table, i32 0, i32 %i - store %externref %g, ptr addrspace(1) %p + call void @llvm.wasm.table.set.externref(ptr addrspace(1) @externref_table, i32 %i, %externref %g) ret void } @@ -25,8 +26,7 @@ ; CHECK-NEXT: local.get 0 ; CHECK-NEXT: table.set externref_table ; CHECK-NEXT: end_function - %p = getelementptr [0 x %externref], ptr addrspace (1) @externref_table, i32 0, i32 0 - store %externref %g, ptr addrspace(1) %p + call void @llvm.wasm.table.set.externref(ptr addrspace(1) @externref_table, i32 0, %externref %g) ret void } @@ -40,8 +40,7 @@ ; CHECK-NEXT: table.set externref_table ; CHECK-NEXT: end_function %off = add nsw i32 %i, 2 - %p = getelementptr [0 x %externref], ptr addrspace (1) @externref_table, i32 0, i32 %off - store %externref %g, ptr addrspace(1) %p + call void @llvm.wasm.table.set.externref(ptr addrspace(1) @externref_table, i32 %off, %externref %g) ret void } @@ -55,8 +54,7 @@ ; CHECK-NEXT: table.set externref_table ; CHECK-NEXT: end_function %off = add nsw i32 %i, %j - %p = getelementptr [0 x %externref], ptr addrspace (1) @externref_table, i32 0, i32 %off - store %externref %g, ptr addrspace(1) %p + call void @llvm.wasm.table.set.externref(ptr addrspace(1) @externref_table, i32 %off, %externref %g) ret void } @@ -73,8 +71,7 @@ ; CHECK-NEXT: end_function %j = call i32 @set_offset() %off = add nsw i32 %i, %j - %p = getelementptr [0 x %externref], ptr addrspace (1) @externref_table, i32 0, i32 %off - store %externref %g, ptr addrspace(1) %p + call void @llvm.wasm.table.set.externref(ptr addrspace(1) @externref_table, i32 %off, %externref %g) ret void } @@ -88,8 +85,7 @@ ; CHECK-NEXT: table.set externref_table ; CHECK-NEXT: end_function %id = call i32 @get_table_slot() - %p = getelementptr [0 x %externref], ptr addrspace (1) @externref_table, i32 0, i32 %id - store %externref %g, ptr addrspace(1) %p + call void @llvm.wasm.table.set.externref(ptr addrspace(1) @externref_table, i32 %id, %externref %g) ret void } 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 @@ -6,6 +6,8 @@ ; CHECK: .tabletype __funcref_call_table, funcref, 1 +declare %funcref @llvm.wasm.table.get.funcref(ptr addrspace(1), i32) nounwind + define void @call_funcref_from_table(i32 %i) { ; CHECK-LABEL: call_funcref_from_table: ; CHECK-NEXT: .functype call_funcref_from_table (i32) -> () @@ -19,8 +21,7 @@ ; CHECK-NEXT: ref.null_func ; CHECK-NEXT: table.set __funcref_call_table ; CHECK-NEXT: end_function - %p = getelementptr [0 x %funcref], ptr addrspace (1) @funcref_table, i32 0, i32 %i - %ref = load %funcref, ptr addrspace(1) %p + %ref = call %funcref @llvm.wasm.table.get.funcref(ptr addrspace(1) @funcref_table, i32 %i) call addrspace(20) void %ref() ret void } 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 @@ -4,14 +4,15 @@ @funcref_table = local_unnamed_addr addrspace(1) global [0 x %funcref] undef +declare %funcref @llvm.wasm.table.get.funcref(ptr addrspace(1), i32) nounwind + define %funcref @get_funcref_from_table(i32 %i) { ; CHECK-LABEL: get_funcref_from_table: ; CHECK-NEXT: .functype get_funcref_from_table (i32) -> (funcref) ; CHECK-NEXT: local.get 0 ; CHECK-NEXT: table.get funcref_table ; CHECK-NEXT: end_function - %p = getelementptr [0 x %funcref], ptr addrspace (1) @funcref_table, i32 0, i32 %i - %ref = load %funcref, ptr addrspace(1) %p + %ref = call %funcref @llvm.wasm.table.get.funcref(ptr addrspace(1) @funcref_table, i32 %i) ret %funcref %ref } @@ -21,8 +22,7 @@ ; CHECK-NEXT: i32.const 0 ; CHECK-NEXT: table.get funcref_table ; CHECK-NEXT: end_function - %p = getelementptr [0 x %funcref], ptr addrspace (1) @funcref_table, i32 0, i32 0 - %ref = load %funcref, ptr addrspace(1) %p + %ref = call %funcref @llvm.wasm.table.get.funcref(ptr addrspace(1) @funcref_table, i32 0) ret %funcref %ref } @@ -35,8 +35,7 @@ ; CHECK-NEXT: table.get funcref_table ; CHECK-NEXT: end_function %off = add nsw i32 %i, 2 - %p = getelementptr [0 x %funcref], ptr addrspace (1) @funcref_table, i32 0, i32 %off - %ref = load %funcref, ptr addrspace(1) %p + %ref = call %funcref @llvm.wasm.table.get.funcref(ptr addrspace(1) @funcref_table, i32 %off) ret %funcref %ref } @@ -50,8 +49,7 @@ ; CHECK-NEXT: table.get funcref_table ; CHECK-NEXT: end_function %off = add nsw i32 %i, %j - %p = getelementptr [0 x %funcref], ptr addrspace (1) @funcref_table, i32 0, i32 %off - %ref = load %funcref, ptr addrspace(1) %p + %ref = call %funcref @llvm.wasm.table.get.funcref(ptr addrspace(1) @funcref_table, i32 %off) ret %funcref %ref } @@ -67,8 +65,7 @@ ; CHECK-NEXT: end_function %j = call i32 @get_offset() %off = add nsw i32 %i, %j - %p = getelementptr [0 x %funcref], ptr addrspace (1) @funcref_table, i32 0, i32 %off - %ref = load %funcref, ptr addrspace(1) %p + %ref = call %funcref @llvm.wasm.table.get.funcref(ptr addrspace(1) @funcref_table, i32 %off) ret %funcref %ref } 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 @@ -4,6 +4,8 @@ @funcref_table = local_unnamed_addr addrspace(1) global [0 x %funcref] undef +declare void @llvm.wasm.table.set.funcref(ptr addrspace(1), i32, %funcref) nounwind + define void @set_funcref_table(%funcref %g, i32 %i) { ; CHECK-LABEL: set_funcref_table: ; CHECK-NEXT: .functype set_funcref_table (funcref, i32) -> () @@ -13,8 +15,7 @@ ; CHECK-NEXT: end_function ;; this generates a table.set of @funcref_table - %p = getelementptr [0 x %funcref], ptr addrspace (1) @funcref_table, i32 0, i32 %i - store %funcref %g, ptr addrspace(1) %p + call void @llvm.wasm.table.set.funcref(ptr addrspace(1) @funcref_table, i32 %i, %funcref %g) ret void } @@ -25,8 +26,7 @@ ; CHECK-NEXT: local.get 0 ; CHECK-NEXT: table.set funcref_table ; CHECK-NEXT: end_function - %p = getelementptr [0 x %funcref], ptr addrspace (1) @funcref_table, i32 0, i32 0 - store %funcref %g, ptr addrspace(1) %p + call void @llvm.wasm.table.set.funcref(ptr addrspace(1) @funcref_table, i32 0, %funcref %g) ret void } @@ -40,8 +40,7 @@ ; CHECK-NEXT: table.set funcref_table ; CHECK-NEXT: end_function %off = add nsw i32 %i, 2 - %p = getelementptr [0 x %funcref], ptr addrspace (1) @funcref_table, i32 0, i32 %off - store %funcref %g, ptr addrspace(1) %p + call void @llvm.wasm.table.set.funcref(ptr addrspace(1) @funcref_table, i32 %off, %funcref %g) ret void } @@ -55,8 +54,7 @@ ; CHECK-NEXT: table.set funcref_table ; CHECK-NEXT: end_function %off = add nsw i32 %i, %j - %p = getelementptr [0 x %funcref], ptr addrspace (1) @funcref_table, i32 0, i32 %off - store %funcref %g, ptr addrspace(1) %p + call void @llvm.wasm.table.set.funcref(ptr addrspace(1) @funcref_table, i32 %off, %funcref %g) ret void } @@ -73,8 +71,7 @@ ; CHECK-NEXT: end_function %j = call i32 @set_offset() %off = add nsw i32 %i, %j - %p = getelementptr [0 x %funcref], ptr addrspace (1) @funcref_table, i32 0, i32 %off - store %funcref %g, ptr addrspace(1) %p + call void @llvm.wasm.table.set.funcref(ptr addrspace(1) @funcref_table, i32 %off, %funcref %g) ret void }