Beispiel #1
0
TCA genFuncBodyDispatch(Func* func, const DVFuncletsVec& dvs,
                        CodeCache::View code) {
  auto context = prologue_context(kInvalidTransID, TransKind::Live,
                                  func, func->base());
  IRUnit unit{context};
  irgen::IRGS env{unit};

  irgen::emitFuncBodyDispatch(env, dvs);
  irgen::sealUnit(env);

  CGMeta fixups;
  auto vunit = irlower::lowerUnit(env.unit, CodeKind::CrossTrace);

  auto& main = code.main();
  auto const start = main.frontier();

  emitVunit(*vunit, env.unit, code, fixups);

  if (RuntimeOption::EvalPerfRelocate) {
    GrowableVector<IncomingBranch> ibs;
    auto& frozen = code.frozen();
    tc::recordPerfRelocMap(start, main.frontier(),
                           frozen.frontier(), frozen.frontier(),
                           context.srcKey(), 0, ibs, fixups);
  }
  fixups.process(nullptr);

  return start;
}
Beispiel #2
0
static TransIDSet findPredTrans(TransID dstID, const ProfData* profData) {
  auto const dstRec = profData->transRec(dstID);
  auto const dstSK = dstRec->srcKey();
  const SrcRec* dstSR = tc::findSrcRec(dstSK);
  assertx(dstSR);
  TransIDSet predSet;

  for (auto& inBr : dstSR->incomingBranches()) {
    auto const srcID = profData->jmpTransID(inBr.toSmash());
    if (srcID == kInvalidTransID) continue;

    auto const srcRec = profData->transRec(srcID);
    if (!srcRec || !srcRec->isProfile()) continue;

    FTRACE(5, "findPredTrans: toSmash = {}   srcID = {}\n",
           inBr.toSmash(), srcID);
    auto srcSuccOffsets = srcRec->lastSrcKey().succOffsets();
    if (srcSuccOffsets.count(dstSK.offset())) {
      predSet.insert(srcID);
    } else {
      FTRACE(5, "findPredTrans: WARNING: incoming branch with impossible "
             "control flow between translations: {} -> {}"
             "(probably due to side exit)\n", srcID, dstID);
    }
  }

  return predSet;
}
Beispiel #3
0
RegionDescPtr selectHotTrace(HotTransContext& ctx,
                             TransIDSet& selectedSet,
                             TransIDVec* selectedVec /* = nullptr */) {
  auto region = std::make_shared<RegionDesc>();
  TransID tid    = ctx.tid;
  TransID prevId = kInvalidTransID;
  selectedSet.clear();
  if (selectedVec) selectedVec->clear();

  TypedLocations accumPostConds;

  // Maps from BlockIds to accumulated post conditions for that block.
  // Used to determine if we can add branch-over edges by checking the
  // pre-conditions of the successor block.
  hphp_hash_map<RegionDesc::BlockId, TypedLocations> blockPostConds;

  auto numBCInstrs = ctx.maxBCInstrs;
  FTRACE(1, "selectHotTrace: starting with maxBCInstrs = {}\n", numBCInstrs);

  while (!selectedSet.count(tid)) {
    auto rec = ctx.profData->transRec(tid);
    auto blockRegion = rec->region();
    if (blockRegion == nullptr) break;

    // Break if region would be larger than the specified limit.
    if (blockRegion->instrSize() > numBCInstrs) {
      FTRACE(2, "selectHotTrace: breaking region at Translation {} because "
             "size would exceed of maximum translation limit\n", tid);
      break;
    }

    // If the debugger is attached, only allow single-block regions.
    if (prevId != kInvalidTransID && isDebuggerAttachedProcess()) {
      FTRACE(2, "selectHotTrace: breaking region at Translation {} "
             "because of debugger is attached\n", tid);
      break;
    }

    // Break if block is not the first and it corresponds to the main
    // function body entry.  This is to prevent creating multiple
    // large regions containing the function body (starting at various
    // DV funclets).
    if (prevId != kInvalidTransID) {
      auto const func = rec->func();
      auto const bcOffset = rec->startBcOff();
      if (func->base() == bcOffset) {
        FTRACE(2, "selectHotTrace: breaking region because reached the main "
               "function body entry at Translation {} (BC offset {})\n",
               tid, bcOffset);
        break;
      }
    }

    if (prevId != kInvalidTransID) {
      auto sk = rec->srcKey();
      if (ctx.profData->optimized(sk)) {
        FTRACE(2, "selectHotTrace: breaking region because next sk already "
               "optimized, for Translation {}\n", tid);
        break;
      }
    }

    bool hasPredBlock = !region->empty();
    RegionDesc::BlockId predBlockId = (hasPredBlock ?
                                       region->blocks().back().get()->id() : 0);
    auto const& newFirstBlock = blockRegion->entry();
    auto newFirstBlockId = newFirstBlock->id();

    // Add blockRegion's blocks and arcs to region.
    region->append(*blockRegion);
    numBCInstrs -= blockRegion->instrSize();
    assertx(numBCInstrs >= 0);

    if (hasPredBlock) {
      region->addArc(predBlockId, newFirstBlockId);
    }
    selectedSet.insert(tid);
    if (selectedVec) selectedVec->push_back(tid);

    const auto lastSk = rec->lastSrcKey();
    if (breaksRegion(lastSk)) {
      FTRACE(2, "selectHotTrace: breaking region because of last instruction "
             "in Translation {}: {}\n", tid, opcodeToName(lastSk.op()));
      break;
    }

    auto outArcs = ctx.cfg->outArcs(tid);
    if (outArcs.size() == 0) {
      FTRACE(2, "selectHotTrace: breaking region because there's no successor "
             "for Translation {}\n", tid);
      break;
    }

    auto newLastBlock = blockRegion->blocks().back();
    discardPoppedTypes(accumPostConds,
                       blockRegion->entry()->initialSpOffset());
    mergePostConds(accumPostConds, newLastBlock->postConds());
    blockPostConds[newLastBlock->id()] = accumPostConds;

    TransCFG::ArcPtrVec possibleOutArcs;
    for (auto arc : outArcs) {
      auto dstRec = ctx.profData->transRec(arc->dst());
      auto possibleNext = dstRec->region()->entry();
      if (preCondsAreSatisfied(possibleNext, accumPostConds)) {
        possibleOutArcs.emplace_back(arc);
      }
    }

    if (possibleOutArcs.size() == 0) {
      FTRACE(2, "selectHotTrace: breaking region because postcondition check "
             "pruned all successors of Translation {}\n", tid);
      break;
    }

    auto maxWeight = std::numeric_limits<int64_t>::min();
    TransCFG::Arc* maxArc = nullptr;
    for (auto arc : possibleOutArcs) {
      if (arc->weight() >= maxWeight) {
        maxWeight = arc->weight();
        maxArc = arc;
      }
    }
    assertx(maxArc != nullptr);
    prevId = tid;
    tid = maxArc->dst();
  }

  FTRACE(3, "selectHotTrace: before chainRetransBlocks:\n{}\n", show(*region));
  region->chainRetransBlocks();
  FTRACE(3, "selectHotTrace: after chainRetransBlocks:\n{}\n", show(*region));

  return region;
}
Beispiel #4
0
TransCFG::TransCFG(FuncId funcId,
                   const ProfData* profData,
                   bool inlining /* = false */) {
  assertx(profData);

  // add nodes
  for (auto const tid : profData->funcProfTransIDs(funcId)) {
    auto const rec = profData->transRec(tid);
    assertx(rec->region() != nullptr);
    // This will skip DV Funclets if they were already
    // retranslated w/ the prologues:
    if (inlining || !profData->optimized(rec->srcKey())) {
      int64_t weight = profData->transCounter(tid);
      addNode(tid, weight);
    }
  }

  // add arcs
  for (auto const dstId : nodes()) {
    auto const rec = profData->transRec(dstId);
    auto const dstSK = rec->srcKey();
    auto const dstBlock = rec->region()->entry();
    FTRACE(5, "TransCFG: adding incoming arcs in dstId = {}\n", dstId);
    TransIDSet predIDs = findPredTrans(dstId, profData);
    for (auto predId : predIDs) {
      if (hasNode(predId)) {
        auto const predRec = profData->transRec(predId);
        auto const predBlock = predRec->region()->blocks().back();
        auto const& postConds = predBlock->postConds();
        auto predPostConds = postConds.changed;
        predPostConds.insert(predPostConds.end(), postConds.refined.begin(),
                             postConds.refined.end());
        auto const predSK = predRec->srcKey();
        if (preCondsAreSatisfied(dstBlock, predPostConds) &&
            predSK.resumed() == dstSK.resumed()) {
          FTRACE(5, "TransCFG: adding arc {} -> {} ({} -> {})\n",
                 predId, dstId, showShort(predSK), showShort(dstSK));
          addArc(predId, dstId, TransCFG::Arc::kUnknownWeight);
        }
      }
    }
  }

  // infer arc weights
  bool changed;
  do {
    changed = false;
    for (auto const tid : nodes()) {
      auto const nodeWeight = weight(tid);
      if (inferredArcWeight(inArcs(tid),  nodeWeight)) changed = true;
      if (inferredArcWeight(outArcs(tid), nodeWeight)) changed = true;
    }
  } while (changed);

  // guess weight for non-inferred arcs
  for (auto const tid : nodes()) {
    for (auto arc : outArcs(tid)) {
      if (arc->weight() == Arc::kUnknownWeight) {
        arc->setGuessed();
        auto arcWgt = std::min(weight(arc->src()), weight(arc->dst())) / 2;
        arc->setWeight(arcWgt);
      }
    }
  }
}