static LoopUnrollInfo* prepareUnrollInfo(MemoryManager& mm, LoopTree* lt, BranchInst* branchInst) { if (Log::isEnabled()) { Log::out()<<"==Checking loop exit:"; branchInst->print(Log::out()); Log::out()<<std::endl; } //traverse loop and track all modifications Node* node = branchInst->getNode(); LoopNode* loopHeader = lt->getLoopNode(node, false); Opnd* opnd1 = branchInst->getSrc(0); Opnd* opnd2 = branchInst->getNumSrcOperands()==1?NULL:branchInst->getSrc(1); if (opnd2==NULL) { assert(branchInst->getComparisonModifier() == Cmp_Zero || branchInst->getComparisonModifier() == Cmp_NonZero); assert(opnd1->getType()->isObject()); if (Log::isEnabled()) { Log::out()<<"----Unsupported comparison modifier."<<std::endl; } return NULL; } if (!opnd1->getType()->isInteger() || opnd1->getType()->isInt8() || !opnd2->getType()->isInteger() || opnd2->getType()->isInt8()) { if (Log::isEnabled()) { Log::out()<<"----Unsupported opnd types."<<std::endl; } return NULL; //IMPROVE: longs and floating types are not supported } InstStack defStack(mm); Log::out()<<"----Analyzing opnd1 id="<<opnd1->getId()<<std::endl; OpndLoopInfo opndInfo1 = processOpnd(loopHeader, lt, defStack, opnd1); assert(defStack.empty()); Log::out()<<"----Analyzing opnd2 id="<<opnd2->getId()<<std::endl; OpndLoopInfo opndInfo2 = processOpnd(loopHeader, lt, defStack, opnd2); assert(defStack.empty()); if(Log::isEnabled()) { Log::out()<<"----Result: opndId1="<<opnd1->getId()<<" type=";opndInfo1.print(Log::out()); Log::out()<<", opndId2="<<opnd2->getId()<<" type=";opndInfo2.print(Log::out());Log::out()<<std::endl; } //default values -> this item will not be unrolled unless all constraints are OK LoopUnrollInfo* info = new (mm) LoopUnrollInfo(); info->header = loopHeader->getHeader(); info->branchInst = branchInst; info->branchTargetIsExit = !loopHeader->inLoop(branchInst->getTargetLabel()->getNode()); info->doUnroll = false; if (opndInfo1.isCounter() && (opndInfo2.isDOL() || opndInfo2.isLDConst())) { info->doUnroll = true; info->branchLimitOpndPos=1; info->increment = opndInfo1.getIncrement(); } else if (opndInfo2.isCounter() && (opndInfo1.isDOL() || opndInfo1.isLDConst())) { info->doUnroll = true; info->branchLimitOpndPos=0; info->increment = opndInfo2.getIncrement(); } return info; }
void LoopUnrollPass::_run(IRManager& irm) { const UnrollFlags& flags = ((LoopUnrollAction*)getAction())->getFlags(); OptPass::computeDominatorsAndLoops(irm); ControlFlowGraph& cfg = irm.getFlowGraph(); LoopTree* lt = cfg.getLoopTree(); if (!lt->hasLoops()) { return; } MemoryManager mm("loopUnrollMM"); UnrollInfos loopsToUnroll(mm); findLoopsToUnroll(mm, irm, loopsToUnroll, flags); if (loopsToUnroll.empty()) { if (Log::isEnabled()) Log::out() << "No candidates found to unroll"<<std::endl; return; } if (Log::isEnabled()) { Log::out()<<"Loops to unroll before filtering:"<<std::endl; for (UnrollInfos::const_iterator it = loopsToUnroll.begin(), end = loopsToUnroll.end();it!=end; ++it) { const LoopUnrollInfo* info = *it; info->print(Log::out()); Log::out()<<std::endl; } } bool hasProfile = cfg.hasEdgeProfile(); //filter out that can't be unrolled, calculate BodyA and BodyB BitSet bodyANodes(mm, cfg.getMaxNodeId()), bodyBNodes(mm, cfg.getMaxNodeId()); for (UnrollInfos::iterator it = loopsToUnroll.begin(), end = loopsToUnroll.end();it!=end; ++it) { LoopUnrollInfo* info = *it; if (info == NULL) { continue; } if (!info->doUnroll) { *it=NULL; continue; } Node* header=info->header; LoopNode* loopHeader = lt->getLoopNode(header, false); assert(loopHeader->getHeader() == header); Node* checkNode = info->branchInst->getNode(); bodyANodes.clear(); bodyBNodes.clear(); calculateReachableNodesInLoop(loopHeader, loopHeader->getHeader(), checkNode, bodyANodes); calculateReachableNodesInLoop(loopHeader, checkNode, NULL, bodyBNodes); bodyANodes.intersectWith(bodyBNodes); bool checkNodeIsJunctionPoint = bodyANodes.isEmpty(); if (!checkNodeIsJunctionPoint) { if (Log::isEnabled()) { Log::out()<<"Check node is not a junction point -> removing from the list: branch inst id=I"<<info->branchInst->getId()<<std::endl; } *it=NULL; continue; } //check if branch semantic is OK ComparisonModifier cmpMod = info->branchInst->getModifier().getComparisonModifier(); if (cmpMod!=Cmp_GT && cmpMod!=Cmp_GTE && cmpMod!=Cmp_GT_Un && cmpMod!=Cmp_GTE_Un) { if (Log::isEnabled()) { Log::out()<<"Branch is not a range comparison -> removing from the list: branch inst id=I"<<info->branchInst->getId()<<std::endl; } *it=NULL; continue; } //check config settings bool failed = false; int nodesInLoop = (int)loopHeader->getNodesInLoop().size(); const char* reason = "unknown"; if (nodesInLoop > flags.largeLoopSize) { reason = "loop is too large"; failed = true; } else if (hasProfile) { int headHotness = (int)(header->getExecCount()*100.0 / cfg.getEntryNode()->getExecCount()); int minHeaderHotness= nodesInLoop <= flags.smallLoopSize ? flags.smallLoopHotness : nodesInLoop <= flags.mediumLoopSize ? flags.mediumLoopHotness : flags.largeLoopHotness; info->unrollCount = nodesInLoop <= flags.smallLoopSize ? flags.smallLoopUnrollCount : nodesInLoop <= flags.mediumLoopSize? flags.mediumLoopUnrollCount: flags.largeLoopUnrollCount; failed = headHotness < minHeaderHotness || info->unrollCount < 1; if (failed) { reason = "loop is too cold"; } } if (failed) { if (Log::isEnabled()) { Log::out()<<"Loop does not match unroll configuration ("<<reason<<") -> removing from the list: branch inst id=I"<<info->branchInst->getId()<<std::endl; } *it=NULL; } } //filter out loops with multiple exits for (UnrollInfos::iterator it1 = loopsToUnroll.begin(), end = loopsToUnroll.end();it1!=end; ++it1) { const LoopUnrollInfo* info1 = *it1; if (info1== NULL) { continue; } Node* header=info1->header; for (UnrollInfos::iterator it2 = it1+1; it2!=end; ++it2) { const LoopUnrollInfo* info2 = *it2; if (info2!=NULL && header==info2->header) { if (Log::isEnabled()) { Log::out() << "Found multiple exits:"; FlowGraph::printLabel(Log::out(), header);Log::out()<<std::endl; } if (hasProfile) { Node* check1 = info1->branchInst->getNode(); Node* check2 = info2->branchInst->getNode(); if (check1->getExecCount() > check2->getExecCount()) { *it2 = NULL; } else { *it1 = NULL; } } else { // random selection *it2=NULL; } } } } loopsToUnroll.erase(std::remove(loopsToUnroll.begin(), loopsToUnroll.end(), (LoopUnrollInfo*)NULL), loopsToUnroll.end()); if (loopsToUnroll.empty()) { if (Log::isEnabled()) Log::out() << "--------No candidates to unroll left after filtering"<<std::endl; return; } //dessa CFG before unrolling -> need to duplicate regions and we can do it on dessa form only today { SSABuilder::deconvertSSA(&cfg, irm.getOpndManager()); irm.setInSsa(false); } if (Log::isEnabled()) { Log::out()<<"--------Loops to unroll after filtering : n="<<loopsToUnroll.size()<<std::endl; for (UnrollInfos::const_iterator it = loopsToUnroll.begin(), end = loopsToUnroll.end();it!=end; ++it) { const LoopUnrollInfo* info = *it; info->print(Log::out()); Log::out()<<std::endl; } } for (UnrollInfos::const_iterator it = loopsToUnroll.begin(), end = loopsToUnroll.end();it!=end; ++it) { const LoopUnrollInfo* info = *it; doUnroll(mm, irm, info, flags); } };