void breakCriticalEdges(Code& code) { BlockInsertionSet insertionSet(code); for (BasicBlock* block : code) { if (block->numSuccessors() <= 1) continue; for (BasicBlock*& successor : block->successorBlocks()) { if (successor->numPredecessors() <= 1) continue; BasicBlock* pad = insertionSet.insertBefore(successor, successor->frequency()); pad->append(Jump, successor->at(0).origin); pad->setSuccessors(successor); pad->addPredecessor(block); successor->replacePredecessor(block, pad); successor = pad; } } insertionSet.execute(); }
void mergeBlocks( BlockIndex firstBlockIndex, BlockIndex secondBlockIndex, BlockIndex jettisonedBlockIndex) { // This will add all of the nodes in secondBlock to firstBlock, but in so doing // it will also ensure that any GetLocals from the second block that refer to // SetLocals in the first block are relinked. If jettisonedBlock is not NoBlock, // then Phantoms are inserted for anything that the jettisonedBlock would have // kept alive. BasicBlock* firstBlock = m_graph.m_blocks[firstBlockIndex].get(); BasicBlock* secondBlock = m_graph.m_blocks[secondBlockIndex].get(); // Remove the terminal of firstBlock since we don't need it anymore. Well, we don't // really remove it; we actually turn it into a Phantom. ASSERT(firstBlock->last()->isTerminal()); CodeOrigin boundaryCodeOrigin = firstBlock->last()->codeOrigin; firstBlock->last()->convertToPhantom(); ASSERT(firstBlock->last()->refCount() == 1); if (jettisonedBlockIndex != NoBlock) { BasicBlock* jettisonedBlock = m_graph.m_blocks[jettisonedBlockIndex].get(); // Time to insert ghosties for things that need to be kept alive in case we OSR // exit prior to hitting the firstBlock's terminal, and end up going down a // different path than secondBlock. for (size_t i = 0; i < jettisonedBlock->variablesAtHead.numberOfArguments(); ++i) keepOperandAlive(firstBlock, jettisonedBlock, boundaryCodeOrigin, argumentToOperand(i)); for (size_t i = 0; i < jettisonedBlock->variablesAtHead.numberOfLocals(); ++i) keepOperandAlive(firstBlock, jettisonedBlock, boundaryCodeOrigin, i); } for (size_t i = 0; i < secondBlock->phis.size(); ++i) firstBlock->phis.append(secondBlock->phis[i]); for (size_t i = 0; i < secondBlock->size(); ++i) firstBlock->append(secondBlock->at(i)); ASSERT(firstBlock->last()->isTerminal()); // Fix the predecessors of my new successors. This is tricky, since we are going to reset // all predecessors anyway due to reachability analysis. But we need to fix the // predecessors eagerly to ensure that we know what they are in case the next block we // consider in this phase wishes to query the predecessors of one of the blocks we // affected. for (unsigned i = m_graph.numSuccessors(firstBlock); i--;) { BasicBlock* successor = m_graph.m_blocks[m_graph.successor(firstBlock, i)].get(); for (unsigned j = 0; j < successor->m_predecessors.size(); ++j) { if (successor->m_predecessors[j] == secondBlockIndex) successor->m_predecessors[j] = firstBlockIndex; } } // Fix the predecessors of my former successors. Again, we'd rather not do this, but it's // an unfortunate necessity. See above comment. if (jettisonedBlockIndex != NoBlock) fixJettisonedPredecessors(firstBlockIndex, jettisonedBlockIndex); firstBlock->valuesAtTail = secondBlock->valuesAtTail; firstBlock->cfaBranchDirection = secondBlock->cfaBranchDirection; m_graph.m_blocks[secondBlockIndex].clear(); }