RegSet PhysLoc::regs() const { RegSet regs; if (hasReg(0)) { regs.add(reg(0)); if (hasReg(1)) regs.add(reg(1)); } return regs; }
Vpoint emitCall(Vout& v, CppCall call, RegSet args) { PhysReg arg0(argReg(0)); PhysReg rHostCall(rHostCallReg); switch (call.kind()) { case CppCall::Kind::Direct: v << ldimm{reinterpret_cast<intptr_t>(call.address()), rHostCall}; break; case CppCall::Kind::Virtual: v << loadq{arg0[0], rHostCall}; v << loadq{rHostCall[call.vtableOffset()], rHostCall}; break; case CppCall::Kind::IndirectReg: case CppCall::Kind::IndirectVreg: // call indirect currently not implemented. It'll be something like // a.Br(x2a(call.getReg())) not_implemented(); always_assert(0); break; case CppCall::Kind::ArrayVirt: case CppCall::Kind::Destructor: not_implemented(); always_assert(0); break; } uint8_t argc = args.size(); args.add(rHostCall); auto fixupAddr = v.makePoint(); v << hostcall{args, argc, fixupAddr}; return fixupAddr; }
/* * Check that each destination register or spill slot is unique, * and that sources have the same number or less operands than * destinations. */ bool checkShuffle(const IRInstruction& inst, const RegAllocInfo& regs) { auto n = inst.numSrcs(); assert(n == inst.extra<Shuffle>()->size); RegSet destRegs; std::bitset<NumPreAllocatedSpillLocs> destSlots; auto& inst_regs = regs[inst]; for (uint32_t i = 0; i < n; ++i) { DEBUG_ONLY auto& rs = inst_regs.src(i); DEBUG_ONLY auto& rd = inst.extra<Shuffle>()->dests[i]; if (rd.numAllocated() == 0) continue; // dest was unused; ignore. if (rd.spilled()) { assert(!rs.spilled()); // no mem-mem copies } else { // rs could have less assigned registers/slots than rd, in these cases: // - when rs is empty, because the source is a constant. // - when rs has 1 register because it's untagged but rd needs 2 because // it's a more general (tagged) type, because of a phi. assert(rs.numWords() <= rd.numWords()); assert(rs.spilled() || rs.isFullSIMD() == rd.isFullSIMD()); } for (int j = 0; j < rd.numAllocated(); ++j) { if (rd.spilled()) { assert(!destSlots.test(rd.slot(j))); destSlots.set(rd.slot(j)); } else { assert(!destRegs.contains(rd.reg(j))); // no duplicate dests destRegs.add(rd.reg(j)); } } } return true; }
void getEffects(const Abi& abi, const Vinstr& i, RegSet& uses, RegSet& across, RegSet& defs) { uses = defs = across = RegSet(); switch (i.op) { case Vinstr::mccall: case Vinstr::call: case Vinstr::callm: case Vinstr::callr: defs = abi.all() - abi.calleeSaved; switch (arch()) { case Arch::ARM: defs.add(PhysReg(arm::rLinkReg)); defs.remove(PhysReg(arm::rVmFp)); break; case Arch::X64: defs.remove(reg::rbp); break; } break; case Vinstr::bindcall: defs = abi.all(); switch (arch()) { case Arch::ARM: break; case Arch::X64: defs.remove(x64::rVmTl); break; } break; case Vinstr::contenter: case Vinstr::callstub: defs = abi.all(); switch (arch()) { case Arch::ARM: defs.remove(PhysReg(arm::rVmFp)); break; case Arch::X64: defs -= reg::rbp | x64::rVmTl; break; } break; case Vinstr::cqo: uses = RegSet(reg::rax); defs = reg::rax | reg::rdx; break; case Vinstr::idiv: uses = defs = reg::rax | reg::rdx; break; case Vinstr::shlq: case Vinstr::sarq: across = RegSet(reg::rcx); break; // arm instrs case Vinstr::hostcall: defs = (abi.all() - abi.calleeSaved) | RegSet(PhysReg(arm::rHostCallReg)); break; case Vinstr::vcall: case Vinstr::vinvoke: case Vinstr::vcallstub: always_assert(false && "Unsupported instruction in vxls"); default: break; } }
void CodeGenerator::cgCallHelper(Vout& v, CppCall call, const CallDest& dstInfo, SyncOptions sync, ArgGroup& args) { auto dstReg0 = dstInfo.reg0; DEBUG_ONLY auto dstReg1 = dstInfo.reg1; RegSet argRegs; for (size_t i = 0; i < args.numGpArgs(); i++) { auto const r = rarg(i); args.gpArg(i).setDstReg(r); argRegs.add(r); } always_assert_flog( args.numStackArgs() == 0, "Stack arguments not yet supported on ARM: `{}'", *m_curInst ); shuffleArgs(v, args, call); auto syncPoint = emitCall(v, call, argRegs); if (RuntimeOption::HHProfServerEnabled || sync != SyncOptions::kNoSyncPoint) { recordHostCallSyncPoint(v, syncPoint); } auto* taken = m_curInst->taken(); if (taken && taken->isCatch()) { assert_not_implemented(args.numStackArgs() == 0); auto next = v.makeBlock(); v << hcunwind{syncPoint, {next, m_state.labels[taken]}}; v = next; } else if (!m_curInst->is(Call, CallArray, ContEnter)) { v << hcnocatch{syncPoint}; } switch (dstInfo.type) { case DestType::TV: CG_PUNT(cgCall-ReturnTV); case DestType::SIMD: CG_PUNT(cgCall-ReturnSIMD); case DestType::SSA: case DestType::Byte: assertx(dstReg1 == InvalidReg); v << copy{PhysReg(vixl::x0), dstReg0}; break; case DestType::None: assertx(dstReg0 == InvalidReg && dstReg1 == InvalidReg); break; case DestType::Dbl: assertx(dstReg1 == InvalidReg); v << copy{PhysReg(vixl::d0), dstReg0}; break; } }
void getEffects(const Abi& abi, const Vinstr& i, RegSet& uses, RegSet& across, RegSet& defs) { uses = defs = across = RegSet(); switch (i.op) { case Vinstr::mccall: case Vinstr::call: case Vinstr::callm: case Vinstr::callr: defs = abi.all() - (abi.calleeSaved | rvmfp()); switch (arch()) { case Arch::ARM: defs.add(PhysReg(arm::rLinkReg)); break; case Arch::X64: break; case Arch::PPC64: not_implemented(); break; } break; case Vinstr::bindcall: defs = abi.all(); switch (arch()) { case Arch::ARM: break; case Arch::X64: defs.remove(rvmtl()); break; case Arch::PPC64: not_implemented(); break; } break; case Vinstr::contenter: case Vinstr::callarray: defs = abi.all() - RegSet(rvmfp()); switch (arch()) { case Arch::ARM: break; case Arch::X64: defs.remove(rvmtl()); break; case Arch::PPC64: not_implemented(); break; } break; case Vinstr::callfaststub: defs = abi.all() - abi.calleeSaved - abi.gpUnreserved; break; case Vinstr::cqo: uses = RegSet(reg::rax); defs = reg::rax | reg::rdx; break; case Vinstr::idiv: uses = defs = reg::rax | reg::rdx; break; case Vinstr::shlq: case Vinstr::sarq: across = RegSet(reg::rcx); break; // arm instrs case Vinstr::hostcall: defs = (abi.all() - abi.calleeSaved) | RegSet(PhysReg(arm::rHostCallReg)); break; case Vinstr::vcall: case Vinstr::vinvoke: case Vinstr::vcallarray: always_assert(false && "Unsupported instruction in vxls"); default: break; } }