-
Notifications
You must be signed in to change notification settings - Fork 15k
[WebAssembly,llvm] Add llvm.wasm.ref.test.func intrinsic #147486
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
|
@llvm/pr-subscribers-backend-webassembly @llvm/pr-subscribers-llvm-selectiondag Author: Hood Chatham (hoodmane) ChangesTo test whether or not a function pointer has the expected signature. Intended for adding a future clang builtin This is an alternative to #147076, where instead of using a ref.test.pseudo instruction with a custom inserter, we teach SelectionDag a type of TargetConstantAP nodes that get converted to a CImm in the MCInst layer. Full diff: https://github.com/llvm/llvm-project/pull/147486.diff 11 Files Affected:
diff --git a/llvm/include/llvm/CodeGen/ISDOpcodes.h b/llvm/include/llvm/CodeGen/ISDOpcodes.h
index 465e4a0a9d0d8..a9d4e5ade0ba8 100644
--- a/llvm/include/llvm/CodeGen/ISDOpcodes.h
+++ b/llvm/include/llvm/CodeGen/ISDOpcodes.h
@@ -173,6 +173,7 @@ enum NodeType {
/// materialized in registers.
TargetConstant,
TargetConstantFP,
+ TargetConstantAP,
/// TargetGlobalAddress - Like GlobalAddress, but the DAG does no folding or
/// anything else with this node, and this is valid in the target-specific
diff --git a/llvm/include/llvm/CodeGen/SelectionDAG.h b/llvm/include/llvm/CodeGen/SelectionDAG.h
index 7d8a0c4ce8e45..0a7e3ec24be23 100644
--- a/llvm/include/llvm/CodeGen/SelectionDAG.h
+++ b/llvm/include/llvm/CodeGen/SelectionDAG.h
@@ -683,7 +683,8 @@ class SelectionDAG {
LLVM_ABI SDValue getConstant(uint64_t Val, const SDLoc &DL, EVT VT,
bool isTarget = false, bool isOpaque = false);
LLVM_ABI SDValue getConstant(const APInt &Val, const SDLoc &DL, EVT VT,
- bool isTarget = false, bool isOpaque = false);
+ bool isTarget = false, bool isOpaque = false,
+ bool isArbitraryPrecision = false);
LLVM_ABI SDValue getSignedConstant(int64_t Val, const SDLoc &DL, EVT VT,
bool isTarget = false,
@@ -694,7 +695,8 @@ class SelectionDAG {
bool IsOpaque = false);
LLVM_ABI SDValue getConstant(const ConstantInt &Val, const SDLoc &DL, EVT VT,
- bool isTarget = false, bool isOpaque = false);
+ bool isTarget = false, bool isOpaque = false,
+ bool isArbitraryPrecision = false);
LLVM_ABI SDValue getIntPtrConstant(uint64_t Val, const SDLoc &DL,
bool isTarget = false);
LLVM_ABI SDValue getShiftAmountConstant(uint64_t Val, EVT VT,
@@ -712,6 +714,10 @@ class SelectionDAG {
bool isOpaque = false) {
return getConstant(Val, DL, VT, true, isOpaque);
}
+ SDValue getTargetConstantAP(const APInt &Val, const SDLoc &DL, EVT VT,
+ bool isOpaque = false) {
+ return getConstant(Val, DL, VT, true, isOpaque, true);
+ }
SDValue getTargetConstant(const ConstantInt &Val, const SDLoc &DL, EVT VT,
bool isOpaque = false) {
return getConstant(Val, DL, VT, true, isOpaque);
diff --git a/llvm/include/llvm/CodeGen/SelectionDAGNodes.h b/llvm/include/llvm/CodeGen/SelectionDAGNodes.h
index 5d9937f832396..45e57c491181b 100644
--- a/llvm/include/llvm/CodeGen/SelectionDAGNodes.h
+++ b/llvm/include/llvm/CodeGen/SelectionDAGNodes.h
@@ -1742,10 +1742,11 @@ class ConstantSDNode : public SDNode {
const ConstantInt *Value;
- ConstantSDNode(bool isTarget, bool isOpaque, const ConstantInt *val,
- SDVTList VTs)
- : SDNode(isTarget ? ISD::TargetConstant : ISD::Constant, 0, DebugLoc(),
- VTs),
+ ConstantSDNode(bool isTarget, bool isOpaque, bool isAPTarget,
+ const ConstantInt *val, SDVTList VTs)
+ : SDNode(isAPTarget ? ISD::TargetConstantAP
+ : (isTarget ? ISD::TargetConstant : ISD::Constant),
+ 0, DebugLoc(), VTs),
Value(val) {
assert(!isa<VectorType>(val->getType()) && "Unexpected vector type!");
ConstantSDNodeBits.IsOpaque = isOpaque;
@@ -1772,7 +1773,8 @@ class ConstantSDNode : public SDNode {
static bool classof(const SDNode *N) {
return N->getOpcode() == ISD::Constant ||
- N->getOpcode() == ISD::TargetConstant;
+ N->getOpcode() == ISD::TargetConstant ||
+ N->getOpcode() == ISD::TargetConstantAP;
}
};
diff --git a/llvm/include/llvm/IR/IntrinsicsWebAssembly.td b/llvm/include/llvm/IR/IntrinsicsWebAssembly.td
index f592ff287a0e3..fb61d8a11e5c0 100644
--- a/llvm/include/llvm/IR/IntrinsicsWebAssembly.td
+++ b/llvm/include/llvm/IR/IntrinsicsWebAssembly.td
@@ -43,6 +43,10 @@ def int_wasm_ref_is_null_exn :
DefaultAttrsIntrinsic<[llvm_i32_ty], [llvm_exnref_ty], [IntrNoMem],
"llvm.wasm.ref.is_null.exn">;
+def int_wasm_ref_test_func
+ : DefaultAttrsIntrinsic<[llvm_i32_ty], [llvm_ptr_ty, llvm_vararg_ty],
+ [IntrNoMem], "llvm.wasm.ref.test.func">;
+
//===----------------------------------------------------------------------===//
// Table intrinsics
//===----------------------------------------------------------------------===//
diff --git a/llvm/lib/CodeGen/SelectionDAG/InstrEmitter.cpp b/llvm/lib/CodeGen/SelectionDAG/InstrEmitter.cpp
index 03d3e8eab35d0..95a93d0cefff9 100644
--- a/llvm/lib/CodeGen/SelectionDAG/InstrEmitter.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/InstrEmitter.cpp
@@ -402,7 +402,12 @@ void InstrEmitter::AddOperand(MachineInstrBuilder &MIB, SDValue Op,
AddRegisterOperand(MIB, Op, IIOpNum, II, VRBaseMap,
IsDebug, IsClone, IsCloned);
} else if (ConstantSDNode *C = dyn_cast<ConstantSDNode>(Op)) {
- MIB.addImm(C->getSExtValue());
+ if (C->getOpcode() == ISD::TargetConstantAP) {
+ MIB.addCImm(
+ ConstantInt::get(MF->getFunction().getContext(), C->getAPIntValue()));
+ } else {
+ MIB.addImm(C->getSExtValue());
+ }
} else if (ConstantFPSDNode *F = dyn_cast<ConstantFPSDNode>(Op)) {
MIB.addFPImm(F->getConstantFPValue());
} else if (RegisterSDNode *R = dyn_cast<RegisterSDNode>(Op)) {
diff --git a/llvm/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp b/llvm/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp
index f5f4d71236fee..ef5c74610f887 100644
--- a/llvm/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp
@@ -968,6 +968,7 @@ void SelectionDAGLegalize::LegalizeOp(SDNode *Node) {
// Allow illegal target nodes and illegal registers.
if (Node->getOpcode() == ISD::TargetConstant ||
+ Node->getOpcode() == ISD::TargetConstantAP ||
Node->getOpcode() == ISD::Register)
return;
@@ -979,10 +980,11 @@ void SelectionDAGLegalize::LegalizeOp(SDNode *Node) {
for (const SDValue &Op : Node->op_values())
assert((TLI.getTypeAction(*DAG.getContext(), Op.getValueType()) ==
- TargetLowering::TypeLegal ||
+ TargetLowering::TypeLegal ||
Op.getOpcode() == ISD::TargetConstant ||
+ Op->getOpcode() == ISD::TargetConstantAP ||
Op.getOpcode() == ISD::Register) &&
- "Unexpected illegal type!");
+ "Unexpected illegal type!");
#endif
// Figure out the correct action; the way to query this varies by opcode
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
index 2a8bda55fef04..413631e42668c 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
@@ -1664,14 +1664,14 @@ SDValue SelectionDAG::getConstant(uint64_t Val, const SDLoc &DL, EVT VT,
}
SDValue SelectionDAG::getConstant(const APInt &Val, const SDLoc &DL, EVT VT,
- bool isT, bool isO) {
- return getConstant(*ConstantInt::get(*Context, Val), DL, VT, isT, isO);
+ bool isT, bool isO, bool isAP) {
+ return getConstant(*ConstantInt::get(*Context, Val), DL, VT, isT, isO, isAP);
}
SDValue SelectionDAG::getConstant(const ConstantInt &Val, const SDLoc &DL,
- EVT VT, bool isT, bool isO) {
+ EVT VT, bool isT, bool isO, bool isAP) {
assert(VT.isInteger() && "Cannot create FP integer constant!");
-
+ isT |= isAP;
EVT EltVT = VT.getScalarType();
const ConstantInt *Elt = &Val;
@@ -1760,7 +1760,8 @@ SDValue SelectionDAG::getConstant(const ConstantInt &Val, const SDLoc &DL,
assert(Elt->getBitWidth() == EltVT.getSizeInBits() &&
"APInt size does not match type size!");
- unsigned Opc = isT ? ISD::TargetConstant : ISD::Constant;
+ unsigned Opc = isAP ? ISD::TargetConstantAP
+ : (isT ? ISD::TargetConstant : ISD::Constant);
SDVTList VTs = getVTList(EltVT);
FoldingSetNodeID ID;
AddNodeIDNode(ID, Opc, VTs, {});
@@ -1773,7 +1774,7 @@ SDValue SelectionDAG::getConstant(const ConstantInt &Val, const SDLoc &DL,
return SDValue(N, 0);
if (!N) {
- N = newSDNode<ConstantSDNode>(isT, isO, Elt, VTs);
+ N = newSDNode<ConstantSDNode>(isT, isO, isAP, Elt, VTs);
CSEMap.InsertNode(N, IP);
InsertNode(N);
NewSDValueDbgMsg(SDValue(N, 0), "Creating constant: ", this);
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp
index d9b9cf6bcc772..5a3b96743b0ef 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp
@@ -3255,6 +3255,7 @@ void SelectionDAGISel::SelectCodeCommon(SDNode *NodeToMatch,
case ISD::HANDLENODE:
case ISD::MDNODE_SDNODE:
case ISD::TargetConstant:
+ case ISD::TargetConstantAP:
case ISD::TargetConstantFP:
case ISD::TargetConstantPool:
case ISD::TargetFrameIndex:
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp
index bf2e04caa0a61..ec369eaeae0a5 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp
@@ -18,6 +18,7 @@
#include "WebAssemblySubtarget.h"
#include "WebAssemblyTargetMachine.h"
#include "WebAssemblyUtilities.h"
+#include "llvm/BinaryFormat/Wasm.h"
#include "llvm/CodeGen/CallingConvLower.h"
#include "llvm/CodeGen/MachineFrameInfo.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
@@ -794,6 +795,7 @@ LowerCallResults(MachineInstr &CallResults, DebugLoc DL, MachineBasicBlock *BB,
if (IsIndirect) {
// Placeholder for the type index.
+ // This gets replaced with the correct value in WebAssemblyMCInstLower.cpp
MIB.addImm(0);
// The table into which this call_indirect indexes.
MCSymbolWasm *Table = IsFuncrefCall
@@ -2253,6 +2255,71 @@ SDValue WebAssemblyTargetLowering::LowerIntrinsic(SDValue Op,
DAG.getTargetExternalSymbol(TlsBase, PtrVT)),
0);
}
+ case Intrinsic::wasm_ref_test_func: {
+ // First emit the TABLE_GET instruction to convert function pointer ==>
+ // funcref
+ MachineFunction &MF = DAG.getMachineFunction();
+ auto PtrVT = getPointerTy(MF.getDataLayout());
+ MCSymbol *Table =
+ WebAssembly::getOrCreateFunctionTableSymbol(MF.getContext(), Subtarget);
+ SDValue TableSym = DAG.getMCSymbol(Table, PtrVT);
+ SDValue FuncRef =
+ SDValue(DAG.getMachineNode(WebAssembly::TABLE_GET_FUNCREF, DL,
+ MVT::funcref, TableSym, Op.getOperand(1)),
+ 0);
+
+ // Encode the signature information into the type index placeholder.
+ // This gets decoded and converted into the actual type signature in
+ // WebAssemblyMCInstLower.cpp.
+ auto NParams = Op.getNumOperands() - 2;
+ auto Sig = APInt(NParams * 64, 0);
+ // The return type has to be a BlockType since it can be void.
+ {
+ SDValue Operand = Op.getOperand(2);
+ MVT VT = Operand.getValueType().getSimpleVT();
+ WebAssembly::BlockType V;
+ if (VT == MVT::Untyped) {
+ V = WebAssembly::BlockType::Void;
+ } else if (VT == MVT::i32) {
+ V = WebAssembly::BlockType::I32;
+ } else if (VT == MVT::i64) {
+ V = WebAssembly::BlockType::I64;
+ } else if (VT == MVT::f32) {
+ V = WebAssembly::BlockType::F32;
+ } else if (VT == MVT::f64) {
+ V = WebAssembly::BlockType::F64;
+ } else {
+ llvm_unreachable("Unhandled type!");
+ }
+ Sig |= (int64_t)V;
+ }
+ for (unsigned i = 3; i < Op.getNumOperands(); ++i) {
+ SDValue Operand = Op.getOperand(i);
+ MVT VT = Operand.getValueType().getSimpleVT();
+ wasm::ValType V;
+ if (VT == MVT::i32) {
+ V = wasm::ValType::I32;
+ } else if (VT == MVT::i64) {
+ V = wasm::ValType::I64;
+ } else if (VT == MVT::f32) {
+ V = wasm::ValType::F32;
+ } else if (VT == MVT::f64) {
+ V = wasm::ValType::F64;
+ } else {
+ llvm_unreachable("Unhandled type!");
+ }
+ Sig <<= 64;
+ Sig |= (int64_t)V;
+ }
+
+ SmallVector<SDValue, 4> Ops;
+ Ops.push_back(DAG.getTargetConstantAP(
+ Sig, DL, EVT::getIntegerVT(*DAG.getContext(), NParams * 64)));
+ Ops.push_back(FuncRef);
+ return SDValue(
+ DAG.getMachineNode(WebAssembly::REF_TEST_FUNCREF, DL, MVT::i32, Ops),
+ 0);
+ }
}
}
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp
index cc36244e63ff5..f725ec344d922 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp
@@ -15,13 +15,17 @@
#include "WebAssemblyMCInstLower.h"
#include "MCTargetDesc/WebAssemblyMCAsmInfo.h"
#include "MCTargetDesc/WebAssemblyMCTargetDesc.h"
+#include "MCTargetDesc/WebAssemblyMCTypeUtilities.h"
#include "TargetInfo/WebAssemblyTargetInfo.h"
#include "Utils/WebAssemblyTypeUtilities.h"
#include "WebAssemblyAsmPrinter.h"
#include "WebAssemblyMachineFunctionInfo.h"
#include "WebAssemblyUtilities.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/BinaryFormat/Wasm.h"
#include "llvm/CodeGen/AsmPrinter.h"
#include "llvm/CodeGen/MachineFunction.h"
+#include "llvm/CodeGen/MachineOperand.h"
#include "llvm/IR/Constants.h"
#include "llvm/MC/MCAsmInfo.h"
#include "llvm/MC/MCContext.h"
@@ -196,11 +200,80 @@ void WebAssemblyMCInstLower::lower(const MachineInstr *MI,
MCOp = MCOperand::createReg(WAReg);
break;
}
+ case llvm::MachineOperand::MO_CImmediate: {
+ // Lower type index placeholder for ref.test
+ // Currently this is the only way that CImmediates show up so panic if we
+ // get confused.
+ unsigned DescIndex = I - NumVariadicDefs;
+ if (DescIndex >= Desc.NumOperands) {
+ llvm_unreachable("unexpected CImmediate operand");
+ }
+ const MCOperandInfo &Info = Desc.operands()[DescIndex];
+ if (Info.OperandType != WebAssembly::OPERAND_TYPEINDEX) {
+ llvm_unreachable("unexpected CImmediate operand");
+ }
+ auto CImm = MO.getCImm()->getValue();
+ auto NumWords = CImm.getNumWords();
+ // Extract the type data we packed into the CImm in LowerRefTestFuncRef.
+ // We need to load the words from most significant to least significant
+ // order because of the way we bitshifted them in from the right.
+ // The return type needs special handling because it could be void.
+ auto ReturnType = static_cast<WebAssembly::BlockType>(
+ CImm.extractBitsAsZExtValue(64, (NumWords - 1) * 64));
+ SmallVector<wasm::ValType, 2> Returns;
+ switch (ReturnType) {
+ case WebAssembly::BlockType::Invalid:
+ llvm_unreachable("Invalid return type");
+ case WebAssembly::BlockType::I32:
+ Returns = {wasm::ValType::I32};
+ break;
+ case WebAssembly::BlockType::I64:
+ Returns = {wasm::ValType::I64};
+ break;
+ case WebAssembly::BlockType::F32:
+ Returns = {wasm::ValType::F32};
+ break;
+ case WebAssembly::BlockType::F64:
+ Returns = {wasm::ValType::F64};
+ break;
+ case WebAssembly::BlockType::Void:
+ Returns = {};
+ break;
+ case WebAssembly::BlockType::Exnref:
+ Returns = {wasm::ValType::EXNREF};
+ break;
+ case WebAssembly::BlockType::Externref:
+ Returns = {wasm::ValType::EXTERNREF};
+ break;
+ case WebAssembly::BlockType::Funcref:
+ Returns = {wasm::ValType::FUNCREF};
+ break;
+ case WebAssembly::BlockType::V128:
+ Returns = {wasm::ValType::V128};
+ break;
+ case WebAssembly::BlockType::Multivalue: {
+ llvm_unreachable("Invalid return type");
+ }
+ }
+ SmallVector<wasm::ValType, 4> Params;
+
+ for (int I = NumWords - 2; I >= 0; I--) {
+ auto Val = CImm.extractBitsAsZExtValue(64, 64 * I);
+ auto ParamType = static_cast<wasm::ValType>(Val);
+ Params.push_back(ParamType);
+ }
+ MCOp = lowerTypeIndexOperand(std::move(Returns), std::move(Params));
+ break;
+ }
case MachineOperand::MO_Immediate: {
unsigned DescIndex = I - NumVariadicDefs;
if (DescIndex < Desc.NumOperands) {
const MCOperandInfo &Info = Desc.operands()[DescIndex];
+ // Replace type index placeholder with actual type index. The type index
+ // placeholders are Immediates and have an operand type of
+ // OPERAND_TYPEINDEX or OPERAND_SIGNATURE.
if (Info.OperandType == WebAssembly::OPERAND_TYPEINDEX) {
+ // Lower type index placeholder for a CALL_INDIRECT instruction
SmallVector<wasm::ValType, 4> Returns;
SmallVector<wasm::ValType, 4> Params;
@@ -228,6 +301,7 @@ void WebAssemblyMCInstLower::lower(const MachineInstr *MI,
break;
}
if (Info.OperandType == WebAssembly::OPERAND_SIGNATURE) {
+ // Lower type index placeholder for blocks
auto BT = static_cast<WebAssembly::BlockType>(MO.getImm());
assert(BT != WebAssembly::BlockType::Invalid);
if (BT == WebAssembly::BlockType::Multivalue) {
diff --git a/llvm/test/CodeGen/WebAssembly/ref-test-func.ll b/llvm/test/CodeGen/WebAssembly/ref-test-func.ll
new file mode 100644
index 0000000000000..3fc848cd167f9
--- /dev/null
+++ b/llvm/test/CodeGen/WebAssembly/ref-test-func.ll
@@ -0,0 +1,42 @@
+; RUN: llc < %s -mcpu=mvp -mattr=+reference-types | FileCheck %s
+
+target triple = "wasm32-unknown-unknown"
+
+; CHECK-LABEL: test_function_pointer_signature_void:
+; CHECK-NEXT: .functype test_function_pointer_signature_void (i32) -> ()
+; CHECK-NEXT: .local funcref
+; CHECK: local.get 0
+; CHECK-NEXT: table.get __indirect_function_table
+; CHECK-NEXT: local.tee 1
+; CHECK-NEXT: ref.test (f32, f64, i32) -> (f32)
+; CHECK-NEXT: call use
+; CHECK-NEXT: local.get 1
+; CHECK-NEXT: ref.test (f32, f64, i32) -> (i32)
+; CHECK-NEXT: call use
+; CHECK-NEXT: local.get 1
+; CHECK-NEXT: ref.test (i32, i32, i32) -> (i32)
+; CHECK-NEXT: call use
+; CHECK-NEXT: local.get 1
+; CHECK-NEXT: ref.test (i32, i32, i32) -> ()
+; CHECK-NEXT: call use
+; CHECK-NEXT: local.get 1
+; CHECK-NEXT: ref.test () -> ()
+; CHECK-NEXT: call use
+
+; Function Attrs: nounwind
+define void @test_function_pointer_signature_void(ptr noundef %func) local_unnamed_addr #0 {
+entry:
+ %0 = tail call i32 (ptr, ...) @llvm.wasm.ref.test.func(ptr %func, float 0.000000e+00, float 0.000000e+00, double 0.000000e+00, i32 0)
+ tail call void @use(i32 noundef %0) #3
+ %1 = tail call i32 (ptr, ...) @llvm.wasm.ref.test.func(ptr %func, i32 0, float 0.000000e+00, double 0.000000e+00, i32 0)
+ tail call void @use(i32 noundef %1) #3
+ %2 = tail call i32 (ptr, ...) @llvm.wasm.ref.test.func(ptr %func, i32 0, i32 0, i32 0, i32 0)
+ tail call void @use(i32 noundef %2) #3
+ %3 = tail call i32 (ptr, ...) @llvm.wasm.ref.test.func(ptr %func, token poison, i32 0, i32 0, i32 0)
+ tail call void @use(i32 noundef %3) #3
+ %4 = tail call i32 (ptr, ...) @llvm.wasm.ref.test.func(ptr %func, token poison)
+ tail call void @use(i32 noundef %4) #3
+ ret void
+}
+
+declare void @use(i32 noundef) local_unnamed_addr #1
|
|
@llvm/pr-subscribers-llvm-ir Author: Hood Chatham (hoodmane) ChangesTo test whether or not a function pointer has the expected signature. Intended for adding a future clang builtin This is an alternative to #147076, where instead of using a ref.test.pseudo instruction with a custom inserter, we teach SelectionDag a type of TargetConstantAP nodes that get converted to a CImm in the MCInst layer. Full diff: https://github.com/llvm/llvm-project/pull/147486.diff 11 Files Affected:
diff --git a/llvm/include/llvm/CodeGen/ISDOpcodes.h b/llvm/include/llvm/CodeGen/ISDOpcodes.h
index 465e4a0a9d0d8..a9d4e5ade0ba8 100644
--- a/llvm/include/llvm/CodeGen/ISDOpcodes.h
+++ b/llvm/include/llvm/CodeGen/ISDOpcodes.h
@@ -173,6 +173,7 @@ enum NodeType {
/// materialized in registers.
TargetConstant,
TargetConstantFP,
+ TargetConstantAP,
/// TargetGlobalAddress - Like GlobalAddress, but the DAG does no folding or
/// anything else with this node, and this is valid in the target-specific
diff --git a/llvm/include/llvm/CodeGen/SelectionDAG.h b/llvm/include/llvm/CodeGen/SelectionDAG.h
index 7d8a0c4ce8e45..0a7e3ec24be23 100644
--- a/llvm/include/llvm/CodeGen/SelectionDAG.h
+++ b/llvm/include/llvm/CodeGen/SelectionDAG.h
@@ -683,7 +683,8 @@ class SelectionDAG {
LLVM_ABI SDValue getConstant(uint64_t Val, const SDLoc &DL, EVT VT,
bool isTarget = false, bool isOpaque = false);
LLVM_ABI SDValue getConstant(const APInt &Val, const SDLoc &DL, EVT VT,
- bool isTarget = false, bool isOpaque = false);
+ bool isTarget = false, bool isOpaque = false,
+ bool isArbitraryPrecision = false);
LLVM_ABI SDValue getSignedConstant(int64_t Val, const SDLoc &DL, EVT VT,
bool isTarget = false,
@@ -694,7 +695,8 @@ class SelectionDAG {
bool IsOpaque = false);
LLVM_ABI SDValue getConstant(const ConstantInt &Val, const SDLoc &DL, EVT VT,
- bool isTarget = false, bool isOpaque = false);
+ bool isTarget = false, bool isOpaque = false,
+ bool isArbitraryPrecision = false);
LLVM_ABI SDValue getIntPtrConstant(uint64_t Val, const SDLoc &DL,
bool isTarget = false);
LLVM_ABI SDValue getShiftAmountConstant(uint64_t Val, EVT VT,
@@ -712,6 +714,10 @@ class SelectionDAG {
bool isOpaque = false) {
return getConstant(Val, DL, VT, true, isOpaque);
}
+ SDValue getTargetConstantAP(const APInt &Val, const SDLoc &DL, EVT VT,
+ bool isOpaque = false) {
+ return getConstant(Val, DL, VT, true, isOpaque, true);
+ }
SDValue getTargetConstant(const ConstantInt &Val, const SDLoc &DL, EVT VT,
bool isOpaque = false) {
return getConstant(Val, DL, VT, true, isOpaque);
diff --git a/llvm/include/llvm/CodeGen/SelectionDAGNodes.h b/llvm/include/llvm/CodeGen/SelectionDAGNodes.h
index 5d9937f832396..45e57c491181b 100644
--- a/llvm/include/llvm/CodeGen/SelectionDAGNodes.h
+++ b/llvm/include/llvm/CodeGen/SelectionDAGNodes.h
@@ -1742,10 +1742,11 @@ class ConstantSDNode : public SDNode {
const ConstantInt *Value;
- ConstantSDNode(bool isTarget, bool isOpaque, const ConstantInt *val,
- SDVTList VTs)
- : SDNode(isTarget ? ISD::TargetConstant : ISD::Constant, 0, DebugLoc(),
- VTs),
+ ConstantSDNode(bool isTarget, bool isOpaque, bool isAPTarget,
+ const ConstantInt *val, SDVTList VTs)
+ : SDNode(isAPTarget ? ISD::TargetConstantAP
+ : (isTarget ? ISD::TargetConstant : ISD::Constant),
+ 0, DebugLoc(), VTs),
Value(val) {
assert(!isa<VectorType>(val->getType()) && "Unexpected vector type!");
ConstantSDNodeBits.IsOpaque = isOpaque;
@@ -1772,7 +1773,8 @@ class ConstantSDNode : public SDNode {
static bool classof(const SDNode *N) {
return N->getOpcode() == ISD::Constant ||
- N->getOpcode() == ISD::TargetConstant;
+ N->getOpcode() == ISD::TargetConstant ||
+ N->getOpcode() == ISD::TargetConstantAP;
}
};
diff --git a/llvm/include/llvm/IR/IntrinsicsWebAssembly.td b/llvm/include/llvm/IR/IntrinsicsWebAssembly.td
index f592ff287a0e3..fb61d8a11e5c0 100644
--- a/llvm/include/llvm/IR/IntrinsicsWebAssembly.td
+++ b/llvm/include/llvm/IR/IntrinsicsWebAssembly.td
@@ -43,6 +43,10 @@ def int_wasm_ref_is_null_exn :
DefaultAttrsIntrinsic<[llvm_i32_ty], [llvm_exnref_ty], [IntrNoMem],
"llvm.wasm.ref.is_null.exn">;
+def int_wasm_ref_test_func
+ : DefaultAttrsIntrinsic<[llvm_i32_ty], [llvm_ptr_ty, llvm_vararg_ty],
+ [IntrNoMem], "llvm.wasm.ref.test.func">;
+
//===----------------------------------------------------------------------===//
// Table intrinsics
//===----------------------------------------------------------------------===//
diff --git a/llvm/lib/CodeGen/SelectionDAG/InstrEmitter.cpp b/llvm/lib/CodeGen/SelectionDAG/InstrEmitter.cpp
index 03d3e8eab35d0..95a93d0cefff9 100644
--- a/llvm/lib/CodeGen/SelectionDAG/InstrEmitter.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/InstrEmitter.cpp
@@ -402,7 +402,12 @@ void InstrEmitter::AddOperand(MachineInstrBuilder &MIB, SDValue Op,
AddRegisterOperand(MIB, Op, IIOpNum, II, VRBaseMap,
IsDebug, IsClone, IsCloned);
} else if (ConstantSDNode *C = dyn_cast<ConstantSDNode>(Op)) {
- MIB.addImm(C->getSExtValue());
+ if (C->getOpcode() == ISD::TargetConstantAP) {
+ MIB.addCImm(
+ ConstantInt::get(MF->getFunction().getContext(), C->getAPIntValue()));
+ } else {
+ MIB.addImm(C->getSExtValue());
+ }
} else if (ConstantFPSDNode *F = dyn_cast<ConstantFPSDNode>(Op)) {
MIB.addFPImm(F->getConstantFPValue());
} else if (RegisterSDNode *R = dyn_cast<RegisterSDNode>(Op)) {
diff --git a/llvm/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp b/llvm/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp
index f5f4d71236fee..ef5c74610f887 100644
--- a/llvm/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp
@@ -968,6 +968,7 @@ void SelectionDAGLegalize::LegalizeOp(SDNode *Node) {
// Allow illegal target nodes and illegal registers.
if (Node->getOpcode() == ISD::TargetConstant ||
+ Node->getOpcode() == ISD::TargetConstantAP ||
Node->getOpcode() == ISD::Register)
return;
@@ -979,10 +980,11 @@ void SelectionDAGLegalize::LegalizeOp(SDNode *Node) {
for (const SDValue &Op : Node->op_values())
assert((TLI.getTypeAction(*DAG.getContext(), Op.getValueType()) ==
- TargetLowering::TypeLegal ||
+ TargetLowering::TypeLegal ||
Op.getOpcode() == ISD::TargetConstant ||
+ Op->getOpcode() == ISD::TargetConstantAP ||
Op.getOpcode() == ISD::Register) &&
- "Unexpected illegal type!");
+ "Unexpected illegal type!");
#endif
// Figure out the correct action; the way to query this varies by opcode
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
index 2a8bda55fef04..413631e42668c 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
@@ -1664,14 +1664,14 @@ SDValue SelectionDAG::getConstant(uint64_t Val, const SDLoc &DL, EVT VT,
}
SDValue SelectionDAG::getConstant(const APInt &Val, const SDLoc &DL, EVT VT,
- bool isT, bool isO) {
- return getConstant(*ConstantInt::get(*Context, Val), DL, VT, isT, isO);
+ bool isT, bool isO, bool isAP) {
+ return getConstant(*ConstantInt::get(*Context, Val), DL, VT, isT, isO, isAP);
}
SDValue SelectionDAG::getConstant(const ConstantInt &Val, const SDLoc &DL,
- EVT VT, bool isT, bool isO) {
+ EVT VT, bool isT, bool isO, bool isAP) {
assert(VT.isInteger() && "Cannot create FP integer constant!");
-
+ isT |= isAP;
EVT EltVT = VT.getScalarType();
const ConstantInt *Elt = &Val;
@@ -1760,7 +1760,8 @@ SDValue SelectionDAG::getConstant(const ConstantInt &Val, const SDLoc &DL,
assert(Elt->getBitWidth() == EltVT.getSizeInBits() &&
"APInt size does not match type size!");
- unsigned Opc = isT ? ISD::TargetConstant : ISD::Constant;
+ unsigned Opc = isAP ? ISD::TargetConstantAP
+ : (isT ? ISD::TargetConstant : ISD::Constant);
SDVTList VTs = getVTList(EltVT);
FoldingSetNodeID ID;
AddNodeIDNode(ID, Opc, VTs, {});
@@ -1773,7 +1774,7 @@ SDValue SelectionDAG::getConstant(const ConstantInt &Val, const SDLoc &DL,
return SDValue(N, 0);
if (!N) {
- N = newSDNode<ConstantSDNode>(isT, isO, Elt, VTs);
+ N = newSDNode<ConstantSDNode>(isT, isO, isAP, Elt, VTs);
CSEMap.InsertNode(N, IP);
InsertNode(N);
NewSDValueDbgMsg(SDValue(N, 0), "Creating constant: ", this);
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp
index d9b9cf6bcc772..5a3b96743b0ef 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp
@@ -3255,6 +3255,7 @@ void SelectionDAGISel::SelectCodeCommon(SDNode *NodeToMatch,
case ISD::HANDLENODE:
case ISD::MDNODE_SDNODE:
case ISD::TargetConstant:
+ case ISD::TargetConstantAP:
case ISD::TargetConstantFP:
case ISD::TargetConstantPool:
case ISD::TargetFrameIndex:
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp
index bf2e04caa0a61..ec369eaeae0a5 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp
@@ -18,6 +18,7 @@
#include "WebAssemblySubtarget.h"
#include "WebAssemblyTargetMachine.h"
#include "WebAssemblyUtilities.h"
+#include "llvm/BinaryFormat/Wasm.h"
#include "llvm/CodeGen/CallingConvLower.h"
#include "llvm/CodeGen/MachineFrameInfo.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
@@ -794,6 +795,7 @@ LowerCallResults(MachineInstr &CallResults, DebugLoc DL, MachineBasicBlock *BB,
if (IsIndirect) {
// Placeholder for the type index.
+ // This gets replaced with the correct value in WebAssemblyMCInstLower.cpp
MIB.addImm(0);
// The table into which this call_indirect indexes.
MCSymbolWasm *Table = IsFuncrefCall
@@ -2253,6 +2255,71 @@ SDValue WebAssemblyTargetLowering::LowerIntrinsic(SDValue Op,
DAG.getTargetExternalSymbol(TlsBase, PtrVT)),
0);
}
+ case Intrinsic::wasm_ref_test_func: {
+ // First emit the TABLE_GET instruction to convert function pointer ==>
+ // funcref
+ MachineFunction &MF = DAG.getMachineFunction();
+ auto PtrVT = getPointerTy(MF.getDataLayout());
+ MCSymbol *Table =
+ WebAssembly::getOrCreateFunctionTableSymbol(MF.getContext(), Subtarget);
+ SDValue TableSym = DAG.getMCSymbol(Table, PtrVT);
+ SDValue FuncRef =
+ SDValue(DAG.getMachineNode(WebAssembly::TABLE_GET_FUNCREF, DL,
+ MVT::funcref, TableSym, Op.getOperand(1)),
+ 0);
+
+ // Encode the signature information into the type index placeholder.
+ // This gets decoded and converted into the actual type signature in
+ // WebAssemblyMCInstLower.cpp.
+ auto NParams = Op.getNumOperands() - 2;
+ auto Sig = APInt(NParams * 64, 0);
+ // The return type has to be a BlockType since it can be void.
+ {
+ SDValue Operand = Op.getOperand(2);
+ MVT VT = Operand.getValueType().getSimpleVT();
+ WebAssembly::BlockType V;
+ if (VT == MVT::Untyped) {
+ V = WebAssembly::BlockType::Void;
+ } else if (VT == MVT::i32) {
+ V = WebAssembly::BlockType::I32;
+ } else if (VT == MVT::i64) {
+ V = WebAssembly::BlockType::I64;
+ } else if (VT == MVT::f32) {
+ V = WebAssembly::BlockType::F32;
+ } else if (VT == MVT::f64) {
+ V = WebAssembly::BlockType::F64;
+ } else {
+ llvm_unreachable("Unhandled type!");
+ }
+ Sig |= (int64_t)V;
+ }
+ for (unsigned i = 3; i < Op.getNumOperands(); ++i) {
+ SDValue Operand = Op.getOperand(i);
+ MVT VT = Operand.getValueType().getSimpleVT();
+ wasm::ValType V;
+ if (VT == MVT::i32) {
+ V = wasm::ValType::I32;
+ } else if (VT == MVT::i64) {
+ V = wasm::ValType::I64;
+ } else if (VT == MVT::f32) {
+ V = wasm::ValType::F32;
+ } else if (VT == MVT::f64) {
+ V = wasm::ValType::F64;
+ } else {
+ llvm_unreachable("Unhandled type!");
+ }
+ Sig <<= 64;
+ Sig |= (int64_t)V;
+ }
+
+ SmallVector<SDValue, 4> Ops;
+ Ops.push_back(DAG.getTargetConstantAP(
+ Sig, DL, EVT::getIntegerVT(*DAG.getContext(), NParams * 64)));
+ Ops.push_back(FuncRef);
+ return SDValue(
+ DAG.getMachineNode(WebAssembly::REF_TEST_FUNCREF, DL, MVT::i32, Ops),
+ 0);
+ }
}
}
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp
index cc36244e63ff5..f725ec344d922 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp
@@ -15,13 +15,17 @@
#include "WebAssemblyMCInstLower.h"
#include "MCTargetDesc/WebAssemblyMCAsmInfo.h"
#include "MCTargetDesc/WebAssemblyMCTargetDesc.h"
+#include "MCTargetDesc/WebAssemblyMCTypeUtilities.h"
#include "TargetInfo/WebAssemblyTargetInfo.h"
#include "Utils/WebAssemblyTypeUtilities.h"
#include "WebAssemblyAsmPrinter.h"
#include "WebAssemblyMachineFunctionInfo.h"
#include "WebAssemblyUtilities.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/BinaryFormat/Wasm.h"
#include "llvm/CodeGen/AsmPrinter.h"
#include "llvm/CodeGen/MachineFunction.h"
+#include "llvm/CodeGen/MachineOperand.h"
#include "llvm/IR/Constants.h"
#include "llvm/MC/MCAsmInfo.h"
#include "llvm/MC/MCContext.h"
@@ -196,11 +200,80 @@ void WebAssemblyMCInstLower::lower(const MachineInstr *MI,
MCOp = MCOperand::createReg(WAReg);
break;
}
+ case llvm::MachineOperand::MO_CImmediate: {
+ // Lower type index placeholder for ref.test
+ // Currently this is the only way that CImmediates show up so panic if we
+ // get confused.
+ unsigned DescIndex = I - NumVariadicDefs;
+ if (DescIndex >= Desc.NumOperands) {
+ llvm_unreachable("unexpected CImmediate operand");
+ }
+ const MCOperandInfo &Info = Desc.operands()[DescIndex];
+ if (Info.OperandType != WebAssembly::OPERAND_TYPEINDEX) {
+ llvm_unreachable("unexpected CImmediate operand");
+ }
+ auto CImm = MO.getCImm()->getValue();
+ auto NumWords = CImm.getNumWords();
+ // Extract the type data we packed into the CImm in LowerRefTestFuncRef.
+ // We need to load the words from most significant to least significant
+ // order because of the way we bitshifted them in from the right.
+ // The return type needs special handling because it could be void.
+ auto ReturnType = static_cast<WebAssembly::BlockType>(
+ CImm.extractBitsAsZExtValue(64, (NumWords - 1) * 64));
+ SmallVector<wasm::ValType, 2> Returns;
+ switch (ReturnType) {
+ case WebAssembly::BlockType::Invalid:
+ llvm_unreachable("Invalid return type");
+ case WebAssembly::BlockType::I32:
+ Returns = {wasm::ValType::I32};
+ break;
+ case WebAssembly::BlockType::I64:
+ Returns = {wasm::ValType::I64};
+ break;
+ case WebAssembly::BlockType::F32:
+ Returns = {wasm::ValType::F32};
+ break;
+ case WebAssembly::BlockType::F64:
+ Returns = {wasm::ValType::F64};
+ break;
+ case WebAssembly::BlockType::Void:
+ Returns = {};
+ break;
+ case WebAssembly::BlockType::Exnref:
+ Returns = {wasm::ValType::EXNREF};
+ break;
+ case WebAssembly::BlockType::Externref:
+ Returns = {wasm::ValType::EXTERNREF};
+ break;
+ case WebAssembly::BlockType::Funcref:
+ Returns = {wasm::ValType::FUNCREF};
+ break;
+ case WebAssembly::BlockType::V128:
+ Returns = {wasm::ValType::V128};
+ break;
+ case WebAssembly::BlockType::Multivalue: {
+ llvm_unreachable("Invalid return type");
+ }
+ }
+ SmallVector<wasm::ValType, 4> Params;
+
+ for (int I = NumWords - 2; I >= 0; I--) {
+ auto Val = CImm.extractBitsAsZExtValue(64, 64 * I);
+ auto ParamType = static_cast<wasm::ValType>(Val);
+ Params.push_back(ParamType);
+ }
+ MCOp = lowerTypeIndexOperand(std::move(Returns), std::move(Params));
+ break;
+ }
case MachineOperand::MO_Immediate: {
unsigned DescIndex = I - NumVariadicDefs;
if (DescIndex < Desc.NumOperands) {
const MCOperandInfo &Info = Desc.operands()[DescIndex];
+ // Replace type index placeholder with actual type index. The type index
+ // placeholders are Immediates and have an operand type of
+ // OPERAND_TYPEINDEX or OPERAND_SIGNATURE.
if (Info.OperandType == WebAssembly::OPERAND_TYPEINDEX) {
+ // Lower type index placeholder for a CALL_INDIRECT instruction
SmallVector<wasm::ValType, 4> Returns;
SmallVector<wasm::ValType, 4> Params;
@@ -228,6 +301,7 @@ void WebAssemblyMCInstLower::lower(const MachineInstr *MI,
break;
}
if (Info.OperandType == WebAssembly::OPERAND_SIGNATURE) {
+ // Lower type index placeholder for blocks
auto BT = static_cast<WebAssembly::BlockType>(MO.getImm());
assert(BT != WebAssembly::BlockType::Invalid);
if (BT == WebAssembly::BlockType::Multivalue) {
diff --git a/llvm/test/CodeGen/WebAssembly/ref-test-func.ll b/llvm/test/CodeGen/WebAssembly/ref-test-func.ll
new file mode 100644
index 0000000000000..3fc848cd167f9
--- /dev/null
+++ b/llvm/test/CodeGen/WebAssembly/ref-test-func.ll
@@ -0,0 +1,42 @@
+; RUN: llc < %s -mcpu=mvp -mattr=+reference-types | FileCheck %s
+
+target triple = "wasm32-unknown-unknown"
+
+; CHECK-LABEL: test_function_pointer_signature_void:
+; CHECK-NEXT: .functype test_function_pointer_signature_void (i32) -> ()
+; CHECK-NEXT: .local funcref
+; CHECK: local.get 0
+; CHECK-NEXT: table.get __indirect_function_table
+; CHECK-NEXT: local.tee 1
+; CHECK-NEXT: ref.test (f32, f64, i32) -> (f32)
+; CHECK-NEXT: call use
+; CHECK-NEXT: local.get 1
+; CHECK-NEXT: ref.test (f32, f64, i32) -> (i32)
+; CHECK-NEXT: call use
+; CHECK-NEXT: local.get 1
+; CHECK-NEXT: ref.test (i32, i32, i32) -> (i32)
+; CHECK-NEXT: call use
+; CHECK-NEXT: local.get 1
+; CHECK-NEXT: ref.test (i32, i32, i32) -> ()
+; CHECK-NEXT: call use
+; CHECK-NEXT: local.get 1
+; CHECK-NEXT: ref.test () -> ()
+; CHECK-NEXT: call use
+
+; Function Attrs: nounwind
+define void @test_function_pointer_signature_void(ptr noundef %func) local_unnamed_addr #0 {
+entry:
+ %0 = tail call i32 (ptr, ...) @llvm.wasm.ref.test.func(ptr %func, float 0.000000e+00, float 0.000000e+00, double 0.000000e+00, i32 0)
+ tail call void @use(i32 noundef %0) #3
+ %1 = tail call i32 (ptr, ...) @llvm.wasm.ref.test.func(ptr %func, i32 0, float 0.000000e+00, double 0.000000e+00, i32 0)
+ tail call void @use(i32 noundef %1) #3
+ %2 = tail call i32 (ptr, ...) @llvm.wasm.ref.test.func(ptr %func, i32 0, i32 0, i32 0, i32 0)
+ tail call void @use(i32 noundef %2) #3
+ %3 = tail call i32 (ptr, ...) @llvm.wasm.ref.test.func(ptr %func, token poison, i32 0, i32 0, i32 0)
+ tail call void @use(i32 noundef %3) #3
+ %4 = tail call i32 (ptr, ...) @llvm.wasm.ref.test.func(ptr %func, token poison)
+ tail call void @use(i32 noundef %4) #3
+ ret void
+}
+
+declare void @use(i32 noundef) local_unnamed_addr #1
|
|
✅ With the latest revision this PR passed the C/C++ code formatter. |
To test whether or not a function pointer has the expected signature. Intended for adding a future clang builtin ` __builtin_wasm_test_function_pointer_signature` so we can test whether calling a function pointer will fail with function signature mismatch. This is an alternative to llvm#147076, where instead of using a ref.test.pseudo instruction with a custom inserter, we teach SelectionDag a type of TargetConstantAP nodes that get converted to a CImm in the MCInst layer.
2b1d843 to
5eb65fd
Compare
|
Thanks for the quick review @arsenm! |
|
Hmm one test failed: It seems unrelated to my changes so probably a flake? It passed before and I only changed functions in WebAssembly files that I introduced in this PR... |
|
@dschuff could you merge it? |
|
LLVM Buildbot has detected a new failure on builder Full details are available at: https://lab.llvm.org/buildbot/#/builders/51/builds/20261 Here is the relevant piece of the build log for the reference |
|
LLVM Buildbot has detected a new failure on builder Full details are available at: https://lab.llvm.org/buildbot/#/builders/3/builds/19416 Here is the relevant piece of the build log for the reference |
|
LLVM Buildbot has detected a new failure on builder Full details are available at: https://lab.llvm.org/buildbot/#/builders/187/builds/8391 Here is the relevant piece of the build log for the reference |
|
Hi, This PR broken a few buildbots. Could you take a look? |
|
LLVM Buildbot has detected a new failure on builder Full details are available at: https://lab.llvm.org/buildbot/#/builders/168/builds/14468 Here is the relevant piece of the build log for the reference |
|
LLVM Buildbot has detected a new failure on builder Full details are available at: https://lab.llvm.org/buildbot/#/builders/186/builds/10946 Here is the relevant piece of the build log for the reference |
|
The sanitizer problem is fixed by #150116. The CurDAG->getMachineNode(WebAssembly::TABLE_GET_FUNCREF, DL,
MVT::funcref, TableSym, Node->getOperand(1)),is an i64 but |
|
I suppose the codegen is also wrong for wasm64 since we use |
|
The failures in |
PR llvm#147486 broke the sanitizer buildbot. These captures were needed when toWasmValType emitted a diagnostic but are no longer needed since we changed it to an assertion failure. This removes the unneeded captures and should fix the sanitizer-buildbot.
|
Okay I updated #150116 to disable the test on wasm64 so I think that will fix both buildbot problems. |
…e clang intrinsic Tests if the runtime type of the function pointer matches the static type. If this returns false, calling the function pointer will trap. Uses `@llvm.wasm.ref.test.func` added in llvm#147486.
…#150116) PR #147486 broke the sanitizer and expensive-checks buildbot. These captures were needed when toWasmValType emitted a diagnostic but are no longer needed since we changed it to an assertion failure. This removes the unneeded captures and should fix the sanitizer-buildbot. I also fixed the codegen in the wasm64 target: table.get requires an i32 but in wasm64 the function pointer is an i64. We need an additional `i32.wrap_i64` to convert it. I also added `-verify-machineinstrs` to the tests so that the test suite validates this fix. Finally, I noticed that #150201 uses a feature of the intrinsic that is not covered by the tests, namely `ptr` arguments. So I added one additional test case to ensure that it works properly. cc @dschuff
This adds an llvm intrinsic for WebAssembly to test the type of a function. It is intended for adding a future clang builtin ` __builtin_wasm_test_function_pointer_signature` so we can test whether calling a function pointer will fail with function signature mismatch. Since the type of a function pointer is just `ptr` we can't figure out the expected type from that. The way I figured out to encode the type was by passing 0's of the appropriate type to the intrinsic. The first argument gives the expected type of the return type and the later values give the expected type of the arguments. So ```llvm @llvm.wasm.ref.test.func(ptr %func, float 0.000000e+00, double 0.000000e+00, i32 0) ``` tests if `%func` is of type `(double, i32) -> (i32)`. It will lower to: ```wat local.get $func table.get $__indirect_function_table ref.test (double, i32) -> (i32) ``` To indicate the function should be void, I somewhat arbitrarily picked `token poison`, so the following tests for `(i32) -> ()`: ```llvm @llvm.wasm.ref.test.func(ptr %func, token poison, i32 0) ``` To lower this intrinsic, we need some place to put the type information. With `encodeFunctionSignature()` we encode the signature information into an `APInt`. We decode it in `lowerEncodedFunctionSignature` in `WebAssemblyMCInstLower.cpp`.
…llvm#150116) PR llvm#147486 broke the sanitizer and expensive-checks buildbot. These captures were needed when toWasmValType emitted a diagnostic but are no longer needed since we changed it to an assertion failure. This removes the unneeded captures and should fix the sanitizer-buildbot. I also fixed the codegen in the wasm64 target: table.get requires an i32 but in wasm64 the function pointer is an i64. We need an additional `i32.wrap_i64` to convert it. I also added `-verify-machineinstrs` to the tests so that the test suite validates this fix. Finally, I noticed that llvm#150201 uses a feature of the intrinsic that is not covered by the tests, namely `ptr` arguments. So I added one additional test case to ensure that it works properly. cc @dschuff
llvm#150201) Tests if the runtime type of the function pointer matches the static type. If this returns false, calling the function pointer will trap. Uses `@llvm.wasm.ref.test.func` added in llvm#147486. Also adds a "gc" wasm feature to gate the use of the ref.test instruction.
This adds an llvm intrinsic for WebAssembly to test the type of a function. It is intended for adding a future clang builtin
__builtin_wasm_test_function_pointer_signatureso we can test whether calling a function pointer will fail with function signature mismatch.Since the type of a function pointer is just
ptrwe can't figure out the expected type from that.The way I figured out to encode the type was by passing 0's of the appropriate type to the intrinsic.
The first argument gives the expected type of the return type and the later values give the expected
type of the arguments. So
tests if
%funcis of type(double, i32) -> (i32). It will lower to:To indicate the function should be void, I somewhat arbitrarily picked
token poison, so the following tests for(i32) -> ():To lower this intrinsic, we need some place to put the type information. With
encodeFunctionSignature()we encode the signature information into anAPInt. We decode it inlowerEncodedFunctionSignatureinWebAssemblyMCInstLower.cpp.