static void tcg_out_op()

in tcg/aarch64/tcg-target.c.inc [1832:2258]


static void tcg_out_op(TCGContext *s, TCGOpcode opc,
                       const TCGArg args[TCG_MAX_OP_ARGS],
                       const int const_args[TCG_MAX_OP_ARGS])
{
    /* 99% of the time, we can signal the use of extension registers
       by looking to see if the opcode handles 64-bit data.  */
    TCGType ext = (tcg_op_defs[opc].flags & TCG_OPF_64BIT) != 0;

    /* Hoist the loads of the most common arguments.  */
    TCGArg a0 = args[0];
    TCGArg a1 = args[1];
    TCGArg a2 = args[2];
    int c2 = const_args[2];

    /* Some operands are defined with "rZ" constraint, a register or
       the zero register.  These need not actually test args[I] == 0.  */
#define REG0(I)  (const_args[I] ? TCG_REG_XZR : (TCGReg)args[I])

    switch (opc) {
    case INDEX_op_exit_tb:
        /* Reuse the zeroing that exists for goto_ptr.  */
        if (a0 == 0) {
            tcg_out_goto_long(s, tcg_code_gen_epilogue);
        } else {
            tcg_out_movi(s, TCG_TYPE_I64, TCG_REG_X0, a0);
            tcg_out_goto_long(s, tb_ret_addr);
        }
        break;

    case INDEX_op_goto_tb:
        if (s->tb_jmp_insn_offset != NULL) {
            /* TCG_TARGET_HAS_direct_jump */
            /* Ensure that ADRP+ADD are 8-byte aligned so that an atomic
               write can be used to patch the target address. */
            if ((uintptr_t)s->code_ptr & 7) {
                tcg_out32(s, NOP);
            }
            s->tb_jmp_insn_offset[a0] = tcg_current_code_size(s);
            /* actual branch destination will be patched by
               tb_target_set_jmp_target later. */
            tcg_out_insn(s, 3406, ADRP, TCG_REG_TMP, 0);
            tcg_out_insn(s, 3401, ADDI, TCG_TYPE_I64, TCG_REG_TMP, TCG_REG_TMP, 0);
        } else {
            /* !TCG_TARGET_HAS_direct_jump */
            tcg_debug_assert(s->tb_jmp_target_addr != NULL);
            intptr_t offset = tcg_pcrel_diff(s, (s->tb_jmp_target_addr + a0)) >> 2;
            tcg_out_insn(s, 3305, LDR, offset, TCG_REG_TMP);
        }
        tcg_out_insn(s, 3207, BR, TCG_REG_TMP);
        set_jmp_reset_offset(s, a0);
        break;

    case INDEX_op_goto_ptr:
        tcg_out_insn(s, 3207, BR, a0);
        break;

    case INDEX_op_br:
        tcg_out_goto_label(s, arg_label(a0));
        break;

    case INDEX_op_ld8u_i32:
    case INDEX_op_ld8u_i64:
        tcg_out_ldst(s, I3312_LDRB, a0, a1, a2, 0);
        break;
    case INDEX_op_ld8s_i32:
        tcg_out_ldst(s, I3312_LDRSBW, a0, a1, a2, 0);
        break;
    case INDEX_op_ld8s_i64:
        tcg_out_ldst(s, I3312_LDRSBX, a0, a1, a2, 0);
        break;
    case INDEX_op_ld16u_i32:
    case INDEX_op_ld16u_i64:
        tcg_out_ldst(s, I3312_LDRH, a0, a1, a2, 1);
        break;
    case INDEX_op_ld16s_i32:
        tcg_out_ldst(s, I3312_LDRSHW, a0, a1, a2, 1);
        break;
    case INDEX_op_ld16s_i64:
        tcg_out_ldst(s, I3312_LDRSHX, a0, a1, a2, 1);
        break;
    case INDEX_op_ld_i32:
    case INDEX_op_ld32u_i64:
        tcg_out_ldst(s, I3312_LDRW, a0, a1, a2, 2);
        break;
    case INDEX_op_ld32s_i64:
        tcg_out_ldst(s, I3312_LDRSWX, a0, a1, a2, 2);
        break;
    case INDEX_op_ld_i64:
        tcg_out_ldst(s, I3312_LDRX, a0, a1, a2, 3);
        break;

    case INDEX_op_st8_i32:
    case INDEX_op_st8_i64:
        tcg_out_ldst(s, I3312_STRB, REG0(0), a1, a2, 0);
        break;
    case INDEX_op_st16_i32:
    case INDEX_op_st16_i64:
        tcg_out_ldst(s, I3312_STRH, REG0(0), a1, a2, 1);
        break;
    case INDEX_op_st_i32:
    case INDEX_op_st32_i64:
        tcg_out_ldst(s, I3312_STRW, REG0(0), a1, a2, 2);
        break;
    case INDEX_op_st_i64:
        tcg_out_ldst(s, I3312_STRX, REG0(0), a1, a2, 3);
        break;

    case INDEX_op_add_i32:
        a2 = (int32_t)a2;
        /* FALLTHRU */
    case INDEX_op_add_i64:
        if (c2) {
            tcg_out_addsubi(s, ext, a0, a1, a2);
        } else {
            tcg_out_insn(s, 3502, ADD, ext, a0, a1, a2);
        }
        break;

    case INDEX_op_sub_i32:
        a2 = (int32_t)a2;
        /* FALLTHRU */
    case INDEX_op_sub_i64:
        if (c2) {
            tcg_out_addsubi(s, ext, a0, a1, -a2);
        } else {
            tcg_out_insn(s, 3502, SUB, ext, a0, a1, a2);
        }
        break;

    case INDEX_op_neg_i64:
    case INDEX_op_neg_i32:
        tcg_out_insn(s, 3502, SUB, ext, a0, TCG_REG_XZR, a1);
        break;

    case INDEX_op_and_i32:
        a2 = (int32_t)a2;
        /* FALLTHRU */
    case INDEX_op_and_i64:
        if (c2) {
            tcg_out_logicali(s, I3404_ANDI, ext, a0, a1, a2);
        } else {
            tcg_out_insn(s, 3510, AND, ext, a0, a1, a2);
        }
        break;

    case INDEX_op_andc_i32:
        a2 = (int32_t)a2;
        /* FALLTHRU */
    case INDEX_op_andc_i64:
        if (c2) {
            tcg_out_logicali(s, I3404_ANDI, ext, a0, a1, ~a2);
        } else {
            tcg_out_insn(s, 3510, BIC, ext, a0, a1, a2);
        }
        break;

    case INDEX_op_or_i32:
        a2 = (int32_t)a2;
        /* FALLTHRU */
    case INDEX_op_or_i64:
        if (c2) {
            tcg_out_logicali(s, I3404_ORRI, ext, a0, a1, a2);
        } else {
            tcg_out_insn(s, 3510, ORR, ext, a0, a1, a2);
        }
        break;

    case INDEX_op_orc_i32:
        a2 = (int32_t)a2;
        /* FALLTHRU */
    case INDEX_op_orc_i64:
        if (c2) {
            tcg_out_logicali(s, I3404_ORRI, ext, a0, a1, ~a2);
        } else {
            tcg_out_insn(s, 3510, ORN, ext, a0, a1, a2);
        }
        break;

    case INDEX_op_xor_i32:
        a2 = (int32_t)a2;
        /* FALLTHRU */
    case INDEX_op_xor_i64:
        if (c2) {
            tcg_out_logicali(s, I3404_EORI, ext, a0, a1, a2);
        } else {
            tcg_out_insn(s, 3510, EOR, ext, a0, a1, a2);
        }
        break;

    case INDEX_op_eqv_i32:
        a2 = (int32_t)a2;
        /* FALLTHRU */
    case INDEX_op_eqv_i64:
        if (c2) {
            tcg_out_logicali(s, I3404_EORI, ext, a0, a1, ~a2);
        } else {
            tcg_out_insn(s, 3510, EON, ext, a0, a1, a2);
        }
        break;

    case INDEX_op_not_i64:
    case INDEX_op_not_i32:
        tcg_out_insn(s, 3510, ORN, ext, a0, TCG_REG_XZR, a1);
        break;

    case INDEX_op_mul_i64:
    case INDEX_op_mul_i32:
        tcg_out_insn(s, 3509, MADD, ext, a0, a1, a2, TCG_REG_XZR);
        break;

    case INDEX_op_div_i64:
    case INDEX_op_div_i32:
        tcg_out_insn(s, 3508, SDIV, ext, a0, a1, a2);
        break;
    case INDEX_op_divu_i64:
    case INDEX_op_divu_i32:
        tcg_out_insn(s, 3508, UDIV, ext, a0, a1, a2);
        break;

    case INDEX_op_rem_i64:
    case INDEX_op_rem_i32:
        tcg_out_insn(s, 3508, SDIV, ext, TCG_REG_TMP, a1, a2);
        tcg_out_insn(s, 3509, MSUB, ext, a0, TCG_REG_TMP, a2, a1);
        break;
    case INDEX_op_remu_i64:
    case INDEX_op_remu_i32:
        tcg_out_insn(s, 3508, UDIV, ext, TCG_REG_TMP, a1, a2);
        tcg_out_insn(s, 3509, MSUB, ext, a0, TCG_REG_TMP, a2, a1);
        break;

    case INDEX_op_shl_i64:
    case INDEX_op_shl_i32:
        if (c2) {
            tcg_out_shl(s, ext, a0, a1, a2);
        } else {
            tcg_out_insn(s, 3508, LSLV, ext, a0, a1, a2);
        }
        break;

    case INDEX_op_shr_i64:
    case INDEX_op_shr_i32:
        if (c2) {
            tcg_out_shr(s, ext, a0, a1, a2);
        } else {
            tcg_out_insn(s, 3508, LSRV, ext, a0, a1, a2);
        }
        break;

    case INDEX_op_sar_i64:
    case INDEX_op_sar_i32:
        if (c2) {
            tcg_out_sar(s, ext, a0, a1, a2);
        } else {
            tcg_out_insn(s, 3508, ASRV, ext, a0, a1, a2);
        }
        break;

    case INDEX_op_rotr_i64:
    case INDEX_op_rotr_i32:
        if (c2) {
            tcg_out_rotr(s, ext, a0, a1, a2);
        } else {
            tcg_out_insn(s, 3508, RORV, ext, a0, a1, a2);
        }
        break;

    case INDEX_op_rotl_i64:
    case INDEX_op_rotl_i32:
        if (c2) {
            tcg_out_rotl(s, ext, a0, a1, a2);
        } else {
            tcg_out_insn(s, 3502, SUB, 0, TCG_REG_TMP, TCG_REG_XZR, a2);
            tcg_out_insn(s, 3508, RORV, ext, a0, a1, TCG_REG_TMP);
        }
        break;

    case INDEX_op_clz_i64:
    case INDEX_op_clz_i32:
        tcg_out_cltz(s, ext, a0, a1, a2, c2, false);
        break;
    case INDEX_op_ctz_i64:
    case INDEX_op_ctz_i32:
        tcg_out_cltz(s, ext, a0, a1, a2, c2, true);
        break;

    case INDEX_op_brcond_i32:
        a1 = (int32_t)a1;
        /* FALLTHRU */
    case INDEX_op_brcond_i64:
        tcg_out_brcond(s, ext, a2, a0, a1, const_args[1], arg_label(args[3]));
        break;

    case INDEX_op_setcond_i32:
        a2 = (int32_t)a2;
        /* FALLTHRU */
    case INDEX_op_setcond_i64:
        tcg_out_cmp(s, ext, a1, a2, c2);
        /* Use CSET alias of CSINC Wd, WZR, WZR, invert(cond).  */
        tcg_out_insn(s, 3506, CSINC, TCG_TYPE_I32, a0, TCG_REG_XZR,
                     TCG_REG_XZR, tcg_invert_cond(args[3]));
        break;

    case INDEX_op_movcond_i32:
        a2 = (int32_t)a2;
        /* FALLTHRU */
    case INDEX_op_movcond_i64:
        tcg_out_cmp(s, ext, a1, a2, c2);
        tcg_out_insn(s, 3506, CSEL, ext, a0, REG0(3), REG0(4), args[5]);
        break;

    case INDEX_op_qemu_ld_i32:
    case INDEX_op_qemu_ld_i64:
        tcg_out_qemu_ld(s, a0, a1, a2, ext);
        break;
    case INDEX_op_qemu_st_i32:
    case INDEX_op_qemu_st_i64:
        tcg_out_qemu_st(s, REG0(0), a1, a2);
        break;

    case INDEX_op_bswap64_i64:
        tcg_out_rev(s, TCG_TYPE_I64, MO_64, a0, a1);
        break;
    case INDEX_op_bswap32_i64:
        tcg_out_rev(s, TCG_TYPE_I32, MO_32, a0, a1);
        if (a2 & TCG_BSWAP_OS) {
            tcg_out_sxt(s, TCG_TYPE_I64, MO_32, a0, a0);
        }
        break;
    case INDEX_op_bswap32_i32:
        tcg_out_rev(s, TCG_TYPE_I32, MO_32, a0, a1);
        break;
    case INDEX_op_bswap16_i64:
    case INDEX_op_bswap16_i32:
        tcg_out_rev(s, TCG_TYPE_I32, MO_16, a0, a1);
        if (a2 & TCG_BSWAP_OS) {
            /* Output must be sign-extended. */
            tcg_out_sxt(s, ext, MO_16, a0, a0);
        } else if ((a2 & (TCG_BSWAP_IZ | TCG_BSWAP_OZ)) == TCG_BSWAP_OZ) {
            /* Output must be zero-extended, but input isn't. */
            tcg_out_uxt(s, MO_16, a0, a0);
        }
        break;

    case INDEX_op_ext8s_i64:
    case INDEX_op_ext8s_i32:
        tcg_out_sxt(s, ext, MO_8, a0, a1);
        break;
    case INDEX_op_ext16s_i64:
    case INDEX_op_ext16s_i32:
        tcg_out_sxt(s, ext, MO_16, a0, a1);
        break;
    case INDEX_op_ext_i32_i64:
    case INDEX_op_ext32s_i64:
        tcg_out_sxt(s, TCG_TYPE_I64, MO_32, a0, a1);
        break;
    case INDEX_op_ext8u_i64:
    case INDEX_op_ext8u_i32:
        tcg_out_uxt(s, MO_8, a0, a1);
        break;
    case INDEX_op_ext16u_i64:
    case INDEX_op_ext16u_i32:
        tcg_out_uxt(s, MO_16, a0, a1);
        break;
    case INDEX_op_extu_i32_i64:
    case INDEX_op_ext32u_i64:
        tcg_out_movr(s, TCG_TYPE_I32, a0, a1);
        break;

    case INDEX_op_deposit_i64:
    case INDEX_op_deposit_i32:
        tcg_out_dep(s, ext, a0, REG0(2), args[3], args[4]);
        break;

    case INDEX_op_extract_i64:
    case INDEX_op_extract_i32:
        tcg_out_ubfm(s, ext, a0, a1, a2, a2 + args[3] - 1);
        break;

    case INDEX_op_sextract_i64:
    case INDEX_op_sextract_i32:
        tcg_out_sbfm(s, ext, a0, a1, a2, a2 + args[3] - 1);
        break;

    case INDEX_op_extract2_i64:
    case INDEX_op_extract2_i32:
        tcg_out_extr(s, ext, a0, REG0(2), REG0(1), args[3]);
        break;

    case INDEX_op_add2_i32:
        tcg_out_addsub2(s, TCG_TYPE_I32, a0, a1, REG0(2), REG0(3),
                        (int32_t)args[4], args[5], const_args[4],
                        const_args[5], false);
        break;
    case INDEX_op_add2_i64:
        tcg_out_addsub2(s, TCG_TYPE_I64, a0, a1, REG0(2), REG0(3), args[4],
                        args[5], const_args[4], const_args[5], false);
        break;
    case INDEX_op_sub2_i32:
        tcg_out_addsub2(s, TCG_TYPE_I32, a0, a1, REG0(2), REG0(3),
                        (int32_t)args[4], args[5], const_args[4],
                        const_args[5], true);
        break;
    case INDEX_op_sub2_i64:
        tcg_out_addsub2(s, TCG_TYPE_I64, a0, a1, REG0(2), REG0(3), args[4],
                        args[5], const_args[4], const_args[5], true);
        break;

    case INDEX_op_muluh_i64:
        tcg_out_insn(s, 3508, UMULH, TCG_TYPE_I64, a0, a1, a2);
        break;
    case INDEX_op_mulsh_i64:
        tcg_out_insn(s, 3508, SMULH, TCG_TYPE_I64, a0, a1, a2);
        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:
        g_assert_not_reached();
    }

#undef REG0
}