/* * 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; }
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; }
/* * 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; }
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; }