From patchwork Mon Sep 26 10:56:40 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sagar Karandikar X-Patchwork-Id: 9350543 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 5CE4A6077B for ; Mon, 26 Sep 2016 11:45:09 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 4E83328D3E for ; Mon, 26 Sep 2016 11:45:09 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 4245028D51; Mon, 26 Sep 2016 11:45:09 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.9 required=2.0 tests=BAYES_00,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id 24FFC28D3E for ; Mon, 26 Sep 2016 11:45:08 +0000 (UTC) Received: from localhost ([::1]:43515 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1boULL-0007RT-BE for patchwork-qemu-devel@patchwork.kernel.org; Mon, 26 Sep 2016 07:45:07 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:42297) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1boU8d-0003oR-4V for qemu-devel@nongnu.org; Mon, 26 Sep 2016 07:32:01 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1boU8a-0006Vp-2q for qemu-devel@nongnu.org; Mon, 26 Sep 2016 07:31:58 -0400 Received: from gateway0.eecs.berkeley.edu ([169.229.60.87]:41702) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1boU8Z-0006Cc-PE for qemu-devel@nongnu.org; Mon, 26 Sep 2016 07:31:55 -0400 Received: from a8.Millennium.Berkeley.EDU (a8.millennium.berkeley.edu [169.229.49.48]) (authenticated bits=0) by gateway0.EECS.Berkeley.EDU (8.14.7/8.13.5) with ESMTP id u8QAvTWX024255 (version=TLSv1/SSLv3 cipher=AES256-SHA bits=256 verify=NOT); Mon, 26 Sep 2016 03:57:47 -0700 (PDT) From: Sagar Karandikar To: qemu-devel@nongnu.org Date: Mon, 26 Sep 2016 03:56:40 -0700 Message-Id: <88ca2544800fbf4f966df9558f5254d6bd29646b.1474886798.git.sagark@eecs.berkeley.edu> X-Mailer: git-send-email 2.9.3 In-Reply-To: References: In-Reply-To: References: X-detected-operating-system: by eggs.gnu.org: Windows NT kernel [generic] [fuzzy] X-Received-From: 169.229.60.87 Subject: [Qemu-devel] [PATCH 10/18] target-riscv: Add Single Precision Floating-Point Instructions X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: peter.maydell@linaro.org, kbastian@mail.uni-paderborn.de, Sagar Karandikar , rth@twiddle.net Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Sender: "Qemu-devel" X-Virus-Scanned: ClamAV using ClamSMTP Signed-off-by: Sagar Karandikar --- target-riscv/fpu_helper.c | 206 ++++++++++++++++++++++++++++++++++++++++++++++ target-riscv/helper.h | 28 +++++++ target-riscv/translate.c | 146 ++++++++++++++++++++++++++++++++ 3 files changed, 380 insertions(+) diff --git a/target-riscv/fpu_helper.c b/target-riscv/fpu_helper.c index 9023d10..8d33fa1 100644 --- a/target-riscv/fpu_helper.c +++ b/target-riscv/fpu_helper.c @@ -149,3 +149,209 @@ uint64_t helper_fnmadd_d(CPURISCVState *env, uint64_t frs1, uint64_t frs2, set_fp_exceptions(); return frs1; } + +uint64_t helper_fadd_s(CPURISCVState *env, uint64_t frs1, uint64_t frs2, + uint64_t rm) +{ + set_float_rounding_mode(RM, &env->fp_status); + frs1 = float32_add(frs1, frs2, &env->fp_status); + set_fp_exceptions(); + return frs1; +} + +uint64_t helper_fsub_s(CPURISCVState *env, uint64_t frs1, uint64_t frs2, + uint64_t rm) +{ + set_float_rounding_mode(RM, &env->fp_status); + frs1 = float32_sub(frs1, frs2, &env->fp_status); + set_fp_exceptions(); + return frs1; +} + +uint64_t helper_fmul_s(CPURISCVState *env, uint64_t frs1, uint64_t frs2, + uint64_t rm) +{ + set_float_rounding_mode(RM, &env->fp_status); + frs1 = float32_mul(frs1, frs2, &env->fp_status); + set_fp_exceptions(); + return frs1; +} + +uint64_t helper_fdiv_s(CPURISCVState *env, uint64_t frs1, uint64_t frs2, + uint64_t rm) +{ + set_float_rounding_mode(RM, &env->fp_status); + frs1 = float32_div(frs1, frs2, &env->fp_status); + set_fp_exceptions(); + return frs1; +} + +uint64_t helper_fsgnj_s(CPURISCVState *env, uint64_t frs1, uint64_t frs2) +{ + frs1 = (frs1 & ~(uint32_t)INT32_MIN) | (frs2 & (uint32_t)INT32_MIN); + return frs1; +} + +uint64_t helper_fsgnjn_s(CPURISCVState *env, uint64_t frs1, uint64_t frs2) +{ + frs1 = (frs1 & ~(uint32_t)INT32_MIN) | ((~frs2) & (uint32_t)INT32_MIN); + return frs1; +} + +uint64_t helper_fsgnjx_s(CPURISCVState *env, uint64_t frs1, uint64_t frs2) +{ + frs1 = frs1 ^ (frs2 & (uint32_t)INT32_MIN); + return frs1; +} + +uint64_t helper_fmin_s(CPURISCVState *env, uint64_t frs1, uint64_t frs2) +{ + frs1 = float32_is_any_nan(frs2) || + float32_lt_quiet(frs1, frs2, &env->fp_status) ? frs1 : frs2; + set_fp_exceptions(); + return frs1; +} + +uint64_t helper_fmax_s(CPURISCVState *env, uint64_t frs1, uint64_t frs2) +{ + frs1 = float32_is_any_nan(frs2) || + float32_le_quiet(frs2, frs1, &env->fp_status) ? frs1 : frs2; + set_fp_exceptions(); + return frs1; +} + +uint64_t helper_fsqrt_s(CPURISCVState *env, uint64_t frs1, uint64_t rm) +{ + set_float_rounding_mode(RM, &env->fp_status); + frs1 = float32_sqrt(frs1, &env->fp_status); + set_fp_exceptions(); + return frs1; +} + +target_ulong helper_fle_s(CPURISCVState *env, uint64_t frs1, uint64_t frs2) +{ + frs1 = float32_le(frs1, frs2, &env->fp_status); + set_fp_exceptions(); + return frs1; +} + +target_ulong helper_flt_s(CPURISCVState *env, uint64_t frs1, uint64_t frs2) +{ + frs1 = float32_lt(frs1, frs2, &env->fp_status); + set_fp_exceptions(); + return frs1; +} + +target_ulong helper_feq_s(CPURISCVState *env, uint64_t frs1, uint64_t frs2) +{ + frs1 = float32_eq(frs1, frs2, &env->fp_status); + set_fp_exceptions(); + return frs1; +} + +target_ulong helper_fcvt_w_s(CPURISCVState *env, uint64_t frs1, uint64_t rm) +{ + set_float_rounding_mode(RM, &env->fp_status); + frs1 = (int64_t)((int32_t)float32_to_int32(frs1, &env->fp_status)); + set_fp_exceptions(); + return frs1; +} + +target_ulong helper_fcvt_wu_s(CPURISCVState *env, uint64_t frs1, uint64_t rm) +{ + set_float_rounding_mode(RM, &env->fp_status); + frs1 = (int64_t)((int32_t)float32_to_uint32(frs1, &env->fp_status)); + set_fp_exceptions(); + return frs1; +} + +#if defined(TARGET_RISCV64) +uint64_t helper_fcvt_l_s(CPURISCVState *env, uint64_t frs1, uint64_t rm) +{ + set_float_rounding_mode(RM, &env->fp_status); + frs1 = float32_to_int64(frs1, &env->fp_status); + set_fp_exceptions(); + return frs1; +} + +uint64_t helper_fcvt_lu_s(CPURISCVState *env, uint64_t frs1, uint64_t rm) +{ + set_float_rounding_mode(RM, &env->fp_status); + frs1 = float32_to_uint64(frs1, &env->fp_status); + set_fp_exceptions(); + return frs1; +} +#endif + +uint64_t helper_fcvt_s_w(CPURISCVState *env, target_ulong rs1, uint64_t rm) +{ + set_float_rounding_mode(RM, &env->fp_status); + rs1 = int32_to_float32((int32_t)rs1, &env->fp_status); + set_fp_exceptions(); + return rs1; +} + +uint64_t helper_fcvt_s_wu(CPURISCVState *env, target_ulong rs1, uint64_t rm) +{ + set_float_rounding_mode(RM, &env->fp_status); + rs1 = uint32_to_float32((uint32_t)rs1, &env->fp_status); + set_fp_exceptions(); + return rs1; +} + +#if defined(TARGET_RISCV64) +uint64_t helper_fcvt_s_l(CPURISCVState *env, uint64_t rs1, uint64_t rm) +{ + set_float_rounding_mode(RM, &env->fp_status); + rs1 = int64_to_float32(rs1, &env->fp_status); + set_fp_exceptions(); + return rs1; +} + +uint64_t helper_fcvt_s_lu(CPURISCVState *env, uint64_t rs1, uint64_t rm) +{ + set_float_rounding_mode(RM, &env->fp_status); + rs1 = uint64_to_float32(rs1, &env->fp_status); + set_fp_exceptions(); + return rs1; +} +#endif + +/* adapted from spike */ +#define isNaNF32UI(ui) (0xFF000000 < (uint32_t)((uint_fast32_t)ui << 1)) +#define signF32UI(a) ((bool)((uint32_t)a >> 31)) +#define expF32UI(a) ((int_fast16_t)(a >> 23) & 0xFF) +#define fracF32UI(a) (a & 0x007FFFFF) + +union ui32_f32 { uint32_t ui; uint32_t f; }; + +uint_fast16_t float32_classify(uint32_t a, float_status *status) +{ + union ui32_f32 uA; + uint_fast32_t uiA; + + uA.f = a; + uiA = uA.ui; + + uint_fast16_t infOrNaN = expF32UI(uiA) == 0xFF; + uint_fast16_t subnormalOrZero = expF32UI(uiA) == 0; + bool sign = signF32UI(uiA); + + return + (sign && infOrNaN && fracF32UI(uiA) == 0) << 0 | + (sign && !infOrNaN && !subnormalOrZero) << 1 | + (sign && subnormalOrZero && fracF32UI(uiA)) << 2 | + (sign && subnormalOrZero && fracF32UI(uiA) == 0) << 3 | + (!sign && infOrNaN && fracF32UI(uiA) == 0) << 7 | + (!sign && !infOrNaN && !subnormalOrZero) << 6 | + (!sign && subnormalOrZero && fracF32UI(uiA)) << 5 | + (!sign && subnormalOrZero && fracF32UI(uiA) == 0) << 4 | + (isNaNF32UI(uiA) && float32_is_signaling_nan(uiA, status)) << 8 | + (isNaNF32UI(uiA) && !float32_is_signaling_nan(uiA, status)) << 9; +} + +target_ulong helper_fclass_s(CPURISCVState *env, uint64_t frs1) +{ + frs1 = float32_classify(frs1, &env->fp_status); + return frs1; +} diff --git a/target-riscv/helper.h b/target-riscv/helper.h index 586abae5..85b505a 100644 --- a/target-riscv/helper.h +++ b/target-riscv/helper.h @@ -16,3 +16,31 @@ DEF_HELPER_FLAGS_5(fnmsub_s, TCG_CALL_NO_RWG, i64, env, i64, i64, i64, i64) DEF_HELPER_FLAGS_5(fnmsub_d, TCG_CALL_NO_RWG, i64, env, i64, i64, i64, i64) DEF_HELPER_FLAGS_5(fnmadd_s, TCG_CALL_NO_RWG, i64, env, i64, i64, i64, i64) DEF_HELPER_FLAGS_5(fnmadd_d, TCG_CALL_NO_RWG, i64, env, i64, i64, i64, i64) + +/* Floating Point - Single Precision */ +DEF_HELPER_FLAGS_4(fadd_s, TCG_CALL_NO_RWG, i64, env, i64, i64, i64) +DEF_HELPER_FLAGS_4(fsub_s, TCG_CALL_NO_RWG, i64, env, i64, i64, i64) +DEF_HELPER_FLAGS_4(fmul_s, TCG_CALL_NO_RWG, i64, env, i64, i64, i64) +DEF_HELPER_FLAGS_4(fdiv_s, TCG_CALL_NO_RWG, i64, env, i64, i64, i64) +DEF_HELPER_FLAGS_3(fsgnj_s, TCG_CALL_NO_RWG, i64, env, i64, i64) +DEF_HELPER_FLAGS_3(fsgnjn_s, TCG_CALL_NO_RWG, i64, env, i64, i64) +DEF_HELPER_FLAGS_3(fsgnjx_s, TCG_CALL_NO_RWG, i64, env, i64, i64) +DEF_HELPER_FLAGS_3(fmin_s, TCG_CALL_NO_RWG, i64, env, i64, i64) +DEF_HELPER_FLAGS_3(fmax_s, TCG_CALL_NO_RWG, i64, env, i64, i64) +DEF_HELPER_FLAGS_3(fsqrt_s, TCG_CALL_NO_RWG, i64, env, i64, i64) +DEF_HELPER_FLAGS_3(fle_s, TCG_CALL_NO_RWG, tl, env, i64, i64) +DEF_HELPER_FLAGS_3(flt_s, TCG_CALL_NO_RWG, tl, env, i64, i64) +DEF_HELPER_FLAGS_3(feq_s, TCG_CALL_NO_RWG, tl, env, i64, i64) +DEF_HELPER_FLAGS_3(fcvt_w_s, TCG_CALL_NO_RWG, tl, env, i64, i64) +DEF_HELPER_FLAGS_3(fcvt_wu_s, TCG_CALL_NO_RWG, tl, env, i64, i64) +#if defined(TARGET_RISCV64) +DEF_HELPER_FLAGS_3(fcvt_l_s, TCG_CALL_NO_RWG, i64, env, i64, i64) +DEF_HELPER_FLAGS_3(fcvt_lu_s, TCG_CALL_NO_RWG, i64, env, i64, i64) +#endif +DEF_HELPER_FLAGS_3(fcvt_s_w, TCG_CALL_NO_RWG, i64, env, tl, i64) +DEF_HELPER_FLAGS_3(fcvt_s_wu, TCG_CALL_NO_RWG, i64, env, tl, i64) +#if defined(TARGET_RISCV64) +DEF_HELPER_FLAGS_3(fcvt_s_l, TCG_CALL_NO_RWG, i64, env, i64, i64) +DEF_HELPER_FLAGS_3(fcvt_s_lu, TCG_CALL_NO_RWG, i64, env, i64, i64) +#endif +DEF_HELPER_FLAGS_2(fclass_s, TCG_CALL_NO_RWG, tl, env, i64) diff --git a/target-riscv/translate.c b/target-riscv/translate.c index 07f24e8..4140769 100644 --- a/target-riscv/translate.c +++ b/target-riscv/translate.c @@ -881,6 +881,148 @@ static inline void gen_fp_fnmadd(DisasContext *ctx, uint32_t opc, int rd, tcg_temp_free_i64(rm_reg); } +static inline void gen_fp_arith(DisasContext *ctx, uint32_t opc, int rd, + int rs1, int rs2, int rm) +{ + TCGv_i64 rm_reg = tcg_temp_new_i64(); + TCGv write_int_rd = tcg_temp_new(); + tcg_gen_movi_i64(rm_reg, rm); + + switch (opc) { + case OPC_RISC_FADD_S: + gen_helper_fadd_s(cpu_fpr[rd], cpu_env, cpu_fpr[rs1], cpu_fpr[rs2], + rm_reg); + break; + case OPC_RISC_FSUB_S: + gen_helper_fsub_s(cpu_fpr[rd], cpu_env, cpu_fpr[rs1], cpu_fpr[rs2], + rm_reg); + break; + case OPC_RISC_FMUL_S: + gen_helper_fmul_s(cpu_fpr[rd], cpu_env, cpu_fpr[rs1], cpu_fpr[rs2], + rm_reg); + break; + case OPC_RISC_FDIV_S: + gen_helper_fdiv_s(cpu_fpr[rd], cpu_env, cpu_fpr[rs1], cpu_fpr[rs2], + rm_reg); + break; + case OPC_RISC_FSGNJ_S: + /* also handles: OPC_RISC_FSGNJN_S, OPC_RISC_FSGNJX_S */ + if (rm == 0x0) { + gen_helper_fsgnj_s(cpu_fpr[rd], cpu_env, cpu_fpr[rs1], + cpu_fpr[rs2]); + } else if (rm == 0x1) { + gen_helper_fsgnjn_s(cpu_fpr[rd], cpu_env, cpu_fpr[rs1], + cpu_fpr[rs2]); + } else if (rm == 0x2) { + gen_helper_fsgnjx_s(cpu_fpr[rd], cpu_env, cpu_fpr[rs1], + cpu_fpr[rs2]); + } else { + kill_unknown(ctx, RISCV_EXCP_ILLEGAL_INST); + } + break; + case OPC_RISC_FMIN_S: + /* also handles: OPC_RISC_FMAX_S */ + if (rm == 0x0) { + gen_helper_fmin_s(cpu_fpr[rd], cpu_env, cpu_fpr[rs1], cpu_fpr[rs2]); + } else if (rm == 0x1) { + gen_helper_fmax_s(cpu_fpr[rd], cpu_env, cpu_fpr[rs1], cpu_fpr[rs2]); + } else { + kill_unknown(ctx, RISCV_EXCP_ILLEGAL_INST); + } + break; + case OPC_RISC_FSQRT_S: + gen_helper_fsqrt_s(cpu_fpr[rd], cpu_env, cpu_fpr[rs1], rm_reg); + break; + case OPC_RISC_FEQ_S: + /* also handles: OPC_RISC_FLT_S, OPC_RISC_FLE_S */ + if (rm == 0x0) { + gen_helper_fle_s(write_int_rd, cpu_env, cpu_fpr[rs1], cpu_fpr[rs2]); + } else if (rm == 0x1) { + gen_helper_flt_s(write_int_rd, cpu_env, cpu_fpr[rs1], cpu_fpr[rs2]); + } else if (rm == 0x2) { + gen_helper_feq_s(write_int_rd, cpu_env, cpu_fpr[rs1], cpu_fpr[rs2]); + } else { + kill_unknown(ctx, RISCV_EXCP_ILLEGAL_INST); + } + gen_set_gpr(rd, write_int_rd); + break; + case OPC_RISC_FCVT_W_S: + /* also OPC_RISC_FCVT_WU_S, OPC_RISC_FCVT_L_S, OPC_RISC_FCVT_LU_S */ + if (rs2 == 0x0) { /* FCVT_W_S */ + gen_helper_fcvt_w_s(write_int_rd, cpu_env, cpu_fpr[rs1], rm_reg); + } else if (rs2 == 0x1) { /* FCVT_WU_S */ + gen_helper_fcvt_wu_s(write_int_rd, cpu_env, cpu_fpr[rs1], rm_reg); + } else if (rs2 == 0x2) { /* FCVT_L_S */ +#if defined(TARGET_RISCV64) + gen_helper_fcvt_l_s(write_int_rd, cpu_env, cpu_fpr[rs1], rm_reg); +#else + kill_unknown(ctx, RISCV_EXCP_ILLEGAL_INST); +#endif + } else if (rs2 == 0x3) { /* FCVT_LU_S */ +#if defined(TARGET_RISCV64) + gen_helper_fcvt_lu_s(write_int_rd, cpu_env, cpu_fpr[rs1], rm_reg); +#else + kill_unknown(ctx, RISCV_EXCP_ILLEGAL_INST); +#endif + } else { + kill_unknown(ctx, RISCV_EXCP_ILLEGAL_INST); + } + gen_set_gpr(rd, write_int_rd); + break; + case OPC_RISC_FCVT_S_W: + /* also OPC_RISC_FCVT_S_WU, OPC_RISC_FCVT_S_L, OPC_RISC_FCVT_S_LU */ + gen_get_gpr(write_int_rd, rs1); + if (rs2 == 0) { /* FCVT_S_W */ + gen_helper_fcvt_s_w(cpu_fpr[rd], cpu_env, write_int_rd, rm_reg); + } else if (rs2 == 0x1) { /* FCVT_S_WU */ + gen_helper_fcvt_s_wu(cpu_fpr[rd], cpu_env, write_int_rd, rm_reg); + } else if (rs2 == 0x2) { /* FCVT_S_L */ +#if defined(TARGET_RISCV64) + gen_helper_fcvt_s_l(cpu_fpr[rd], cpu_env, write_int_rd, rm_reg); +#else + kill_unknown(ctx, RISCV_EXCP_ILLEGAL_INST); +#endif + } else if (rs2 == 0x3) { /* FCVT_S_LU */ +#if defined(TARGET_RISCV64) + gen_helper_fcvt_s_lu(cpu_fpr[rd], cpu_env, write_int_rd, rm_reg); +#else + kill_unknown(ctx, RISCV_EXCP_ILLEGAL_INST); +#endif + } else { + kill_unknown(ctx, RISCV_EXCP_ILLEGAL_INST); + } + break; + case OPC_RISC_FMV_X_S: + /* also OPC_RISC_FCLASS_S */ + if (rm == 0x0) { /* FMV */ +#if defined(TARGET_RISCV64) + tcg_gen_ext32s_tl(write_int_rd, cpu_fpr[rs1]); +#else + tcg_gen_extrl_i64_i32(write_int_rd, cpu_fpr[rs1]); +#endif + } else if (rm == 0x1) { + gen_helper_fclass_s(write_int_rd, cpu_env, cpu_fpr[rs1]); + } else { + kill_unknown(ctx, RISCV_EXCP_ILLEGAL_INST); + } + gen_set_gpr(rd, write_int_rd); + break; + case OPC_RISC_FMV_S_X: + gen_get_gpr(write_int_rd, rs1); +#if defined(TARGET_RISCV64) + tcg_gen_mov_tl(cpu_fpr[rd], write_int_rd); +#else + tcg_gen_extu_i32_i64(cpu_fpr[rd], write_int_rd); +#endif + break; + default: + kill_unknown(ctx, RISCV_EXCP_ILLEGAL_INST); + break; + } + tcg_temp_free_i64(rm_reg); + tcg_temp_free(write_int_rd); +} + static void decode_opc(CPURISCVState *env, DisasContext *ctx) { int rs1; @@ -1005,6 +1147,10 @@ static void decode_opc(CPURISCVState *env, DisasContext *ctx) gen_fp_fnmadd(ctx, MASK_OP_FP_FNMADD(ctx->opcode), rd, rs1, rs2, GET_RS3(ctx->opcode), GET_RM(ctx->opcode)); break; + case OPC_RISC_FP_ARITH: + gen_fp_arith(ctx, MASK_OP_FP_ARITH(ctx->opcode), rd, rs1, rs2, + GET_RM(ctx->opcode)); + break; default: kill_unknown(ctx, RISCV_EXCP_ILLEGAL_INST); break;