void I586InstsExpansion::lowerToX87()

in vm/jitrino/src/codegenerator/ia32/Ia32i586InstsExpansion.cpp [188:656]


void I586InstsExpansion::lowerToX87() {
    //check if to use FPU mode. Otherwise SSE1 insts will be allowed
    irManager->updateLivenessInfo();
    hasSideEffects = true;

    //create stack memory operands for storing values of XMM registers
    StlMap<unsigned, Opnd *> xmmMemOp32Map(irManager->getMemoryManager());
    StlMap<unsigned, Opnd *> xmmMemOp64Map(irManager->getMemoryManager());
    for (unsigned i = 0; i< 16; i++) {
        xmmMemOp32Map[i] = NULL;
        xmmMemOp64Map[i] = NULL;
    }
    StlMap<unsigned, Opnd *> * xmmMemOpsPtr = &xmmMemOp64Map;

    //create FP registers operands with corresponding size
    Opnd * fp0Op32 = irManager->newOpnd(irManager->getTypeManager().getSingleType(), RegName_FP0S);
    fp0Op32->assignRegName(RegName_FP0S);
    Opnd * fp0Op64 = irManager->newOpnd(irManager->getTypeManager().getDoubleType(), RegName_FP0D);
    fp0Op64->assignRegName(RegName_FP0D);
    Opnd * fp1Op32 = irManager->newOpnd(irManager->getTypeManager().getSingleType(), RegName_FP1S);
    fp1Op32->assignRegName(RegName_FP1S);
    Opnd * fp1Op64 = irManager->newOpnd(irManager->getTypeManager().getDoubleType(), RegName_FP1D);
    fp1Op64->assignRegName(RegName_FP1D);
    
    const Nodes& nodes = irManager->getFlowGraph()->getNodes();
    for (Nodes::const_iterator cit = nodes.begin(); cit != nodes.end(); ++cit) {
        Node* node = *cit;
        if (!node->isBlockNode()) {
            continue;
        }
        for(Inst * inst = (Inst *)node->getFirstInst(); inst != NULL; ) {
            Inst * tmpInst = inst->getNextInst();
            Mnemonic mn = inst->getMnemonic();
            
            Mnemonic fMnem1 = Mnemonic_NULL, fMnem2 = Mnemonic_NULL;
            if (!isSSEOrNewer(mn)) {
                //check all other instruction for XMM registers operands
                Inst::Opnds xmms(inst, Inst::OpndRole_Explicit|Inst::OpndRole_UseDef);
                for (Inst::Opnds::iterator it = xmms.begin(); it != xmms.end(); it = xmms.next(it)) {
                    Opnd * op = inst->getOpnd(it);
                    if (op->isPlacedIn(OpndKind_XMMReg)) {
                        std::string str = std::string("SSE instruction found: ") + Encoder::getMnemonicString(mn);
                        Jitrino::crash(str.c_str());
                    }
                }
                inst = tmpInst;
                continue;
            }

            mapToX87(mn, fMnem1, fMnem2);


            Opnd * fp0;
            Opnd * fp1;

            //number of registers in instruction
            unsigned regNum1 = 0;

            //XMM-suspected operands
            Inst::Opnds xmms(inst, Inst::OpndRole_Explicit|Inst::OpndRole_UseDef);
            Opnd * op1 = inst->getOpnd(xmms.begin());
            Opnd * op2 = inst->getOpnd(xmms.begin()+1);

            //choose operands size
            if (op2->getSize() == OpndSize_64) {
                fp0 = fp0Op64;
                fp1 = fp1Op64;
                xmmMemOpsPtr = &xmmMemOp64Map;
            } else {
                fp0 = fp0Op32;
                fp1 = fp1Op32;
                xmmMemOpsPtr = &xmmMemOp32Map;
            }

            switch (mn) {
                case Mnemonic_XORPD:
                case Mnemonic_XORPS:
                case Mnemonic_PXOR:
                {
                    //Packed XOR is used only for loading of zero into a XMM register
                    //replace: XORPD xmm2, xmm2     ->      FLDZ fp0
                    //                                      FSTP [xmm2_Mem] 
                    if (op1 == op2) {
                        RegName reg = op1->getRegName();
                        unsigned regNum = (unsigned)reg & 0xF;
                        
                        //create memory operand for the XMM register if it doesn't exist
                        if (!(*xmmMemOpsPtr)[regNum]  || (*xmmMemOpsPtr)[regNum]->getSize() != op1->getSize()) {
                            Opnd* opnd = irManager->newMemOpnd(fp0->getType(), MemOpndKind_StackAutoLayout, irManager->getRegOpnd(STACK_REG), 0);
                            opnd->setMemOpndAlignment(Opnd::MemOpndAlignment_16);
                            (*xmmMemOpsPtr)[regNum] = opnd; 
                        }
                        
                        //load zero
                        node->prependInst(irManager->newInst(Mnemonic_FLDZ, fp0),inst);
                        
                        //store zero and pop FPU stack
                        node->prependInst(irManager->newInst(Mnemonic_FSTP, (*xmmMemOpsPtr)[regNum], fp0), inst);
                    } else {
                        assert(0);
                    }
                    break;
                }
                case Mnemonic_ADDSS:
                case Mnemonic_ADDSD:
                case Mnemonic_SUBSS:
                case Mnemonic_SUBSD:
                case Mnemonic_MULSS:
                case Mnemonic_MULSD:
                case Mnemonic_DIVSS:
                case Mnemonic_DIVSD:
                {
                    //replace: ADDSS xmm1, xmm2 (op2) ->    FLD     fp0, [xmm1_Mem]
                    //                                      FLD     fp0, [xmm2_Mem]     ;also move previous fp0 value to fp1)
                    //                                      FADDP   fp0, fp1            (FADD   fp0, op2)
                    //                                      FSTP    [xmm1_Mem] 
                    
                    //push first operand on stack
                    if (op1->isPlacedIn(OpndKind_XMMReg)) {
                        RegName reg1 = op1->getRegName();
                        regNum1 = (unsigned)reg1 & 0xF;
                        assert((*xmmMemOpsPtr)[regNum1]);
                        node->prependInst(irManager->newInst(Mnemonic_FLD, fp0, (*xmmMemOpsPtr)[regNum1]),inst);
                    } else {
                        assert(0);
                    }

                    //push second operand on FPU stack if it is an XMM register
                    if (op2->isPlacedIn(OpndKind_XMMReg)) {
                        RegName reg2 = op2->getRegName();
                        unsigned regNum2 = (unsigned)reg2 & 0xF;
                        assert((*xmmMemOpsPtr)[regNum2]);
                        node->prependInst(irManager->newInst(Mnemonic_FLD, fp0, (*xmmMemOpsPtr)[regNum2]),inst);
                      
                        //do the operation and pop FPU stack  
                        node->prependInst(irManager->newInst(fMnem1, fp0, fp1),inst);
                    } else {
                        //do the operation
                        node->prependInst(irManager->newInst(fMnem2, fp0, op2),inst);
                    }
                    
                    //store result and pop FPU stack
                    node->prependInst(irManager->newInst(Mnemonic_FSTP, (*xmmMemOpsPtr)[regNum1], fp0),inst);
                    break;
                }
                case Mnemonic_MOVQ:
                case Mnemonic_MOVD:
                case Mnemonic_MOVSD:
                case Mnemonic_MOVSS:
                {
                    if (op1->isPlacedIn(OpndKind_XMMReg)) {
                        RegName reg1 = op1->getRegName();
                        regNum1 = (unsigned)reg1 & 0xF;
                        
                        //create memory operand for the destination XMM register if it doesn't exist
                        if (!(*xmmMemOpsPtr)[regNum1] || (*xmmMemOpsPtr)[regNum1]->getSize() != op1->getSize()) {
                            (*xmmMemOpsPtr)[regNum1] = irManager->newMemOpnd(fp0->getType(), MemOpndKind_StackAutoLayout, irManager->getRegOpnd(STACK_REG), 0);
                        }

                        //store value to XMM-memory slot and pop FPU stack
                        node->appendInst(irManager->newInst(Mnemonic_FSTP, (*xmmMemOpsPtr)[regNum1], fp0),inst);
                    } else {
                        //store value to memory and pop FPU stack
                        node->appendInst(irManager->newInst(Mnemonic_FSTP, op1, fp0),inst);
                    }
                    if (op2->isPlacedIn(OpndKind_XMMReg)) {
                        RegName reg2 = op2->getRegName();
                        unsigned regNum2 = (unsigned)reg2 & 0xF;
                        assert((*xmmMemOpsPtr)[regNum2]);
                        
                        //load value from XMM-memory slot onto FPU stack
                        node->prependInst(irManager->newInst(Mnemonic_FLD, fp0, (*xmmMemOpsPtr)[regNum2]),inst);
                    } else {
                        //load value from memory onto FPU stack
                        node->prependInst(irManager->newInst(Mnemonic_FLD, fp0, op2),inst);
                    }
                    break;
                }
                case Mnemonic_CVTTSS2SI:
                case Mnemonic_CVTTSD2SI:
                {

                    //replace: CVTTSS2SI ebx, xmm2  ->  FNSTCW  [fpucw]
                    //                                  FNSTCW  [tmpcw]
                    //                                  OR      [fpucw], ROUND_FLAG
                    //                                  FLDCW   [fpucw]
                    //                                  FLD     fp0, [xmm2_Mem]
                    //                                  FISTP   [cMemOp], fp0
                    //                                  MOV     ebx, [cMemOp]
                    //                                  FLDCW   [tmpcw]
                    
                    
                    //set rounding mode to "round to zero" before operation and and restore old value after operation
                    Opnd * fpucw = irManager->newMemOpnd(irManager->getTypeManager().getInt16Type(), 
                                                            MemOpndKind_StackAutoLayout,  irManager->getRegOpnd(STACK_REG), 0);
                    Opnd * tmpcw = irManager->newMemOpnd(irManager->getTypeManager().getInt16Type(), 
                                                            MemOpndKind_StackAutoLayout,  irManager->getRegOpnd(STACK_REG), 0);
                    node->prependInst(irManager->newInst(Mnemonic_FNSTCW, fpucw),inst);
                    node->prependInst(irManager->newInst(Mnemonic_FNSTCW, tmpcw),inst);
                    node->prependInst(irManager->newInst(Mnemonic_OR, fpucw, irManager->newImmOpnd(fpucw->getType(), ROUND_FLAG)),inst);
                    node->prependInst(irManager->newInst(Mnemonic_FLDCW, fpucw),inst);
                    node->appendInst(irManager->newInst(Mnemonic_FLDCW, tmpcw),inst);

                    //create the memory slot
                    Opnd * cMemOp = irManager->newMemOpnd(op1->getType(), MemOpndKind_StackAutoLayout, irManager->getRegOpnd(STACK_REG), 0);

                    //move result from the memory slot to destination
                    node->appendInst(irManager->newInst(Mnemonic_MOV, op1, cMemOp),inst);
                    
                    //store the value with truncation to the memory slot and pop FPU stack
                    node->appendInst(irManager->newInst(Mnemonic_FISTP, cMemOp, fp0),inst);
                    
                    if (op2->isPlacedIn(OpndKind_XMMReg)) {
                        RegName reg2 = op2->getRegName();
                        unsigned regNum2 = (unsigned)reg2 & 0xF;
                        assert((*xmmMemOpsPtr)[regNum2]);

                        //load value from XMM-memory slot onto FPU stack
                        node->prependInst(irManager->newInst(Mnemonic_FLD, fp0, (*xmmMemOpsPtr)[regNum2]),inst);
                    } else {
                        //load value from memory onto FPU stack
                        node->prependInst(irManager->newInst(Mnemonic_FLD, fp0, op2),inst);
                    }
                    break;
                }
                case Mnemonic_UCOMISD:
                case Mnemonic_UCOMISS:
                {
                    //replace:  UCOMISD xmm0, xmm2  ->  PUSH    eax
                    //          JP      L1              FLD     fp0, [xmm2_Mem]
                    //          JNA     L2              FLD     fp0, [xmm0_Mem]
                    //                                  FUCOMPP fp0, fp1
                    //                                  FNSTSW  eax
                    //                                  MOV     [cMemOp], eax
                    //                                  POP     eax
                    //                                  AND     [cMemOp], FPU_FLAGS
                    //                                  CMP     [cMemOp], FPU_FLAGS
                    //                                  JZ      L1
                    //                                  AND     [cMemOp], FPU_FLAGS
                    //                                  CMP     [cMemOp], 0
                    //                                  JNZ      L2
                    Inst * nextInst = inst->getNextInst();
                    //find conditional instruction
                    for (; nextInst != NULL ; nextInst = nextInst->getNextInst()) {
                        Mnemonic bm = getBaseConditionMnemonic(nextInst->getMnemonic());
                        if (bm != Mnemonic_Null)
                            break;
                    }
                    assert(nextInst);

                    //save and restore EAX register
                    Opnd * eax = irManager->getRegOpnd(RegName_EAX);
                    node->prependInst(irManager->newInst(Mnemonic_PUSH, eax),inst);
                    node->appendInst(irManager->newInst(Mnemonic_POP, eax),inst);
                    
                    //generate x87 comparison
                    if (op2->isPlacedIn(OpndKind_XMMReg)) {
                        RegName reg2 = op2->getRegName();
                        unsigned regNum2 = (unsigned)reg2 & 0xF;
                        assert((*xmmMemOpsPtr)[regNum2]);
                        node->prependInst(irManager->newInst(Mnemonic_FLD, fp0, (*xmmMemOpsPtr)[regNum2]),inst);
                    } else {
                        node->prependInst(irManager->newInst(Mnemonic_FLD, fp0, op2),inst);
                    }
                    if (op1->isPlacedIn(OpndKind_XMMReg)) {
                        RegName reg1 = op1->getRegName();
                        regNum1 = (unsigned)reg1 & 0xF;
                        assert((*xmmMemOpsPtr)[regNum1]);
                        node->prependInst(irManager->newInst(Mnemonic_FLD, fp0, (*xmmMemOpsPtr)[regNum1]),inst);
                    } else {
                        assert(0);
                    }
                    node->prependInst(irManager->newInst(Mnemonic_FUCOMPP, fp0, fp1),inst);
                    
                    node->prependInst(irManager->newInst(Mnemonic_FNSTSW, eax),inst);
                    
                    //save result from eax to memory
                    Opnd * cMemOp = irManager->newMemOpnd(eax->getType(), MemOpndKind_StackAutoLayout, irManager->getRegOpnd(STACK_REG), 0);
                    node->appendInst(irManager->newInst(Mnemonic_MOV, cMemOp, eax),inst);

                    Inst * parityInst = NULL;
                    Node * trueTarget, * falseTarget;

                    if (nextInst->getKind() == Inst::Kind_BranchInst) {
                        Mnemonic mn = nextInst->getMnemonic();
                        //if the instruction is a check for NaN
                        if (mn == Mnemonic_JP || mn == Mnemonic_JNP) {
                            parityInst = nextInst;
                            trueTarget = ((BranchInst *)parityInst)->getTrueTarget();
                            falseTarget = ((BranchInst *)parityInst)->getFalseTarget();

                            //if NaN then all FPU flags are set
                            node->prependInst(irManager->newInst(Mnemonic_AND, cMemOp, irManager->newImmOpnd(cMemOp->getType(),FPU_FLAGS)),nextInst);
                            node->prependInst(irManager->newInst(Mnemonic_CMP, cMemOp, irManager->newImmOpnd(cMemOp->getType(),FPU_FLAGS)),nextInst);

                            if (mn == Mnemonic_JP) {
                                node->prependInst(irManager->newBranchInst(Mnemonic_JZ, trueTarget, falseTarget),nextInst);
                                nextInst = (Inst *)falseTarget->getLastInst();
                            } else {
                                node->prependInst(irManager->newBranchInst(Mnemonic_JNZ, trueTarget, falseTarget),nextInst);
                                nextInst = (Inst *)trueTarget->getLastInst();
                            }
                            parityInst->unlink();
                            mn = nextInst->getMnemonic();
                        } 
                        trueTarget = ((BranchInst *)nextInst)->getTrueTarget();
                        falseTarget = ((BranchInst *)nextInst)->getFalseTarget();
                        Node * nextNode = nextInst->getNode();

                        //check particular flags and do the corresponding conditional jump
                        if (mn == Mnemonic_JA || mn == Mnemonic_JNA) {
                            nextNode->prependInst(irManager->newInst(Mnemonic_AND, cMemOp, irManager->newImmOpnd(cMemOp->getType(),FPU_FLAGS)),nextInst);
                            nextNode->prependInst(irManager->newInst(Mnemonic_CMP, cMemOp, irManager->newImmOpnd(cMemOp->getType(),0)),nextInst);
                            nextNode->prependInst(irManager->newBranchInst(mn==Mnemonic_JA ? Mnemonic_JZ : Mnemonic_JNZ, trueTarget, falseTarget),nextInst);
                        } else if (mn == Mnemonic_JAE || mn == Mnemonic_JNAE) {
                            nextNode->prependInst(irManager->newInst(Mnemonic_AND, cMemOp, irManager->newImmOpnd(cMemOp->getType(),FPU_FLAG_C0)),nextInst);
                            nextNode->prependInst(irManager->newBranchInst(mn==Mnemonic_JAE? Mnemonic_JZ : Mnemonic_JNZ, trueTarget, falseTarget),nextInst);
                        } else if (mn == Mnemonic_JE || mn == Mnemonic_JNE) {
                            nextNode->prependInst(irManager->newInst(Mnemonic_AND, cMemOp, irManager->newImmOpnd(cMemOp->getType(),FPU_FLAG_C3)),nextInst);
                            nextNode->prependInst(irManager->newBranchInst(mn==Mnemonic_JE? Mnemonic_JNZ : Mnemonic_JZ, trueTarget, falseTarget),nextInst);
                        }
                        nextInst->unlink();
                    } else {
                        nextInst = nextInst->getNextInst();
                        Mnemonic mn = nextInst->getMnemonic();
                        Inst::Opnds sopnds(nextInst, Inst::OpndRole_Explicit|Inst::OpndRole_UseDef);
                        Inst::Opnds::iterator oit = sopnds.begin();
                        Opnd * sop = inst->getOpnd(oit);
                        
                        //check particular flags and do the corresponding conditional set
                        if (mn == Mnemonic_SETA || mn == Mnemonic_SETNA) {
                            node->prependInst(irManager->newInst(Mnemonic_CMP, cMemOp, irManager->newImmOpnd(cMemOp->getType(),0)),nextInst);
                            node->prependInst(irManager->newInst(mn==Mnemonic_SETA ? Mnemonic_SETZ : Mnemonic_SETNZ, sop),nextInst);
                        } else if (mn == Mnemonic_SETAE || mn == Mnemonic_SETNAE) {
                            node->prependInst(irManager->newInst(Mnemonic_AND, cMemOp, irManager->newImmOpnd(cMemOp->getType(),FPU_FLAGS)),nextInst);
                            node->prependInst(irManager->newInst(Mnemonic_CMP, cMemOp, irManager->newImmOpnd(cMemOp->getType(),FPU_FLAG_C0)),nextInst);
                            node->prependInst(irManager->newInst(mn==Mnemonic_SETAE? Mnemonic_SETNZ : Mnemonic_SETZ, sop),nextInst);
                        } else if (mn == Mnemonic_SETE || mn == Mnemonic_SETNE) {
                            node->prependInst(irManager->newInst(Mnemonic_AND, cMemOp, irManager->newImmOpnd(cMemOp->getType(),FPU_FLAGS)),nextInst);
                            node->prependInst(irManager->newInst(Mnemonic_CMP, cMemOp, irManager->newImmOpnd(cMemOp->getType(),FPU_FLAGS)),nextInst);
                            node->prependInst(irManager->newInst(mn==Mnemonic_SETE? Mnemonic_SETZ : Mnemonic_SETNZ, sop),nextInst);
                        }
                        parityInst = nextInst->getNextInst();
                        nextInst->unlink();
                        if (parityInst) {
                            nextInst = parityInst;
                            mn = parityInst->getMnemonic();
                            
                            //if the instruction is a check for NaN
                            if (mn == Mnemonic_CMOVP || mn == Mnemonic_CMOVNP) {
                                node->prependInst(irManager->newInst(Mnemonic_AND, cMemOp, irManager->newImmOpnd(cMemOp->getType(),FPU_FLAGS)),nextInst);
                                node->prependInst(irManager->newInst(Mnemonic_CMP, cMemOp, irManager->newImmOpnd(cMemOp->getType(),FPU_FLAGS)),nextInst);
                                Opnd * cop0 = NULL;
                                Opnd * cop1 = NULL;
                                Inst::Opnds copnds(nextInst, Inst::OpndRole_Explicit|Inst::OpndRole_UseDef);
                                Inst::Opnds::iterator oit = copnds.begin();
                                cop0 = inst->getOpnd(oit);
                                cop1 = inst->getOpnd(copnds.next(oit));
                                if (mn ==Mnemonic_CMOVP) {
                                    node->prependInst(irManager->newInst((Mnemonic_CMOVNZ), cop0, cop1),nextInst);
                                    nextInst = nextInst->getNextInst();
                                } else {
                                    node->prependInst(irManager->newInst((Mnemonic_CMOVZ), cop0, cop1),nextInst);
                                }
                                nextInst->unlink();
                            }
                        }
                    }
                    break;
                }
                default:
                {
                    assert(0);
                    break;
                }
            }
            
            inst->unlink();
            inst = (Inst * )node->getFirstInst();
        }
    }
    
    StlVector<Inst *> cmovs(irManager->getMemoryManager());
    StlVector<Inst *> sets(irManager->getMemoryManager());

    for (Nodes::const_iterator cit = nodes.begin(); cit != nodes.end(); ++cit) {
        Node* node = *cit;
        if (!node->isBlockNode()) {
            continue;
        }
        for(Inst * inst = (Inst *)node->getFirstInst(); inst != NULL; inst = inst->getNextInst()) {
            Mnemonic mn = inst->getMnemonic();
            Mnemonic bm = getBaseConditionMnemonic(mn);
            if(bm == Mnemonic_CMOVcc) {
                cmovs.push_back(inst);
            } else if (bm == Mnemonic_SETcc) {
                sets.push_back(inst);
            }
        }
    }
    
    for(unsigned i = 0 ; i<cmovs.size(); i++) {
        //replace: CMOVcc op1, op2  ->      Jcc L1
        //                                  JMP L2
        //                              L1: MOV op1, op2
        //                              L2: ...
        Inst * inst = cmovs[i];
        Mnemonic mn = inst->getMnemonic();
        Mnemonic bm = getBaseConditionMnemonic(mn);
        Inst::Opnds opnds(inst, Inst::OpndRole_Explicit|Inst::OpndRole_UseDef);
        Opnd * op1 = inst->getOpnd(opnds.begin());
        Opnd * op2 = inst->getOpnd(opnds.begin()+1);
        ControlFlowGraph* subCFG = irManager->createSubCFG(true, false);
        Node* bbJmp = subCFG->getEntryNode();
        Node* bbTrue  = subCFG->createBlockNode();
        Node* bbRet = subCFG->getReturnNode();

        Inst * jmp = irManager->newBranchInst((Mnemonic)(Mnemonic_Jcc+(mn-bm)),bbTrue, bbRet);
        bbJmp->appendInst(jmp);

        Inst * trueMov = irManager->newInst(Mnemonic_MOV, op1, op2);
        bbTrue->appendInst(trueMov);

        subCFG->addEdge(bbJmp, bbTrue, 0.5);
        subCFG->addEdge(bbJmp, bbRet, 0.5);
        subCFG->addEdge(bbTrue, bbRet, 1);
        irManager->getFlowGraph()->spliceFlowGraphInline(inst, *subCFG);
        inst->unlink();
    }
    
    for(unsigned i = 0 ; i<sets.size(); i++) {
        //replace: SETcc op1  ->     Jcc L1
        //                           MOV op1, 0
        //                           JMP L2
        //                       L1: MOV op1, 1
        //                       L2: ...
        Inst * inst = sets[i];
        Mnemonic mn = inst->getMnemonic();
        Mnemonic bm = getBaseConditionMnemonic(mn);
        Inst::Opnds opnds(inst, Inst::OpndRole_Explicit|Inst::OpndRole_UseDef);
        Opnd * op1 = inst->getOpnd(opnds.begin());
        ControlFlowGraph* subCFG = irManager->createSubCFG(true, false);
        Node* bbJmp = subCFG->getEntryNode();
        Node* bbTrue  = subCFG->createBlockNode();
        Node* bbFalse = subCFG->createBlockNode();
        Node* bbRet = subCFG->getReturnNode();

        Inst * jmp = irManager->newBranchInst((Mnemonic)(Mnemonic_Jcc+(mn-bm)),bbTrue, bbFalse);
        bbJmp->appendInst(jmp);

        Inst * trueMov = irManager->newInst(Mnemonic_MOV, op1, irManager->newImmOpnd(op1->getType(), 1));
        bbTrue->appendInst(trueMov);

        Inst * falseMov = irManager->newInst(Mnemonic_MOV, op1, irManager->newImmOpnd(op1->getType(), 0));
        bbFalse->appendInst(falseMov);

        subCFG->addEdge(bbJmp, bbTrue, 0.5);
        subCFG->addEdge(bbJmp, bbFalse, 0.5);
        subCFG->addEdge(bbTrue, bbRet, 1);
        subCFG->addEdge(bbFalse, bbRet, 1);
        irManager->getFlowGraph()->spliceFlowGraphInline(inst, *subCFG);
        inst->unlink();
    }
    
    irManager->getFlowGraph()->purgeEmptyNodes();
    irManager->getFlowGraph()->purgeUnreachableNodes();
    irManager->fixEdgeProfile();
    
}