U0 ICAndBranch(CIntermediateCode *tmpi, I64 rip, I64 is, U8 *buf, I64 rip2)
{
        U64                      i;
        I64                      it, t1, r1, d1, r2;
        Bool             short_jmp, swap, override;
        CCodeMisc       *lb;
        CICArg          *arg1, *arg2;

        if (tmpi->arg1.type & MDF_IMM)
        {
                swap = TRUE;
                arg1 = &tmpi->arg2;
                arg2 = &tmpi->arg1;
        }
        else
        {
                swap = FALSE;
                arg1 = &tmpi->arg1;
                arg2 = &tmpi->arg2;
        }

        if (arg2->type & MDF_IMM && arg2->disp > U32_MAX)
                override = TRUE;
        else
                override = FALSE;

        if (arg1->type.raw_type < arg2->type.raw_type)
                it = arg1->type.raw_type;
        else
                it = arg2->type.raw_type;

        i = arg2->disp;
        if (arg2->type & MDF_IMM && i <= U32_MAX)
        {
                ICMov(tmpi, MDF_REG + RT_I64, REG_RAX, 0, arg1->type, arg1->reg, arg1->disp, rip2);
                if (i <= U8_MAX)
                        ICU16(tmpi, i << 8 + 0xA8);
                else if (i <= U16_MAX)
                        ICU32(tmpi, i << 16 + 0xA900 + OC_OP_SIZE_PREFIX);
                else
                {
                        ICU8(tmpi, 0xA9);
                        ICU32(tmpi, i);
                }
        }
        else
        {
                t1 = MDF_REG + it;
                d1 = 0;
                if (swap && !override)
                {
                        if (arg1->type & MDF_REG)
                        {
                                r1 = arg1->reg;
                                swap = TRUE;
                        }
                        else
                        {
                                r1 = REG_RCX;
                                swap = FALSE;
                        }
                        if (arg2->type & MDF_REG)
                        {
                                r2 = arg2->reg;
                                swap = FALSE;
                        }
                        else
                                r2 = REG_RDX;
                        if (swap)
                        {
                                if (!(arg1->type & MDF_REG) || r1 != arg1->reg)
                                        ICMov(tmpi, MDF_REG + RT_I64, r1, 0, arg1->type, arg1->reg, arg1->disp, rip2);
                                if (arg2->type & MDG_REG_DISP_SIB_RIP)
                                {
                                        t1 = arg2->type & MDG_MASK + it;
                                        r2 = arg2->reg;
                                        d1 = arg2->disp;
                                }
                                else
                                        ICMov(tmpi, MDF_REG + RT_I64, r2, 0, arg2->type, arg2->reg, arg2->disp, rip2);
                                i = ICModr1(r1, t1, r2, d1);
                        }
                        else
                        {
                                if (arg1->type & MDG_REG_DISP_SIB_RIP)
                                {
                                        t1 = arg1->type & MDG_MASK + it;
                                        r1 = arg1->reg;
                                        d1 = arg1->disp;
                                }
                                else
                                        ICMov(tmpi, MDF_REG + RT_I64, r1, 0, arg1->type, arg1->reg, arg1->disp, rip2);
                                if (!(arg2->type & MDF_REG) || r2 != arg2->reg)
                                        ICMov(tmpi, MDF_REG + RT_I64, r2, 0, arg2->type, arg2->reg, arg2->disp, rip2);
                                i = ICModr1(r2, t1, r1, d1);
                        }
                }
                else
                {
                        if (arg2->type & MDF_REG)
                        {
                                r2 = arg2->reg;
                                swap = FALSE;
                        }
                        else
                        {
                                r2 = REG_RDX;
                                swap = TRUE;
                        }
                        if (arg1->type & MDF_REG)
                        {
                                r1 = arg1->reg;
                                swap = TRUE;
                        }
                        else
                                r1 = REG_RCX;
                        if (override)
                                swap = FALSE;
                        if (swap)
                        {
                                if (arg2->type & MDG_REG_DISP_SIB_RIP)
                                {
                                        t1 = arg2->type & MDG_MASK + it;
                                        r2 = arg2->reg;
                                        d1 = arg2->disp;
                                }
                                else
                                        ICMov(tmpi, MDF_REG + RT_I64, r2, 0, arg2->type, arg2->reg, arg2->disp, rip2);
                                if (!(arg1->type & MDF_REG) || r1 != arg1->reg)
                                        ICMov(tmpi, MDF_REG + RT_I64, r1, 0, arg1->type, arg1->reg, arg1->disp, rip2);
                                i = ICModr1(r1, t1, r2, d1);
                        }
                        else
                        {
                                if (!(arg2->type & MDF_REG) || r2 != arg2->reg)
                                        ICMov(tmpi, MDF_REG + RT_I64, r2, 0, arg2->type, arg2->reg, arg2->disp, rip2);
                                if (arg1->type & MDG_REG_DISP_SIB_RIP)
                                {
                                        t1 = arg1->type & MDG_MASK + it;
                                        r1 = arg1->reg;
                                        d1 = arg1->disp;
                                }
                                else
                                        ICMov(tmpi, MDF_REG + RT_I64, r1, 0, arg1->type, arg1->reg, arg1->disp, rip2);
                                i = ICModr1(r2, t1, r1, d1);
                        }
                }
                switch (it)
                {
                        case RT_I8:
                        case RT_U8:
                                ICRex(tmpi, i.u8[1]);
                                ICU16(tmpi, i.u8[2] << 8 + 0x84);
                                break;

                        case RT_U16:
                        case RT_I16:
                                ICOpSizeRex(tmpi, i.u8[1]);
                                ICU16(tmpi, i.u8[2] << 8 + 0x85);
                                break;

                        default:
                                ICRex(tmpi, i.u8[1]);
                                ICU16(tmpi, i.u8[2] << 8 + 0x85);
                }
                ICModr2(tmpi, i,, d1, rip2);
        }

        rip += tmpi->ic_count;
        lb = OptLabelFwd(tmpi->ic_data);
        short_jmp = ToBool(tmpi->ic_flags & ICF_SHORT_JMP);
        if (!buf && lb->addr != INVALID_PTR)
        {
                i = lb->addr - (rip + 2);
                if (lb->flags & CMF_POP_CMP)
                        i += 8;
                if (I8_MIN <= i <= I8_MAX)
                        short_jmp = TRUE;
        }

        if (short_jmp)
        {
                tmpi->ic_flags |= ICF_SHORT_JMP;
                i = lb->addr - (rip + 2);
                if (lb->flags & CMF_POP_CMP)
                        i += 8;
                ICU16(tmpi, i << 8 + is.u8[2]);
        }
        else
        {
                tmpi->ic_flags &= ~ICF_SHORT_JMP;
                i = lb->addr - (rip + 6);
                if (lb->flags & CMF_POP_CMP)
                        i += 8;
                ICU16(tmpi, is.u16[0]);
                ICU32(tmpi, i);
        }
}

