#define CN_A2   0
#define CN_A1   1
#define CN_INST 2
#define CN_RES  3

U0 CompNoteFloatOp(CCompCtrl *cc, CIntermediateCode *tmpi, Bool dont_pushable, Bool dont_popable, I64 pos)
{
        Bool link = FALSE;

        if (cc->pass == 7 && cc->last_float_op_ic && cc->last_dont_popable && dont_pushable)
        {
                switch [pos]
                {
                        case CN_A2:
                                if (cc->last_float_op_ic != tmpi && cc->dont_push_float)
                                        link = TRUE;
                                break;

                        case CN_A1:
                                if (cc->last_float_op_ic != tmpi && cc->dont_push_float)
                                        link = TRUE;
                                break;

                        case CN_INST:
                                if (cc->last_float_op_ic != tmpi)
                                {
                                        if (cc->dont_push_float)
                                        {
                                                if (intermediate_code_table[tmpi->ic_code].arg_count == IS_2_ARG &&
                                                                cc->last_float_op_ic->res.reg != REG_R8)
                                                        tmpi->ic_flags |= ICF_ALT_TEMPLATE;
                                                else
                                                        tmpi->ic_flags &= ~ICF_ALT_TEMPLATE;
                                                link = TRUE;
                                        }
                                }
                                else
                                {
                                        if (intermediate_code_table[tmpi->ic_code].arg_count == IS_2_ARG && cc->last_float_op_pos != CN_A1)
                                                tmpi->ic_flags |= ICF_ALT_TEMPLATE;
                                        else
                                                tmpi->ic_flags &= ~ICF_ALT_TEMPLATE;
                                        link = TRUE;
                                }
                                break;

                        case CN_RES:
                                if (cc->last_float_op_ic == tmpi && cc->last_float_op_pos == CN_INST)
                                        link = TRUE;
                                break;
                }
                if (link)
                {
                        if (!Bts(&cc->last_float_op_ic->ic_flags, ICf_DONT_POP_FLOAT0 + cc->last_ic_float_op_num))
                                cc->last_float_op_ic->ic_flags &= ~ICF_CODE_FINAL;
                        if (!Bts(&tmpi->ic_flags, ICf_DONT_PUSH_FLOAT0 + cc->cur_ic_float_op_num))
                                tmpi->ic_flags &= ~ICF_CODE_FINAL;
                }
        }
        cc->last_float_op_ic     = tmpi;
        cc->last_dont_pushable   = dont_pushable;
        cc->last_dont_popable    = dont_popable;
        cc->last_ic_float_op_num = cc->cur_ic_float_op_num++;
        cc->last_float_op_pos    = pos;
        if (cc->cur_ic_float_op_num > 4)
                throw('Compiler');
}

U0 CompSetFloatOpPushPop(CCompCtrl *cc, CIntermediateCode *tmpi, Bool *dont_push_float, Bool *dont_pop_float)
{
        if (cc->pass == 7)
        {
                *dont_push_float = FALSE;
                *dont_pop_float  = FALSE;
                tmpi->ic_flags &= ~ICF_CODE_FINAL;
        }
        else
        {
                *dont_push_float = Bt(&tmpi->ic_flags, ICf_DONT_PUSH_FLOAT0 + cc->cur_ic_float_op_num);
                *dont_pop_float  = Bt(&tmpi->ic_flags, ICf_DONT_POP_FLOAT0  + cc->cur_ic_float_op_num);
        }
}

