void emitter::emitIns_R_R_I()

in src/coreclr/jit/emitloongarch64.cpp [952:1449]


void emitter::emitIns_R_R_I(
    instruction ins, emitAttr attr, regNumber reg1, regNumber reg2, ssize_t imm, insOpts opt /* = INS_OPTS_NONE */)
{
    code_t code = emitInsCode(ins);

    if ((INS_slli_w <= ins) && (ins <= INS_rotri_w))
    {
#ifdef DEBUG
        switch (ins)
        {
            case INS_slli_w:
            case INS_srli_w:
            case INS_srai_w:
            case INS_rotri_w:
                break;
            default:
                NYI_LOONGARCH64("illegal ins within emitIns_R_R_I --1!");
        }
#endif

        assert(isGeneralRegister(reg1));
        assert(isGeneralRegisterOrR0(reg2));
        assert((0 <= imm) && (imm <= 0x1f));

        code |= reg1;               // rd
        code |= reg2 << 5;          // rj
        code |= (imm & 0x1f) << 10; // ui5
    }
    else if ((INS_slli_d <= ins) && (ins <= INS_rotri_d))
    {
#ifdef DEBUG
        switch (ins)
        {
            case INS_slli_d:
            case INS_srli_d:
            case INS_srai_d:
            case INS_rotri_d:
                break;
            default:
                NYI_LOONGARCH64("illegal ins within emitIns_R_R_I --2!");
        }
#endif
        assert(isGeneralRegister(reg1));
        assert(isGeneralRegisterOrR0(reg2));
        assert((0 <= imm) && (imm <= 0x3f));

        code |= reg1;               // rd
        code |= reg2 << 5;          // rj
        code |= (imm & 0x3f) << 10; // ui6
    }
    else if (((INS_addi_w <= ins) && (ins <= INS_xori)) || ((INS_ld_b <= ins) && (ins <= INS_ld_wu)) ||
             ((INS_st_b <= ins) && (ins <= INS_st_d)))
    {
#ifdef DEBUG
        assert(isGeneralRegister(reg1));
        assert(isGeneralRegisterOrR0(reg2));
        if (((INS_addi_w <= ins) && (ins <= INS_slti)) || ((INS_ld_b <= ins) && (ins <= INS_ld_wu)) ||
            ((INS_st_b <= ins) && (ins <= INS_st_d)))
        {
            switch (ins)
            {
                case INS_addi_w:
                case INS_addi_d:
                case INS_lu52i_d:
                case INS_slti:
                case INS_ld_b:
                case INS_ld_h:
                case INS_ld_w:
                case INS_ld_d:
                case INS_ld_bu:
                case INS_ld_hu:
                case INS_ld_wu:
                case INS_st_b:
                case INS_st_h:
                case INS_st_w:
                case INS_st_d:
                    break;
                default:
                    NYI_LOONGARCH64("illegal ins within emitIns_R_R_I --3!");
            }

            assert((-2048 <= imm) && (imm <= 2047));
        }
        else if (ins == INS_sltui)
        {
            assert((0 <= imm) && (imm <= 0x7ff));
        }
        else
        {
            switch (ins)
            {
                case INS_andi:
                case INS_ori:
                case INS_xori:
                    break;
                default:
                    NYI_LOONGARCH64("illegal ins within emitIns_R_R_I --4!");
            }
            assert((0 <= imm) && (imm <= 0xfff));
        }
#endif
        code |= reg1;                // rd
        code |= reg2 << 5;           // rj
        code |= (imm & 0xfff) << 10; // si12 or ui12
    }
    else if ((INS_fld_s <= ins) && (ins <= INS_fst_d))
    {
#ifdef DEBUG
        switch (ins)
        {
            case INS_fld_s:
            case INS_fld_d:
            case INS_fst_s:
            case INS_fst_d:
                break;
            default:
                NYI_LOONGARCH64("illegal ins within emitIns_R_R_I --5!");
        }
#endif
        assert(isFloatReg(reg1));
        assert(isGeneralRegisterOrR0(reg2));
        assert((-2048 <= imm) && (imm <= 2047));

        code |= reg1 & 0x1f;         // fd
        code |= reg2 << 5;           // rj
        code |= (imm & 0xfff) << 10; // si12
    }
    else if (((INS_ll_d >= ins) && (ins >= INS_ldptr_w)) || ((INS_sc_d >= ins) && (ins >= INS_stptr_w)))
    {
#ifdef DEBUG
        switch (ins)
        {
            case INS_ldptr_w:
            case INS_ldptr_d:
            case INS_ll_w:
            case INS_ll_d:
            case INS_stptr_w:
            case INS_stptr_d:
            case INS_sc_w:
            case INS_sc_d:
                break;
            default:
                NYI_LOONGARCH64("illegal ins within emitIns_R_R_I --6!");
        }
#endif
        assert(isGeneralRegister(reg1));
        assert(isGeneralRegisterOrR0(reg2));
        assert((-8192 <= imm) && (imm <= 8191));

        code |= reg1;                 // rd
        code |= reg2 << 5;            // rj
        code |= (imm & 0x3fff) << 10; // si14
    }
    else if ((INS_beq <= ins) && (ins <= INS_bgeu))
    {
#ifdef DEBUG
        switch (ins)
        {
            case INS_beq:
            case INS_bne:
            case INS_blt:
            case INS_bltu:
            case INS_bge:
            case INS_bgeu:
                break;
            default:
                NYI_LOONGARCH64("illegal ins within emitIns_R_R_I --7!");
        }
#endif
        assert(isGeneralRegisterOrR0(reg1));
        assert(isGeneralRegisterOrR0(reg2));
        assert(!(imm & 0x3));
        assert((-32768 <= (imm >> 2)) && ((imm >> 2) <= 32767));

        code |= reg1 << 5;                   // rj
        code |= reg2;                        // rd
        code |= ((imm >> 2) & 0xffff) << 10; // offs16
    }
    else if ((INS_fcmp_caf_s <= ins) && (ins <= INS_fcmp_sune_s))
    {
#ifdef DEBUG
        switch (ins)
        {
            case INS_fcmp_caf_s:
            case INS_fcmp_cun_s:
            case INS_fcmp_ceq_s:
            case INS_fcmp_cueq_s:
            case INS_fcmp_clt_s:
            case INS_fcmp_cult_s:
            case INS_fcmp_cle_s:
            case INS_fcmp_cule_s:
            case INS_fcmp_cne_s:
            case INS_fcmp_cor_s:
            case INS_fcmp_cune_s:
            case INS_fcmp_saf_d:
            case INS_fcmp_sun_d:
            case INS_fcmp_seq_d:
            case INS_fcmp_sueq_d:
            case INS_fcmp_slt_d:
            case INS_fcmp_sult_d:
            case INS_fcmp_sle_d:
            case INS_fcmp_sule_d:
            case INS_fcmp_sne_d:
            case INS_fcmp_sor_d:
            case INS_fcmp_sune_d:
            case INS_fcmp_caf_d:
            case INS_fcmp_cun_d:
            case INS_fcmp_ceq_d:
            case INS_fcmp_cueq_d:
            case INS_fcmp_clt_d:
            case INS_fcmp_cult_d:
            case INS_fcmp_cle_d:
            case INS_fcmp_cule_d:
            case INS_fcmp_cne_d:
            case INS_fcmp_cor_d:
            case INS_fcmp_cune_d:
            case INS_fcmp_saf_s:
            case INS_fcmp_sun_s:
            case INS_fcmp_seq_s:
            case INS_fcmp_sueq_s:
            case INS_fcmp_slt_s:
            case INS_fcmp_sult_s:
            case INS_fcmp_sle_s:
            case INS_fcmp_sule_s:
            case INS_fcmp_sne_s:
            case INS_fcmp_sor_s:
            case INS_fcmp_sune_s:
                break;
            default:
                NYI_LOONGARCH64("illegal ins within emitIns_R_R_I --8!");
        }
#endif
        assert(isFloatReg(reg1));
        assert(isFloatReg(reg2));
        assert((0 <= imm) && (imm <= 7));

        code |= (reg1 & 0x1f) << 5;  // fj
        code |= (reg2 & 0x1f) << 10; // fk
        code |= imm & 0x7;           // cc
    }
    else if (INS_addu16i_d == ins)
    {
        assert(isGeneralRegister(reg1));
        assert(isGeneralRegisterOrR0(reg2));
        assert((-32768 <= imm) && (imm < 32768));

        code |= reg1;                 // rd
        code |= reg2 << 5;            // rj
        code |= (imm & 0xffff) << 10; // si16
    }
    else if (INS_jirl == ins)
    {
        assert(isGeneralRegister(reg1));
        assert(isGeneralRegisterOrR0(reg2));
        assert((-32768 <= imm) && (imm < 32768));

        code |= reg1;                 // rd
        code |= reg2 << 5;            // rj
        code |= (imm & 0xffff) << 10; // offs16
    }
#ifdef FEATURE_SIMD
    else if (((INS_vseqi_b <= ins) && (ins <= INS_vmini_d)) || ((INS_xvseqi_b <= ins) && (ins <= INS_xvmin_d)))
    {
        assert(isVectorRegister(reg1));
        assert(isVectorRegister(reg2));
        assert((-16 <= imm) && (imm <= 15));

        code |= reg1 & 0x1f;        // vd/xd
        code |= (reg2 & 0x1f) << 5; // vj/xj
        code |= (imm & 0x1f) << 10; // si5
    }
    else if ((INS_vldrepl_d == ins) || (INS_xvldrepl_d == ins))
    {
        assert(isVectorRegister(reg1));
        assert(isGeneralRegisterOrR0(reg2));
        assert((-256 <= imm) && (imm <= 255));
        code |= reg1 & 0x1f;         // vd/xd
        code |= (reg2 & 0x1f) << 5;  // rj
        code |= (imm & 0x1ff) << 10; // si9
    }
    else if ((INS_vldrepl_w == ins) || (INS_xvldrepl_w == ins))
    {
        assert(isVectorRegister(reg1));
        assert(isGeneralRegisterOrR0(reg2));
        assert((-512 <= imm) && (imm <= 511));
        code |= reg1 & 0x1f;         // vd/xd
        code |= (reg2 & 0x1f) << 5;  // rj
        code |= (imm & 0x3ff) << 10; // si10
    }
    else if ((INS_vldrepl_h == ins) || (INS_xvldrepl_h == ins))
    {
        assert(isVectorRegister(reg1));
        assert(isGeneralRegisterOrR0(reg2));
        assert((-1024 <= imm) && (imm <= 1023));
        code |= reg1 & 0x1f;         // vd/xd
        code |= (reg2 & 0x1f) << 5;  // rj
        code |= (imm & 0x7ff) << 10; // si11
    }
    else if (((INS_vld <= ins) && (ins <= INS_vst)) || ((INS_xvld <= ins) && (ins <= INS_xvst)))
    {
        assert(isVectorRegister(reg1));
        assert(isGeneralRegisterOrR0(reg2));
        assert((-2048 <= imm) && (imm <= 2047));

        code |= reg1 & 0x1f;         // vd(xd)
        code |= (reg2 & 0x1f) << 5;  // rj
        code |= (imm & 0xfff) << 10; // si12
    }
    else if (((INS_vinsgr2vr_d <= ins) && (ins <= INS_vreplvei_d)) || (INS_xvrepl128vei_d == ins))
    {
#ifdef DEBUG
        if (INS_vinsgr2vr_d == ins)
        {
            assert(isVectorRegister(reg1));      // xd
            assert(isGeneralRegisterOrR0(reg2)); // rj
        }
        else if ((INS_vreplvei_d == ins) || (INS_xvrepl128vei_d == ins))
        {
            assert(isVectorRegister(reg1)); // vd/xd
            assert(isVectorRegister(reg2)); // vj/xj
        }
        else
        {
            assert(isGeneralRegisterOrR0(reg1)); // rd
            assert(isVectorRegister(reg2));      // vj/xj
        }
        assert((0 <= imm) && (imm <= 1));
#endif

        code |= reg1 & 0x1f;
        code |= (reg2 & 0x1f) << 5;
        code |= (imm & 0x1) << 10; // ui1
    }
    else if (((INS_vinsgr2vr_w <= ins) && (ins <= INS_vreplvei_w)) ||
             ((INS_xvinsve0_d <= ins) && (ins <= INS_xvpickve2gr_du)))
    {
#ifdef DEBUG
        if (INS_vinsgr2vr_w == ins)
        {
            assert(isVectorRegister(reg1));      // vd
            assert(isGeneralRegisterOrR0(reg2)); // rj
        }
        else if ((INS_vpickve2gr_w <= ins) && (ins <= INS_vpickve2gr_wu))
        {
            assert(isGeneralRegisterOrR0(reg1)); // rd
            assert(isVectorRegister(reg2));      // vj
        }
        else if (INS_vreplvei_w == ins)
        {
            assert(isVectorRegister(reg1)); // vd
            assert(isVectorRegister(reg2)); // vj
        }
        else if ((INS_xvinsve0_d <= ins) && (ins <= INS_xvpickve_d))
        {
            assert(isVectorRegister(reg1)); // xd
            assert(isVectorRegister(reg2)); // xj
        }
        else if (INS_xvinsgr2vr_d == ins)
        {
            assert(isVectorRegister(reg1));      // xd
            assert(isGeneralRegisterOrR0(reg2)); // rj
        }
        else if ((INS_xvpickve2gr_d <= ins) && (ins <= INS_xvpickve2gr_du))
        {
            assert(isGeneralRegisterOrR0(reg1)); // rd
            assert(isVectorRegister(reg2));      // xj
        }
        else
        {
            assert(isVectorRegister(reg1)); // xd/vd
            assert(isVectorRegister(reg2)); // xj/vj
        }
#endif
        assert((0 <= imm) && (imm <= 3));

        code |= reg1 & 0x1f;        // xd/vd/rd
        code |= (reg2 & 0x1f) << 5; // xj/vj/rj
        code |= (imm & 0x3) << 10;  // ui2
    }
    else if (((INS_vslli_b <= ins) && (ins <= INS_vreplvei_h)) || ((INS_xvslli_b <= ins) && (ins <= INS_xvsat_bu)))
    {
#ifdef DEBUG
        if ((INS_vinsgr2vr_h == ins) || (INS_xvinsgr2vr_w == ins))
        {
            // vd/xd, rj, ui3
            assert(isVectorRegister(reg1));      // vd/xd
            assert(isGeneralRegisterOrR0(reg2)); // rj
        }
        else if ((INS_vpickve2gr_h == ins) || (INS_vpickve2gr_hu == ins) || (INS_xvpickve2gr_w == ins) ||
                 (INS_xvpickve2gr_wu == ins))
        {
            // rd, vj/xj, ui3
            assert(isGeneralRegisterOrR0(reg1)); // rd
            assert(isVectorRegister(reg2));      // vj/xj
        }
        else
        {
            assert(isVectorRegister(reg1)); // vd/xd
            assert(isVectorRegister(reg2)); // vj/xj
        }
#endif
        assert((0 <= imm) && (imm <= 7));

        code |= reg1 & 0x1f;        // vd(xd)
        code |= (reg2 & 0x1f) << 5; // vj(xj)
        code |= (imm & 0x7) << 10;  // ui3
    }
    else if (((INS_vslli_h <= ins) && (ins <= INS_vreplvei_b)) || ((INS_xvslli_h <= ins) && (ins <= INS_xvsat_hu)))
    {
#ifdef DEBUG
        if (INS_vinsgr2vr_b == ins)
        {
            assert(isVectorRegister(reg1));      // vd/xd
            assert(isGeneralRegisterOrR0(reg2)); // rj
        }
        else if (INS_vpickve2gr_b == ins)
        {
            assert(isGeneralRegisterOrR0(reg1)); // rd
            assert(isVectorRegister(reg2));      // vj/xj
        }
        else if (INS_vpickve2gr_bu == ins)
        {
            assert(isGeneralRegisterOrR0(reg1)); // rd
            assert(isVectorRegister(reg2));      // vj/xj
        }
        else
        {
            assert(isVectorRegister(reg1)); // vd/xd
            assert(isVectorRegister(reg2)); // vj/xj
        }
#endif
        assert((0 <= imm) && (imm <= 15));

        code |= reg1 & 0x1f;        // vd
        code |= (reg2 & 0x1f) << 5; // vj
        code |= (imm & 0xf) << 10;  // ui4
    }
    else if (((INS_vslei_bu <= ins) && (ins <= INS_vsat_wu)) || ((INS_xvslei_bu <= ins) && (ins <= INS_xvsat_wu)))
    {
        assert(isVectorRegister(reg1)); // vd/xd
        assert(isVectorRegister(reg2)); // vj/xj

        assert((0 <= imm) && (imm <= 31));

        code |= reg1 & 0x1f;        // vd
        code |= (reg2 & 0x1f) << 5; // vj
        code |= (imm & 0x1f) << 10; // ui5
    }
    else if (((INS_vslli_d <= ins) && (ins <= INS_vsat_du)) || ((INS_xvslli_d <= ins) && (ins <= INS_xvsat_du)))
    {
        assert(isVectorRegister(reg1)); // vd/xd
        assert(isVectorRegister(reg2)); // vj/xj

        assert((0 <= imm) && (imm <= 63));

        code |= reg1 & 0x1f;        // vd
        code |= (reg2 & 0x1f) << 5; // vj
        code |= (imm & 0x3f) << 10; // ui6
    }
    else if (((INS_vsrlni_d_q <= ins) && (ins <= INS_vssrarni_du_q)) ||
             ((INS_xvsrlni_d_q <= ins) && (ins <= INS_xvssrarni_du_q)))
    {
        assert(isVectorRegister(reg1)); // vd/xd
        assert(isVectorRegister(reg2)); // vj/xj

        assert((0 <= imm) && (imm <= 127));

        code |= reg1 & 0x1f;        // vd
        code |= (reg2 & 0x1f) << 5; // vj
        code |= (imm & 0x7f) << 10; // ui7
    }
    else if (((INS_vextrins_d <= ins) && (ins <= INS_vpermi_w)) || ((INS_xvextrins_d <= ins) && (ins <= INS_xvpermi_q)))
    {
        assert(isVectorRegister(reg1)); // vd/xd
        assert(isVectorRegister(reg2)); // vj/xj

        assert((0 <= imm) && (imm <= 255));

        code |= reg1 & 0x1f;        // vd
        code |= (reg2 & 0x1f) << 5; // vj
        code |= (imm & 0xff) << 10; // ui8
    }
#endif
    else
    {
        unreached();
    }

    instrDesc* id = emitNewInstr(attr);

    id->idIns(ins);
    id->idReg1(reg1);
    id->idReg2(reg2);
    id->idAddr()->iiaSetInstrEncode(code);
    id->idCodeSize(4);

    appendToCurIG(id);
}