https://github.com/hoodmane updated 
https://github.com/llvm/llvm-project/pull/147076

>From 2009bb945f57c67daa522448eddb2cc01aac4369 Mon Sep 17 00:00:00 2001
From: Hood Chatham <roberthoodchat...@gmail.com>
Date: Wed, 2 Jul 2025 20:53:56 +0200
Subject: [PATCH 1/8] Add __builtin_wasm_test_function_pointer_signature

This uses ref.test to check whether the function pointer's runtime type
matches its static type. If so, then calling it won't trap with "indirect
call signature mismatch". This would be very useful here:
https://github.com/python/cpython/blob/main/Python/emscripten_trampoline.c
and would allow us to fix function pointer mismatches on the WASI target
and the Emscripten target in a uniform way.
---
 .../clang/Basic/BuiltinsWebAssembly.def       |   6 +
 .../clang/Basic/DiagnosticSemaKinds.td        |   6 +
 clang/include/clang/Sema/SemaWasm.h           |   1 +
 .../CodeGen/TargetBuiltins/WebAssembly.cpp    |  58 +++++++++
 clang/lib/Sema/SemaWasm.cpp                   |  49 ++++++++
 llvm/include/llvm/IR/IntrinsicsWebAssembly.td |   4 +
 .../WebAssembly/WebAssemblyISelLowering.cpp   | 114 ++++++++++++++++++
 .../Target/WebAssembly/WebAssemblyInstrRef.td |   5 +
 .../WebAssembly/WebAssemblyMCInstLower.cpp    |  75 ++++++++++++
 9 files changed, 318 insertions(+)