U0 ICCopyTemplate(CCompCtrl *cc, CIntermediateCode *tmpi, I64 op,
                                  Bool off_the_record, Bool dont_pushable, Bool dont_popable, I64 pos)
{
        Bool dont_push_float, dont_pop_float, alt;
        U8  *ptr;
        I64  i = 0;

        if (!off_the_record)
        {
                if (tmpi->ic_flags & ICF_ALT_TEMPLATE)
                        alt = TRUE;
                else
                        alt = FALSE;
                CompSetFloatOpPushPop(cc, tmpi, &dont_push_float, &dont_pop_float);
        }
        else
        {
                dont_push_float = FALSE;
                dont_pop_float  = FALSE;
                alt = FALSE;
        }
        if (alt && dont_push_float && !dont_pop_float)
        {
                ptr = comp_templates_dont_push2[op];
                i   = comp_templates_dont_push2[op + 1] - ptr;
        }
        if (!i)
        {
                if (dont_push_float)
                {
                        if (dont_pop_float)
                        {
                                ptr = comp_templates_dont_push_pop[op];
                                i   = comp_templates_dont_push_pop[op + 1] - ptr;
                        }
                        else
                        {
                                ptr = comp_templates_dont_push[op];
                                i   = comp_templates_dont_push[op + 1] - ptr;
                        }
                }
                else
                {
                        if (dont_pop_float)
                        {
                                ptr = comp_templates_dont_pop[op];
                                i   = comp_templates_dont_pop[op + 1] - ptr;
                        }
                        else
                        {
                                ptr = comp_templates[op];
                                i   = comp_templates[op + 1] - ptr;
                        }
                }
        }
        MemCopy(&tmpi->ic_body[tmpi->ic_count], ptr, i);
        if (!off_the_record)
                CompNoteFloatOp(cc, tmpi, dont_pushable, dont_popable, pos);
        tmpi->ic_count += i;
}

U0 ICFConvert(CCompCtrl *cc, CIntermediateCode *tmpi, I64 r1, CICType t2, I64 r2, I64 d2, Bool to_int, I64 pos, I64 rip)
{
        I64  rsp_size = 0, op1, op2;
        Bool dont_push_float, dont_pop_float;

        if (to_int)
        {
                op1 = SLASH_OP_FLD;
                op2 = SLASH_OP_FISTTP;
        }
        else
        {
                op1 = SLASH_OP_FILD;
                op2 = SLASH_OP_FSTP;
        }

        CompSetFloatOpPushPop(cc, tmpi, &dont_push_float, &dont_pop_float);
        if (!dont_push_float)
        {
                if (!(t2.raw_type >= RT_I64 && t2 & MDG_DISP_SIB_RIP))
                {
                        ICPush(tmpi, t2, r2, d2, rip);
                        t2 = MDF_SIB + RT_I64;
                        r2 = REG_RSP + REG_RSP << 8;
                        d2 = 0;
                        rsp_size = 8;
                }
                else
                {
                        if (!dont_pop_float)
                        {
                                rsp_size = 8;
                                ICAddRSP(tmpi, -8);
                        }
                }
                ICSlashOp(tmpi, t2, r2, d2, op1, rip);
        }
        else
        {
                if (!dont_pop_float)
                {
                        rsp_size = 8;
                        ICAddRSP(tmpi, -8);
                }
        }
        if (to_int)
                CompNoteFloatOp(cc, tmpi, TRUE, FALSE, pos);
        else
                CompNoteFloatOp(cc, tmpi, FALSE, TRUE, pos);
        if (dont_pop_float)
        {
                if (rsp_size)
                        ICAddRSP(tmpi, rsp_size);
        }
        else
        {
                ICSlashOp(tmpi, MDF_SIB + RT_I64, REG_RSP + REG_RSP << 8, 0, op2, rip);
                ICPop(tmpi, MDF_REG + RT_I64, r1, 0, rip);
        }
}

U0 ICFConvert2(CCompCtrl *cc, CIntermediateCode *tmpi, I64 r1, CICType t2, I64 r2, I64 d2, Bool to_int, I64 rip)
{
        I64 rsp_size = 0, op1, op2;

        if (to_int)
        {
                op1 = SLASH_OP_FLD;
                op2 = SLASH_OP_FISTTP;
        }
        else
        {
                op1 = SLASH_OP_FILD;
                op2 = SLASH_OP_FSTP;
        }
        if (!(t2.raw_type >= RT_I64 && t2 & MDG_DISP_SIB_RIP))
        {
                ICPush(tmpi, t2, r2, d2, rip);
                t2 = MDF_SIB + RT_I64;
                r2 = REG_RSP + REG_RSP << 8;
                d2 = 0;
                rsp_size = 8;
        }
        else
        {
                rsp_size = 8;
                ICAddRSP(tmpi, -8);
        }
        ICSlashOp(tmpi, t2, r2, d2, op1, rip);
        ICSlashOp(tmpi, MDF_SIB + RT_I64, REG_RSP + REG_RSP << 8, 0, op2, rip);
        ICPop(tmpi, MDF_REG + RT_I64, r1, 0, rip);
        cc->last_dont_pushable = cc->last_dont_popable = FALSE; //TODO: improve this
}

