예제 #1
0
void TraceBuilder::endInlining() {
  auto calleeAR = m_fpValue;
  gen(InlineReturn, calleeAR);

  useState(std::move(m_inlineSavedStates.back()));
  m_inlineSavedStates.pop_back();

  // See the comment in beginInlining about generator frames.
  if (m_curFunc->getValFunc()->isGenerator()) {
    gen(ReDefGeneratorSP, StackOffset(m_spOffset), m_spValue);
  } else {
    gen(ReDefSP, StackOffset(m_spOffset), m_fpValue, m_spValue);
  }
}
예제 #2
0
SSATmp* IRBuilder::preOptimizeCheckStk(IRInstruction* inst) {
  auto const newType = inst->typeParam();
  auto sp = inst->src(0);
  auto offset = inst->extra<CheckStk>()->offset;

  auto stkVal = getStackValue(sp, offset);
  auto const oldType = stkVal.knownType;

  if (oldType.isBoxed() && newType.isBoxed() &&
      (oldType.not(newType) || newType < oldType)) {
    /* This CheckStk serves to update the inner type hint for a boxed
     * value, which requires no runtime work. This depends on the type being
     * boxed, and constraining it with DataTypeCountness will do it.  */
    constrainStack(sp, offset, DataTypeCountness);
    return gen(AssertStk, newType, StackOffset(offset), sp);
  }

  if (newType.not(oldType)) {
    /* This check will always fail. It's probably due to an incorrect
     * prediction. Generate a Jmp, and return the source because
     * following instructions may depend on the output of CheckStk
     * (they'll be DCEd later).  Note that we can't use convertToJmp
     * because the return value isn't nullptr, so the original
     * instruction won't be inserted into the stream. */
    gen(Jmp, inst->taken());
    return sp;
  }

  if (newType >= oldType) {
    // The new type isn't better than the old type.
    return sp;
  }

  return nullptr;
}
예제 #3
0
void IRBuilder::startBlock(Block* block) {
  assert(block);
  assert(m_savedBlocks.empty());  // No bytecode control flow in exits.

  if (block->empty()) {
    if (block != m_curBlock) {
      if (m_state.compatible(block)) {
        m_state.pauseBlock(block);
      } else {
        m_state.clearCse();
      }
      assert(m_curBlock);
      auto& prev = m_curBlock->back();
      if (!prev.hasEdges()) {
        gen(Jmp, block);
      } else if (!prev.isTerminal()) {
        prev.setNext(block);
      }
      m_curBlock = block;
      m_state.startBlock(m_curBlock);
      FTRACE(2, "IRBuilder switching to block B{}: {}\n", block->id(),
             show(m_state));
    }
  }

  if (sp() == nullptr) {
    gen(DefSP, StackOffset(spOffset() + evalStack().size() - stackDeficit()),
        fp());
  }

}
예제 #4
0
파일: opt.cpp 프로젝트: Halfnhav/hiphop-php
/*
 * Insert asserts at various points in the IR.
 * TODO: t2137231 Insert DbgAssertPtr at points that use or produces a GenPtr
 */