diff --git a/clang/include/clang/Basic/BuiltinsWebAssembly.def 
b/clang/include/clang/Basic/BuiltinsWebAssembly.def
index e2afcc08064b2..1e03a40b1a22b 100644
--- a/clang/include/clang/Basic/BuiltinsWebAssembly.def
+++ b/clang/include/clang/Basic/BuiltinsWebAssembly.def
@@ -199,6 +199,12 @@ TARGET_BUILTIN(__builtin_wasm_ref_is_null_extern, "ii", 
"nct", "reference-types"
 // return type.
 TARGET_BUILTIN(__builtin_wasm_ref_null_func, "i", "nct", "reference-types")
 
+// Check if the static type of a function pointer matches its static type. Used
+// to avoid "function signature mismatch" traps. Takes a function pointer, uses
+// table.get to look up the pointer in __indirect_function_table and then
+// ref.test to test the type.
+TARGET_BUILTIN(__builtin_wasm_test_function_pointer_signature, "i.", "nct", 
"reference-types")
+
 // Table builtins
 TARGET_BUILTIN(__builtin_wasm_table_set,  "viii", "t", "reference-types")
 TARGET_BUILTIN(__builtin_wasm_table_get,  "iii", "t", "reference-types")
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td 
b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 968edd967e0c5..3a0d69c9c097b 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -7566,6 +7566,8 @@ def err_typecheck_illegal_increment_decrement : Error<
   "cannot %select{decrement|increment}1 value of type %0">;
 def err_typecheck_expect_int : Error<
   "used type %0 where integer is required">;
+def err_typecheck_expect_function_pointer
+    : Error<"used type %0 where function pointer is required">;
 def err_typecheck_expect_hlsl_resource : Error<
   "used type %0 where __hlsl_resource_t is required">;
 def err_typecheck_arithmetic_incomplete_or_sizeless_type : Error<
@@ -13164,6 +13166,10 @@ def err_wasm_builtin_arg_must_match_table_element_type 
: Error <
   "%ordinal0 argument must match the element type of the WebAssembly table in 
the %ordinal1 argument">;
 def err_wasm_builtin_arg_must_be_integer_type : Error <
   "%ordinal0 argument must be an integer">;
+def err_wasm_builtin_test_fp_sig_cannot_include_reference_type
+    : Error<"__builtin_wasm_test_function_pointer_signature not supported for "
+            "function pointers with reference types in their "
+            "%select{return|parameter}0 type">;
 
 // OpenACC diagnostics.
 def warn_acc_routine_unimplemented
diff --git a/clang/include/clang/Sema/SemaWasm.h 
b/clang/include/clang/Sema/SemaWasm.h
index 2123e073516cb..8c0639fd7e76f 100644
--- a/clang/include/clang/Sema/SemaWasm.h
+++ b/clang/include/clang/Sema/SemaWasm.h
@@ -37,6 +37,7 @@ class SemaWasm : public SemaBase {
   bool BuiltinWasmTableGrow(CallExpr *TheCall);
   bool BuiltinWasmTableFill(CallExpr *TheCall);
   bool BuiltinWasmTableCopy(CallExpr *TheCall);
+  bool BuiltinWasmTestFunctionPointerSignature(CallExpr *TheCall);
 
   WebAssemblyImportNameAttr *
   mergeImportNameAttr(Decl *D, const WebAssemblyImportNameAttr &AL);
diff --git a/clang/lib/CodeGen/TargetBuiltins/WebAssembly.cpp 
b/clang/lib/CodeGen/TargetBuiltins/WebAssembly.cpp
index b7fd70e855d40..0dc89e091eec9 100644
--- a/clang/lib/CodeGen/TargetBuiltins/WebAssembly.cpp
+++ b/clang/lib/CodeGen/TargetBuiltins/WebAssembly.cpp
@@ -12,7 +12,10 @@
 
 #include "CGBuiltin.h"
 #include "clang/Basic/TargetBuiltins.h"
+#include "llvm/ADT/APInt.h"
+#include "llvm/IR/Constants.h"
 #include "llvm/IR/IntrinsicsWebAssembly.h"
+#include "llvm/Support/ErrorHandling.h"
 
 using namespace clang;
 using namespace CodeGen;
@@ -218,6 +221,61 @@ Value 
*CodeGenFunction::EmitWebAssemblyBuiltinExpr(unsigned BuiltinID,
     Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_ref_null_func);
     return Builder.CreateCall(Callee);
   }
+  case WebAssembly::BI__builtin_wasm_test_function_pointer_signature: {
+    Value *FuncRef = EmitScalarExpr(E->getArg(0));
+
+    // Get the function type from the argument's static type
+    QualType ArgType = E->getArg(0)->getType();
+    const PointerType *PtrTy = ArgType->getAs<PointerType>();
+    assert(PtrTy && "Sema should have ensured this is a function pointer");
+
+    const FunctionType *FuncTy = 
PtrTy->getPointeeType()->getAs<FunctionType>();
+    assert(FuncTy && "Sema should have ensured this is a function pointer");
+
+    // In the llvm IR, we won't have access anymore to the type of the function
+    // pointer so we need to insert this type information somehow. We gave the
+    // @llvm.wasm.ref.test.func varargs and here we add an extra 0 argument of
+    // the type corresponding to the type of each argument of the function
+    // signature. When we lower from the IR we'll use the types of these
+    // arguments to determine the signature we want to test for.
+
+    // Make a type index constant with 0. This gets replaced by the actual type
+    // in WebAssemblyMCInstLower.cpp.
+    llvm::FunctionType *LLVMFuncTy =
+        cast<llvm::FunctionType>(ConvertType(QualType(FuncTy, 0)));
+
+    uint NParams = LLVMFuncTy->getNumParams();
+    std::vector<Value *> Args;
+    Args.reserve(NParams + 1);
+    // The only real argument is the FuncRef
+    Args.push_back(FuncRef);
+
+    // Add the type information
+    auto addType = [this, &Args](llvm::Type *T) {
+      if (T->isVoidTy()) {
+        // Use TokenTy as dummy for void b/c the verifier rejects a
+        // void arg with 'Instruction operands must be first-class values!'
+        // TokenTy isn't a first class value either but apparently the verifier
+        // doesn't mind it.
+        Args.push_back(
+            UndefValue::get(llvm::Type::getTokenTy(getLLVMContext())));
+      } else if (T->isFloatingPointTy()) {
+        Args.push_back(ConstantFP::get(T, 0));
+      } else if (T->isIntegerTy()) {
+        Args.push_back(ConstantInt::get(T, 0));
+      } else {
+        // TODO: Handle reference types here. For now, we reject them in Sema.
+        llvm_unreachable("Unhandled type");
+      }
+    };
+
+    addType(LLVMFuncTy->getReturnType());
+    for (uint i = 0; i < NParams; i++) {
+      addType(LLVMFuncTy->getParamType(i));
+    }
+    Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_ref_test_func);
+    return Builder.CreateCall(Callee, Args);
+  }
   case WebAssembly::BI__builtin_wasm_swizzle_i8x16: {
     Value *Src = EmitScalarExpr(E->getArg(0));
     Value *Indices = EmitScalarExpr(E->getArg(1));
diff --git a/clang/lib/Sema/SemaWasm.cpp b/clang/lib/Sema/SemaWasm.cpp
index 6faea24a46b09..8998492a71619 100644
--- a/clang/lib/Sema/SemaWasm.cpp
+++ b/clang/lib/Sema/SemaWasm.cpp
@@ -227,6 +227,53 @@ bool SemaWasm::BuiltinWasmTableCopy(CallExpr *TheCall) {
   return false;
 }
 
+bool SemaWasm::BuiltinWasmTestFunctionPointerSignature(CallExpr *TheCall) {
+  if (SemaRef.checkArgCount(TheCall, 1))
+    return true;
+
+  Expr *FuncPtrArg = TheCall->getArg(0);
+  QualType ArgType = FuncPtrArg->getType();
+
+  // Check that the argument is a function pointer
+  const PointerType *PtrTy = ArgType->getAs<PointerType>();
+  if (!PtrTy) {
+    return Diag(FuncPtrArg->getBeginLoc(),
+                diag::err_typecheck_expect_function_pointer)
+           << ArgType << FuncPtrArg->getSourceRange();
+  }
+
+  const FunctionProtoType *FuncTy =
+      PtrTy->getPointeeType()->getAs<FunctionProtoType>();
+  if (!FuncTy) {
+    return Diag(FuncPtrArg->getBeginLoc(),
+                diag::err_typecheck_expect_function_pointer)
+           << ArgType << FuncPtrArg->getSourceRange();
+  }
+
+  // Check that the function pointer doesn't use reference types
+  if (FuncTy->getReturnType().isWebAssemblyReferenceType()) {
+    return Diag(
+               FuncPtrArg->getBeginLoc(),
+               
diag::err_wasm_builtin_test_fp_sig_cannot_include_reference_type)
+           << 0 << FuncTy->getReturnType() << FuncPtrArg->getSourceRange();
+  }
+  auto NParams = FuncTy->getNumParams();
+  for (unsigned I = 0; I < NParams; I++) {
+    if (FuncTy->getParamType(I).isWebAssemblyReferenceType()) {
+      return Diag(
+                 FuncPtrArg->getBeginLoc(),
+                 diag::
+                     
err_wasm_builtin_test_fp_sig_cannot_include_reference_type)
+             << 1 << FuncPtrArg->getSourceRange();
+    }
+  }
+
+  // Set return type to int (the result of the test)
+  TheCall->setType(getASTContext().IntTy);
+
+  return false;
+}
+
 bool SemaWasm::CheckWebAssemblyBuiltinFunctionCall(const TargetInfo &TI,
                                                    unsigned BuiltinID,
                                                    CallExpr *TheCall) {
@@ -249,6 +296,8 @@ bool SemaWasm::CheckWebAssemblyBuiltinFunctionCall(const 
TargetInfo &TI,
     return BuiltinWasmTableFill(TheCall);
   case WebAssembly::BI__builtin_wasm_table_copy:
     return BuiltinWasmTableCopy(TheCall);
+  case WebAssembly::BI__builtin_wasm_test_function_pointer_signature:
+    return BuiltinWasmTestFunctionPointerSignature(TheCall);
   }
 
   return false;
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/Target/WebAssembly/WebAssemblyISelLowering.cpp 
b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp
index bf2e04caa0a61..755f3a2293445 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"
@@ -501,6 +502,51 @@ MVT 
WebAssemblyTargetLowering::getScalarShiftAmountTy(const DataLayout & /*DL*/,
   return Result;
 }
 
+static MachineBasicBlock *LowerRefTestFuncRef(MachineInstr &MI, DebugLoc DL,
+                                              MachineBasicBlock *BB,
+                                              const TargetInstrInfo &TII) {
+  // Lower a REF_TEST_FUNCREF_PSEUDO instruction into a REF_TEST_FUNCREF
+  // instruction by combining the signature info Imm operands that
+  // SelectionDag/InstrEmitter.cpp makes into one CImm operand. Put this into
+  // the type index placeholder for REF_TEST_FUNCREF
+  Register ResultReg = MI.getOperand(0).getReg();
+  Register FuncRefReg = MI.getOperand(1).getReg();
+
+  auto NParams = MI.getNumOperands() - 3;
+  auto Sig = APInt(NParams * 64, 0);
+
+  {
+    uint64_t V = MI.getOperand(2).getImm();
+    Sig |= int64_t(V);
+  }
+
+  for (unsigned I = 3; I < MI.getNumOperands(); I++) {
+    const MachineOperand &MO = MI.getOperand(I);
+    if (!MO.isImm()) {
+      // I'm not really sure what these are or where they come from but it 
seems
+      // to be okay to ignore them
+      continue;
+    }
+    uint16_t V = MO.getImm();
+    Sig <<= 64;
+    Sig |= int64_t(V);
+  }
+
+  ConstantInt *TypeInfo =
+      ConstantInt::get(BB->getParent()->getFunction().getContext(), Sig);
+
+  // Put the type info first in the placeholder for the type index, then the
+  // actual funcref arg
+  BuildMI(*BB, MI, DL, TII.get(WebAssembly::REF_TEST_FUNCREF), ResultReg)
+      .addCImm(TypeInfo)
+      .addReg(FuncRefReg);
+
+  // Remove the original instruction
+  MI.eraseFromParent();
+
+  return BB;
+}
+
 // Lower an fp-to-int conversion operator from the LLVM opcode, which has an
 // undefined result on invalid/overflow, to the WebAssembly opcode, which
 // traps on invalid/overflow.
@@ -862,6 +908,8 @@ MachineBasicBlock 
*WebAssemblyTargetLowering::EmitInstrWithCustomInserter(
   switch (MI.getOpcode()) {
   default:
     llvm_unreachable("Unexpected instr type to insert");
+  case WebAssembly::REF_TEST_FUNCREF_PSEUDO:
+    return LowerRefTestFuncRef(MI, DL, BB, TII);
   case WebAssembly::FP_TO_SINT_I32_F32:
     return LowerFPToInt(MI, DL, BB, TII, false, false, false,
                         WebAssembly::I32_TRUNC_S_F32);
@@ -2253,6 +2301,72 @@ 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);
+
+    SmallVector<SDValue, 4> Ops;
+    Ops.push_back(FuncRef);
+
+    // We want to encode the type information into an APInt which we'll put
+    // in a CImm. However, in SelectionDag/InstrEmitter.cpp there is no code
+    // path that emits a CImm. So we need a custom inserter to put it in.
+
+    // We'll put each type argument in a separate TargetConstant which gets
+    // lowered to a MachineInstruction Imm. We combine these into a CImm in our
+    // custom inserter because it creates a problem downstream to have all 
these
+    // extra immediates.
+    {
+      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!");
+      }
+      Ops.push_back(DAG.getTargetConstant((int64_t)V, DL, MVT::i64));
+    }
+
+    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!");
+      }
+      Ops.push_back(DAG.getTargetConstant((int64_t)V, DL, MVT::i64));
+    }
+
+    return SDValue(DAG.getMachineNode(WebAssembly::REF_TEST_FUNCREF_PSEUDO, DL,
+                                      MVT::i32, Ops),
+                   0);
+  }
   }
 }
 
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyInstrRef.td 
b/llvm/lib/Target/WebAssembly/WebAssemblyInstrRef.td
index 40b87a084c687..0c61f5770e748 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyInstrRef.td
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyInstrRef.td
@@ -36,6 +36,11 @@ multiclass REF_I<WebAssemblyRegClass rc, ValueType vt, 
string ht> {
         Requires<[HasReferenceTypes]>;
 }
 