U0 ICFUnaryMinus(CCompCtrl *cc, CIntermediateCode *tmpi, U8 *buf2, I64 rip)
{
        CICArg  *arg1 = &tmpi->arg1;
        I64              rsp_size = 0, builtin1 = 0, t1, r1, d1;
        Bool     dont_push_float, dont_pop_float;

        if (cc->flags & CCF_AOT_COMPILE)
                buf2 = cc->aotc->rip;

        CompSetFloatOpPushPop(cc, tmpi, &dont_push_float, &dont_pop_float);
        if (!dont_push_float)
        {
                if (arg1->type.raw_type >= RT_I64 && arg1->type & MDG_DISP_SIB_RIP)
                {
                        t1 = arg1->type;
                        r1 = arg1->reg;
                        d1 = arg1->disp;
                }
                else
                {
                        if (arg1->type & MDF_IMM)
                        {
                                if (!(builtin1 = ICBuiltInFloatConst(arg1->disp(F64))))
                                {
                                        t1 = MDF_RIP_DISP32 + RT_I64;
                                        r1 = REG_RIP;
                                        d1 = COCFloatConstFind(cc, arg1->disp(F64)) + buf2;
                                }
                        }
                        else
                        {
                                ICPush(tmpi, arg1->type, arg1->reg, arg1->disp, rip);
                                t1 = MDF_SIB + RT_I64;
                                r1 = REG_RSP + REG_RSP << 8;
                                d1 = 0;
                                rsp_size += 8;
                        }
                }
                if (builtin1)
                        ICU16(tmpi, builtin1);
                else
                        ICSlashOp(tmpi, t1, r1, d1, SLASH_OP_FLD, rip);
        }
        if (!dont_pop_float && !rsp_size)
        {
                rsp_size = 8;
                ICAddRSP(tmpi, -8);
        }
        ICU16(tmpi, 0xE0D9); //FCHS
        CompNoteFloatOp(cc, tmpi, TRUE, TRUE, CN_INST);
        if (dont_pop_float)
        {
                if (rsp_size)
                        ICAddRSP(tmpi, rsp_size);
        }
        else
        {
                ICSlashOp(tmpi, MDF_SIB + RT_I64, REG_RSP + REG_RSP << 8, 0, SLASH_OP_FSTP, rip);
                ICPop(tmpi, tmpi->res.type, tmpi->res.reg, tmpi->res.disp, rip);
        }
}

U0 ICFMod(CCompCtrl *cc, CIntermediateCode *tmpi, I64 rip)
{//for MOD
        Bool dont_push_float, dont_pop_float;

        CompSetFloatOpPushPop(cc, tmpi, &dont_push_float, &dont_pop_float);
        if (dont_push_float)
        {
                if (tmpi->ic_flags & ICF_ALT_TEMPLATE)
                        ICMov(tmpi, MDF_REG + RT_I64, REG_RAX, 0, tmpi->arg1.type, tmpi->arg1.reg, tmpi->arg1.disp, rip);
                else
                        ICMov(tmpi, MDF_REG + RT_I64, REG_RAX, 0, tmpi->arg2.type, tmpi->arg2.reg, tmpi->arg2.disp, rip);
        }
        else
        {
                ICMov(tmpi, MDF_REG + RT_I64, REG_RAX, 0, tmpi->arg2.type, tmpi->arg2.reg, tmpi->arg2.disp, rip);
                ICMov(tmpi, MDF_REG + RT_I64, REG_RDX, 0, tmpi->arg1.type, tmpi->arg1.reg, tmpi->arg1.disp, rip);
        }
//TODO: unpushable,unpop?  Not sure
        ICCopyTemplate(cc, tmpi, CMP_TEMPLATE_MOD, FALSE, FALSE, FALSE, CN_INST);
        if (!dont_pop_float)
                ICMov(tmpi, tmpi->res.type, tmpi->res.reg, tmpi->res.disp, MDF_REG + RT_I64, REG_RAX, 0, rip);
}

