aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--fpu/softfloat-specialize.h691
-rw-r--r--fpu/softfloat.c726
-rw-r--r--hw/display/Makefile.objs2
-rw-r--r--hw/usb/ccid-card-passthru.c2
-rw-r--r--hw/usb/dev-smartcard-reader.c14
-rw-r--r--include/fpu/softfloat-types.h1
-rw-r--r--include/fpu/softfloat.h18
-rw-r--r--target/arm/helper-a64.c7
-rw-r--r--target/arm/helper.c108
-rw-r--r--target/arm/helper.h10
-rw-r--r--target/arm/translate-a64.c37
-rw-r--r--target/arm/translate.c74
-rw-r--r--target/arm/translate.h12
-rw-r--r--target/hppa/cpu.c1
-rw-r--r--target/hppa/op_helper.c2
-rw-r--r--target/m68k/softfloat.c3
-rw-r--r--target/mips/msa_helper.c4
-rw-r--r--target/mips/op_helper.c2
-rw-r--r--target/ppc/fpu_helper.c1
-rw-r--r--target/riscv/fpu_helper.c6
-rw-r--r--target/s390x/fpu_helper.c12
-rw-r--r--target/sh4/cpu.c1
-rw-r--r--target/unicore32/cpu.c2
-rw-r--r--ui/Makefile.objs11
-rw-r--r--ui/console.c5
-rw-r--r--ui/sdl2-2d.c6
26 files changed, 742 insertions, 1016 deletions
diff --git a/fpu/softfloat-specialize.h b/fpu/softfloat-specialize.h
index 27834af..16c0bcb 100644
--- a/fpu/softfloat-specialize.h
+++ b/fpu/softfloat-specialize.h
@@ -79,82 +79,111 @@ this code that are retained.
* version 2 or later. See the COPYING file in the top-level directory.
*/
-#if defined(TARGET_XTENSA)
/* Define for architectures which deviate from IEEE in not supporting
* signaling NaNs (so all NaNs are treated as quiet).
*/
+#if defined(TARGET_XTENSA)
#define NO_SIGNALING_NANS 1
#endif
-/*----------------------------------------------------------------------------
-| The pattern for a default generated half-precision NaN.
-*----------------------------------------------------------------------------*/
-float16 float16_default_nan(float_status *status)
+/* Define how the architecture discriminates signaling NaNs.
+ * This done with the most significant bit of the fraction.
+ * In IEEE 754-1985 this was implementation defined, but in IEEE 754-2008
+ * the msb must be zero. MIPS is (so far) unique in supporting both the
+ * 2008 revision and backward compatibility with their original choice.
+ * Thus for MIPS we must make the choice at runtime.
+ */
+static inline flag snan_bit_is_one(float_status *status)
{
-#if defined(TARGET_ARM)
- return const_float16(0x7E00);
-#else
- if (status->snan_bit_is_one) {
- return const_float16(0x7DFF);
- } else {
#if defined(TARGET_MIPS)
- return const_float16(0x7E00);
+ return status->snan_bit_is_one;
+#elif defined(TARGET_HPPA) || defined(TARGET_UNICORE32) || defined(TARGET_SH4)
+ return 1;
#else
- return const_float16(0xFE00);
+ return 0;
#endif
- }
+}
+
+/*----------------------------------------------------------------------------
+| For the deconstructed floating-point with fraction FRAC, return true
+| if the fraction represents a signalling NaN; otherwise false.
+*----------------------------------------------------------------------------*/
+
+static bool parts_is_snan_frac(uint64_t frac, float_status *status)
+{
+#ifdef NO_SIGNALING_NANS
+ return false;
+#else
+ flag msb = extract64(frac, DECOMPOSED_BINARY_POINT - 1, 1);
+ return msb == snan_bit_is_one(status);
#endif
}
/*----------------------------------------------------------------------------
-| The pattern for a default generated single-precision NaN.
+| The pattern for a default generated deconstructed floating-point NaN.
*----------------------------------------------------------------------------*/
-float32 float32_default_nan(float_status *status)
+
+static FloatParts parts_default_nan(float_status *status)
{
+ bool sign = 0;
+ uint64_t frac;
+
#if defined(TARGET_SPARC) || defined(TARGET_M68K)
- return const_float32(0x7FFFFFFF);
-#elif defined(TARGET_PPC) || defined(TARGET_ARM) || defined(TARGET_ALPHA) || \
- defined(TARGET_XTENSA) || defined(TARGET_S390X) || \
- defined(TARGET_TRICORE) || defined(TARGET_RISCV)
- return const_float32(0x7FC00000);
+ /* !snan_bit_is_one, set all bits */
+ frac = (1ULL << DECOMPOSED_BINARY_POINT) - 1;
+#elif defined(TARGET_I386) || defined(TARGET_X86_64) \
+ || defined(TARGET_MICROBLAZE)
+ /* !snan_bit_is_one, set sign and msb */
+ frac = 1ULL << (DECOMPOSED_BINARY_POINT - 1);
+ sign = 1;
#elif defined(TARGET_HPPA)
- return const_float32(0x7FA00000);
+ /* snan_bit_is_one, set msb-1. */
+ frac = 1ULL << (DECOMPOSED_BINARY_POINT - 2);
#else
- if (status->snan_bit_is_one) {
- return const_float32(0x7FBFFFFF);
+ /* This case is true for Alpha, ARM, MIPS, OpenRISC, PPC, RISC-V,
+ * S390, SH4, TriCore, and Xtensa. I cannot find documentation
+ * for Unicore32; the choice from the original commit is unchanged.
+ * Our other supported targets, CRIS, LM32, Moxie, Nios2, and Tile,
+ * do not have floating-point.
+ */
+ if (snan_bit_is_one(status)) {
+ /* set all bits other than msb */
+ frac = (1ULL << (DECOMPOSED_BINARY_POINT - 1)) - 1;
} else {
-#if defined(TARGET_MIPS)
- return const_float32(0x7FC00000);
-#else
- return const_float32(0xFFC00000);
-#endif
+ /* set msb */
+ frac = 1ULL << (DECOMPOSED_BINARY_POINT - 1);
}
#endif
+
+ return (FloatParts) {
+ .cls = float_class_qnan,
+ .sign = sign,
+ .exp = INT_MAX,
+ .frac = frac
+ };
}
/*----------------------------------------------------------------------------
-| The pattern for a default generated double-precision NaN.
+| Returns a quiet NaN from a signalling NaN for the deconstructed
+| floating-point parts.
*----------------------------------------------------------------------------*/
-float64 float64_default_nan(float_status *status)
+
+static FloatParts parts_silence_nan(FloatParts a, float_status *status)
{
-#if defined(TARGET_SPARC) || defined(TARGET_M68K)
- return const_float64(LIT64(0x7FFFFFFFFFFFFFFF));
-#elif defined(TARGET_PPC) || defined(TARGET_ARM) || defined(TARGET_ALPHA) || \
- defined(TARGET_S390X) || defined(TARGET_RISCV)
- return const_float64(LIT64(0x7FF8000000000000));
+#ifdef NO_SIGNALING_NANS
+ g_assert_not_reached();
#elif defined(TARGET_HPPA)
- return const_float64(LIT64(0x7FF4000000000000));
+ a.frac &= ~(1ULL << (DECOMPOSED_BINARY_POINT - 1));
+ a.frac |= 1ULL << (DECOMPOSED_BINARY_POINT - 2);
#else
- if (status->snan_bit_is_one) {
- return const_float64(LIT64(0x7FF7FFFFFFFFFFFF));
+ if (snan_bit_is_one(status)) {
+ return parts_default_nan(status);
} else {
-#if defined(TARGET_MIPS)
- return const_float64(LIT64(0x7FF8000000000000));
-#else
- return const_float64(LIT64(0xFFF8000000000000));
-#endif
+ a.frac |= 1ULL << (DECOMPOSED_BINARY_POINT - 1);
}
#endif
+ a.cls = float_class_qnan;
+ return a;
}
/*----------------------------------------------------------------------------
@@ -163,17 +192,16 @@ float64 float64_default_nan(float_status *status)
floatx80 floatx80_default_nan(float_status *status)
{
floatx80 r;
+
+ /* None of the targets that have snan_bit_is_one use floatx80. */
+ assert(!snan_bit_is_one(status));
#if defined(TARGET_M68K)
r.low = LIT64(0xFFFFFFFFFFFFFFFF);
r.high = 0x7FFF;
#else
- if (status->snan_bit_is_one) {
- r.low = LIT64(0xBFFFFFFFFFFFFFFF);
- r.high = 0x7FFF;
- } else {
- r.low = LIT64(0xC000000000000000);
- r.high = 0xFFFF;
- }
+ /* X86 */
+ r.low = LIT64(0xC000000000000000);
+ r.high = 0xFFFF;
#endif
return r;
}
@@ -193,27 +221,6 @@ const floatx80 floatx80_infinity
= make_floatx80_init(floatx80_infinity_high, floatx80_infinity_low);
/*----------------------------------------------------------------------------
-| The pattern for a default generated quadruple-precision NaN.
-*----------------------------------------------------------------------------*/
-float128 float128_default_nan(float_status *status)
-{
- float128 r;
-
- if (status->snan_bit_is_one) {
- r.low = LIT64(0xFFFFFFFFFFFFFFFF);
- r.high = LIT64(0x7FFF7FFFFFFFFFFF);
- } else {
- r.low = LIT64(0x0000000000000000);
-#if defined(TARGET_S390X) || defined(TARGET_PPC) || defined(TARGET_RISCV)
- r.high = LIT64(0x7FFF800000000000);
-#else
- r.high = LIT64(0xFFFF800000000000);
-#endif
- }
- return r;
-}
-
-/*----------------------------------------------------------------------------
| Raises the exceptions specified by `flags'. Floating-point traps can be
| defined here if desired. It is currently not possible for such a trap
| to substitute a result value. If traps are not implemented, this routine
@@ -233,17 +240,6 @@ typedef struct {
uint64_t high, low;
} commonNaNT;
-#ifdef NO_SIGNALING_NANS
-int float16_is_quiet_nan(float16 a_, float_status *status)
-{
- return float16_is_any_nan(a_);
-}
-
-int float16_is_signaling_nan(float16 a_, float_status *status)
-{
- return 0;
-}
-#else
/*----------------------------------------------------------------------------
| Returns 1 if the half-precision floating-point value `a' is a quiet
| NaN; otherwise returns 0.
@@ -251,12 +247,16 @@ int float16_is_signaling_nan(float16 a_, float_status *status)
int float16_is_quiet_nan(float16 a_, float_status *status)
{
+#ifdef NO_SIGNALING_NANS
+ return float16_is_any_nan(a_);
+#else
uint16_t a = float16_val(a_);
- if (status->snan_bit_is_one) {
+ if (snan_bit_is_one(status)) {
return (((a >> 9) & 0x3F) == 0x3E) && (a & 0x1FF);
} else {
return ((a & ~0x8000) >= 0x7C80);
}
+#endif
}
/*----------------------------------------------------------------------------
@@ -266,97 +266,35 @@ int float16_is_quiet_nan(float16 a_, float_status *status)
int float16_is_signaling_nan(float16 a_, float_status *status)
{
+#ifdef NO_SIGNALING_NANS
+ return 0;
+#else
uint16_t a = float16_val(a_);
- if (status->snan_bit_is_one) {
+ if (snan_bit_is_one(status)) {
return ((a & ~0x8000) >= 0x7C80);
} else {
return (((a >> 9) & 0x3F) == 0x3E) && (a & 0x1FF);
}
-}
#endif
-
-/*----------------------------------------------------------------------------
-| Returns a quiet NaN if the half-precision floating point value `a' is a
-| signaling NaN; otherwise returns `a'.
-*----------------------------------------------------------------------------*/
-float16 float16_maybe_silence_nan(float16 a_, float_status *status)
-{
- if (float16_is_signaling_nan(a_, status)) {
- if (status->snan_bit_is_one) {
- return float16_default_nan(status);
- } else {
- uint16_t a = float16_val(a_);
- a |= (1 << 9);
- return make_float16(a);
- }
- }
- return a_;
-}
-
-/*----------------------------------------------------------------------------
-| Returns the result of converting the half-precision floating-point NaN
-| `a' to the canonical NaN format. If `a' is a signaling NaN, the invalid
-| exception is raised.
-*----------------------------------------------------------------------------*/
-
-static commonNaNT float16ToCommonNaN(float16 a, float_status *status)
-{
- commonNaNT z;
-
- if (float16_is_signaling_nan(a, status)) {
- float_raise(float_flag_invalid, status);
- }
- z.sign = float16_val(a) >> 15;
- z.low = 0;
- z.high = ((uint64_t) float16_val(a)) << 54;
- return z;
}
/*----------------------------------------------------------------------------
-| Returns the result of converting the canonical NaN `a' to the half-
-| precision floating-point format.
-*----------------------------------------------------------------------------*/
-
-static float16 commonNaNToFloat16(commonNaNT a, float_status *status)
-{
- uint16_t mantissa = a.high >> 54;
-
- if (status->default_nan_mode) {
- return float16_default_nan(status);
- }
-
- if (mantissa) {
- return make_float16(((((uint16_t) a.sign) << 15)
- | (0x1F << 10) | mantissa));
- } else {
- return float16_default_nan(status);
- }
-}
-
-#ifdef NO_SIGNALING_NANS
-int float32_is_quiet_nan(float32 a_, float_status *status)
-{
- return float32_is_any_nan(a_);
-}
-
-int float32_is_signaling_nan(float32 a_, float_status *status)
-{
- return 0;
-}
-#else
-/*----------------------------------------------------------------------------
| Returns 1 if the single-precision floating-point value `a' is a quiet
| NaN; otherwise returns 0.
*----------------------------------------------------------------------------*/
int float32_is_quiet_nan(float32 a_, float_status *status)
{
+#ifdef NO_SIGNALING_NANS
+ return float32_is_any_nan(a_);
+#else
uint32_t a = float32_val(a_);
- if (status->snan_bit_is_one) {
+ if (snan_bit_is_one(status)) {
return (((a >> 22) & 0x1FF) == 0x1FE) && (a & 0x003FFFFF);
} else {
return ((uint32_t)(a << 1) >= 0xFF800000);
}
+#endif
}
/*----------------------------------------------------------------------------
@@ -366,39 +304,16 @@ int float32_is_quiet_nan(float32 a_, float_status *status)
int float32_is_signaling_nan(float32 a_, float_status *status)
{
+#ifdef NO_SIGNALING_NANS
+ return 0;
+#else
uint32_t a = float32_val(a_);
- if (status->snan_bit_is_one) {
+ if (snan_bit_is_one(status)) {
return ((uint32_t)(a << 1) >= 0xFF800000);
} else {
return (((a >> 22) & 0x1FF) == 0x1FE) && (a & 0x003FFFFF);
}
-}
-#endif
-
-/*----------------------------------------------------------------------------
-| Returns a quiet NaN if the single-precision floating point value `a' is a
-| signaling NaN; otherwise returns `a'.
-*----------------------------------------------------------------------------*/
-
-float32 float32_maybe_silence_nan(float32 a_, float_status *status)
-{
- if (float32_is_signaling_nan(a_, status)) {
- if (status->snan_bit_is_one) {
-#ifdef TARGET_HPPA
- uint32_t a = float32_val(a_);
- a &= ~0x00400000;
- a |= 0x00200000;
- return make_float32(a);
-#else
- return float32_default_nan(status);
#endif
- } else {
- uint32_t a = float32_val(a_);
- a |= (1 << 22);
- return make_float32(a);
- }
- }
- return a_;
}
/*----------------------------------------------------------------------------
@@ -448,7 +363,7 @@ static float32 commonNaNToFloat32(commonNaNT a, float_status *status)
| The routine is passed various bits of information about the
| two NaNs and should return 0 to select NaN a and 1 for NaN b.
| Note that signalling NaNs are always squashed to quiet NaNs
-| by the caller, by calling floatXX_maybe_silence_nan() before
+| by the caller, by calling floatXX_silence_nan() before
| returning them.
|
| aIsLargerSignificand is only valid if both a and b are NaNs
@@ -458,10 +373,10 @@ static float32 commonNaNToFloat32(commonNaNT a, float_status *status)
| tie-break rule.
*----------------------------------------------------------------------------*/
-#if defined(TARGET_ARM)
-static int pickNaN(flag aIsQNaN, flag aIsSNaN, flag bIsQNaN, flag bIsSNaN,
+static int pickNaN(FloatClass a_cls, FloatClass b_cls,
flag aIsLargerSignificand)
{
+#if defined(TARGET_ARM) || defined(TARGET_MIPS) || defined(TARGET_HPPA)
/* ARM mandated NaN propagation rules (see FPProcessNaNs()), take
* the first of:
* 1. A if it is signaling
@@ -470,23 +385,9 @@ static int pickNaN(flag aIsQNaN, flag aIsSNaN, flag bIsQNaN, flag bIsSNaN,
* 4. B (quiet)
* A signaling NaN is always quietened before returning it.
*/
- if (aIsSNaN) {
- return 0;
- } else if (bIsSNaN) {
- return 1;
- } else if (aIsQNaN) {
- return 0;
- } else {
- return 1;
- }
-}
-#elif defined(TARGET_MIPS) || defined(TARGET_HPPA)
-static int pickNaN(flag aIsQNaN, flag aIsSNaN, flag bIsQNaN, flag bIsSNaN,
- flag aIsLargerSignificand)
-{
/* According to MIPS specifications, if one of the two operands is
* a sNaN, a new qNaN has to be generated. This is done in
- * floatXX_maybe_silence_nan(). For qNaN inputs the specifications
+ * floatXX_silence_nan(). For qNaN inputs the specifications
* says: "When possible, this QNaN result is one of the operand QNaN
* values." In practice it seems that most implementations choose
* the first operand if both operands are qNaN. In short this gives
@@ -497,35 +398,21 @@ static int pickNaN(flag aIsQNaN, flag aIsSNaN, flag bIsQNaN, flag bIsSNaN,
* 4. B (quiet)
* A signaling NaN is always silenced before returning it.
*/
- if (aIsSNaN) {
+ if (is_snan(a_cls)) {
return 0;
- } else if (bIsSNaN) {
+ } else if (is_snan(b_cls)) {
return 1;
- } else if (aIsQNaN) {
+ } else if (is_qnan(a_cls)) {
return 0;
} else {
return 1;
}
-}
-#elif defined(TARGET_PPC) || defined(TARGET_XTENSA)
-static int pickNaN(flag aIsQNaN, flag aIsSNaN, flag bIsQNaN, flag bIsSNaN,
- flag aIsLargerSignificand)
-{
+#elif defined(TARGET_PPC) || defined(TARGET_XTENSA) || defined(TARGET_M68K)
/* PowerPC propagation rules:
* 1. A if it sNaN or qNaN
* 2. B if it sNaN or qNaN
* A signaling NaN is always silenced before returning it.
*/
- if (aIsSNaN || aIsQNaN) {
- return 0;
- } else {
- return 1;
- }
-}
-#elif defined(TARGET_M68K)
-static int pickNaN(flag aIsQNaN, flag aIsSNaN, flag bIsQNaN, flag bIsSNaN,
- flag aIsLargerSignificand)
-{
/* M68000 FAMILY PROGRAMMER'S REFERENCE MANUAL
* 3.4 FLOATING-POINT INSTRUCTION DETAILS
* If either operand, but not both operands, of an operation is a
@@ -540,16 +427,12 @@ static int pickNaN(flag aIsQNaN, flag aIsSNaN, flag bIsQNaN, flag bIsSNaN,
* a nonsignaling NaN. The operation then continues as described in the
* preceding paragraph for nonsignaling NaNs.
*/
- if (aIsQNaN || aIsSNaN) { /* a is the destination operand */
- return 0; /* return the destination operand */
+ if (is_nan(a_cls)) {
+ return 0;
} else {
- return 1; /* return b */
+ return 1;
}
-}
#else
-static int pickNaN(flag aIsQNaN, flag aIsSNaN, flag bIsQNaN, flag bIsSNaN,
- flag aIsLargerSignificand)
-{
/* This implements x87 NaN propagation rules:
* SNaN + QNaN => return the QNaN
* two SNaNs => return the one with the larger significand, silenced
@@ -560,13 +443,13 @@ static int pickNaN(flag aIsQNaN, flag aIsSNaN, flag bIsQNaN, flag bIsSNaN,
* If we get down to comparing significands and they are the same,
* return the NaN with the positive sign bit (if any).
*/
- if (aIsSNaN) {
- if (bIsSNaN) {
+ if (is_snan(a_cls)) {
+ if (is_snan(b_cls)) {
return aIsLargerSignificand ? 0 : 1;
}
- return bIsQNaN ? 1 : 0;
- } else if (aIsQNaN) {
- if (bIsSNaN || !bIsQNaN) {
+ return is_qnan(b_cls) ? 1 : 0;
+ } else if (is_qnan(a_cls)) {
+ if (is_snan(b_cls) || !is_qnan(b_cls)) {
return 0;
} else {
return aIsLargerSignificand ? 0 : 1;
@@ -574,8 +457,8 @@ static int pickNaN(flag aIsQNaN, flag aIsSNaN, flag bIsQNaN, flag bIsSNaN,
} else {
return 1;
}
-}
#endif
+}
/*----------------------------------------------------------------------------
| Select which NaN to propagate for a three-input operation.
@@ -583,15 +466,14 @@ static int pickNaN(flag aIsQNaN, flag aIsSNaN, flag bIsQNaN, flag bIsSNaN,
| information.
| Return values : 0 : a; 1 : b; 2 : c; 3 : default-NaN
*----------------------------------------------------------------------------*/
-#if defined(TARGET_ARM)
-static int pickNaNMulAdd(flag aIsQNaN, flag aIsSNaN, flag bIsQNaN, flag bIsSNaN,
- flag cIsQNaN, flag cIsSNaN, flag infzero,
- float_status *status)
+static int pickNaNMulAdd(FloatClass a_cls, FloatClass b_cls, FloatClass c_cls,
+ bool infzero, float_status *status)
{
+#if defined(TARGET_ARM)
/* For ARM, the (inf,zero,qnan) case sets InvalidOp and returns
* the default NaN
*/
- if (infzero && cIsQNaN) {
+ if (infzero && is_qnan(c_cls)) {
float_raise(float_flag_invalid, status);
return 3;
}
@@ -599,25 +481,20 @@ static int pickNaNMulAdd(flag aIsQNaN, flag aIsSNaN, flag bIsQNaN, flag bIsSNaN,
/* This looks different from the ARM ARM pseudocode, because the ARM ARM
* puts the operands to a fused mac operation (a*b)+c in the order c,a,b.
*/
- if (cIsSNaN) {
+ if (is_snan(c_cls)) {
return 2;
- } else if (aIsSNaN) {
+ } else if (is_snan(a_cls)) {
return 0;
- } else if (bIsSNaN) {
+ } else if (is_snan(b_cls)) {
return 1;
- } else if (cIsQNaN) {
+ } else if (is_qnan(c_cls)) {
return 2;
- } else if (aIsQNaN) {
+ } else if (is_qnan(a_cls)) {
return 0;
} else {
return 1;
}
-}
#elif defined(TARGET_MIPS)
-static int pickNaNMulAdd(flag aIsQNaN, flag aIsSNaN, flag bIsQNaN, flag bIsSNaN,
- flag cIsQNaN, flag cIsSNaN, flag infzero,
- float_status *status)
-{
/* For MIPS, the (inf,zero,qnan) case sets InvalidOp and returns
* the default NaN
*/
@@ -626,43 +503,38 @@ static int pickNaNMulAdd(flag aIsQNaN, flag aIsSNaN, flag bIsQNaN, flag bIsSNaN,
return 3;
}
- if (status->snan_bit_is_one) {
+ if (snan_bit_is_one(status)) {
/* Prefer sNaN over qNaN, in the a, b, c order. */
- if (aIsSNaN) {
+ if (is_snan(a_cls)) {
return 0;
- } else if (bIsSNaN) {
+ } else if (is_snan(b_cls)) {
return 1;
- } else if (cIsSNaN) {
+ } else if (is_snan(c_cls)) {
return 2;
- } else if (aIsQNaN) {
+ } else if (is_qnan(a_cls)) {
return 0;
- } else if (bIsQNaN) {
+ } else if (is_qnan(b_cls)) {
return 1;
} else {
return 2;
}
} else {
/* Prefer sNaN over qNaN, in the c, a, b order. */
- if (cIsSNaN) {
+ if (is_snan(c_cls)) {
return 2;
- } else if (aIsSNaN) {
+ } else if (is_snan(a_cls)) {
return 0;
- } else if (bIsSNaN) {
+ } else if (is_snan(b_cls)) {
return 1;
- } else if (cIsQNaN) {
+ } else if (is_qnan(c_cls)) {
return 2;
- } else if (aIsQNaN) {
+ } else if (is_qnan(a_cls)) {
return 0;
} else {
return 1;
}
}
-}
#elif defined(TARGET_PPC)
-static int pickNaNMulAdd(flag aIsQNaN, flag aIsSNaN, flag bIsQNaN, flag bIsSNaN,
- flag cIsQNaN, flag cIsSNaN, flag infzero,
- float_status *status)
-{
/* For PPC, the (inf,zero,qnan) case sets InvalidOp, but we prefer
* to return an input NaN if we have one (ie c) rather than generating
* a default NaN
@@ -675,31 +547,26 @@ static int pickNaNMulAdd(flag aIsQNaN, flag aIsSNaN, flag bIsQNaN, flag bIsSNaN,
/* If fRA is a NaN return it; otherwise if fRB is a NaN return it;
* otherwise return fRC. Note that muladd on PPC is (fRA * fRC) + frB
*/
- if (aIsSNaN || aIsQNaN) {
+ if (is_nan(a_cls)) {
return 0;
- } else if (cIsSNaN || cIsQNaN) {
+ } else if (is_nan(c_cls)) {
return 2;
} else {
return 1;
}
-}
#else
-/* A default implementation: prefer a to b to c.
- * This is unlikely to actually match any real implementation.
- */
-static int pickNaNMulAdd(flag aIsQNaN, flag aIsSNaN, flag bIsQNaN, flag bIsSNaN,
- flag cIsQNaN, flag cIsSNaN, flag infzero,
- float_status *status)
-{
- if (aIsSNaN || aIsQNaN) {
+ /* A default implementation: prefer a to b to c.
+ * This is unlikely to actually match any real implementation.
+ */
+ if (is_nan(a_cls)) {
return 0;
- } else if (bIsSNaN || bIsQNaN) {
+ } else if (is_nan(b_cls)) {
return 1;
} else {
return 2;
}
-}
#endif
+}
/*----------------------------------------------------------------------------
| Takes two single-precision floating-point values `a' and `b', one of which
@@ -709,18 +576,26 @@ static int pickNaNMulAdd(flag aIsQNaN, flag aIsSNaN, flag bIsQNaN, flag bIsSNaN,
static float32 propagateFloat32NaN(float32 a, float32 b, float_status *status)
{
- flag aIsQuietNaN, aIsSignalingNaN, bIsQuietNaN, bIsSignalingNaN;
flag aIsLargerSignificand;
uint32_t av, bv;
+ FloatClass a_cls, b_cls;
+
+ /* This is not complete, but is good enough for pickNaN. */
+ a_cls = (!float32_is_any_nan(a)
+ ? float_class_normal
+ : float32_is_signaling_nan(a, status)
+ ? float_class_snan
+ : float_class_qnan);
+ b_cls = (!float32_is_any_nan(b)
+ ? float_class_normal
+ : float32_is_signaling_nan(b, status)
+ ? float_class_snan
+ : float_class_qnan);
- aIsQuietNaN = float32_is_quiet_nan(a, status);
- aIsSignalingNaN = float32_is_signaling_nan(a, status);
- bIsQuietNaN = float32_is_quiet_nan(b, status);
- bIsSignalingNaN = float32_is_signaling_nan(b, status);
av = float32_val(a);
bv = float32_val(b);
- if (aIsSignalingNaN | bIsSignalingNaN) {
+ if (is_snan(a_cls) || is_snan(b_cls)) {
float_raise(float_flag_invalid, status);
}
@@ -736,25 +611,19 @@ static float32 propagateFloat32NaN(float32 a, float32 b, float_status *status)
aIsLargerSignificand = (av < bv) ? 1 : 0;
}
- if (pickNaN(aIsQuietNaN, aIsSignalingNaN, bIsQuietNaN, bIsSignalingNaN,
- aIsLargerSignificand)) {
- return float32_maybe_silence_nan(b, status);
+ if (pickNaN(a_cls, b_cls, aIsLargerSignificand)) {
+ if (is_snan(b_cls)) {
+ return float32_silence_nan(b, status);
+ }
+ return b;
} else {
- return float32_maybe_silence_nan(a, status);
+ if (is_snan(a_cls)) {
+ return float32_silence_nan(a, status);
+ }
+ return a;
}
}
-#ifdef NO_SIGNALING_NANS
-int float64_is_quiet_nan(float64 a_, float_status *status)
-{
- return float64_is_any_nan(a_);
-}
-
-int float64_is_signaling_nan(float64 a_, float_status *status)
-{
- return 0;
-}
-#else
/*----------------------------------------------------------------------------
| Returns 1 if the double-precision floating-point value `a' is a quiet
| NaN; otherwise returns 0.
@@ -762,13 +631,17 @@ int float64_is_signaling_nan(float64 a_, float_status *status)
int float64_is_quiet_nan(float64 a_, float_status *status)
{
+#ifdef NO_SIGNALING_NANS
+ return float64_is_any_nan(a_);
+#else
uint64_t a = float64_val(a_);
- if (status->snan_bit_is_one) {
+ if (snan_bit_is_one(status)) {
return (((a >> 51) & 0xFFF) == 0xFFE)
&& (a & 0x0007FFFFFFFFFFFFULL);
} else {
return ((a << 1) >= 0xFFF0000000000000ULL);
}
+#endif
}
/*----------------------------------------------------------------------------
@@ -778,40 +651,17 @@ int float64_is_quiet_nan(float64 a_, float_status *status)
int float64_is_signaling_nan(float64 a_, float_status *status)
{
+#ifdef NO_SIGNALING_NANS
+ return 0;
+#else
uint64_t a = float64_val(a_);
- if (status->snan_bit_is_one) {
+ if (snan_bit_is_one(status)) {
return ((a << 1) >= 0xFFF0000000000000ULL);
} else {
return (((a >> 51) & 0xFFF) == 0xFFE)
&& (a & LIT64(0x0007FFFFFFFFFFFF));
}
-}
-#endif
-
-/*----------------------------------------------------------------------------
-| Returns a quiet NaN if the double-precision floating point value `a' is a
-| signaling NaN; otherwise returns `a'.
-*----------------------------------------------------------------------------*/
-
-float64 float64_maybe_silence_nan(float64 a_, float_status *status)
-{
- if (float64_is_signaling_nan(a_, status)) {
- if (status->snan_bit_is_one) {
-#ifdef TARGET_HPPA
- uint64_t a = float64_val(a_);
- a &= ~0x0008000000000000ULL;
- a |= 0x0004000000000000ULL;
- return make_float64(a);
-#else
- return float64_default_nan(status);
#endif
- } else {
- uint64_t a = float64_val(a_);
- a |= LIT64(0x0008000000000000);
- return make_float64(a);
- }
- }
- return a_;
}
/*----------------------------------------------------------------------------
@@ -864,18 +714,26 @@ static float64 commonNaNToFloat64(commonNaNT a, float_status *status)
static float64 propagateFloat64NaN(float64 a, float64 b, float_status *status)
{
- flag aIsQuietNaN, aIsSignalingNaN, bIsQuietNaN, bIsSignalingNaN;
flag aIsLargerSignificand;
uint64_t av, bv;
+ FloatClass a_cls, b_cls;
+
+ /* This is not complete, but is good enough for pickNaN. */
+ a_cls = (!float64_is_any_nan(a)
+ ? float_class_normal
+ : float64_is_signaling_nan(a, status)
+ ? float_class_snan
+ : float_class_qnan);
+ b_cls = (!float64_is_any_nan(b)
+ ? float_class_normal
+ : float64_is_signaling_nan(b, status)
+ ? float_class_snan
+ : float_class_qnan);
- aIsQuietNaN = float64_is_quiet_nan(a, status);
- aIsSignalingNaN = float64_is_signaling_nan(a, status);
- bIsQuietNaN = float64_is_quiet_nan(b, status);
- bIsSignalingNaN = float64_is_signaling_nan(b, status);
av = float64_val(a);
bv = float64_val(b);
- if (aIsSignalingNaN | bIsSignalingNaN) {
+ if (is_snan(a_cls) || is_snan(b_cls)) {
float_raise(float_flag_invalid, status);
}
@@ -891,25 +749,19 @@ static float64 propagateFloat64NaN(float64 a, float64 b, float_status *status)
aIsLargerSignificand = (av < bv) ? 1 : 0;
}
- if (pickNaN(aIsQuietNaN, aIsSignalingNaN, bIsQuietNaN, bIsSignalingNaN,
- aIsLargerSignificand)) {
- return float64_maybe_silence_nan(b, status);
+ if (pickNaN(a_cls, b_cls, aIsLargerSignificand)) {
+ if (is_snan(b_cls)) {
+ return float64_silence_nan(b, status);
+ }
+ return b;
} else {
- return float64_maybe_silence_nan(a, status);
+ if (is_snan(a_cls)) {
+ return float64_silence_nan(a, status);
+ }
+ return a;
}
}
-#ifdef NO_SIGNALING_NANS
-int floatx80_is_quiet_nan(floatx80 a_, float_status *status)
-{
- return floatx80_is_any_nan(a_);
-}
-
-int floatx80_is_signaling_nan(floatx80 a_, float_status *status)
-{
- return 0;
-}
-#else
/*----------------------------------------------------------------------------
| Returns 1 if the extended double-precision floating-point value `a' is a
| quiet NaN; otherwise returns 0. This slightly differs from the same
@@ -918,7 +770,10 @@ int floatx80_is_signaling_nan(floatx80 a_, float_status *status)
int floatx80_is_quiet_nan(floatx80 a, float_status *status)
{
- if (status->snan_bit_is_one) {
+#ifdef NO_SIGNALING_NANS
+ return floatx80_is_any_nan(a);
+#else
+ if (snan_bit_is_one(status)) {
uint64_t aLow;
aLow = a.low & ~0x4000000000000000ULL;
@@ -929,6 +784,7 @@ int floatx80_is_quiet_nan(floatx80 a, float_status *status)
return ((a.high & 0x7FFF) == 0x7FFF)
&& (LIT64(0x8000000000000000) <= ((uint64_t)(a.low << 1)));
}
+#endif
}
/*----------------------------------------------------------------------------
@@ -939,7 +795,10 @@ int floatx80_is_quiet_nan(floatx80 a, float_status *status)
int floatx80_is_signaling_nan(floatx80 a, float_status *status)
{
- if (status->snan_bit_is_one) {
+#ifdef NO_SIGNALING_NANS
+ return 0;
+#else
+ if (snan_bit_is_one(status)) {
return ((a.high & 0x7FFF) == 0x7FFF)
&& ((a.low << 1) >= 0x8000000000000000ULL);
} else {
@@ -950,24 +809,19 @@ int floatx80_is_signaling_nan(floatx80 a, float_status *status)
&& (uint64_t)(aLow << 1)
&& (a.low == aLow);
}
-}
#endif
+}
/*----------------------------------------------------------------------------
-| Returns a quiet NaN if the extended double-precision floating point value
-| `a' is a signaling NaN; otherwise returns `a'.
+| Returns a quiet NaN from a signalling NaN for the extended double-precision
+| floating point value `a'.
*----------------------------------------------------------------------------*/
-floatx80 floatx80_maybe_silence_nan(floatx80 a, float_status *status)
+floatx80 floatx80_silence_nan(floatx80 a, float_status *status)
{
- if (floatx80_is_signaling_nan(a, status)) {
- if (status->snan_bit_is_one) {
- a = floatx80_default_nan(status);
- } else {
- a.low |= LIT64(0xC000000000000000);
- return a;
- }
- }
+ /* None of the targets that have snan_bit_is_one use floatx80. */
+ assert(!snan_bit_is_one(status));
+ a.low |= LIT64(0xC000000000000000);
return a;
}
@@ -1028,15 +882,22 @@ static floatx80 commonNaNToFloatx80(commonNaNT a, float_status *status)
floatx80 propagateFloatx80NaN(floatx80 a, floatx80 b, float_status *status)
{
- flag aIsQuietNaN, aIsSignalingNaN, bIsQuietNaN, bIsSignalingNaN;
flag aIsLargerSignificand;
-
- aIsQuietNaN = floatx80_is_quiet_nan(a, status);
- aIsSignalingNaN = floatx80_is_signaling_nan(a, status);
- bIsQuietNaN = floatx80_is_quiet_nan(b, status);
- bIsSignalingNaN = floatx80_is_signaling_nan(b, status);
-
- if (aIsSignalingNaN | bIsSignalingNaN) {
+ FloatClass a_cls, b_cls;
+
+ /* This is not complete, but is good enough for pickNaN. */
+ a_cls = (!floatx80_is_any_nan(a)
+ ? float_class_normal
+ : floatx80_is_signaling_nan(a, status)
+ ? float_class_snan
+ : float_class_qnan);
+ b_cls = (!floatx80_is_any_nan(b)
+ ? float_class_normal
+ : floatx80_is_signaling_nan(b, status)
+ ? float_class_snan
+ : float_class_qnan);
+
+ if (is_snan(a_cls) || is_snan(b_cls)) {
float_raise(float_flag_invalid, status);
}
@@ -1052,25 +913,19 @@ floatx80 propagateFloatx80NaN(floatx80 a, floatx80 b, float_status *status)
aIsLargerSignificand = (a.high < b.high) ? 1 : 0;
}
- if (pickNaN(aIsQuietNaN, aIsSignalingNaN, bIsQuietNaN, bIsSignalingNaN,
- aIsLargerSignificand)) {
- return floatx80_maybe_silence_nan(b, status);
+ if (pickNaN(a_cls, b_cls, aIsLargerSignificand)) {
+ if (is_snan(b_cls)) {
+ return floatx80_silence_nan(b, status);
+ }
+ return b;
} else {
- return floatx80_maybe_silence_nan(a, status);
+ if (is_snan(a_cls)) {
+ return floatx80_silence_nan(a, status);
+ }
+ return a;
}
}
-#ifdef NO_SIGNALING_NANS
-int float128_is_quiet_nan(float128 a_, float_status *status)
-{
- return float128_is_any_nan(a_);
-}
-
-int float128_is_signaling_nan(float128 a_, float_status *status)
-{
- return 0;
-}
-#else
/*----------------------------------------------------------------------------
| Returns 1 if the quadruple-precision floating-point value `a' is a quiet
| NaN; otherwise returns 0.
@@ -1078,13 +933,17 @@ int float128_is_signaling_nan(float128 a_, float_status *status)
int float128_is_quiet_nan(float128 a, float_status *status)
{
- if (status->snan_bit_is_one) {
+#ifdef NO_SIGNALING_NANS
+ return float128_is_any_nan(a);
+#else
+ if (snan_bit_is_one(status)) {
return (((a.high >> 47) & 0xFFFF) == 0xFFFE)
&& (a.low || (a.high & 0x00007FFFFFFFFFFFULL));
} else {
return ((a.high << 1) >= 0xFFFF000000000000ULL)
&& (a.low || (a.high & 0x0000FFFFFFFFFFFFULL));
}
+#endif
}
/*----------------------------------------------------------------------------
@@ -1094,32 +953,36 @@ int float128_is_quiet_nan(float128 a, float_status *status)
int float128_is_signaling_nan(float128 a, float_status *status)
{
- if (status->snan_bit_is_one) {
+#ifdef NO_SIGNALING_NANS
+ return 0;
+#else
+ if (snan_bit_is_one(status)) {
return ((a.high << 1) >= 0xFFFF000000000000ULL)
&& (a.low || (a.high & 0x0000FFFFFFFFFFFFULL));
} else {
return (((a.high >> 47) & 0xFFFF) == 0xFFFE)
&& (a.low || (a.high & LIT64(0x00007FFFFFFFFFFF)));
}
-}
#endif
+}
/*----------------------------------------------------------------------------
-| Returns a quiet NaN if the quadruple-precision floating point value `a' is
-| a signaling NaN; otherwise returns `a'.
+| Returns a quiet NaN from a signalling NaN for the quadruple-precision
+| floating point value `a'.
*----------------------------------------------------------------------------*/
-float128 float128_maybe_silence_nan(float128 a, float_status *status)
+float128 float128_silence_nan(float128 a, float_status *status)
{
- if (float128_is_signaling_nan(a, status)) {
- if (status->snan_bit_is_one) {
- a = float128_default_nan(status);
- } else {
- a.high |= LIT64(0x0000800000000000);
- return a;
- }
+#ifdef NO_SIGNALING_NANS
+ g_assert_not_reached();
+#else
+ if (snan_bit_is_one(status)) {
+ return float128_default_nan(status);
+ } else {
+ a.high |= LIT64(0x0000800000000000);
+ return a;
}
- return a;
+#endif
}
/*----------------------------------------------------------------------------
@@ -1167,15 +1030,22 @@ static float128 commonNaNToFloat128(commonNaNT a, float_status *status)
static float128 propagateFloat128NaN(float128 a, float128 b,
float_status *status)
{
- flag aIsQuietNaN, aIsSignalingNaN, bIsQuietNaN, bIsSignalingNaN;
flag aIsLargerSignificand;
-
- aIsQuietNaN = float128_is_quiet_nan(a, status);
- aIsSignalingNaN = float128_is_signaling_nan(a, status);
- bIsQuietNaN = float128_is_quiet_nan(b, status);
- bIsSignalingNaN = float128_is_signaling_nan(b, status);
-
- if (aIsSignalingNaN | bIsSignalingNaN) {
+ FloatClass a_cls, b_cls;
+
+ /* This is not complete, but is good enough for pickNaN. */
+ a_cls = (!float128_is_any_nan(a)
+ ? float_class_normal
+ : float128_is_signaling_nan(a, status)
+ ? float_class_snan
+ : float_class_qnan);
+ b_cls = (!float128_is_any_nan(b)
+ ? float_class_normal
+ : float128_is_signaling_nan(b, status)
+ ? float_class_snan
+ : float_class_qnan);
+
+ if (is_snan(a_cls) || is_snan(b_cls)) {
float_raise(float_flag_invalid, status);
}
@@ -1191,10 +1061,15 @@ static float128 propagateFloat128NaN(float128 a, float128 b,
aIsLargerSignificand = (a.high < b.high) ? 1 : 0;
}
- if (pickNaN(aIsQuietNaN, aIsSignalingNaN, bIsQuietNaN, bIsSignalingNaN,
- aIsLargerSignificand)) {
- return float128_maybe_silence_nan(b, status);
+ if (pickNaN(a_cls, b_cls, aIsLargerSignificand)) {
+ if (is_snan(b_cls)) {
+ return float128_silence_nan(b, status);
+ }
+ return b;
} else {
- return float128_maybe_silence_nan(a, status);
+ if (is_snan(a_cls)) {
+ return float128_silence_nan(a, status);
+ }
+ return a;
}
}
diff --git a/fpu/softfloat.c b/fpu/softfloat.c
index bc0f52f..8cd2400 100644
--- a/fpu/softfloat.c
+++ b/fpu/softfloat.c
@@ -96,16 +96,6 @@ this code that are retained.
#include "fpu/softfloat-macros.h"
/*----------------------------------------------------------------------------
-| Functions and definitions to determine: (1) whether tininess for underflow
-| is detected before or after rounding by default, (2) what (if anything)
-| happens when exceptions are raised, (3) how signaling NaNs are distinguished
-| from quiet NaNs, (4) the default generated quiet NaNs, and (5) how NaNs
-| are propagated from function inputs to output. These details are target-
-| specific.
-*----------------------------------------------------------------------------*/
-#include "softfloat-specialize.h"
-
-/*----------------------------------------------------------------------------
| Returns the fraction bits of the half-precision floating-point value `a'.
*----------------------------------------------------------------------------*/
@@ -124,15 +114,6 @@ static inline int extractFloat16Exp(float16 a)
}
/*----------------------------------------------------------------------------
-| Returns the sign bit of the single-precision floating-point value `a'.
-*----------------------------------------------------------------------------*/
-
-static inline flag extractFloat16Sign(float16 a)
-{
- return float16_val(a)>>15;
-}
-
-/*----------------------------------------------------------------------------
| Returns the fraction bits of the single-precision floating-point value `a'.
*----------------------------------------------------------------------------*/
@@ -198,10 +179,24 @@ typedef enum __attribute__ ((__packed__)) {
float_class_inf,
float_class_qnan, /* all NaNs from here */
float_class_snan,
- float_class_dnan,
- float_class_msnan, /* maybe silenced */
} FloatClass;
+/* Simple helpers for checking if, or what kind of, NaN we have */
+static inline __attribute__((unused)) bool is_nan(FloatClass c)
+{
+ return unlikely(c >= float_class_qnan);
+}
+
+static inline __attribute__((unused)) bool is_snan(FloatClass c)
+{
+ return c == float_class_snan;
+}
+
+static inline __attribute__((unused)) bool is_qnan(FloatClass c)
+{
+ return c == float_class_qnan;
+}
+
/*
* Structure holding all of the decomposed parts of a float. The
* exponent is unbiased and the fraction is normalized. All
@@ -232,8 +227,10 @@ typedef struct {
* frac_shift: shift to normalise the fraction with DECOMPOSED_BINARY_POINT
* The following are computed based the size of fraction
* frac_lsb: least significant bit of fraction
- * fram_lsbm1: the bit bellow the least significant bit (for rounding)
+ * frac_lsbm1: the bit below the least significant bit (for rounding)
* round_mask/roundeven_mask: masks used for rounding
+ * The following optional modifiers are available:
+ * arm_althp: handle ARM Alternative Half Precision
*/
typedef struct {
int exp_size;
@@ -245,6 +242,7 @@ typedef struct {
uint64_t frac_lsbm1;
uint64_t round_mask;
uint64_t roundeven_mask;
+ bool arm_althp;
} FloatFmt;
/* Expand fields based on the size of exponent and fraction */
@@ -263,6 +261,11 @@ static const FloatFmt float16_params = {
FLOAT_PARAMS(5, 10)
};
+static const FloatFmt float16_params_ahp = {
+ FLOAT_PARAMS(5, 10),
+ .arm_althp = true
+};
+
static const FloatFmt float32_params = {
FLOAT_PARAMS(8, 23)
};
@@ -322,24 +325,27 @@ static inline float64 float64_pack_raw(FloatParts p)
return make_float64(pack_raw(float64_params, p));
}
+/*----------------------------------------------------------------------------
+| Functions and definitions to determine: (1) whether tininess for underflow
+| is detected before or after rounding by default, (2) what (if anything)
+| happens when exceptions are raised, (3) how signaling NaNs are distinguished
+| from quiet NaNs, (4) the default generated quiet NaNs, and (5) how NaNs
+| are propagated from function inputs to output. These details are target-
+| specific.
+*----------------------------------------------------------------------------*/
+#include "softfloat-specialize.h"
+
/* Canonicalize EXP and FRAC, setting CLS. */
static FloatParts canonicalize(FloatParts part, const FloatFmt *parm,
float_status *status)
{
- if (part.exp == parm->exp_max) {
+ if (part.exp == parm->exp_max && !parm->arm_althp) {
if (part.frac == 0) {
part.cls = float_class_inf;
} else {
-#ifdef NO_SIGNALING_NANS
- part.cls = float_class_qnan;
-#else
- int64_t msb = part.frac << (parm->frac_shift + 2);
- if ((msb < 0) == status->snan_bit_is_one) {
- part.cls = float_class_snan;
- } else {
- part.cls = float_class_qnan;
- }
-#endif
+ part.frac <<= parm->frac_shift;
+ part.cls = (parts_is_snan_frac(part.frac, status)
+ ? float_class_snan : float_class_qnan);
}
} else if (part.exp == 0) {
if (likely(part.frac == 0)) {
@@ -422,7 +428,15 @@ static FloatParts round_canonical(FloatParts p, float_status *s,
}
frac >>= frac_shift;
- if (unlikely(exp >= exp_max)) {
+ if (parm->arm_althp) {
+ /* ARM Alt HP eschews Inf and NaN for a wider exponent. */
+ if (unlikely(exp > exp_max)) {
+ /* Overflow. Return the maximum normal. */
+ flags = float_flag_invalid;
+ exp = exp_max;
+ frac = -1;
+ }
+ } else if (unlikely(exp >= exp_max)) {
flags |= float_flag_overflow | float_flag_inexact;
if (overflow_norm) {
exp = exp_max - 1;
@@ -473,13 +487,16 @@ static FloatParts round_canonical(FloatParts p, float_status *s,
case float_class_inf:
do_inf:
+ assert(!parm->arm_althp);
exp = exp_max;
frac = 0;
break;
case float_class_qnan:
case float_class_snan:
+ assert(!parm->arm_althp);
exp = exp_max;
+ frac >>= parm->frac_shift;
break;
default:
@@ -492,22 +509,27 @@ static FloatParts round_canonical(FloatParts p, float_status *s,
return p;
}
+/* Explicit FloatFmt version */
+static FloatParts float16a_unpack_canonical(float16 f, float_status *s,
+ const FloatFmt *params)
+{
+ return canonicalize(float16_unpack_raw(f), params, s);
+}
+
static FloatParts float16_unpack_canonical(float16 f, float_status *s)
{
- return canonicalize(float16_unpack_raw(f), &float16_params, s);
+ return float16a_unpack_canonical(f, s, &float16_params);
+}
+
+static float16 float16a_round_pack_canonical(FloatParts p, float_status *s,
+ const FloatFmt *params)
+{
+ return float16_pack_raw(round_canonical(p, s, params));
}
static float16 float16_round_pack_canonical(FloatParts p, float_status *s)
{
- switch (p.cls) {
- case float_class_dnan:
- return float16_default_nan(s);
- case float_class_msnan:
- return float16_maybe_silence_nan(float16_pack_raw(p), s);
- default:
- p = round_canonical(p, s, &float16_params);
- return float16_pack_raw(p);
- }
+ return float16a_round_pack_canonical(p, s, &float16_params);
}
static FloatParts float32_unpack_canonical(float32 f, float_status *s)
@@ -517,15 +539,7 @@ static FloatParts float32_unpack_canonical(float32 f, float_status *s)
static float32 float32_round_pack_canonical(FloatParts p, float_status *s)
{
- switch (p.cls) {
- case float_class_dnan:
- return float32_default_nan(s);
- case float_class_msnan:
- return float32_maybe_silence_nan(float32_pack_raw(p), s);
- default:
- p = round_canonical(p, s, &float32_params);
- return float32_pack_raw(p);
- }
+ return float32_pack_raw(round_canonical(p, s, &float32_params));
}
static FloatParts float64_unpack_canonical(float64 f, float_status *s)
@@ -535,29 +549,7 @@ static FloatParts float64_unpack_canonical(float64 f, float_status *s)
static float64 float64_round_pack_canonical(FloatParts p, float_status *s)
{
- switch (p.cls) {
- case float_class_dnan:
- return float64_default_nan(s);
- case float_class_msnan:
- return float64_maybe_silence_nan(float64_pack_raw(p), s);
- default:
- p = round_canonical(p, s, &float64_params);
- return float64_pack_raw(p);
- }
-}
-
-/* Simple helpers for checking if what NaN we have */
-static bool is_nan(FloatClass c)
-{
- return unlikely(c >= float_class_qnan);
-}
-static bool is_snan(FloatClass c)
-{
- return c == float_class_snan;
-}
-static bool is_qnan(FloatClass c)
-{
- return c == float_class_qnan;
+ return float64_pack_raw(round_canonical(p, s, &float64_params));
}
static FloatParts return_nan(FloatParts a, float_status *s)
@@ -565,11 +557,11 @@ static FloatParts return_nan(FloatParts a, float_status *s)
switch (a.cls) {
case float_class_snan:
s->float_exception_flags |= float_flag_invalid;
- a.cls = float_class_msnan;
+ a = parts_silence_nan(a, s);
/* fall through */
case float_class_qnan:
if (s->default_nan_mode) {
- a.cls = float_class_dnan;
+ return parts_default_nan(s);
}
break;
@@ -586,15 +578,16 @@ static FloatParts pick_nan(FloatParts a, FloatParts b, float_status *s)
}
if (s->default_nan_mode) {
- a.cls = float_class_dnan;
+ return parts_default_nan(s);
} else {
- if (pickNaN(is_qnan(a.cls), is_snan(a.cls),
- is_qnan(b.cls), is_snan(b.cls),
+ if (pickNaN(a.cls, b.cls,
a.frac > b.frac ||
(a.frac == b.frac && a.sign < b.sign))) {
a = b;
}
- a.cls = float_class_msnan;
+ if (is_snan(a.cls)) {
+ return parts_silence_nan(a, s);
+ }
}
return a;
}
@@ -608,17 +601,13 @@ static FloatParts pick_nan_muladd(FloatParts a, FloatParts b, FloatParts c,
s->float_exception_flags |= float_flag_invalid;
}
- which = pickNaNMulAdd(is_qnan(a.cls), is_snan(a.cls),
- is_qnan(b.cls), is_snan(b.cls),
- is_qnan(c.cls), is_snan(c.cls),
- inf_zero, s);
+ which = pickNaNMulAdd(a.cls, b.cls, c.cls, inf_zero, s);
if (s->default_nan_mode) {
/* Note that this check is after pickNaNMulAdd so that function
* has an opportunity to set the Invalid flag.
*/
- a.cls = float_class_dnan;
- return a;
+ which = 3;
}
switch (which) {
@@ -631,13 +620,14 @@ static FloatParts pick_nan_muladd(FloatParts a, FloatParts b, FloatParts c,
a = c;
break;
case 3:
- a.cls = float_class_dnan;
- return a;
+ return parts_default_nan(s);
default:
g_assert_not_reached();
}
- a.cls = float_class_msnan;
+ if (is_snan(a.cls)) {
+ return parts_silence_nan(a, s);
+ }
return a;
}
@@ -685,7 +675,7 @@ static FloatParts addsub_floats(FloatParts a, FloatParts b, bool subtract,
if (a.cls == float_class_inf) {
if (b.cls == float_class_inf) {
float_raise(float_flag_invalid, s);
- a.cls = float_class_dnan;
+ return parts_default_nan(s);
}
return a;
}
@@ -831,9 +821,7 @@ static FloatParts mul_floats(FloatParts a, FloatParts b, float_status *s)
if ((a.cls == float_class_inf && b.cls == float_class_zero) ||
(a.cls == float_class_zero && b.cls == float_class_inf)) {
s->float_exception_flags |= float_flag_invalid;
- a.cls = float_class_dnan;
- a.sign = sign;
- return a;
+ return parts_default_nan(s);
}
/* Multiply by 0 or Inf */
if (a.cls == float_class_inf || a.cls == float_class_zero) {
@@ -911,8 +899,7 @@ static FloatParts muladd_floats(FloatParts a, FloatParts b, FloatParts c,
if (inf_zero) {
s->float_exception_flags |= float_flag_invalid;
- a.cls = float_class_dnan;
- return a;
+ return parts_default_nan(s);
}
if (flags & float_muladd_negate_c) {
@@ -936,12 +923,12 @@ static FloatParts muladd_floats(FloatParts a, FloatParts b, FloatParts c,
if (c.cls == float_class_inf) {
if (p_class == float_class_inf && p_sign != c.sign) {
s->float_exception_flags |= float_flag_invalid;
- a.cls = float_class_dnan;
+ return parts_default_nan(s);
} else {
a.cls = float_class_inf;
a.sign = c.sign ^ sign_flip;
+ return a;
}
- return a;
}
if (p_class == float_class_inf) {
@@ -1151,8 +1138,7 @@ static FloatParts div_floats(FloatParts a, FloatParts b, float_status *s)
&&
(a.cls == float_class_inf || a.cls == float_class_zero)) {
s->float_exception_flags |= float_flag_invalid;
- a.cls = float_class_dnan;
- return a;
+ return parts_default_nan(s);
}
/* Inf / x or 0 / x */
if (a.cls == float_class_inf || a.cls == float_class_zero) {
@@ -1203,6 +1189,104 @@ float64 float64_div(float64 a, float64 b, float_status *status)
}
/*
+ * Float to Float conversions
+ *
+ * Returns the result of converting one float format to another. The
+ * conversion is performed according to the IEC/IEEE Standard for
+ * Binary Floating-Point Arithmetic.
+ *
+ * The float_to_float helper only needs to take care of raising
+ * invalid exceptions and handling the conversion on NaNs.
+ */
+
+static FloatParts float_to_float(FloatParts a, const FloatFmt *dstf,
+ float_status *s)
+{
+ if (dstf->arm_althp) {
+ switch (a.cls) {
+ case float_class_qnan:
+ case float_class_snan:
+ /* There is no NaN in the destination format. Raise Invalid
+ * and return a zero with the sign of the input NaN.
+ */
+ s->float_exception_flags |= float_flag_invalid;
+ a.cls = float_class_zero;
+ a.frac = 0;
+ a.exp = 0;
+ break;
+
+ case float_class_inf:
+ /* There is no Inf in the destination format. Raise Invalid
+ * and return the maximum normal with the correct sign.
+ */
+ s->float_exception_flags |= float_flag_invalid;
+ a.cls = float_class_normal;
+ a.exp = dstf->exp_max;
+ a.frac = ((1ull << dstf->frac_size) - 1) << dstf->frac_shift;
+ break;
+
+ default:
+ break;
+ }
+ } else if (is_nan(a.cls)) {
+ if (is_snan(a.cls)) {
+ s->float_exception_flags |= float_flag_invalid;
+ a = parts_silence_nan(a, s);
+ }
+ if (s->default_nan_mode) {
+ return parts_default_nan(s);
+ }
+ }
+ return a;
+}
+
+float32 float16_to_float32(float16 a, bool ieee, float_status *s)
+{
+ const FloatFmt *fmt16 = ieee ? &float16_params : &float16_params_ahp;
+ FloatParts p = float16a_unpack_canonical(a, s, fmt16);
+ FloatParts pr = float_to_float(p, &float32_params, s);
+ return float32_round_pack_canonical(pr, s);
+}
+
+float64 float16_to_float64(float16 a, bool ieee, float_status *s)
+{
+ const FloatFmt *fmt16 = ieee ? &float16_params : &float16_params_ahp;
+ FloatParts p = float16a_unpack_canonical(a, s, fmt16);
+ FloatParts pr = float_to_float(p, &float64_params, s);
+ return float64_round_pack_canonical(pr, s);
+}
+
+float16 float32_to_float16(float32 a, bool ieee, float_status *s)
+{
+ const FloatFmt *fmt16 = ieee ? &float16_params : &float16_params_ahp;
+ FloatParts p = float32_unpack_canonical(a, s);
+ FloatParts pr = float_to_float(p, fmt16, s);
+ return float16a_round_pack_canonical(pr, s, fmt16);
+}
+
+float64 float32_to_float64(float32 a, float_status *s)
+{
+ FloatParts p = float32_unpack_canonical(a, s);
+ FloatParts pr = float_to_float(p, &float64_params, s);
+ return float64_round_pack_canonical(pr, s);
+}
+
+float16 float64_to_float16(float64 a, bool ieee, float_status *s)
+{
+ const FloatFmt *fmt16 = ieee ? &float16_params : &float16_params_ahp;
+ FloatParts p = float64_unpack_canonical(a, s);
+ FloatParts pr = float_to_float(p, fmt16, s);
+ return float16a_round_pack_canonical(pr, s, fmt16);
+}
+
+float32 float64_to_float32(float64 a, float_status *s)
+{
+ FloatParts p = float64_unpack_canonical(a, s);
+ FloatParts pr = float_to_float(p, &float32_params, s);
+ return float32_round_pack_canonical(pr, s);
+}
+
+/*
* Rounds the floating-point value `a' to an integer, and returns the
* result as a floating-point value. The operation is performed
* according to the IEC/IEEE Standard for Binary Floating-Point
@@ -1350,8 +1434,6 @@ static int64_t round_to_int_and_pack(FloatParts in, int rmode,
switch (p.cls) {
case float_class_snan:
case float_class_qnan:
- case float_class_dnan:
- case float_class_msnan:
s->float_exception_flags = orig_flags | float_flag_invalid;
return max;
case float_class_inf:
@@ -1442,8 +1524,6 @@ static uint64_t round_to_uint_and_pack(FloatParts in, int rmode, uint64_t max,
switch (p.cls) {
case float_class_snan:
case float_class_qnan:
- case float_class_dnan:
- case float_class_msnan:
s->float_exception_flags = orig_flags | float_flag_invalid;
return max;
case float_class_inf:
@@ -1943,8 +2023,7 @@ static FloatParts sqrt_float(FloatParts a, float_status *s, const FloatFmt *p)
}
if (a.sign) {
s->float_exception_flags |= float_flag_invalid;
- a.cls = float_class_dnan;
- return a;
+ return parts_default_nan(s);
}
if (a.cls == float_class_inf) {
return a; /* sqrt(+inf) = +inf */
@@ -2013,6 +2092,78 @@ float64 __attribute__((flatten)) float64_sqrt(float64 a, float_status *status)
return float64_round_pack_canonical(pr, status);
}
+/*----------------------------------------------------------------------------
+| The pattern for a default generated NaN.
+*----------------------------------------------------------------------------*/
+
+float16 float16_default_nan(float_status *status)
+{
+ FloatParts p = parts_default_nan(status);
+ p.frac >>= float16_params.frac_shift;
+ return float16_pack_raw(p);
+}
+
+float32 float32_default_nan(float_status *status)
+{
+ FloatParts p = parts_default_nan(status);
+ p.frac >>= float32_params.frac_shift;
+ return float32_pack_raw(p);
+}
+
+float64 float64_default_nan(float_status *status)
+{
+ FloatParts p = parts_default_nan(status);
+ p.frac >>= float64_params.frac_shift;
+ return float64_pack_raw(p);
+}
+
+float128 float128_default_nan(float_status *status)
+{
+ FloatParts p = parts_default_nan(status);
+ float128 r;
+
+ /* Extrapolate from the choices made by parts_default_nan to fill
+ * in the quad-floating format. If the low bit is set, assume we
+ * want to set all non-snan bits.
+ */
+ r.low = -(p.frac & 1);
+ r.high = p.frac >> (DECOMPOSED_BINARY_POINT - 48);
+ r.high |= LIT64(0x7FFF000000000000);
+ r.high |= (uint64_t)p.sign << 63;
+
+ return r;
+}
+
+/*----------------------------------------------------------------------------
+| Returns a quiet NaN from a signalling NaN for the floating point value `a'.
+*----------------------------------------------------------------------------*/
+
+float16 float16_silence_nan(float16 a, float_status *status)
+{
+ FloatParts p = float16_unpack_raw(a);
+ p.frac <<= float16_params.frac_shift;
+ p = parts_silence_nan(p, status);
+ p.frac >>= float16_params.frac_shift;
+ return float16_pack_raw(p);
+}
+
+float32 float32_silence_nan(float32 a, float_status *status)
+{
+ FloatParts p = float32_unpack_raw(a);
+ p.frac <<= float32_params.frac_shift;
+ p = parts_silence_nan(p, status);
+ p.frac >>= float32_params.frac_shift;
+ return float32_pack_raw(p);
+}
+
+float64 float64_silence_nan(float64 a, float_status *status)
+{
+ FloatParts p = float64_unpack_raw(a);
+ p.frac <<= float64_params.frac_shift;
+ p = parts_silence_nan(p, status);
+ p.frac >>= float64_params.frac_shift;
+ return float64_pack_raw(p);
+}
/*----------------------------------------------------------------------------
| Takes a 64-bit fixed-point value `absZ' with binary point between bits 6
@@ -3147,42 +3298,7 @@ float128 uint64_to_float128(uint64_t a, float_status *status)
if (a == 0) {
return float128_zero;
}
- return normalizeRoundAndPackFloat128(0, 0x406E, a, 0, status);
-}
-
-
-
-
-/*----------------------------------------------------------------------------
-| Returns the result of converting the single-precision floating-point value
-| `a' to the double-precision floating-point format. The conversion is
-| performed according to the IEC/IEEE Standard for Binary Floating-Point
-| Arithmetic.
-*----------------------------------------------------------------------------*/
-
-float64 float32_to_float64(float32 a, float_status *status)
-{
- flag aSign;
- int aExp;
- uint32_t aSig;
- a = float32_squash_input_denormal(a, status);
-
- aSig = extractFloat32Frac( a );
- aExp = extractFloat32Exp( a );
- aSign = extractFloat32Sign( a );
- if ( aExp == 0xFF ) {
- if (aSig) {
- return commonNaNToFloat64(float32ToCommonNaN(a, status), status);
- }
- return packFloat64( aSign, 0x7FF, 0 );
- }
- if ( aExp == 0 ) {
- if ( aSig == 0 ) return packFloat64( aSign, 0, 0 );
- normalizeFloat32Subnormal( aSig, &aExp, &aSig );
- --aExp;
- }
- return packFloat64( aSign, aExp + 0x380, ( (uint64_t) aSig )<<29 );
-
+ return normalizeRoundAndPackFloat128(0, 0x406E, 0, a, status);
}
/*----------------------------------------------------------------------------
@@ -3703,173 +3819,6 @@ int float32_unordered_quiet(float32 a, float32 b, float_status *status)
return 0;
}
-
-/*----------------------------------------------------------------------------
-| Returns the result of converting the double-precision floating-point value
-| `a' to the single-precision floating-point format. The conversion is
-| performed according to the IEC/IEEE Standard for Binary Floating-Point
-| Arithmetic.
-*----------------------------------------------------------------------------*/
-
-float32 float64_to_float32(float64 a, float_status *status)
-{
- flag aSign;
- int aExp;
- uint64_t aSig;
- uint32_t zSig;
- a = float64_squash_input_denormal(a, status);
-
- aSig = extractFloat64Frac( a );
- aExp = extractFloat64Exp( a );
- aSign = extractFloat64Sign( a );
- if ( aExp == 0x7FF ) {
- if (aSig) {
- return commonNaNToFloat32(float64ToCommonNaN(a, status), status);
- }
- return packFloat32( aSign, 0xFF, 0 );
- }
- shift64RightJamming( aSig, 22, &aSig );
- zSig = aSig;
- if ( aExp || zSig ) {
- zSig |= 0x40000000;
- aExp -= 0x381;
- }
- return roundAndPackFloat32(aSign, aExp, zSig, status);
-
-}
-
-
-/*----------------------------------------------------------------------------
-| Packs the sign `zSign', exponent `zExp', and significand `zSig' into a
-| half-precision floating-point value, returning the result. After being
-| shifted into the proper positions, the three fields are simply added
-| together to form the result. This means that any integer portion of `zSig'
-| will be added into the exponent. Since a properly normalized significand
-| will have an integer portion equal to 1, the `zExp' input should be 1 less
-| than the desired result exponent whenever `zSig' is a complete, normalized
-| significand.
-*----------------------------------------------------------------------------*/
-static float16 packFloat16(flag zSign, int zExp, uint16_t zSig)
-{
- return make_float16(
- (((uint32_t)zSign) << 15) + (((uint32_t)zExp) << 10) + zSig);
-}
-
-/*----------------------------------------------------------------------------
-| Takes an abstract floating-point value having sign `zSign', exponent `zExp',
-| and significand `zSig', and returns the proper half-precision floating-
-| point value corresponding to the abstract input. Ordinarily, the abstract
-| value is simply rounded and packed into the half-precision format, with
-| the inexact exception raised if the abstract input cannot be represented
-| exactly. However, if the abstract value is too large, the overflow and
-| inexact exceptions are raised and an infinity or maximal finite value is
-| returned. If the abstract value is too small, the input value is rounded to
-| a subnormal number, and the underflow and inexact exceptions are raised if
-| the abstract input cannot be represented exactly as a subnormal half-
-| precision floating-point number.
-| The `ieee' flag indicates whether to use IEEE standard half precision, or
-| ARM-style "alternative representation", which omits the NaN and Inf
-| encodings in order to raise the maximum representable exponent by one.
-| The input significand `zSig' has its binary point between bits 22
-| and 23, which is 13 bits to the left of the usual location. This shifted
-| significand must be normalized or smaller. If `zSig' is not normalized,
-| `zExp' must be 0; in that case, the result returned is a subnormal number,
-| and it must not require rounding. In the usual case that `zSig' is
-| normalized, `zExp' must be 1 less than the ``true'' floating-point exponent.
-| Note the slightly odd position of the binary point in zSig compared with the
-| other roundAndPackFloat functions. This should probably be fixed if we
-| need to implement more float16 routines than just conversion.
-| The handling of underflow and overflow follows the IEC/IEEE Standard for
-| Binary Floating-Point Arithmetic.
-*----------------------------------------------------------------------------*/
-
-static float16 roundAndPackFloat16(flag zSign, int zExp,
- uint32_t zSig, flag ieee,
- float_status *status)
-{
- int maxexp = ieee ? 29 : 30;
- uint32_t mask;
- uint32_t increment;
- bool rounding_bumps_exp;
- bool is_tiny = false;
-
- /* Calculate the mask of bits of the mantissa which are not
- * representable in half-precision and will be lost.
- */
- if (zExp < 1) {
- /* Will be denormal in halfprec */
- mask = 0x00ffffff;
- if (zExp >= -11) {
- mask >>= 11 + zExp;
- }
- } else {
- /* Normal number in halfprec */
- mask = 0x00001fff;
- }
-
- switch (status->float_rounding_mode) {
- case float_round_nearest_even:
- increment = (mask + 1) >> 1;
- if ((zSig & mask) == increment) {
- increment = zSig & (increment << 1);
- }
- break;
- case float_round_ties_away:
- increment = (mask + 1) >> 1;
- break;
- case float_round_up:
- increment = zSign ? 0 : mask;
- break;
- case float_round_down:
- increment = zSign ? mask : 0;
- break;
- default: /* round_to_zero */
- increment = 0;
- break;
- }
-
- rounding_bumps_exp = (zSig + increment >= 0x01000000);
-
- if (zExp > maxexp || (zExp == maxexp && rounding_bumps_exp)) {
- if (ieee) {
- float_raise(float_flag_overflow | float_flag_inexact, status);
- return packFloat16(zSign, 0x1f, 0);
- } else {
- float_raise(float_flag_invalid, status);
- return packFloat16(zSign, 0x1f, 0x3ff);
- }
- }
-
- if (zExp < 0) {
- /* Note that flush-to-zero does not affect half-precision results */
- is_tiny =
- (status->float_detect_tininess == float_tininess_before_rounding)
- || (zExp < -1)
- || (!rounding_bumps_exp);
- }
- if (zSig & mask) {
- float_raise(float_flag_inexact, status);
- if (is_tiny) {
- float_raise(float_flag_underflow, status);
- }
- }
-
- zSig += increment;
- if (rounding_bumps_exp) {
- zSig >>= 1;
- zExp++;
- }
-
- if (zExp < -10) {
- return packFloat16(zSign, 0, 0);
- }
- if (zExp < 0) {
- zSig >>= -zExp;
- zExp = 0;
- }
- return packFloat16(zSign, zExp, zSig >> 13);
-}
-
/*----------------------------------------------------------------------------
| If `a' is denormal and we are in flush-to-zero mode then set the
| input-denormal exception and return zero. Otherwise just return the value.
@@ -3885,163 +3834,6 @@ float16 float16_squash_input_denormal(float16 a, float_status *status)
return a;
}
-static void normalizeFloat16Subnormal(uint32_t aSig, int *zExpPtr,
- uint32_t *zSigPtr)
-{
- int8_t shiftCount = countLeadingZeros32(aSig) - 21;
- *zSigPtr = aSig << shiftCount;
- *zExpPtr = 1 - shiftCount;
-}
-
-/* Half precision floats come in two formats: standard IEEE and "ARM" format.
- The latter gains extra exponent range by omitting the NaN/Inf encodings. */
-
-float32 float16_to_float32(float16 a, flag ieee, float_status *status)
-{
- flag aSign;
- int aExp;
- uint32_t aSig;
-
- aSign = extractFloat16Sign(a);
- aExp = extractFloat16Exp(a);
- aSig = extractFloat16Frac(a);
-
- if (aExp == 0x1f && ieee) {
- if (aSig) {
- return commonNaNToFloat32(float16ToCommonNaN(a, status), status);
- }
- return packFloat32(aSign, 0xff, 0);
- }
- if (aExp == 0) {
- if (aSig == 0) {
- return packFloat32(aSign, 0, 0);
- }
-
- normalizeFloat16Subnormal(aSig, &aExp, &aSig);
- aExp--;
- }
- return packFloat32( aSign, aExp + 0x70, aSig << 13);
-}
-
-float16 float32_to_float16(float32 a, flag ieee, float_status *status)
-{
- flag aSign;
- int aExp;
- uint32_t aSig;
-
- a = float32_squash_input_denormal(a, status);
-
- aSig = extractFloat32Frac( a );
- aExp = extractFloat32Exp( a );
- aSign = extractFloat32Sign( a );
- if ( aExp == 0xFF ) {
- if (aSig) {
- /* Input is a NaN */
- if (!ieee) {
- float_raise(float_flag_invalid, status);
- return packFloat16(aSign, 0, 0);
- }
- return commonNaNToFloat16(
- float32ToCommonNaN(a, status), status);
- }
- /* Infinity */
- if (!ieee) {
- float_raise(float_flag_invalid, status);
- return packFloat16(aSign, 0x1f, 0x3ff);
- }
- return packFloat16(aSign, 0x1f, 0);
- }
- if (aExp == 0 && aSig == 0) {
- return packFloat16(aSign, 0, 0);
- }
- /* Decimal point between bits 22 and 23. Note that we add the 1 bit
- * even if the input is denormal; however this is harmless because
- * the largest possible single-precision denormal is still smaller
- * than the smallest representable half-precision denormal, and so we
- * will end up ignoring aSig and returning via the "always return zero"
- * codepath.
- */
- aSig |= 0x00800000;
- aExp -= 0x71;
-
- return roundAndPackFloat16(aSign, aExp, aSig, ieee, status);
-}
-
-float64 float16_to_float64(float16 a, flag ieee, float_status *status)
-{
- flag aSign;
- int aExp;
- uint32_t aSig;
-
- aSign = extractFloat16Sign(a);
- aExp = extractFloat16Exp(a);
- aSig = extractFloat16Frac(a);
-
- if (aExp == 0x1f && ieee) {
- if (aSig) {
- return commonNaNToFloat64(
- float16ToCommonNaN(a, status), status);
- }
- return packFloat64(aSign, 0x7ff, 0);
- }
- if (aExp == 0) {
- if (aSig == 0) {
- return packFloat64(aSign, 0, 0);
- }
-
- normalizeFloat16Subnormal(aSig, &aExp, &aSig);
- aExp--;
- }
- return packFloat64(aSign, aExp + 0x3f0, ((uint64_t)aSig) << 42);
-}
-
-float16 float64_to_float16(float64 a, flag ieee, float_status *status)
-{
- flag aSign;
- int aExp;
- uint64_t aSig;
- uint32_t zSig;
-
- a = float64_squash_input_denormal(a, status);
-
- aSig = extractFloat64Frac(a);
- aExp = extractFloat64Exp(a);
- aSign = extractFloat64Sign(a);
- if (aExp == 0x7FF) {
- if (aSig) {
- /* Input is a NaN */
- if (!ieee) {
- float_raise(float_flag_invalid, status);
- return packFloat16(aSign, 0, 0);
- }
- return commonNaNToFloat16(
- float64ToCommonNaN(a, status), status);
- }
- /* Infinity */
- if (!ieee) {
- float_raise(float_flag_invalid, status);
- return packFloat16(aSign, 0x1f, 0x3ff);
- }
- return packFloat16(aSign, 0x1f, 0);
- }
- shift64RightJamming(aSig, 29, &aSig);
- zSig = aSig;
- if (aExp == 0 && zSig == 0) {
- return packFloat16(aSign, 0, 0);
- }
- /* Decimal point between bits 22 and 23. Note that we add the 1 bit
- * even if the input is denormal; however this is harmless because
- * the largest possible single-precision denormal is still smaller
- * than the smallest representable half-precision denormal, and so we
- * will end up ignoring aSig and returning via the "always return zero"
- * codepath.
- */
- zSig |= 0x00800000;
- aExp -= 0x3F1;
-
- return roundAndPackFloat16(aSign, aExp, zSig, ieee, status);
-}
-
/*----------------------------------------------------------------------------
| Returns the result of converting the double-precision floating-point value
| `a' to the extended double-precision floating-point format. The conversion
diff --git a/hw/display/Makefile.objs b/hw/display/Makefile.objs
index 3c7c75b..11321e4 100644
--- a/hw/display/Makefile.objs
+++ b/hw/display/Makefile.objs
@@ -20,6 +20,8 @@ common-obj-$(CONFIG_MILKYMIST) += milkymist-vgafb.o
common-obj-$(CONFIG_ZAURUS) += tc6393xb.o
common-obj-$(CONFIG_MILKYMIST_TMU2) += milkymist-tmu2.o
+milkymist-tmu2.o-cflags := $(X11_CFLAGS)
+milkymist-tmu2.o-libs := $(X11_LIBS)
obj-$(CONFIG_OMAP) += omap_dss.o
obj-$(CONFIG_OMAP) += omap_lcdc.o
diff --git a/hw/usb/ccid-card-passthru.c b/hw/usb/ccid-card-passthru.c
index 7684db0..25fb19b 100644
--- a/hw/usb/ccid-card-passthru.c
+++ b/hw/usb/ccid-card-passthru.c
@@ -345,7 +345,7 @@ static void passthru_realize(CCIDCardState *base, Error **errp)
card->vscard_in_pos = 0;
card->vscard_in_hdr = 0;
if (qemu_chr_fe_backend_connected(&card->cs)) {
- error_setg(errp, "ccid-card-passthru: initing chardev");
+ DPRINTF(card, D_INFO, "ccid-card-passthru: initing chardev");
qemu_chr_fe_set_handlers(&card->cs,
ccid_card_vscard_can_read,
ccid_card_vscard_read,
diff --git a/hw/usb/dev-smartcard-reader.c b/hw/usb/dev-smartcard-reader.c
index cabb564..f745192 100644
--- a/hw/usb/dev-smartcard-reader.c
+++ b/hw/usb/dev-smartcard-reader.c
@@ -1064,7 +1064,8 @@ err:
return;
}
-static void ccid_bulk_in_copy_to_guest(USBCCIDState *s, USBPacket *p)
+static void ccid_bulk_in_copy_to_guest(USBCCIDState *s, USBPacket *p,
+ unsigned int max_packet_size)
{
int len = 0;
@@ -1072,10 +1073,13 @@ static void ccid_bulk_in_copy_to_guest(USBCCIDState *s, USBPacket *p)
if (s->current_bulk_in != NULL) {
len = MIN(s->current_bulk_in->len - s->current_bulk_in->pos,
p->iov.size);
- usb_packet_copy(p, s->current_bulk_in->data +
- s->current_bulk_in->pos, len);
+ if (len) {
+ usb_packet_copy(p, s->current_bulk_in->data +
+ s->current_bulk_in->pos, len);
+ }
s->current_bulk_in->pos += len;
- if (s->current_bulk_in->pos == s->current_bulk_in->len) {
+ if (s->current_bulk_in->pos == s->current_bulk_in->len
+ && len != max_packet_size) {
ccid_bulk_in_release(s);
}
} else {
@@ -1107,7 +1111,7 @@ static void ccid_handle_data(USBDevice *dev, USBPacket *p)
case USB_TOKEN_IN:
switch (p->ep->nr) {
case CCID_BULK_IN_EP:
- ccid_bulk_in_copy_to_guest(s, p);
+ ccid_bulk_in_copy_to_guest(s, p, dev->ep_ctl.max_packet_size);
break;
case CCID_INT_IN_EP:
if (s->notify_slot_change) {
diff --git a/include/fpu/softfloat-types.h b/include/fpu/softfloat-types.h
index 4e378cb..2aae6a8 100644
--- a/include/fpu/softfloat-types.h
+++ b/include/fpu/softfloat-types.h
@@ -173,6 +173,7 @@ typedef struct float_status {
/* should denormalised inputs go to zero and set the input_denormal flag? */
flag flush_inputs_to_zero;
flag default_nan_mode;
+ /* not always used -- see snan_bit_is_one() in softfloat-specialize.h */
flag snan_bit_is_one;
} float_status;
diff --git a/include/fpu/softfloat.h b/include/fpu/softfloat.h
index 36626a5..69f4dbc 100644
--- a/include/fpu/softfloat.h
+++ b/include/fpu/softfloat.h
@@ -211,10 +211,10 @@ float128 uint64_to_float128(uint64_t, float_status *status);
/*----------------------------------------------------------------------------
| Software half-precision conversion routines.
*----------------------------------------------------------------------------*/
-float16 float32_to_float16(float32, flag, float_status *status);
-float32 float16_to_float32(float16, flag, float_status *status);
-float16 float64_to_float16(float64 a, flag ieee, float_status *status);
-float64 float16_to_float64(float16 a, flag ieee, float_status *status);
+float16 float32_to_float16(float32, bool ieee, float_status *status);
+float32 float16_to_float32(float16, bool ieee, float_status *status);
+float16 float64_to_float16(float64 a, bool ieee, float_status *status);
+float64 float16_to_float64(float16 a, bool ieee, float_status *status);
int16_t float16_to_int16(float16, float_status *status);
uint16_t float16_to_uint16(float16 a, float_status *status);
int16_t float16_to_int16_round_to_zero(float16, float_status *status);
@@ -257,7 +257,7 @@ int float16_compare_quiet(float16, float16, float_status *status);
int float16_is_quiet_nan(float16, float_status *status);
int float16_is_signaling_nan(float16, float_status *status);
-float16 float16_maybe_silence_nan(float16, float_status *status);
+float16 float16_silence_nan(float16, float_status *status);
static inline int float16_is_any_nan(float16 a)
{
@@ -368,7 +368,7 @@ float32 float32_minnummag(float32, float32, float_status *status);
float32 float32_maxnummag(float32, float32, float_status *status);
int float32_is_quiet_nan(float32, float_status *status);
int float32_is_signaling_nan(float32, float_status *status);
-float32 float32_maybe_silence_nan(float32, float_status *status);
+float32 float32_silence_nan(float32, float_status *status);
float32 float32_scalbn(float32, int, float_status *status);
static inline float32 float32_abs(float32 a)
@@ -497,7 +497,7 @@ float64 float64_minnummag(float64, float64, float_status *status);
float64 float64_maxnummag(float64, float64, float_status *status);
int float64_is_quiet_nan(float64 a, float_status *status);
int float64_is_signaling_nan(float64, float_status *status);
-float64 float64_maybe_silence_nan(float64, float_status *status);
+float64 float64_silence_nan(float64, float_status *status);
float64 float64_scalbn(float64, int, float_status *status);
static inline float64 float64_abs(float64 a)
@@ -600,7 +600,7 @@ int floatx80_compare(floatx80, floatx80, float_status *status);
int floatx80_compare_quiet(floatx80, floatx80, float_status *status);
int floatx80_is_quiet_nan(floatx80, float_status *status);
int floatx80_is_signaling_nan(floatx80, float_status *status);
-floatx80 floatx80_maybe_silence_nan(floatx80, float_status *status);
+floatx80 floatx80_silence_nan(floatx80, float_status *status);
floatx80 floatx80_scalbn(floatx80, int, float_status *status);
static inline floatx80 floatx80_abs(floatx80 a)
@@ -811,7 +811,7 @@ int float128_compare(float128, float128, float_status *status);
int float128_compare_quiet(float128, float128, float_status *status);
int float128_is_quiet_nan(float128, float_status *status);
int float128_is_signaling_nan(float128, float_status *status);
-float128 float128_maybe_silence_nan(float128, float_status *status);
+float128 float128_silence_nan(float128, float_status *status);
float128 float128_scalbn(float128, int, float_status *status);
static inline float128 float128_abs(float128 a)
diff --git a/target/arm/helper-a64.c b/target/arm/helper-a64.c
index 4f8034c..f92bdea 100644
--- a/target/arm/helper-a64.c
+++ b/target/arm/helper-a64.c
@@ -376,7 +376,7 @@ float16 HELPER(frecpx_f16)(float16 a, void *fpstp)
float16 nan = a;
if (float16_is_signaling_nan(a, fpst)) {
float_raise(float_flag_invalid, fpst);
- nan = float16_maybe_silence_nan(a, fpst);
+ nan = float16_silence_nan(a, fpst);
}
if (fpst->default_nan_mode) {
nan = float16_default_nan(fpst);
@@ -405,7 +405,7 @@ float32 HELPER(frecpx_f32)(float32 a, void *fpstp)
float32 nan = a;
if (float32_is_signaling_nan(a, fpst)) {
float_raise(float_flag_invalid, fpst);
- nan = float32_maybe_silence_nan(a, fpst);
+ nan = float32_silence_nan(a, fpst);
}
if (fpst->default_nan_mode) {
nan = float32_default_nan(fpst);
@@ -434,7 +434,7 @@ float64 HELPER(frecpx_f64)(float64 a, void *fpstp)
float64 nan = a;
if (float64_is_signaling_nan(a, fpst)) {
float_raise(float_flag_invalid, fpst);
- nan = float64_maybe_silence_nan(a, fpst);
+ nan = float64_silence_nan(a, fpst);
}
if (fpst->default_nan_mode) {
nan = float64_default_nan(fpst);
@@ -466,7 +466,6 @@ float32 HELPER(fcvtx_f64_to_f32)(float64 a, CPUARMState *env)
set_float_rounding_mode(float_round_to_zero, &tstat);
set_float_exception_flags(0, &tstat);
r = float64_to_float32(a, &tstat);
- r = float32_maybe_silence_nan(r, &tstat);
exflags = get_float_exception_flags(&tstat);
if (exflags & float_flag_inexact) {
r = make_float32(float32_val(r) | 1);
diff --git a/target/arm/helper.c b/target/arm/helper.c
index c6fd7f9..db8bbe5 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -11348,20 +11348,12 @@ FLOAT_CONVS(ui, d, 64, u)
/* floating point conversion */
float64 VFP_HELPER(fcvtd, s)(float32 x, CPUARMState *env)
{
- float64 r = float32_to_float64(x, &env->vfp.fp_status);
- /* ARM requires that S<->D conversion of any kind of NaN generates
- * a quiet NaN by forcing the most significant frac bit to 1.
- */
- return float64_maybe_silence_nan(r, &env->vfp.fp_status);
+ return float32_to_float64(x, &env->vfp.fp_status);
}
float32 VFP_HELPER(fcvts, d)(float64 x, CPUARMState *env)
{
- float32 r = float64_to_float32(x, &env->vfp.fp_status);
- /* ARM requires that S<->D conversion of any kind of NaN generates
- * a quiet NaN by forcing the most significant frac bit to 1.
- */
- return float32_maybe_silence_nan(r, &env->vfp.fp_status);
+ return float64_to_float32(x, &env->vfp.fp_status);
}
/* VFP3 fixed point conversion. */
@@ -11540,64 +11532,56 @@ uint32_t HELPER(set_neon_rmode)(uint32_t rmode, CPUARMState *env)
}
/* Half precision conversions. */
-static float32 do_fcvt_f16_to_f32(uint32_t a, CPUARMState *env, float_status *s)
+float32 HELPER(vfp_fcvt_f16_to_f32)(float16 a, void *fpstp, uint32_t ahp_mode)
{
- int ieee = (env->vfp.xregs[ARM_VFP_FPSCR] & (1 << 26)) == 0;
- float32 r = float16_to_float32(make_float16(a), ieee, s);
- if (ieee) {
- return float32_maybe_silence_nan(r, s);
- }
+ /* Squash FZ16 to 0 for the duration of conversion. In this case,
+ * it would affect flushing input denormals.
+ */
+ float_status *fpst = fpstp;
+ flag save = get_flush_inputs_to_zero(fpst);
+ set_flush_inputs_to_zero(false, fpst);
+ float32 r = float16_to_float32(a, !ahp_mode, fpst);
+ set_flush_inputs_to_zero(save, fpst);
return r;
}
-static uint32_t do_fcvt_f32_to_f16(float32 a, CPUARMState *env, float_status *s)
-{
- int ieee = (env->vfp.xregs[ARM_VFP_FPSCR] & (1 << 26)) == 0;
- float16 r = float32_to_float16(a, ieee, s);
- if (ieee) {
- r = float16_maybe_silence_nan(r, s);
- }
- return float16_val(r);
-}
-
-float32 HELPER(neon_fcvt_f16_to_f32)(uint32_t a, CPUARMState *env)
-{
- return do_fcvt_f16_to_f32(a, env, &env->vfp.standard_fp_status);
-}
-
-uint32_t HELPER(neon_fcvt_f32_to_f16)(float32 a, CPUARMState *env)
-{
- return do_fcvt_f32_to_f16(a, env, &env->vfp.standard_fp_status);
-}
-
-float32 HELPER(vfp_fcvt_f16_to_f32)(uint32_t a, CPUARMState *env)
-{
- return do_fcvt_f16_to_f32(a, env, &env->vfp.fp_status);
-}
-
-uint32_t HELPER(vfp_fcvt_f32_to_f16)(float32 a, CPUARMState *env)
+float16 HELPER(vfp_fcvt_f32_to_f16)(float32 a, void *fpstp, uint32_t ahp_mode)
{
- return do_fcvt_f32_to_f16(a, env, &env->vfp.fp_status);
+ /* Squash FZ16 to 0 for the duration of conversion. In this case,
+ * it would affect flushing output denormals.
+ */
+ float_status *fpst = fpstp;
+ flag save = get_flush_to_zero(fpst);
+ set_flush_to_zero(false, fpst);
+ float16 r = float32_to_float16(a, !ahp_mode, fpst);
+ set_flush_to_zero(save, fpst);
+ return r;
}
-float64 HELPER(vfp_fcvt_f16_to_f64)(uint32_t a, CPUARMState *env)
+float64 HELPER(vfp_fcvt_f16_to_f64)(float16 a, void *fpstp, uint32_t ahp_mode)
{
- int ieee = (env->vfp.xregs[ARM_VFP_FPSCR] & (1 << 26)) == 0;
- float64 r = float16_to_float64(make_float16(a), ieee, &env->vfp.fp_status);
- if (ieee) {
- return float64_maybe_silence_nan(r, &env->vfp.fp_status);
- }
+ /* Squash FZ16 to 0 for the duration of conversion. In this case,
+ * it would affect flushing input denormals.
+ */
+ float_status *fpst = fpstp;
+ flag save = get_flush_inputs_to_zero(fpst);
+ set_flush_inputs_to_zero(false, fpst);
+ float64 r = float16_to_float64(a, !ahp_mode, fpst);
+ set_flush_inputs_to_zero(save, fpst);
return r;
}
-uint32_t HELPER(vfp_fcvt_f64_to_f16)(float64 a, CPUARMState *env)
+float16 HELPER(vfp_fcvt_f64_to_f16)(float64 a, void *fpstp, uint32_t ahp_mode)
{
- int ieee = (env->vfp.xregs[ARM_VFP_FPSCR] & (1 << 26)) == 0;
- float16 r = float64_to_float16(a, ieee, &env->vfp.fp_status);
- if (ieee) {
- r = float16_maybe_silence_nan(r, &env->vfp.fp_status);
- }
- return float16_val(r);
+ /* Squash FZ16 to 0 for the duration of conversion. In this case,
+ * it would affect flushing output denormals.
+ */
+ float_status *fpst = fpstp;
+ flag save = get_flush_to_zero(fpst);
+ set_flush_to_zero(false, fpst);
+ float16 r = float64_to_float16(a, !ahp_mode, fpst);
+ set_flush_to_zero(save, fpst);
+ return r;
}
#define float32_two make_float32(0x40000000)
@@ -11739,7 +11723,7 @@ float16 HELPER(recpe_f16)(float16 input, void *fpstp)
float16 nan = f16;
if (float16_is_signaling_nan(f16, fpst)) {
float_raise(float_flag_invalid, fpst);
- nan = float16_maybe_silence_nan(f16, fpst);
+ nan = float16_silence_nan(f16, fpst);
}
if (fpst->default_nan_mode) {
nan = float16_default_nan(fpst);
@@ -11787,7 +11771,7 @@ float32 HELPER(recpe_f32)(float32 input, void *fpstp)
float32 nan = f32;
if (float32_is_signaling_nan(f32, fpst)) {
float_raise(float_flag_invalid, fpst);
- nan = float32_maybe_silence_nan(f32, fpst);
+ nan = float32_silence_nan(f32, fpst);
}
if (fpst->default_nan_mode) {
nan = float32_default_nan(fpst);
@@ -11835,7 +11819,7 @@ float64 HELPER(recpe_f64)(float64 input, void *fpstp)
float64 nan = f64;
if (float64_is_signaling_nan(f64, fpst)) {
float_raise(float_flag_invalid, fpst);
- nan = float64_maybe_silence_nan(f64, fpst);
+ nan = float64_silence_nan(f64, fpst);
}
if (fpst->default_nan_mode) {
nan = float64_default_nan(fpst);
@@ -11934,7 +11918,7 @@ float16 HELPER(rsqrte_f16)(float16 input, void *fpstp)
float16 nan = f16;
if (float16_is_signaling_nan(f16, s)) {
float_raise(float_flag_invalid, s);
- nan = float16_maybe_silence_nan(f16, s);
+ nan = float16_silence_nan(f16, s);
}
if (s->default_nan_mode) {
nan = float16_default_nan(s);
@@ -11978,7 +11962,7 @@ float32 HELPER(rsqrte_f32)(float32 input, void *fpstp)
float32 nan = f32;
if (float32_is_signaling_nan(f32, s)) {
float_raise(float_flag_invalid, s);
- nan = float32_maybe_silence_nan(f32, s);
+ nan = float32_silence_nan(f32, s);
}
if (s->default_nan_mode) {
nan = float32_default_nan(s);
@@ -12021,7 +12005,7 @@ float64 HELPER(rsqrte_f64)(float64 input, void *fpstp)
float64 nan = f64;
if (float64_is_signaling_nan(f64, s)) {
float_raise(float_flag_invalid, s);
- nan = float64_maybe_silence_nan(f64, s);
+ nan = float64_silence_nan(f64, s);
}
if (s->default_nan_mode) {
nan = float64_default_nan(s);
diff --git a/target/arm/helper.h b/target/arm/helper.h
index ce89968..047f3bc 100644
--- a/target/arm/helper.h
+++ b/target/arm/helper.h
@@ -187,12 +187,10 @@ DEF_HELPER_3(vfp_uqtoh, f16, i64, i32, ptr)
DEF_HELPER_FLAGS_2(set_rmode, TCG_CALL_NO_RWG, i32, i32, ptr)
DEF_HELPER_FLAGS_2(set_neon_rmode, TCG_CALL_NO_RWG, i32, i32, env)
-DEF_HELPER_2(vfp_fcvt_f16_to_f32, f32, i32, env)
-DEF_HELPER_2(vfp_fcvt_f32_to_f16, i32, f32, env)
-DEF_HELPER_2(neon_fcvt_f16_to_f32, f32, i32, env)
-DEF_HELPER_2(neon_fcvt_f32_to_f16, i32, f32, env)
-DEF_HELPER_FLAGS_2(vfp_fcvt_f16_to_f64, TCG_CALL_NO_RWG, f64, i32, env)
-DEF_HELPER_FLAGS_2(vfp_fcvt_f64_to_f16, TCG_CALL_NO_RWG, i32, f64, env)
+DEF_HELPER_FLAGS_3(vfp_fcvt_f16_to_f32, TCG_CALL_NO_RWG, f32, f16, ptr, i32)
+DEF_HELPER_FLAGS_3(vfp_fcvt_f32_to_f16, TCG_CALL_NO_RWG, f16, f32, ptr, i32)
+DEF_HELPER_FLAGS_3(vfp_fcvt_f16_to_f64, TCG_CALL_NO_RWG, f64, f16, ptr, i32)
+DEF_HELPER_FLAGS_3(vfp_fcvt_f64_to_f16, TCG_CALL_NO_RWG, f16, f64, ptr, i32)
DEF_HELPER_4(vfp_muladdd, f64, f64, f64, f64, ptr)
DEF_HELPER_4(vfp_muladds, f32, f32, f32, f32, ptr)
diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c
index a0b0c43..d8284678 100644
--- a/target/arm/translate-a64.c
+++ b/target/arm/translate-a64.c
@@ -5147,10 +5147,15 @@ static void handle_fp_fcvt(DisasContext *s, int opcode,
} else {
/* Single to half */
TCGv_i32 tcg_rd = tcg_temp_new_i32();
- gen_helper_vfp_fcvt_f32_to_f16(tcg_rd, tcg_rn, cpu_env);
+ TCGv_i32 ahp = get_ahp_flag();
+ TCGv_ptr fpst = get_fpstatus_ptr(false);
+
+ gen_helper_vfp_fcvt_f32_to_f16(tcg_rd, tcg_rn, fpst, ahp);
/* write_fp_sreg is OK here because top half of tcg_rd is zero */
write_fp_sreg(s, rd, tcg_rd);
tcg_temp_free_i32(tcg_rd);
+ tcg_temp_free_i32(ahp);
+ tcg_temp_free_ptr(fpst);
}
tcg_temp_free_i32(tcg_rn);
break;
@@ -5163,9 +5168,13 @@ static void handle_fp_fcvt(DisasContext *s, int opcode,
/* Double to single */
gen_helper_vfp_fcvtsd(tcg_rd, tcg_rn, cpu_env);
} else {
+ TCGv_ptr fpst = get_fpstatus_ptr(false);
+ TCGv_i32 ahp = get_ahp_flag();
/* Double to half */
- gen_helper_vfp_fcvt_f64_to_f16(tcg_rd, tcg_rn, cpu_env);
+ gen_helper_vfp_fcvt_f64_to_f16(tcg_rd, tcg_rn, fpst, ahp);
/* write_fp_sreg is OK here because top half of tcg_rd is zero */
+ tcg_temp_free_ptr(fpst);
+ tcg_temp_free_i32(ahp);
}
write_fp_sreg(s, rd, tcg_rd);
tcg_temp_free_i32(tcg_rd);
@@ -5175,17 +5184,21 @@ static void handle_fp_fcvt(DisasContext *s, int opcode,
case 0x3:
{
TCGv_i32 tcg_rn = read_fp_sreg(s, rn);
+ TCGv_ptr tcg_fpst = get_fpstatus_ptr(false);
+ TCGv_i32 tcg_ahp = get_ahp_flag();
tcg_gen_ext16u_i32(tcg_rn, tcg_rn);
if (dtype == 0) {
/* Half to single */
TCGv_i32 tcg_rd = tcg_temp_new_i32();
- gen_helper_vfp_fcvt_f16_to_f32(tcg_rd, tcg_rn, cpu_env);
+ gen_helper_vfp_fcvt_f16_to_f32(tcg_rd, tcg_rn, tcg_fpst, tcg_ahp);
write_fp_sreg(s, rd, tcg_rd);
+ tcg_temp_free_ptr(tcg_fpst);
+ tcg_temp_free_i32(tcg_ahp);
tcg_temp_free_i32(tcg_rd);
} else {
/* Half to double */
TCGv_i64 tcg_rd = tcg_temp_new_i64();
- gen_helper_vfp_fcvt_f16_to_f64(tcg_rd, tcg_rn, cpu_env);
+ gen_helper_vfp_fcvt_f16_to_f64(tcg_rd, tcg_rn, tcg_fpst, tcg_ahp);
write_fp_dreg(s, rd, tcg_rd);
tcg_temp_free_i64(tcg_rd);
}
@@ -9053,12 +9066,17 @@ static void handle_2misc_narrow(DisasContext *s, bool scalar,
} else {
TCGv_i32 tcg_lo = tcg_temp_new_i32();
TCGv_i32 tcg_hi = tcg_temp_new_i32();
+ TCGv_ptr fpst = get_fpstatus_ptr(false);
+ TCGv_i32 ahp = get_ahp_flag();
+
tcg_gen_extr_i64_i32(tcg_lo, tcg_hi, tcg_op);
- gen_helper_vfp_fcvt_f32_to_f16(tcg_lo, tcg_lo, cpu_env);
- gen_helper_vfp_fcvt_f32_to_f16(tcg_hi, tcg_hi, cpu_env);
+ gen_helper_vfp_fcvt_f32_to_f16(tcg_lo, tcg_lo, fpst, ahp);
+ gen_helper_vfp_fcvt_f32_to_f16(tcg_hi, tcg_hi, fpst, ahp);
tcg_gen_deposit_i32(tcg_res[pass], tcg_lo, tcg_hi, 16, 16);
tcg_temp_free_i32(tcg_lo);
tcg_temp_free_i32(tcg_hi);
+ tcg_temp_free_ptr(fpst);
+ tcg_temp_free_i32(ahp);
}
break;
case 0x56: /* FCVTXN, FCVTXN2 */
@@ -11532,18 +11550,23 @@ static void handle_2misc_widening(DisasContext *s, int opcode, bool is_q,
/* 16 -> 32 bit fp conversion */
int srcelt = is_q ? 4 : 0;
TCGv_i32 tcg_res[4];
+ TCGv_ptr fpst = get_fpstatus_ptr(false);
+ TCGv_i32 ahp = get_ahp_flag();
for (pass = 0; pass < 4; pass++) {
tcg_res[pass] = tcg_temp_new_i32();
read_vec_element_i32(s, tcg_res[pass], rn, srcelt + pass, MO_16);
gen_helper_vfp_fcvt_f16_to_f32(tcg_res[pass], tcg_res[pass],
- cpu_env);
+ fpst, ahp);
}
for (pass = 0; pass < 4; pass++) {
write_vec_element_i32(s, tcg_res[pass], rd, pass, MO_32);
tcg_temp_free_i32(tcg_res[pass]);
}
+
+ tcg_temp_free_ptr(fpst);
+ tcg_temp_free_i32(ahp);
}
}
diff --git a/target/arm/translate.c b/target/arm/translate.c
index 731cf32..46a9725 100644
--- a/target/arm/translate.c
+++ b/target/arm/translate.c
@@ -3824,38 +3824,56 @@ static int disas_vfp_insn(DisasContext *s, uint32_t insn)
gen_vfp_sqrt(dp);
break;
case 4: /* vcvtb.f32.f16, vcvtb.f64.f16 */
+ {
+ TCGv_ptr fpst = get_fpstatus_ptr(false);
+ TCGv_i32 ahp_mode = get_ahp_flag();
tmp = gen_vfp_mrs();
tcg_gen_ext16u_i32(tmp, tmp);
if (dp) {
gen_helper_vfp_fcvt_f16_to_f64(cpu_F0d, tmp,
- cpu_env);
+ fpst, ahp_mode);
} else {
gen_helper_vfp_fcvt_f16_to_f32(cpu_F0s, tmp,
- cpu_env);
+ fpst, ahp_mode);
}
+ tcg_temp_free_i32(ahp_mode);
+ tcg_temp_free_ptr(fpst);
tcg_temp_free_i32(tmp);
break;
+ }
case 5: /* vcvtt.f32.f16, vcvtt.f64.f16 */
+ {
+ TCGv_ptr fpst = get_fpstatus_ptr(false);
+ TCGv_i32 ahp = get_ahp_flag();
tmp = gen_vfp_mrs();
tcg_gen_shri_i32(tmp, tmp, 16);
if (dp) {
gen_helper_vfp_fcvt_f16_to_f64(cpu_F0d, tmp,
- cpu_env);
+ fpst, ahp);
} else {
gen_helper_vfp_fcvt_f16_to_f32(cpu_F0s, tmp,
- cpu_env);
+ fpst, ahp);
}
tcg_temp_free_i32(tmp);
+ tcg_temp_free_i32(ahp);
+ tcg_temp_free_ptr(fpst);
break;
+ }
case 6: /* vcvtb.f16.f32, vcvtb.f16.f64 */
+ {
+ TCGv_ptr fpst = get_fpstatus_ptr(false);
+ TCGv_i32 ahp = get_ahp_flag();
tmp = tcg_temp_new_i32();
+
if (dp) {
gen_helper_vfp_fcvt_f64_to_f16(tmp, cpu_F0d,
- cpu_env);
+ fpst, ahp);
} else {
gen_helper_vfp_fcvt_f32_to_f16(tmp, cpu_F0s,
- cpu_env);
+ fpst, ahp);
}
+ tcg_temp_free_i32(ahp);
+ tcg_temp_free_ptr(fpst);
gen_mov_F0_vreg(0, rd);
tmp2 = gen_vfp_mrs();
tcg_gen_andi_i32(tmp2, tmp2, 0xffff0000);
@@ -3863,15 +3881,21 @@ static int disas_vfp_insn(DisasContext *s, uint32_t insn)
tcg_temp_free_i32(tmp2);
gen_vfp_msr(tmp);
break;
+ }
case 7: /* vcvtt.f16.f32, vcvtt.f16.f64 */
+ {
+ TCGv_ptr fpst = get_fpstatus_ptr(false);
+ TCGv_i32 ahp = get_ahp_flag();
tmp = tcg_temp_new_i32();
if (dp) {
gen_helper_vfp_fcvt_f64_to_f16(tmp, cpu_F0d,
- cpu_env);
+ fpst, ahp);
} else {
gen_helper_vfp_fcvt_f32_to_f16(tmp, cpu_F0s,
- cpu_env);
+ fpst, ahp);
}
+ tcg_temp_free_i32(ahp);
+ tcg_temp_free_ptr(fpst);
tcg_gen_shli_i32(tmp, tmp, 16);
gen_mov_F0_vreg(0, rd);
tmp2 = gen_vfp_mrs();
@@ -3880,6 +3904,7 @@ static int disas_vfp_insn(DisasContext *s, uint32_t insn)
tcg_temp_free_i32(tmp2);
gen_vfp_msr(tmp);
break;
+ }
case 8: /* cmp */
gen_vfp_cmp(dp);
break;
@@ -7222,53 +7247,70 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn)
}
break;
case NEON_2RM_VCVT_F16_F32:
+ {
+ TCGv_ptr fpst;
+ TCGv_i32 ahp;
+
if (!arm_dc_feature(s, ARM_FEATURE_VFP_FP16) ||
q || (rm & 1)) {
return 1;
}
tmp = tcg_temp_new_i32();
tmp2 = tcg_temp_new_i32();
+ fpst = get_fpstatus_ptr(true);
+ ahp = get_ahp_flag();
tcg_gen_ld_f32(cpu_F0s, cpu_env, neon_reg_offset(rm, 0));
- gen_helper_neon_fcvt_f32_to_f16(tmp, cpu_F0s, cpu_env);
+ gen_helper_vfp_fcvt_f32_to_f16(tmp, cpu_F0s, fpst, ahp);
tcg_gen_ld_f32(cpu_F0s, cpu_env, neon_reg_offset(rm, 1));
- gen_helper_neon_fcvt_f32_to_f16(tmp2, cpu_F0s, cpu_env);
+ gen_helper_vfp_fcvt_f32_to_f16(tmp2, cpu_F0s, fpst, ahp);
tcg_gen_shli_i32(tmp2, tmp2, 16);
tcg_gen_or_i32(tmp2, tmp2, tmp);
tcg_gen_ld_f32(cpu_F0s, cpu_env, neon_reg_offset(rm, 2));
- gen_helper_neon_fcvt_f32_to_f16(tmp, cpu_F0s, cpu_env);
+ gen_helper_vfp_fcvt_f32_to_f16(tmp, cpu_F0s, fpst, ahp);
tcg_gen_ld_f32(cpu_F0s, cpu_env, neon_reg_offset(rm, 3));
neon_store_reg(rd, 0, tmp2);
tmp2 = tcg_temp_new_i32();
- gen_helper_neon_fcvt_f32_to_f16(tmp2, cpu_F0s, cpu_env);
+ gen_helper_vfp_fcvt_f32_to_f16(tmp2, cpu_F0s, fpst, ahp);
tcg_gen_shli_i32(tmp2, tmp2, 16);
tcg_gen_or_i32(tmp2, tmp2, tmp);
neon_store_reg(rd, 1, tmp2);
tcg_temp_free_i32(tmp);
+ tcg_temp_free_i32(ahp);
+ tcg_temp_free_ptr(fpst);
break;
+ }
case NEON_2RM_VCVT_F32_F16:
+ {
+ TCGv_ptr fpst;
+ TCGv_i32 ahp;
if (!arm_dc_feature(s, ARM_FEATURE_VFP_FP16) ||
q || (rd & 1)) {
return 1;
}
+ fpst = get_fpstatus_ptr(true);
+ ahp = get_ahp_flag();
tmp3 = tcg_temp_new_i32();
tmp = neon_load_reg(rm, 0);
tmp2 = neon_load_reg(rm, 1);
tcg_gen_ext16u_i32(tmp3, tmp);
- gen_helper_neon_fcvt_f16_to_f32(cpu_F0s, tmp3, cpu_env);
+ gen_helper_vfp_fcvt_f16_to_f32(cpu_F0s, tmp3, fpst, ahp);
tcg_gen_st_f32(cpu_F0s, cpu_env, neon_reg_offset(rd, 0));
tcg_gen_shri_i32(tmp3, tmp, 16);
- gen_helper_neon_fcvt_f16_to_f32(cpu_F0s, tmp3, cpu_env);
+ gen_helper_vfp_fcvt_f16_to_f32(cpu_F0s, tmp3, fpst, ahp);
tcg_gen_st_f32(cpu_F0s, cpu_env, neon_reg_offset(rd, 1));
tcg_temp_free_i32(tmp);
tcg_gen_ext16u_i32(tmp3, tmp2);
- gen_helper_neon_fcvt_f16_to_f32(cpu_F0s, tmp3, cpu_env);
+ gen_helper_vfp_fcvt_f16_to_f32(cpu_F0s, tmp3, fpst, ahp);
tcg_gen_st_f32(cpu_F0s, cpu_env, neon_reg_offset(rd, 2));
tcg_gen_shri_i32(tmp3, tmp2, 16);
- gen_helper_neon_fcvt_f16_to_f32(cpu_F0s, tmp3, cpu_env);
+ gen_helper_vfp_fcvt_f16_to_f32(cpu_F0s, tmp3, fpst, ahp);
tcg_gen_st_f32(cpu_F0s, cpu_env, neon_reg_offset(rd, 3));
tcg_temp_free_i32(tmp2);
tcg_temp_free_i32(tmp3);
+ tcg_temp_free_i32(ahp);
+ tcg_temp_free_ptr(fpst);
break;
+ }
case NEON_2RM_AESE: case NEON_2RM_AESMC:
if (!arm_dc_feature(s, ARM_FEATURE_V8_AES)
|| ((rm | rd) & 1)) {
diff --git a/target/arm/translate.h b/target/arm/translate.h
index 37a1bba..45f0424 100644
--- a/target/arm/translate.h
+++ b/target/arm/translate.h
@@ -177,4 +177,16 @@ void arm_free_cc(DisasCompare *cmp);
void arm_jump_cc(DisasCompare *cmp, TCGLabel *label);
void arm_gen_test_cc(int cc, TCGLabel *label);
+/* Return state of Alternate Half-precision flag, caller frees result */
+static inline TCGv_i32 get_ahp_flag(void)
+{
+ TCGv_i32 ret = tcg_temp_new_i32();
+
+ tcg_gen_ld_i32(ret, cpu_env,
+ offsetof(CPUARMState, vfp.xregs[ARM_VFP_FPSCR]));
+ tcg_gen_extract_i32(ret, ret, 26, 1);
+
+ return ret;
+}
+
#endif /* TARGET_ARM_TRANSLATE_H */
diff --git a/target/hppa/cpu.c b/target/hppa/cpu.c
index c261b6b..00bf444 100644
--- a/target/hppa/cpu.c
+++ b/target/hppa/cpu.c
@@ -141,7 +141,6 @@ static void hppa_cpu_initfn(Object *obj)
cs->env_ptr = env;
cs->exception_index = -1;
cpu_hppa_loaded_fr0(env);
- set_snan_bit_is_one(true, &env->fp_status);
cpu_hppa_put_psw(env, PSW_W);
}
diff --git a/target/hppa/op_helper.c b/target/hppa/op_helper.c
index a3af62d..912e8d5 100644
--- a/target/hppa/op_helper.c
+++ b/target/hppa/op_helper.c
@@ -341,7 +341,6 @@ float64 HELPER(fdiv_d)(CPUHPPAState *env, float64 a, float64 b)
float64 HELPER(fcnv_s_d)(CPUHPPAState *env, float32 arg)
{
float64 ret = float32_to_float64(arg, &env->fp_status);
- ret = float64_maybe_silence_nan(ret, &env->fp_status);
update_fr0_op(env, GETPC());
return ret;
}
@@ -349,7 +348,6 @@ float64 HELPER(fcnv_s_d)(CPUHPPAState *env, float32 arg)
float32 HELPER(fcnv_d_s)(CPUHPPAState *env, float64 arg)
{
float32 ret = float64_to_float32(arg, &env->fp_status);
- ret = float32_maybe_silence_nan(ret, &env->fp_status);
update_fr0_op(env, GETPC());
return ret;
}
diff --git a/target/m68k/softfloat.c b/target/m68k/softfloat.c
index d093997..b45a5e8 100644
--- a/target/m68k/softfloat.c
+++ b/target/m68k/softfloat.c
@@ -31,13 +31,14 @@ static floatx80 propagateFloatx80NaNOneArg(floatx80 a, float_status *status)
{
if (floatx80_is_signaling_nan(a, status)) {
float_raise(float_flag_invalid, status);
+ a = floatx80_silence_nan(a, status);
}
if (status->default_nan_mode) {
return floatx80_default_nan(status);
}
- return floatx80_maybe_silence_nan(a, status);
+ return a;
}
/*----------------------------------------------------------------------------
diff --git a/target/mips/msa_helper.c b/target/mips/msa_helper.c
index 8fb7a36..c74e3cd 100644
--- a/target/mips/msa_helper.c
+++ b/target/mips/msa_helper.c
@@ -1615,7 +1615,6 @@ static inline float16 float16_from_float32(int32_t a, flag ieee,
float16 f_val;
f_val = float32_to_float16((float32)a, ieee, status);
- f_val = float16_maybe_silence_nan(f_val, status);
return a < 0 ? (f_val | (1 << 15)) : f_val;
}
@@ -1625,7 +1624,6 @@ static inline float32 float32_from_float64(int64_t a, float_status *status)
float32 f_val;
f_val = float64_to_float32((float64)a, status);
- f_val = float32_maybe_silence_nan(f_val, status);
return a < 0 ? (f_val | (1 << 31)) : f_val;
}
@@ -1636,7 +1634,6 @@ static inline float32 float32_from_float16(int16_t a, flag ieee,
float32 f_val;
f_val = float16_to_float32((float16)a, ieee, status);
- f_val = float32_maybe_silence_nan(f_val, status);
return a < 0 ? (f_val | (1 << 31)) : f_val;
}
@@ -1646,7 +1643,6 @@ static inline float64 float64_from_float32(int32_t a, float_status *status)
float64 f_val;
f_val = float32_to_float64((float64)a, status);
- f_val = float64_maybe_silence_nan(f_val, status);
return a < 0 ? (f_val | (1ULL << 63)) : f_val;
}
diff --git a/target/mips/op_helper.c b/target/mips/op_helper.c
index 798cdad..9025f42 100644
--- a/target/mips/op_helper.c
+++ b/target/mips/op_helper.c
@@ -2700,7 +2700,6 @@ uint64_t helper_float_cvtd_s(CPUMIPSState *env, uint32_t fst0)
uint64_t fdt2;
fdt2 = float32_to_float64(fst0, &env->active_fpu.fp_status);
- fdt2 = float64_maybe_silence_nan(fdt2, &env->active_fpu.fp_status);
update_fcr31(env, GETPC());
return fdt2;
}
@@ -2790,7 +2789,6 @@ uint32_t helper_float_cvts_d(CPUMIPSState *env, uint64_t fdt0)
uint32_t fst2;
fst2 = float64_to_float32(fdt0, &env->active_fpu.fp_status);
- fst2 = float32_maybe_silence_nan(fst2, &env->active_fpu.fp_status);
update_fcr31(env, GETPC());
return fst2;
}
diff --git a/target/ppc/fpu_helper.c b/target/ppc/fpu_helper.c
index 9ae418a..d31a933 100644
--- a/target/ppc/fpu_helper.c
+++ b/target/ppc/fpu_helper.c
@@ -3382,7 +3382,6 @@ void helper_xssqrtqp(CPUPPCState *env, uint32_t opcode)
xt.f128 = xb.f128;
} else if (float128_is_neg(xb.f128) && !float128_is_zero(xb.f128)) {
float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSQRT, 1);
- set_snan_bit_is_one(0, &env->fp_status);
xt.f128 = float128_default_nan(&env->fp_status);
}
}
diff --git a/target/riscv/fpu_helper.c b/target/riscv/fpu_helper.c
index abbadea..fdb87d8 100644
--- a/target/riscv/fpu_helper.c
+++ b/target/riscv/fpu_helper.c
@@ -279,14 +279,12 @@ uint64_t helper_fmax_d(CPURISCVState *env, uint64_t frs1, uint64_t frs2)
uint64_t helper_fcvt_s_d(CPURISCVState *env, uint64_t rs1)
{
- rs1 = float64_to_float32(rs1, &env->fp_status);
- return float32_maybe_silence_nan(rs1, &env->fp_status);
+ return float64_to_float32(rs1, &env->fp_status);
}
uint64_t helper_fcvt_d_s(CPURISCVState *env, uint64_t rs1)
{
- rs1 = float32_to_float64(rs1, &env->fp_status);
- return float64_maybe_silence_nan(rs1, &env->fp_status);
+ return float32_to_float64(rs1, &env->fp_status);
}
uint64_t helper_fsqrt_d(CPURISCVState *env, uint64_t frs1)
diff --git a/target/s390x/fpu_helper.c b/target/s390x/fpu_helper.c
index 43f8bf1..5c5b451 100644
--- a/target/s390x/fpu_helper.c
+++ b/target/s390x/fpu_helper.c
@@ -269,7 +269,7 @@ uint64_t HELPER(ldeb)(CPUS390XState *env, uint64_t f2)
{
float64 ret = float32_to_float64(f2, &env->fpu_status);
handle_exceptions(env, GETPC());
- return float64_maybe_silence_nan(ret, &env->fpu_status);
+ return ret;
}
/* convert 128-bit float to 64-bit float */
@@ -277,7 +277,7 @@ uint64_t HELPER(ldxb)(CPUS390XState *env, uint64_t ah, uint64_t al)
{
float64 ret = float128_to_float64(make_float128(ah, al), &env->fpu_status);
handle_exceptions(env, GETPC());
- return float64_maybe_silence_nan(ret, &env->fpu_status);
+ return ret;
}
/* convert 64-bit float to 128-bit float */
@@ -285,7 +285,7 @@ uint64_t HELPER(lxdb)(CPUS390XState *env, uint64_t f2)
{
float128 ret = float64_to_float128(f2, &env->fpu_status);
handle_exceptions(env, GETPC());
- return RET128(float128_maybe_silence_nan(ret, &env->fpu_status));
+ return RET128(ret);
}
/* convert 32-bit float to 128-bit float */
@@ -293,7 +293,7 @@ uint64_t HELPER(lxeb)(CPUS390XState *env, uint64_t f2)
{
float128 ret = float32_to_float128(f2, &env->fpu_status);
handle_exceptions(env, GETPC());
- return RET128(float128_maybe_silence_nan(ret, &env->fpu_status));
+ return RET128(ret);
}
/* convert 64-bit float to 32-bit float */
@@ -301,7 +301,7 @@ uint64_t HELPER(ledb)(CPUS390XState *env, uint64_t f2)
{
float32 ret = float64_to_float32(f2, &env->fpu_status);
handle_exceptions(env, GETPC());
- return float32_maybe_silence_nan(ret, &env->fpu_status);
+ return ret;
}
/* convert 128-bit float to 32-bit float */
@@ -309,7 +309,7 @@ uint64_t HELPER(lexb)(CPUS390XState *env, uint64_t ah, uint64_t al)
{
float32 ret = float128_to_float32(make_float128(ah, al), &env->fpu_status);
handle_exceptions(env, GETPC());
- return float32_maybe_silence_nan(ret, &env->fpu_status);
+ return ret;
}
/* 32-bit FP compare */
diff --git a/target/sh4/cpu.c b/target/sh4/cpu.c
index 541ffc2..b9f393b 100644
--- a/target/sh4/cpu.c
+++ b/target/sh4/cpu.c
@@ -71,7 +71,6 @@ static void superh_cpu_reset(CPUState *s)
set_flush_to_zero(1, &env->fp_status);
#endif
set_default_nan_mode(1, &env->fp_status);
- set_snan_bit_is_one(1, &env->fp_status);
}
static void superh_cpu_disas_set_info(CPUState *cpu, disassemble_info *info)
diff --git a/target/unicore32/cpu.c b/target/unicore32/cpu.c
index 29d160a..68f978d 100644
--- a/target/unicore32/cpu.c
+++ b/target/unicore32/cpu.c
@@ -70,7 +70,6 @@ static void unicore_ii_cpu_initfn(Object *obj)
set_feature(env, UC32_HWCAP_CMOV);
set_feature(env, UC32_HWCAP_UCF64);
- set_snan_bit_is_one(1, &env->ucf64.fp_status);
}
static void uc32_any_cpu_initfn(Object *obj)
@@ -83,7 +82,6 @@ static void uc32_any_cpu_initfn(Object *obj)
set_feature(env, UC32_HWCAP_CMOV);
set_feature(env, UC32_HWCAP_UCF64);
- set_snan_bit_is_one(1, &env->ucf64.fp_status);
}
static void uc32_cpu_realizefn(DeviceState *dev, Error **errp)
diff --git a/ui/Makefile.objs b/ui/Makefile.objs
index cc78434..00f6976 100644
--- a/ui/Makefile.objs
+++ b/ui/Makefile.objs
@@ -15,10 +15,6 @@ common-obj-$(CONFIG_COCOA) += cocoa.o
common-obj-$(CONFIG_VNC) += $(vnc-obj-y)
common-obj-$(call lnot,$(CONFIG_VNC)) += vnc-stubs.o
-common-obj-$(CONFIG_X11) += x_keymap.o
-x_keymap.o-cflags := $(X11_CFLAGS)
-x_keymap.o-libs := $(X11_LIBS)
-
# ui-sdl module
common-obj-$(CONFIG_SDL) += sdl.mo
ifeq ($(CONFIG_SDLABI),1.2)
@@ -46,6 +42,13 @@ gtk.mo-objs += gtk-gl-area.o
endif
endif
+ifeq ($(CONFIG_X11),y)
+sdl.mo-objs += x_keymap.o
+gtk.mo-objs += x_keymap.o
+x_keymap.o-cflags := $(X11_CFLAGS)
+x_keymap.o-libs := $(X11_LIBS)
+endif
+
common-obj-$(CONFIG_CURSES) += curses.mo
curses.mo-objs := curses.o
curses.mo-cflags := $(CURSES_CFLAGS)
diff --git a/ui/console.c b/ui/console.c
index 945f05d..ef1247f 100644
--- a/ui/console.c
+++ b/ui/console.c
@@ -372,6 +372,11 @@ void qmp_screendump(const char *filename, bool has_device, const char *device,
graphic_hw_update(con);
surface = qemu_console_surface(con);
+ if (!surface) {
+ error_setg(errp, "no surface");
+ return;
+ }
+
ppm_save(filename, surface, errp);
}
diff --git a/ui/sdl2-2d.c b/ui/sdl2-2d.c
index 1f34817..8548440 100644
--- a/ui/sdl2-2d.c
+++ b/ui/sdl2-2d.c
@@ -36,9 +36,7 @@ void sdl2_2d_update(DisplayChangeListener *dcl,
struct sdl2_console *scon = container_of(dcl, struct sdl2_console, dcl);
DisplaySurface *surf = qemu_console_surface(dcl->con);
SDL_Rect rect;
- size_t surface_data_offset = surface_bytes_per_pixel(surf) * x +
- surface_stride(surf) * y;
-
+ size_t surface_data_offset;
assert(!scon->opengl);
if (!surf) {
@@ -48,6 +46,8 @@ void sdl2_2d_update(DisplayChangeListener *dcl,
return;
}
+ surface_data_offset = surface_bytes_per_pixel(surf) * x +
+ surface_stride(surf) * y;
rect.x = x;
rect.y = y;
rect.w = w;