U0 ICAssign(CIntermediateCode *tmpi, I64 rip)
{
        CIntermediateCode *tmpi1;

        if (tmpi->ic_flags & ICF_BY_VAL)
        {
                ICMov(tmpi, tmpi->arg1.type & MDG_MASK + tmpi->arg1_type_pointed_to, tmpi->arg1.reg, tmpi->arg1.disp,
                          tmpi->arg2.type, tmpi->arg2.reg, tmpi->arg2.disp, rip);
                if (tmpi->res.type.mode)
                        ICMov(tmpi, tmpi->res.type & MDG_MASK + tmpi->arg1_type_pointed_to, tmpi->res.reg, tmpi->res.disp,
                                  tmpi->arg1.type & MDG_MASK + tmpi->arg1_type_pointed_to, tmpi->arg1.reg, tmpi->arg1.disp, rip);
        }
        else
        {
                if (tmpi->arg1.type & MDF_REG)
                {
                        if (!(tmpi1 = OptLag1(tmpi)) || tmpi1->ic_code != IC_ADD_CONST ||
                                tmpi1->res.type != MDF_REG + RT_I64 || tmpi1->res.reg != tmpi->arg1.reg ||
                                tmpi1->arg1.type != MDF_REG + RT_I64 ||
                                tmpi1->arg1.reg != tmpi->arg1.reg ||
                                (tmpi->arg2.type & MDF_REG || tmpi->arg2.type & MDF_DISP) &&
                                tmpi->arg2.reg == tmpi->arg1.reg ||
                                tmpi->res.type.mode || tmpi1->ic_flags & ~ICG_NO_CONVERT_MASK)
                        {
                                ICMov(tmpi, MDF_DISP + tmpi->arg1_type_pointed_to, tmpi->arg1.reg, tmpi->arg1.disp,
                                          tmpi->arg2.type, tmpi->arg2.reg, tmpi->arg2.disp, rip);
                                if (tmpi->res.type.mode)
                                        ICMov(tmpi, tmpi->res.type, tmpi->res.reg, tmpi->res.disp,
                                                  tmpi->arg2.type, tmpi->arg2.reg, tmpi->arg2.disp, rip);
                        }
                        else
                        {
                                tmpi->ic_flags = (tmpi->ic_flags | tmpi1->ic_flags) & ~ICF_CODE_FINAL | ICF_DONT_RESTORE;
                                tmpi->arg1.disp = tmpi1->ic_data;
                                OptSetNOP1(tmpi1); //This better not be last pass!
                                ICMov(tmpi, MDF_DISP + tmpi->arg1_type_pointed_to, tmpi->arg1.reg, tmpi->arg1.disp,
                                          tmpi->arg2.type, tmpi->arg2.reg, tmpi->arg2.disp, rip);
                        }
                }
                else
                {
                        ICMov(tmpi, MDF_REG + RT_I64, REG_RCX, 0, tmpi->arg1.type, tmpi->arg1.reg, tmpi->arg1.disp, rip);
                        ICMov(tmpi, MDF_DISP + tmpi->arg1_type_pointed_to, REG_RCX, 0,
                                  tmpi->arg2.type, tmpi->arg2.reg, tmpi->arg2.disp, rip);
                        if (tmpi->res.type.mode)
                                ICMov(tmpi, tmpi->res.type, tmpi->res.reg, tmpi->res.disp,
                                          tmpi->arg2.type, tmpi->arg2.reg, tmpi->arg2.disp, rip);
                }
        }
}