+let usesCustomInserter = 1, isPseudo = 1 in defm REF_TEST_FUNCREF_PSEUDO
+    : I<(outs I32:$res), (ins TypeIndex:$type, FUNCREF:$ref, variable_ops),
+        (outs), (ins TypeIndex:$type), [], "ref.test.pseudo\t$type, $ref",
+        "ref.test.pseudo $type", -1>;
+
 defm REF_TEST_FUNCREF :
   I<(outs I32: $res),
     (ins TypeIndex:$type, FUNCREF: $ref),
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp 
b/llvm/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp
index cc36244e63ff5..449361530c550 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,81 @@ 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));
+      assert(ReturnType != WebAssembly::BlockType::Invalid);
+      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 immedates or CImmediates 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 +302,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) {

>From d52e1e85bf0ce00d894372b1c6f3fe73b1a64600 Mon Sep 17 00:00:00 2001
From: Hood Chatham <roberthoodchat...@gmail.com>
Date: Fri, 4 Jul 2025 17:37:38 +0200
Subject: [PATCH 2/8] Update sema test

---
 .../clang/Basic/DiagnosticSemaKinds.td        |  6 ++---
 clang/test/Sema/builtins-wasm.c               | 24 +++++++++++++++++++
 2 files changed, 27 insertions(+), 3 deletions(-)

diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td 
b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 3a0d69c9c097b..c0aee1f6b264f 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -13167,9 +13167,9 @@ def err_wasm_builtin_arg_must_match_table_element_type 
: Error <
 def err_wasm_builtin_arg_must_be_integer_type : Error <
   "%ordinal0 argument must be an integer">;
 def err_wasm_builtin_test_fp_sig_cannot_include_reference_type
-    : Error<"__builtin_wasm_test_function_pointer_signature not supported for "
-            "function pointers with reference types in their "
-            "%select{return|parameter}0 type">;
+    : Error<"not supported for "
+            "function pointers with a reference type %select{return "
+            "value|parameter}0">;
 
 // OpenACC diagnostics.
 def warn_acc_routine_unimplemented
diff --git a/clang/test/Sema/builtins-wasm.c b/clang/test/Sema/builtins-wasm.c
index 31e5291d3ae5e..a3486b1aedb13 100644
--- a/clang/test/Sema/builtins-wasm.c
+++ b/clang/test/Sema/builtins-wasm.c
@@ -54,3 +54,27 @@ void test_table_copy(int dst_idx, int src_idx, int nelem) {
   __builtin_wasm_table_copy(table, table, dst_idx, src_idx, table);    // 
expected-error {{5th argument must be an integer}}
   __builtin_wasm_table_copy(table, table, dst_idx, src_idx, nelem);
 }
+
+typedef void (*F1)(void);
+typedef int (*F2)(int);
+typedef int (*F3)(__externref_t);
+typedef __externref_t (*F4)(int);
+
+void test_function_pointer_signature() {
+  // Test argument count validation
+  (void)__builtin_wasm_test_function_pointer_signature(); // expected-error 
{{too few arguments to function call, expected 1, have 0}}
+  (void)__builtin_wasm_test_function_pointer_signature((F1)0, (F2)0); // 
expected-error {{too many arguments to function call, expected 1, have 2}}
+
+  // // Test argument type validation - should require function pointer
+  (void)__builtin_wasm_test_function_pointer_signature((void*)0); // 
expected-error {{used type 'void *' where function pointer is required}}
+  (void)__builtin_wasm_test_function_pointer_signature((int)0);   // 
expected-error {{used type 'int' where function pointer is required}}
+  (void)__builtin_wasm_test_function_pointer_signature((F3)0);   // 
expected-error {{not supported for function pointers with a reference type 
parameter}}
+  (void)__builtin_wasm_test_function_pointer_signature((F4)0);   // 
expected-error {{not supported for function pointers with a reference type 
return value}}
+
+  // // Test valid usage
+  int res = __builtin_wasm_test_function_pointer_signature((F1)0);
+  res = __builtin_wasm_test_function_pointer_signature((F2)0);
+
+  // Test return type
+  
_Static_assert(EXPR_HAS_TYPE(__builtin_wasm_test_function_pointer_signature((F1)0),
 int), "");
+}

>From bec1ceda5d4a03dfc5b01ba7ada7a579935af19e Mon Sep 17 00:00:00 2001
From: Hood Chatham <roberthoodchat...@gmail.com>
Date: Fri, 4 Jul 2025 17:47:57 +0200
Subject: [PATCH 3/8] Update builtins-wasm.c CodeGen test

---
 clang/test/CodeGen/builtins-wasm.c | 24 ++++++++++++++++++++++++
 1 file changed, 24 insertions(+)

diff --git a/clang/test/CodeGen/builtins-wasm.c 
b/clang/test/CodeGen/builtins-wasm.c
index d8aff82b0c140..bb32cb0afea51 100644
--- a/clang/test/CodeGen/builtins-wasm.c
+++ b/clang/test/CodeGen/builtins-wasm.c
@@ -751,3 +751,27 @@ void *tp (void) {
   return __builtin_thread_pointer ();
   // WEBASSEMBLY: call {{.*}} @llvm.thread.pointer.p0()
 }
+
+
+typedef void (*funcref_t)();
+typedef int (*funcref_int_t)(int);
+typedef float (*F1)(float, double, int);
+typedef int (*F2)(float, double, int);
+typedef int (*F3)(int, int, int);
+typedef void (*F4)(int, int, int);
+typedef void (*F5)(void);
+
+void use(int);
+
+void test_function_pointer_signature_void(F1 func) {
+  // WEBASSEMBLY:  %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)
+  use(__builtin_wasm_test_function_pointer_signature(func));
+  // WEBASSEMBLY:  %1 = tail call i32 (ptr, ...) @llvm.wasm.ref.test.func(ptr 
%func, i32 0, float 0.000000e+00, double 0.000000e+00, i32 0)
+  use(__builtin_wasm_test_function_pointer_signature((F2)func));
+  // WEBASSEMBLY:  %2 = tail call i32 (ptr, ...) @llvm.wasm.ref.test.func(ptr 
%func, i32 0, i32 0, i32 0, i32 0)
+  use(__builtin_wasm_test_function_pointer_signature((F3)func));
+  // WEBASSEMBLY:  %3 = tail call i32 (ptr, ...) @llvm.wasm.ref.test.func(ptr 
%func, token undef, i32 0, i32 0, i32 0)
+  use(__builtin_wasm_test_function_pointer_signature((F4)func));
+  // WEBASSEMBLY:  %4 = tail call i32 (ptr, ...) @llvm.wasm.ref.test.func(ptr 
%func, token undef)
+  use(__builtin_wasm_test_function_pointer_signature((F5)func));
+}