U0 ICFPow(CCompCtrl *cc, CIntermediateCode *tmpi, U8 *buf, I64 rip)
{//for POW
        I64                                      i;
        CAOTImportExport        *tmpie;
        CHashExport                     *tmpex = HashFind("SYS_POW", cc->htc.hash_table_list, HTT_EXPORT_SYS_SYM);

        ICMov(tmpi, MDF_REG + RT_I64, REG_RAX, 0, tmpi->arg2.type, tmpi->arg2.reg, tmpi->arg2.disp, rip);
        ICMov(tmpi, MDF_REG + RT_I64, REG_RDX, 0, tmpi->arg1.type, tmpi->arg1.reg, tmpi->arg1.disp, rip);
        if (cc->flags & CCF_AOT_COMPILE)
        {
                if (!tmpex)
                {
                        tmpex           = CAlloc(sizeof(CHashExport));
                        tmpex->str      = StrNew("SYS_POW");
                        tmpex->type     = HTT_EXPORT_SYS_SYM | HTF_UNRESOLVED | HTF_IMPORT;
                        HashAdd(tmpex, cc->htc.global_hash_table);
                }
                if (tmpex->type & HTF_IMPORT)
                {
                        if (OptionGet(OPTf_USE_IMM64))
                        {
                                ICU16(tmpi, 0xBB48);
                                ICU64(tmpi, 0);
                                if (buf)
                                {
                                        tmpie           = CAlloc(sizeof(CAOTImportExport));
                                        tmpie->type     = IET_IMM_I64;
                                        tmpie->rip      = rip + tmpi->ic_count - 8;
                                        tmpie->next     = tmpex->ie_list;
                                        tmpex->ie_list = tmpie;
                                }
                                ICU16(tmpi, 0xD3FF);
                        }
                        else
                        {
                                ICU8(tmpi, 0xE8);
                                ICU32(tmpi, -(rip + tmpi->ic_count + 4));
                                if (buf)
                                {
                                        tmpie           = CAlloc(sizeof(CAOTImportExport));
                                        tmpie->type     = IET_REL_I32;
                                        tmpie->rip      = rip + tmpi->ic_count - 4;
                                        tmpie->next     = tmpex->ie_list;
                                        tmpex->ie_list = tmpie;
                                }
                        }
                }
                else
                {//Kernel
                        if (tmpex->type & HTF_UNRESOLVED)
                                throw('Compiler');
                        else
                        {
                                i = tmpex->val - (rip + tmpi->ic_count + 5);
                                if (!(I32_MIN <= i <= I32_MAX))
                                {
                                        throw('Compiler');
                                        // ICU16(tmpi, 0xBB48);
                                        // ICU64(tmpi, tmpex->val);
                                        // ICU16(tmpi, 0xD3FF);
                                }
                                else
                                {
                                        ICU8(tmpi, 0xE8);
                                        ICU32(tmpi, i);
                                }
                        }
                }
        }
        else
        {
                i = tmpex->val - (rip + tmpi->ic_count + 5);
                if (!(I32_MIN <= i <= I32_MAX))
                {
                        ICU16(tmpi, 0xBB48);
                        ICU64(tmpi, tmpex->val);
                        ICU16(tmpi, 0xD3FF);
                }
                else
                {
                        ICU8(tmpi, 0xE8);
                        ICU32(tmpi, i);
                }
        }
        tmpi->ic_flags &= ~ICF_CODE_FINAL;
        ICMov(tmpi, tmpi->res.type, tmpi->res.reg, tmpi->res.disp, MDF_REG + RT_I64, REG_RAX, 0, rip);
}

