Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 58 additions & 0 deletions llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -409,6 +409,10 @@ WebAssemblyTargetLowering::WebAssemblyTargetLowering(
setOperationAction(ISD::INTRINSIC_W_CHAIN, MVT::Other, Custom);
setOperationAction(ISD::INTRINSIC_VOID, MVT::Other, Custom);

// Allow converting function ptrs in address space 0 to WASM funcref (address
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// Allow converting function ptrs in address space 0 to WASM funcref (address
// Allow converting function ptrs in address space 0 to Wasm funcref (address

// space 20)
setOperationAction(ISD::ADDRSPACECAST, MVT::funcref, Custom);

setMaxAtomicSizeInBitsSupported(64);

// Always convert switches to br_tables unless there is only one case, which
Expand Down Expand Up @@ -1733,6 +1737,8 @@ SDValue WebAssemblyTargetLowering::LowerOperation(SDValue Op,
return LowerMUL_LOHI(Op, DAG);
case ISD::UADDO:
return LowerUADDO(Op, DAG);
case ISD::ADDRSPACECAST:
return LowerADDRSPACECAST(Op, DAG);
}
}

Expand Down Expand Up @@ -1876,6 +1882,58 @@ SDValue WebAssemblyTargetLowering::LowerUADDO(SDValue Op,
return DAG.getMergeValues(Ops, DL);
}

SDValue WebAssemblyTargetLowering::LowerADDRSPACECAST(SDValue Op,
SelectionDAG &DAG) const {
SDLoc DL(Op);

AddrSpaceCastSDNode *ACN = cast<AddrSpaceCastSDNode>(Op.getNode());

if (ACN->getSrcAddressSpace() !=
WebAssembly::WasmAddressSpace::WASM_ADDRESS_SPACE_DEFAULT ||
ACN->getDestAddressSpace() !=
WebAssembly::WasmAddressSpace::WASM_ADDRESS_SPACE_FUNCREF)
return Op;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we don't want to lower this operation, I think we want return an emptySDValue() rather than the original, to let the target-agnostic logic kick in.


if (ACN->getValueType(0) != MVT::funcref) {
reportFatalInternalError("Cannot addrspacecast to funcref addrspace with "
"results other than MVT::funcref");
}

SDValue Src = ACN->getOperand(0);

// Lower addrspacecasts of direct/constant function ptrs to ref.func
if (auto *GA = dyn_cast<GlobalAddressSDNode>(
Src->getOpcode() == WebAssemblyISD::Wrapper ? Src->getOperand(0)
: Src)) {
auto *GV = GA->getGlobal();

if (const Function *F = dyn_cast<Function>(GV)) {
SDValue FnAddress = DAG.getTargetGlobalAddress(F, DL, MVT::i32);

SDValue RefFuncNode =
DAG.getNode(WebAssemblyISD::REF_FUNC, DL, MVT::funcref, FnAddress);
return RefFuncNode;
}
}

// Lower everything else to a table.get from the indirect function table
const MachineFunction &MF = DAG.getMachineFunction();

MVT PtrVT = getPointerTy(MF.getDataLayout());

MCSymbolWasm *Table =
WebAssembly::getOrCreateFunctionTableSymbol(MF.getContext(), Subtarget);
SDValue TableSym = DAG.getMCSymbol(Table, PtrVT);

SDValue TableSlot = Op.getOperand(0);

SDValue Result(DAG.getMachineNode(WebAssembly::TABLE_GET_FUNCREF, DL,
MVT::funcref, TableSym, TableSlot),
0);

return Result;
}