>From 35c0757f3540e635f30e0a0fd1f040515dfde11a Mon Sep 17 00:00:00 2001
From: Hood Chatham <roberthoodchat...@gmail.com>
Date: Fri, 4 Jul 2025 18:02:01 +0200
Subject: [PATCH 4/8] Use Poison instead of Undef

---
 clang/lib/CodeGen/TargetBuiltins/WebAssembly.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/clang/lib/CodeGen/TargetBuiltins/WebAssembly.cpp 
b/clang/lib/CodeGen/TargetBuiltins/WebAssembly.cpp
index 0dc89e091eec9..4167a5f49b732 100644
--- a/clang/lib/CodeGen/TargetBuiltins/WebAssembly.cpp
+++ b/clang/lib/CodeGen/TargetBuiltins/WebAssembly.cpp
@@ -258,7 +258,7 @@ Value *CodeGenFunction::EmitWebAssemblyBuiltinExpr(unsigned 
BuiltinID,
         // TokenTy isn't a first class value either but apparently the verifier
         // doesn't mind it.
         Args.push_back(
-            UndefValue::get(llvm::Type::getTokenTy(getLLVMContext())));
+            PoisonValue::get(llvm::Type::getTokenTy(getLLVMContext())));
       } else if (T->isFloatingPointTy()) {
         Args.push_back(ConstantFP::get(T, 0));
       } else if (T->isIntegerTy()) {

>From a8a61964281592d54a73be78ed1bc0752e4260b3 Mon Sep 17 00:00:00 2001
From: Hood Chatham <roberthoodchat...@gmail.com>
Date: Fri, 4 Jul 2025 18:28:26 +0200
Subject: [PATCH 5/8] Add llvm ir test

---
 .../test/CodeGen/WebAssembly/ref-test-func.ll | 42 +++++++++++++++++++
 1 file changed, 42 insertions(+)
 create mode 100644 llvm/test/CodeGen/WebAssembly/ref-test-func.ll

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

>From b65ab586fbed608f266db60c89ac524366e11e81 Mon Sep 17 00:00:00 2001
From: Hood Chatham <roberthoodchat...@gmail.com>
Date: Fri, 4 Jul 2025 18:47:01 +0200
Subject: [PATCH 6/8] Update codegen test

---
 clang/test/CodeGen/builtins-wasm.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/clang/test/CodeGen/builtins-wasm.c 
b/clang/test/CodeGen/builtins-wasm.c
index bb32cb0afea51..5d0795841eb48 100644
--- a/clang/test/CodeGen/builtins-wasm.c
+++ b/clang/test/CodeGen/builtins-wasm.c
@@ -770,8 +770,8 @@ void test_function_pointer_signature_void(F1 func) {
   use(__builtin_wasm_test_function_pointer_signature((F2)func));
   // WEBASSEMBLY:  %2 = tail call i32 (ptr, ...) @llvm.wasm.ref.test.func(ptr 
%func, i32 0, i32 0, i32 0, i32 0)
   use(__builtin_wasm_test_function_pointer_signature((F3)func));
-  // WEBASSEMBLY:  %3 = tail call i32 (ptr, ...) @llvm.wasm.ref.test.func(ptr 
%func, token undef, i32 0, i32 0, i32 0)
+  // WEBASSEMBLY:  %3 = tail call i32 (ptr, ...) @llvm.wasm.ref.test.func(ptr 
%func, token poison, i32 0, i32 0, i32 0)
   use(__builtin_wasm_test_function_pointer_signature((F4)func));
