Example #1
0
bool Opnd::isImm(int size) {

    if (isImm() == false) return false;
    
    Opnd* imm = (Opnd*) this;
    if (Opnd::isFoldableImm(imm->getValue(), size)) return true;
    return false;
}
PeepHoleOpt::Changed PeepHoleOpt::handleInst_CMP(Inst* inst) {
    assert(inst->getMnemonic()==Mnemonic_CMP);
    
    Inst::Opnds uses(inst, Inst::OpndRole_Explicit | Inst::OpndRole_Use);
    Opnd* src1 = inst->getOpnd(uses.begin());
    Opnd* src2 = inst->getOpnd(uses.next(uses.begin()));
    assert(src1!=NULL && src2!=NULL);

    if (isImm(src1)) {
        Opnd* tmp = src1; src1 = src2; src2 = tmp;
    }

    if (isImm(src2) && isReg(src1) && (int)src2->getImmValue() == 0) {
            if (Log::isEnabled()) Log::out()<<"I"<<inst->getId()<<" -> CMP with 0"<<std::endl;
            irManager->newInst(Mnemonic_TEST, src1, src1)->insertAfter(inst);
            inst->unlink();
            return Changed_Inst;
    }
    return Changed_Nothing;
}
Example #3
0
bool OpndUtils::isSingleDef(const Opnd* opnd)
{
    return isImm(opnd) || (opnd->getDefiningInst() != NULL);
}
Example #4
0
bool OpndUtils::isZeroImm(const Opnd* op)
{
    return isImm(op, 0);
}
Example #5
0
bool OpndUtils::fitsImm8(const Opnd* op)
{
    return isImm(op) && 
           (CHAR_MIN <= op->getImmValue() && op->getImmValue() <= CHAR_MAX);
}
Example #6
0
bool OpndUtils::isImm32(const Opnd* op)
{
    return isImm(op) && op->getSize() == OpndSize_32;
}
Example #7
0
bool OpndUtils::isImm(const Opnd* op, int iVal)
{
    return isImm(op) && (op->getImmValue() == iVal);
}
Example #8
0
	const char *Operand::string() const
	{
		static char string[256];

		if(isVoid(type))
		{
			return 0;
		}
		else if(isImm(type))
		{
			if(reference)
			{
				return reference;
			}
			else
			{
				if(value <= 127 && value >= -128)
				{
					snprintf(string, 255, "0x%0.2X", value & 0xFF);
				}
				else if(value <= 32767 && value -32768)
				{
					snprintf(string, 255, "0x%0.4X", value & 0xFFFF);
				}
				else
				{
					snprintf(string, 255, "0x%0.8X", value);
				}
			}
		}
		else if(isReg(type))
		{
			return regName();
		}
		else if(isMem(type))
		{
			switch(type)
			{
			case OPERAND_MEM8:
				snprintf(string, 255, "byte ptr [");
				break;
			case OPERAND_MEM16:
				snprintf(string, 255, "word ptr [");
				break;
			case OPERAND_MEM32:
				snprintf(string, 255, "dword ptr [");
				break;
			case OPERAND_MEM64:
				snprintf(string, 255, "qword ptr [");
				break;
			case OPERAND_MEM128:
				snprintf(string, 255, "xmmword ptr [");
				break;
			case OPERAND_MEM:
			default:
				snprintf(string, 255, "byte ptr [");
			}

			if(baseReg != Encoding::REG_UNKNOWN)
			{
				snprintf(string, 255, "%s%s", string, regName());

				if(indexReg != Encoding::REG_UNKNOWN)
				{
					snprintf(string, 255, "%s+", string);
				}
			}

			if(indexReg != Encoding::REG_UNKNOWN)
			{
				snprintf(string, 255, "%s%s", string, indexName());
			}

			switch(scale)
			{
			case 0:
			case 1:
				break;
			case 2:
				snprintf(string, 255, "%s*2", string);
				break;
			case 4:
				snprintf(string, 255, "%s*4", string);
				break;
			case 8:
				snprintf(string, 255, "%s*8", string);
				break;
			default:
				throw INTERNAL_ERROR;
			}

			if(displacement)
			{
				if(baseReg != Encoding::REG_UNKNOWN ||
				   indexReg != Encoding::REG_UNKNOWN)
				{
					snprintf(string, 255, "%s+", string);
				}

				if(reference)
				{
					snprintf(string, 255, "%s%s", string, reference);
				}
				else
				{
					if(displacement <= 32767 && displacement >= -32768)
					{
						snprintf(string, 255, "%s%d", string, displacement);
					}
					else
					{					
						snprintf(string, 255, "%s0x%0.8X", string, displacement);
					}
				}
			}

			snprintf(string, 255, "%s]", string);
		}
		else
		{
			throw INTERNAL_ERROR;
		}

		return strlwr(string);
	}