U0 ICFOp(CCompCtrl *cc, CIntermediateCode *tmpi, I64 op, U8 *buf2, I64 rip)
{//for ADD,SUB,DIV,MUL
        CICArg  *arg1, *arg2;
        Bool     dont_push_float, dont_pop_float, alt;
        I64              rsp_size = 0, builtin1 = 0, builtin2 = 0, t1, r1, d1, t2, r2, d2;

        if (tmpi->ic_flags & ICF_ALT_TEMPLATE)
        {
                arg1 = &tmpi->arg2;
                arg2 = &tmpi->arg1;
                alt = TRUE;
        }
        else
        {
                arg1 = &tmpi->arg1;
                arg2 = &tmpi->arg2;
                alt = FALSE;
        }

        if (cc->flags & CCF_AOT_COMPILE)
                buf2 = cc->aotc->rip;

        CompSetFloatOpPushPop(cc, tmpi, &dont_push_float, &dont_pop_float);
        if (dont_push_float)
        {
                if (arg2->type.raw_type >= RT_I64 && arg2->type & MDG_DISP_SIB_RIP)
                {
                        t2 = arg2->type;
                        r2 = arg2->reg;
                        d2 = arg2->disp;
                }
                else
                {
                        if (arg2->type & MDF_IMM)
                        {
                                if (!(builtin2 = ICBuiltInFloatConst(arg2->disp(F64))))
                                {
                                        t2 = MDF_RIP_DISP32 + RT_I64;
                                        r2 = REG_RIP;
                                        d2 = COCFloatConstFind(cc, arg2->disp(F64)) + buf2;
                                }
                        }
                        else
                        {
                                ICPush(tmpi,arg2->type, arg2->reg, arg2->disp, rip);
                                t2 = MDF_SIB + RT_I64;
                                r2 = REG_RSP + REG_RSP << 8;
                                d2 = 0;
                                rsp_size += 8;
                        }
                }
        }
        else
        {
                if (alt)
                {
                        if (!(arg2->type & MDF_STACK))
                        {
                                if (arg1->type.raw_type >= RT_I64 && arg1->type & MDG_DISP_SIB_RIP)
                                {
                                        t1 = arg1->type;
                                        r1 = arg1->reg;
                                        d1 = arg1->disp;
                                }
                                else
                                {
                                        if (arg1->type & MDF_IMM)
                                        {
                                                if (!(builtin1 = ICBuiltInFloatConst(arg1->disp(F64))))
                                                {
                                                        t1 = MDF_RIP_DISP32 + RT_I64;
                                                        r1 = REG_RIP;
                                                        d1 = COCFloatConstFind(cc, arg1->disp(F64)) + buf2;
                                                }
                                        }
                                        else
                                        {
                                                ICPush(tmpi, arg1->type, arg1->reg, arg1->disp, rip);
                                                t1 = MDF_SIB + RT_I64;
                                                r1 = REG_RSP + REG_RSP << 8;
                                                d1 = 0;
                                                rsp_size+=8;
                                        }
                                }
                                if (arg2->type.raw_type >= RT_I64 && arg2->type & MDG_DISP_SIB_RIP)
                                {
                                        t2 = arg2->type;
                                        r2 = arg2->reg;
                                        d2 = arg2->disp;
                                }
                                else
                                {
                                        if (arg2->type & MDF_IMM)
                                        {
                                                if (!(builtin2 = ICBuiltInFloatConst(arg2->disp(F64))))
                                                {
                                                        t2 = MDF_RIP_DISP32 + RT_I64;
                                                        r2 = REG_RIP;
                                                        d2 = COCFloatConstFind(cc, arg2->disp(F64)) + buf2;
                                                }
                                        }
                                        else
                                        {
                                                ICPush(tmpi, arg2->type, arg2->reg, arg2->disp, rip);
                                                t2 = MDF_SIB + RT_I64;
                                                r2 = REG_RSP + REG_RSP << 8;
                                                d2 = 0;
                                                rsp_size += 8;
                                                if (r1 == REG_RSP + REG_RSP << 8)
                                                        d1 += 8;
                                        }
                                }
                        }
                        else
                        {
                                ICMov(tmpi, MDF_REG +RT_I64, REG_RDX, 0, arg1->type, arg1->reg, arg1->disp, rip);
                                ICMov(tmpi, MDF_REG +RT_I64, REG_RAX, 0, arg2->type, arg2->reg, arg2->disp, rip);
                                ICU16(tmpi, 0x5052); //PUSH EDX PUSH EAX
                                rsp_size = 16;
                                t1 = MDF_SIB + RT_I64;
                                r1 = REG_RSP + REG_RSP << 8;
                                d1 = 8;
                                t2 = MDF_SIB + RT_I64;
                                r2 = REG_RSP + REG_RSP << 8;
                                d2 = 0;
                        }
                }
                else
                {
                        if (!(arg1->type & MDF_STACK))
                        {
                                if (arg2->type.raw_type >= RT_I64 && arg2->type & MDG_DISP_SIB_RIP)
                                {
                                        t2 = arg2->type;
                                        r2 = arg2->reg;
                                        d2 = arg2->disp;
                                }
                                else
                                {
                                        if (arg2->type & MDF_IMM)
                                        {
                                                if (!(builtin2 = ICBuiltInFloatConst(arg2->disp(F64))))
                                                {
                                                        t2 = MDF_RIP_DISP32 + RT_I64;
                                                        r2 = REG_RIP;
                                                        d2 = COCFloatConstFind(cc, arg2->disp(F64)) + buf2;
                                                }
                                        }
                                        else
                                        {
                                                ICPush(tmpi, arg2->type, arg2->reg, arg2->disp, rip);
                                                t2 = MDF_SIB + RT_I64;
                                                r2 = REG_RSP + REG_RSP << 8;
                                                d2 = 0;
                                                rsp_size += 8;
                                        }
                                }
                                if (arg1->type.raw_type >= RT_I64 && arg1->type & MDG_DISP_SIB_RIP)
                                {
                                        t1 = arg1->type;
                                        r1 = arg1->reg;
                                        d1 = arg1->disp;
                                }
                                else
                                {
                                        if (arg1->type & MDF_IMM)
                                        {
                                                if (!(builtin1 = ICBuiltInFloatConst(arg1->disp(F64))))
                                                {
                                                        t1 = MDF_RIP_DISP32 + RT_I64;
                                                        r1 = REG_RIP;
                                                        d1 = COCFloatConstFind(cc, arg1->disp(F64)) + buf2;
                                                }
                                        }
                                        else
                                        {
                                                ICPush(tmpi, arg1->type, arg1->reg, arg1->disp, rip);
                                                t1 = MDF_SIB + RT_I64;
                                                r1 = REG_RSP + REG_RSP << 8;
                                                d1 = 0;
                                                rsp_size += 8;
                                                if (r2 == REG_RSP + REG_RSP << 8)
                                                        d2 += 8;
                                        }
                                }
                        }
                        else
                        {
                                ICMov(tmpi, MDF_REG + RT_I64, REG_RAX, 0, arg2->type, arg2->reg, arg2->disp, rip);
                                ICMov(tmpi, MDF_REG + RT_I64, REG_RDX, 0, arg1->type, arg1->reg, arg1->disp, rip);
                                ICU16(tmpi, 0x5052); //PUSH EDX PUSH EAX
                                rsp_size = 16;
                                t1 = MDF_SIB + RT_I64;
                                r1 = REG_RSP + REG_RSP << 8;
                                d1 = 8;
                                t2 = MDF_SIB + RT_I64;
                                r2 = REG_RSP + REG_RSP << 8;
                                d2 = 0;
                        }
                }
        }
        if (!dont_pop_float && !rsp_size)
        {
                rsp_size = 8;
                ICAddRSP(tmpi, -8);
        }
        if (!dont_push_float)
        {
                if (builtin2 && !builtin1)
                {
                        alt = !alt;
                        SwapI64(&t1, &t2);
                        SwapI64(&r1, &r2);
                        SwapI64(&d1, &d2);
                        SwapI64(&builtin1, &builtin2);
                }
                if (builtin1)
                        ICU16(tmpi, builtin1);
                else
                        ICSlashOp(tmpi, t1, r1, d1, SLASH_OP_FLD, rip);
        }
        if (alt)
                switch (op.u8[0])
                {
                        case 4:
                                op = SLASH_OP_FSUBR;
                                break;

                        case 6:
                                op = SLASH_OP_FDIVR;
                                break;
                }
        if (builtin2)
        {
                ICU16(tmpi, builtin2);
                ICU16(tmpi, op.u16[2]);
        }
        else
                ICSlashOp(tmpi, t2, r2, d2, op, rip);
        CompNoteFloatOp(cc, tmpi, TRUE, TRUE, CN_INST);
        if (dont_pop_float)
        {
                if (rsp_size)
                        ICAddRSP(tmpi, rsp_size);
        }
        else
        {
                if (rsp_size == 8)
                        ICSlashOp(tmpi, MDF_SIB + RT_I64, REG_RSP + REG_RSP << 8, 0, SLASH_OP_FSTP, rip);
                else if (rsp_size > 8)
                {
                        ICSlashOp(tmpi, MDF_SIB + RT_I64, REG_RSP + REG_RSP << 8, rsp_size - 8, SLASH_OP_FSTP, rip);
                        ICAddRSP(tmpi, rsp_size - 8);
                }
                ICPop(tmpi, tmpi->res.type, tmpi->res.reg, tmpi->res.disp, rip);
        }
}

