예제 #1
0
파일: code-gen-arm.cpp 프로젝트: EloB/hhvm
void CodeGenerator::cgInterpOneCommon(IRInstruction* inst) {
  auto fpReg = x2a(curOpd(inst->src(0)).reg());
  auto spReg = x2a(curOpd(inst->src(1)).reg());
  auto pcOff = inst->extra<InterpOneData>()->bcOff;

  auto opc = *(curFunc()->unit()->at(pcOff));
  auto* interpOneHelper = interpOneEntryPoints[opc];

  // This means push x30 (the link register) first, then x29. This mimics the
  // x64 stack frame: return address higher in memory than saved FP.
  m_as.   Push   (x30, x29);

  // TODO(2966997): this really should be saving caller-save registers and
  // basically doing everything else that cgCallHelper does. This only works
  // now because no caller-saved registers are live.
  m_as.   Mov    (rHostCallReg, reinterpret_cast<uint64_t>(interpOneHelper));
  m_as.   Mov    (argReg(0), fpReg);
  m_as.   Mov    (argReg(1), spReg);
  m_as.   Mov    (argReg(2), pcOff);

  // Note that sync points for HostCalls have to be recorded at the *start* of
  // the instruction.
  recordHostCallSyncPoint(m_as, m_as.frontier());
  m_as.   HostCall(3);

  m_as.   Pop    (x29, x30);
}
예제 #2
0
void CodeGenerator::cgInterpOneCommon(IRInstruction* inst) {
  auto fpReg = x2a(m_regs[inst->src(0)].reg());
  auto spReg = x2a(m_regs[inst->src(1)].reg());
  auto pcOff = inst->extra<InterpOneData>()->bcOff;

  auto opc = *(curFunc()->unit()->at(pcOff));
  auto* interpOneHelper = interpOneEntryPoints[opc];

  m_as.   Push   (x29, x30);

  // TODO(2966997): this really should be saving caller-save registers and
  // basically doing everything else that cgCallHelper does. This only works
  // now because no caller-saved registers are live.
  m_as.   Mov    (rHostCallReg, reinterpret_cast<uint64_t>(interpOneHelper));
  m_as.   Mov    (argReg(0), fpReg);
  m_as.   Mov    (argReg(1), spReg);
  m_as.   Mov    (argReg(2), pcOff);
  m_as.   HostCall(3);

  m_as.   Pop    (x30, x29);
}
예제 #3
0
// Lower svcreq{} by making copies to abi registers explicit, saving
// vm regs, and returning to the VM. svcreq{} is guaranteed to be
// at the end of a block, so we can just keep appending to the same block.
void lower_svcreq(Vunit& unit, Vlabel b, Vinstr& inst) {
  auto svcreq = inst.svcreq_; // copy it
  auto origin = inst.origin;
  auto& argv = unit.tuples[svcreq.extraArgs];
  unit.blocks[b].code.pop_back(); // delete the svcreq instruction
  Vout v(unit, b, origin);

  RegSet arg_regs;
  VregList arg_dests;
  for (int i = 0, n = argv.size(); i < n; ++i) {
    PhysReg d{serviceReqArgReg(i)};
    arg_dests.push_back(d);
    arg_regs |= d;
  }
  v << copyargs{svcreq.extraArgs, v.makeTuple(arg_dests)};
  // Save VM regs
  PhysReg vmfp{rVmFp}, vmsp{rVmSp}, sp{vixl::sp}, rdsp{rVmTl};
  v << store{vmfp, rdsp[rds::kVmfpOff]};
  v << store{vmsp, rdsp[rds::kVmspOff]};
  if (svcreq.stub_block) {
    always_assert(false && "use rip-rel addr to get ephemeral stub addr");
  } else {
    v << ldimmq{0, PhysReg{arm::rAsm}}; // because persist flag
  }
  v << ldimmq{svcreq.req, PhysReg{argReg(0)}};
  arg_regs |= arm::rAsm | argReg(0);

  // Weird hand-shaking with enterTC: reverse-call a service routine.
  // In the case of some special stubs (m_callToExit, m_retHelper), we
  // have already unbalanced the return stack by doing a ret to
  // something other than enterTCHelper.  In that case
  // SRJmpInsteadOfRet indicates to fake the return.
  v << load{sp[0], PhysReg{rLinkReg}};
  v << lea{sp[16], sp}; // fake postindexing
  arg_regs |= rLinkReg; // arm ret{} implicitly uses LR
  v << ret{arg_regs};
}