/* The code below is based on loop_unroll processOpnd function. However it * gathers some additional OSR-specific information which is obsolele for * loop_unroll. * * TODO: create flexible mechanism for gathering info on the operands which * would help to avoid code duplication from the one hand, and be customizable * from another hand */ OSROpndInfo OSRInductionDetector::processOpnd(LoopTree* tree, LoopNode* loopHead, InstStack& defStack, const Opnd* opnd, iv_detection_flag flag) { if (Log::isEnabled()) { Log::out() << "Processing opnd: "; opnd->print(Log::out()); Log::out() << "\n"; } OSROpndInfo result; Inst* defInst = opnd->getInst(); if (std::find(defStack.begin(), defStack.end(), defInst) != defStack.end()) { result.setType(OSROpndInfo::COUNTER); result.setIncrement(0); result.setOpnd((Opnd*) opnd); return result; } Opcode opcode = defInst->getOpcode(); if (opcode == Op_LdConstant) { result.setType(OSROpndInfo::LD_CONST); result.setConst(defInst->asConstInst()->getValue().i4); result.setOpnd((Opnd*) opnd); result.setHeader((Opnd*) opnd); result.setHeaderFound(); return result; } if (!inExactLoop(tree, (Opnd*) opnd, loopHead)) { result.setOpnd((Opnd*) opnd); result.setHeader((Opnd*) opnd); result.setHeaderFound(); return result; } defStack.push_back(defInst); if (opcode == Op_Phi) { OSROpndInfo info1 = processOpnd(tree, loopHead, defStack, defInst->getSrc(0)); if (defInst->getNumSrcOperands() > 1) { OSROpndInfo info2 = processOpnd(tree, loopHead, defStack, defInst->getSrc(1)); if ( ((info1.isCounter() && !info1.isPhiSplit()) && (info2.isDOL() || info2.isLDConst())) || ((info2.isCounter() && !info2.isPhiSplit()) && (info1.isDOL() || info1.isLDConst())) ) { result.setType(OSROpndInfo::COUNTER); result.setIncrement(info1.isCounter()? info1. getIncrement() : info2.getIncrement()); result.markPhiSplit(); result.setHeader((Opnd*) opnd); result.setHeaderFound(); } else if ((flag == CHOOSE_MAX_IN_BRANCH) && info1.isCounter() && info2.isCounter() && signof(info1.getIncrement()) == signof(info2.getIncrement())) { result.setType(OSROpndInfo::COUNTER); result.setIncrement(std::abs(info1.getIncrement()) > std::abs(info2.getIncrement())? info1. getIncrement() : info2.getIncrement()); result.markPhiSplit(); result.setHeader((Opnd*) opnd); result.setHeaderFound(); } else { result.setType(OSROpndInfo::UNDEF); } } } else if (opcode == Op_Add || opcode == Op_Sub) { Opnd* opnd1 = defInst->getSrc(0); Opnd* opnd2 = defInst->getSrc(1); OSROpndInfo info1 = processOpnd(tree, loopHead, defStack, opnd1); OSROpndInfo info2 = processOpnd(tree, loopHead, defStack, opnd2); if ((info1.isLDConst() || info1.isDOL()) && (info2.isLDConst() || info2.isDOL())) { if (info1.isLDConst() && info2.isLDConst() && info1.getConst() == info2.getConst()) { result.setType(OSROpndInfo::LD_CONST); result.setConst(info1.getConst()); writeHeaderToResult(result, tree, info1, info2); } } else if ((info1.isCounter() && info2.isLDConst()) || (info2.isCounter() && info1.isLDConst())) { U_32 increment = info1.isCounter() ? info1.getIncrement() : info2.getIncrement(); U_32 diff = info1.isLDConst()? info1.getConst() : info2.getConst(); bool monotonousFlag = increment == 0 || diff == 0 || (opcode == Op_Add && signof(diff) == signof(increment)) || (opcode == Op_Sub && signof(diff) != signof(increment)); if (monotonousFlag) { result.setType(OSROpndInfo::COUNTER); if ((info1.isCounter() && info1.isPhiSplit()) || (info2.isCounter() && info2.isPhiSplit())) { result.markPhiSplit(); writeHeaderToResult(result, tree, info1, info2); } if (opcode == Op_Add) { result.setIncrement(increment + diff); writeHeaderToResult(result, tree, info1, info2); } else { result.setIncrement(increment - diff); writeHeaderToResult(result, tree, info1, info2); } } else { result.setType(OSROpndInfo::UNDEF); } } else { result.setType(OSROpndInfo::UNDEF); } } else if (opcode == Op_StVar || opcode == Op_LdVar) { Opnd* newOpnd = defInst->getSrc(0); result = processOpnd(tree, loopHead, defStack, newOpnd); } else if (opcode == Op_TauArrayLen) { Opnd* arrayOpnd = defInst->getSrc(0); result = processOpnd(tree, loopHead, defStack, arrayOpnd); } else { result.setType(OSROpndInfo::UNDEF); } defStack.pop_back(); result.setOpnd((Opnd*) opnd); return result; }
static OpndLoopInfo processOpnd(LoopNode* loopHead, LoopTree* lt, InstStack& defStack, Opnd* opnd) { OpndLoopInfo result; Inst* defInst = opnd->getInst(); if (Log::isEnabled()) { log_ident(defStack.size()); defInst->print(Log::out()); Log::out()<<"]"<<std::endl; } if (std::find(defStack.begin(), defStack.end(), defInst)!=defStack.end()) { result.setType(OpndLoopInfo::COUNTER); result.setIncrement(0); if (Log::isEnabled()) { log_ident(defStack.size()); Log::out()<<"Found duplicate in def stack -> stopping recursion. ";result.print(Log::out()); Log::out()<<std::endl; } return result; } Node* defNode = defInst->getNode(); Opcode opcode = defInst->getOpcode(); if (opcode == Op_LdConstant) { result.setType(OpndLoopInfo::LD_CONST); result.setConst(defInst->asConstInst()->getValue().i4); if (Log::isEnabled()) { log_ident(defStack.size()); Log::out()<<"assigning to const -> stopping recursion. ";result.print(Log::out());Log::out()<<std::endl; } return result; } if (!loopHead->inLoop(defNode)) { if (Log::isEnabled()) { log_ident(defStack.size()); Log::out()<<"Inst out of the loop -> stopping recursion. ";result.print(Log::out()); Log::out()<<std::endl; } return result; } defStack.push_back(defInst); if (opcode == Op_Phi) { OpndLoopInfo info1 = processOpnd(loopHead, lt, defStack, defInst->getSrc(0)); OpndLoopInfo info2 = processOpnd(loopHead, lt, defStack, defInst->getSrc(1)); if (Log::isEnabled()) { log_ident(defStack.size()); Log::out()<<"PHI(";info1.print(Log::out());Log::out()<<",";info2.print(Log::out());Log::out()<<")"<<std::endl; } if ( ((info1.isCounter() && !info1.isPhiSplit()) && (info2.isDOL() || info2.isLDConst())) || ((info2.isCounter() && !info2.isPhiSplit()) && (info1.isDOL() || info1.isLDConst())) ) { result.setType(OpndLoopInfo::COUNTER); result.setIncrement(info1.isCounter() ? info1.getIncrement() : info2.getIncrement()); result.markPhiSplit(); } else { result.setType(OpndLoopInfo::UNDEF); } } else if (opcode == Op_Add || opcode == Op_Sub) { //todo: LADD Opnd *op1 = defInst->getSrc(0); Opnd *op2 = defInst->getSrc(1); OpndLoopInfo info1 = processOpnd(loopHead, lt, defStack, op1); OpndLoopInfo info2 = processOpnd(loopHead, lt, defStack, op2); if ((info1.isLDConst() || info1.isDOL()) && (info2.isLDConst() || info2.isDOL())) { if (info1.isLDConst() && info2.isLDConst() && info1.getConst() == info2.getConst()) { result.setType(OpndLoopInfo::LD_CONST); result.setConst(info1.getConst()); } else { //result is DOL (default type) } } else if ((info1.isCounter() && info2.isLDConst()) || (info2.isCounter() && info1.isLDConst())) { int increment = info1.isCounter()? info1.getIncrement(): info2.getIncrement(); int diff = info1.isLDConst()? info1.getConst(): info2.getConst(); //we use SSA form to analyze how opnd changes in loop and we do not analyze actual control flow, // so we can unroll loops with monotonically changing 'counters' only. //Example: when 'counter' changes not monotonically and we can't unroll: //idx=0; loop {idx+=100; if(idx>=100) break; idx-=99;} ->'increment'=1 but not monotonicaly. bool monotonousFlag = increment == 0 || diff == 0 || (opcode == Op_Add && signof(diff) == signof(increment)) || (opcode == Op_Sub && signof(diff) != signof(increment)); if (monotonousFlag) { result.setType(OpndLoopInfo::COUNTER); if ((info1.isCounter() && info1.isPhiSplit()) || (info2.isCounter() && info2.isPhiSplit())) { result.markPhiSplit(); } //TO IMPROVE: for loops like: for (; length-1>=0;length--){...} //we have 2 SUBs by -1 => "-2", but real counter is changed by "-1". //Loop unroll will use "-2". It's ok, because this value is used in a guard inst //and ABS(increment_in_unroll) >= ABS(real_increment). This work only for monotonous loops. //To make increment_in_unroll == real_increment we must track modifications (SUB,ADD) that affects vars only. if (opcode == Op_Add) { result.setIncrement(increment + diff); } else { result.setIncrement(increment - diff); } } else { result.setType(OpndLoopInfo::UNDEF); } } else { result.setType(OpndLoopInfo::UNDEF); } } else if (opcode == Op_StVar || opcode == Op_LdVar) { Opnd* newOpnd = defInst->getSrc(0); result = processOpnd(loopHead, lt, defStack, newOpnd); } else if (opcode == Op_TauArrayLen) { Opnd* arrayOpnd = defInst->getSrc(0); result = processOpnd(loopHead, lt, defStack, arrayOpnd); } else { //unsupported op result.setType(OpndLoopInfo::UNDEF); if (Log::isEnabled()) { log_ident(defStack.size()); Log::out()<<"unknown op -> stopping recursion. "; } } defStack.pop_back(); if (Log::isEnabled()) { log_ident(defStack.size()); result.print(Log::out());Log::out()<<std::endl; } return result; }
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 PRDF::computeLocal(IRBB * bb, List<IR const*> & lst) { DefSBitSetCore * gen = get_def(BB_id(bb)); DefSBitSetCore * use = get_use(BB_id(bb)); gen->clean(m_sbs_mgr); use->clean(m_sbs_mgr); for (IR * x = BB_last_ir(bb); x != NULL; x = BB_prev_ir(bb)) { ASSERT0(x->is_stmt()); switch (IR_code(x)) { case IR_ST: lst.clean(); processOpnd(ST_rhs(x), lst, use, gen); break; case IR_STPR: gen->bunion(STPR_no(x), m_sbs_mgr); use->diff(STPR_no(x), m_sbs_mgr); processMay(x, gen, use, true); lst.clean(); processOpnd(STPR_rhs(x), lst, use, gen); break; case IR_SETELEM: gen->bunion(SETELEM_prno(x), m_sbs_mgr); use->diff(SETELEM_prno(x), m_sbs_mgr); processMay(x, gen, use, true); lst.clean(); processOpnd(SETELEM_rhs(x), lst, use, gen); lst.clean(); processOpnd(SETELEM_ofst(x), lst, use, gen); break; case IR_GETELEM: gen->bunion(GETELEM_prno(x), m_sbs_mgr); use->diff(GETELEM_prno(x), m_sbs_mgr); processMay(x, gen, use, true); lst.clean(); processOpnd(GETELEM_base(x), lst, use, gen); lst.clean(); processOpnd(GETELEM_ofst(x), lst, use, gen); break; case IR_STARRAY: lst.clean(); processOpnd(x, lst, use, gen); break; case IR_IST: lst.clean(); processOpnd(x, lst, use, gen); break; case IR_SWITCH: lst.clean(); processOpnd(SWITCH_vexp(x), lst, use, gen); break; case IR_IGOTO: lst.clean(); processOpnd(IGOTO_vexp(x), lst, use, gen); break; case IR_GOTO: break; case IR_CALL: case IR_ICALL: if (x->hasReturnValue()) { gen->bunion(CALL_prno(x), m_sbs_mgr); use->diff(CALL_prno(x), m_sbs_mgr); processMay(x, gen, use, true); } lst.clean(); processOpnd(CALL_param_list(x), lst, use, gen); if (x->is_icall() && ICALL_callee(x)->is_pr()) { use->bunion(PR_no(ICALL_callee(x)), m_sbs_mgr); processMay(ICALL_callee(x), gen, use, false); } break; case IR_TRUEBR: case IR_FALSEBR: lst.clean(); processOpnd(BR_det(x), lst, use, gen); break; case IR_RETURN: lst.clean(); processOpnd(RET_exp(x), lst, use, gen); break; case IR_PHI: gen->bunion(PHI_prno(x), m_sbs_mgr); use->diff(PHI_prno(x), m_sbs_mgr); processMay(x, gen, use, true); lst.clean(); processOpnd(PHI_opnd_list(x), lst, use, gen); break; case IR_REGION: break; default: ASSERT0(0); } } }