// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void IndirectCallPromotion::MergeReturnedValues(BlockList& callBlocks, Block* continuationBlock, CallInstr* instr) { // If the call returns 'void' or the result is not used // there are no values to merge. if(instr->IsVoid() || (instr->HasDestinationOp() == false)) { return; } auto unit = callBlocks[0]->ParentFunction()->ParentUnit(); auto& references = unit->References(); // Create the 'phi' that merges the returned values. auto phiResultOp = Temporary::GetTemporary(instr->ResultOp()->GetType()); auto phiInstr = PhiInstr::GetPhi(phiResultOp, callBlocks.Count()); continuationBlock->InsertInstructionFirst(phiInstr); // Now add the incoming operands. for(int i = 0; i < callBlocks.Count(); i++) { auto beforeGoto = callBlocks[i]->LastInstruction()->PreviousInstruction(); auto callInstr = beforeGoto->As<CallInstr>(); DebugValidator::IsNotNull(callInstr); DebugValidator::IsNotNull(callInstr->ResultOp()); auto blockRef = references.GetBlockRef(callBlocks[i]); phiInstr->AddOperand(callInstr->ResultOp(), blockRef); } // The original returned value is replaced by the 'phi' result. instr->ResultOp()->ReplaceWith(phiResultOp); }
bool isRPOSorted(const BlockList& blocks) { int id = 0; for (auto it = blocks.rbegin(); it != blocks.rend(); ++it) { if ((*it)->postId() != id++) return false; } return true; }
void LinearScan::allocRegsToTrace() { ExitTraceMap etm; numberInstructions(m_blocks); if (HPHP::Trace::moduleEnabled(HPHP::Trace::hhir, 5)) { std::stringstream s; s << "RPO: "; for (auto& b : m_blocks) { s << folly::format("{}{} ", b->isMain() ? "M" : "E", b->id()); } s << "\n"; HPHP::Trace::traceRelease("%s\n", s.str().c_str()); } BlockList::iterator it = m_blocks.begin(); while (it != m_blocks.end()) { allocRegsOneTrace(it, etm); } for (it = m_blocks.begin(); it != m_blocks.end();) { if ((*it)->isMain()) { ++it; continue; } allocRegsOneTrace(it, etm); } }
/* Acquire one blob from the pool. */ void* blob_pool::acquire() { BlockList* blist; if(! helper::get_blist(&blist, &_pool)) new (blist) BlockList(&_pool, BLOB_POOL_TEMPLATE_ARGS); void* ptr = blist->acquire(BLOB_POOL_TEMPLATE_ARGS); assert(_pool.validate_pointer(ptr)); return ptr; }
typename MemoryManager<AllocatorType>::BlockList::iterator MemoryManager<AllocatorType>::findBlock(BlockList& blockList, Byte* address, size_t index) { typename BlockList::iterator it{blockList.begin()}; const size_t blockSize{1UL << index}; // Loop while the address is not in the block pointed by it while((address < *it or address >= *it + blockSize) and it != blockList.end()) ++it; return it; }
// // Compute the generate and kill sets for each basic block in the given // function. The generate and kill functions are overriden by the subclass. // void DataFlowPass::initStates(const BlockList& blocks, BlockStates& states) { for (BlockList::const_iterator FI = blocks.begin(), FE = blocks.end(); FI != FE; ++FI) { const BasicBlock& block = *FI; BlockState state; initState(block, state); states.insert(BlockStatePair(&block, state)); } }
void Line::moveToNextPage(BlockList& floats, double minX, double maxX, const WTextRenderer& renderer) { for (unsigned i = 0; i < blocks_.size(); ++i) { Block *b = blocks_[i]; if (b->isFloat()) Utils::erase(floats, b); } PageState ps; ps.floats = floats; ps.page = page_; Block::clearFloats(ps); page_ = ps.page; floats = ps.floats; double oldY = y_; y_ = 0; x_ = minX; ++page_; BlockList blocks = blocks_; blocks_.clear(); Range rangeX(x_, maxX); Block::adjustAvailableWidth(y_, page_, floats, rangeX); x_ = rangeX.start; maxX = rangeX.end; for (unsigned i = 0; i < blocks.size(); ++i) { Block *b = blocks[i]; if (b->isFloat()) { b->layoutFloat(y_, page_, floats, x_, height_, minX, maxX, false, renderer); reflow(b); } else { for (unsigned j = 0; j < b->inlineLayout.size(); ++j) { InlineBox& ib = b->inlineLayout[j]; if (ib.y == oldY && ib.page == page_ - 1) { if (ib.x != LEFT_MARGIN_X) { ib.x = x_; x_ += ib.width; } ib.page = page_; ib.y = y_; } } } blocks_.push_back(b); } }
// This function attempts to find a pre-coloring hint from two // different sources: If tmp comes from a DefLabel, it will scan up to // the SSATmps providing values to incoming Jmp_s to look for a // hint. If tmp is consumed by a Jmp_, look for other incoming Jmp_s // to its destination and see if any of them have already been given a // register. If all of these fail, let normal register allocation // proceed unhinted. RegNumber LinearScan::getJmpPreColor(SSATmp* tmp, uint32_t regIndex, bool isReload) { IRInstruction* srcInst = tmp->inst(); const JmpList& jmps = m_jmps[tmp]; if (isReload && (srcInst->op() == DefLabel || !jmps.empty())) { // If we're precoloring a Reload of a temp that we'd normally find // a hint for, just return the register allocated to the spilled // temp. auto reg = m_allocInfo[tmp].reg(regIndex); assert(reg != reg::noreg); return reg; } if (srcInst->op() == DefLabel) { // Figure out which dst of the label is tmp for (unsigned i = 0, n = srcInst->numDsts(); i < n; ++i) { if (srcInst->dst(i) == tmp) { auto reg = findLabelSrcReg(m_allocInfo, srcInst, i, regIndex); // Until we handle loops, it's a bug to try and allocate a // register to a DefLabel's dest before all of its incoming // Jmp_s have had their srcs allocated, unless the incoming // block is unreachable. const DEBUG_ONLY bool unreachable = std::find(m_blocks.begin(), m_blocks.end(), srcInst->block()) == m_blocks.end(); always_assert(reg != reg::noreg || unreachable); return reg; } } not_reached(); } // If srcInst wasn't a label, check if tmp is used by any Jmp_ // instructions. If it is, trace to the Jmp_'s label and use the // same procedure as above. for (unsigned ji = 0, jn = jmps.size(); ji < jn; ++ji) { IRInstruction* jmp = jmps[ji]; IRInstruction* label = jmp->taken()->front(); // Figure out which src of the Jmp_ is tmp for (unsigned si = 0, sn = jmp->numSrcs(); si < sn; ++si) { SSATmp* src = jmp->src(si); if (tmp == src) { // For now, a DefLabel should never have a register assigned // to it before any of its incoming Jmp_ instructions. always_assert(m_allocInfo[label->dst(si)].reg(regIndex) == reg::noreg); auto reg = findLabelSrcReg(m_allocInfo, label, si, regIndex); if (reg != reg::noreg) return reg; } } } return reg::noreg; }
void write_bc_file(const BlockList &blockList, const std::string &file_name) { FILE *fp = fopen(file_name.c_str(), "wb"); if (!fp) { abort_("[write_bc_file] File %s cound not be opened for writing", file_name.c_str()); } cout << "Writing " << file_name << " ..." << endl; for (BlockList::const_iterator it=blockList.begin(); it!=blockList.end(); ++it) { fwrite(&it->front(), 1, it->size(), fp); } fclose(fp); }
// // Called after the pass is complete. // Show the results of the pass for each program point b/t blocks. // void DataFlowPass::display(const BlockList& blocks, BlockStates& states) { for (BlockList::const_iterator I = blocks.begin(), IE = blocks.end(); I != IE; ++I) { const BasicBlock* block = &(*I); BlockState& state = states[block]; if (I == blocks.begin()) { DataFlowUtil::print(state.in); cout << endl; } block->dump(); DataFlowUtil::print(state.out); cout << endl; } cout << endl; }
void LinearScan::collectInfo(BlockList::iterator it, IRTrace* trace) { m_natives.clear(); m_uses.reset(); // TODO(#2536764): serious time sink while (it != m_blocks.end()) { Block* block = *it++; bool offTrace = block->trace() != trace; if (offTrace) { if (!trace->isMain()) return; int lastId = block->trace()->data(); for (IRInstruction& inst : *block) { for (auto* src : inst.srcs()) { if (lastId > m_uses[src].lastUse) { m_uses[src].lastUse = lastId; } } } } else { for (IRInstruction& inst : *block) { for (auto* src : inst.srcs()) { m_uses[src].lastUse = m_linear[inst]; } if (inst.isNative()) m_natives.push_back(&inst); } IRInstruction* jmp = block->back(); if (jmp->op() == Jmp_ && jmp->numSrcs() != 0) { for (SSATmp* src : jmp->srcs()) { m_jmps[src].push_back(jmp); } } } } }
// // Generic helper functions for arbitrary sets of blocks // BlockStates DataFlowPass::runOnBlocks(const BlockList& blocks) { BlockStates states; // First pass: precompute generate and kill sets. initStates(blocks, states); // iterate for a forwards pass if (_direction == FORWARDS) { const BasicBlock* start = &(blocks.front()); traverseForwards(start, states); } // iterate for a backwards pass else if (_direction == BACKWARDS) { const BasicBlock* start = &(blocks.back()); traverseBackwards(start, states); } // return copy of states return states; }
/* * Find the immediate dominator of each block using Cooper, Harvey, and * Kennedy's "A Simple, Fast Dominance Algorithm", returned as a vector * of postorder ids, indexed by postorder id. */ IdomVector findDominators(const BlockList& blocks) { assert(isRPOSorted(blocks)); // Calculate immediate dominators with the iterative two-finger algorithm. // When it terminates, idom[post-id] will contain the post-id of the // immediate dominator of each block. idom[start] will be -1. This is // the general algorithm but it will only loop twice for loop-free graphs. auto const num_blocks = blocks.size(); IdomVector idom(num_blocks, -1); auto start = blocks.begin(); int start_id = (*start)->postId(); idom[start_id] = start_id; start++; for (bool changed = true; changed; ) { changed = false; // for each block after start, in reverse postorder for (auto it = start; it != blocks.end(); it++) { Block* block = *it; int b = block->postId(); // new_idom = any already-processed predecessor auto edge_it = block->preds().begin(); int new_idom = edge_it->from()->postId(); while (idom[new_idom] == -1) new_idom = (++edge_it)->from()->postId(); // for all other already-processed predecessors p of b for (auto& edge : block->preds()) { auto p = edge.from()->postId(); if (p != new_idom && idom[p] != -1) { // find earliest common predecessor of p and new_idom // (higher postIds are earlier in flow and in dom-tree). int b1 = p, b2 = new_idom; do { while (b1 < b2) b1 = idom[b1]; while (b2 < b1) b2 = idom[b2]; } while (b1 != b2); new_idom = b1; } } if (idom[b] != new_idom) { idom[b] = new_idom; changed = true; } } } idom[start_id] = -1; // start has no idom. return idom; }
DomChildren findDomChildren(const BlockList& blocks) { IdomVector idom = findDominators(blocks); DomChildren children(blocks.size(), BlockList()); for (Block* block : blocks) { int idom_id = idom[block->postId()]; if (idom_id != -1) children[idom_id].push_back(block); } return children; }
/*removes the temp blocks in the current scope, then delete the scope's TempBlockStack */ void BlockManager::leave_scope() { BlockList* temps = temp_block_list_stack_.back(); BlockList::iterator it; for (it = temps->begin(); it != temps->end(); ++it) { BlockId &block_id = *it; int array_id = block_id.array_id(); // Cached delete for distributed/served arrays. // Regular delete for temp blocks. if (sip_tables_.is_distributed(array_id) || sip_tables_.is_served(array_id)) cached_delete_block(*it); else delete_block(*it); // delete_block(*it); } temp_block_list_stack_.pop_back(); delete temps; }
void reflowTypes(Block* const changed, const BlockList& blocks) { assert(isRPOSorted(blocks)); auto it = rpoIteratorTo(blocks, changed); assert(it != blocks.end()); for (; it != blocks.end(); ++it) { FTRACE(5, "reflowTypes: visiting block {}\n", (*it)->id()); for (auto& inst : **it) visitInstruction(&inst); } }
bool UnreachableCodeElimination::enqueue(MBasicBlock *block, BlockList &list) { if (block->isMarked()) return true; block->mark(); marked_++; return list.append(block); }
/* * Find the immediate dominator of each block using Cooper, Harvey, and * Kennedy's "A Simple, Fast Dominance Algorithm", returned as a vector * of Block*, indexed by block. IdomVector[b] == nullptr if b has no * dominator. This is the case for the entry block and any blocks not * reachable from the entry block. */ IdomVector findDominators(const IRUnit& unit, const BlockList& blocks, const BlockIDs& rpoIDs) { // Calculate immediate dominators with the iterative two-finger algorithm. // When it terminates, idom[post-id] will contain the post-id of the // immediate dominator of each block. idom[start] will be -1. This is // the general algorithm but it will only loop twice for loop-free graphs. IdomVector idom(unit, nullptr); auto start = blocks.begin(); auto entry = *start; idom[entry] = entry; start++; for (bool changed = true; changed; ) { changed = false; // for each block after start, in reverse postorder for (auto it = start; it != blocks.end(); it++) { Block* block = *it; // p1 = any already-processed predecessor auto predIter = block->preds().begin(); auto predEnd = block->preds().end(); auto p1 = predIter->from(); while (!idom[p1]) p1 = (++predIter)->from(); // for all other already-processed predecessors p2 of block for (++predIter; predIter != predEnd; ++predIter) { auto p2 = predIter->from(); if (p2 == p1 || !idom[p2]) continue; // find earliest common predecessor of p1 and p2 // (lower RPO ids are earlier in flow and in dom-tree). do { while (rpoIDs[p1] < rpoIDs[p2]) p2 = idom[p2]; while (rpoIDs[p2] < rpoIDs[p1]) p1 = idom[p1]; } while (p1 != p2); } if (idom[block] != p1) { idom[block] = p1; changed = true; } } } idom[entry] = nullptr; // entry has no dominator. return idom; }
GlobalValueNumbering::GlobalValueNumbering(IR* ir) : _current_map(NULL) , _value_maps(ir->linear_scan_order()->length(), NULL) , _compilation(ir->compilation()) { TRACE_VALUE_NUMBERING(tty->print_cr("****** start of global value numbering")); ShortLoopOptimizer short_loop_optimizer(this); BlockList* blocks = ir->linear_scan_order(); int num_blocks = blocks->length(); BlockBegin* start_block = blocks->at(0); assert(start_block == ir->start() && start_block->number_of_preds() == 0 && start_block->dominator() == NULL, "must be start block"); assert(start_block->next()->as_Base() != NULL && start_block->next()->next() == NULL, "start block must not have instructions"); // method parameters are not linked in instructions list, so process them separateley for_each_state_value(start_block->state(), value, assert(value->as_Local() != NULL, "only method parameters allowed"); set_processed(value); );
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void IndirectCallPromotion::ConnectGeneratedBlocks(BlockList& testBlocks, BlockList& callBlocks) { // Connect the blocks based on the following pattern: // TEST_BLOCK0: // t0 = ucmp targetOp, FUNCT_REF0 // if t0, CALL_BLOCK0, TEST_BLOCK1 // CALL_BLOCK0: // call FUNCT_REF0 // goto CONTINUATION_BLOCK // TEST_BLOCK1: // t1 = ucmp targetOp, FUNCT_REF1 // if t1, CALL_BLOCK1, TEST_BLOCK2 // ... // CALL_BLOCK_N: // only if unpromoted targets // call targetOp // goto CONTINUATION_BLOCK // CONTINUATION_BLOCK: auto unit = callBlocks[0]->ParentFunction()->ParentUnit(); auto& references = unit->References(); for(int i = 0; i < testBlocks.Count(); i++) { auto testBlock = testBlocks[i]; auto ucmpResultOp = testBlocks[i]->LastInstruction()->GetDestinationOp(); auto trueBlockRef = references.GetBlockRef(callBlocks[i]); Block* falseBlock; if((i + 1) < testBlocks.Count()) { // There is a next target test. falseBlock = testBlocks[i + 1]; } else { // Unpromoted targets exist, always do the call. falseBlock = callBlocks[i + 1]; } auto falseBlockRef = references.GetBlockRef(falseBlock); auto ifInstr = IfInstr::GetIf(ucmpResultOp, trueBlockRef, falseBlockRef); testBlock->InsertInstruction(ifInstr); } }
void InvalidateWithChildren(Block *New) { // TODO: rename New BlockList ToInvalidate; // Being in the list means you need to be invalidated ToInvalidate.push_back(New); while (ToInvalidate.size() > 0) { Block *Invalidatee = ToInvalidate.front(); ToInvalidate.pop_front(); Block *Owner = Ownership[Invalidatee]; if (IndependentGroups.find(Owner) != IndependentGroups.end()) { // Owner may have been invalidated, do not add to IndependentGroups! IndependentGroups[Owner].erase(Invalidatee); } if (Ownership[Invalidatee]) { // may have been seen before and invalidated already Ownership[Invalidatee] = NULL; for (BlockBranchMap::iterator iter = Invalidatee->BranchesOut.begin(); iter != Invalidatee->BranchesOut.end(); iter++) { Block *Target = iter->first; BlockBlockMap::iterator Known = Ownership.find(Target); if (Known != Ownership.end()) { Block *TargetOwner = Known->second; if (TargetOwner) { ToInvalidate.push_back(Target); } } } } } }
bool ShortLoopOptimizer::process(BlockBegin* loop_header) { TRACE_VALUE_NUMBERING(tty->print_cr("** loop header block")); _too_complicated_loop = false; _loop_blocks.clear(); _loop_blocks.append(loop_header); for (int i = 0; i < _loop_blocks.length(); i++) { BlockBegin* block = _loop_blocks.at(i); TRACE_VALUE_NUMBERING(tty->print_cr("processing loop block B%d", block->block_id())); if (block->is_set(BlockBegin::exception_entry_flag)) { // this would be too complicated return false; } // add predecessors to worklist for (int j = block->number_of_preds() - 1; j >= 0; j--) { BlockBegin* pred = block->pred_at(j); if (pred->is_set(BlockBegin::osr_entry_flag)) { return false; } ValueMap* pred_map = value_map_of(pred); if (pred_map != NULL) { current_map()->kill_map(pred_map); } else if (!_loop_blocks.contains(pred)) { if (_loop_blocks.length() >= ValueMapMaxLoopSize) { return false; } _loop_blocks.append(pred); } } // use the instruction visitor for killing values for (Value instr = block->next(); instr != NULL; instr = instr->next()) { instr->visit(this); if (_too_complicated_loop) { return false; } } } bool optimistic = this->_gvn->compilation()->is_optimistic(); if (UseLoopInvariantCodeMotion && optimistic) { LoopInvariantCodeMotion code_motion(this, _gvn, loop_header, &_loop_blocks); } TRACE_VALUE_NUMBERING(tty->print_cr("** loop successfully optimized")); return true; }
void cloneToBlock(const BlockList& rpoBlocks, IRFactory& irFactory, Block::iterator const first, Block::iterator const last, Block* const target) { assert(isRPOSorted(rpoBlocks)); StateVector<SSATmp,SSATmp*> rewriteMap(irFactory, nullptr); auto rewriteSources = [&] (IRInstruction* inst) { for (int i = 0; i < inst->numSrcs(); ++i) { if (auto newTmp = rewriteMap[inst->src(i)]) { FTRACE(5, " rewrite: {} -> {}\n", inst->src(i)->toString(), newTmp->toString()); inst->setSrc(i, newTmp); } } }; auto targetIt = target->skipHeader(); for (auto it = first; it != last; ++it) { assert(!it->isControlFlow()); FTRACE(5, "cloneToBlock({}): {}\n", target->id(), it->toString()); auto const newInst = irFactory.cloneInstruction(&*it); if (auto const numDests = newInst->numDsts()) { for (int i = 0; i < numDests; ++i) { FTRACE(5, " add rewrite: {} -> {}\n", it->dst(i)->toString(), newInst->dst(i)->toString()); rewriteMap[it->dst(i)] = newInst->dst(i); } } target->insert(targetIt, newInst); targetIt = ++target->iteratorTo(newInst); } auto it = rpoIteratorTo(rpoBlocks, target); for (; it != rpoBlocks.end(); ++it) { FTRACE(5, "cloneToBlock: rewriting block {}\n", (*it)->id()); for (auto& inst : **it) { FTRACE(5, " rewriting {}\n", inst.toString()); rewriteSources(&inst); } } }
void process_bin_file(char *file_name) { int seq = 0; FILE *fp = fopen(file_name, "rb"); if (!fp) { abort_("[read_bin_file] File %s cound not be opened for reading", file_name); } fseek(fp, 0, SEEK_END); long file_size = ftell(fp); if (file_size % BLOCK_SIZE) { abort_("[read_bin_file] File %s bad size", file_name); } fseek(fp, 0, SEEK_SET); Block block; block.resize(BLOCK_SIZE); BlockList blockList; for (int i=0; i<file_size/BLOCK_SIZE; ++i) { if (BLOCK_SIZE != fread(&(block.front()), 1, BLOCK_SIZE, fp)) { abort_("[read_bin_file] Fild %s read error", file_name); } if (0 == memcmp(&block.front(), FCC_TEX1, 4)) { if (!blockList.empty()) { ostringstream bc_file_name; bc_file_name << file_name << "-" << seq << ".bc"; write_bc_file(blockList, bc_file_name.str()); seq ++; blockList.clear(); } blockList.push_back(block); } else { blockList.push_back(block); } } fclose(fp); cout << "Done" << endl; }
BlockList rpoSortCfg(const IRUnit& unit) { BlockList blocks; blocks.reserve(unit.numBlocks()); postorderWalk(unit, [&](Block* block) { blocks.push_back(block); }); std::reverse(blocks.begin(), blocks.end()); assert(blocks.size() <= unit.numBlocks()); return blocks; }
void FindLive(Block *Root) { BlockList ToInvestigate; ToInvestigate.push_back(Root); while (ToInvestigate.size() > 0) { Block *Curr = ToInvestigate.front(); ToInvestigate.pop_front(); if (Live.find(Curr) != Live.end()) continue; Live.insert(Curr); for (BlockBranchMap::iterator iter = Curr->BranchesOut.begin(); iter != Curr->BranchesOut.end(); iter++) { ToInvestigate.push_back(iter->first); } } }
void reflowTypes(Block* const changed, const BlockList& blocks) { assert(isRPOSorted(blocks)); auto retypeDst = [&] (IRInstruction* inst, int num) { auto ssa = inst->dst(num); /* * The type of a tmp defined by DefLabel is the union of the * types of the tmps at each incoming Jmp. */ if (inst->op() == DefLabel) { Type type = Type::Bottom; inst->block()->forEachSrc(num, [&](IRInstruction*, SSATmp* tmp) { type = Type::unionOf(type, tmp->type()); }); ssa->setType(type); return; } ssa->setType(outputType(inst, num)); }; auto visit = [&] (IRInstruction* inst) { for (int i = 0; i < inst->numDsts(); ++i) { auto const ssa = inst->dst(i); auto const oldType = ssa->type(); retypeDst(inst, i); if (!ssa->type().equals(oldType)) { FTRACE(5, "reflowTypes: retyped {} in {}\n", oldType.toString(), inst->toString()); } } }; auto it = rpoIteratorTo(blocks, changed); assert(it != blocks.end()); for (; it != blocks.end(); ++it) { FTRACE(5, "reflowTypes: visiting block {}\n", (*it)->id()); for (auto& inst : **it) visit(&inst); } }
BlockList rpoSortCfg(IRTrace* trace, const IRFactory& factory) { assert(trace->isMain()); BlockList blocks; blocks.reserve(factory.numBlocks()); unsigned next_id = 0; postorderWalk( [&](Block* block) { block->setPostId(next_id++); blocks.push_back(block); }, factory.numBlocks(), trace->front() ); std::reverse(blocks.begin(), blocks.end()); assert(blocks.size() <= factory.numBlocks()); assert(next_id <= factory.numBlocks()); return blocks; }
void LoopFinder::gather_loop_blocks(LoopList* loops) { int lng = loops->length(); BitMap blocks_in_loop(max_blocks()); for (int i = 0; i < lng; i++) { // for each loop do the following blocks_in_loop.clear(); Loop* loop = loops->at(i); BlockList* ends = loop->ends(); if (!loop->is_end(loop->start())) { GrowableArray<BlockBegin*>* stack = new GrowableArray<BlockBegin*>(); blocks_in_loop.at_put(loop->start()->block_id(), true); // insert all the ends into the list for (int i = 0; i < ends->length(); i++) { blocks_in_loop.at_put(ends->at(i)->block_id() , true); stack->push(ends->at(i)); } while (!stack->is_empty()) { BlockBegin* bb = stack->pop(); BlockLoopInfo* bli = get_block_info(bb); // push all predecessors that are not yet in loop int npreds = bli->nof_preds(); for (int m = 0; m < npreds; m++) { BlockBegin* pred = bli->pred_no(m); if (!blocks_in_loop.at(pred->block_id())) { blocks_in_loop.at_put(pred->block_id(), true); loop->append_node(pred); stack->push(pred); } } } loop->append_node(loop->start()); } // insert all the ends into the loop for (int i = 0; i < ends->length(); i++) { loop->append_node(ends->at(i)); } } }
void HBlock::subdivide(BlockList& bl) { bl.addBlock(this); }