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, 0x########
        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);  // MOV  U64 RAX, U64 RSP
    ICU16(tmpi, 0x5748);    // PUSH U64 RDI
    ICU24(tmpi, 0xF88B48);  // MOV  U64 RDI, U64 RAX
    ICU24(tmpi, 0xC1C748);  // MOV  U64 RCX, I32 0x########
    ICU32(tmpi, tmpi->ic_data);
    ICU16(tmpi, sys_var_init_val << 8 + 0xB0); // MOV AL, sys_var_init_val
    ICU24(tmpi, 0xAA48F3);  // REP_STOSB
    ICU16(tmpi, 0x5F48);    // POP  U64 RDI
}