|
From: <sv...@va...> - 2013-09-12 17:26:53
|
Author: carll
Date: Thu Sep 12 17:26:42 2013
New Revision: 2760
Log:
The Power ISA 2.07 document includes a correction to the description for the
behavior of the xscvspdp instruction, indicating that if the source argument
is a SNaN, it is first changed to a QNaN before being converted from
single-precision to double-precision. This updated information about the
xscvspdp instruction exposed a bug in the VEX implementation for that
instruction and also a bug in the testing for all instructions having
special behavior for single-precision SNaN arguments.
This patch fixes both the VEX bug in xscvspdp implementation:
The current implementation of xscvspdp emulates the instruction by
extracting the single-precision floating point from the vector register,
storing it in single-prcision, and then loading the data just stored using
the lfsx instruction. But the lfsx instruction does not change SNaN input
arguments to QNaN inputs before conversion to double-precision, so this
emulation is not sufficient for the xscvspdp instruction as described in the
current documentation. This patch fixes that issue by recognizing a SNaN input
and changing it to a QNaN before performing the emulation using lfsx.
While fixing the bug in xscvspdp implementation, it was also discovered that
xvcvspdp had the same issue where SNaN inputs were not being handled correctly,
so this patch also fixes its implementation, too
See bugzilla 324816.
Modified:
trunk/priv/guest_ppc_toIR.c
Modified: trunk/priv/guest_ppc_toIR.c
==============================================================================
--- trunk/priv/guest_ppc_toIR.c (original)
+++ trunk/priv/guest_ppc_toIR.c Thu Sep 12 17:26:42 2013
@@ -2926,6 +2926,36 @@
return mkAND1( NaN_exp, binop( Iop_CmpNE32, frac_part, mkU32( 0 ) ) );
}
+/* This function takes an Ity_I32 input argument interpreted
+ * as a single-precision floating point value. If src is a
+ * SNaN, it is changed to a QNaN and returned; otherwise,
+ * the original value is returned.
+ */
+static IRExpr * handle_SNaN_to_QNaN_32(IRExpr * src)
+{
+#define SNAN_MASK32 0x00400000
+ IRTemp tmp = newTemp(Ity_I32);
+ IRTemp mask = newTemp(Ity_I32);
+ IRTemp is_SNAN = newTemp(Ity_I1);
+
+ vassert( typeOfIRExpr(irsb->tyenv, src ) == Ity_I32 );
+ assign(tmp, src);
+
+ /* check if input is SNaN, if it is convert to QNaN */
+ assign( is_SNAN,
+ mkAND1( is_NaN_32( tmp ),
+ binop( Iop_CmpEQ32,
+ binop( Iop_And32, mkexpr( tmp ),
+ mkU32( SNAN_MASK32 ) ),
+ mkU32( 0 ) ) ) );
+ /* create mask with QNaN bit set to make it a QNaN if tmp is SNaN */
+ assign ( mask, binop( Iop_And32,
+ unop( Iop_1Sto32, mkexpr( is_SNAN ) ),
+ mkU32( SNAN_MASK32 ) ) );
+ return binop( Iop_Or32, mkexpr( mask ), mkexpr( tmp) );
+}
+
+
/* This helper function performs the negation part of operations of the form:
* "Negate Multiply-<op>"
* where "<op>" is either "Add" or "Sub".
@@ -12062,9 +12092,11 @@
break;
// scalar single precision argument
case 0x292: // xscvspdp
- xB = newTemp(Ity_I32);
- assign( xB,
- unop( Iop_64HIto32, unop( Iop_V128HIto64, getVSReg( XB ) ) ) );
+ xB = newTemp(Ity_I32);
+
+ assign( xB, handle_SNaN_to_QNaN_32(unop( Iop_64HIto32,
+ unop( Iop_V128HIto64,
+ getVSReg( XB ) ) ) ) );
break;
case 0x296: // xscvspdpn (non signaling version of xscvpdp)
xB = newTemp(Ity_I32);
@@ -12311,10 +12343,12 @@
binop( Iop_64HLtoV128,
unop( Iop_ReinterpF64asI64,
unop( Iop_F32toF64,
- unop( Iop_ReinterpI32asF32, mkexpr( b3 ) ) ) ),
+ unop( Iop_ReinterpI32asF32,
+ handle_SNaN_to_QNaN_32( mkexpr( b3 ) ) ) ) ),
unop( Iop_ReinterpF64asI64,
unop( Iop_F32toF64,
- unop( Iop_ReinterpI32asF32, mkexpr( b1 ) ) ) ) ) );
+ unop( Iop_ReinterpI32asF32,
+ handle_SNaN_to_QNaN_32( mkexpr( b1 ) ) ) ) ) ) );
break;
case 0x330: // xvcvspsxds (VSX Vector truncate Single-Precision to integer and
// Convert to Signed Integer Doubleword format with Saturate)
|