U0 ICBrBitOps(CIntermediateCode *tmpi, I64 rip, I64 op, I64 op_imm, I64 is, U8 *buf, I64 rip2)
{
        I64                      i, t, r1, r2, d1, d2, t1, t2;
        CICArg          *arg1 = &tmpi->arg1, *arg2 = &tmpi->arg2;
        Bool             short_jmp;
        CCodeMisc       *lb;

        if (tmpi->ic_flags & ICF_BY_VAL)
        {
                if (tmpi->ic_flags & ICF_SWAP && !(arg2->type & MDF_REG) &&
                        (!(arg2->type & MDF_IMM) || arg2->disp > 63) ||
                        !(tmpi->ic_flags & ICF_SWAP) && arg2->type & MDF_IMM &&
                        arg2->disp < 64 || arg2->type & MDF_STACK)
                {
                        ICMov(tmpi, MDF_REG + RT_I64, REG_RCX, 0, arg2->type, arg2->reg, arg2->disp, rip2);
                        t2 = MDF_REG+RT_I64;
                        r2 = REG_RCX;
                        d2 = 0;
                }
                else
                {
                        t2 = arg2->type;
                        if (t2 & MDF_IMM && arg2->disp < 64)
                                r2 = 0;
                        else
                                r2 = arg2->reg;
                        d2 = arg2->disp;
                }
                if (!(tmpi->ic_flags & ICF_SWAP) && !(arg1->type & MDF_REG) &&
                        (!(arg1->type & MDF_IMM) || arg1->disp > 63) ||
                        tmpi->ic_flags & ICF_SWAP && arg1->type & MDF_IMM &&
                        arg1->disp < 64 || arg1->type & MDF_STACK)
                {
                        ICMov(tmpi, MDF_REG + RT_I64, REG_RDX, 0, arg1->type, arg1->reg, arg1->disp, rip2);
                        t1 = MDF_REG+RT_I64;
                        r1 = REG_RDX;
                        d1 = 0;
                }
                else
                {
                        t1 = arg1->type;
                        if (t1 & MDF_IMM && arg1->disp < 64)
                                r1 = 0;
                        else
                                r1 = arg1->reg;
                        d1 = arg1->disp;
                }
        }
        else
        {
                t1 = MDF_DISP + RT_I64;
                t2 = MDF_DISP + RT_I64;
                d1 = 0;
                d2 = 0;
                if (arg2->type & MDF_REG)
                        r2 = arg2->reg;
                else if (!(tmpi->ic_flags & ICF_SWAP) || !(arg2->type & MDF_IMM) || arg2->disp > 63)
                {
                        ICMov(tmpi, MDF_REG + RT_I64, REG_RCX, 0, arg2->type, arg2->reg, arg2->disp, rip2);
                        r2 = REG_RCX;
                }
                else
                        r2 = 0;
                if (arg1->type & MDF_REG)
                        r1 = arg1->reg;
                else if (tmpi->ic_flags & ICF_SWAP || !(arg1->type & MDF_IMM) || arg1->disp > 63)
                {
                        ICMov(tmpi, MDF_REG + RT_I64, REG_RDX, 0, arg1->type, arg1->reg, arg1->disp, rip2);
                        r1 = REG_RDX;
                }
                else
                        r1 = 0;
        }
        if (tmpi->ic_flags & ICF_LOCK && op != 0xA30F)
                ICU8(tmpi, OC_LOCK_PREFIX);
        if (tmpi->ic_flags & ICF_SWAP)
        {
                if (arg2->type & MDF_IMM && arg2->disp < 32)
                {
                        if (op == 0xA30F && arg2->disp < 8)
                        {
                                t = t1 & MDG_MASK+RT_U8;
                                op_imm = 0xF6; //TEST
                        }
                        else
                                t = t1 & MDG_MASK + RT_U32;
                }
                else
                        t = t1;
                i = ICModr1(r2, t, r1, d1);
                SwapI64(&arg1, &arg2);
        }
        else
        {
                if (arg1->type & MDF_IMM && arg1->disp < 32)
                {
                        if (op == 0xA30F && arg1->disp < 8)
                        {
                                t = t2 & MDG_MASK + RT_U8;
                                op_imm = 0xF6; //TEST
                        }
                        else
                                t = t2 & MDG_MASK + RT_U32;
                }
                else
                        t = t2;
                i = ICModr1(r1, t, r2, d2);
        }
        ICRex(tmpi, i.u8[1]);
        if (op_imm == 0xF6)
        {//TEST
                ICU16(tmpi, i.u8[2] << 8 + op_imm);
                ICModr2(tmpi, i,, arg2->disp, rip2 + 1);
                ICU8(tmpi, 1 << arg1->disp);
                if (is == 0x72820F)
                        is = 0x75850F;
                else
                        is = 0x74840F;
        }
        else if (arg1->type & MDF_IMM && arg1->disp < 64)
        {
                ICU24(tmpi, i.u8[2] << 16 + op_imm);
                ICModr2(tmpi, i,, arg2->disp, rip2 + 1);
                ICU8(tmpi, arg1->disp);
        }
        else
        {
                ICU24(tmpi, i.u8[2] << 16 + op);
                ICModr2(tmpi, i,, arg2->disp, rip2);
        }

        rip += tmpi->ic_count;
        lb = OptLabelFwd(tmpi->ic_data);
        short_jmp = ToBool(tmpi->ic_flags & ICF_SHORT_JMP);
        if (!buf && lb->addr != INVALID_PTR)
        {
                i = lb->addr - (rip + 2);
                if (lb->flags & CMF_POP_CMP)
                        i += 8;
                if (I8_MIN <= i <= I8_MAX)
                        short_jmp = TRUE;
        }

        if (short_jmp)
        {
                tmpi->ic_flags |= ICF_SHORT_JMP;
                i = lb->addr - (rip + 2);
                if (lb->flags & CMF_POP_CMP)
                        i += 8;
                ICU16(tmpi, i << 8 + is.u8[2]);
        }
        else
        {
                tmpi->ic_flags &= ~ICF_SHORT_JMP;
                i = lb->addr - (rip + 6);
                if (lb->flags & CMF_POP_CMP)
                        i += 8;
                ICU16(tmpi, is.u16[0]);
                ICU32(tmpi, i);
        }
}

