aboutsummaryrefslogtreecommitdiff
path: root/target/hexagon/op_helper.c
diff options
context:
space:
mode:
Diffstat (limited to 'target/hexagon/op_helper.c')
-rw-r--r--target/hexagon/op_helper.c392
1 files changed, 258 insertions, 134 deletions
diff --git a/target/hexagon/op_helper.c b/target/hexagon/op_helper.c
index 2c6d718..63dd685 100644
--- a/target/hexagon/op_helper.c
+++ b/target/hexagon/op_helper.c
@@ -25,7 +25,6 @@
#include "arch.h"
#include "hex_arch_types.h"
#include "fma_emu.h"
-#include "conv_emu.h"
#define SF_BIAS 127
#define SF_MANTBITS 23
@@ -35,7 +34,7 @@ static void QEMU_NORETURN do_raise_exception_err(CPUHexagonState *env,
uint32_t exception,
uintptr_t pc)
{
- CPUState *cs = CPU(hexagon_env_get_cpu(env));
+ CPUState *cs = env_cpu(env);
qemu_log_mask(CPU_LOG_INT, "%s: %d\n", __func__, exception);
cs->exception_index = exception;
cpu_loop_exit_restore(cs, pc);
@@ -46,8 +45,8 @@ void QEMU_NORETURN HELPER(raise_exception)(CPUHexagonState *env, uint32_t excp)
do_raise_exception_err(env, excp, 0);
}
-static inline void log_reg_write(CPUHexagonState *env, int rnum,
- target_ulong val, uint32_t slot)
+static void log_reg_write(CPUHexagonState *env, int rnum,
+ target_ulong val, uint32_t slot)
{
HEX_DEBUG_LOG("log_reg_write[%d] = " TARGET_FMT_ld " (0x" TARGET_FMT_lx ")",
rnum, val, val);
@@ -57,14 +56,13 @@ static inline void log_reg_write(CPUHexagonState *env, int rnum,
HEX_DEBUG_LOG("\n");
env->new_value[rnum] = val;
-#if HEX_DEBUG
- /* Do this so HELPER(debug_commit_end) will know */
- env->reg_written[rnum] = 1;
-#endif
+ if (HEX_DEBUG) {
+ /* Do this so HELPER(debug_commit_end) will know */
+ env->reg_written[rnum] = 1;
+ }
}
-static inline void log_pred_write(CPUHexagonState *env, int pnum,
- target_ulong val)
+static void log_pred_write(CPUHexagonState *env, int pnum, target_ulong val)
{
HEX_DEBUG_LOG("log_pred_write[%d] = " TARGET_FMT_ld
" (0x" TARGET_FMT_lx ")\n",
@@ -79,8 +77,8 @@ static inline void log_pred_write(CPUHexagonState *env, int pnum,
}
}
-static inline void log_store32(CPUHexagonState *env, target_ulong addr,
- target_ulong val, int width, int slot)
+static void log_store32(CPUHexagonState *env, target_ulong addr,
+ target_ulong val, int width, int slot)
{
HEX_DEBUG_LOG("log_store%d(0x" TARGET_FMT_lx
", %" PRId32 " [0x08%" PRIx32 "])\n",
@@ -90,8 +88,8 @@ static inline void log_store32(CPUHexagonState *env, target_ulong addr,
env->mem_log_stores[slot].data32 = val;
}
-static inline void log_store64(CPUHexagonState *env, target_ulong addr,
- int64_t val, int width, int slot)
+static void log_store64(CPUHexagonState *env, target_ulong addr,
+ int64_t val, int width, int slot)
{
HEX_DEBUG_LOG("log_store%d(0x" TARGET_FMT_lx
", %" PRId64 " [0x016%" PRIx64 "])\n",
@@ -101,7 +99,7 @@ static inline void log_store64(CPUHexagonState *env, target_ulong addr,
env->mem_log_stores[slot].data64 = val;
}
-static inline void write_new_pc(CPUHexagonState *env, target_ulong addr)
+static void write_new_pc(CPUHexagonState *env, target_ulong addr)
{
HEX_DEBUG_LOG("write_new_pc(0x" TARGET_FMT_lx ")\n", addr);
@@ -119,7 +117,6 @@ static inline void write_new_pc(CPUHexagonState *env, target_ulong addr)
}
}
-#if HEX_DEBUG
/* Handy place to set a breakpoint */
void HELPER(debug_start_packet)(CPUHexagonState *env)
{
@@ -130,14 +127,12 @@ void HELPER(debug_start_packet)(CPUHexagonState *env)
env->reg_written[i] = 0;
}
}
-#endif
-static inline int32_t new_pred_value(CPUHexagonState *env, int pnum)
+static int32_t new_pred_value(CPUHexagonState *env, int pnum)
{
return env->new_pred_value[pnum];
}
-#if HEX_DEBUG
/* Checks for bookkeeping errors between disassembly context and runtime */
void HELPER(debug_check_store_width)(CPUHexagonState *env, int slot, int check)
{
@@ -147,7 +142,6 @@ void HELPER(debug_check_store_width)(CPUHexagonState *env, int slot, int check)
g_assert_not_reached();
}
}
-#endif
void HELPER(commit_store)(CPUHexagonState *env, int slot_num)
{
@@ -173,7 +167,6 @@ void HELPER(commit_store)(CPUHexagonState *env, int slot_num)
}
}
-#if HEX_DEBUG
static void print_store(CPUHexagonState *env, int slot)
{
if (!(env->slot_cancelled & (1 << slot))) {
@@ -257,35 +250,26 @@ void HELPER(debug_commit_end)(CPUHexagonState *env, int has_st0, int has_st1)
env->gpr[HEX_REG_QEMU_INSN_CNT]);
}
-#endif
-
-static int32_t fcircadd_v4(int32_t RxV, int32_t offset, int32_t M, int32_t CS)
-{
- int32_t length = M & 0x0001ffff;
- uint32_t new_ptr = RxV + offset;
- uint32_t start_addr = CS;
- uint32_t end_addr = start_addr + length;
-
- if (new_ptr >= end_addr) {
- new_ptr -= length;
- } else if (new_ptr < start_addr) {
- new_ptr += length;
- }
-
- return new_ptr;
-}
int32_t HELPER(fcircadd)(int32_t RxV, int32_t offset, int32_t M, int32_t CS)
{
- int32_t K_const = (M >> 24) & 0xf;
- int32_t length = M & 0x1ffff;
- int32_t mask = (1 << (K_const + 2)) - 1;
+ int32_t K_const = sextract32(M, 24, 4);
+ int32_t length = sextract32(M, 0, 17);
uint32_t new_ptr = RxV + offset;
- uint32_t start_addr = RxV & (~mask);
- uint32_t end_addr = start_addr | length;
+ uint32_t start_addr;
+ uint32_t end_addr;
if (K_const == 0 && length >= 4) {
- return fcircadd_v4(RxV, offset, M, CS);
+ start_addr = CS;
+ end_addr = start_addr + length;
+ } else {
+ /*
+ * Versions v3 and earlier used the K value to specify a power-of-2 size
+ * 2^(K+2) that is greater than the buffer length
+ */
+ int32_t mask = (1 << (K_const + 2)) - 1;
+ start_addr = RxV & (~mask);
+ end_addr = start_addr | length;
}
if (new_ptr >= end_addr) {
@@ -297,24 +281,103 @@ int32_t HELPER(fcircadd)(int32_t RxV, int32_t offset, int32_t M, int32_t CS)
return new_ptr;
}
+uint32_t HELPER(fbrev)(uint32_t addr)
+{
+ /*
+ * Bit reverse the low 16 bits of the address
+ */
+ return deposit32(addr, 0, 16, revbit16(addr));
+}
+
+static float32 build_float32(uint8_t sign, uint32_t exp, uint32_t mant)
+{
+ return make_float32(
+ ((sign & 1) << 31) |
+ ((exp & 0xff) << SF_MANTBITS) |
+ (mant & ((1 << SF_MANTBITS) - 1)));
+}
+
/*
- * Hexagon FP operations return ~0 insteat of NaN
- * The hex_check_sfnan/hex_check_dfnan functions perform this check
+ * sfrecipa, sfinvsqrta have two 32-bit results
+ * r0,p0=sfrecipa(r1,r2)
+ * r0,p0=sfinvsqrta(r1)
+ *
+ * Since helpers can only return a single value, we pack the two results
+ * into a 64-bit value.
*/
-static float32 hex_check_sfnan(float32 x)
+uint64_t HELPER(sfrecipa)(CPUHexagonState *env, float32 RsV, float32 RtV)
{
- if (float32_is_any_nan(x)) {
- return make_float32(0xFFFFFFFFU);
+ int32_t PeV = 0;
+ float32 RdV;
+ int idx;
+ int adjust;
+ int mant;
+ int exp;
+
+ arch_fpop_start(env);
+ if (arch_sf_recip_common(&RsV, &RtV, &RdV, &adjust, &env->fp_status)) {
+ PeV = adjust;
+ idx = (RtV >> 16) & 0x7f;
+ mant = (recip_lookup_table[idx] << 15) | 1;
+ exp = SF_BIAS - (float32_getexp(RtV) - SF_BIAS) - 1;
+ RdV = build_float32(extract32(RtV, 31, 1), exp, mant);
+ }
+ arch_fpop_end(env);
+ return ((uint64_t)RdV << 32) | PeV;
+}
+
+uint64_t HELPER(sfinvsqrta)(CPUHexagonState *env, float32 RsV)
+{
+ int PeV = 0;
+ float32 RdV;
+ int idx;
+ int adjust;
+ int mant;
+ int exp;
+
+ arch_fpop_start(env);
+ if (arch_sf_invsqrt_common(&RsV, &RdV, &adjust, &env->fp_status)) {
+ PeV = adjust;
+ idx = (RsV >> 17) & 0x7f;
+ mant = (invsqrt_lookup_table[idx] << 15);
+ exp = SF_BIAS - ((float32_getexp(RsV) - SF_BIAS) >> 1) - 1;
+ RdV = build_float32(extract32(RsV, 31, 1), exp, mant);
+ }
+ arch_fpop_end(env);
+ return ((uint64_t)RdV << 32) | PeV;
+}
+
+int64_t HELPER(vacsh_val)(CPUHexagonState *env,
+ int64_t RxxV, int64_t RssV, int64_t RttV)
+{
+ for (int i = 0; i < 4; i++) {
+ int xv = sextract64(RxxV, i * 16, 16);
+ int sv = sextract64(RssV, i * 16, 16);
+ int tv = sextract64(RttV, i * 16, 16);
+ int max;
+ xv = xv + tv;
+ sv = sv - tv;
+ max = xv > sv ? xv : sv;
+ /* Note that fSATH can set the OVF bit in usr */
+ RxxV = deposit64(RxxV, i * 16, 16, fSATH(max));
}
- return x;
+ return RxxV;
}
-static float64 hex_check_dfnan(float64 x)
+int32_t HELPER(vacsh_pred)(CPUHexagonState *env,
+ int64_t RxxV, int64_t RssV, int64_t RttV)
{
- if (float64_is_any_nan(x)) {
- return make_float64(0xFFFFFFFFFFFFFFFFULL);
+ int32_t PeV = 0;
+ for (int i = 0; i < 4; i++) {
+ int xv = sextract64(RxxV, i * 16, 16);
+ int sv = sextract64(RssV, i * 16, 16);
+ int tv = sextract64(RttV, i * 16, 16);
+ xv = xv + tv;
+ sv = sv - tv;
+ PeV = deposit32(PeV, i * 2, 1, (xv > sv));
+ PeV = deposit32(PeV, i * 2 + 1, 1, (xv > sv));
}
- return x;
+ return PeV;
}
/*
@@ -332,8 +395,8 @@ static void check_noshuf(CPUHexagonState *env, uint32_t slot)
}
}
-static inline uint8_t mem_load1(CPUHexagonState *env, uint32_t slot,
- target_ulong vaddr)
+static uint8_t mem_load1(CPUHexagonState *env, uint32_t slot,
+ target_ulong vaddr)
{
uint8_t retval;
check_noshuf(env, slot);
@@ -341,8 +404,8 @@ static inline uint8_t mem_load1(CPUHexagonState *env, uint32_t slot,
return retval;
}
-static inline uint16_t mem_load2(CPUHexagonState *env, uint32_t slot,
- target_ulong vaddr)
+static uint16_t mem_load2(CPUHexagonState *env, uint32_t slot,
+ target_ulong vaddr)
{
uint16_t retval;
check_noshuf(env, slot);
@@ -350,8 +413,8 @@ static inline uint16_t mem_load2(CPUHexagonState *env, uint32_t slot,
return retval;
}
-static inline uint32_t mem_load4(CPUHexagonState *env, uint32_t slot,
- target_ulong vaddr)
+static uint32_t mem_load4(CPUHexagonState *env, uint32_t slot,
+ target_ulong vaddr)
{
uint32_t retval;
check_noshuf(env, slot);
@@ -359,8 +422,8 @@ static inline uint32_t mem_load4(CPUHexagonState *env, uint32_t slot,
return retval;
}
-static inline uint64_t mem_load8(CPUHexagonState *env, uint32_t slot,
- target_ulong vaddr)
+static uint64_t mem_load8(CPUHexagonState *env, uint32_t slot,
+ target_ulong vaddr)
{
uint64_t retval;
check_noshuf(env, slot);
@@ -374,7 +437,6 @@ float64 HELPER(conv_sf2df)(CPUHexagonState *env, float32 RsV)
float64 out_f64;
arch_fpop_start(env);
out_f64 = float32_to_float64(RsV, &env->fp_status);
- out_f64 = hex_check_dfnan(out_f64);
arch_fpop_end(env);
return out_f64;
}
@@ -384,7 +446,6 @@ float32 HELPER(conv_df2sf)(CPUHexagonState *env, float64 RssV)
float32 out_f32;
arch_fpop_start(env);
out_f32 = float64_to_float32(RssV, &env->fp_status);
- out_f32 = hex_check_sfnan(out_f32);
arch_fpop_end(env);
return out_f32;
}
@@ -394,7 +455,6 @@ float32 HELPER(conv_uw2sf)(CPUHexagonState *env, int32_t RsV)
float32 RdV;
arch_fpop_start(env);
RdV = uint32_to_float32(RsV, &env->fp_status);
- RdV = hex_check_sfnan(RdV);
arch_fpop_end(env);
return RdV;
}
@@ -404,7 +464,6 @@ float64 HELPER(conv_uw2df)(CPUHexagonState *env, int32_t RsV)
float64 RddV;
arch_fpop_start(env);
RddV = uint32_to_float64(RsV, &env->fp_status);
- RddV = hex_check_dfnan(RddV);
arch_fpop_end(env);
return RddV;
}
@@ -414,7 +473,6 @@ float32 HELPER(conv_w2sf)(CPUHexagonState *env, int32_t RsV)
float32 RdV;
arch_fpop_start(env);
RdV = int32_to_float32(RsV, &env->fp_status);
- RdV = hex_check_sfnan(RdV);
arch_fpop_end(env);
return RdV;
}
@@ -424,7 +482,6 @@ float64 HELPER(conv_w2df)(CPUHexagonState *env, int32_t RsV)
float64 RddV;
arch_fpop_start(env);
RddV = int32_to_float64(RsV, &env->fp_status);
- RddV = hex_check_dfnan(RddV);
arch_fpop_end(env);
return RddV;
}
@@ -434,7 +491,6 @@ float32 HELPER(conv_ud2sf)(CPUHexagonState *env, int64_t RssV)
float32 RdV;
arch_fpop_start(env);
RdV = uint64_to_float32(RssV, &env->fp_status);
- RdV = hex_check_sfnan(RdV);
arch_fpop_end(env);
return RdV;
}
@@ -444,7 +500,6 @@ float64 HELPER(conv_ud2df)(CPUHexagonState *env, int64_t RssV)
float64 RddV;
arch_fpop_start(env);
RddV = uint64_to_float64(RssV, &env->fp_status);
- RddV = hex_check_dfnan(RddV);
arch_fpop_end(env);
return RddV;
}
@@ -454,7 +509,6 @@ float32 HELPER(conv_d2sf)(CPUHexagonState *env, int64_t RssV)
float32 RdV;
arch_fpop_start(env);
RdV = int64_to_float32(RssV, &env->fp_status);
- RdV = hex_check_sfnan(RdV);
arch_fpop_end(env);
return RdV;
}
@@ -464,16 +518,21 @@ float64 HELPER(conv_d2df)(CPUHexagonState *env, int64_t RssV)
float64 RddV;
arch_fpop_start(env);
RddV = int64_to_float64(RssV, &env->fp_status);
- RddV = hex_check_dfnan(RddV);
arch_fpop_end(env);
return RddV;
}
-int32_t HELPER(conv_sf2uw)(CPUHexagonState *env, float32 RsV)
+uint32_t HELPER(conv_sf2uw)(CPUHexagonState *env, float32 RsV)
{
- int32_t RdV;
+ uint32_t RdV;
arch_fpop_start(env);
- RdV = conv_sf_to_4u(RsV, &env->fp_status);
+ /* Hexagon checks the sign before rounding */
+ if (float32_is_neg(RsV) && !float32_is_any_nan(RsV)) {
+ float_raise(float_flag_invalid, &env->fp_status);
+ RdV = 0;
+ } else {
+ RdV = float32_to_uint32(RsV, &env->fp_status);
+ }
arch_fpop_end(env);
return RdV;
}
@@ -482,16 +541,28 @@ int32_t HELPER(conv_sf2w)(CPUHexagonState *env, float32 RsV)
{
int32_t RdV;
arch_fpop_start(env);
- RdV = conv_sf_to_4s(RsV, &env->fp_status);
+ /* Hexagon returns -1 for NaN */
+ if (float32_is_any_nan(RsV)) {
+ float_raise(float_flag_invalid, &env->fp_status);
+ RdV = -1;
+ } else {
+ RdV = float32_to_int32(RsV, &env->fp_status);
+ }
arch_fpop_end(env);
return RdV;
}
-int64_t HELPER(conv_sf2ud)(CPUHexagonState *env, float32 RsV)
+uint64_t HELPER(conv_sf2ud)(CPUHexagonState *env, float32 RsV)
{
- int64_t RddV;
+ uint64_t RddV;
arch_fpop_start(env);
- RddV = conv_sf_to_8u(RsV, &env->fp_status);
+ /* Hexagon checks the sign before rounding */
+ if (float32_is_neg(RsV) && !float32_is_any_nan(RsV)) {
+ float_raise(float_flag_invalid, &env->fp_status);
+ RddV = 0;
+ } else {
+ RddV = float32_to_uint64(RsV, &env->fp_status);
+ }
arch_fpop_end(env);
return RddV;
}
@@ -500,16 +571,28 @@ int64_t HELPER(conv_sf2d)(CPUHexagonState *env, float32 RsV)
{
int64_t RddV;
arch_fpop_start(env);
- RddV = conv_sf_to_8s(RsV, &env->fp_status);
+ /* Hexagon returns -1 for NaN */
+ if (float32_is_any_nan(RsV)) {
+ float_raise(float_flag_invalid, &env->fp_status);
+ RddV = -1;
+ } else {
+ RddV = float32_to_int64(RsV, &env->fp_status);
+ }
arch_fpop_end(env);
return RddV;
}
-int32_t HELPER(conv_df2uw)(CPUHexagonState *env, float64 RssV)
+uint32_t HELPER(conv_df2uw)(CPUHexagonState *env, float64 RssV)
{
- int32_t RdV;
+ uint32_t RdV;
arch_fpop_start(env);
- RdV = conv_df_to_4u(RssV, &env->fp_status);
+ /* Hexagon checks the sign before rounding */
+ if (float64_is_neg(RssV) && !float64_is_any_nan(RssV)) {
+ float_raise(float_flag_invalid, &env->fp_status);
+ RdV = 0;
+ } else {
+ RdV = float64_to_uint32(RssV, &env->fp_status);
+ }
arch_fpop_end(env);
return RdV;
}
@@ -518,16 +601,28 @@ int32_t HELPER(conv_df2w)(CPUHexagonState *env, float64 RssV)
{
int32_t RdV;
arch_fpop_start(env);
- RdV = conv_df_to_4s(RssV, &env->fp_status);
+ /* Hexagon returns -1 for NaN */
+ if (float64_is_any_nan(RssV)) {
+ float_raise(float_flag_invalid, &env->fp_status);
+ RdV = -1;
+ } else {
+ RdV = float64_to_int32(RssV, &env->fp_status);
+ }
arch_fpop_end(env);
return RdV;
}
-int64_t HELPER(conv_df2ud)(CPUHexagonState *env, float64 RssV)
+uint64_t HELPER(conv_df2ud)(CPUHexagonState *env, float64 RssV)
{
- int64_t RddV;
+ uint64_t RddV;
arch_fpop_start(env);
- RddV = conv_df_to_8u(RssV, &env->fp_status);
+ /* Hexagon checks the sign before rounding */
+ if (float64_is_neg(RssV) && !float64_is_any_nan(RssV)) {
+ float_raise(float_flag_invalid, &env->fp_status);
+ RddV = 0;
+ } else {
+ RddV = float64_to_uint64(RssV, &env->fp_status);
+ }
arch_fpop_end(env);
return RddV;
}
@@ -536,17 +631,28 @@ int64_t HELPER(conv_df2d)(CPUHexagonState *env, float64 RssV)
{
int64_t RddV;
arch_fpop_start(env);
- RddV = conv_df_to_8s(RssV, &env->fp_status);
+ /* Hexagon returns -1 for NaN */
+ if (float64_is_any_nan(RssV)) {
+ float_raise(float_flag_invalid, &env->fp_status);
+ RddV = -1;
+ } else {
+ RddV = float64_to_int64(RssV, &env->fp_status);
+ }
arch_fpop_end(env);
return RddV;
}
-int32_t HELPER(conv_sf2uw_chop)(CPUHexagonState *env, float32 RsV)
+uint32_t HELPER(conv_sf2uw_chop)(CPUHexagonState *env, float32 RsV)
{
- int32_t RdV;
+ uint32_t RdV;
arch_fpop_start(env);
- set_float_rounding_mode(float_round_to_zero, &env->fp_status);
- RdV = conv_sf_to_4u(RsV, &env->fp_status);
+ /* Hexagon checks the sign before rounding */
+ if (float32_is_neg(RsV) && !float32_is_any_nan(RsV)) {
+ float_raise(float_flag_invalid, &env->fp_status);
+ RdV = 0;
+ } else {
+ RdV = float32_to_uint32_round_to_zero(RsV, &env->fp_status);
+ }
arch_fpop_end(env);
return RdV;
}
@@ -555,18 +661,28 @@ int32_t HELPER(conv_sf2w_chop)(CPUHexagonState *env, float32 RsV)
{
int32_t RdV;
arch_fpop_start(env);
- set_float_rounding_mode(float_round_to_zero, &env->fp_status);
- RdV = conv_sf_to_4s(RsV, &env->fp_status);
+ /* Hexagon returns -1 for NaN */
+ if (float32_is_any_nan(RsV)) {
+ float_raise(float_flag_invalid, &env->fp_status);
+ RdV = -1;
+ } else {
+ RdV = float32_to_int32_round_to_zero(RsV, &env->fp_status);
+ }
arch_fpop_end(env);
return RdV;
}
-int64_t HELPER(conv_sf2ud_chop)(CPUHexagonState *env, float32 RsV)
+uint64_t HELPER(conv_sf2ud_chop)(CPUHexagonState *env, float32 RsV)
{
- int64_t RddV;
+ uint64_t RddV;
arch_fpop_start(env);
- set_float_rounding_mode(float_round_to_zero, &env->fp_status);
- RddV = conv_sf_to_8u(RsV, &env->fp_status);
+ /* Hexagon checks the sign before rounding */
+ if (float32_is_neg(RsV) && !float32_is_any_nan(RsV)) {
+ float_raise(float_flag_invalid, &env->fp_status);
+ RddV = 0;
+ } else {
+ RddV = float32_to_uint64_round_to_zero(RsV, &env->fp_status);
+ }
arch_fpop_end(env);
return RddV;
}
@@ -575,18 +691,28 @@ int64_t HELPER(conv_sf2d_chop)(CPUHexagonState *env, float32 RsV)
{
int64_t RddV;
arch_fpop_start(env);
- set_float_rounding_mode(float_round_to_zero, &env->fp_status);
- RddV = conv_sf_to_8s(RsV, &env->fp_status);
+ /* Hexagon returns -1 for NaN */
+ if (float32_is_any_nan(RsV)) {
+ float_raise(float_flag_invalid, &env->fp_status);
+ RddV = -1;
+ } else {
+ RddV = float32_to_int64_round_to_zero(RsV, &env->fp_status);
+ }
arch_fpop_end(env);
return RddV;
}
-int32_t HELPER(conv_df2uw_chop)(CPUHexagonState *env, float64 RssV)
+uint32_t HELPER(conv_df2uw_chop)(CPUHexagonState *env, float64 RssV)
{
- int32_t RdV;
+ uint32_t RdV;
arch_fpop_start(env);
- set_float_rounding_mode(float_round_to_zero, &env->fp_status);
- RdV = conv_df_to_4u(RssV, &env->fp_status);
+ /* Hexagon checks the sign before rounding */
+ if (float64_is_neg(RssV) && !float32_is_any_nan(RssV)) {
+ float_raise(float_flag_invalid, &env->fp_status);
+ RdV = 0;
+ } else {
+ RdV = float64_to_uint32_round_to_zero(RssV, &env->fp_status);
+ }
arch_fpop_end(env);
return RdV;
}
@@ -595,18 +721,28 @@ int32_t HELPER(conv_df2w_chop)(CPUHexagonState *env, float64 RssV)
{
int32_t RdV;
arch_fpop_start(env);
- set_float_rounding_mode(float_round_to_zero, &env->fp_status);
- RdV = conv_df_to_4s(RssV, &env->fp_status);
+ /* Hexagon returns -1 for NaN */
+ if (float64_is_any_nan(RssV)) {
+ float_raise(float_flag_invalid, &env->fp_status);
+ RdV = -1;
+ } else {
+ RdV = float64_to_int32_round_to_zero(RssV, &env->fp_status);
+ }
arch_fpop_end(env);
return RdV;
}
-int64_t HELPER(conv_df2ud_chop)(CPUHexagonState *env, float64 RssV)
+uint64_t HELPER(conv_df2ud_chop)(CPUHexagonState *env, float64 RssV)
{
- int64_t RddV;
+ uint64_t RddV;
arch_fpop_start(env);
- set_float_rounding_mode(float_round_to_zero, &env->fp_status);
- RddV = conv_df_to_8u(RssV, &env->fp_status);
+ /* Hexagon checks the sign before rounding */
+ if (float64_is_neg(RssV) && !float64_is_any_nan(RssV)) {
+ float_raise(float_flag_invalid, &env->fp_status);
+ RddV = 0;
+ } else {
+ RddV = float64_to_uint64_round_to_zero(RssV, &env->fp_status);
+ }
arch_fpop_end(env);
return RddV;
}
@@ -615,8 +751,13 @@ int64_t HELPER(conv_df2d_chop)(CPUHexagonState *env, float64 RssV)
{
int64_t RddV;
arch_fpop_start(env);
- set_float_rounding_mode(float_round_to_zero, &env->fp_status);
- RddV = conv_df_to_8s(RssV, &env->fp_status);
+ /* Hexagon returns -1 for NaN */
+ if (float64_is_any_nan(RssV)) {
+ float_raise(float_flag_invalid, &env->fp_status);
+ RddV = -1;
+ } else {
+ RddV = float64_to_int64_round_to_zero(RssV, &env->fp_status);
+ }
arch_fpop_end(env);
return RddV;
}
@@ -626,7 +767,6 @@ float32 HELPER(sfadd)(CPUHexagonState *env, float32 RsV, float32 RtV)
float32 RdV;
arch_fpop_start(env);
RdV = float32_add(RsV, RtV, &env->fp_status);
- RdV = hex_check_sfnan(RdV);
arch_fpop_end(env);
return RdV;
}
@@ -636,7 +776,6 @@ float32 HELPER(sfsub)(CPUHexagonState *env, float32 RsV, float32 RtV)
float32 RdV;
arch_fpop_start(env);
RdV = float32_sub(RsV, RtV, &env->fp_status);
- RdV = hex_check_sfnan(RdV);
arch_fpop_end(env);
return RdV;
}
@@ -688,7 +827,6 @@ float32 HELPER(sfmax)(CPUHexagonState *env, float32 RsV, float32 RtV)
float32 RdV;
arch_fpop_start(env);
RdV = float32_maxnum(RsV, RtV, &env->fp_status);
- RdV = hex_check_sfnan(RdV);
arch_fpop_end(env);
return RdV;
}
@@ -698,7 +836,6 @@ float32 HELPER(sfmin)(CPUHexagonState *env, float32 RsV, float32 RtV)
float32 RdV;
arch_fpop_start(env);
RdV = float32_minnum(RsV, RtV, &env->fp_status);
- RdV = hex_check_sfnan(RdV);
arch_fpop_end(env);
return RdV;
}
@@ -765,7 +902,6 @@ float64 HELPER(dfadd)(CPUHexagonState *env, float64 RssV, float64 RttV)
float64 RddV;
arch_fpop_start(env);
RddV = float64_add(RssV, RttV, &env->fp_status);
- RddV = hex_check_dfnan(RddV);
arch_fpop_end(env);
return RddV;
}
@@ -775,7 +911,6 @@ float64 HELPER(dfsub)(CPUHexagonState *env, float64 RssV, float64 RttV)
float64 RddV;
arch_fpop_start(env);
RddV = float64_sub(RssV, RttV, &env->fp_status);
- RddV = hex_check_dfnan(RddV);
arch_fpop_end(env);
return RddV;
}
@@ -788,7 +923,6 @@ float64 HELPER(dfmax)(CPUHexagonState *env, float64 RssV, float64 RttV)
if (float64_is_any_nan(RssV) || float64_is_any_nan(RttV)) {
float_raise(float_flag_invalid, &env->fp_status);
}
- RddV = hex_check_dfnan(RddV);
arch_fpop_end(env);
return RddV;
}
@@ -801,7 +935,6 @@ float64 HELPER(dfmin)(CPUHexagonState *env, float64 RssV, float64 RttV)
if (float64_is_any_nan(RssV) || float64_is_any_nan(RttV)) {
float_raise(float_flag_invalid, &env->fp_status);
}
- RddV = hex_check_dfnan(RddV);
arch_fpop_end(env);
return RddV;
}
@@ -877,7 +1010,6 @@ float32 HELPER(sfmpy)(CPUHexagonState *env, float32 RsV, float32 RtV)
float32 RdV;
arch_fpop_start(env);
RdV = internal_mpyf(RsV, RtV, &env->fp_status);
- RdV = hex_check_sfnan(RdV);
arch_fpop_end(env);
return RdV;
}
@@ -887,7 +1019,6 @@ float32 HELPER(sffma)(CPUHexagonState *env, float32 RxV,
{
arch_fpop_start(env);
RxV = internal_fmafx(RsV, RtV, RxV, 0, &env->fp_status);
- RxV = hex_check_sfnan(RxV);
arch_fpop_end(env);
return RxV;
}
@@ -919,7 +1050,6 @@ float32 HELPER(sffma_sc)(CPUHexagonState *env, float32 RxV,
RxV = check_nan(RxV, RsV, &env->fp_status);
RxV = check_nan(RxV, RtV, &env->fp_status);
tmp = internal_fmafx(RsV, RtV, RxV, fSXTN(8, 64, PuV), &env->fp_status);
- tmp = hex_check_sfnan(tmp);
if (!(float32_is_zero(RxV) && is_zero_prod(RsV, RtV))) {
RxV = tmp;
}
@@ -934,12 +1064,11 @@ float32 HELPER(sffms)(CPUHexagonState *env, float32 RxV,
arch_fpop_start(env);
neg_RsV = float32_sub(float32_zero, RsV, &env->fp_status);
RxV = internal_fmafx(neg_RsV, RtV, RxV, 0, &env->fp_status);
- RxV = hex_check_sfnan(RxV);
arch_fpop_end(env);
return RxV;
}
-static inline bool is_inf_prod(int32_t a, int32_t b)
+static bool is_inf_prod(int32_t a, int32_t b)
{
return (float32_is_infinity(a) && float32_is_infinity(b)) ||
(float32_is_infinity(a) && is_finite(b) && !float32_is_zero(b)) ||
@@ -949,8 +1078,8 @@ static inline bool is_inf_prod(int32_t a, int32_t b)
float32 HELPER(sffma_lib)(CPUHexagonState *env, float32 RxV,
float32 RsV, float32 RtV)
{
- int infinp;
- int infminusinf;
+ bool infinp;
+ bool infminusinf;
float32 tmp;
arch_fpop_start(env);
@@ -965,7 +1094,6 @@ float32 HELPER(sffma_lib)(CPUHexagonState *env, float32 RxV,
RxV = check_nan(RxV, RsV, &env->fp_status);
RxV = check_nan(RxV, RtV, &env->fp_status);
tmp = internal_fmafx(RsV, RtV, RxV, 0, &env->fp_status);
- tmp = hex_check_sfnan(tmp);
if (!(float32_is_zero(RxV) && is_zero_prod(RsV, RtV))) {
RxV = tmp;
}
@@ -983,8 +1111,8 @@ float32 HELPER(sffma_lib)(CPUHexagonState *env, float32 RxV,
float32 HELPER(sffms_lib)(CPUHexagonState *env, float32 RxV,
float32 RsV, float32 RtV)
{
- int infinp;
- int infminusinf;
+ bool infinp;
+ bool infminusinf;
float32 tmp;
arch_fpop_start(env);
@@ -1000,7 +1128,6 @@ float32 HELPER(sffms_lib)(CPUHexagonState *env, float32 RxV,
RxV = check_nan(RxV, RtV, &env->fp_status);
float32 minus_RsV = float32_sub(float32_zero, RsV, &env->fp_status);
tmp = internal_fmafx(minus_RsV, RtV, RxV, 0, &env->fp_status);
- tmp = hex_check_sfnan(tmp);
if (!(float32_is_zero(RxV) && is_zero_prod(RsV, RtV))) {
RxV = tmp;
}
@@ -1024,13 +1151,11 @@ float64 HELPER(dfmpyfix)(CPUHexagonState *env, float64 RssV, float64 RttV)
float64_is_normal(RttV)) {
RddV = float64_mul(RssV, make_float64(0x4330000000000000),
&env->fp_status);
- RddV = hex_check_dfnan(RddV);
} else if (float64_is_denormal(RttV) &&
(float64_getexp(RssV) >= 512) &&
float64_is_normal(RssV)) {
RddV = float64_mul(RssV, make_float64(0x3cb0000000000000),
&env->fp_status);
- RddV = hex_check_dfnan(RddV);
} else {
RddV = RssV;
}
@@ -1043,7 +1168,6 @@ float64 HELPER(dfmpyhh)(CPUHexagonState *env, float64 RxxV,
{
arch_fpop_start(env);
RxxV = internal_mpyhh(RssV, RttV, RxxV, &env->fp_status);
- RxxV = hex_check_dfnan(RxxV);
arch_fpop_end(env);
return RxxV;
}