Ejemplo n.º 1
0
void IpfCfgCodeSelector::genSwitchEdges(U_32  tailNodeId, 
                                        U_32  numTargets, 
                                        U_32 *targets, 
                                        double *probs, 
                                        U_32  defaultTarget) {

    BbNode         *tailNode       = (BbNode *)nodes[tailNodeId];
    InstVector     &insts          = tailNode->getInsts();
    Inst           *switchInst     = insts.back();
    Opnd           *defTargetImm   =                   switchInst->getOpnd(POS_SWITCH_DEFAULT);
    ConstantRef    *constantRef    = (ConstantRef *)   switchInst->getOpnd(POS_SWITCH_TABLE);
    SwitchConstant *switchConstant = (SwitchConstant *)constantRef->getConstant();
    Edge           *defedge        = NULL;
    Edge           *edge           = NULL;

    bool   defadded = false;
    U_32 i        = 0;

    IPF_LOG << "    Generate Switch     tailNodeId=" << tailNodeId 
        << "; defaultTarget=" << defaultTarget << endl;

    defedge = new(mm) Edge(nodes[tailNodeId], nodes[defaultTarget], probs[defaultTarget], EDGE_BRANCH);
    defedge->insert();

    for(i=0; i<numTargets; i++) {
        if(targets[i] == defaultTarget) {
            defTargetImm->setValue(i);
            switchConstant->addEdge(defedge);
            defadded = true;
            IPF_LOG << "        default: " << i << endl;
            continue;
        }
        IPF_LOG << "        case " << i << ": " << targets[i] << endl;
        edge = new(mm) Edge(nodes[tailNodeId], nodes[targets[i]], probs[i], EDGE_BRANCH);
        edge->insert();
        switchConstant->addEdge(edge);
    }

    if (!defadded) {
        defTargetImm->setValue(i);
        switchConstant->addEdge(defedge);
        defadded = true;
        IPF_LOG << "        default: " << i << endl;
    }
}
Ejemplo n.º 2
0
Opnd* OpndUtils::findImmediateSource(Opnd* opnd) 
{
    Opnd* res = opnd;
    while (!res->isPlacedIn(OpndKind_Imm)) {
        Inst* defInst = res->getDefiningInst();
        if (!defInst || defInst->getMnemonic()!=Mnemonic_MOV) {
            return NULL;
        }
        res = defInst->getOpnd(1);
    }
    return res;
}
Ejemplo n.º 3
0
//_________________________________________________________________________________________________
void DCE::runImpl()
{
    bool early = false;
    getArg("early", early);
    if (early && !irManager->getCGFlags()->earlyDCEOn) {
        return;
    }

    irManager->updateLivenessInfo();
    irManager->calculateOpndStatistics();
    BitSet ls(irManager->getMemoryManager(), irManager->getOpndCount());
    const Nodes& nodes = irManager->getFlowGraph()->getNodesPostOrder();

#ifdef ORDER

    MemoryManager mm("dce_parents");

    U_32 opndCount = irManager->getOpndCount();
    bool * isParentOpnd = new(mm) bool [opndCount];
    memset(isParentOpnd, 0, sizeof(bool) * opndCount);
    for (Nodes::const_iterator it = nodes.begin(),end = nodes.end(); it!=end; ++it) {
        Node* node = *it;
        for (Inst * inst=(Inst*)node->getLastInst(); inst!=NULL; inst=inst->getPrevInst()) {
            Opnd* load_obj = inst->getParentObjectLoad();
            if (load_obj)
            {
                isParentOpnd[load_obj->getId()] = true;
            }

            Opnd* store_obj = inst->getParentObjectStore();
            if (store_obj)
            {
                isParentOpnd[store_obj->getId()] = true;
            }

        }
    }
#endif



    for (Nodes::const_iterator it = nodes.begin(),end = nodes.end(); it!=end; ++it) {
        Node* node = *it;
        if (node->isBlockNode()) {
            //Here we'll try to remove redundant branches that could appear after
            //branch translations. All such branches are supposed to be conditional.
            Inst * inst = (Inst *)node->getLastInst();
            if(inst && node->getOutEdges().size() > 1) {
                Edges edges = node->getOutEdges();
                for (Edges::const_iterator ite1 = ++edges.begin(), end = edges.end(); ite1 != end; ++ite1) {
                    for (Edges::const_iterator ite2 = edges.begin(); ite1 != ite2; ++ite2) {
                        Edge *edge1 = *ite1;
                        Edge *edge2 = *ite2;
                        assert(edge1 != edge2);

                        //If this condition is satisfied then there are at least two branches with
                        //the same destination
                        if (edge1->getTargetNode() == edge2->getTargetNode()) {
                            //Check that edges are conditional and the last instruction is branch,
                            //the other situations are not permitted at the moment
                            assert(inst->hasKind(Inst::Kind_BranchInst));
                            assert(edge1->getKind() == Edge::Kind_True ||
                                   edge1->getKind() == Edge::Kind_False);
                            assert(edge2->getKind() == Edge::Kind_True ||
                                   edge2->getKind() == Edge::Kind_False);

                            //Remove last instruction if it is a branch
                            inst->unlink();
                            irManager->getFlowGraph()->removeEdge(edge2);
                        }

                    }
                }
            }

            irManager->getLiveAtExit(node, ls);
            for (Inst * inst=(Inst*)node->getLastInst(), * prevInst=NULL; inst!=NULL; inst=prevInst) {
                prevInst=inst->getPrevInst();
                // Prevent debug traps or instructions with side effects
                // like (MOVS) from being removed.
                bool deadInst=!inst->hasSideEffect() && (inst->getMnemonic() != Mnemonic_INT3);

#ifdef ORDER //yzm
                for (unsigned int i = 0 ; i < inst->getOpndCount() ; i ++)
                {
                    Opnd* opnd = inst->getOpnd(i);
                    if (isParentOpnd[opnd->getId()])
                        deadInst = false;
                }
#endif

                if (deadInst) {
                    if (inst->hasKind(Inst::Kind_CopyPseudoInst)) {
                        Opnd * opnd=inst->getOpnd(1);
                        if (opnd->getType()->isFP() && opnd->getDefiningInst()!=NULL && opnd->getDefiningInst()->getMnemonic()==Mnemonic_CALL) {
                            deadInst=false;
                        }
                    }
                    if (deadInst) {
                        Inst::Opnds opnds(inst, Inst::OpndRole_All);
                        for (Inst::Opnds::iterator ito = opnds.begin(); ito != opnds.end(); ito = opnds.next(ito)) {
                            Opnd * opnd = inst->getOpnd(ito);
                            if ((ls.getBit(opnd->getId()) && (inst->getOpndRoles(ito) & Inst::OpndRole_Def)) ||
                                    (((opnd->getMemOpndKind()&(MemOpndKind_Heap|MemOpndKind_StackManualLayout))!=0) && (inst->getMnemonic() != Mnemonic_LEA))) {
                                deadInst=false;
                                break;
                            }
                        }
                    }
                }
                if (deadInst) {
                    inst->unlink();
                } else {
                    irManager->updateLiveness(inst, ls);
                }
            }
            irManager->getLiveAtEntry(node)->copyFrom(ls);
        }
    }

    irManager->eliminateSameOpndMoves();

    irManager->getFlowGraph()->purgeEmptyNodes();
    irManager->getFlowGraph()->mergeAdjacentNodes(true, false);
    irManager->getFlowGraph()->purgeUnreachableNodes();

    irManager->packOpnds();
    irManager->invalidateLivenessInfo();
}
//___________________________________________________________________________________________________
void EarlyPropagation::runImpl()
{ 
        irManager->updateLoopInfo();
        U_32 opndCount=irManager->getOpndCount();

        MemoryManager mm("early_prop");
        OpndInfo * opndInfos = new(mm) OpndInfo[opndCount];
        Node * currentLoopHeader = NULL;

        bool anyInstHandled=false;

        LoopTree* lt = irManager->getFlowGraph()->getLoopTree();
        const Nodes& postOrdered = irManager->getFlowGraph()->getNodesPostOrder();
        for (Nodes::const_reverse_iterator it = postOrdered.rbegin(), end = postOrdered.rend(); it!=end; ++it) {
            Node * node=*it;
            if (!node->isBlockNode())  {
                continue;
            }
            Node * loopHeader = lt->getLoopHeader(node, false);
            if (currentLoopHeader != loopHeader){
                currentLoopHeader = loopHeader;
                for (U_32 i = 0; i < opndCount; ++i)
                    if (opndInfos[i].sourceOpndId != EmptyUint32)
                        opndInfos[i].defCount++;
            }

            for (Inst * inst = (Inst*)node->getFirstInst(); inst != NULL; inst=inst->getNextInst()){
                bool assignedOpndPropagated = false;
                Inst::Opnds opnds(inst, Inst::OpndRole_All);
                for (Inst::Opnds::iterator it = opnds.begin(); it != opnds.end(); it = opnds.next(it)){
                    Opnd * opnd=inst->getOpnd(it);
                    U_32 roles=inst->getOpndRoles(it);
                    U_32 opndId = opnd->getId();
                    OpndInfo& opndInfo = opndInfos[opndId];

                    U_32 mask = 0;

                    if (roles & Inst::OpndRole_Def){
                        ++opndInfo.defCount;
                    }else if (roles & Inst::OpndRole_Use){
                        if (opndInfo.sourceOpndId != EmptyUint32){
                            if (opndInfo.sourceOpndDefCountAtCopy < opndInfos[opndInfo.sourceOpndId].defCount)
                                opndInfo.sourceOpndId = EmptyUint32;
                            else{
                                Opnd * srcOpnd = irManager->getOpnd(opndInfo.sourceOpndId);
                                Constraint co = srcOpnd->getConstraint(Opnd::ConstraintKind_Location);
                                if (co.getKind() == OpndKind_Mem){
                                    mask = (1<<it)-1;
                                    if ((roles & Inst::OpndRole_Explicit) == 0 ||
                                        inst->hasKind(Inst::Kind_PseudoInst) || irManager->isGCSafePoint(inst) ||
                                        opndInfo.sourceInst != inst->getPrevInst() || assignedOpndPropagated ||
                                    (inst->getConstraint(it, mask, co.getSize())&co).isNull()
                                    )
                                        opndInfo.sourceOpndId = EmptyUint32;
                                    assignedOpndPropagated = true;
                                }
                            }
                        }
                    }
                    if (opndInfo.defCount > 1){
                        opndInfo.sourceOpndId = EmptyUint32;
                    }
                }
                /*
                Here is the previous version to test whether the inst is copy or not.
                bool isCopy = inst->getMnemonic() == Mnemonic_MOV ||(
                        (inst->getMnemonic() == Mnemonic_ADD || inst->getMnemonic() == Mnemonic_SUB) && 
                        inst->getOpnd(3)->isPlacedIn(OpndKind_Imm) && inst->getOpnd(3)->getImmValue()==0
                        && inst->getOpnd(3)->getRuntimeInfo()==NULL
                    );
                It considered special case of 'dst = src +/- 0' as copy. 
                In fact there are more similar cases like 'IMUL src, 1 ; shift src, 0' etc.
                Such checks are obsolete now, Should as peephole takes care about such copies.

                Anyway, the code above had a bug: 'inst->getOpnd(3)' crashes in instructions 
                in native form (like ADD def_use, use).
                */
                const bool isCopy = inst->getMnemonic() == Mnemonic_MOV;

                if (isCopy){ // CopyPseudoInst or mov
                    Opnd * defOpnd = inst->getOpnd(0);
                    Opnd * srcOpnd = inst->getOpnd(1);
                    U_32 defOpndId = defOpnd->getId();
                    OpndInfo * opndInfo = opndInfos + defOpndId;
                    bool instHandled=false;
                    bool typeConvOk = isTypeConversionAllowed(srcOpnd, defOpnd);
                    if (typeConvOk && opndInfo->defCount == 1 && ! srcOpnd->isPlacedIn(OpndKind_Reg)){
                        if (!defOpnd->hasAssignedPhysicalLocation()){
                            opndInfo->sourceInst = inst;
                            opndInfo->sourceOpndId = srcOpnd->getId();
                            instHandled=true;
                        }
                    }
                    if (instHandled){
                        if (opndInfos[opndInfo->sourceOpndId].sourceOpndId != EmptyUint32)
                            opndInfo->sourceOpndId = opndInfos[opndInfo->sourceOpndId].sourceOpndId;
                        opndInfo->sourceOpndDefCountAtCopy = opndInfos[opndInfo->sourceOpndId].defCount;
                        anyInstHandled=true;
                    }
                }
            }
        }

        if (anyInstHandled){
            Opnd ** replacements = new(mm) Opnd* [opndCount];
            memset(replacements, 0, sizeof(Opnd*) * opndCount);
            bool hasReplacements = false;
            for (U_32 i = 0; i < opndCount; ++i){
                if (opndInfos[i].sourceOpndId != EmptyUint32){
                    Inst * inst = opndInfos[i].sourceInst;
                    if (inst !=NULL){
                        inst->unlink();
                    }
                    if (opndInfos[i].sourceOpndId != i){
                        Opnd* origOpnd= irManager->getOpnd(i);
                        Opnd* replacementOpnd = irManager->getOpnd(opndInfos[i].sourceOpndId);
                        assert(isTypeConversionAllowed(replacementOpnd, origOpnd));
                        if (origOpnd->getType()->isUnmanagedPtr() && replacementOpnd->getType()->isInteger()) {
                            replacementOpnd->setType(origOpnd->getType());
                        }/* else if (origOpnd->getType()->isObject() && replacementOpnd->getType()->isUnmanagedPtr()) {
                            replacementOpnd->setType(origOpnd->getType());
                        }*/
                        replacements[i] = replacementOpnd;
                        hasReplacements = true;
                    }
                }
            }

            if (hasReplacements){
                const Nodes& postOrdered = irManager->getFlowGraph()->getNodesPostOrder();
                for (Nodes::const_reverse_iterator it = postOrdered.rbegin(), end = postOrdered.rend(); it!=end; ++it) {
                    Node * node=*it;
                    if (!node->isBlockNode())  {
                        continue;
                    }
                    for (Inst * inst = (Inst*)node->getFirstInst(); inst != NULL; inst=inst->getNextInst()){
                        inst->replaceOpnds(replacements);
                    }   
                }
            }
        }
}
Ejemplo n.º 5
0
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;
}
Ejemplo n.º 6
0
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;
}