Example #9
0
	bool Operand::isImm(const Operand &operand)
	{
		return isImm(operand.type);
	}
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;
}
PeepHoleOpt::Changed PeepHoleOpt::handleInst_ALU(Inst* inst)
{
    // The normal form is 'OPERATION left opnd, right operand'
    // except for NOT operation.
    const Mnemonic mnemonic = inst->getMnemonic();
    if (mnemonic == Mnemonic_NOT) {
        // No optimizations this time
        return Changed_Nothing;
    }
    
    // Only these mnemonics have the majestic name of ALUs.
    assert(mnemonic == Mnemonic_ADD || mnemonic == Mnemonic_SUB ||
           mnemonic == Mnemonic_ADC || mnemonic == Mnemonic_SBB ||
           mnemonic == Mnemonic_OR || mnemonic == Mnemonic_XOR ||
           mnemonic == Mnemonic_AND ||
           mnemonic == Mnemonic_CMP || mnemonic == Mnemonic_TEST);
    
    if (mnemonic == Mnemonic_AND)
    {
        Inst::Opnds defs(inst, Inst::OpndRole_Explicit|Inst::OpndRole_Def);
        Opnd* dst = inst->getOpnd(defs.begin());
        Inst::Opnds uses(inst, Inst::OpndRole_Explicit|Inst::OpndRole_Use);
        Opnd* src1= inst->getOpnd(uses.begin());
        Opnd* src2= inst->getOpnd(uses.next(uses.begin()));

        Opnd *newopnd2;
        // test can work only with operands having equal sizes
        if (isImm(src2) && src2->getSize() != src1->getSize())
            newopnd2 = irManager->newImmOpnd(src1->getType(), src2->getImmValue());
        else
            newopnd2 = src2;
        if (!isMem(dst) && !isMem(src1) && !isMem(src2))
        {
            BitSet ls(irManager->getMemoryManager(), irManager->getOpndCount());
            irManager->updateLivenessInfo();
            irManager->getLiveAtExit(inst->getNode(), ls);
            for (Inst* i = (Inst*)inst->getNode()->getLastInst(); i!=inst; i = i->getPrevInst()) {
                irManager->updateLiveness(i, ls);
            }
            bool dstNotUsed = !ls.getBit(dst->getId());
            if (dstNotUsed)
            {
                // what: AND opnd1, opnd2 => TEST opnd1, opnd2
                // nb: applicable if opnd1 will not be used further
                
                if (inst->getForm() == Inst::Form_Extended)
                    irManager->newInstEx(Mnemonic_TEST, 0, src1, newopnd2)->insertAfter(inst);
                else
                    irManager->newInst(Mnemonic_TEST, src1, newopnd2)->insertAfter(inst);
                inst->unlink();
                return Changed_Inst;
            }
        }
    } else if (mnemonic == Mnemonic_ADD) {
        /* Change "dst=src+0" to "MOV dst, src" if there is another ADD inst followed in the same BB. */
        Inst::Opnds defs(inst, Inst::OpndRole_Explicit|Inst::OpndRole_Def);
        Opnd* dst = inst->getOpnd(defs.begin());
        Inst::Opnds uses(inst, Inst::OpndRole_Explicit|Inst::OpndRole_Use);
        Opnd* src1= inst->getOpnd(uses.begin());
        Opnd* src2= inst->getOpnd(uses.next(uses.begin()));

        bool src1IsZero = false;
        bool src2IsZero = false;
        if (src1->isPlacedIn(OpndKind_Imm) && (src1->getImmValue() == 0))
            src1IsZero = true;
        if (src2->isPlacedIn(OpndKind_Imm) && (src2->getImmValue() == 0))
            src2IsZero = true;

        bool anotherADD = false;
        Inst *iter = inst->getNextInst();
        while (iter != NULL) {
            if (iter->getMnemonic() == Mnemonic_ADC)
                break;
            if (iter->getMnemonic() == Mnemonic_ADD) {
                anotherADD = true;
                break;
            }
            iter = iter->getNextInst();;
        }

        if (anotherADD) {
            if (src1IsZero) {
                irManager->newCopyPseudoInst(Mnemonic_MOV, dst, src2)->insertAfter(inst);
                inst->unlink();
                return Changed_Inst;
            } else if (src2IsZero) {
                irManager->newCopyPseudoInst(Mnemonic_MOV, dst, src1)->insertAfter(inst);
                inst->unlink();
                return Changed_Inst;
            }
        }
    }
    return Changed_Nothing;
}
PeepHoleOpt::Changed PeepHoleOpt::handleInst_MUL(Inst* inst) {
    assert((inst->getMnemonic() == Mnemonic_IMUL) || (inst->getMnemonic() == Mnemonic_MUL));
    
    if (inst->getForm() == Inst::Form_Native) {
        return Changed_Nothing;
    }
    
    Inst::Opnds defs(inst, Inst::OpndRole_Explicit|Inst::OpndRole_Def);
    Opnd* dst1 = inst->getOpnd(defs.begin());
    Opnd* dst2 = NULL;
    if ((inst->getMnemonic() == Mnemonic_IMUL) && (defs.next(defs.begin()) != defs.end())){
        return Changed_Nothing;
    }
    else { //inst->getMnemonic() == Mnemonic_MUL
        dst2 = inst->getOpnd(defs.next(defs.begin()));
        if (defs.next(defs.next(defs.begin()))!=defs.end())
            return Changed_Nothing;
    }

    Inst::Opnds uses(inst, Inst::OpndRole_Explicit|Inst::OpndRole_Use);
    Opnd* src1= inst->getOpnd(uses.begin());
    Opnd* src2= inst->getOpnd(uses.next(uses.begin()));
    if (inst->getMnemonic() == Mnemonic_IMUL)
        assert(src1!=NULL && src2!=NULL && dst1!=NULL);
    else //inst->getMnemonic() == Mnemonic_MUL
        assert(src1!=NULL && src2!=NULL && dst1!=NULL && dst2!=NULL);

    if (isImm(src1)) {
        Opnd* tmp = src1; src1 = src2; src2 = tmp;
    }
    if (isImm(src2) && irManager->getTypeSize(src2->getType()) <=32) {
        int immVal = (int)src2->getImmValue();
        if (immVal == 0) {
            if (Log::isEnabled()) Log::out()<<"I"<<inst->getId()<<" -> MUL with 0"<<std::endl;
            if (inst->getMnemonic() == Mnemonic_IMUL) {
                irManager->newCopyPseudoInst(Mnemonic_MOV, dst1, src2)->insertAfter(inst);
            } else { //inst->getMnemonic() == Mnemonic_MUL
                irManager->newCopyPseudoInst(Mnemonic_MOV, dst1, src2)->insertAfter(inst);
                irManager->newCopyPseudoInst(Mnemonic_MOV, dst2, src2)->insertAfter(inst);
            }
            inst->unlink();
            return Changed_Inst;
        } else if (immVal == 1) {
            if (Log::isEnabled()) Log::out()<<"I"<<inst->getId()<<" -> MUL with 1"<<std::endl;
            if (inst->getMnemonic() == Mnemonic_IMUL) {
                irManager->newCopyPseudoInst(Mnemonic_MOV, dst1, src1)->insertAfter(inst);
            } else { //inst->getMnemonic() == Mnemonic_MUL
                Opnd* zero = irManager->newImmOpnd(dst1->getType(), 0);
                irManager->newCopyPseudoInst(Mnemonic_MOV, dst1, zero)->insertAfter(inst);
                irManager->newCopyPseudoInst(Mnemonic_MOV, dst2, src1)->insertAfter(inst);
            }
            inst->unlink();
            return Changed_Inst;
        } else if (immVal == 2) {
            if (inst->getMnemonic() == Mnemonic_IMUL) {
                if (Log::isEnabled()) Log::out()<<"I"<<inst->getId()<<" -> MUL with 2"<<std::endl;
                irManager->newInstEx(Mnemonic_ADD, 1, dst1, src1, src1)->insertAfter(inst);
                inst->unlink();
                return Changed_Inst;
            }
        } else {
            if (inst->getMnemonic() == Mnemonic_IMUL) {
                int minBit=getMinBit(immVal);   
                int maxBit=getMaxBit(immVal);
                if (minBit == maxBit) {
                     assert(minBit>=2);
                     if (Log::isEnabled()) Log::out()<<"I"<<inst->getId()<<" -> MUL with 2^"<<minBit<<std::endl;
                     Type* immType = irManager->getTypeManager().getUInt8Type();
                     irManager->newCopyPseudoInst(Mnemonic_MOV, dst1, src1)->insertBefore(inst);
                     irManager->newInst(Mnemonic_SHL, dst1, irManager->newImmOpnd(immType, minBit))->insertBefore(inst);
                     inst->unlink();
                     return Changed_Inst;
                 }
             }
          }
      }
      return Changed_Nothing;
}
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;
}