|
12 | 12 |
|
13 | 13 | #include "CGBuiltin.h"
|
14 | 14 | #include "clang/Basic/TargetBuiltins.h"
|
| 15 | +#include "llvm/ADT/APInt.h" |
| 16 | +#include "llvm/IR/Constants.h" |
15 | 17 | #include "llvm/IR/IntrinsicsWebAssembly.h"
|
| 18 | +#include "llvm/Support/ErrorHandling.h" |
16 | 19 |
|
17 | 20 | using namespace clang;
|
18 | 21 | using namespace CodeGen;
|
@@ -218,6 +221,64 @@ Value *CodeGenFunction::EmitWebAssemblyBuiltinExpr(unsigned BuiltinID,
|
218 | 221 | Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_ref_null_func);
|
219 | 222 | return Builder.CreateCall(Callee);
|
220 | 223 | }
|
| 224 | + case WebAssembly::BI__builtin_wasm_test_function_pointer_signature: { |
| 225 | + Value *FuncRef = EmitScalarExpr(E->getArg(0)); |
| 226 | + |
| 227 | + // Get the function type from the argument's static type |
| 228 | + QualType ArgType = E->getArg(0)->getType(); |
| 229 | + const PointerType *PtrTy = ArgType->getAs<PointerType>(); |
| 230 | + assert(PtrTy && "Sema should have ensured this is a function pointer"); |
| 231 | + |
| 232 | + const FunctionType *FuncTy = PtrTy->getPointeeType()->getAs<FunctionType>(); |
| 233 | + assert(FuncTy && "Sema should have ensured this is a function pointer"); |
| 234 | + |
| 235 | + // In the llvm IR, we won't have access any more to the type of the function |
| 236 | + // pointer so we need to insert this type information somehow. The |
| 237 | + // @llvm.wasm.ref.test.func takes varargs arguments whose values are unused |
| 238 | + // to indicate the type of the function to test for. See the test here: |
| 239 | + // llvm/test/CodeGen/WebAssembly/ref-test-func.ll |
| 240 | + // |
| 241 | + // The format is: first we include the return types (since this is a C |
| 242 | + // function pointer, there will be 0 or one of these) then a token type to |
| 243 | + // indicate the boundary between return types and param types, then the |
| 244 | + // param types. |
| 245 | + |
| 246 | + llvm::FunctionType *LLVMFuncTy = |
| 247 | + cast<llvm::FunctionType>(ConvertType(QualType(FuncTy, 0))); |
| 248 | + |
| 249 | + unsigned NParams = LLVMFuncTy->getNumParams(); |
| 250 | + std::vector<Value *> Args; |
| 251 | + Args.reserve(NParams + 3); |
| 252 | + // The only real argument is the FuncRef |
| 253 | + Args.push_back(FuncRef); |
| 254 | + |
| 255 | + // Add the type information |
| 256 | + auto addType = [this, &Args](llvm::Type *T) { |
| 257 | + if (T->isVoidTy()) { |
| 258 | + // Do nothing |
| 259 | + } else if (T->isFloatingPointTy()) { |
| 260 | + Args.push_back(ConstantFP::get(T, 0)); |
| 261 | + } else if (T->isIntegerTy()) { |
| 262 | + Args.push_back(ConstantInt::get(T, 0)); |
| 263 | + } else if (T->isPointerTy()) { |
| 264 | + Args.push_back(ConstantPointerNull::get(llvm::PointerType::get( |
| 265 | + getLLVMContext(), T->getPointerAddressSpace()))); |
| 266 | + } else { |
| 267 | + // TODO: Handle reference types. For now, we reject them in Sema. |
| 268 | + llvm_unreachable("Unhandled type"); |
| 269 | + } |
| 270 | + }; |
| 271 | + |
| 272 | + addType(LLVMFuncTy->getReturnType()); |
| 273 | + // The token type indicates the boundary between return types and param |
| 274 | + // types. |
| 275 | + Args.push_back(PoisonValue::get(llvm::Type::getTokenTy(getLLVMContext()))); |
| 276 | + for (unsigned i = 0; i < NParams; i++) { |
| 277 | + addType(LLVMFuncTy->getParamType(i)); |
| 278 | + } |
| 279 | + Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_ref_test_func); |
| 280 | + return Builder.CreateCall(Callee, Args); |
| 281 | + } |
221 | 282 | case WebAssembly::BI__builtin_wasm_swizzle_i8x16: {
|
222 | 283 | Value *Src = EmitScalarExpr(E->getArg(0));
|
223 | 284 | Value *Indices = EmitScalarExpr(E->getArg(1));
|
|
0 commit comments