bool OSR::isNoArrayInLoop(LoopNode* lnode, SsaOpnd* iv) { Nodes nodes = lnode->getNodesInLoop(); StlVector < Node* >::iterator iter = nodes.begin(), end = nodes.end(); for (; iter != end; iter++) { Node* node = *iter; Inst* last_inst = (Inst*) node->getLastInst(); for (Inst* iter1 = (Inst*) node->getFirstInst(); iter1 != last_inst; iter1 = iter1->getNextInst()) { Inst inst = *iter1; if (inst.getOpcode() == Op_AddScaledIndex) { Opnd* opnd = inst.getSrc(1); findLeadingOpnd(&inst, (SsaOpnd*) opnd); SsaOpnd* lop = getLeadingOperand((SsaOpnd*) opnd); if (lop != 0) { SsaOpnd* ivlop = getLeadingOperand(iv); if (lop == ivlop) { return false; } } } } } return true; }
void SSABuilder::deconvertSSA(ControlFlowGraph* fg,OpndManager& opndManager) { const Nodes& nodes = fg->getNodes(); Nodes::const_iterator niter; for(niter = nodes.begin(); niter != nodes.end(); ++niter) { Node* node = *niter; Inst *headInst = (Inst*)node->getFirstInst(); for (Inst *inst = headInst->getNextInst(); inst != NULL; ) { Inst *nextInst = inst->getNextInst(); if (inst->isPhi()) { inst->unlink(); } else { for (U_32 i = 0; i < inst->getNumSrcOperands(); i++) { Opnd *opnd = inst->getSrc(i); if (opnd->isSsaVarOpnd()) { SsaVarOpnd *ssa = (SsaVarOpnd *)opnd; VarOpnd *var = ssa->getVar(); inst->setSrc(i,var); } else if (opnd->isVarOpnd()) { } } Opnd *dst = inst->getDst(); if (dst->isSsaVarOpnd()) { SsaVarOpnd *ssa = (SsaVarOpnd *)dst; inst->setDst(ssa->getVar()); } } inst = nextInst; } } }
SsaTmpOpnd* OSR::makeTmp(SsaOpnd* inOpnd, Inst* place) { if (inOpnd->isSsaVarOpnd()) { SsaVarOpnd* inSsaVarOpnd = inOpnd->asSsaVarOpnd(); Inst* inst = inSsaVarOpnd->getInst(); if (inst->getOpcode() == Op_StVar) { SsaTmpOpnd* res = inst->getSrc(0)->asSsaTmpOpnd(); return res; } else { OpndManager& opndManager = irManager.getOpndManager(); InstFactory& instFactory = irManager.getInstFactory(); SsaTmpOpnd* res = opndManager.createSsaTmpOpnd(inOpnd->getType()); Inst* ldVarInst = instFactory.makeLdVar(res, inSsaVarOpnd); Inst* where = chooseLocationForConvert(inst, place); insertInst(ldVarInst, where); writeLeadingOperand(res, getLeadingOperand(inOpnd)); return res; } } else { return inOpnd->asSsaTmpOpnd(); } }
/* 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; }
void SSABuilder::clearPhiSrcs2(Node *node, const StlVectorSet<VarOpnd *> *whatVars, StlVector<VarOpnd *> *changedVars, const StlVectorSet<Opnd *> *removedVars, StlVector<Node *> &scratchNodeList) { bool needPreds = true; StlVector<Node *> &preds = scratchNodeList; Inst* inst = (Inst*)node->getSecondInst(); for (;inst!=NULL && inst->isPhi(); inst = inst->getNextInst()) { Opnd *dstOp =inst->getDst(); VarOpnd *varOpnd = 0; if (whatVars) { varOpnd = dstOp->asVarOpnd(); if (!varOpnd) { SsaVarOpnd *ssaOpnd = dstOp->asSsaVarOpnd(); assert(ssaOpnd); varOpnd = ssaOpnd->getVar(); } if (!whatVars->has(varOpnd)) continue; } bool changed=false; U_32 numSrcs = inst->getNumSrcOperands(); for (U_32 i=0; i<numSrcs; ++i) { Opnd *thisOpnd = inst->getSrc(i); if (!(removedVars && removedVars->has(thisOpnd))) { // need to test whether need to remove if (needPreds) { needPreds = false; const Edges& edges2 = node->getInEdges(); preds.clear(); preds.reserve(edges2.size()); Edges::const_iterator eiter2; for(eiter2 = edges2.begin(); eiter2 != edges2.end(); ++eiter2){ preds.push_back((*eiter2)->getSourceNode()); } } DominatorTree &domTree = frontier.getDominator(); Inst *thisOpndInst = thisOpnd->getInst(); Node *thisOpndInstNode = thisOpndInst->getNode(); if (thisOpndInstNode) { // the operand's source instruction was not already dead. StlVector<Node *>::const_iterator predIter = preds.begin(), predEnd = preds.end(); bool foundDom = false; for ( ; predIter != predEnd; ++predIter) { Node *predNode = *predIter; if (domTree.dominates(thisOpndInstNode, predNode)) { // we found it, leave this operand alone. foundDom = true; break; } } if (foundDom) continue; // leave operand alone. } } // remove this operand; if (i < numSrcs-1) { inst->setSrc(i, inst->getSrc(numSrcs-1)); --i; // re-examine this operand, which is now the last } --numSrcs; // we deleted one operand PhiInst *phiInst = inst->asPhiInst(); assert(phiInst); phiInst->setNumSrcs(numSrcs); changed = true; } if (changed) { // note the changed var; if (!varOpnd) { varOpnd = dstOp->asVarOpnd(); if (!varOpnd) { SsaVarOpnd *ssaOpnd = dstOp->asSsaVarOpnd(); assert(ssaOpnd); varOpnd = ssaOpnd->getVar(); } } changedVars->push_back(varOpnd); } } }
// // traverse dominator tree and rename variables // void SSABuilder::renameNode(RenameStack *renameStack, DominatorNode* dt, const StlVectorSet<VarOpnd *> *whatVars) { if (dt == NULL) return; Node* node = dt->getNode(); Inst* head = (Inst*)node->getFirstInst(); #ifdef DEBUG_SSA std::ostream &cout = Log::out(); if (Log::isEnabled()) { cout << "renameNode "; FlowGraph::printLabel(cout, node); cout << std::endl; } #endif for (Inst* i = head->getNextInst(); i != NULL; i = i->getNextInst()) { if (!i->isPhi()) { // replace src with ssa opnd U_32 nSrcs = i->getNumSrcOperands(); for (U_32 j = 0; j < nSrcs; j++) { Opnd *srcj = i->getSrc(j); VarOpnd *srcjVar = (srcj->isSsaVarOpnd() ? srcj->asSsaVarOpnd()->getVar() : srcj->asVarOpnd()); if (!(srcjVar && !srcjVar->isAddrTaken())) continue; if (whatVars && !whatVars->has(srcjVar)) continue; SsaVarOpnd* ssa = renameStack->lookup(srcjVar); assert(ssa); i->setSrc(j,ssa); } } // for both Phi and non-Phi // we replace any non-ssa dst with a new ssa opnd // and record it in the RenameStack map Opnd* dst = i->getDst(); VarOpnd *theVar = dst->asVarOpnd(); if (theVar && (!theVar->isAddrTaken()) && !(whatVars && !whatVars->has(theVar))) { SsaVarOpnd* ssaDst = opndManager.createSsaVarOpnd((VarOpnd*)dst); #ifdef DEBUG_SSA if (Log::isEnabled()) { cout << "SSA "; ssaDst->print(cout); cout << ::std::endl; } #endif renameStack->insert((VarOpnd*)dst, ssaDst); i->setDst(ssaDst); #ifdef DEBUG_SSA if (Log::isEnabled()) { i->print(cout); cout << ::std::endl; } #endif // record stVar inst } else if (dst->isSsaVarOpnd()) { SsaVarOpnd* ssaDst = dst->asSsaVarOpnd(); theVar = ssaDst->getVar(); if (whatVars && !whatVars->has(theVar)) continue; #ifdef DEBUG_SSA if (Log::isEnabled()) { cout << "SSA "; ssaDst->print(cout); cout << ::std::endl; } #endif renameStack->insert(ssaDst->getVar(), ssaDst); #ifdef DEBUG_SSA if (Log::isEnabled()) { i->print(cout); cout << ::std::endl; } #endif } } // add var sources to following phi instructions const Edges& edges = node->getOutEdges(); Edges::const_iterator eiter = edges.begin(), eend = edges.end(); for(eiter = edges.begin(); eiter != eend; ++eiter) { Edge* e = *eiter; Node* succ = e->getTargetNode(); // Phi insts are inserted to the beginning of the block // if succ does not have phi insts, then we can skip it Inst *phi = (Inst*)succ->getSecondInst(); if (phi==NULL || !phi->isPhi()) continue; // node is jth predecessor for succ // replace jth var of phi insts Inst* nextphi = phi->getNextInst(); for (;phi!=NULL && phi->isPhi(); phi = nextphi) { nextphi = phi->getNextInst(); // get var Opnd *theopnd = phi->getDst(); VarOpnd *thevar = theopnd->asVarOpnd(); if (!thevar) { SsaVarOpnd *theSsaVar = theopnd->asSsaVarOpnd(); assert(theSsaVar); #ifdef DEBUG_SSA if (Log::isEnabled()) { Log::out() << "case 2" << ::std::endl; } #endif thevar = theSsaVar->getVar(); } if (whatVars && !whatVars->has(thevar)) continue; SsaVarOpnd* ssa = renameStack->lookup((VarOpnd*)thevar); if (ssa != NULL) { #ifdef DEBUG_SSA if (Log::isEnabled()) { cout << "redge"; // cout << (I_32)j; cout << " with ssa "; ssa->print(cout); cout << ::std::endl; } #endif addPhiSrc((PhiInst*)phi,ssa); } else { #ifdef DEBUG_SSA if (Log::isEnabled()) { cout << "no source for phi of var "; thevar->print(cout); cout << ::std::endl; } #endif // if ssa is NULL, then the phi must be a dead phi inst // (no more use of var afterwards). it will be removed. } } } }
// rename vars to make un-overlapping live ranges of a variable into // different variables. void SSABuilder::splitSsaWebs(ControlFlowGraph* fg,OpndManager& opndManager) { U_32 numSsaOpnds = opndManager.getNumSsaOpnds(); MemoryManager localMM("SSABuilder::splitSsaWebs::memManager"); SsaVarClique *cliques = new (localMM) SsaVarClique[numSsaOpnds]; const Nodes& nodes = fg->getNodes(); Nodes::const_iterator niter; for(niter = nodes.begin(); niter != nodes.end(); ++niter) { Node* node = *niter; Inst *headInst = (Inst*)node->getFirstInst(); for (Inst *inst = headInst->getNextInst(); inst != NULL; ) { Inst *nextInst = inst->getNextInst(); if (inst->isPhi()) { // do something VarOpnd *var0 = 0; SsaVarClique *clique = 0; for (U_32 i = 0; i < inst->getNumSrcOperands(); i++) { Opnd *opnd = inst->getSrc(i); if (opnd->isSsaVarOpnd()) { SsaVarOpnd *ssa = (SsaVarOpnd *)opnd; U_32 id = ssa->getId(); if (var0) { assert(ssa->getVar()==var0); cliques[id].link(clique); } else { var0 = ssa->getVar(); clique = &cliques[id]; } } } Opnd *dst = inst->getDst(); if (dst->isSsaVarOpnd()) { SsaVarOpnd *ssa = (SsaVarOpnd *)dst; ssa->getVar(); U_32 id = ssa->getId(); if (var0) { assert(ssa->getVar()==var0); cliques[id].link(clique); } else { var0 = ssa->getVar(); clique = &cliques[id]; } } } inst = nextInst; } } U_32 numvars = opndManager.getNumVarOpnds(); bool *used = new (localMM) bool[numvars]; for (U_32 i=0; i<numvars; i++) { used[i] = false; } for(niter = nodes.begin(); niter != nodes.end(); ++niter) { Node* node = *niter; Inst *headInst = (Inst*)node->getFirstInst(); for (Inst *inst = headInst->getNextInst(); inst != NULL; ) { Inst *nextInst = inst->getNextInst(); for (U_32 i = 0; i < inst->getNumSrcOperands(); i++) { Opnd *opnd = inst->getSrc(i); if (opnd->isSsaVarOpnd()) { SsaVarOpnd *ssa = (SsaVarOpnd *)opnd; VarOpnd *var = ssa->getVar(); U_32 id=ssa->getId(); SsaVarClique *clique = &cliques[id]; clique = clique->getRoot(); VarOpnd *cvar = clique->var; if (cvar == 0) { U_32 varId = var->getId(); if (used[varId]) { cvar = opndManager.createVarOpnd(var->getType(), var->isPinned()); } else { cvar = var; used[varId] = true; } clique->var = cvar; } if (cvar != var) { ssa->setVar(cvar); } } } Opnd *dst = inst->getDst(); if (dst->isSsaVarOpnd()) { SsaVarOpnd *ssa = (SsaVarOpnd *)dst; VarOpnd *var = ssa->getVar(); U_32 id=ssa->getId(); SsaVarClique *clique = &cliques[id]; clique = clique->getRoot(); VarOpnd *cvar = clique->var; if (cvar == 0) { U_32 varId = var->getId(); if (used[varId]) { cvar = opndManager.createVarOpnd(var->getType(), var->isPinned()); } else { cvar = var; used[varId] = true; } clique->var = cvar; } if (cvar != var) { ssa->setVar(cvar); } } inst = nextInst; } } }