-  // WEBASSEMBLY:  %4 = tail call i32 (ptr, ...) @llvm.wasm.ref.test.func(ptr 
%func, token undef)
+  // WEBASSEMBLY:  %4 = tail call i32 (ptr, ...) @llvm.wasm.ref.test.func(ptr 
%func, token poison)
   use(__builtin_wasm_test_function_pointer_signature((F5)func));
 }

>From 1afbce88d1c700fd0f75b40eb72488dd32f2bb43 Mon Sep 17 00:00:00 2001
From: Hood Chatham <roberthoodchat...@gmail.com>
Date: Mon, 7 Jul 2025 19:51:27 +0200
Subject: [PATCH 7/8] Update some comments

---
 llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp | 1 +
 llvm/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp  | 3 +--
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp 
b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp
index 755f3a2293445..4e71e12653473 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp
@@ -840,6 +840,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
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp 
b/llvm/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp
index 449361530c550..f725ec344d922 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp
@@ -220,7 +220,6 @@ void WebAssemblyMCInstLower::lower(const MachineInstr *MI,
       // The return type needs special handling because it could be void.
       auto ReturnType = static_cast<WebAssembly::BlockType>(
           CImm.extractBitsAsZExtValue(64, (NumWords - 1) * 64));
-      assert(ReturnType != WebAssembly::BlockType::Invalid);
       SmallVector<wasm::ValType, 2> Returns;
       switch (ReturnType) {
       case WebAssembly::BlockType::Invalid:
@@ -271,7 +270,7 @@ void WebAssemblyMCInstLower::lower(const MachineInstr *MI,
       if (DescIndex < Desc.NumOperands) {
         const MCOperandInfo &Info = Desc.operands()[DescIndex];
         // Replace type index placeholder with actual type index. The type 
index
-        // placeholders are immedates or CImmediates and have an operand type 
of
+        // 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

>From 60cb6c2fe461fc62e69929a326c1bb0cf885fca9 Mon Sep 17 00:00:00 2001
From: Hood Chatham <roberthoodchat...@gmail.com>
Date: Mon, 7 Jul 2025 22:49:02 +0200
Subject: [PATCH 8/8] Revert clang changes

---
 .../clang/Basic/BuiltinsWebAssembly.def       |  6 --
 .../clang/Basic/DiagnosticSemaKinds.td        |  6 --
 clang/include/clang/Sema/SemaWasm.h           |  1 -
 .../CodeGen/TargetBuiltins/WebAssembly.cpp    | 58 -------------------
 clang/lib/Sema/SemaWasm.cpp                   | 49 ----------------
 clang/test/CodeGen/builtins-wasm.c            | 24 --------
 clang/test/Sema/builtins-wasm.c               | 24 --------
 7 files changed, 168 deletions(-)

diff --git a/clang/include/clang/Basic/BuiltinsWebAssembly.def 
b/clang/include/clang/Basic/BuiltinsWebAssembly.def
index 1e03a40b1a22b..e2afcc08064b2 100644
--- a/clang/include/clang/Basic/BuiltinsWebAssembly.def
+++ b/clang/include/clang/Basic/BuiltinsWebAssembly.def
@@ -199,12 +199,6 @@ TARGET_BUILTIN(__builtin_wasm_ref_is_null_extern, "ii", 
"nct", "reference-types"
 // return type.
 TARGET_BUILTIN(__builtin_wasm_ref_null_func, "i", "nct", "reference-types")
 
-// Check if the static type of a function pointer matches its static type. Used
-// to avoid "function signature mismatch" traps. Takes a function pointer, uses
-// table.get to look up the pointer in __indirect_function_table and then
-// ref.test to test the type.
-TARGET_BUILTIN(__builtin_wasm_test_function_pointer_signature, "i.", "nct", 
"reference-types")
-
 // Table builtins
 TARGET_BUILTIN(__builtin_wasm_table_set,  "viii", "t", "reference-types")
 TARGET_BUILTIN(__builtin_wasm_table_get,  "iii", "t", "reference-types")
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td 
b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index c0aee1f6b264f..968edd967e0c5 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -7566,8 +7566,6 @@ def err_typecheck_illegal_increment_decrement : Error<
   "cannot %select{decrement|increment}1 value of type %0">;
 def err_typecheck_expect_int : Error<
   "used type %0 where integer is required">;
-def err_typecheck_expect_function_pointer
-    : Error<"used type %0 where function pointer is required">;
 def err_typecheck_expect_hlsl_resource : Error<
   "used type %0 where __hlsl_resource_t is required">;
 def err_typecheck_arithmetic_incomplete_or_sizeless_type : Error<
@@ -13166,10 +13164,6 @@ def err_wasm_builtin_arg_must_match_table_element_type 
: Error <
   "%ordinal0 argument must match the element type of the WebAssembly table in 
the %ordinal1 argument">;
 def err_wasm_builtin_arg_must_be_integer_type : Error <
   "%ordinal0 argument must be an integer">;
-def err_wasm_builtin_test_fp_sig_cannot_include_reference_type
-    : Error<"not supported for "
-            "function pointers with a reference type %select{return "
-            "value|parameter}0">;
 
 // OpenACC diagnostics.
 def warn_acc_routine_unimplemented
diff --git a/clang/include/clang/Sema/SemaWasm.h 
b/clang/include/clang/Sema/SemaWasm.h
index 8c0639fd7e76f..2123e073516cb 100644
--- a/clang/include/clang/Sema/SemaWasm.h
+++ b/clang/include/clang/Sema/SemaWasm.h
@@ -37,7 +37,6 @@ class SemaWasm : public SemaBase {
   bool BuiltinWasmTableGrow(CallExpr *TheCall);
   bool BuiltinWasmTableFill(CallExpr *TheCall);
   bool BuiltinWasmTableCopy(CallExpr *TheCall);
-  bool BuiltinWasmTestFunctionPointerSignature(CallExpr *TheCall);
 
   WebAssemblyImportNameAttr *
   mergeImportNameAttr(Decl *D, const WebAssemblyImportNameAttr &AL);
diff --git a/clang/lib/CodeGen/TargetBuiltins/WebAssembly.cpp 
b/clang/lib/CodeGen/TargetBuiltins/WebAssembly.cpp
index 4167a5f49b732..b7fd70e855d40 100644
--- a/clang/lib/CodeGen/TargetBuiltins/WebAssembly.cpp
+++ b/clang/lib/CodeGen/TargetBuiltins/WebAssembly.cpp
@@ -12,10 +12,7 @@
 
 #include "CGBuiltin.h"
 #include "clang/Basic/TargetBuiltins.h"
-#include "llvm/ADT/APInt.h"
-#include "llvm/IR/Constants.h"
 #include "llvm/IR/IntrinsicsWebAssembly.h"
-#include "llvm/Support/ErrorHandling.h"
 
 using namespace clang;
 using namespace CodeGen;
@@ -221,61 +218,6 @@ Value 
*CodeGenFunction::EmitWebAssemblyBuiltinExpr(unsigned BuiltinID,
     Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_ref_null_func);
     return Builder.CreateCall(Callee);
   }
-  case WebAssembly::BI__builtin_wasm_test_function_pointer_signature: {
-    Value *FuncRef = EmitScalarExpr(E->getArg(0));
-
-    // Get the function type from the argument's static type
-    QualType ArgType = E->getArg(0)->getType();
-    const PointerType *PtrTy = ArgType->getAs<PointerType>();
-    assert(PtrTy && "Sema should have ensured this is a function pointer");
-
-    const FunctionType *FuncTy = 
PtrTy->getPointeeType()->getAs<FunctionType>();
-    assert(FuncTy && "Sema should have ensured this is a function pointer");
-
-    // In the llvm IR, we won't have access anymore to the type of the function
-    // pointer so we need to insert this type information somehow. We gave the
-    // @llvm.wasm.ref.test.func varargs and here we add an extra 0 argument of
-    // the type corresponding to the type of each argument of the function
-    // signature. When we lower from the IR we'll use the types of these
-    // arguments to determine the signature we want to test for.
-
-    // Make a type index constant with 0. This gets replaced by the actual type
-    // in WebAssemblyMCInstLower.cpp.
-    llvm::FunctionType *LLVMFuncTy =
-        cast<llvm::FunctionType>(ConvertType(QualType(FuncTy, 0)));
-
-    uint NParams = LLVMFuncTy->getNumParams();
-    std::vector<Value *> Args;
-    Args.reserve(NParams + 1);
-    // The only real argument is the FuncRef
-    Args.push_back(FuncRef);
-
-    // Add the type information
-    auto addType = [this, &Args](llvm::Type *T) {
-      if (T->isVoidTy()) {
-        // Use TokenTy as dummy for void b/c the verifier rejects a
-        // void arg with 'Instruction operands must be first-class values!'
-        // TokenTy isn't a first class value either but apparently the verifier
-        // doesn't mind it.
-        Args.push_back(
-            PoisonValue::get(llvm::Type::getTokenTy(getLLVMContext())));
-      } else if (T->isFloatingPointTy()) {
-        Args.push_back(ConstantFP::get(T, 0));
-      } else if (T->isIntegerTy()) {
-        Args.push_back(ConstantInt::get(T, 0));
-      } else {
-        // TODO: Handle reference types here. For now, we reject them in Sema.
-        llvm_unreachable("Unhandled type");
-      }
-    };
-
-    addType(LLVMFuncTy->getReturnType());
-    for (uint i = 0; i < NParams; i++) {
-      addType(LLVMFuncTy->getParamType(i));
-    }
-    Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_ref_test_func);
-    return Builder.CreateCall(Callee, Args);
-  }
   case WebAssembly::BI__builtin_wasm_swizzle_i8x16: {
     Value *Src = EmitScalarExpr(E->getArg(0));
     Value *Indices = EmitScalarExpr(E->getArg(1));
diff --git a/clang/lib/Sema/SemaWasm.cpp b/clang/lib/Sema/SemaWasm.cpp
index 8998492a71619..6faea24a46b09 100644
--- a/clang/lib/Sema/SemaWasm.cpp
+++ b/clang/lib/Sema/SemaWasm.cpp
@@ -227,53 +227,6 @@ bool SemaWasm::BuiltinWasmTableCopy(CallExpr *TheCall) {
   return false;
 }
 
-bool SemaWasm::BuiltinWasmTestFunctionPointerSignature(CallExpr *TheCall) {
-  if (SemaRef.checkArgCount(TheCall, 1))
-    return true;
-
-  Expr *FuncPtrArg = TheCall->getArg(0);
-  QualType ArgType = FuncPtrArg->getType();
-
-  // Check that the argument is a function pointer
-  const PointerType *PtrTy = ArgType->getAs<PointerType>();
-  if (!PtrTy) {
-    return Diag(FuncPtrArg->getBeginLoc(),
-                diag::err_typecheck_expect_function_pointer)
-           << ArgType << FuncPtrArg->getSourceRange();
-  }
-
-  const FunctionProtoType *FuncTy =
-      PtrTy->getPointeeType()->getAs<FunctionProtoType>();
-  if (!FuncTy) {
-    return Diag(FuncPtrArg->getBeginLoc(),
-                diag::err_typecheck_expect_function_pointer)
-           << ArgType << FuncPtrArg->getSourceRange();
-  }
-
-  // Check that the function pointer doesn't use reference types
-  if (FuncTy->getReturnType().isWebAssemblyReferenceType()) {
-    return Diag(
-               FuncPtrArg->getBeginLoc(),
-               
diag::err_wasm_builtin_test_fp_sig_cannot_include_reference_type)
-           << 0 << FuncTy->getReturnType() << FuncPtrArg->getSourceRange();
-  }
-  auto NParams = FuncTy->getNumParams();
-  for (unsigned I = 0; I < NParams; I++) {
-    if (FuncTy->getParamType(I).isWebAssemblyReferenceType()) {
-      return Diag(
-                 FuncPtrArg->getBeginLoc(),
-                 diag::
-                     
err_wasm_builtin_test_fp_sig_cannot_include_reference_type)
-             << 1 << FuncPtrArg->getSourceRange();
-    }
-  }
-
-  // Set return type to int (the result of the test)
-  TheCall->setType(getASTContext().IntTy);
-
-  return false;
-}
-
 bool SemaWasm::CheckWebAssemblyBuiltinFunctionCall(const TargetInfo &TI,
                                                    unsigned BuiltinID,
                                                    CallExpr *TheCall) {
@@ -296,8 +249,6 @@ bool SemaWasm::CheckWebAssemblyBuiltinFunctionCall(const 
TargetInfo &TI,
     return BuiltinWasmTableFill(TheCall);
   case WebAssembly::BI__builtin_wasm_table_copy:
     return BuiltinWasmTableCopy(TheCall);
-  case WebAssembly::BI__builtin_wasm_test_function_pointer_signature:
-    return BuiltinWasmTestFunctionPointerSignature(TheCall);
   }
 
   return false;
diff --git a/clang/test/CodeGen/builtins-wasm.c 
b/clang/test/CodeGen/builtins-wasm.c
index 5d0795841eb48..d8aff82b0c140 100644
--- a/clang/test/CodeGen/builtins-wasm.c
+++ b/clang/test/CodeGen/builtins-wasm.c
@@ -751,27 +751,3 @@ void *tp (void) {
   return __builtin_thread_pointer ();
   // WEBASSEMBLY: call {{.*}} @llvm.thread.pointer.p0()
 }
-
-
-typedef void (*funcref_t)();
-typedef int (*funcref_int_t)(int);
-typedef float (*F1)(float, double, int);
-typedef int (*F2)(float, double, int);
-typedef int (*F3)(int, int, int);
-typedef void (*F4)(int, int, int);
-typedef void (*F5)(void);
-
-void use(int);
-
-void test_function_pointer_signature_void(F1 func) {
-  // WEBASSEMBLY:  %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)
-  use(__builtin_wasm_test_function_pointer_signature(func));
-  // WEBASSEMBLY:  %1 = tail call i32 (ptr, ...) @llvm.wasm.ref.test.func(ptr 
%func, i32 0, float 0.000000e+00, double 0.000000e+00, i32 0)
-  use(__builtin_wasm_test_function_pointer_signature((F2)func));
-  // WEBASSEMBLY:  %2 = tail call i32 (ptr, ...) @llvm.wasm.ref.test.func(ptr 
%func, i32 0, i32 0, i32 0, i32 0)
-  use(__builtin_wasm_test_function_pointer_signature((F3)func));
-  // WEBASSEMBLY:  %3 = tail call i32 (ptr, ...) @llvm.wasm.ref.test.func(ptr 
%func, token poison, i32 0, i32 0, i32 0)
-  use(__builtin_wasm_test_function_pointer_signature((F4)func));
-  // WEBASSEMBLY:  %4 = tail call i32 (ptr, ...) @llvm.wasm.ref.test.func(ptr 
%func, token poison)
-  use(__builtin_wasm_test_function_pointer_signature((F5)func));
-}
diff --git a/clang/test/Sema/builtins-wasm.c b/clang/test/Sema/builtins-wasm.c
index a3486b1aedb13..31e5291d3ae5e 100644
--- a/clang/test/Sema/builtins-wasm.c
+++ b/clang/test/Sema/builtins-wasm.c
@@ -54,27 +54,3 @@ void test_table_copy(int dst_idx, int src_idx, int nelem) {
   __builtin_wasm_table_copy(table, table, dst_idx, src_idx, table);    // 
expected-error {{5th argument must be an integer}}
   __builtin_wasm_table_copy(table, table, dst_idx, src_idx, nelem);
 }
-
-typedef void (*F1)(void);
-typedef int (*F2)(int);
-typedef int (*F3)(__externref_t);
-typedef __externref_t (*F4)(int);
-
-void test_function_pointer_signature() {
-  // Test argument count validation
-  (void)__builtin_wasm_test_function_pointer_signature(); // expected-error 
{{too few arguments to function call, expected 1, have 0}}
-  (void)__builtin_wasm_test_function_pointer_signature((F1)0, (F2)0); // 
expected-error {{too many arguments to function call, expected 1, have 2}}
-
-  // // Test argument type validation - should require function pointer
-  (void)__builtin_wasm_test_function_pointer_signature((void*)0); // 
expected-error {{used type 'void *' where function pointer is required}}
-  (void)__builtin_wasm_test_function_pointer_signature((int)0);   // 
expected-error {{used type 'int' where function pointer is required}}
-  (void)__builtin_wasm_test_function_pointer_signature((F3)0);   // 
expected-error {{not supported for function pointers with a reference type 
parameter}}
-  (void)__builtin_wasm_test_function_pointer_signature((F4)0);   // 
expected-error {{not supported for function pointers with a reference type 
return value}}
-
-  // // Test valid usage
-  int res = __builtin_wasm_test_function_pointer_signature((F1)0);
-  res = __builtin_wasm_test_function_pointer_signature((F2)0);
-
-  // Test return type
-  
_Static_assert(EXPR_HAS_TYPE(__builtin_wasm_test_function_pointer_signature((F1)0),
 int), "");
-}

_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to