From: Aurelien Jarno <aurelien@aurel32.net>
To: qemu-devel@nongnu.org
Subject: [Qemu-devel] [PATCH][SPARC] Full implementation of IEEE exceptions
Date: Thu, 5 Apr 2007 21:16:44 +0200 [thread overview]
Message-ID: <20070405191644.GA15575@amd64.aurel32.net> (raw)
[-- Attachment #1: Type: text/plain, Size: 1441 bytes --]
Hi,
The attached patch fully implements IEEE exceptions on the SPARC target.
Some more details:
- Any floating point operation that does not trap should clear the ftt
flags. Similary, any floating point operation that does not generate
an IEEE exception should clear the cexec flags. In the patch this
operation is actually done at the same place before emulating the
instruction via op_clear_ieee_excp_and_FTT, and set back to the
correct value in the unlikely case of a trap.
- To compute the IEEE flags, and to trap if needed, every floating point
instruction that can generate a trap is precedeed by a clear of the
IEEE flags of the softmmu functions. After the instruction, the
check_ieee_exceptions function copies the softmmu flags into the FSR
flags (aexec, cexec), and if the corresponding TEM flag is set, a trap
is generated.
- GEN_FCMP has to set the FSR_NVC flag, and should set the ftt flags
to IEEE_754_exception.
- This patch also correctly implements the fcmpes and fcmped instructions
by adding a sixth parameter. If this parameter is set, the comparaison
generates a trap for unordered relations even if FSR_NVM is not set.
Bye,
Aurelien
--
.''`. Aurelien Jarno | GPG: 1024D/F1BCDB73
: :' : Debian developer | Electrical Engineer
`. `' aurel32@debian.org | aurelien@aurel32.net
`- people.debian.org/~aurel32 | www.aurel32.net
[-- Attachment #2: sparc-qemu-ieee_exceptions.diff --]
[-- Type: text/x-diff, Size: 11365 bytes --]
diff -u -d -p -r1.17 exec.h
--- qemu.orig/target-sparc/exec.h 19 Mar 2007 14:47:40 -0000 1.17
+++ qemu/target-sparc/exec.h 5 Apr 2007 18:46:48 -0000
@@ -61,6 +61,8 @@ void do_fsqrts(void);
void do_fsqrtd(void);
void do_fcmps(void);
void do_fcmpd(void);
+void do_fcmpes(void);
+void do_fcmped(void);
#ifdef TARGET_SPARC64
void do_fabsd(void);
void do_fcmps_fcc1(void);
@@ -69,6 +71,12 @@ void do_fcmps_fcc2(void);
void do_fcmpd_fcc2(void);
void do_fcmps_fcc3(void);
void do_fcmpd_fcc3(void);
+void do_fcmpes_fcc1(void);
+void do_fcmped_fcc1(void);
+void do_fcmpes_fcc2(void);
+void do_fcmped_fcc2(void);
+void do_fcmpes_fcc3(void);
+void do_fcmped_fcc3(void);
void do_popc();
void do_wrpstate();
void do_done();
@@ -79,6 +87,7 @@ void do_ldd_user(target_ulong addr);
void do_ldd_raw(target_ulong addr);
void do_interrupt(int intno);
void raise_exception(int tt);
+void check_ieee_exceptions();
void memcpy32(target_ulong *dst, const target_ulong *src);
target_ulong mmu_probe(CPUState *env, target_ulong address, int mmulev);
void dump_mmu(CPUState *env);
diff -u -d -p -r1.27 op.c
--- qemu.orig/target-sparc/op.c 1 Apr 2007 15:38:17 -0000 1.27
+++ qemu/target-sparc/op.c 5 Apr 2007 18:46:48 -0000
@@ -1534,16 +1534,25 @@ void OPPROTO op_flush_T0(void)
helper_flush(T0);
}
+void OPPROTO op_clear_ieee_excp_and_FTT(void)
+{
+ env->fsr &= ~(FSR_FTT_MASK | FSR_CEXEC_MASK);;
+}
+
#define F_OP(name, p) void OPPROTO op_f##name##p(void)
#define F_BINOP(name) \
F_OP(name, s) \
{ \
+ set_float_exception_flags(0, &env->fp_status); \
FT0 = float32_ ## name (FT0, FT1, &env->fp_status); \
+ check_ieee_exceptions(); \
} \
F_OP(name, d) \
{ \
+ set_float_exception_flags(0, &env->fp_status); \
DT0 = float64_ ## name (DT0, DT1, &env->fp_status); \
+ check_ieee_exceptions(); \
}
F_BINOP(add);
@@ -1554,9 +1563,11 @@ F_BINOP(div);
void OPPROTO op_fsmuld(void)
{
+ set_float_exception_flags(0, &env->fp_status);
DT0 = float64_mul(float32_to_float64(FT0, &env->fp_status),
float32_to_float64(FT1, &env->fp_status),
&env->fp_status);
+ check_ieee_exceptions();
}
#define F_HELPER(name) \
@@ -1582,6 +1593,7 @@ F_OP(abs, s)
}
F_HELPER(cmp);
+F_HELPER(cmpe);
#ifdef TARGET_SPARC64
F_OP(neg, d)
@@ -1623,6 +1635,37 @@ void OPPROTO op_fcmpd_fcc3(void)
{
do_fcmpd_fcc3();
}
+
+void OPPROTO op_fcmpes_fcc1(void)
+{
+ do_fcmpes_fcc1();
+}
+
+void OPPROTO op_fcmped_fcc1(void)
+{
+ do_fcmped_fcc1();
+}
+
+void OPPROTO op_fcmpes_fcc2(void)
+{
+ do_fcmpes_fcc2();
+}
+
+void OPPROTO op_fcmped_fcc2(void)
+{
+ do_fcmped_fcc2();
+}
+
+void OPPROTO op_fcmpes_fcc3(void)
+{
+ do_fcmpes_fcc3();
+}
+
+void OPPROTO op_fcmped_fcc3(void)
+{
+ do_fcmped_fcc3();
+}
+
#endif
/* Integer to float conversion. */
@@ -1631,23 +1674,31 @@ F_HELPER(ito);
#else
F_OP(ito, s)
{
+ set_float_exception_flags(0, &env->fp_status);
FT0 = int32_to_float32(*((int32_t *)&FT1), &env->fp_status);
+ check_ieee_exceptions();
}
F_OP(ito, d)
{
+ set_float_exception_flags(0, &env->fp_status);
DT0 = int32_to_float64(*((int32_t *)&FT1), &env->fp_status);
+ check_ieee_exceptions();
}
#ifdef TARGET_SPARC64
F_OP(xto, s)
{
+ set_float_exception_flags(0, &env->fp_status);
FT0 = int64_to_float32(*((int64_t *)&DT1), &env->fp_status);
+ check_ieee_exceptions();
}
F_OP(xto, d)
{
+ set_float_exception_flags(0, &env->fp_status);
DT0 = int64_to_float64(*((int64_t *)&DT1), &env->fp_status);
+ check_ieee_exceptions();
}
#endif
#endif
@@ -1656,34 +1707,46 @@ F_OP(xto, d)
/* floating point conversion */
void OPPROTO op_fdtos(void)
{
+ set_float_exception_flags(0, &env->fp_status);
FT0 = float64_to_float32(DT1, &env->fp_status);
+ check_ieee_exceptions();
}
void OPPROTO op_fstod(void)
{
+ set_float_exception_flags(0, &env->fp_status);
DT0 = float32_to_float64(FT1, &env->fp_status);
+ check_ieee_exceptions();
}
/* Float to integer conversion. */
void OPPROTO op_fstoi(void)
{
+ set_float_exception_flags(0, &env->fp_status);
*((int32_t *)&FT0) = float32_to_int32_round_to_zero(FT1, &env->fp_status);
+ check_ieee_exceptions();
}
void OPPROTO op_fdtoi(void)
{
+ set_float_exception_flags(0, &env->fp_status);
*((int32_t *)&FT0) = float64_to_int32_round_to_zero(DT1, &env->fp_status);
+ check_ieee_exceptions();
}
#ifdef TARGET_SPARC64
void OPPROTO op_fstox(void)
{
+ set_float_exception_flags(0, &env->fp_status);
*((int64_t *)&DT0) = float32_to_int64_round_to_zero(FT1, &env->fp_status);
+ check_ieee_exceptions();
}
void OPPROTO op_fdtox(void)
{
+ set_float_exception_flags(0, &env->fp_status);
*((int64_t *)&DT0) = float64_to_int64_round_to_zero(DT1, &env->fp_status);
+ check_ieee_exceptions();
}
void OPPROTO op_fmovs_cc(void)
diff -u -d -p -r1.23 op_helper.c
--- qemu.orig/target-sparc/op_helper.c 1 Apr 2007 15:15:36 -0000 1.23
+++ qemu/target-sparc/op_helper.c 5 Apr 2007 18:46:48 -0000
@@ -9,10 +9,43 @@ void raise_exception(int tt)
cpu_loop_exit();
}
+void check_ieee_exceptions()
+{
+ T0 = get_float_exception_flags(&env->fp_status);
+ if (T0)
+ {
+ /* Copy IEEE 754 flags into FSR */
+ if (T0 & float_flag_invalid)
+ env->fsr |= FSR_NVC;
+ if (T0 & float_flag_overflow)
+ env->fsr |= FSR_OFC;
+ if (T0 & float_flag_underflow)
+ env->fsr |= FSR_UFC;
+ if (T0 & float_flag_divbyzero)
+ env->fsr |= FSR_DZC;
+ if (T0 & float_flag_inexact)
+ env->fsr |= FSR_NXC;
+
+ if ((env->fsr & FSR_CEXC_MASK) & ((env->fsr & FSR_TEM_MASK) >> 23))
+ {
+ /* Unmasked exception, generate a trap */
+ env->fsr |= FSR_FTT_IEEE_EXCP;
+ raise_exception(TT_FP_EXCP);
+ }
+ else
+ {
+ /* Accumulate exceptions */
+ env->fsr |= (env->fsr & FSR_CEXC_MASK) << 5;
+ }
+ }
+}
+
#ifdef USE_INT_TO_FLOAT_HELPERS
void do_fitos(void)
{
+ set_float_exception_flags(0, &env->fp_status);
FT0 = int32_to_float32(*((int32_t *)&FT1), &env->fp_status);
+ check_ieee_exceptions();
}
void do_fitod(void)
@@ -35,23 +68,29 @@ void do_fabsd(void)
void do_fsqrts(void)
{
+ set_float_exception_flags(0, &env->fp_status);
FT0 = float32_sqrt(FT1, &env->fp_status);
+ check_ieee_exceptions();
}
void do_fsqrtd(void)
{
+ set_float_exception_flags(0, &env->fp_status);
DT0 = float64_sqrt(DT1, &env->fp_status);
+ check_ieee_exceptions();
}
-#define GEN_FCMP(name, size, reg1, reg2, FS) \
+#define GEN_FCMP(name, size, reg1, reg2, FS, TRAP) \
void glue(do_, name) (void) \
{ \
env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS); \
switch (glue(size, _compare) (reg1, reg2, &env->fp_status)) { \
case float_relation_unordered: \
T0 = (FSR_FCC1 | FSR_FCC0) << FS; \
- if (env->fsr & FSR_NVM) { \
+ if ((env->fsr & FSR_NVM) || TRAP) { \
env->fsr |= T0; \
+ env->fsr |= FSR_NVC; \
+ env->fsr |= FSR_FTT_IEEE_EXCP; \
raise_exception(TT_FP_EXCP); \
} else { \
env->fsr |= FSR_NVA; \
@@ -70,18 +109,30 @@ void do_fsqrtd(void)
env->fsr |= T0; \
}
-GEN_FCMP(fcmps, float32, FT0, FT1, 0);
-GEN_FCMP(fcmpd, float64, DT0, DT1, 0);
+GEN_FCMP(fcmps, float32, FT0, FT1, 0, 0);
+GEN_FCMP(fcmpd, float64, DT0, DT1, 0, 0);
+
+GEN_FCMP(fcmpes, float32, FT0, FT1, 0, 1);
+GEN_FCMP(fcmped, float64, DT0, DT1, 0, 1);
#ifdef TARGET_SPARC64
-GEN_FCMP(fcmps_fcc1, float32, FT0, FT1, 22);
-GEN_FCMP(fcmpd_fcc1, float64, DT0, DT1, 22);
+GEN_FCMP(fcmps_fcc1, float32, FT0, FT1, 22, 0);
+GEN_FCMP(fcmpd_fcc1, float64, DT0, DT1, 22, 0);
-GEN_FCMP(fcmps_fcc2, float32, FT0, FT1, 24);
-GEN_FCMP(fcmpd_fcc2, float64, DT0, DT1, 24);
+GEN_FCMP(fcmps_fcc2, float32, FT0, FT1, 24, 0);
+GEN_FCMP(fcmpd_fcc2, float64, DT0, DT1, 24, 0);
-GEN_FCMP(fcmps_fcc3, float32, FT0, FT1, 26);
-GEN_FCMP(fcmpd_fcc3, float64, DT0, DT1, 26);
+GEN_FCMP(fcmps_fcc3, float32, FT0, FT1, 26, 0);
+GEN_FCMP(fcmpd_fcc3, float64, DT0, DT1, 26, 0);
+
+GEN_FCMP(fcmpes_fcc1, float32, FT0, FT1, 22, 1);
+GEN_FCMP(fcmped_fcc1, float64, DT0, DT1, 22, 1);
+
+GEN_FCMP(fcmpes_fcc2, float32, FT0, FT1, 24, 1);
+GEN_FCMP(fcmped_fcc2, float64, DT0, DT1, 24, 1);
+
+GEN_FCMP(fcmpes_fcc3, float32, FT0, FT1, 26, 1);
+GEN_FCMP(fcmped_fcc3, float64, DT0, DT1, 26, 1);
#endif
#if defined(CONFIG_USER_ONLY)
diff -u -d -p -r1.46 translate.c
--- qemu.orig/target-sparc/translate.c 5 Apr 2007 18:12:08 -0000 1.46
+++ qemu/target-sparc/translate.c 5 Apr 2007 18:46:49 -0000
@@ -943,6 +943,21 @@ static GenOpFunc * const gen_fcmpd[4] =
gen_op_fcmpd_fcc2,
gen_op_fcmpd_fcc3,
};
+
+static GenOpFunc * const gen_fcmpes[4] = {
+ gen_op_fcmpes,
+ gen_op_fcmpes_fcc1,
+ gen_op_fcmpes_fcc2,
+ gen_op_fcmpes_fcc3,
+};
+
+static GenOpFunc * const gen_fcmped[4] = {
+ gen_op_fcmped,
+ gen_op_fcmped_fcc1,
+ gen_op_fcmped_fcc2,
+ gen_op_fcmped_fcc3,
+};
+
#endif
static int gen_trap_ifnofpu(DisasContext * dc)
@@ -1289,6 +1304,7 @@ static void disas_sparc_insn(DisasContex
} else if (xop == 0x34) { /* FPU Operations */
if (gen_trap_ifnofpu(dc))
goto jmp_insn;
+ gen_op_clear_ieee_excp_and_FTT();
rs1 = GET_FIELD(insn, 13, 17);
rs2 = GET_FIELD(insn, 27, 31);
xop = GET_FIELD(insn, 18, 26);
@@ -1476,6 +1492,7 @@ static void disas_sparc_insn(DisasContex
#endif
if (gen_trap_ifnofpu(dc))
goto jmp_insn;
+ gen_op_clear_ieee_excp_and_FTT();
rs1 = GET_FIELD(insn, 13, 17);
rs2 = GET_FIELD(insn, 27, 31);
xop = GET_FIELD(insn, 18, 26);
@@ -1653,18 +1670,18 @@ static void disas_sparc_insn(DisasContex
gen_op_load_fpr_FT0(rs1);
gen_op_load_fpr_FT1(rs2);
#ifdef TARGET_SPARC64
- gen_fcmps[rd & 3]();
+ gen_fcmpes[rd & 3]();
#else
- gen_op_fcmps(); /* XXX should trap if qNaN or sNaN */
+ gen_op_fcmpes();
#endif
break;
case 0x56: /* fcmped, V9 %fcc */
gen_op_load_fpr_DT0(DFPREG(rs1));
gen_op_load_fpr_DT1(DFPREG(rs2));
#ifdef TARGET_SPARC64
- gen_fcmpd[rd & 3]();
+ gen_fcmped[rd & 3]();
#else
- gen_op_fcmpd(); /* XXX should trap if qNaN or sNaN */
+ gen_op_fcmped();
#endif
break;
case 0x57: /* fcmpeq */
next reply other threads:[~2007-04-05 19:20 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2007-04-05 19:16 Aurelien Jarno [this message]
2007-04-06 6:22 ` [Qemu-devel] [PATCH][SPARC] Full implementation of IEEE exceptions Blue Swirl
2007-04-06 7:06 ` Aurelien Jarno
2007-04-06 6:47 ` Blue Swirl
2007-04-06 7:07 ` Aurelien Jarno
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20070405191644.GA15575@amd64.aurel32.net \
--to=aurelien@aurel32.net \
--cc=qemu-devel@nongnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).