Exemplo n.º 1
0
RegSet PhysLoc::regs() const {
  RegSet regs;
  if (hasReg(0)) {
    regs.add(reg(0));
    if (hasReg(1)) regs.add(reg(1));
  }
  return regs;
}
Exemplo n.º 2
0
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;
}
Exemplo n.º 3
0
/*
 * 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;
}
Exemplo n.º 4
0
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;
  }
}
Exemplo n.º 5
0
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;
  }
}
Exemplo n.º 6
0
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;
  }
}