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; }
PeepHoleOpt::Changed PeepHoleOpt::handleInst_MOV(Inst* inst) { Node* node = inst->getNode(); if (((BasicBlock*)node)->getLayoutSucc() == NULL) { Inst *next = inst->getNextInst(); Node *currNode = node; bool methodMarkerOccur = false; MethodMarkerPseudoInst* methodMarker = NULL; // ignoring instructions that have no effect and saving method markers to correct them during optimizations while (next == NULL || next->getKind() == Inst::Kind_MethodEndPseudoInst || next->getMnemonic() == Mnemonic_JMP) { if (next == NULL) { currNode = currNode->getOutEdge(Edge::Kind_Unconditional)->getTargetNode(); if (currNode->getKind() == Node::Kind_Exit) return Changed_Nothing; next = (Inst*) currNode->getFirstInst(); } else { if (next->getKind() == Inst::Kind_MethodEndPseudoInst) { //max 1 saved method marker if (methodMarkerOccur) { return Changed_Nothing; } methodMarker = (MethodMarkerPseudoInst*)next; methodMarkerOccur = true; } next = next->getNextInst(); } } Inst *jump = next->getNextInst(); bool step1 = true; currNode = node; while (currNode != next->getNode()) { currNode = currNode->getOutEdge(Edge::Kind_Unconditional)->getTargetNode(); if (currNode->getInDegree()!=1) { step1 = false; break; } } // step1: // --------------------------------------------- // MOV opnd, opnd2 MOV opnd3, opnd2 // MOV opnd3, opnd -> // --------------------------------------------- // nb: applicable if opnd will not be used further if (step1 && next->getMnemonic() == Mnemonic_MOV) { Opnd *movopnd1, *movopnd2, *nextmovopnd1, *nextmovopnd2; bool isInstCopyPseudo = (inst->getKind() == Inst::Kind_CopyPseudoInst); if (isInstCopyPseudo) { movopnd1 = inst->getOpnd(0); movopnd2 = inst->getOpnd(1); } else { Inst::Opnds movuses(inst, Inst::OpndRole_Explicit|Inst::OpndRole_Use); Inst::Opnds movdefs(inst, Inst::OpndRole_Explicit|Inst::OpndRole_Def); movopnd1 = inst->getOpnd(movdefs.begin()); movopnd2 = inst->getOpnd(movuses.begin()); } bool isNextCopyPseudo = (next->getKind() == Inst::Kind_CopyPseudoInst); if (isNextCopyPseudo) { nextmovopnd1 = next->getOpnd(0); nextmovopnd2 = next->getOpnd(1); } else { Inst::Opnds nextmovuses(next, Inst::OpndRole_Explicit|Inst::OpndRole_Use); Inst::Opnds nextmovdefs(next, Inst::OpndRole_Explicit|Inst::OpndRole_Def); nextmovopnd1 = next->getOpnd(nextmovdefs.begin()); nextmovopnd2 = next->getOpnd(nextmovuses.begin()); } if (movopnd1->getId() == nextmovopnd2->getId() && !isMem(movopnd2) && !isMem(nextmovopnd1) && !isMem(movopnd1) ) { BitSet ls(irManager->getMemoryManager(), irManager->getOpndCount()); irManager->updateLivenessInfo(); irManager->getLiveAtExit(next->getNode(), ls); for (Inst* i = (Inst*)next->getNode()->getLastInst(); i!=next; i = i->getPrevInst()) { irManager->updateLiveness(i, ls); } bool dstNotUsed = !ls.getBit(movopnd1->getId()); if (dstNotUsed) { if (isInstCopyPseudo && isNextCopyPseudo) irManager->newCopyPseudoInst(Mnemonic_MOV, nextmovopnd1, movopnd2)->insertAfter(inst); else irManager->newInst(Mnemonic_MOV, nextmovopnd1, movopnd2)->insertAfter(inst); inst->unlink(); next->unlink(); return Changed_Node; } } } // step2: // -------------------------------------------------------------- // MOV opnd, 0/1 Jmp smwh/BB1 Jmp smwh/BB1 // CMP opnd, 0 -> CMP opnd, 0 v // Jcc smwh Jcc smwh // BB1: BB1: // -------------------------------------------------------------- // nb: applicable if opnd will not be used further if (next->getMnemonic() == Mnemonic_CMP && jump!= NULL && (jump->getMnemonic() == Mnemonic_JE || jump->getMnemonic() == Mnemonic_JNE)) { Opnd *movopnd1, *movopnd2; if (inst->getKind() == Inst::Kind_CopyPseudoInst) { movopnd1 = inst->getOpnd(0); movopnd2 = inst->getOpnd(1); } else { Inst::Opnds movuses(inst, Inst::OpndRole_Explicit|Inst::OpndRole_Use); Inst::Opnds movdefs(inst, Inst::OpndRole_Explicit|Inst::OpndRole_Def); movopnd1 = inst->getOpnd(movdefs.begin()); movopnd2 = inst->getOpnd(movuses.begin()); } Inst::Opnds cmpuses(next, Inst::OpndRole_Explicit|Inst::OpndRole_Use); Opnd* cmpopnd1 = next->getOpnd(cmpuses.begin()); Opnd* cmpopnd2 = next->getOpnd(cmpuses.next(cmpuses.begin())); if (isImm(movopnd2) && (movopnd2->getImmValue() == 0 || movopnd2->getImmValue() == 1) && movopnd1->getId() == cmpopnd1->getId() && isImm(cmpopnd2) && cmpopnd2->getImmValue() == 0) { BitSet ls(irManager->getMemoryManager(), irManager->getOpndCount()); irManager->updateLivenessInfo(); irManager->getLiveAtExit(jump->getNode(), ls); bool opndNotUsed = !ls.getBit(movopnd1->getId()); if (opndNotUsed) { ControlFlowGraph* cfg = irManager->getFlowGraph(); Node* destination = ((BranchInst*)jump)->getTrueTarget(); if ((jump->getMnemonic() == Mnemonic_JNE || movopnd2->getImmValue() == 1) && !(jump->getMnemonic() == Mnemonic_JNE && movopnd2->getImmValue() == 1)) { destination = ((BranchInst*)jump)->getFalseTarget(); } if (node->getId() != next->getNode()->getId()) { if (methodMarkerOccur) { inst->getNode()->appendInst(irManager->newMethodEndPseudoInst(methodMarker->getMethodDesc())); } inst->unlink(); Edge *outEdge = node->getOutEdge(Edge::Kind_Unconditional); cfg->replaceEdgeTarget(outEdge, destination, true); cfg->purgeUnreachableNodes(); // previous successor may become unreachable } else { cfg->removeEdge(node->getOutEdge(Edge::Kind_True)); cfg->removeEdge(node->getOutEdge(Edge::Kind_False)); cfg->addEdge(node, destination); inst->unlink(); next->unlink(); jump->unlink(); } return Changed_Node; } } } } return Changed_Nothing; }
PeepHoleOpt::Changed PeepHoleOpt::handleInst_SETcc(Inst* inst) { if (((BasicBlock*)inst->getNode())->getLayoutSucc() == NULL) { Mnemonic mn = inst->getMnemonic(); Inst* prev = inst->getPrevInst(); Inst *next = inst->getNextInst(); Node *currNode = inst->getNode(); bool methodMarkerOccur = false; MethodMarkerPseudoInst* methodMarker = NULL; // ignoring instructions that have no effect and saving method markers to correct them during optimizations while (next == NULL || next->getKind() == Inst::Kind_MethodEndPseudoInst || next->getMnemonic() == Mnemonic_JMP) { if (next == NULL) { currNode = currNode->getOutEdge(Edge::Kind_Unconditional)->getTargetNode(); if (currNode->getKind() == Node::Kind_Exit) return Changed_Nothing; next = (Inst*) currNode->getFirstInst(); } else { if (next->getKind() == Inst::Kind_MethodEndPseudoInst) { //max 1 saved method marker if (methodMarkerOccur) { return Changed_Nothing; } methodMarker = (MethodMarkerPseudoInst*)next; methodMarkerOccur = true; } next = next->getNextInst(); } } Inst *next2 = next->getNextInst(); bool step1 = true; currNode = inst->getNode(); while (currNode != next->getNode()) { currNode = currNode->getOutEdge(Edge::Kind_Unconditional)->getTargetNode(); if (currNode->getInDegree()!=1) { step1 = false; break; } } // step1: // ------------------------------------------ // MOV opnd, 0 MOV opnd2, 0 // SETcc opnd -> SETcc opnd2 // MOV opnd2, opnd // ------------------------------------------ // nb: applicable if opnd will not be used further if (step1 && prev!= NULL && prev->getMnemonic() == Mnemonic_MOV && next!= NULL && next->getMnemonic() == Mnemonic_MOV) { Opnd *prevopnd1, *prevopnd2, *nextopnd1, *nextopnd2, *setopnd; if (prev->getKind() == Inst::Kind_CopyPseudoInst) { prevopnd1 = prev->getOpnd(0); prevopnd2 = prev->getOpnd(1); } else { Inst::Opnds prevuses(prev, Inst::OpndRole_Explicit|Inst::OpndRole_Use); Inst::Opnds prevdefs(prev, Inst::OpndRole_Explicit|Inst::OpndRole_Def); prevopnd1 = prev->getOpnd(prevdefs.begin()); prevopnd2 = prev->getOpnd(prevuses.begin()); } if (next->getKind() == Inst::Kind_CopyPseudoInst) { nextopnd1 = next->getOpnd(0); nextopnd2 = next->getOpnd(1); } else { Inst::Opnds nextuses(next, Inst::OpndRole_Explicit|Inst::OpndRole_Use); Inst::Opnds nextdefs(next, Inst::OpndRole_Explicit|Inst::OpndRole_Def); nextopnd1 = next->getOpnd(nextdefs.begin()); nextopnd2 = next->getOpnd(nextuses.begin()); } Inst::Opnds setdefs(inst, Inst::OpndRole_Explicit|Inst::OpndRole_Def); setopnd = inst->getOpnd(setdefs.begin()); if (isReg(nextopnd1) && prevopnd1->getId() == setopnd->getId() && setopnd->getId() == nextopnd2->getId() && isImm(prevopnd2) && prevopnd2->getImmValue() == 0 ) { BitSet ls(irManager->getMemoryManager(), irManager->getOpndCount()); irManager->updateLivenessInfo(); irManager->getLiveAtExit(next->getNode(), ls); for (Inst* i = (Inst*)next->getNode()->getLastInst(); i!=next; i = i->getPrevInst()) { irManager->updateLiveness(i, ls); } bool opndNotUsed = !ls.getBit(setopnd->getId()); if (opndNotUsed) { if (nextopnd1->getRegName() != RegName_Null && Constraint::getAliasRegName(nextopnd1->getRegName(), OpndSize_8) == RegName_Null) { nextopnd1->assignRegName(setopnd->getRegName()); } irManager->newInst(Mnemonic_MOV, nextopnd1, prevopnd2)->insertBefore(inst); irManager->newInst(mn, nextopnd1)->insertBefore(inst); prev->unlink(); inst->unlink(); next->unlink(); return Changed_Node; } } } // step2: // -------------------------------------------------------------- // MOV opnd, 0 Jcc smwh Jcc smwh // SETcc opnd -> BB1: v BB1: // CMP opnd, 0 ... // Jcc smwh CMP opnd, 0 // BB1: Jcc smwh // -------------------------------------------------------------- // nb: applicable if opnd will not be used further // nb: conditions of new jumps are calculated from conditions of old jump and set instructions if (prev!= NULL && prev->getMnemonic() == Mnemonic_MOV && next!= NULL && (next->getMnemonic() == Mnemonic_CMP || next->getMnemonic() == Mnemonic_TEST) && next2!= NULL && (next2->getMnemonic() == Mnemonic_JG || next2->getMnemonic() == Mnemonic_JE || next2->getMnemonic() == Mnemonic_JNE) ) { Opnd* movopnd1; Opnd* movopnd2; if (prev->getKind() == Inst::Kind_CopyPseudoInst) { movopnd1 = prev->getOpnd(0); movopnd2 = prev->getOpnd(1); } else { Inst::Opnds movuses(prev, Inst::OpndRole_Explicit|Inst::OpndRole_Use); Inst::Opnds movdefs(prev, Inst::OpndRole_Explicit|Inst::OpndRole_Def); movopnd1 = prev->getOpnd(movdefs.begin()); movopnd2 = prev->getOpnd(movuses.begin()); } Inst::Opnds cmpuses(next, Inst::OpndRole_Explicit|Inst::OpndRole_Use); Opnd* cmpopnd1 = next->getOpnd(cmpuses.begin()); Opnd* cmpopnd2 = next->getOpnd(cmpuses.next(cmpuses.begin())); if ( isImm(movopnd2) && movopnd2->getImmValue() == 0 && movopnd1->getId() == cmpopnd1->getId() && //case CMP: (next->getMnemonic() != Mnemonic_CMP || (isImm(cmpopnd2) && cmpopnd2->getImmValue() == 0)) && //case TEST: (next->getMnemonic() != Mnemonic_TEST || cmpopnd1->getId() == cmpopnd2->getId()) ) { BitSet ls(irManager->getMemoryManager(), irManager->getOpndCount()); irManager->updateLivenessInfo(); irManager->getLiveAtExit(next2->getNode(), ls); bool opndNotUsed = !ls.getBit(movopnd1->getId()); if (opndNotUsed) { BranchInst* br = (BranchInst*) next2; Mnemonic newjumpmn = Mnemonic_JZ; if (next2->getMnemonic() == Mnemonic_JE) { switch (mn) { case Mnemonic_SETG: newjumpmn = Mnemonic_JLE; break; case Mnemonic_SETE: newjumpmn = Mnemonic_JNE; break; case Mnemonic_SETL: newjumpmn = Mnemonic_JGE; break; case Mnemonic_SETNE: newjumpmn = Mnemonic_JE; break; default: assert(0); break; } } else { switch (mn) { case Mnemonic_SETG: newjumpmn = Mnemonic_JG; break; case Mnemonic_SETE: newjumpmn = Mnemonic_JE; break; case Mnemonic_SETL: newjumpmn = Mnemonic_JL; break; case Mnemonic_SETNE: newjumpmn = Mnemonic_JNE; break; default: assert(0); break; } } if (inst->getNode()->getId() != next->getNode()->getId()) { ControlFlowGraph* cfg = irManager->getFlowGraph(); cfg->removeEdge(inst->getNode()->getOutEdge(Edge::Kind_Unconditional)); double trueEdgeProb = next2->getNode()->getOutEdge(Edge::Kind_True)->getEdgeProb(); double falseEdgeProb = next2->getNode()->getOutEdge(Edge::Kind_False)->getEdgeProb(); cfg->addEdge(inst->getNode(), br->getTrueTarget(), trueEdgeProb); cfg->addEdge(inst->getNode(), br->getFalseTarget(), falseEdgeProb); irManager->newBranchInst(newjumpmn, br->getTrueTarget(), br->getFalseTarget())->insertAfter(inst); if (methodMarkerOccur) { inst->getNode()->appendInst(irManager->newMethodEndPseudoInst(methodMarker->getMethodDesc())); } prev->unlink(); inst->unlink(); cfg->purgeUnreachableNodes(); } else { irManager->newBranchInst(newjumpmn, br->getTrueTarget(), br->getFalseTarget())->insertAfter(next2); prev->unlink(); inst->unlink(); next->unlink(); next2->unlink(); } return Changed_Node; }// endif opndNotUsed } } } return Changed_Nothing; }
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); } } }