U0 ICQueueInit(CIntermediateCode *tmpi, I64 rip2)
{
        I64 r1;

        if (tmpi->arg1.type == MDF_REG + RT_I64)
                r1 = tmpi->arg1.reg;
        else
        {
                ICMov(tmpi, MDF_REG + RT_I64, REG_RAX, 0, tmpi->arg1.type, tmpi->arg1.reg, tmpi->arg1.disp, rip2);
                r1 = REG_RAX;
        }
        ICMov(tmpi, MDF_DISP + RT_I64, r1, 0,                    MDF_REG + RT_I64, r1, 0, rip2);
        ICMov(tmpi, MDF_DISP + RT_I64, r1, sizeof(U8 *), MDF_REG + RT_I64, r1, 0, rip2);
}

U0 ICQueueInsert(CIntermediateCode *tmpi, I64 rip2)
{
        I64 r1, r2;

        if (tmpi->arg2.type == MDF_REG + RT_I64 && tmpi->arg2.reg != REG_RDX)
                r2 = tmpi->arg2.reg;
        else
        {
                ICMov(tmpi, MDF_REG + RT_I64, REG_RAX, 0, tmpi->arg2.type, tmpi->arg2.reg, tmpi->arg2.disp, rip2);
                r2 = REG_RAX;
        }
        if (tmpi->arg1.type == MDF_REG + RT_I64)
                r1 = tmpi->arg1.reg;
        else
        {
                ICMov(tmpi, MDF_REG + RT_I64, REG_RDX, 0, tmpi->arg1.type, tmpi->arg1.reg, tmpi->arg1.disp, rip2);
                r1 = REG_RDX;
        }
        ICMov(tmpi, MDF_REG  + RT_I64, REG_RBX, 0,                              MDF_DISP + RT_I64, r1,          0, rip2);
        ICMov(tmpi, MDF_DISP + RT_I64, r1,              0,                              MDF_REG  + RT_I64, r2,          0, rip2);
        ICMov(tmpi, MDF_DISP + RT_I64, r2,              0,                              MDF_REG  + RT_I64, REG_RBX,     0, rip2);
        ICMov(tmpi, MDF_DISP + RT_I64, r2,              sizeof(U8 *),   MDF_REG  + RT_I64, r1,          0, rip2);
        ICMov(tmpi, MDF_DISP + RT_I64, REG_RBX, sizeof(U8 *),   MDF_REG  + RT_I64, r2,          0, rip2);
}

U0 ICQueueInsertRev(CIntermediateCode *tmpi, I64 rip2)
{
        I64 r1, r2;

        if (tmpi->arg2.type == MDF_REG + RT_I64 && tmpi->arg2.reg != REG_RDX)
                r2 = tmpi->arg2.reg;
        else
        {
                ICMov(tmpi, MDF_REG + RT_I64, REG_RAX, 0, tmpi->arg2.type, tmpi->arg2.reg, tmpi->arg2.disp, rip2);
                r2 = REG_RAX;
        }
        if (tmpi->arg1.type == MDF_REG + RT_I64)
                r1 = tmpi->arg1.reg;
        else
        {
                ICMov(tmpi, MDF_REG + RT_I64, REG_RDX, 0, tmpi->arg1.type, tmpi->arg1.reg, tmpi->arg1.disp, rip2);
                r1 = REG_RDX;
        }
        ICMov(tmpi, MDF_REG  + RT_I64, REG_RBX, 0,                              MDF_DISP + RT_I64,      r1,                     sizeof(U8 *),   rip2);
        ICMov(tmpi, MDF_DISP + RT_I64, REG_RBX, 0,                              MDF_REG  + RT_I64,      r2,                     0,                              rip2);
        ICMov(tmpi, MDF_DISP + RT_I64, r2,              0,                              MDF_REG  + RT_I64,      r1,                     0,                              rip2);
        ICMov(tmpi, MDF_DISP + RT_I64, r2,              sizeof(U8 *),   MDF_REG  + RT_I64,      REG_RBX,        0,                              rip2);
        ICMov(tmpi, MDF_DISP + RT_I64, r1,              sizeof(U8 *),   MDF_REG  + RT_I64,      r2,                     0,                              rip2);
}