SDValue WebAssemblyTargetLowering::Replace128Op(SDNode *N,
SelectionDAG &DAG) const {
assert(Subtarget->hasWideArithmetic());
Expand Down
1 change: 1 addition & 0 deletions llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.h
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ class WebAssemblyTargetLowering final : public TargetLowering {
SDValue LowerMUL_LOHI(SDValue Op, SelectionDAG &DAG) const;
SDValue Replace128Op(SDNode *N, SelectionDAG &DAG) const;
SDValue LowerUADDO(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerADDRSPACECAST(SDValue Op, SelectionDAG &DAG) const;

// Custom DAG combine hooks
SDValue
Expand Down
7 changes: 6 additions & 1 deletion llvm/lib/Target/WebAssembly/WebAssemblyInstrRef.td
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,11 @@
///
//===----------------------------------------------------------------------===//

def WebAssemblyRefFunc_t : SDTypeProfile<1, 1, [SDTCisVT<0, funcref>, SDTCisPtrTy<1>]>;
def WebAssemblyRefFunc :
SDNode<"WebAssemblyISD::REF_FUNC", WebAssemblyRefFunc_t,
[]>;

multiclass REF_I<WebAssemblyRegClass rc, ValueType vt, string ht> {
defm REF_NULL_#rc : I<(outs rc:$dst), (ins),
(outs), (ins),
Expand Down Expand Up @@ -42,7 +47,7 @@ defm REF_TEST_FUNCREF : I<(outs I32:$res), (ins TypeIndex:$type, FUNCREF:$ref),
Requires<[HasGC]>;

defm REF_FUNC : I<(outs FUNCREF:$res), (ins function32_op:$func),
(outs), (ins function32_op:$func), [],
(outs), (ins function32_op:$func), [(set FUNCREF:$res, (WebAssemblyRefFunc tglobaladdr:$func))],
"ref.func\t$func", "ref.func $func", 0xd2>,
Requires<[HasReferenceTypes]>;

Expand Down
55 changes: 55 additions & 0 deletions llvm/test/CodeGen/WebAssembly/addrspacecast-funcref.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6
; RUN: llc -mtriple=wasm32-unknown-unknown -mattr=+reference-types < %s | FileCheck -check-prefixes=CHECK,WASM32 %s
; RUN: llc -mtriple=wasm64-unknown-unknown -mattr=+reference-types < %s | FileCheck -check-prefixes=CHECK,WASM64 %s

%funcref = type ptr addrspace(20) ;; addrspace 20 is nonintegral

declare void @foo();

@global_var = local_unnamed_addr global i32 0

define %funcref @cast_const_funcptr() {
; CHECK-LABEL: cast_const_funcptr:
; CHECK: .functype cast_const_funcptr () -> (funcref)
; CHECK-NEXT: # %bb.0:
; CHECK-NEXT: ref.func foo
; CHECK-NEXT: # fallthrough-return
%result = addrspacecast ptr @foo to ptr addrspace(20)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there any reason the target type has to be spelled out and can't be just %funcref?

ret %funcref %result
}

define %funcref @cast_const_not_funcptr() {
; WASM32-LABEL: cast_const_not_funcptr:
; WASM32: .functype cast_const_not_funcptr () -> (funcref)
; WASM32-NEXT: # %bb.0:
; WASM32-NEXT: i32.const global_var
; WASM32-NEXT: table.get __indirect_function_table
; WASM32-NEXT: # fallthrough-return
;
; WASM64-LABEL: cast_const_not_funcptr:
; WASM64: .functype cast_const_not_funcptr () -> (funcref)
; WASM64-NEXT: # %bb.0:
; WASM64-NEXT: i64.const global_var
; WASM64-NEXT: table.get __indirect_function_table
; WASM64-NEXT: # fallthrough-return
%result = addrspacecast ptr @global_var to ptr addrspace(20)
ret %funcref %result
}

define %funcref @cast_param_funcptr(ptr %funcptr) {
; WASM32-LABEL: cast_param_funcptr:
; WASM32: .functype cast_param_funcptr (i32) -> (funcref)
; WASM32-NEXT: # %bb.0:
; WASM32-NEXT: local.get 0
; WASM32-NEXT: table.get __indirect_function_table
; WASM32-NEXT: # fallthrough-return
;
; WASM64-LABEL: cast_param_funcptr:
; WASM64: .functype cast_param_funcptr (i64) -> (funcref)
; WASM64-NEXT: # %bb.0:
; WASM64-NEXT: local.get 0
; WASM64-NEXT: table.get __indirect_function_table
; WASM64-NEXT: # fallthrough-return
%result = addrspacecast ptr %funcptr to ptr addrspace(20)
ret %funcref %result
}