U0 ICFCmp(CCompCtrl *cc, CIntermediateCode *tmpi, I64 op, I64 rip)
{
        Bool dont_push_float, dont_pop_float;

        CompSetFloatOpPushPop(cc, tmpi, &dont_push_float, &dont_pop_float);
        if (dont_push_float)
        {
                if (tmpi->ic_flags & ICF_ALT_TEMPLATE)
                {
                        if (tmpi->ic_flags & ICF_POP_CMP)
                                ICPopRegs(tmpi, 1 << REG_RAX);
                        else
                                ICMov(tmpi, MDF_REG + RT_I64, REG_RAX, 0, tmpi->arg1.type, tmpi->arg1.reg, tmpi->arg1.disp, rip);
                }
                else
                        ICMov(tmpi, MDF_REG + RT_I64, REG_RAX, 0, tmpi->arg2.type, tmpi->arg2.reg, tmpi->arg2.disp, rip);
        }
        else
        {
                ICMov(tmpi, MDF_REG + RT_I64, REG_RAX, 0, tmpi->arg2.type, tmpi->arg2.reg, tmpi->arg2.disp, rip);
                if (tmpi->ic_flags & ICF_POP_CMP)
                        ICPopRegs(tmpi, 1 << REG_RDX);
                else
                        ICMov(tmpi, MDF_REG + RT_I64, REG_RDX, 0, tmpi->arg1.type, tmpi->arg1.reg, tmpi->arg1.disp, rip);
        }
        if (tmpi->ic_flags & ICF_PUSH_CMP)
                ICPushRegs(tmpi, 1 << REG_RAX);
        ICCopyTemplate(cc, tmpi, op, FALSE, TRUE, FALSE, CN_INST);
        ICMov(tmpi, tmpi->res.type, tmpi->res.reg, tmpi->res.disp, MDF_REG + RT_I64, REG_RAX, 0, rip);
}