U0 ICQueueRemove(CIntermediateCode *tmpi, I64 rip2)
{
        I64 r1;

        if (tmpi->arg1.type == MDF_REG+RT_I64)
                r1 = tmpi->arg1.reg;
        else
        {
                ICMov(tmpi, MDF_REG + RT_I64, REG_RAX, 0, tmpi->arg1.type, tmpi->arg1.reg, tmpi->arg1.disp, rip2);
                r1 = REG_RAX;
        }
        ICMov(tmpi, MDF_REG + RT_I64, REG_RBX, 0, MDF_DISP + RT_I64, r1, 0, rip2);
        ICMov(tmpi, MDF_REG + RT_I64, REG_RDX, 0, MDF_DISP + RT_I64, r1, sizeof(U8 *), rip2);
        ICU24(tmpi, 0x1A8948);
        ICU32(tmpi, sizeof(U8 *) << 24 + 0x538948);
}

U0 ICMinMax(CIntermediateCode *tmpi, I64 op, I64 rip2)
{
        I64 r1, i1 = 0x48;

        if (tmpi->arg2.type == MDF_REG + RT_I64 && tmpi->arg2.reg != REG_RAX)
        {
                r1 = tmpi->arg2.reg;
                if (r1 > 7)
                {
                        i1++;
                        r1 &= 7;
                }
                ICMov(tmpi, MDF_REG + RT_I64, REG_RAX, 0, tmpi->arg1.type, tmpi->arg1.reg, tmpi->arg1.disp, rip2);
        }
        else
        {
                if (tmpi->arg1.reg == REG_RAX && tmpi->arg1.type & MDG_REG_DISP_SIB)
                {
                        ICMov(tmpi, MDF_REG + RT_I64, REG_RDX, 0, tmpi->arg2.type, tmpi->arg2.reg, tmpi->arg2.disp, rip2);
                        r1 = REG_RDX;
                        ICMov(tmpi, MDF_REG + RT_I64, REG_RAX, 0, tmpi->arg1.type, tmpi->arg1.reg, tmpi->arg1.disp, rip2);
                }
                else
                {
                        ICMov(tmpi, MDF_REG + RT_I64, REG_RAX, 0, tmpi->arg2.type, tmpi->arg2.reg, tmpi->arg2.disp, rip2);
                        if (tmpi->arg1.type == MDF_REG + RT_I64)
                        {
                                r1 = tmpi->arg1.reg;
                                if (r1 > 7)
                                {
                                        i1++;
                                        r1 &= 7;
                                }
                        }
                        else
                        {
                                r1 = REG_RDX;
                                ICMov(tmpi, MDF_REG + RT_I64, REG_RDX, 0, tmpi->arg1.type, tmpi->arg1.reg, tmpi->arg1.disp, rip2);
                        }
                }
        }
        ICU24(tmpi, 0xC03B00   + r1 << 16 + i1);
        ICU32(tmpi, 0xC0000F00 + op << 16 + r1 << 24 + i1);
}

U0 ICSqr(CIntermediateCode *tmpi, I64 op, I64 rip2)
{
        ICMov(tmpi, MDF_REG + RT_I64, REG_RAX, 0, tmpi->arg1.type, tmpi->arg1.reg, tmpi->arg1.disp, rip2);
        ICSlashOp(tmpi, MDF_REG + RT_I64, REG_RAX, 0, op, rip2);
}

U0 ICModU64(CIntermediateCode *tmpi, I64 rip2)
{
        CICType t1;
        I64             r1, d1;

        ICMov(tmpi, MDF_REG + RT_I64, REG_RCX, 0, tmpi->arg2.type, tmpi->arg2.reg, tmpi->arg2.disp, rip2);
        if (tmpi->arg1.reg != REG_RAX && tmpi->arg1.reg != REG_RDX &&
                tmpi->arg1.type & MDG_REG_DISP_SIB &&
                tmpi->arg1.type.raw_type >= RT_I64)
        {
                t1 = tmpi->arg1.type;
                r1 = tmpi->arg1.reg;
                d1 = tmpi->arg1.disp;
        }
        else
        {
                t1 = MDF_REG + RT_I64;
                r1 = REG_RBX;
                d1 = 0;
                ICMov(tmpi, MDF_REG + RT_I64, REG_RBX, 0, tmpi->arg1.type, tmpi->arg1.reg, tmpi->arg1.disp, rip2);
        }
        ICMov(tmpi, MDF_REG + RT_I64, REG_RAX, 0, MDF_DISP + RT_I64, REG_RCX, 0, rip2);
        ICZero(tmpi, REG_RDX);
        ICSlashOp(tmpi, t1, r1, d1, SLASH_OP_DIV, rip2);
        ICMov(tmpi, MDF_DISP + RT_I64, REG_RCX, 0, MDF_REG + RT_I64, REG_RAX, 0, rip2);
        ICMov(tmpi, MDF_REG  + RT_I64, REG_RAX, 0, MDF_REG + RT_I64, REG_RDX, 0, rip2);
}