static void insertAsserts(IRTrace* trace, IRFactory& factory) {
  forEachTraceBlock(trace, [&](Block* block) {
    for (auto it = block->begin(), end = block->end(); it != end; ) {
      IRInstruction& inst = *it;
      ++it;
      if (inst.op() == SpillStack) {
        insertSpillStackAsserts(inst, factory);
        continue;
      }
      if (inst.op() == Call) {
        SSATmp* sp = inst.dst();
        IRInstruction* addr = factory.gen(LdStackAddr,
                                          inst.marker(),
                                          Type::PtrToGen,
                                          StackOffset(0),
                                          sp);
        insertAfter(&inst, addr);
        insertAfter(addr, factory.gen(DbgAssertPtr, inst.marker(),
                                      addr->dst()));
        continue;
      }
      if (!inst.isBlockEnd()) insertRefCountAsserts(inst, factory);
    }
  });
}
예제 #5
0
파일: jump-opts.cpp 프로젝트: csvan/hhvm
TEST(JumpOpts, optimizeSideExitCheck) {
  BCMarker marker = BCMarker::Dummy();
  IRUnit unit{0};

  Block* entry = unit.entry();
  Block* taken = unit.defBlock();
  Block* fallthru = unit.defBlock();

  // A conditional jump that goes to a "SyncABIRegs; ReqBindJmp" on the taken
  // edge only can turn into a SideExitJmpSomething.

  auto fp = unit.gen(DefFP, marker);
  auto sp = unit.gen(DefSP, marker, StackOffset(0), fp->dst());
  auto chk = unit.gen(CheckStk, marker, Type::Int, taken,
                      StackOffset(0), sp->dst());
  chk->setNext(fallthru);
  entry->push_back({fp, sp, chk});

  fallthru->push_back(unit.gen(Halt, marker));

  auto bcoff = 10;
  auto sync = unit.gen(SyncABIRegs, marker, fp->dst(), sp->dst());
  auto bind = unit.gen(ReqBindJmp, marker, BCOffset(bcoff));
  taken->push_back({sync, bind});

  optimizeJumps(unit);

  // This exercises trivial jump optimization too: since the JmpZero gets turned
  // into a non-branch, the entry block gets coalesced with the Halt block.
  EXPECT_EQ(nullptr, entry->next());
  EXPECT_EQ(nullptr, entry->taken());
  EXPECT_EQ(Halt, entry->back().op());
  auto const& sideExit = *(--entry->backIter());
  EXPECT_EQ(SideExitGuardStk, sideExit.op());
  EXPECT_EQ(bcoff, sideExit.extra<SideExitGuardData>()->taken);
}
예제 #6
0
void TraceBuilder::useState(std::unique_ptr<State> state) {
  m_spValue = state->spValue;
  m_fpValue = state->fpValue;
  m_spOffset = state->spOffset;
  m_curFunc = state->curFunc;
  m_thisIsAvailable = state->thisAvailable;
  m_refCountedMemValue = state->refCountedMemValue;
  m_localValues = std::move(state->localValues);
  m_localTypes = std::move(state->localTypes);
  m_callerAvailableValues = std::move(state->callerAvailableValues);
  // If spValue is null, we merged two different but equivalent values.
  // Define a new sp using the known-good spOffset.
  if (!m_spValue) {
    gen(DefSP, StackOffset(m_spOffset), m_fpValue);
  }
}
예제 #7
0
/*
 * Insert a DbgAssertTv instruction for each stack location stored to by
 * a SpillStack instruction.
 */