U0 ICFModEqu(CCompCtrl *cc, CIntermediateCode *tmpi, I64 rip)
{
        Bool dont_push_float, dont_pop_float;

        CompSetFloatOpPushPop(cc, tmpi, &dont_push_float, &dont_pop_float);
        if (tmpi->ic_flags & ICF_BY_VAL)
        {
                if (dont_push_float)
                {
                        ICMov(tmpi, MDF_REG + RT_I64, REG_RAX, 0,
                                  tmpi->arg1.type & MDG_MASK + tmpi->arg1_type_pointed_to,
                                  tmpi->arg1.reg, tmpi->arg1.disp, rip);
                        if (tmpi->arg1_type_pointed_to != RT_F64)
                                ICFConvert2(cc, tmpi, REG_RAX, MDF_REG + RT_I64, REG_RAX, 0, FALSE, rip);
                }
                else
                {
                        ICMov(tmpi, MDF_REG + RT_I64, REG_RAX, 0, tmpi->arg2.type, tmpi->arg2.reg, tmpi->arg2.disp, rip);
                        ICMov(tmpi, MDF_REG + RT_I64, REG_RDX, 0,
                                  tmpi->arg1.type & MDG_MASK + tmpi->arg1_type_pointed_to,
                                  tmpi->arg1.reg, tmpi->arg1.disp, rip);
                        if (tmpi->arg1_type_pointed_to != RT_F64)
                                ICFConvert2(cc, tmpi, REG_RDX, MDF_REG + RT_I64, REG_RDX, 0, FALSE, rip);
                }
//TODO: unpushable,unpop?  Not sure
                ICCopyTemplate(cc, tmpi, CMP_TEMPLATE_MOD, FALSE, FALSE, FALSE, CN_INST);
                if (tmpi->arg1_type_pointed_to != RT_F64)
                        ICFConvert2(cc, tmpi, REG_RAX, MDF_REG + RT_I64, REG_RAX, 0, TRUE, rip);
                ICMov(tmpi, tmpi->arg1.type & MDG_MASK + tmpi->arg1_type_pointed_to,
                          tmpi->arg1.reg, tmpi->arg1.disp, MDF_REG + RT_I64, REG_RAX, 0, rip);
                if (tmpi->res.type.mode)
                        ICMov(tmpi, tmpi->res.type, 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 (dont_push_float)
                {
                        ICMov(tmpi, MDF_REG + RT_I64, REG_RCX, 0, tmpi->arg1.type, tmpi->arg1.reg, tmpi->arg1.disp, rip);
                        ICMov(tmpi, MDF_REG + RT_I64, REG_RAX, 0, MDF_DISP + tmpi->arg1_type_pointed_to, REG_RCX, 0, rip);
                        if (tmpi->arg1_type_pointed_to != RT_F64)
                                ICFConvert2(cc, tmpi, REG_RAX, MDF_REG + RT_I64, REG_RAX, 0, FALSE, rip);
                }
                else
                {
                        ICMov(tmpi, MDF_REG + RT_I64, REG_RAX, 0, tmpi->arg2.type, tmpi->arg2.reg, tmpi->arg2.disp, rip);
                        ICMov(tmpi, MDF_REG + RT_I64, REG_RCX, 0, tmpi->arg1.type, tmpi->arg1.reg, tmpi->arg1.disp, rip);
                        ICMov(tmpi, MDF_REG + RT_I64, REG_RDX, 0, MDF_DISP + tmpi->arg1_type_pointed_to, REG_RCX, 0, rip);
                        if (tmpi->arg1_type_pointed_to != RT_F64)
                                ICFConvert2(cc, tmpi, REG_RDX, MDF_REG + RT_I64, REG_RDX, 0, FALSE, rip);
                }
//TODO: unpushable,unpop?  Not sure
                ICCopyTemplate(cc, tmpi, CMP_TEMPLATE_MOD, FALSE, FALSE, FALSE, CN_INST);
                if (tmpi->arg1_type_pointed_to != RT_F64)
                        ICFConvert2(cc, tmpi, REG_RAX, MDF_REG + RT_I64, REG_RAX, 0, TRUE, rip);
                ICMov(tmpi, MDF_DISP + tmpi->arg1_type_pointed_to, REG_RCX, 0, MDF_REG + RT_I64, REG_RAX, 0, rip);
                if (tmpi->res.type.mode)
                        ICMov(tmpi, tmpi->res.type, tmpi->res.reg, tmpi->res.disp, MDF_REG + RT_I64, REG_RAX, 0, rip);
        }
}