U0 ICSwap(CIntermediateCode *tmpi, I64 rip2)
{
        I64 r1, r2;

        if (tmpi->arg1.type & MDF_REG)
                r1 = tmpi->arg1.reg;
        else
                r1 = REG_RAX;
        if (tmpi->arg2.type & MDF_REG)
                r2 = tmpi->arg2.reg;
        else
                r2 = REG_RAX;
        if (r1 == r2)
        {
                if (r1 == REG_RAX)
                        r1 = REG_RBX;
                else
                        r2 = REG_RAX;
        }
        ICMov(tmpi, MDF_REG + RT_I64, r2, 0, tmpi->arg2.type, tmpi->arg2.reg, tmpi->arg2.disp, rip2);
        ICMov(tmpi, MDF_REG + RT_I64, r1, 0, tmpi->arg1.type, tmpi->arg1.reg, tmpi->arg1.disp, rip2);
        switch (tmpi->ic_code)
        {
                case IC_SWAP_U8:
                        ICMov(tmpi, MDF_REG  + RT_I64, REG_RCX, 0, MDF_DISP + RT_U8,  r1,               0, rip2);
                        ICMov(tmpi, MDF_REG  + RT_I64, REG_RDX, 0, MDF_DISP + RT_U8,  r2,               0, rip2);
                        ICMov(tmpi, MDF_DISP + RT_U8,  r2,              0, MDF_REG  + RT_I64, REG_RCX,  0, rip2);
                        ICMov(tmpi, MDF_DISP + RT_U8,  r1,              0, MDF_REG  + RT_I64, REG_RDX,  0, rip2);
                        break;

                case IC_SWAP_U16:
                        ICMov(tmpi, MDF_REG  + RT_I64, REG_RCX, 0, MDF_DISP + RT_U16, r1,               0, rip2);
                        ICMov(tmpi, MDF_REG  + RT_I64, REG_RDX, 0, MDF_DISP + RT_U16, r2,               0, rip2);
                        ICMov(tmpi, MDF_DISP + RT_U16, r2,              0, MDF_REG  + RT_I64, REG_RCX,  0, rip2);
                        ICMov(tmpi, MDF_DISP + RT_U16, r1,              0, MDF_REG  + RT_I64, REG_RDX,  0, rip2);
                        break;

                case IC_SWAP_U32:
                        ICMov(tmpi, MDF_REG  + RT_I64, REG_RCX, 0, MDF_DISP + RT_U32, r1,               0, rip2);
                        ICMov(tmpi, MDF_REG  + RT_I64, REG_RDX, 0, MDF_DISP + RT_U32, r2,               0, rip2);
                        ICMov(tmpi, MDF_DISP + RT_U32, r2,              0, MDF_REG  + RT_I64, REG_RCX,  0, rip2);
                        ICMov(tmpi, MDF_DISP + RT_U32, r1,              0, MDF_REG  + RT_I64, REG_RDX,  0, rip2);
                        break;

                case IC_SWAP_I64:
                        ICMov(tmpi, MDF_REG  + RT_I64, REG_RCX, 0, MDF_DISP + RT_U64, r1,               0, rip2);
                        ICMov(tmpi, MDF_REG  + RT_I64, REG_RDX, 0, MDF_DISP + RT_U64, r2,               0, rip2);
                        ICMov(tmpi, MDF_DISP + RT_U64, r2,              0, MDF_REG  + RT_I64, REG_RCX,  0, rip2);
                        ICMov(tmpi, MDF_DISP + RT_U64, r1,              0, MDF_REG  + RT_I64, REG_RDX,  0, rip2);
                        break;
        }
}

U0 ICAndEqu(CIntermediateCode *tmpi, I64 rip2)
{
        I64 i, bit;

        if (tmpi->arg2.type & MDF_IMM && !(tmpi->arg1.type & MDF_STACK) && tmpi->ic_flags & ICF_RES_NOT_USED)
        {
                i = ~tmpi->arg2.disp;
                bit = Bsf(i);
                if (0 <= bit == Bsr(i))
                {
                        tmpi->arg2.disp = bit;
                        tmpi->arg2.reg = 0;
                        tmpi->arg1.type = tmpi->arg1.type & MDG_MASK + RT_I64;
                        ICBitOps(tmpi, &tmpi->arg2, &tmpi->arg1, tmpi, 0xB30F, 0x30BA0F, rip2);
                        return;
                }
        }
        ICAddSubEctEqu(tmpi, tmpi->arg1_type_pointed_to, tmpi->res.type,tmpi->res.reg, tmpi->res.disp,
                                   tmpi->arg1.type, tmpi->arg1.reg, tmpi->arg1.disp,
                                   tmpi->arg2.type, tmpi->arg2.reg, tmpi->arg2.disp,
                                   0x210425240423, rip2);
}

