void CfgCodeSelector::genUnconditionalEdge(U_32 tailNodeId,U_32 headNodeId, double prob) { Node * tailNode = nodes[tailNodeId]; Node * headNode = nodes[headNodeId]; assert(tailNode->isBlockNode()); assert(headNode->isBlockNode() || headNode == irManager.getFlowGraph()->getExitNode()); Inst* lastInst = (Inst*)tailNode->getLastInst(); if (lastInst!=NULL && lastInst->hasKind(Inst::Kind_BranchInst)) { BranchInst* br = (BranchInst*)lastInst; assert(br->getTrueTarget() != NULL); assert(br->getFalseTarget() == NULL); br->setFalseTarget(headNode); } irManager.getFlowGraph()->addEdge(tailNode, headNode, prob); }
void CfgCodeSelector::fixNodeInfo() { MemoryManager tmpMM("Ia32CS:fixNodeInfoMM"); ControlFlowGraph* fg = irManager.getFlowGraph(); Nodes nodes(tmpMM); fg->getNodes(nodes); //copy nodes -> loop creates new ones, so we can't use reference to cfg->getNodes() for (Nodes::const_iterator it = nodes.begin(), end = nodes.end(); it!=end; ++it) { Node* node = *it; // connect throw nodes added during inst code selection to corresponding dispatch or unwind nodes if (node->isBlockNode()){ Inst * lastInst = (Inst*)node->getLastInst(); if (lastInst) { Inst * prevInst = lastInst->getPrevInst(); if(prevInst && prevInst->getKind() == Inst::Kind_BranchInst) { Edge * ftEdge = node->getFalseEdge(); Edge * dbEdge = node->getTrueEdge(); assert(ftEdge && dbEdge); Node* newBB = fg->createBlockNode(); Node* nextFT = ftEdge->getTargetNode(); Node* nextDB = dbEdge->getTargetNode(); fg->removeEdge(ftEdge); fg->removeEdge(dbEdge); newBB->appendInst(irManager.newBranchInst(lastInst->getMnemonic(), nextDB, nextFT)); lastInst->unlink(); //now fix prev branch successors BranchInst* prevBranch = (BranchInst*)prevInst; assert(prevBranch->getTrueTarget() == NULL && prevBranch->getFalseTarget() == NULL); prevBranch->setTrueTarget(lastInst->getMnemonic() == Mnemonic_JZ? nextFT : nextDB); prevBranch->setFalseTarget(newBB); fg->addEdge(node, lastInst->getMnemonic() == Mnemonic_JZ? nextFT : nextDB, 0); fg->addEdge(node, newBB, 0); fg->addEdge(newBB, nextDB, 0); fg->addEdge(newBB, nextFT, 0); } } if (node->getOutDegree() == 0){ // throw node assert(node->getInDegree()==1); Node* bbIn = node->getInEdges().front()->getSourceNode(); assert(bbIn!=NULL); Node * target=bbIn->getExceptionEdgeTarget(); assert(target!=NULL); fg->addEdge(node, target, 1.0); } // fixup empty catch blocks otherwise respective catchEdges will be lost // There is no [catchBlock]-->[catchHandler] edge. Catch block will be removed // as an empty one and exception handling will be incorrect if (node->isCatchBlock() && node->isEmpty()) { assert(node->getInDegree()==1); Edge* catchEdge = node->getInEdges().front(); assert(catchEdge->getSourceNode()->isDispatchNode()); assert(node->getOutDegree()==1); Node* succ = node->getUnconditionalEdgeTarget(); while( succ->isEmpty() && (succ->getOutDegree() == 1) ) { succ = succ->getUnconditionalEdgeTarget(); } assert(succ && ((Inst*)succ->getFirstInst())->hasKind(Inst::Kind_CatchPseudoInst)); fg->replaceEdgeTarget(catchEdge,succ,true/*keepOldBody*/); } } } }
/** * The algorithm finds conditional instruction (=condInst) first, then * corresponding CMP instruction (=cmpInst) and arithmetic instruction (=inst) * which affects flags in the same way as CMP. Combination is considered as * available to be reduced if there are no instructions between CMP and * arithmetic instruction which influence to flags or CMP operands. * * Also it transforms some conditional instruction to make them more suitable * for optimizations */ void RCE::runImpl() { Inst * inst, * cmpInst, *condInst; Opnd * cmpOp = NULL; cmpInst = condInst = NULL; const Nodes& nodes = irManager->getFlowGraph()->getNodesPostOrder(); for (Nodes::const_iterator it = nodes.begin(), end = nodes.end(); it!=end; ++it) { Node* node = *it; if (node->isBlockNode()) { if(node->isEmpty()) { continue; } cmpInst = NULL; Inst* prevInst = NULL; for(inst = (Inst*)node->getLastInst(); inst != NULL; inst = prevInst) { prevInst = inst->getPrevInst(); //find conditional instruction Mnemonic baseMnem = getBaseConditionMnemonic(inst->getMnemonic()); if (baseMnem != Mnemonic_NULL) { condInst = condInst ? NULL : inst; cmpInst = NULL; } else if (condInst) { //find CMP instruction corresponds to conditional instruction if(inst->getMnemonic() == Mnemonic_CMP || inst->getMnemonic() == Mnemonic_UCOMISD || inst->getMnemonic() == Mnemonic_UCOMISS) { if (cmpInst) { //this comparison is redundant because of overrided by cmpInst inst->unlink(); continue; } cmpInst = inst; U_32 defCount = inst->getOpndCount(Inst::OpndRole_InstLevel|Inst::OpndRole_Def); if(inst->getOpnd(defCount+1)->isPlacedIn(OpndKind_Imm)) { //try to change conditional instruction to make combination available to optimize cmpOp = inst->getOpnd(defCount); Inst * newCondInst = NULL; Mnemonic mnem; int64 val = inst->getOpnd(defCount+1)->getImmValue(); if (val == 0) { continue; } else if (val == 1 && ConditionMnemonic(condInst->getMnemonic()-getBaseConditionMnemonic(condInst->getMnemonic())) == ConditionMnemonic_L){ mnem = Mnemonic((condInst->getMnemonic() - Mnemonic(ConditionMnemonic_L)) + Mnemonic(ConditionMnemonic_LE)); } else if (val == -1 && ConditionMnemonic(condInst->getMnemonic()-getBaseConditionMnemonic(condInst->getMnemonic())) == ConditionMnemonic_G) { mnem = Mnemonic((condInst->getMnemonic() - Mnemonic(ConditionMnemonic_G)) + Mnemonic(ConditionMnemonic_GE)); } else if (val == -1 && ConditionMnemonic(condInst->getMnemonic()-getBaseConditionMnemonic(condInst->getMnemonic())) == ConditionMnemonic_B) { mnem = Mnemonic((condInst->getMnemonic() - Mnemonic(ConditionMnemonic_B)) + Mnemonic(ConditionMnemonic_BE)); } else { continue; } //replace old conditional instruction if (condInst->hasKind(Inst::Kind_BranchInst)) { BranchInst* br = (BranchInst*)condInst; newCondInst = irManager->newBranchInst(mnem,br->getTrueTarget(), br->getFalseTarget(), condInst->getOpnd(0)); } else { Mnemonic condMnem = getBaseConditionMnemonic(condInst->getMnemonic()); Inst::Opnds defs(condInst,Inst::OpndRole_Def|Inst::OpndRole_Explicit); if (condMnem == Mnemonic_CMOVcc) { Inst::Opnds uses(condInst,Inst::OpndRole_Use|Inst::OpndRole_Explicit); newCondInst = irManager->newInst(mnem, condInst->getOpnd(defs.begin()), inst->getOpnd(uses.begin())); } else if (condMnem == Mnemonic_SETcc) { newCondInst = irManager->newInst(mnem, condInst->getOpnd(defs.begin())); } else { assert(0); continue; } } newCondInst->insertAfter(condInst); condInst->unlink(); condInst = newCondInst; inst->setOpnd(defCount+1, irManager->newImmOpnd(inst->getOpnd(defCount+1)->getType(),0)); } //find flags affected instruction precedes cmpInst } else if (instAffectsFlagsAsCmpInst(inst, condInst)) { if (cmpInst) { if (isSuitableToRemove(inst, condInst, cmpInst, cmpOp)) { cmpInst->unlink(); } } condInst = NULL; // do not optimize cmpInst any more in this block } else { if (inst->getOpndCount(Inst::OpndRole_Implicit|Inst::OpndRole_Def) || inst->getMnemonic() == Mnemonic_CALL) { // instruction affects flags, skip optimizing cmpInst condInst = NULL; } else { //check for moving cmpInst operands if ((inst->getMnemonic() == Mnemonic_MOV) && (inst->getOpnd(0) == cmpOp)) { cmpOp = inst->getOpnd(1); } } } }//end if/else by condInst }//end for() by Insts }//end if BasicBlock }//end for() by Nodes }
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; }