|
18 | 18 | #include "WebAssemblySubtarget.h" |
19 | 19 | #include "WebAssemblyTargetMachine.h" |
20 | 20 | #include "WebAssemblyUtilities.h" |
| 21 | +#include "llvm/BinaryFormat/Wasm.h" |
21 | 22 | #include "llvm/CodeGen/CallingConvLower.h" |
22 | 23 | #include "llvm/CodeGen/MachineFrameInfo.h" |
23 | 24 | #include "llvm/CodeGen/MachineInstrBuilder.h" |
@@ -501,6 +502,51 @@ MVT WebAssemblyTargetLowering::getScalarShiftAmountTy(const DataLayout & /*DL*/, |
501 | 502 | return Result; |
502 | 503 | } |
503 | 504 |
|
| 505 | +static MachineBasicBlock *LowerRefTestFuncRef(MachineInstr &MI, DebugLoc DL, |
| 506 | + MachineBasicBlock *BB, |
| 507 | + const TargetInstrInfo &TII) { |
| 508 | + // Lower a REF_TEST_FUNCREF_PSEUDO instruction into a REF_TEST_FUNCREF |
| 509 | + // instruction by combining the signature info Imm operands that |
| 510 | + // SelectionDag/InstrEmitter.cpp makes into one CImm operand. Put this into |
| 511 | + // the type index placeholder for REF_TEST_FUNCREF |
| 512 | + Register ResultReg = MI.getOperand(0).getReg(); |
| 513 | + Register FuncRefReg = MI.getOperand(1).getReg(); |
| 514 | + |
| 515 | + auto NParams = MI.getNumOperands() - 3; |
| 516 | + auto Sig = APInt(NParams * 64, 0); |
| 517 | + |
| 518 | + { |
| 519 | + uint64_t V = MI.getOperand(2).getImm(); |
| 520 | + Sig |= int64_t(V); |
| 521 | + } |
| 522 | + |
| 523 | + for (unsigned I = 3; I < MI.getNumOperands(); I++) { |
| 524 | + const MachineOperand &MO = MI.getOperand(I); |
| 525 | + if (!MO.isImm()) { |
| 526 | + // I'm not really sure what these are or where they come from but it seems |
| 527 | + // to be okay to ignore them |
| 528 | + continue; |
| 529 | + } |
| 530 | + uint16_t V = MO.getImm(); |
| 531 | + Sig <<= 64; |
| 532 | + Sig |= int64_t(V); |
| 533 | + } |
| 534 | + |
| 535 | + ConstantInt *TypeInfo = |
| 536 | + ConstantInt::get(BB->getParent()->getFunction().getContext(), Sig); |
| 537 | + |
| 538 | + // Put the type info first in the placeholder for the type index, then the |
| 539 | + // actual funcref arg |
| 540 | + BuildMI(*BB, MI, DL, TII.get(WebAssembly::REF_TEST_FUNCREF), ResultReg) |
| 541 | + .addCImm(TypeInfo) |
| 542 | + .addReg(FuncRefReg); |
| 543 | + |
| 544 | + // Remove the original instruction |
| 545 | + MI.eraseFromParent(); |
| 546 | + |
| 547 | + return BB; |
| 548 | +} |
| 549 | + |
504 | 550 | // Lower an fp-to-int conversion operator from the LLVM opcode, which has an |
505 | 551 | // undefined result on invalid/overflow, to the WebAssembly opcode, which |
506 | 552 | // traps on invalid/overflow. |
@@ -862,6 +908,8 @@ MachineBasicBlock *WebAssemblyTargetLowering::EmitInstrWithCustomInserter( |
862 | 908 | switch (MI.getOpcode()) { |
863 | 909 | default: |
864 | 910 | llvm_unreachable("Unexpected instr type to insert"); |
| 911 | + case WebAssembly::REF_TEST_FUNCREF_PSEUDO: |
| 912 | + return LowerRefTestFuncRef(MI, DL, BB, TII); |
865 | 913 | case WebAssembly::FP_TO_SINT_I32_F32: |
866 | 914 | return LowerFPToInt(MI, DL, BB, TII, false, false, false, |
867 | 915 | WebAssembly::I32_TRUNC_S_F32); |
@@ -2253,6 +2301,72 @@ SDValue WebAssemblyTargetLowering::LowerIntrinsic(SDValue Op, |
2253 | 2301 | DAG.getTargetExternalSymbol(TlsBase, PtrVT)), |
2254 | 2302 | 0); |
2255 | 2303 | } |
| 2304 | + case Intrinsic::wasm_ref_test_func: { |
| 2305 | + // First emit the TABLE_GET instruction to convert function pointer ==> |
| 2306 | + // funcref |
| 2307 | + MachineFunction &MF = DAG.getMachineFunction(); |
| 2308 | + auto PtrVT = getPointerTy(MF.getDataLayout()); |
| 2309 | + MCSymbol *Table = |
| 2310 | + WebAssembly::getOrCreateFunctionTableSymbol(MF.getContext(), Subtarget); |
| 2311 | + SDValue TableSym = DAG.getMCSymbol(Table, PtrVT); |
| 2312 | + SDValue FuncRef = |
| 2313 | + SDValue(DAG.getMachineNode(WebAssembly::TABLE_GET_FUNCREF, DL, |
| 2314 | + MVT::funcref, TableSym, Op.getOperand(1)), |
| 2315 | + 0); |
| 2316 | + |
| 2317 | + SmallVector<SDValue, 4> Ops; |
| 2318 | + Ops.push_back(FuncRef); |
| 2319 | + |
| 2320 | + // We want to encode the type information into an APInt which we'll put |
| 2321 | + // in a CImm. However, in SelectionDag/InstrEmitter.cpp there is no code |
| 2322 | + // path that emits a CImm. So we need a custom inserter to put it in. |
| 2323 | + |
| 2324 | + // We'll put each type argument in a separate TargetConstant which gets |
| 2325 | + // lowered to a MachineInstruction Imm. We combine these into a CImm in our |
| 2326 | + // custom inserter because it creates a problem downstream to have all these |
| 2327 | + // extra immediates. |
| 2328 | + { |
| 2329 | + SDValue Operand = Op.getOperand(2); |
| 2330 | + MVT VT = Operand.getValueType().getSimpleVT(); |
| 2331 | + WebAssembly::BlockType V; |
| 2332 | + if (VT == MVT::Untyped) { |
| 2333 | + V = WebAssembly::BlockType::Void; |
| 2334 | + } else if (VT == MVT::i32) { |
| 2335 | + V = WebAssembly::BlockType::I32; |
| 2336 | + } else if (VT == MVT::i64) { |
| 2337 | + V = WebAssembly::BlockType::I64; |
| 2338 | + } else if (VT == MVT::f32) { |
| 2339 | + V = WebAssembly::BlockType::F32; |
| 2340 | + } else if (VT == MVT::f64) { |
| 2341 | + V = WebAssembly::BlockType::F64; |
| 2342 | + } else { |
| 2343 | + llvm_unreachable("Unhandled type!"); |
| 2344 | + } |
| 2345 | + Ops.push_back(DAG.getTargetConstant((int64_t)V, DL, MVT::i64)); |
| 2346 | + } |
| 2347 | + |
| 2348 | + for (unsigned i = 3; i < Op.getNumOperands(); ++i) { |
| 2349 | + SDValue Operand = Op.getOperand(i); |
| 2350 | + MVT VT = Operand.getValueType().getSimpleVT(); |
| 2351 | + wasm::ValType V; |
| 2352 | + if (VT == MVT::i32) { |
| 2353 | + V = wasm::ValType::I32; |
| 2354 | + } else if (VT == MVT::i64) { |
| 2355 | + V = wasm::ValType::I64; |
| 2356 | + } else if (VT == MVT::f32) { |
| 2357 | + V = wasm::ValType::F32; |
| 2358 | + } else if (VT == MVT::f64) { |
| 2359 | + V = wasm::ValType::F64; |
| 2360 | + } else { |
| 2361 | + llvm_unreachable("Unhandled type!"); |
| 2362 | + } |
| 2363 | + Ops.push_back(DAG.getTargetConstant((int64_t)V, DL, MVT::i64)); |
| 2364 | + } |
| 2365 | + |
| 2366 | + return SDValue(DAG.getMachineNode(WebAssembly::REF_TEST_FUNCREF_PSEUDO, DL, |
| 2367 | + MVT::i32, Ops), |
| 2368 | + 0); |
| 2369 | + } |
2256 | 2370 | } |
2257 | 2371 | } |
2258 | 2372 |
|
|
0 commit comments