U0 ICOrEqu(CIntermediateCode *tmpi, I64 rip2)
{
        I64 i, bit;

        if (tmpi->arg2.type & MDF_IMM && !(tmpi->arg1.type & MDF_STACK) && tmpi->ic_flags & ICF_RES_NOT_USED)
        {
                i = tmpi->arg2.disp;
                bit = Bsf(i);
                if (0 <= bit == Bsr(i) && i > I8_MAX)
                {
                        tmpi->arg2.disp = bit;
                        tmpi->arg2.reg = 0;
                        tmpi->arg1.type = tmpi->arg1.type & MDG_MASK + RT_I64;
                        ICBitOps(tmpi, &tmpi->arg2, &tmpi->arg1, tmpi, 0xAB0F, 0x28BA0F, rip2);
                        return;
                }
        }
        ICAddSubEctEqu(tmpi, tmpi->arg1_type_pointed_to, tmpi->res.type, tmpi->res.reg, tmpi->res.disp,
                                   tmpi->arg1.type, tmpi->arg1.reg, tmpi->arg1.disp,
                                   tmpi->arg2.type, tmpi->arg2.reg, tmpi->arg2.disp,
                                   0x09010D0C010B, rip2);
}

U0 ICXorEqu(CIntermediateCode *tmpi, I64 rip2)
{
        I64 i, bit;

        if (tmpi->arg2.type & MDF_IMM && !(tmpi->arg1.type & MDF_STACK) && tmpi->ic_flags & ICF_RES_NOT_USED)
        {
                i = tmpi->arg2.disp;
                bit = Bsf(i);
                if (0 <= bit == Bsr(i))
                {
                        tmpi->arg2.disp = bit;
                        tmpi->arg2.reg = 0;
                        tmpi->arg1.type = tmpi->arg1.type & MDG_MASK + RT_I64;
                        ICBitOps(tmpi, &tmpi->arg2, &tmpi->arg1, tmpi, 0xBB0F, 0x38BA0F, rip2);
                        return;
                }
        }
        ICAddSubEctEqu(tmpi, tmpi->arg1_type_pointed_to, tmpi->res.type, tmpi->res.reg,tmpi->res.disp,
                                   tmpi->arg1.type, tmpi->arg1.reg, tmpi->arg1.disp,
                                   tmpi->arg2.type, tmpi->arg2.reg, tmpi->arg2.disp,
                                   0x310635340633, rip2);
}

