Ejemplo n.º 1
0
void optimize(IRUnit& unit, IRBuilder& irBuilder, TransKind kind) {
  Timer timer(Timer::optimize);

  assertx(checkEverything(unit));

  auto const hasLoop = RuntimeOption::EvalJitLoops && cfgHasLoop(unit);
  auto const func = unit.entry()->front().marker().func();
  auto const regionMode = pgoRegionMode(*func);
  auto const traceMode = kind != TransKind::Optimize ||
                         regionMode == PGORegionMode::Hottrace;

  // TODO (#5792564): Guard relaxation doesn't work with loops.
  // TODO (#6599498): Guard relaxation is broken in wholecfg mode.
  if (shouldHHIRRelaxGuards() && !hasLoop && traceMode) {
    Timer _t(Timer::optimize_relaxGuards);
    const bool simple = kind == TransKind::Profile &&
                        (RuntimeOption::EvalJitRegionSelector == "tracelet" ||
                         RuntimeOption::EvalJitRegionSelector == "method");
    RelaxGuardsFlags flags = (RelaxGuardsFlags)
      (RelaxReflow | (simple ? RelaxSimple : RelaxNormal));
    auto changed = relaxGuards(unit, *irBuilder.guards(), flags);
    if (changed) {
      printUnit(6, unit, "after guard relaxation");
      mandatoryDCE(unit);  // relaxGuards can leave unreachable preds.
    }

    if (RuntimeOption::EvalHHIRSimplification) {
      doPass(unit, simplifyPass, DCE::Minimal);
      doPass(unit, cleanCfg, DCE::None);
    }
  }

  fullDCE(unit);
  printUnit(6, unit, " after initial DCE ");
  assertx(checkEverything(unit));

  if (RuntimeOption::EvalHHIRTypeCheckHoisting) {
    doPass(unit, hoistTypeChecks, DCE::None);
  }

  if (RuntimeOption::EvalHHIRPredictionOpts) {
    doPass(unit, optimizePredictions, DCE::None);
  }

  if (RuntimeOption::EvalHHIRSimplification) {
    doPass(unit, simplifyPass, DCE::Full);
    doPass(unit, cleanCfg, DCE::None);
  }

  if (RuntimeOption::EvalHHIRGlobalValueNumbering) {
    doPass(unit, gvn, DCE::Full);
  }

  if (kind != TransKind::Profile && RuntimeOption::EvalHHIRMemoryOpts) {
    doPass(unit, optimizeLoads, DCE::Full);
  }

  if (kind != TransKind::Profile && RuntimeOption::EvalHHIRMemoryOpts) {
    doPass(unit, optimizeStores, DCE::Full);
  }

  if (kind != TransKind::Profile && RuntimeOption::EvalHHIRRefcountOpts) {
    doPass(unit, optimizeRefcounts2, DCE::Full);
  }

  if (RuntimeOption::EvalHHIRLICM) {
    if (kind != TransKind::Profile && hasLoop) {
      // The clean pass is just to stress lack of pre_headers for now, since
      // LICM is a disabled prototype pass.
      doPass(unit, cleanCfg, DCE::None);
      doPass(unit, optimizeLoopInvariantCode, DCE::Minimal);
    }
  }
  doPass(unit, removeExitPlaceholders, DCE::Full);

  if (RuntimeOption::EvalHHIRGenerateAsserts) {
    doPass(unit, insertAsserts, DCE::None);
  }
}
Ejemplo n.º 2
0
Archivo: opt.cpp Proyecto: BillHu/hhvm
void optimize(IRUnit& unit, IRBuilder& irBuilder, TransKind kind) {
  Timer _t(Timer::optimize);

  auto const finishPass = [&] (const char* msg) {
    if (msg) {
      printUnit(6, unit, folly::format("after {}", msg).str().c_str());
    }
    assertx(checkCfg(unit));
    assertx(checkTmpsSpanningCalls(unit));
    if (debug) {
      forEachInst(rpoSortCfg(unit), [&](IRInstruction* inst) {
        assertx(checkOperandTypes(inst, &unit));
      });
    }
  };

  auto const doPass = [&] (void (*fn)(IRUnit&), const char* msg = nullptr) {
    fn(unit);
    finishPass(msg);
  };

  auto const dce = [&] (const char* which) {
    if (!RuntimeOption::EvalHHIRDeadCodeElim) return;
    eliminateDeadCode(unit);
    finishPass(folly::format("{} DCE", which).str().c_str());
  };

  auto const simplifyPass = [] (IRUnit& unit) {
    boost::dynamic_bitset<> reachable(unit.numBlocks());
    reachable.set(unit.entry()->id());

    auto const blocks = rpoSortCfg(unit);

    for (auto block : blocks) {
      // Skip unreachable blocks, or simplify() cries.
      if (!reachable.test(block->id())) continue;

      for (auto& inst : *block) simplify(unit, &inst);

      if (auto const b = block->back().next())  reachable.set(b->id());
      if (auto const b = block->back().taken()) reachable.set(b->id());
    }
  };

  auto const doSimplify = RuntimeOption::EvalHHIRExtraOptPass &&
                          RuntimeOption::EvalHHIRSimplification;
  auto const hasLoop = RuntimeOption::EvalJitLoops && cfgHasLoop(unit);

  auto const traceMode = kind != TransKind::Optimize ||
                         RuntimeOption::EvalJitPGORegionSelector == "hottrace";

  // TODO (#5792564): Guard relaxation doesn't work with loops.
  // TODO (#6599498): Guard relaxation is broken in wholecfg mode.
  if (shouldHHIRRelaxGuards() && !hasLoop && traceMode) {
    Timer _t(Timer::optimize_relaxGuards);
    const bool simple = kind == TransKind::Profile &&
                        (RuntimeOption::EvalJitRegionSelector == "tracelet" ||
                         RuntimeOption::EvalJitRegionSelector == "method");
    RelaxGuardsFlags flags = (RelaxGuardsFlags)
      (RelaxReflow | (simple ? RelaxSimple : RelaxNormal));
    auto changed = relaxGuards(unit, *irBuilder.guards(), flags);
    if (changed) finishPass("guard relaxation");

    if (doSimplify) {
      doPass(simplifyPass, "guard relaxation simplify");
    }
  }

  // This is vestigial (it removes some instructions needed by the old refcount
  // opts pass), and will be removed soon.
  eliminateTakes(unit);

  dce("initial");

  if (RuntimeOption::EvalHHIRPredictionOpts) {
    doPass(optimizePredictions, "prediction opts");
  }

  if (doSimplify) {
    doPass(simplifyPass, "simplify");
    dce("simplify");
  }

  if (RuntimeOption::EvalHHIRGlobalValueNumbering) {
    doPass(gvn);
    dce("gvn");
  }

  if (kind != TransKind::Profile && RuntimeOption::EvalHHIRMemoryOpts) {
    doPass(optimizeLoads);
    dce("loadelim");
  }

  /*
   * Note: doing this pass this late might not be ideal, in particular because
   * we've already turned some StLoc instructions into StLocNT.
   *
   * But right now there are assumptions preventing us from doing it before
   * refcount opts.  (Refcount opts needs to see all the StLocs explicitly
   * because it makes assumptions about whether references are consumed based
   * on that.)
   */
  if (kind != TransKind::Profile && RuntimeOption::EvalHHIRMemoryOpts) {
    doPass(optimizeStores);
    dce("storeelim");
  }

  if (kind != TransKind::Profile && RuntimeOption::EvalHHIRRefcountOpts) {
    doPass(optimizeRefcounts2);
    dce("refcount");
  }

  if (RuntimeOption::EvalHHIRGenerateAsserts) {
    doPass(insertAsserts);
  }
}
Ejemplo n.º 3
0
Archivo: opt.cpp Proyecto: bjori/hhvm
void optimize(IRUnit& unit, IRBuilder& irBuilder, TransKind kind) {
  Timer _t(Timer::optimize);

  auto finishPass = [&](const char* msg) {
    if (msg) {
      printUnit(6, unit, folly::format("after {}", msg).str().c_str());
    }
    assert(checkCfg(unit));
    assert(checkTmpsSpanningCalls(unit));
    if (debug) {
      forEachInst(rpoSortCfg(unit), [&](IRInstruction* inst) {
        assert(checkOperandTypes(inst, &unit));
      });
    }
  };

  auto doPass = [&](void (*fn)(IRUnit&), const char* msg = nullptr) {
    fn(unit);
    finishPass(msg);
  };

  auto dce = [&](const char* which) {
    if (!RuntimeOption::EvalHHIRDeadCodeElim) return;
    eliminateDeadCode(unit);
    finishPass(folly::format("{} DCE", which).str().c_str());
  };

  auto const doReoptimize = RuntimeOption::EvalHHIRExtraOptPass &&
    (RuntimeOption::EvalHHIRCse || RuntimeOption::EvalHHIRSimplification);

  auto const hasLoop = RuntimeOption::EvalJitLoops && cfgHasLoop(unit);

  // TODO(#5792564): Guard relaxation doesn't work with loops.
  if (shouldHHIRRelaxGuards() && !hasLoop) {
    Timer _t(Timer::optimize_relaxGuards);
    const bool simple = kind == TransKind::Profile &&
                        (RuntimeOption::EvalJitRegionSelector == "tracelet" ||
                         RuntimeOption::EvalJitRegionSelector == "method");
    RelaxGuardsFlags flags = (RelaxGuardsFlags)
      (RelaxReflow | (simple ? RelaxSimple : RelaxNormal));
    auto changed = relaxGuards(unit, *irBuilder.guards(), flags);
    if (changed) finishPass("guard relaxation");

    if (doReoptimize) {
      irBuilder.reoptimize();
      finishPass("guard relaxation reoptimize");
    }
  }

  if (RuntimeOption::EvalHHIRRefcountOpts) {
    optimizeRefcounts(unit, FrameStateMgr{unit.entry()->front().marker()});
    finishPass("refcount opts");
  }

  dce("initial");

  if (RuntimeOption::EvalHHIRPredictionOpts) {
    doPass(optimizePredictions, "prediction opts");
  }

  if (doReoptimize) {
    irBuilder.reoptimize();
    finishPass("reoptimize");
    dce("reoptimize");
  }

  if (RuntimeOption::EvalHHIRGlobalValueNumbering) {
    doPass(gvn);
    dce("gvn");
  }

  if (kind != TransKind::Profile && RuntimeOption::EvalHHIRMemoryOpts) {
    doPass(optimizeLoads);
    dce("loadelim");
  }

  /*
   * Note: doing this pass this late might not be ideal, in particular because
   * we've already turned some StLoc instructions into StLocNT.
   *
   * But right now there are assumptions preventing us from doing it before
   * refcount opts.  (Refcount opts needs to see all the StLocs explicitly
   * because it makes assumptions about whether references are consumed based
   * on that.)
   */
  if (kind != TransKind::Profile && RuntimeOption::EvalHHIRMemoryOpts) {
    doPass(optimizeStores);
    dce("storeelim");
  }

  if (RuntimeOption::EvalHHIRGenerateAsserts) {
    doPass(insertAsserts, "RefCnt asserts");
  }
}