Exemplo n.º 1
0
/*
 * For all guard instructions in trace, check to see if we can relax the
 * destination type to something less specific. The GuardConstraints map
 * contains information about what properties of the guarded type matter for
 * each instruction.
 */
bool relaxGuards(IRTrace* trace, const IRFactory& factory,
                 const GuardConstraints& guards) {
  FTRACE(1, "relaxing guards for trace {}\n", trace);
  auto blocks = rpoSortCfg(trace, factory);
  Block* reflowBlock = nullptr;

  for (auto* block : blocks) {
    for (auto& inst : *block) {
      if (!isGuardOp(inst.op())) continue;

      auto it = guards.find(inst.id());
      auto category = it == guards.end() ? DataTypeGeneric : it->second;

      auto const oldType = inst.typeParam();
      auto newType = relaxType(oldType, category);

      if (!oldType.equals(newType)) {
        FTRACE(1, "relaxGuards changing {}'s type to {}\n", inst, newType);
        inst.setTypeParam(newType);
        if (!reflowBlock) reflowBlock = block;
      }
    }
  }

  // TODO(t2598894): For now we require regenerating the IR after guard
  // relaxation, so it's only useful in the tracelet region selector.
  if (false && reflowBlock) reflowTypes(reflowBlock, blocks);

  return (bool)reflowBlock;
}
Exemplo n.º 2
0
bool splitCriticalEdges(IRUnit& unit) {
  FTRACE(2, "splitting critical edges\n");
  auto modified = removeUnreachable(unit);
  if (modified) reflowTypes(unit);
  auto const startBlocks = unit.numBlocks();

  // Try to split outgoing edges of each reachable block.  This is safe in
  // a postorder walk since we visit blocks after visiting successors.
  postorderWalk(unit, [&](Block* b) {
    splitCriticalEdge(unit, b->takenEdge());
    splitCriticalEdge(unit, b->nextEdge());
  });

  return modified || unit.numBlocks() != startBlocks;
}
Exemplo n.º 3
0
/*
 * For all guard instructions in trace, check to see if we can relax the
 * destination type to something less specific. The GuardConstraints map
 * contains information about what properties of the guarded type matter for
 * each instruction. Returns true iff any changes were made to the trace.
 */
bool relaxGuards(const IRUnit& unit, const GuardConstraints& guards) {
  FTRACE(1, "relaxing guards for trace {}\n", unit.main());
  auto blocks = rpoSortCfg(unit);
  Block* reflowBlock = nullptr;

  for (auto* block : blocks) {
    for (auto& inst : *block) {
      if (!isGuardOp(inst.op())) continue;

      auto it = guards.find(&inst);
      auto constraint = it == guards.end() ? TypeConstraint() : it->second;

      // TODO(t2598894): Support relaxing inner types
      auto const oldType = inst.typeParam();
      auto newType = relaxType(oldType, constraint.category);

      if (constraint.knownType <= newType) {
        // If the known type is at least as good as the relaxed type, we can
        // replace the guard with an assert.
        auto newOp = guardToAssert(inst.op());
        FTRACE(1, "relaxGuards changing {}'s type to {}, op to {}\n",
               inst, constraint.knownType, newOp);
        inst.setTypeParam(constraint.knownType);
        inst.setOpcode(newOp);
        inst.setTaken(nullptr);

        if (!reflowBlock) reflowBlock = block;
      } else if (!oldType.equals(newType)) {
        FTRACE(1, "relaxGuards changing {}'s type to {}\n", inst, newType);
        inst.setTypeParam(newType);

        if (!reflowBlock) reflowBlock = block;
      }
    }
  }

  if (reflowBlock) reflowTypes(reflowBlock, blocks);

  return (bool)reflowBlock;
}
Exemplo n.º 4
0
bool splitCriticalEdges(IRUnit& unit) {
  FTRACE(2, "splitting critical edges\n");
  auto modified = removeUnreachable(unit);
  if (modified) reflowTypes(unit);
  auto const startBlocks = unit.numBlocks();

  std::unordered_set<Block*> newCatches;
  std::unordered_set<Block*> oldCatches;

  // Try to split outgoing edges of each reachable block.  This is safe in
  // a postorder walk since we visit blocks after visiting successors.
  postorderWalk(unit, [&](Block* b) {
    auto bnew = splitCriticalEdge(unit, b->takenEdge());
    splitCriticalEdge(unit, b->nextEdge());

    assertx(!b->next() || !b->next()->isCatch());
    if (bnew && b->taken()->isCatch()) {
      newCatches.emplace(bnew);
      oldCatches.emplace(b->taken());
    }
  });

  for (auto b : newCatches) {
    auto bc = b->next()->begin();
    assertx(bc->is(BeginCatch));
    b->prepend(unit.gen(BeginCatch, bc->bcctx()));
  }

  for (auto b : oldCatches) {
    auto bc = b->begin();
    assertx(bc->is(BeginCatch));
    b->erase(bc);
  }

  return modified || unit.numBlocks() != startBlocks;
}