U0 ICSwitch(CIntermediateCode *tmpi, I64 rip, Bool nobound, CCompCtrl *cc, U8 *buf, I64 rip2)
{
        I64                      i, j, count, min, max, begin, r;
        CCodeMisc       *lb;
        Bool             short_jmp;
        CAOTAbsAddr     *tmpa;

        if (!(tmpi->arg1.type & MDF_REG) || tmpi->arg1.reg & 7 == REG_RSP)
                r = REG_RDX;
        else
                r = tmpi->arg1.reg;
        if (nobound)
                ICMov(tmpi, MDF_REG + RT_I64, r, 0, tmpi->arg1.type, tmpi->arg1.reg, tmpi->arg1.disp, rip2);
        else
        {
                if (tmpi->arg2.type & MDF_IMM)
                {
                        j = tmpi->arg2.disp;
                        ICMov(tmpi, MDF_REG + RT_I64, r, 0, tmpi->arg1.type, tmpi->arg1.reg, tmpi->arg1.disp, rip2);
                        if (I8_MIN <= j <= I8_MAX)
                        {
                                i = 0xF88348 + (r & 7) << 16;
                                if (r > 7)
                                        i++;
                                ICU24(tmpi, i);
                                ICU8(tmpi, j);
                        }
                        else if (I32_MIN <= j <= I32_MAX)
                        {
                                i = 0xF88148 + (r & 7) << 16;
                                if (r > 7)
                                        i++;
                                ICU24(tmpi, i);
                                ICU32(tmpi, j);
                        }
                        else
                        {
                                ICMov(tmpi, MDF_REG + RT_I64, REG_RCX, 0, tmpi->arg2.type, tmpi->arg2.reg, tmpi->arg2.disp, rip2);
                                i = 0xC13B48 + (r & 7) << 19;
                                if (r > 7)
                                        i += 4;
                                ICU24(tmpi, i);
                        }
                }
                else
                {
                        ICMov(tmpi, MDF_REG + RT_I64, REG_RCX,  0, tmpi->arg2.type, tmpi->arg2.reg, tmpi->arg2.disp, rip2);
                        ICMov(tmpi, MDF_REG + RT_I64, r,                0, tmpi->arg1.type, tmpi->arg1.reg, tmpi->arg1.disp, rip2);
                        i = 0xC13B48 + (r & 7) << 19;
                        if (r > 7)
                                i += 4;
                        ICU24(tmpi, i);
                }

                rip += tmpi->ic_count;
                lb = tmpi->ic_data(CCodeMisc *)->default;
                short_jmp = ToBool(tmpi->ic_flags & ICF_SHORT_JMP);
                if (!buf && lb->addr != INVALID_PTR)
                {
                        i = lb->addr - (rip + 2);
                        if (I8_MIN <= i <= I8_MAX)
                                short_jmp = TRUE;
                }
                if (short_jmp)
                {
                        tmpi->ic_flags |= ICF_SHORT_JMP;
                        ICU16(tmpi, (lb->addr - (rip + 2)) << 8 + 0x73);
                }
                else
                {
                        tmpi->ic_flags &= ~ICF_SHORT_JMP;
                        ICU16(tmpi, 0x830F);
                        ICU32(tmpi, lb->addr - (rip + 6));
                }
        }

        lb = tmpi->ic_data;
        begin = lb->begin->addr;
        if (!buf && begin != INVALID_PTR)
        {
                min = I64_MAX;
                max = I64_MIN;
                for (i = 0; i < lb->range; i++)
                {
                        if (lb->jmp_table[i]->addr == INVALID_PTR)
                        {
                                min = I64_MIN;
                                max = I64_MAX;
                                break;
                        }
                        else
                        {
                                j = lb->jmp_table[i]->addr-begin;
                                min = MinI64(min, j);
                                max = MaxI64(max, j);
                        }
                }
                if (I8_MIN <= min <= max <= I8_MAX)
                        lb->flags |= CMF_I8_JMP_TABLE;
                else if (U8_MIN <= min <= max <= U8_MAX)
                        lb->flags |= CMF_U8_JMP_TABLE;
                else if (I16_MIN <= min <= max <= I16_MAX)
                        lb->flags |= CMF_I16_JMP_TABLE;
                else if (U16_MIN <= min <= max <= U16_MAX)
                        lb->flags |= CMF_U16_JMP_TABLE;
        }

        if (lb->flags & CMF_I8_JMP_TABLE)
        {
                if (r < 8)
                        ICU8(tmpi, 0x48);
                else
                        ICU8(tmpi, 0x49);
                ICU24(tmpi, 0x98BE0F + (r & 7) << 16);
                count = 1;
        }
        else if (lb->flags & CMF_U8_JMP_TABLE)
        {
                if (r < 8)
                        count = 2;
                else
                {
                        ICU8(tmpi, 0x49);
                        count = 1;
                }
                ICU24(tmpi, 0x98B60F + (r & 7) << 16);
        }
        else if (lb->flags & CMF_I16_JMP_TABLE)
        {
                if (r < 8)
                        ICU8(tmpi, 0x48);
                else
                        ICU8(tmpi, 0x4A);
                ICU32(tmpi, 0x451CBF0F + (r & 7) << 27);
                count = 0;
        }
        else if (lb->flags & CMF_U16_JMP_TABLE)
        {
                if (r < 8)
                        count = 1;
                else {
                        ICU8(tmpi, 0x4A);
                        count = 0;
                }
                ICU32(tmpi, 0x451CB70F + (r & 7) << 27);
        }
        else
        {
                if (r < 8)
                        count = 2;
                else {
                        ICU8(tmpi, 0x42);
                        count = 1;
                }
                ICU24(tmpi, 0x851C8B + (r & 7) << 19);
        }
        if (buf && cc->flags & CCF_AOT_COMPILE)
        {
                tmpa = CAlloc(sizeof(CAOTAbsAddr));
                tmpa->next = cc->aotc->abss;
                tmpa->type = AAT_ADD_U32;
                cc->aotc->abss = tmpa;
                tmpa->rip = rip2 + tmpi->ic_count;
                ICU32(tmpi, lb->addr + cc->aotc->rip);
        }
        else
                ICU32(tmpi, lb->addr+buf);

        if (lb->flags & (CMF_I8_JMP_TABLE | CMF_U8_JMP_TABLE | CMF_I16_JMP_TABLE | CMF_U16_JMP_TABLE))
        {
                ICU16(tmpi, 0xC381); //ADD EBX,0x12345678
                if (buf && cc->flags & CCF_AOT_COMPILE)
                {
                        tmpa = CAlloc(sizeof(CAOTAbsAddr));
                        tmpa->next = cc->aotc->abss;
                        tmpa->type = AAT_ADD_U32;
                        cc->aotc->abss = tmpa;
                        tmpa->rip = rip2 + tmpi->ic_count;
                        ICU32(tmpi, begin + cc->aotc->rip);
                }
                else
                        ICU32(tmpi, begin + buf);
        }
        else
                count += 6;
        ICU16(tmpi, 0xE3FF); //JMP EBX
        for (i = 0; i < count; i++) //Code must always shrink, not expand
                ICU8(tmpi, OC_NOP);
        tmpi->ic_flags &= ~ICF_CODE_FINAL;
}

U0 ICLocalVarInit(CIntermediateCode *tmpi)
{
        ICU24(tmpi, 0xC48B48);
        ICU16(tmpi, 0x5748);
        ICU24(tmpi, 0xF88B48);
        ICU24(tmpi, 0xC1C748);
        ICU32(tmpi, tmpi->ic_data);
        ICU16(tmpi, sys_var_init_val << 8 + 0xB0);
        ICU24(tmpi, 0xAA48F3);
        ICU16(tmpi, 0x5F48);
}