static void tcg_out_op()

in tcg/mips/tcg-target.c.inc [1620:2075]


static void tcg_out_op(TCGContext *s, TCGOpcode opc,
                       const TCGArg args[TCG_MAX_OP_ARGS],
                       const int const_args[TCG_MAX_OP_ARGS])
{
    MIPSInsn i1, i2;
    TCGArg a0, a1, a2;
    int c2;

    /*
     * Note that many operands use the constraint set "rZ".
     * We make use of the fact that 0 is the ZERO register,
     * and hence such cases need not check for const_args.
     */
    a0 = args[0];
    a1 = args[1];
    a2 = args[2];
    c2 = const_args[2];

    switch (opc) {
    case INDEX_op_exit_tb:
        {
            TCGReg b0 = TCG_REG_ZERO;

            a0 = (intptr_t)a0;
            if (a0 & ~0xffff) {
                tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_V0, a0 & ~0xffff);
                b0 = TCG_REG_V0;
            }
            if (!tcg_out_opc_jmp(s, OPC_J, tb_ret_addr)) {
                tcg_out_movi(s, TCG_TYPE_PTR, TCG_TMP0,
                             (uintptr_t)tb_ret_addr);
                tcg_out_opc_reg(s, OPC_JR, 0, TCG_TMP0, 0);
            }
            tcg_out_opc_imm(s, OPC_ORI, TCG_REG_V0, b0, a0 & 0xffff);
        }
        break;
    case INDEX_op_goto_tb:
        /* indirect jump method */
        tcg_debug_assert(s->tb_jmp_insn_offset == 0);
        tcg_out_ld(s, TCG_TYPE_PTR, TCG_TMP0, TCG_REG_ZERO,
                   (uintptr_t)(s->tb_jmp_target_addr + a0));
        tcg_out_opc_reg(s, OPC_JR, 0, TCG_TMP0, 0);
        tcg_out_nop(s);
        set_jmp_reset_offset(s, a0);
        break;
    case INDEX_op_goto_ptr:
        /* jmp to the given host address (could be epilogue) */
        tcg_out_opc_reg(s, OPC_JR, 0, a0, 0);
        tcg_out_nop(s);
        break;
    case INDEX_op_br:
        tcg_out_brcond(s, TCG_COND_EQ, TCG_REG_ZERO, TCG_REG_ZERO,
                       arg_label(a0));
        break;

    case INDEX_op_ld8u_i32:
    case INDEX_op_ld8u_i64:
        i1 = OPC_LBU;
        goto do_ldst;
    case INDEX_op_ld8s_i32:
    case INDEX_op_ld8s_i64:
        i1 = OPC_LB;
        goto do_ldst;
    case INDEX_op_ld16u_i32:
    case INDEX_op_ld16u_i64:
        i1 = OPC_LHU;
        goto do_ldst;
    case INDEX_op_ld16s_i32:
    case INDEX_op_ld16s_i64:
        i1 = OPC_LH;
        goto do_ldst;
    case INDEX_op_ld_i32:
    case INDEX_op_ld32s_i64:
        i1 = OPC_LW;
        goto do_ldst;
    case INDEX_op_ld32u_i64:
        i1 = OPC_LWU;
        goto do_ldst;
    case INDEX_op_ld_i64:
        i1 = OPC_LD;
        goto do_ldst;
    case INDEX_op_st8_i32:
    case INDEX_op_st8_i64:
        i1 = OPC_SB;
        goto do_ldst;
    case INDEX_op_st16_i32:
    case INDEX_op_st16_i64:
        i1 = OPC_SH;
        goto do_ldst;
    case INDEX_op_st_i32:
    case INDEX_op_st32_i64:
        i1 = OPC_SW;
        goto do_ldst;
    case INDEX_op_st_i64:
        i1 = OPC_SD;
    do_ldst:
        tcg_out_ldst(s, i1, a0, a1, a2);
        break;

    case INDEX_op_add_i32:
        i1 = OPC_ADDU, i2 = OPC_ADDIU;
        goto do_binary;
    case INDEX_op_add_i64:
        i1 = OPC_DADDU, i2 = OPC_DADDIU;
        goto do_binary;
    case INDEX_op_or_i32:
    case INDEX_op_or_i64:
        i1 = OPC_OR, i2 = OPC_ORI;
        goto do_binary;
    case INDEX_op_xor_i32:
    case INDEX_op_xor_i64:
        i1 = OPC_XOR, i2 = OPC_XORI;
    do_binary:
        if (c2) {
            tcg_out_opc_imm(s, i2, a0, a1, a2);
            break;
        }
    do_binaryv:
        tcg_out_opc_reg(s, i1, a0, a1, a2);
        break;

    case INDEX_op_sub_i32:
        i1 = OPC_SUBU, i2 = OPC_ADDIU;
        goto do_subtract;
    case INDEX_op_sub_i64:
        i1 = OPC_DSUBU, i2 = OPC_DADDIU;
    do_subtract:
        if (c2) {
            tcg_out_opc_imm(s, i2, a0, a1, -a2);
            break;
        }
        goto do_binaryv;
    case INDEX_op_and_i32:
        if (c2 && a2 != (uint16_t)a2) {
            int msb = ctz32(~a2) - 1;
            tcg_debug_assert(use_mips32r2_instructions);
            tcg_debug_assert(is_p2m1(a2));
            tcg_out_opc_bf(s, OPC_EXT, a0, a1, msb, 0);
            break;
        }
        i1 = OPC_AND, i2 = OPC_ANDI;
        goto do_binary;
    case INDEX_op_and_i64:
        if (c2 && a2 != (uint16_t)a2) {
            int msb = ctz64(~a2) - 1;
            tcg_debug_assert(use_mips32r2_instructions);
            tcg_debug_assert(is_p2m1(a2));
            tcg_out_opc_bf64(s, OPC_DEXT, OPC_DEXTM, OPC_DEXTU, a0, a1, msb, 0);
            break;
        }
        i1 = OPC_AND, i2 = OPC_ANDI;
        goto do_binary;
    case INDEX_op_nor_i32:
    case INDEX_op_nor_i64:
        i1 = OPC_NOR;
        goto do_binaryv;

    case INDEX_op_mul_i32:
        if (use_mips32_instructions) {
            tcg_out_opc_reg(s, OPC_MUL, a0, a1, a2);
            break;
        }
        i1 = OPC_MULT, i2 = OPC_MFLO;
        goto do_hilo1;
    case INDEX_op_mulsh_i32:
        if (use_mips32r6_instructions) {
            tcg_out_opc_reg(s, OPC_MUH, a0, a1, a2);
            break;
        }
        i1 = OPC_MULT, i2 = OPC_MFHI;
        goto do_hilo1;
    case INDEX_op_muluh_i32:
        if (use_mips32r6_instructions) {
            tcg_out_opc_reg(s, OPC_MUHU, a0, a1, a2);
            break;
        }
        i1 = OPC_MULTU, i2 = OPC_MFHI;
        goto do_hilo1;
    case INDEX_op_div_i32:
        if (use_mips32r6_instructions) {
            tcg_out_opc_reg(s, OPC_DIV_R6, a0, a1, a2);
            break;
        }
        i1 = OPC_DIV, i2 = OPC_MFLO;
        goto do_hilo1;
    case INDEX_op_divu_i32:
        if (use_mips32r6_instructions) {
            tcg_out_opc_reg(s, OPC_DIVU_R6, a0, a1, a2);
            break;
        }
        i1 = OPC_DIVU, i2 = OPC_MFLO;
        goto do_hilo1;
    case INDEX_op_rem_i32:
        if (use_mips32r6_instructions) {
            tcg_out_opc_reg(s, OPC_MOD, a0, a1, a2);
            break;
        }
        i1 = OPC_DIV, i2 = OPC_MFHI;
        goto do_hilo1;
    case INDEX_op_remu_i32:
        if (use_mips32r6_instructions) {
            tcg_out_opc_reg(s, OPC_MODU, a0, a1, a2);
            break;
        }
        i1 = OPC_DIVU, i2 = OPC_MFHI;
        goto do_hilo1;
    case INDEX_op_mul_i64:
        if (use_mips32r6_instructions) {
            tcg_out_opc_reg(s, OPC_DMUL, a0, a1, a2);
            break;
        }
        i1 = OPC_DMULT, i2 = OPC_MFLO;
        goto do_hilo1;
    case INDEX_op_mulsh_i64:
        if (use_mips32r6_instructions) {
            tcg_out_opc_reg(s, OPC_DMUH, a0, a1, a2);
            break;
        }
        i1 = OPC_DMULT, i2 = OPC_MFHI;
        goto do_hilo1;
    case INDEX_op_muluh_i64:
        if (use_mips32r6_instructions) {
            tcg_out_opc_reg(s, OPC_DMUHU, a0, a1, a2);
            break;
        }
        i1 = OPC_DMULTU, i2 = OPC_MFHI;
        goto do_hilo1;
    case INDEX_op_div_i64:
        if (use_mips32r6_instructions) {
            tcg_out_opc_reg(s, OPC_DDIV_R6, a0, a1, a2);
            break;
        }
        i1 = OPC_DDIV, i2 = OPC_MFLO;
        goto do_hilo1;
    case INDEX_op_divu_i64:
        if (use_mips32r6_instructions) {
            tcg_out_opc_reg(s, OPC_DDIVU_R6, a0, a1, a2);
            break;
        }
        i1 = OPC_DDIVU, i2 = OPC_MFLO;
        goto do_hilo1;
    case INDEX_op_rem_i64:
        if (use_mips32r6_instructions) {
            tcg_out_opc_reg(s, OPC_DMOD, a0, a1, a2);
            break;
        }
        i1 = OPC_DDIV, i2 = OPC_MFHI;
        goto do_hilo1;
    case INDEX_op_remu_i64:
        if (use_mips32r6_instructions) {
            tcg_out_opc_reg(s, OPC_DMODU, a0, a1, a2);
            break;
        }
        i1 = OPC_DDIVU, i2 = OPC_MFHI;
    do_hilo1:
        tcg_out_opc_reg(s, i1, 0, a1, a2);
        tcg_out_opc_reg(s, i2, a0, 0, 0);
        break;

    case INDEX_op_muls2_i32:
        i1 = OPC_MULT;
        goto do_hilo2;
    case INDEX_op_mulu2_i32:
        i1 = OPC_MULTU;
        goto do_hilo2;
    case INDEX_op_muls2_i64:
        i1 = OPC_DMULT;
        goto do_hilo2;
    case INDEX_op_mulu2_i64:
        i1 = OPC_DMULTU;
    do_hilo2:
        tcg_out_opc_reg(s, i1, 0, a2, args[3]);
        tcg_out_opc_reg(s, OPC_MFLO, a0, 0, 0);
        tcg_out_opc_reg(s, OPC_MFHI, a1, 0, 0);
        break;

    case INDEX_op_not_i32:
    case INDEX_op_not_i64:
        i1 = OPC_NOR;
        goto do_unary;
    case INDEX_op_ext8s_i32:
    case INDEX_op_ext8s_i64:
        i1 = OPC_SEB;
        goto do_unary;
    case INDEX_op_ext16s_i32:
    case INDEX_op_ext16s_i64:
        i1 = OPC_SEH;
    do_unary:
        tcg_out_opc_reg(s, i1, a0, TCG_REG_ZERO, a1);
        break;

    case INDEX_op_bswap16_i32:
    case INDEX_op_bswap16_i64:
        tcg_out_bswap16(s, a0, a1, a2);
        break;
    case INDEX_op_bswap32_i32:
        tcg_out_bswap32(s, a0, a1, 0);
        break;
    case INDEX_op_bswap32_i64:
        tcg_out_bswap32(s, a0, a1, a2);
        break;
    case INDEX_op_bswap64_i64:
        tcg_out_bswap64(s, a0, a1);
        break;
    case INDEX_op_extrh_i64_i32:
        tcg_out_dsra(s, a0, a1, 32);
        break;
    case INDEX_op_ext32s_i64:
    case INDEX_op_ext_i32_i64:
    case INDEX_op_extrl_i64_i32:
        tcg_out_opc_sa(s, OPC_SLL, a0, a1, 0);
        break;
    case INDEX_op_ext32u_i64:
    case INDEX_op_extu_i32_i64:
        tcg_out_ext32u(s, a0, a1);
        break;

    case INDEX_op_sar_i32:
        i1 = OPC_SRAV, i2 = OPC_SRA;
        goto do_shift;
    case INDEX_op_shl_i32:
        i1 = OPC_SLLV, i2 = OPC_SLL;
        goto do_shift;
    case INDEX_op_shr_i32:
        i1 = OPC_SRLV, i2 = OPC_SRL;
        goto do_shift;
    case INDEX_op_rotr_i32:
        i1 = OPC_ROTRV, i2 = OPC_ROTR;
    do_shift:
        if (c2) {
            tcg_out_opc_sa(s, i2, a0, a1, a2);
            break;
        }
    do_shiftv:
        tcg_out_opc_reg(s, i1, a0, a2, a1);
        break;
    case INDEX_op_rotl_i32:
        if (c2) {
            tcg_out_opc_sa(s, OPC_ROTR, a0, a1, 32 - a2);
        } else {
            tcg_out_opc_reg(s, OPC_SUBU, TCG_TMP0, TCG_REG_ZERO, a2);
            tcg_out_opc_reg(s, OPC_ROTRV, a0, TCG_TMP0, a1);
        }
        break;
    case INDEX_op_sar_i64:
        if (c2) {
            tcg_out_dsra(s, a0, a1, a2);
            break;
        }
        i1 = OPC_DSRAV;
        goto do_shiftv;
    case INDEX_op_shl_i64:
        if (c2) {
            tcg_out_dsll(s, a0, a1, a2);
            break;
        }
        i1 = OPC_DSLLV;
        goto do_shiftv;
    case INDEX_op_shr_i64:
        if (c2) {
            tcg_out_dsrl(s, a0, a1, a2);
            break;
        }
        i1 = OPC_DSRLV;
        goto do_shiftv;
    case INDEX_op_rotr_i64:
        if (c2) {
            tcg_out_opc_sa64(s, OPC_DROTR, OPC_DROTR32, a0, a1, a2);
            break;
        }
        i1 = OPC_DROTRV;
        goto do_shiftv;
    case INDEX_op_rotl_i64:
        if (c2) {
            tcg_out_opc_sa64(s, OPC_DROTR, OPC_DROTR32, a0, a1, 64 - a2);
        } else {
            tcg_out_opc_reg(s, OPC_DSUBU, TCG_TMP0, TCG_REG_ZERO, a2);
            tcg_out_opc_reg(s, OPC_DROTRV, a0, TCG_TMP0, a1);
        }
        break;

    case INDEX_op_clz_i32:
        tcg_out_clz(s, OPC_CLZ, OPC_CLZ_R6, 32, a0, a1, a2);
        break;
    case INDEX_op_clz_i64:
        tcg_out_clz(s, OPC_DCLZ, OPC_DCLZ_R6, 64, a0, a1, a2);
        break;

    case INDEX_op_deposit_i32:
        tcg_out_opc_bf(s, OPC_INS, a0, a2, args[3] + args[4] - 1, args[3]);
        break;
    case INDEX_op_deposit_i64:
        tcg_out_opc_bf64(s, OPC_DINS, OPC_DINSM, OPC_DINSU, a0, a2,
                         args[3] + args[4] - 1, args[3]);
        break;
    case INDEX_op_extract_i32:
        tcg_out_opc_bf(s, OPC_EXT, a0, a1, args[3] - 1, a2);
        break;
    case INDEX_op_extract_i64:
        tcg_out_opc_bf64(s, OPC_DEXT, OPC_DEXTM, OPC_DEXTU, a0, a1,
                         args[3] - 1, a2);
        break;

    case INDEX_op_brcond_i32:
    case INDEX_op_brcond_i64:
        tcg_out_brcond(s, a2, a0, a1, arg_label(args[3]));
        break;
    case INDEX_op_brcond2_i32:
        tcg_out_brcond2(s, args[4], a0, a1, a2, args[3], arg_label(args[5]));
        break;

    case INDEX_op_movcond_i32:
    case INDEX_op_movcond_i64:
        tcg_out_movcond(s, args[5], a0, a1, a2, args[3], args[4]);
        break;

    case INDEX_op_setcond_i32:
    case INDEX_op_setcond_i64:
        tcg_out_setcond(s, args[3], a0, a1, a2);
        break;
    case INDEX_op_setcond2_i32:
        tcg_out_setcond2(s, args[5], a0, a1, a2, args[3], args[4]);
        break;

    case INDEX_op_qemu_ld_i32:
        tcg_out_qemu_ld(s, args, false);
        break;
    case INDEX_op_qemu_ld_i64:
        tcg_out_qemu_ld(s, args, true);
        break;
    case INDEX_op_qemu_st_i32:
        tcg_out_qemu_st(s, args, false);
        break;
    case INDEX_op_qemu_st_i64:
        tcg_out_qemu_st(s, args, true);
        break;

    case INDEX_op_add2_i32:
        tcg_out_addsub2(s, a0, a1, a2, args[3], args[4], args[5],
                        const_args[4], const_args[5], false);
        break;
    case INDEX_op_sub2_i32:
        tcg_out_addsub2(s, a0, a1, a2, args[3], args[4], args[5],
                        const_args[4], const_args[5], true);
        break;

    case INDEX_op_mb:
        tcg_out_mb(s, a0);
        break;
    case INDEX_op_mov_i32:  /* Always emitted via tcg_out_mov.  */
    case INDEX_op_mov_i64:
    case INDEX_op_call:     /* Always emitted via tcg_out_call.  */
    default:
        tcg_abort();
    }
}