Commit 6109aea2 authored by Alex Bennée's avatar Alex Bennée Committed by Peter Maydell
Browse files

arm/translate-a64: add FP16 FPRINTx to simd_two_reg_misc_fp16



This adds the full range of half-precision floating point to integral
instructions.

Signed-off-by: default avatarAlex Bennée <alex.bennee@linaro.org>
Reviewed-by: default avatarRichard Henderson <richard.henderson@linaro.org>
Message-id: 20180227143852.11175-18-alex.bennee@linaro.org
Signed-off-by: default avatarPeter Maydell <peter.maydell@linaro.org>
parent 5d432be6
Loading
Loading
Loading
Loading
+22 −0
Original line number Diff line number Diff line
@@ -745,3 +745,25 @@ uint32_t HELPER(advsimd_acgt_f16)(float16 a, float16 b, void *fpstp)
    int compare = float16_compare(f0, f1, fpst);
    return ADVSIMD_CMPRES(compare == float_relation_greater);
}

/* round to integral */
float16 HELPER(advsimd_rinth_exact)(float16 x, void *fp_status)
{
    return float16_round_to_int(x, fp_status);
}

float16 HELPER(advsimd_rinth)(float16 x, void *fp_status)
{
    int old_flags = get_float_exception_flags(fp_status), new_flags;
    float16 ret;

    ret = float16_round_to_int(x, fp_status);

    /* Suppress any inexact exceptions the conversion produced */
    if (!(old_flags & float_flag_inexact)) {
        new_flags = get_float_exception_flags(fp_status);
        set_float_exception_flags(new_flags & ~float_flag_inexact, fp_status);
    }

    return ret;
}
+2 −0
Original line number Diff line number Diff line
@@ -75,3 +75,5 @@ DEF_HELPER_3(advsimd_maxnum2h, i32, i32, i32, ptr)
DEF_HELPER_3(advsimd_minnum2h, i32, i32, i32, ptr)
DEF_HELPER_3(advsimd_mulx2h, i32, i32, i32, ptr)
DEF_HELPER_4(advsimd_muladd2h, i32, i32, i32, i32, ptr)
DEF_HELPER_2(advsimd_rinth_exact, f16, f16, ptr)
DEF_HELPER_2(advsimd_rinth, f16, f16, ptr)
+118 −5
Original line number Diff line number Diff line
@@ -11180,27 +11180,140 @@ static void disas_simd_two_reg_misc(DisasContext *s, uint32_t insn)
 */
static void disas_simd_two_reg_misc_fp16(DisasContext *s, uint32_t insn)
{
    int fpop, opcode, a;
    int fpop, opcode, a, u;
    int rn, rd;
    bool is_q;
    bool is_scalar;
    bool only_in_vector = false;

    int pass;
    TCGv_i32 tcg_rmode = NULL;
    TCGv_ptr tcg_fpstatus = NULL;
    bool need_rmode = false;
    int rmode;

    if (!arm_dc_feature(s, ARM_FEATURE_V8_FP16)) {
        unallocated_encoding(s);
        return;
    }

    if (!fp_access_check(s)) {
        return;
    }
    rd = extract32(insn, 0, 5);
    rn = extract32(insn, 5, 5);

    opcode = extract32(insn, 12, 4);
    a = extract32(insn, 23, 1);
    u = extract32(insn, 29, 1);
    is_scalar = extract32(insn, 28, 1);
    is_q = extract32(insn, 30, 1);

    opcode = extract32(insn, 12, 5);
    fpop = deposit32(opcode, 5, 1, a);
    fpop = deposit32(fpop, 6, 1, u);

    switch (fpop) {
    case 0x18: /* FRINTN */
        need_rmode = true;
        only_in_vector = true;
        rmode = FPROUNDING_TIEEVEN;
        break;
    case 0x19: /* FRINTM */
        need_rmode = true;
        only_in_vector = true;
        rmode = FPROUNDING_NEGINF;
        break;
    case 0x38: /* FRINTP */
        need_rmode = true;
        only_in_vector = true;
        rmode = FPROUNDING_POSINF;
        break;
    case 0x39: /* FRINTZ */
        need_rmode = true;
        only_in_vector = true;
        rmode = FPROUNDING_ZERO;
        break;
    case 0x58: /* FRINTA */
        need_rmode = true;
        only_in_vector = true;
        rmode = FPROUNDING_TIEAWAY;
        break;
    case 0x59: /* FRINTX */
    case 0x79: /* FRINTI */
        only_in_vector = true;
        /* current rounding mode */
        break;
    default:
        fprintf(stderr, "%s: insn %#04x fpop %#2x\n", __func__, insn, fpop);
        g_assert_not_reached();
    }


    /* Check additional constraints for the scalar encoding */
    if (is_scalar) {
        if (!is_q) {
            unallocated_encoding(s);
            return;
        }
        /* FRINTxx is only in the vector form */
        if (only_in_vector) {
            unallocated_encoding(s);
            return;
        }
    }

    if (!fp_access_check(s)) {
        return;
    }

    if (need_rmode) {
        tcg_fpstatus = get_fpstatus_ptr(true);
    }

    if (need_rmode) {
        tcg_rmode = tcg_const_i32(arm_rmode_to_sf(rmode));
        gen_helper_set_rmode(tcg_rmode, tcg_rmode, tcg_fpstatus);
    }

    if (is_scalar) {
        /* no operations yet */
    } else {
        for (pass = 0; pass < (is_q ? 8 : 4); pass++) {
            TCGv_i32 tcg_op = tcg_temp_new_i32();
            TCGv_i32 tcg_res = tcg_temp_new_i32();

            read_vec_element_i32(s, tcg_op, rn, pass, MO_16);

            switch (fpop) {
            case 0x18: /* FRINTN */
            case 0x19: /* FRINTM */
            case 0x38: /* FRINTP */
            case 0x39: /* FRINTZ */
            case 0x58: /* FRINTA */
            case 0x79: /* FRINTI */
                gen_helper_advsimd_rinth(tcg_res, tcg_op, tcg_fpstatus);
                break;
            case 0x59: /* FRINTX */
                gen_helper_advsimd_rinth_exact(tcg_res, tcg_op, tcg_fpstatus);
                break;
            default:
                g_assert_not_reached();
            }

            write_vec_element_i32(s, tcg_res, rd, pass, MO_16);

            tcg_temp_free_i32(tcg_res);
            tcg_temp_free_i32(tcg_op);
        }

        clear_vec_high(s, is_q, rd);
    }

    if (tcg_rmode) {
        gen_helper_set_rmode(tcg_rmode, tcg_rmode, tcg_fpstatus);
        tcg_temp_free_i32(tcg_rmode);
    }

    if (tcg_fpstatus) {
        tcg_temp_free_ptr(tcg_fpstatus);
    }
}

/* AdvSIMD scalar x indexed element