void TraceBuilder::appendInstruction(IRInstruction* inst) { if (m_curWhere) { // We have a specific position to insert instructions. assert(!inst->isBlockEnd()); auto& it = m_curWhere.get(); it = m_curBlock->insert(it, inst); ++it; return; } Block* block = m_curTrace->back(); if (!block->empty()) { IRInstruction* prev = &block->back(); if (prev->isBlockEnd()) { // start a new block Block* next = m_unit.defBlock(); FTRACE(2, "lazily adding B{}\n", next->id()); m_curTrace->push_back(next); if (!prev->isTerminal()) { // new block is reachable from old block so link it. block->setNext(next); next->setHint(block->hint()); } block = next; } } appendInstruction(inst, block); if (m_savedTraces.empty()) { // We don't track state on non-main traces for now. t2982555 m_state.update(inst); } }
void TraceBuilder::appendInstruction(IRInstruction* inst) { if (m_curWhere) { // We have a specific position to insert instructions. assert(!inst->isBlockEnd()); auto& it = m_curWhere.get(); it = m_curBlock->insert(it, inst); ++it; return; } Block* block = m_curTrace->back(); if (!block->empty()) { IRInstruction* prev = block->back(); if (prev->isBlockEnd()) { // start a new block Block* next = m_irFactory.defBlock(m_curFunc->getValFunc()); m_curTrace->push_back(next); if (!prev->isTerminal()) { // new block is reachable from old block so link it. block->setNext(next); } block = next; } } appendInstruction(inst, block); updateTrackedState(inst); }
void TraceBuilder::appendInstruction(IRInstruction* inst) { Block* block = m_trace->back(); IRInstruction* prev = block->back(); if (prev->isBlockEnd()) { // start a new block Block* next = m_irFactory.defBlock(m_curFunc->getValFunc()); m_trace->push_back(next); if (!prev->isTerminal()) { // new block is reachable from old block so link it. block->setNext(next); } block = next; } appendInstruction(inst, block); updateTrackedState(inst); }
void LinearScan::allocRegsToTrace() { // First, visit every instruction, allocating registers as we go, // and inserting Reload instructions where necessary. for (Block* block : m_blocks) { // clear remembered reloads that don't dominate this block for (SlotInfo& slot : m_slots) { if (SSATmp* reload = slot.m_latestReload) { if (!dominates(reload->getInstruction()->getBlock(), block, m_idoms)) { slot.m_latestReload = nullptr; } } } for (auto it = block->begin(), end = block->end(); it != end; ++it) { allocRegToInstruction(it); if (RuntimeOption::EvalDumpIR > 3) { std::cout << "--- allocated to instruction: "; it->print(std::cout); std::cout << "\n"; } } } // Now that we have visited all instructions and inserted Reloads // for SSATmps which needed to be spilled, we can go back and insert // the spills. All uses must have been visited before we do this. // For each spill slot, insert the spill right after the instruction // that generated the value (without traversing everything else). for (SlotInfo& slot : m_slots) { IRInstruction* spill = slot.m_spillTmp->getInstruction(); IRInstruction* inst = spill->getSrc(0)->getInstruction(); Block* block = inst->getBlock(); if (inst->isBlockEnd()) { block->getNext()->prepend(spill); } else { auto pos = block->iteratorTo(inst); block->insert(++pos, spill); } } }
void LinearScan::allocRegsOneTrace(BlockList::iterator& blockIt, ExitTraceMap& etm) { auto const trace = (*blockIt)->trace(); collectInfo(blockIt, trace); computePreColoringHint(); auto v = etm.find(*blockIt); if (v != etm.end()) { assert(!trace->isMain()); v->second.restore(this); } else { assert(blockIt == m_blocks.begin() && trace->isMain()); initFreeList(); } // First, visit every instruction, allocating registers as we go, // and inserting Reload instructions where necessary. bool isMain = trace->isMain(); size_t sz = m_slots.size(); while (blockIt != m_blocks.end()) { Block* block = *blockIt; if (block->trace() != trace) { if (!isMain) { break; } else { ++blockIt; continue; } } FTRACE(5, "Block{}: {} ({})\n", trace->isMain() ? "" : " (exit trace)", (*blockIt)->id(), (*blockIt)->postId()); // clear remembered reloads that don't dominate this block for (SlotInfo& slot : m_slots) { if (SSATmp* reload = slot.latestReload) { if (!dominates(reload->inst()->block(), block, m_idoms)) { slot.latestReload = nullptr; } } } for (auto it = block->begin(), end = block->end(); it != end; ++it) { allocRegToInstruction(it); dumpIR<IRInstruction, kExtraLevel>(&*it, "allocated to instruction "); } if (isMain) { assert(block->trace()->isMain()); if (block->taken() && !block->taken()->trace()->isMain()) { etm[block->taken()].save(this); } } ++blockIt; } // Now that we have visited all instructions on this trace, // and inserted Reloads for SSATmps which needed to be spilled, // we can go back and insert the spills. // On the main trace, insert the spill right after the instruction // that generated the value (without traversing everything else). // On exit traces, if the instruction that generated the value // is on the main trace, insert the spill at the start of the trace, // otherwise, after the instruction that generated the value size_t begin = sz; size_t end = m_slots.size(); while (begin < end) { SlotInfo& slot = m_slots[begin++]; IRInstruction* spill = slot.spillTmp->inst(); IRInstruction* inst = spill->src(0)->inst(); Block* block = inst->block(); if (!isMain && block->trace()->isMain()) { // We're on an exit trace, but the def is on the // main trace, so put it at the start of this trace if (spill->block()) { // its already been inserted in another exit trace assert(!spill->block()->trace()->isMain()); spill = m_unit.cloneInstruction(spill); } trace->front()->prepend(spill); } else if (inst->isBlockEnd()) { block->next()->prepend(spill); } else { auto pos = block->iteratorTo(inst); block->insert(++pos, spill); } } }