static void insertSpillStackAsserts(IRInstruction& inst, IRFactory* factory) {
  SSATmp* sp = inst.dst();
  auto const vals = inst.srcs().subpiece(2);
  auto* block = inst.block();
  auto pos = block->iteratorTo(&inst); ++pos;
  for (unsigned i = 0, n = vals.size(); i < n; ++i) {
    Type t = vals[i]->type();
    if (t.subtypeOf(Type::Gen)) {
      IRInstruction* addr = factory->gen(LdStackAddr,
                                         Type::PtrToGen,
                                         StackOffset(i),
                                         sp);
      block->insert(pos, addr);
      IRInstruction* check = factory->gen(DbgAssertPtr, addr->dst());
      block->insert(pos, check);
    }
  }
}
예제 #8
0
파일: jump-opts.cpp 프로젝트: csvan/hhvm
TEST(JumpOpts, optimizeCondTraceExit) {
  BCMarker marker = BCMarker::Dummy();

  IRUnit unit{0};

  Block* entry = unit.entry();
  Block* taken = unit.defBlock();
  Block* fallthru = unit.defBlock();

  // A conditional jump that goes to "SyncABIRegs; ReqBindJmp" on both edges
  // can be coalesced into a ReqBindJmpSomething.

  auto fp = unit.gen(DefFP, marker);
  auto sp = unit.gen(DefSP, marker, StackOffset(0), fp->dst());
  auto val = unit.gen(Conjure, marker, Type::Bool);
  auto jmp = unit.gen(JmpZero, marker, taken, val->dst());
  jmp->setNext(fallthru);
  entry->push_back({fp, sp, val, jmp});

  auto bcoff1 = 10;
  auto sync1 = unit.gen(SyncABIRegs, marker, fp->dst(), sp->dst());
  auto bind1 = unit.gen(ReqBindJmp, marker, BCOffset(bcoff1));
  taken->push_back({sync1, bind1});

  auto bcoff2 = 20;
  auto sync2 = unit.gen(SyncABIRegs, marker, fp->dst(), sp->dst());
  auto bind2 = unit.gen(ReqBindJmp, marker, BCOffset(bcoff2));
  fallthru->push_back({sync2, bind2});

  optimizeJumps(unit);

  EXPECT_EQ(nullptr, entry->next());
  EXPECT_EQ(nullptr, entry->taken());
  auto const& back = entry->back();
  EXPECT_EQ(ReqBindJmpZero, back.op());
  EXPECT_EQ(val->dst(), back.src(0));
  auto const* data = back.extra<ReqBindJccData>();
  EXPECT_EQ(bcoff1, data->taken);
  EXPECT_EQ(bcoff2, data->notTaken);
}
예제 #9
0
void TraceBuilder::beginInlining(const Func* target,
                                 SSATmp* calleeFP,
                                 SSATmp* calleeSP,
                                 SSATmp* savedSP,
                                 int32_t savedSPOff) {
  // Saved tracebuilder state will include the "return" fp/sp.
  // Whatever the current fpValue is is good enough, but we have to be
  // passed in the StkPtr that represents the stack prior to the
  // ActRec being allocated.
  m_spOffset = savedSPOff;
  m_spValue = savedSP;

  m_inlineSavedStates.push_back(createState());

  /*
   * Set up the callee state.
   *
   * We set m_thisIsAvailable to true on any object method, because we
   * just don't inline calls to object methods with a null $this.
   */
  m_fpValue         = calleeFP;
  m_spValue         = calleeSP;
  m_thisIsAvailable = target->cls() != nullptr;
  m_curFunc         = cns(target);

  /*
   * Keep the outer locals somewhere for isValueAvailable() to know
   * about their liveness, to help with incref/decref elimination.
   */
  m_callerAvailableValues.insert(m_callerAvailableValues.end(),
                                 m_localValues.begin(),
                                 m_localValues.end());

  m_localValues.clear();
  m_localTypes.clear();
  m_localValues.resize(target->numLocals(), nullptr);
  m_localTypes.resize(target->numLocals(), Type::None);

  gen(ReDefSP, StackOffset(target->numParams()), m_fpValue, m_spValue);
}
예제 #10
0
파일: opt.cpp 프로젝트: Alienfeel/hhvm
/*
 * Insert asserts at various points in the IR.
 * TODO: t2137231 Insert DbgAssertPtr at points that use or produces a GenPtr
 */
static void insertAsserts(IRUnit& unit) {
  postorderWalk(unit, [&](Block* block) {
      for (auto it = block->begin(), end = block->end(); it != end; ) {
        IRInstruction& inst = *it;
        ++it;
        if (inst.op() == SpillStack) {
          insertSpillStackAsserts(inst, unit);
          continue;
        }
        if (inst.op() == Call) {
          SSATmp* sp = inst.dst();
          IRInstruction* addr = unit.gen(LdStackAddr,
                                         inst.marker(),
                                         Type::PtrToGen,
                                         StackOffset(0),
                                         sp);
          insertAfter(&inst, addr);
          insertAfter(addr, unit.gen(DbgAssertPtr, inst.marker(), addr->dst()));
          continue;
        }
        if (!inst.isBlockEnd()) insertRefCountAsserts(inst, unit);
      }
    });
}