|
From: <sv...@va...> - 2016-08-15 21:53:32
|
Author: carll
Date: Mon Aug 15 22:53:20 2016
New Revision: 3244
Log:
Power PC Add support for ISA 3.0, part 5
Added support for the
cnttz, cnttz., cnttzd, cnttzd., vctzb, vctzh, vctzw,
vctzd, xscvhpdp, xscvdphp, xvcvhpsp, xvcvsphpv,
xsrqpi, xsrqpix, xsrqpxp, xsaddqp, xsaddqpo, xsmulqp,
xsmulqpo, xsmaddqp, xsmaddqpo, xsmsubqp, xsmsubqpo,
xsnmaddqp, xsnmaddqpo, xsnmsubqp, xsnmsubqpo, xssubqp,
xssubqpo, xsdivqp, xsdivqpo, xssqrtqp, xssqrtqpo,
xscvqpuwz, xscvudqp, xscvqpswz, xscvsdqp, xscvqpudz,
xscvqpdp, xscvqpdpo, xscvdpqp, xscvqpsdz, vmul10cuq,
vmul10ecuq, vmul10uq, vmul10euq, bcdctsq, bcdcfsq
instructions.
Most of these instructions required adding a new Iop as they could not
be emulated with existing Iops. In some cases, some of the above instrctions
could be emulated using another instruction from the above list.
Most of the instructions add support for 128-bit instructions. There are a
number of helper functions that check a values for zero, infinity, NaN, etc.
for various sizes. The new 128-bit instructions require a new version of these
existing functions for a 128-bit operand. Rather then adding another size
specific version of these functions, the existing size specific functions were
replaced with a single function that takes the size of operand to be operated
on. There are some additional helper functions that are added to support
the size independent version of these functions.
Note this is the last of the 5 patches required to complete the ISA 3.0
support.
Bugzilla 364948
Modified:
trunk/priv/guest_ppc_toIR.c
trunk/priv/host_ppc_defs.c
trunk/priv/host_ppc_defs.h
trunk/priv/host_ppc_isel.c
trunk/priv/ir_defs.c
trunk/pub/libvex_ir.h
Modified: trunk/priv/guest_ppc_toIR.c
==============================================================================
--- trunk/priv/guest_ppc_toIR.c (original)
+++ trunk/priv/guest_ppc_toIR.c Mon Aug 15 22:53:20 2016
@@ -1506,6 +1506,21 @@
return IRExpr_Get( vectorGuestRegOffset(archreg), Ity_V128 );
}
+/* Get contents of 128-bit reg guest register */
+static IRExpr* getF128Reg ( UInt archreg )
+{
+ vassert(archreg < 64);
+ return IRExpr_Get( vectorGuestRegOffset(archreg), Ity_F128 );
+}
+
+/* Ditto, but write to a reg instead. */
+static void putF128Reg ( UInt archreg, IRExpr* e )
+{
+ vassert(archreg < 64);
+ vassert(typeOfIRExpr(irsb->tyenv, e) == Ity_F128);
+ stmt( IRStmt_Put(vectorGuestRegOffset(archreg), e) );
+}
+
/* Ditto, but write to a reg instead. */
static void putVReg ( UInt archreg, IRExpr* e )
{
@@ -1910,6 +1925,36 @@
stmt( IRStmt_Put(guestCR0offset(cr), e) );
}
+static void putC ( IRExpr* e )
+{
+ /* The assumption is that the value of the Floating-Point Result
+ * Class Descriptor bit (C) is passed in the lower four bits of a
+ * 32 bit value.
+ *
+ * Note, the C and FPCC bits which are fields in the FPSCR
+ * register are stored in their own memory location of
+ * memory. The FPCC bits are in the lower 4 bits. The C bit needs
+ * to be shifted to bit 4 in the memory location that holds C and FPCC.
+ * Note not all of the FPSCR register bits are supported. We are
+ * only writing C bit.
+ */
+ IRExpr* tmp;
+
+ vassert(typeOfIRExpr(irsb->tyenv, e) == Ity_I32);
+
+ /* Get the FPCC bit field */
+ tmp = binop( Iop_And32,
+ mkU32( 0xF ),
+ unop( Iop_8Uto32, IRExpr_Get( OFFB_C_FPCC, Ity_I8 ) ) );
+
+ stmt( IRStmt_Put( OFFB_C_FPCC,
+ unop( Iop_32to8,
+ binop( Iop_Or32, tmp,
+ binop( Iop_Shl32,
+ binop( Iop_And32, mkU32( 0x1 ), e ),
+ mkU8( 4 ) ) ) ) ) );
+}
+
static IRExpr* /* :: Ity_I8 */ getCR0 ( UInt cr )
{
vassert(cr < 8);
@@ -3394,266 +3439,488 @@
mkexpr( x ), \
mkU64( NONZERO_FRAC_MASK ) )
-// Returns exponent part of a single precision floating point as I32
-static IRExpr * fp_exp_part_sp(IRTemp src)
+#define NONZERO_FRAC_MASK32 0x007fffffULL
+#define FP_FRAC_PART32(x) binop( Iop_And32, \
+ mkexpr( x ), \
+ mkU32( NONZERO_FRAC_MASK32 ) )
+
+// Returns exponent part of floating point src as I32
+static IRExpr * fp_exp_part( IRType size, IRTemp src )
{
- return binop( Iop_And32,
- binop( Iop_Shr32, mkexpr( src ), mkU8( 23 ) ),
- mkU32( 0xff ) );
+ IRExpr *shift_by, *mask, *tsrc;
+
+ vassert( ( size == Ity_I16 ) || ( size == Ity_I32 )
+ || ( size == Ity_I64 ) );
+
+ if( size == Ity_I16 ) {
+ /* The 16-bit floating point value is in the lower 16-bits
+ * of the 32-bit input value.
+ */
+ tsrc = mkexpr( src );
+ mask = mkU32( 0x1F );
+ shift_by = mkU8( 10 );
+
+ } else if( size == Ity_I32 ) {
+ tsrc = mkexpr( src );
+ mask = mkU32( 0xFF );
+ shift_by = mkU8( 23 );
+
+ } else if( size == Ity_I64 ) {
+ tsrc = unop( Iop_64HIto32, mkexpr( src ) );
+ mask = mkU32( 0x7FF );
+ shift_by = mkU8( 52 - 32 );
+ }
+
+ return binop( Iop_And32, binop( Iop_Shr32, tsrc, shift_by ), mask );
}
-// Returns exponent part of floating point as I32
-static IRExpr * fp_exp_part(IRTemp src, Bool sp)
-{
- IRExpr * exp;
- if (sp)
- return fp_exp_part_sp(src);
+/* The following functions check the floating point value to see if it
+ is zero, infinity, NaN, Normalized, Denormalized.
+*/
+/* 16-bit floating point number is stored in the lower 16-bits of 32-bit value */
+#define I16_EXP_MASK 0x7C00
+#define I16_FRACTION_MASK 0x03FF
+#define I32_EXP_MASK 0x7F800000
+#define I32_FRACTION_MASK 0x007FFFFF
+#define I64_EXP_MASK 0x7FF0000000000000ULL
+#define I64_FRACTION_MASK 0x000FFFFFFFFFFFFFULL
+#define V128_EXP_MASK 0x7FFF000000000000ULL
+#define V128_FRACTION_MASK 0x0000FFFFFFFFFFFFULL /* upper 64-bit fractional mask */
+
+void setup_value_check_args( IRType size, IRTemp *exp_mask, IRTemp *frac_mask,
+ IRTemp *zero );
+
+void setup_value_check_args( IRType size, IRTemp *exp_mask, IRTemp *frac_mask,
+ IRTemp *zero ) {
+
+ vassert( ( size == Ity_I16 ) || ( size == Ity_I32 )
+ || ( size == Ity_I64 ) || ( size == Ity_V128 ) );
+
+ if( size == Ity_I16 ) {
+ /* The 16-bit floating point value is in the lower 16-bits of
+ the 32-bit input value */
+ *frac_mask = newTemp( Ity_I32 );
+ *exp_mask = newTemp( Ity_I32 );
+ *zero = newTemp( Ity_I32 );
+ assign( *exp_mask, mkU32( I16_EXP_MASK ) );
+ assign( *frac_mask, mkU32( I16_FRACTION_MASK ) );
+ assign( *zero, mkU32( 0 ) );
+
+ } else if( size == Ity_I32 ) {
+ *frac_mask = newTemp( Ity_I32 );
+ *exp_mask = newTemp( Ity_I32 );
+ *zero = newTemp( Ity_I32 );
+ assign( *exp_mask, mkU32( I32_EXP_MASK ) );
+ assign( *frac_mask, mkU32( I32_FRACTION_MASK ) );
+ assign( *zero, mkU32( 0 ) );
+
+ } else if( size == Ity_I64 ) {
+ *frac_mask = newTemp( Ity_I64 );
+ *exp_mask = newTemp( Ity_I64 );
+ *zero = newTemp( Ity_I64 );
+ assign( *exp_mask, mkU64( I64_EXP_MASK ) );
+ assign( *frac_mask, mkU64( I64_FRACTION_MASK ) );
+ assign( *zero, mkU64( 0 ) );
- if (!mode64)
- exp = binop( Iop_And32, binop( Iop_Shr32, unop( Iop_64HIto32,
- mkexpr( src ) ),
- mkU8( 20 ) ), mkU32( 0x7ff ) );
- else
- exp = unop( Iop_64to32,
- binop( Iop_And64,
- binop( Iop_Shr64, mkexpr( src ), mkU8( 52 ) ),
- mkU64( 0x7ff ) ) );
- return exp;
+ } else {
+ /* V128 is converted to upper and lower 64 bit values, */
+ /* uses 64-bit operators and temps */
+ *frac_mask = newTemp( Ity_I64 );
+ *exp_mask = newTemp( Ity_I64 );
+ *zero = newTemp( Ity_I64 );
+ assign( *exp_mask, mkU64( V128_EXP_MASK ) );
+ /* upper 64-bit fractional mask */
+ assign( *frac_mask, mkU64( V128_FRACTION_MASK ) );
+ assign( *zero, mkU64( 0 ) );
+ }
}
-static IRExpr * is_Inf_sp(IRTemp src)
+/* Helper function for the various function which check the value of
+ the floating point value.
+*/
+static IRExpr * exponent_compare( IRType size, IRTemp src,
+ IRTemp exp_mask, IRExpr *exp_val )
{
- IRTemp frac_part = newTemp(Ity_I32);
- IRExpr * Inf_exp;
+ IROp opAND, opCmpEQ;
- assign( frac_part, binop( Iop_And32, mkexpr(src), mkU32(0x007fffff)) );
- Inf_exp = binop( Iop_CmpEQ32, fp_exp_part( src, True /*single precision*/ ), mkU32( 0xff ) );
- return mkAND1( Inf_exp, binop( Iop_CmpEQ32, mkexpr( frac_part ), mkU32( 0 ) ) );
-}
+ if( ( size == Ity_I16 ) || ( size == Ity_I32 ) ) {
+ /* The 16-bit floating point value is in the lower 16-bits of
+ the 32-bit input value */
+ opAND = Iop_And32;
+ opCmpEQ = Iop_CmpEQ32;
+
+ } else {
+ opAND = Iop_And64;
+ opCmpEQ = Iop_CmpEQ64;
+ }
+
+ if( size == Ity_V128 ) {
+ return binop( opCmpEQ,
+ binop ( opAND,
+ unop( Iop_V128HIto64, mkexpr( src ) ),
+ mkexpr( exp_mask ) ),
+ exp_val );
+
+ } else if( ( size == Ity_I16 ) || ( size == Ity_I32 ) ) {
+ return binop( opCmpEQ,
+ binop ( opAND, mkexpr( src ), mkexpr( exp_mask ) ),
+ exp_val );
+ } else {
+ /* 64-bit operands */
+ if (mode64) {
+ return binop( opCmpEQ,
+ binop ( opAND, mkexpr( src ), mkexpr( exp_mask ) ),
+ exp_val );
+ } else {
+ /* No support for 64-bit compares in 32-bit mode, need to do upper
+ * and lower parts using 32-bit compare operators.
+ */
+ return
+ mkAND1( binop( Iop_CmpEQ32,
+ binop ( Iop_And32,
+ unop(Iop_64HIto32, mkexpr( src ) ),
+ unop(Iop_64HIto32, mkexpr( exp_mask ) ) ),
+ unop(Iop_64HIto32, exp_val ) ),
+ binop( Iop_CmpEQ32,
+ binop ( Iop_And32,
+ unop(Iop_64to32, mkexpr( src ) ),
+ unop(Iop_64to32, mkexpr( exp_mask ) ) ),
+ unop(Iop_64to32, exp_val ) ) );
+ }
+ }
+}
-// Infinity: exp = 7ff and fraction is zero; s = 0/1
-static IRExpr * is_Inf(IRTemp src, Bool sp)
+static IRExpr *fractional_part_compare( IRType size, IRTemp src,
+ IRTemp frac_mask, IRExpr *zero )
{
- IRExpr * Inf_exp, * hi32, * low32;
- IRTemp frac_part;
+ IROp opAND, opCmpEQ;
- if (sp)
- return is_Inf_sp(src);
+ if( ( size == Ity_I16 ) || ( size == Ity_I32 ) ) {
+ /*The 16-bit floating point value is in the lower 16-bits of
+ the 32-bit input value */
+ opAND = Iop_And32;
+ opCmpEQ = Iop_CmpEQ32;
+
+ } else {
+ opAND = Iop_And64;
+ opCmpEQ = Iop_CmpEQ64;
+ }
- frac_part = newTemp(Ity_I64);
- assign( frac_part, FP_FRAC_PART(src) );
- Inf_exp = binop( Iop_CmpEQ32, fp_exp_part( src, False /*not single precision*/ ), mkU32( 0x7ff ) );
- hi32 = unop( Iop_64HIto32, mkexpr( frac_part ) );
- low32 = unop( Iop_64to32, mkexpr( frac_part ) );
- return mkAND1( Inf_exp, binop( Iop_CmpEQ32, binop( Iop_Or32, low32, hi32 ),
- mkU32( 0 ) ) );
+ if( size == Ity_V128 ) {
+ /* 128-bit, note we only care if the fractional part is zero so take upper
+ 52-bits of fractional part and lower 64-bits and OR them together and test
+ for zero. This keeps the temp variables and operators all 64-bit.
+ */
+ return binop( opCmpEQ,
+ binop( Iop_Or64,
+ binop( opAND,
+ unop( Iop_V128HIto64, mkexpr( src ) ),
+ mkexpr( frac_mask ) ),
+ unop( Iop_V128to64, mkexpr( src ) ) ),
+ zero );
+
+ } else if( ( size == Ity_I16 ) || ( size == Ity_I32 ) ) {
+ return binop( opCmpEQ,
+ binop( opAND, mkexpr( src ), mkexpr( frac_mask ) ),
+ zero );
+ } else {
+ if (mode64) {
+ return binop( opCmpEQ,
+ binop( opAND, mkexpr( src ), mkexpr( frac_mask ) ),
+ zero );
+ } else {
+ /* No support for 64-bit compares in 32-bit mode, need to do upper
+ * and lower parts using 32-bit compare operators.
+ */
+ return
+ mkAND1( binop( Iop_CmpEQ32,
+ binop ( Iop_And32,
+ unop(Iop_64HIto32, mkexpr( src ) ),
+ unop(Iop_64HIto32, mkexpr( frac_mask ) ) ),
+ mkU32 ( 0 ) ),
+ binop( Iop_CmpEQ32,
+ binop ( Iop_And32,
+ unop(Iop_64to32, mkexpr( src ) ),
+ unop(Iop_64to32, mkexpr( frac_mask ) ) ),
+ mkU32 ( 0 ) ) );
+ }
+ }
}
-/* Quad precision floating point number is infinit:
- * exp is 32767 and fraction is zero; sign = 0/1
- */
-static IRExpr * is_Inf_V128 ( IRTemp src )
+// Infinity: exp has all bits set, and fraction is zero; s = 0/1
+static IRExpr * is_Inf( IRType size, IRTemp src )
{
- IRExpr * frac_part_hi, * frac_part_low, *Inf_exp;
+ IRExpr *max_exp, *zero_frac;
+ IRTemp exp_mask, frac_mask, zero;
- Inf_exp = binop( Iop_CmpEQ64,
- binop( Iop_And64,
- binop( Iop_Shr64,
- unop( Iop_V128HIto64,
- mkexpr( src ) ),
- mkU8( 48 ) ),
- mkU64( 0x7FFF ) ),
- mkU64( 0x7FFF ) );
-
- frac_part_hi = binop( Iop_And64,
- unop( Iop_V128HIto64, mkexpr( src ) ),
- mkU64( 0x0000FFFFFFFFFFFF ) );
- frac_part_low = unop( Iop_V128to64, mkexpr( src ) );
-
- return mkAND1( Inf_exp,
- mkAND1( binop( Iop_CmpEQ64, frac_part_hi, mkU64( 0 ) ),
- binop( Iop_CmpEQ64, frac_part_low, mkU64( 0 ) ) ) );
-}
-
-static IRExpr * is_Zero_sp(IRTemp src)
-{
- IRTemp sign_less_part = newTemp(Ity_I32);
- assign( sign_less_part, binop( Iop_And32, mkexpr( src ), mkU32( SIGN_MASK32 ) ) );
- return binop( Iop_CmpEQ32, mkexpr( sign_less_part ), mkU32( 0 ) );
+ setup_value_check_args( size, &exp_mask, &frac_mask, &zero );
+
+ /* check exponent is all ones, i.e. (exp AND exp_mask) = exp_mask */
+ max_exp = exponent_compare( size, src, exp_mask, mkexpr( exp_mask ) );
+
+ /* check fractional part is all zeros */
+ zero_frac = fractional_part_compare( size, src, frac_mask, mkexpr( zero ) );
+
+ return mkAND1( max_exp, zero_frac );
}
// Zero: exp is zero and fraction is zero; s = 0/1
-static IRExpr * is_Zero(IRTemp src, Bool sp)
+static IRExpr * is_Zero( IRType size, IRTemp src )
{
- IRExpr * hi32, * low32;
- IRTemp sign_less_part;
- if (sp)
- return is_Zero_sp(src);
+ IRExpr *zero_exp, *zero_frac;
+ IRTemp exp_mask, frac_mask, zero;
- sign_less_part = newTemp(Ity_I64);
+ setup_value_check_args( size, &exp_mask, &frac_mask, &zero );
- assign( sign_less_part, binop( Iop_And64, mkexpr( src ), mkU64( SIGN_MASK ) ) );
- hi32 = unop( Iop_64HIto32, mkexpr( sign_less_part ) );
- low32 = unop( Iop_64to32, mkexpr( sign_less_part ) );
- return binop( Iop_CmpEQ32, binop( Iop_Or32, low32, hi32 ),
- mkU32( 0 ) );
-}
+ /* check the exponent is all zeros, i.e. (exp AND exp_mask) = zero */
+ zero_exp = exponent_compare( size, src, exp_mask, mkexpr( zero ) );
-/* Quad precision floating point number is Zero:
- exp is zero and fraction is zero; sign = 0/1 */
-static IRExpr * is_Zero_V128 ( IRTemp src )
-{
- IRExpr * hi64, * low64;
+ /* check fractional part is all zeros */
+ zero_frac = fractional_part_compare( size, src, frac_mask, mkexpr( zero ) );
- hi64 = binop( Iop_And64,
- unop( Iop_V128HIto64, mkexpr( src ) ),
- mkU64( 0x7FFFFFFFFFFFFFFF ) );
- low64 = unop( Iop_V128to64, mkexpr( src ) );
- return binop( Iop_CmpEQ64,
- binop( Iop_Or64, hi64, low64 ),
- mkU64( 0 ) );
+ return mkAND1( zero_exp, zero_frac );
}
-/* SNAN: s = 1/0; exp = 0x7ff; fraction is nonzero, with highest bit '1'
- * QNAN: s = 1/0; exp = 0x7ff; fraction is nonzero, with highest bit '0'
- * This function returns an IRExpr value of '1' for any type of NaN.
+/* SNAN: s = 1/0; exp all 1's; fraction is nonzero, with highest bit '1'
+ * QNAN: s = 1/0; exp all 1's; fraction is nonzero, with highest bit '0'
*/
-static IRExpr * is_NaN(IRTemp src)
+static IRExpr * is_NaN( IRType size, IRTemp src )
{
- IRExpr * NaN_exp, * hi32, * low32;
- IRTemp frac_part = newTemp(Ity_I64);
+ IRExpr *max_exp, *not_zero_frac;
+ IRTemp exp_mask, frac_mask, zero;
- assign( frac_part, FP_FRAC_PART(src) );
- hi32 = unop( Iop_64HIto32, mkexpr( frac_part ) );
- low32 = unop( Iop_64to32, mkexpr( frac_part ) );
- NaN_exp = binop( Iop_CmpEQ32, fp_exp_part( src, False /*not single precision*/ ),
- mkU32( 0x7ff ) );
+ setup_value_check_args( size, &exp_mask, &frac_mask, &zero );
- return mkAND1( NaN_exp, binop( Iop_CmpNE32, binop( Iop_Or32, low32, hi32 ),
- mkU32( 0 ) ) );
-}
+ /* check exponent is all ones, i.e. (exp AND exp_mask) = exp_mask */
+ max_exp = exponent_compare( size, src, exp_mask, mkexpr( exp_mask ) );
-/* This function returns an IRExpr value of '1' for any type of NaN.
- The passed 'src' argument is assumed to be Ity_I32. */
-static IRExpr * is_NaN_32(IRTemp src)
-{
-#define NONZERO_FRAC_MASK32 0x007fffffULL
-#define FP_FRAC_PART32(x) binop( Iop_And32, \
- mkexpr( x ), \
- mkU32( NONZERO_FRAC_MASK32 ) )
+ /* check fractional part is not zero */
+ not_zero_frac = unop( Iop_Not1,
+ fractional_part_compare( size, src, frac_mask,
+ mkexpr( zero ) ) );
- IRExpr * frac_part = FP_FRAC_PART32(src);
- IRExpr * exp_part = binop( Iop_And32,
- binop( Iop_Shr32, mkexpr( src ), mkU8( 23 ) ),
- mkU32( 0x0ff ) );
- IRExpr * NaN_exp = binop( Iop_CmpEQ32, exp_part, mkU32( 0xff ) );
-
- return mkAND1( NaN_exp, binop( Iop_CmpNE32, frac_part, mkU32( 0 ) ) );
+ return mkAND1( max_exp, not_zero_frac );
}
-/* This function returns an IRExpr value of '1' for any type of NaN.
- * The passed 'src' argument is assumed to be a quad precisiion
- * floating point number stored in an Ity_V128.
- */
-static IRExpr * is_NaN_V128 ( IRTemp src )
+/* Denormalized number has a zero exponent and non zero fraction. */
+static IRExpr * is_Denorm( IRType size, IRTemp src )
{
+ IRExpr *zero_exp, *not_zero_frac;
+ IRTemp exp_mask, frac_mask, zero;
- /* ignore top fractional bit */
-#define NONZERO_FRAC_MASK64Hi 0x0000ffffffffffffULL
-#define EXP_MASK 0x7fff
-
- IRExpr * frac_part_hi = binop( Iop_And64,
- unop( Iop_V128HIto64,
- mkexpr ( src ) ),
- mkU64( NONZERO_FRAC_MASK64Hi ) );
+ setup_value_check_args( size, &exp_mask, &frac_mask, &zero );
- IRExpr * frac_part_lo = unop( Iop_V128to64, mkexpr ( src ) );
+ /* check exponent is all ones, i.e. (exp AND exp_mask) = exp_mask */
+ zero_exp = exponent_compare( size, src, exp_mask, mkexpr( zero ) );
- IRExpr * exp_part = binop( Iop_And64,
- binop( Iop_Shr64,
- unop( Iop_V128HIto64,
- mkexpr( src ) ),
- mkU8( 48 ) ),
- mkU64( EXP_MASK ) );
- IRExpr * NaN_exp = binop( Iop_CmpEQ64, exp_part, mkU64( EXP_MASK ) );
+ /* check fractional part is not zero */
+ not_zero_frac = unop( Iop_Not1,
+ fractional_part_compare( size, src, frac_mask,
+ mkexpr( zero ) ) );
- return mkAND1( NaN_exp,
- mkOR1( binop( Iop_CmpNE64, frac_part_hi, mkU64( 0 ) ),
- binop( Iop_CmpNE64, frac_part_lo, mkU64( 0 ) ) ) );
+ return mkAND1( zero_exp, not_zero_frac );
}
-static IRExpr * is_Denorm ( IRType size, IRTemp src )
+/* Normalized number has exponent between 1 and max_exp -1, or in other words
+ the exponent is not zero and not equal to the max exponent value. */
+static IRExpr * is_Norm( IRType size, IRTemp src )
{
- /* Denormalized number has a zero exponent and non zero fraction.
- Takes a 32bit or 64-bit floating point number and returns 1-bit result.
- */
- IROp opAND, opSHR, opCmpEQ, opCmpNE;
- IRExpr *shift_by, *mask1, *mask2;
- IRTemp zero = newTemp( size );
+ IRExpr *not_zero_exp, *not_max_exp;
+ IRTemp exp_mask, zero;
- vassert( ( size == Ity_I32 ) || ( size == Ity_I64 ) );
+ vassert( ( size == Ity_I16 ) || ( size == Ity_I32 )
+ || ( size == Ity_I64 ) || ( size == Ity_V128 ) );
- if( size == Ity_I32 ) {
- opAND = Iop_And32;
- opSHR = Iop_Shr32;
- opCmpEQ = Iop_CmpEQ32;
- opCmpNE = Iop_CmpNE32;
- shift_by = mkU8( 23 );
- mask1 = mkU32( 0xFF );
- mask2 = mkU32( 0x007fffff );
- assign( zero , mkU32( 0 ) );
+ if( size == Ity_I16 ) {
+ /* The 16-bit floating point value is in the lower 16-bits of
+ the 32-bit input value */
+ exp_mask = newTemp( Ity_I32 );
+ zero = newTemp( Ity_I32 );
+ assign( exp_mask, mkU32( I16_EXP_MASK ) );
+ assign( zero, mkU32( 0 ) );
+
+ } else if( size == Ity_I32 ) {
+ exp_mask = newTemp( Ity_I32 );
+ zero = newTemp( Ity_I32 );
+ assign( exp_mask, mkU32( I32_EXP_MASK ) );
+ assign( zero, mkU32( 0 ) );
+
+ } else if( size == Ity_I64 ) {
+ exp_mask = newTemp( Ity_I64 );
+ zero = newTemp( Ity_I64 );
+ assign( exp_mask, mkU64( I64_EXP_MASK ) );
+ assign( zero, mkU64( 0 ) );
} else {
- opAND = Iop_And64;
- opSHR = Iop_Shr64;
- opCmpEQ = Iop_CmpEQ64;
- opCmpNE = Iop_CmpNE64;
- shift_by = mkU8( 52 );
- mask1 = mkU64( 0x7FF );
- mask2 = mkU64( 0x000fffffffffffffULL );
+ /* V128 is converted to upper and lower 64 bit values, */
+ /* uses 64-bit operators and temps */
+ exp_mask = newTemp( Ity_I64 );
+ zero = newTemp( Ity_I64 );
+ assign( exp_mask, mkU64( V128_EXP_MASK ) );
assign( zero, mkU64( 0 ) );
}
- IRExpr * exp_part = binop( opAND,
- binop( opSHR,
- mkexpr( src ),
- shift_by ),
- mask1 );
- IRExpr * frac = binop( opAND,
- mkexpr( src ),
- mask2 );
-
- return mkAND1( binop( opCmpEQ, exp_part, mkexpr( zero ) ),
- binop( opCmpNE,
- frac,
- mkexpr( zero ) ) );
+ not_zero_exp = unop( Iop_Not1,
+ exponent_compare( size, src,
+ exp_mask, mkexpr( zero ) ) );
+ not_max_exp = unop( Iop_Not1,
+ exponent_compare( size, src,
+ exp_mask, mkexpr( exp_mask ) ) );
+
+ return mkAND1( not_zero_exp, not_max_exp );
}
-static IRExpr * is_Denorm_V128 ( IRTemp src )
-{
- /* Denormalized number has a zero exponent and non zero fraction.
- * Takes a 128-bit floating point number and returns 1-bit result.
+
+static IRExpr * create_FPCC( IRTemp NaN, IRTemp inf,
+ IRTemp zero, IRTemp norm,
+ IRTemp dnorm, IRTemp pos,
+ IRTemp neg ) {
+ IRExpr *bit0, *bit1, *bit2, *bit3;
+
+ /* If the result is NaN then must force bits 1, 2 and 3 to zero
+ * to get correct result.
*/
- IRExpr * exp_part = binop( Iop_And64,
- binop( Iop_Shr64,
- unop( Iop_V128HIto64,
- mkexpr( src ) ),
- mkU8( 48 ) ),
- mkU64( 0x7FFF ) );
- IRExpr * frac_hi = binop( Iop_And64,
- unop( Iop_V128HIto64, mkexpr( src ) ),
- mkU64( 0x0000ffffffffffffULL ) );
- IRExpr * frac_lo = unop( Iop_V128to64, mkexpr( src ) );
- return mkAND1( binop( Iop_CmpEQ64, exp_part, mkU64( 0 ) ),
- mkOR1( binop( Iop_CmpNE64,
- frac_hi,
- mkU64( 0 ) ),
- binop( Iop_CmpNE64,
- frac_lo,
- mkU64( 0 ) ) ) );
+ bit0 = unop( Iop_1Uto32, mkOR1( mkexpr( NaN ), mkexpr( inf ) ) );
+ bit1 = unop( Iop_1Uto32, mkAND1( mkNOT1( mkexpr( NaN ) ), mkexpr( zero ) ) );
+ bit2 = unop( Iop_1Uto32,
+ mkAND1( mkNOT1( mkexpr( NaN ) ),
+ mkAND1( mkOR1( mkOR1( mkAND1( mkexpr( pos ),
+ mkexpr( dnorm ) ),
+ mkAND1( mkexpr( pos ),
+ mkexpr( norm ) ) ),
+ mkAND1( mkexpr( pos ),
+ mkexpr( inf ) ) ),
+ mkAND1( mkNOT1 ( mkexpr( zero ) ),
+ mkNOT1( mkexpr( NaN ) ) ) ) ) );
+ bit3 = unop( Iop_1Uto32,
+ mkAND1( mkNOT1( mkexpr( NaN ) ),
+ mkAND1( mkOR1( mkOR1( mkAND1( mkexpr( neg ),
+ mkexpr( dnorm ) ),
+ mkAND1( mkexpr( neg ),
+ mkexpr( norm ) ) ),
+ mkAND1( mkexpr( neg ),
+ mkexpr( inf ) ) ),
+ mkAND1( mkNOT1 ( mkexpr( zero ) ),
+ mkNOT1( mkexpr( NaN ) ) ) ) ) );
+
+ return binop( Iop_Or32,
+ binop( Iop_Or32,
+ bit0,
+ binop( Iop_Shl32, bit1, mkU8( 1 ) ) ),
+ binop( Iop_Or32,
+ binop( Iop_Shl32, bit2, mkU8( 2 ) ),
+ binop( Iop_Shl32, bit3, mkU8( 3 ) ) ) );
}
+static IRExpr * create_C( IRTemp NaN, IRTemp zero,
+ IRTemp dnorm, IRTemp pos,
+ IRTemp neg )
+{
+
+ return unop( Iop_1Uto32,
+ mkOR1( mkOR1( mkexpr( NaN ),
+ mkAND1( mkexpr( neg ), mkexpr( dnorm ) ) ),
+ mkOR1( mkAND1( mkexpr( neg ), mkexpr( zero ) ),
+ mkAND1( mkexpr( pos ), mkexpr( dnorm ) ) ) ) );
+}
+
+static void generate_store_FPRF( IRType size, IRTemp src )
+{
+ IRExpr *FPCC, *C;
+ IRTemp NaN = newTemp( Ity_I1 ), inf = newTemp( Ity_I1 );
+ IRTemp dnorm = newTemp( Ity_I1 ), norm = newTemp( Ity_I1 );
+ IRTemp pos = newTemp( Ity_I1 ), neg = newTemp( Ity_I1 );
+ IRTemp zero = newTemp( Ity_I1 );
+
+ IRTemp sign_bit = newTemp( Ity_I1 );
+ IRTemp value;
+
+ vassert( ( size == Ity_I16 ) || ( size == Ity_I32 )
+ || ( size == Ity_I64 ) || ( size == Ity_F128 ) );
+
+ vassert( ( typeOfIRExpr(irsb->tyenv, mkexpr( src ) ) == Ity_I32 )
+ || ( typeOfIRExpr(irsb->tyenv, mkexpr( src ) ) == Ity_I64 )
+ || ( typeOfIRExpr(irsb->tyenv, mkexpr( src ) ) == Ity_F128 ) );
+
+ if( size == Ity_I16 ) {
+ /* The 16-bit floating point value is in the lower 16-bits of
+ the 32-bit input value */
+ value = newTemp( Ity_I32 );
+ assign( value, mkexpr( src ) );
+ assign( sign_bit,
+ unop ( Iop_32to1,
+ binop( Iop_And32,
+ binop( Iop_Shr32, mkexpr( value ), mkU8( 15 ) ),
+ mkU32( 0x1 ) ) ) );
+
+ } else if( size == Ity_I32 ) {
+ value = newTemp( size );
+ assign( value, mkexpr( src ) );
+ assign( sign_bit,
+ unop ( Iop_32to1,
+ binop( Iop_And32,
+ binop( Iop_Shr32, mkexpr( value ), mkU8( 31 ) ),
+ mkU32( 0x1 ) ) ) );
+
+ } else if( size == Ity_I64 ) {
+ value = newTemp( size );
+ assign( value, mkexpr( src ) );
+ assign( sign_bit,
+ unop ( Iop_64to1,
+ binop( Iop_And64,
+ binop( Iop_Shr64, mkexpr( value ), mkU8( 63 ) ),
+ mkU64( 0x1 ) ) ) );
+
+ } else {
+ /* Move the F128 bit pattern to an integer V128 bit pattern */
+ value = newTemp( Ity_V128 );
+ assign( value,
+ binop( Iop_64HLtoV128,
+ unop( Iop_ReinterpF64asI64,
+ unop( Iop_F128HItoF64, mkexpr( src ) ) ),
+ unop( Iop_ReinterpF64asI64,
+ unop( Iop_F128LOtoF64, mkexpr( src ) ) ) ) );
+
+ size = Ity_V128;
+ assign( sign_bit,
+ unop ( Iop_64to1,
+ binop( Iop_And64,
+ binop( Iop_Shr64,
+ unop( Iop_V128HIto64, mkexpr( value ) ),
+ mkU8( 63 ) ),
+ mkU64( 0x1 ) ) ) );
+ }
+
+ /* Calculate the floating point result field FPRF */
+ assign( NaN, is_NaN( size, value ) );
+ assign( inf, is_Inf( size, value ) );
+ assign( zero, is_Zero( size, value ) );
+ assign( norm, is_Norm( size, value ) );
+ assign( dnorm, is_Denorm( size, value ) );
+ assign( pos, mkAND1( mkNOT1( mkexpr( sign_bit ) ), mkU1( 1 ) ) );
+ assign( neg, mkAND1( mkexpr( sign_bit ), mkU1( 1 ) ) );
+
+ /* create the FPRF bit field
+ *
+ * FPRF field[4:0] type of value
+ * 10001 QNaN
+ * 01001 - infininity
+ * 01000 - Normalized
+ * 11000 - Denormalized
+ * 10010 - zero
+ * 00010 + zero
+ * 10100 + Denormalized
+ * 00100 + Normalized
+ * 00101 + infinity
+ */
+ FPCC = create_FPCC( NaN, inf, zero, norm, dnorm, pos, neg );
+ C = create_C( NaN, zero, dnorm, pos, neg );
+
+ /* Write the C and FPCC fields of the FPRF field */
+ putC( C );
+ putFPCC( FPCC );
+}
/* This function takes an Ity_I32 input argument interpreted
as a single-precision floating point value. If src is a
@@ -3671,7 +3938,7 @@
/* check if input is SNaN, if it is convert to QNaN */
assign( is_SNAN,
- mkAND1( is_NaN_32( tmp ),
+ mkAND1( is_NaN( Ity_I32, tmp ),
binop( Iop_CmpEQ32,
binop( Iop_And32, mkexpr( tmp ),
mkU32( SNAN_MASK32 ) ),
@@ -3711,7 +3978,8 @@
binop( Iop_CmpEQ32,
binop( Iop_Xor32,
mkexpr( signbit_32 ),
- unop( Iop_1Uto32, is_NaN( intermediateResult ) ) ),
+ unop( Iop_1Uto32, is_NaN( Ity_I64,
+ intermediateResult ) ) ),
mkU32( 1 ) ) ) );
assign( negatedResult,
@@ -3754,7 +4022,8 @@
binop( Iop_CmpEQ32,
binop( Iop_Xor32,
mkexpr( signbit_32 ),
- unop( Iop_1Uto32, is_NaN_32( intermediateResult ) ) ),
+ unop( Iop_1Uto32, is_NaN( Ity_I32,
+ intermediateResult ) ) ),
mkU32( 1 ) ) ) );
assign( negatedResult,
@@ -4074,9 +4343,8 @@
static IRExpr * BCDstring_zero (IRExpr *src)
{
- /* The src is a 128-bit value containing a BCD string and a sign in the
- * least significant byte. The function returns a 1 if the BCD string
- * values are all zero, 0 otherwise.
+ /* The src is a 128-bit value containing a BCD string. The function
+ * returns a 1 if the BCD string values are all zero, 0 otherwise.
*/
IRTemp tsrc = newTemp( Ity_V128 );
assign( tsrc, src);
@@ -5207,6 +5475,67 @@
break;
}
+ case 0x21A: // cnttzw, cnttzw. Count Trailing Zero Word
+ {
+ /* Note cnttzw RA, RS - RA is dest, RS is source. But the
+ * order of the operands in theInst is opc1 RS RA opc2 which has
+ * the operand fields backwards to what the standard order.
+ */
+ UChar rA_address = ifieldRegA(theInstr);
+ UChar rS_address = ifieldRegDS(theInstr);
+ IRTemp rA = newTemp(Ity_I64);
+ IRTemp rS = newTemp(Ity_I64);
+ UChar flag_rC = ifieldBIT0(theInstr);
+ IRTemp result = newTemp(Ity_I32);
+
+ DIP("cnttzw%s r%u,r%u\n", flag_rC ? "." : "",
+ rA_address, rS_address);
+
+ assign( rS, getIReg( rS_address ) );
+ assign( result, unop( Iop_Ctz32,
+ unop( Iop_64to32, mkexpr( rS ) ) ) );
+ assign( rA, binop( Iop_32HLto64, mkU32( 0 ), mkexpr( result ) ) );
+
+ if ( flag_rC )
+ set_CR0( mkexpr( rA ) );
+
+ putIReg( rA_address, mkexpr( rA ) );
+
+ return True; /* Return here since this inst is not consistent
+ * with the other instructions
+ */
+ }
+ break;
+
+ case 0x23A: // cnttzd, cnttzd. Count Trailing Zero Double word
+ {
+ /* Note cnttzd RA, RS - RA is dest, RS is source. But the
+ * order of the operands in theInst is opc1 RS RA opc2 which has
+ * the operand order listed backwards to what is standard.
+ */
+ UChar rA_address = ifieldRegA(theInstr);
+ UChar rS_address = ifieldRegDS(theInstr);
+ IRTemp rA = newTemp(Ity_I64);
+ IRTemp rS = newTemp(Ity_I64);
+ UChar flag_rC = ifieldBIT0(theInstr);
+
+ DIP("cnttzd%s r%u,r%u\n", flag_rC ? "." : "",
+ rA_address, rS_address);
+
+ assign( rS, getIReg( rS_address ) );
+ assign( rA, unop( Iop_Ctz64, mkexpr( rS ) ) );
+
+ if ( flag_rC == 1 )
+ set_CR0( mkexpr( rA ) );
+
+ putIReg( rA_address, mkexpr( rA ) );
+
+ return True; /* Return here since this inst is not consistent
+ * with the other instructions
+ */
+ }
+ break;
+
case 0x309: // modsd Modulo Signed Double Word
{
IRTemp rA = newTemp( Ity_I64 );
@@ -9317,6 +9646,31 @@
IRRoundingMode. PPCRoundingMode encoding is different to
IRRoundingMode, so need to map it.
*/
+
+static IRExpr* /* :: Ity_I32 */ set_round_to_Oddmode ( void )
+{
+/* PPC/ valgrind have two-bits to designate the rounding mode.
+ ISA 3.0 adds instructions than can use a round to odd mode
+ but did not change the number of bits for the rm. Basically,
+ they added two instructions that only differ by the rounding
+ mode the operation uses. In essesce, they encoded the rm
+ in the name. In order to avoid having to create Iops, that
+ encode the rm in th name, we will "expand" the definition of
+ the rounding mode bits. We will just pass the rm and then
+ map the to odd mode to the appropriate PPCFpOp name that
+ will tell us which instruction to map to.
+
+ rounding mode | PPC | IR
+ ------------------------
+ to nearest | 000 | 00
+ to zero | 001 | 11
+ to +infinity | 010 | 10
+ to -infinity | 011 | 01
+ to odd | 1xx | xx
+*/
+ return mkU32(8);
+}
+
static IRExpr* /* :: Ity_I32 */ get_IR_roundingmode ( void )
{
/*
@@ -10134,6 +10488,7 @@
* Otherwise fg_flag is set to 0.
*
*/
+
static void do_fp_tsqrt(IRTemp frB_Int, Bool sp, IRTemp * fe_flag_tmp, IRTemp * fg_flag_tmp)
{
// The following temps are for holding intermediate results
@@ -10147,7 +10502,12 @@
IRTemp frbInf_tmp = newTemp(Ity_I1);
*fe_flag_tmp = newTemp(Ity_I32);
*fg_flag_tmp = newTemp(Ity_I32);
- assign( frB_exp_shR, fp_exp_part( frB_Int, sp ) );
+
+ if ( sp )
+ assign( frB_exp_shR, fp_exp_part( Ity_I32, frB_Int ) );
+ else
+ assign( frB_exp_shR, fp_exp_part( Ity_I64, frB_Int ) );
+
assign(e_b, binop( Iop_Sub32, mkexpr(frB_exp_shR), mkU32( bias ) ));
////////////////// fe_flag tests BEGIN //////////////////////
@@ -10155,9 +10515,17 @@
* (NOTE: These tests are similar to those used for ftdiv. See do_fp_tdiv()
* for details.)
*/
- frbNaN = sp ? is_NaN_32(frB_Int) : is_NaN(frB_Int);
- assign( frbInf_tmp, is_Inf(frB_Int, sp) );
- assign( frbZero_tmp, is_Zero(frB_Int, sp ) );
+ if ( sp ) {
+ frbNaN = is_NaN( Ity_I32, frB_Int );
+ assign( frbInf_tmp, is_Inf( Ity_I32, frB_Int ) );
+ assign( frbZero_tmp, is_Zero( Ity_I32, frB_Int ) );
+
+ } else {
+ frbNaN = is_NaN( Ity_I64, frB_Int );
+ assign( frbInf_tmp, is_Inf( Ity_I64, frB_Int ) );
+ assign( frbZero_tmp, is_Zero( Ity_I64, frB_Int ) );
+ }
+
{
// Test_value = -970 for double precision
UInt test_value = sp ? 0xffffff99 : 0xfffffc36;
@@ -10271,8 +10639,14 @@
IRExpr * fe_flag, * fg_flag;
// Create temps that will be used throughout the following tests.
- assign( frA_exp_shR, fp_exp_part( frA_int, sp ) );
- assign( frB_exp_shR, fp_exp_part( frB_int, sp ) );
+ if ( sp ) {
+ assign( frA_exp_shR, fp_exp_part( Ity_I32, frA_int ) );
+ assign( frB_exp_shR, fp_exp_part( Ity_I32, frB_int ) );
+ } else{
+ assign( frA_exp_shR, fp_exp_part( Ity_I64, frA_int ) );
+ assign( frB_exp_shR, fp_exp_part( Ity_I64, frB_int ) );
+ }
+
/* Let e_[a|b] be the unbiased exponent: i.e. exp - 1023. */
assign(e_a, binop( Iop_Sub32, mkexpr(frA_exp_shR), mkU32( bias ) ));
assign(e_b, binop( Iop_Sub32, mkexpr(frB_exp_shR), mkU32( bias ) ));
@@ -10285,28 +10659,26 @@
* Test if the double-precision floating-point operand in register FRA is
* a NaN:
*/
- fraNaN = sp ? is_NaN_32(frA_int) : is_NaN(frA_int);
+ fraNaN = sp ? is_NaN( Ity_I32, frA_int ) : is_NaN( Ity_I64, frA_int );
/*
- * Test if the double-precision floating-point operand in register FRA is
- * an Infinity.
+ * Test if the double-precision floating-point operands in register FRA
+ * and FRB is an Infinity. Test if FRB is zero.
*/
- assign(fraInf_tmp, is_Inf(frA_int, sp));
+ if ( sp ) {
+ assign(fraInf_tmp, is_Inf( Ity_I32, frA_int ) );
+ assign( frbInf_tmp, is_Inf( Ity_I32, frB_int ) );
+ assign( frbZero_tmp, is_Zero( Ity_I32, frB_int ) );
+ } else {
+ assign(fraInf_tmp, is_Inf( Ity_I64, frA_int ) );
+ assign( frbInf_tmp, is_Inf( Ity_I64, frB_int ) );
+ assign( frbZero_tmp, is_Zero( Ity_I64, frB_int ) );
+ }
/*
* Test if the double-precision floating-point operand in register FRB is
* a NaN:
*/
- frbNaN = sp ? is_NaN_32(frB_int) : is_NaN(frB_int);
- /*
- * Test if the double-precision floating-point operand in register FRB is
- * an Infinity.
- */
- assign( frbInf_tmp, is_Inf(frB_int, sp) );
- /*
- * Test if the double-precision floating-point operand in register FRB is
- * a Zero.
- */
- assign( frbZero_tmp, is_Zero(frB_int, sp) );
+ frbNaN = sp ? is_NaN( Ity_I32, frB_int ) : is_NaN( Ity_I64, frB_int );
/*
* Test if e_b <= -1022 for double precision;
@@ -10329,7 +10701,11 @@
/*
* Test if FRA != Zero and (e_a - e_b) >= bias
*/
- assign( fraNotZero_tmp, unop( Iop_Not1, is_Zero( frA_int, sp ) ) );
+ if ( sp )
+ assign( fraNotZero_tmp, unop( Iop_Not1, is_Zero( Ity_I32, frA_int ) ) );
+ else
+ assign( fraNotZero_tmp, unop( Iop_Not1, is_Zero( Ity_I64, frA_int ) ) );
+
ea_eb_GTE = mkAND1( mkexpr( fraNotZero_tmp ),
binop( Iop_CmpLT32S, mkU32( bias ),
binop( Iop_Sub32, mkexpr( e_a ),
@@ -14723,12 +15099,64 @@
mkexpr( vB ) ) );
break;
+ case 28: // vctzb, Vector Count Trailing Zeros Byte
+ {
+ DIP("vctzb v%d,v%d", rT_addr, vB_addr);
+
+ /* This instruction is only available in the ISA 3.0 */
+ if ( !mode64 || !allow_isa_3_0 ) {
+ vex_printf("\n vctzb instruction not supported on non ISA 3.0 platform\n\n");
+ return False;
+ }
+ assign( vT, unop( Iop_Ctz8x16, mkexpr( vB ) ) );
+ }
+ break;
+
+ case 29: // vctzh, Vector Count Trailing Zeros Halfword
+ {
+ DIP("vctzh v%d,v%d", rT_addr, vB_addr);
+
+ /* This instruction is only available in the ISA 3.0 */
+ if ( !mode64 || !allow_isa_3_0 ) {
+ vex_printf("\n vctzh instruction not supported on non ISA 3.0 platform\n\n");
+ return False;
+ }
+ assign( vT, unop( Iop_Ctz16x8, mkexpr( vB ) ) );
+ }
+ break;
+
+ case 30: // vctzw, Vector Count Trailing Zeros Word
+ {
+ DIP("vctzw v%d,v%d", rT_addr, vB_addr);
+
+ /* This instruction is only available in the ISA 3.0 */
+ if ( !mode64 || !allow_isa_3_0 ) {
+ vex_printf("\n vctzw instruction not supported on non ISA 3.0 platform\n\n");
+ return False;
+ }
+ assign( vT, unop( Iop_Ctz32x4, mkexpr( vB ) ) );
+ }
+ break;
+
+ case 31: // vctzd, Vector Count Trailing Zeros Double word
+ {
+ DIP("vctzd v%d,v%d", rT_addr, vB_addr);
+
+ /* This instruction is only available in the ISA 3.0 */
+ if ( !mode64 || !allow_isa_3_0 ) {
+ vex_printf("\n vctzd instruction not supported on non ISA 3.0 platform\n\n");
+ return False;
+ }
+ assign( vT, unop( Iop_Ctz64x2, mkexpr( vB ) ) );
+ }
+ break;
+
default:
vex_printf("dis_av_extend_sign(ppc)(Unsupported vector extend sign instruction)\n");
return False;
}
- putVReg( rT_addr, mkexpr( vT) );
+ putVReg( rT_addr, mkexpr( vT ) );
return True;
}
@@ -15239,22 +15667,22 @@
assign( res1, unop(Iop_64HIto32, mkexpr(lo64)) );
assign( res0, unop(Iop_64to32, mkexpr(lo64)) );
- b3_result = IRExpr_ITE(is_NaN_32(b3),
+ b3_result = IRExpr_ITE(is_NaN(Ity_I32, b3),
// then: result is 0x{8|0}80000000
mkU32(un_signed ? 0x00000000 : 0x80000000),
// else: result is from the Iop_QFtoI32{s|u}x4_RZ
mkexpr(res3));
- b2_result = IRExpr_ITE(is_NaN_32(b2),
+ b2_result = IRExpr_ITE(is_NaN(Ity_I32, b2),
// then: result is 0x{8|0}80000000
mkU32(un_signed ? 0x00000000 : 0x80000000),
// else: result is from the Iop_QFtoI32{s|u}x4_RZ
mkexpr(res2));
- b1_result = IRExpr_ITE(is_NaN_32(b1),
+ b1_result = IRExpr_ITE(is_NaN(Ity_I32, b1),
// then: result is 0x{8|0}80000000
mkU32(un_signed ? 0x00000000 : 0x80000000),
// else: result is from the Iop_QFtoI32{s|u}x4_RZ
mkexpr(res1));
- b0_result = IRExpr_ITE(is_NaN_32(b0),
+ b0_result = IRExpr_ITE(is_NaN(Ity_I32, b0),
// then: result is 0x{8|0}80000000
mkU32(un_signed ? 0x00000000 : 0x80000000),
// else: result is from the Iop_QFtoI32{s|u}x4_RZ
@@ -16447,8 +16875,8 @@
IRTemp frA_isQNaN = newTemp(Ity_I1);
IRTemp frB_isQNaN = newTemp(Ity_I1);
- assign( frA_isNaN, is_NaN( frA_I64 ) );
- assign( frB_isNaN, is_NaN( frB_I64 ) );
+ assign( frA_isNaN, is_NaN( Ity_I64, frA_I64 ) );
+ assign( frB_isNaN, is_NaN( Ity_I64, frB_I64 ) );
// If operand is a NAN and bit 12 is '0', then it's an SNaN
assign( frA_isSNaN,
mkAND1( mkexpr(frA_isNaN),
@@ -16540,9 +16968,10 @@
IRTemp anyNaN = newTemp(Ity_I1);
IRTemp frA_isZero = newTemp(Ity_I1);
IRTemp frB_isZero = newTemp(Ity_I1);
- assign(frA_isZero, is_Zero(frA_I64, False /*not single precision*/ ));
- assign(frB_isZero, is_Zero(frB_I64, False /*not single precision*/ ));
- assign(anyNaN, mkOR1(is_NaN(frA_I64), is_NaN(frB_I64)));
+ assign( frA_isZero, is_Zero( Ity_I64, frA_I64 ) );
+ assign( frB_isZero, is_Zero( Ity_I64, frB_I64 ) );
+ assign( anyNaN, mkOR1( is_NaN( Ity_I64, frA_I64 ),
+ is_NaN(Ity_I64, frB_I64 ) ) );
#define MINUS_ZERO 0x8000000000000000ULL
return IRExpr_ITE( /* If both arguments are zero . . . */
@@ -16662,7 +17091,7 @@
#define SNAN_MASK 0x0008000000000000ULL
hi32 = unop( Iop_64HIto32, mkexpr(frB_I64) );
assign( is_SNAN,
- mkAND1( is_NaN( frB_I64 ),
+ mkAND1( is_NaN( Ity_I64, frB_I64 ),
binop( Iop_CmpEQ32,
binop( Iop_And32, hi32, mkU32( 0x00080000 ) ),
mkU32( 0 ) ) ) );
@@ -16707,6 +17136,7 @@
assign(frB2, unop(Iop_V128to64, getVSReg( XB )));
DIP("%s v%d,v%d\n", redp ? "xvredp" : "xvrsqrtedp", XT, XB);
+
if (!redp) {
assign( sqrtHi,
binop( Iop_SqrtF64,
@@ -17696,7 +18126,7 @@
* Miscellaneous VSX Scalar Instructions
*/
static Bool
-dis_vxs_misc( UInt theInstr, UInt opc2 )
+dis_vxs_misc( UInt theInstr, UInt opc2, int allow_isa_3_0 )
{
#define VG_PPC_SIGN_MASK 0x7fffffffffffffffULL
/* XX3-Form and XX2-Form */
@@ -17781,8 +18211,8 @@
mkU64( 0x7FFF00000000000 ) ) );
/* exp A or exp B is NaN */
- bit7 = mkOR1( is_NaN_V128( vA ),
- is_NaN_V128( vB ) );
+ bit7 = mkOR1( is_NaN( Ity_V128, vA ),
+ is_NaN( Ity_V128, vB ) );
assign( eq_lt_gt, binop( Iop_Or32,
binop( Iop_Shl32,
@@ -17881,6 +18311,10 @@
case 0x2b6: // xsxexpdp (VSX Scalar Extract Exponent Double-Precision)
// xsxsigdp (VSX Scalar Extract Significand Doulbe-Precision)
+ // xsvhpdp (VSX Scalar Convert Half-Precision format
+ // to Double-Precision format)
+ // xscvdphp (VSX Scalar round & convert Double-precision
+ // format to Half-precision format)
{
IRTemp rT = newTemp( Ity_I64 );
UInt inst_select = IFIELD( theInstr, 16, 5);
@@ -17903,8 +18337,9 @@
/* Value is normal if it isn't infinite, zero or denormalized */
normal = mkNOT1( mkOR1(
- mkOR1( is_NaN( tmp ), is_Inf( tmp, False ) ),
- mkOR1( is_Zero( tmp, False ),
+ mkOR1( is_NaN( Ity_I64, tmp ),
+ is_Inf( Ity_I64, tmp ) ),
+ mkOR1( is_Zero( Ity_I64, tmp ),
is_Denorm( Ity_I64, tmp ) ) ) );
assign( rT, binop( Iop_Or64,
@@ -17914,11 +18349,46 @@
binop( Iop_Shl64,
unop( Iop_1Uto64, normal),
mkU8( 52 ) ) ) );
+ putIReg( XT, mkexpr( rT ) );
+
+ } else if (inst_select == 16) {
+ IRTemp result = newTemp( Ity_V128 );
+ IRTemp value = newTemp( Ity_I64 );
+ /* Note: PPC only coverts the 16-bit value in the upper 64-bits
+ * of the source V128 to a 64-bit value stored in the upper
+ * 64-bits of the V128 result. The contents of the lower 64-bits
+ * is undefined.
+ */
+
+ DIP("xscvhpdp v%d, v%d\n", (UInt)XT, (UInt)XB);
+ assign( result, unop( Iop_F16toF64x2, mkexpr( vB ) ) );
+
+ putVSReg( XT, mkexpr( result ) );
+
+ assign( value, unop( Iop_V128HIto64, mkexpr( result ) ) );
+ generate_store_FPRF( Ity_I64, value );
+ return True;
+
+ } else if (inst_select == 17) { // xscvdphp
+ IRTemp value = newTemp( Ity_I32 );
+ IRTemp result = newTemp( Ity_V128 );
+ /* Note: PPC only coverts the 64-bit value in the upper 64-bits of
+ * the V128 and stores the 16-bit result in the upper word of the
+ * V128 result. The contents of the lower 64-bits is undefined.
+ */
+ DIP("xscvdphp v%d, v%d\n", (UInt)XT, (UInt)XB);
+ assign( result, unop( Iop_F64toF16x2, mkexpr( vB ) ) );
+ assign( value, unop( Iop_64to32, unop( Iop_V128HIto64,
+ mkexpr( result ) ) ) );
+ putVSReg( XT, mkexpr( result ) );
+ generate_store_FPRF( Ity_I32, value );
+ return True;
+
} else {
vex_printf( "dis_vxv_scalar_extract_exp_sig invalid inst_select (ppc)(opc2)\n" );
+ vex_printf("inst_select = %d\n", inst_select);
return False;
}
- putIReg( XT, mkexpr(rT));
}
break;
@@ -17952,9 +18422,9 @@
mkU8( 63 ) ),
mkU64( 0 ) ) ) );
- assign( NaN, unop( Iop_1Uto64, is_NaN( vB_hi ) ) );
- assign( inf, unop( Iop_1Uto64, is_Inf( vB_hi, False ) ) );
- assign( zero, unop( Iop_1Uto64, is_Zero( vB_hi, False ) ) );
+ assign( NaN, unop( Iop_1Uto64, is_NaN( Ity_I64, vB_hi ) ) );
+ assign( inf, unop( Iop_1Uto64, is_Inf( Ity_I64, vB_hi ) ) );
+ assign( zero, unop( Iop_1Uto64, is_Zero( Ity_I64, vB_hi ) ) );
if (opc2 == 0x254) {
DIP("xststdcsp %d,v%d,%d\n", BF, (UInt)XB, DCMX_mask);
@@ -18254,9 +18724,9 @@
mkU8( 31 ) ),
mkU32( 0 ) ) ) );
- assign( NaN[i], unop( Iop_1Uto32, is_NaN_32( value[i] ) ));
- assign( inf[i], unop( Iop_1Uto32, is_Inf( value[i], True ) ) );
- assign( zero[i], unop( Iop_1Uto32, is_Zero( value[i], True ) ) );
+ assign( NaN[i], unop( Iop_1Uto32, is_NaN( Ity_I32, value[i] ) ));
+ assign( inf[i], unop( Iop_1Uto32, is_Inf( Ity_I32, value[i] ) ) );
+ assign( zero[i], unop( Iop_1Uto32, is_Zero( Ity_I32, value[i] ) ) );
assign( dnorm[i], unop( Iop_1Uto32, is_Denorm( Ity_I32,
value[i] ) ) );
@@ -18384,6 +18854,8 @@
// xxbrw
// xxbrd
// xxbrq
+ // xvcvhpsp (VSX Vector Convert Half-Precision format to Single-Precision format)
+ // xvcvsphp (VSX Vector round and convert Single-Precision format to Half-Precision format)
{
UInt inst_select = IFIELD( theInstr, 16, 5);
@@ -18422,15 +18894,14 @@
mkU64( 0x0 ),
mkU64( 0xFFFFFFFFFFFFFFFF ) ) ) ) );
- new_XT[i+1] = newTemp(Ity_V128);
-
/* Value is normal if it isn't infinite, zero or denormalized */
normal[i] = mkNOT1( mkOR1(
- mkOR1( is_NaN( value[i] ),
- is_Inf( value[i], False ) ),
- mkOR1( is_Zero( value[i], False ),
+ mkOR1( is_NaN( Ity_I64, value[i] ),
+ is_Inf( Ity_I64, value[i] ) ),
+ mkOR1( is_Zero( Ity_I64, value[i] ),
is_Denorm( Ity_I64,
value[i] ) ) ) );
+ new_XT[i+1] = newTemp(Ity_V128);
assign( new_XT[i+1],
binop( Iop_OrV128,
@@ -18517,9 +18988,9 @@
/* Value is normal if it isn't infinite, zero or denormalized */
normal[i] = mkNOT1( mkOR1(
- mkOR1( is_NaN_32( value[i] ),
- is_Inf( value[i], True ) ),
- mkOR1( is_Zero( value[i], True ),
+ mkOR1( is_NaN( Ity_I32, value[i] ),
+ is_Inf( Ity_I32, value[i] ) ),
+ mkOR1( is_Zero( Ity_I32, value[i] ),
is_Denorm( Ity_I32,
value[i] ) ) ) );
new_value[i] = newTemp(Ity_I32);
@@ -18643,6 +19114,79 @@
putVSReg( XT, mkexpr( new_xT[4] ) );
+ } else if (inst_select == 24) {
+ // xvcvhpsp, (VSX Vector Convert half-precision format to
+ // Single-precision format)
+ /* only supported on ISA 3.0 and newer */
+ IRTemp result = newTemp( Ity_V128 );
+ IRTemp src = newTemp( Ity_I64 );
+
+ if (!allow_isa_3_0) return False;
+
+ DIP("xvcvhpsp v%d,v%d\n", XT,XB);
+ /* The instruction does not set the C or FPCC fields. The
+ * instruction takes four 16-bit values stored in a 128-bit value
+ * as follows: x V | x V | x V | x V where V is a 16-bit
+ * value and x is an unused 16-bit value. To use Iop_F16toF32x4
+ * the four 16-bit values will be gathered into a single 64 bit
+ * value. The backend will scatter the four 16-bit values back
+ * into a 128-bit operand before issuing the instruction.
+ */
+ /* Gather 16-bit float values from V128 source into new 64-bit
+ * source value for the Iop.
+ */
+ assign( src,
+ unop( Iop_V128to64,
+ binop( Iop_Perm8x16,
+ mkexpr( vB ),
+ binop ( Iop_64HLtoV128,
+ mkU64( 0 ),
+ mkU64( 0x020306070A0B0E0F) ) ) ) );
+
+ assign( result, unop( Iop_F16toF32x4, mkexpr( src ) ) );
+
+ putVSReg( XT, mkexpr( result ) );
+
+ } else if (inst_select == 25) {
+ // xvcvsphp, (VSX Vector round and Convert single-precision
+ // format to half-precision format)
+ /* only supported on ISA 3.0 and newer */
+ IRTemp result = newTemp( Ity_V128 );
+ IRTemp tmp64 = newTemp( Ity_I64 );
+ IRTemp f0 = newTemp( Ity_I64 );
+ IRTemp f1 = newTemp( Ity_I64 );
+ IRTemp f2 = newTemp( Ity_I64 );
+ IRTemp f3 = newTemp( Ity_I64 );
+
+ if (!allow_isa_3_0) return False;
+ DIP("xvcvsphp v%d,v%d\n", XT,XB);
+
+ /* Iop_F32toF16x4 is V128 -> I64, scatter the 16-bit floats in the
+ * I64 result to the V128 register to store.
+ */
+ assign( tmp64, unop( Iop_F32toF16x4, mkexpr( vB ) ) );
+ assign( f0,binop( Iop_And64,
+ mkU64( 0xFFFF ), mkexpr( tmp64 ) ) );
+ assign( f1, binop( Iop_And64,
+ mkU64( 0xFFFF0000 ), mkexpr( tmp64 ) ) );
+ assign( f2, binop( Iop_And64,
+ mkU64( 0xFFFF00000000 ), mkexpr( tmp64 ) ) );
+ assign( f3, binop( Iop_And64,
+ mkU64( 0xFFFF000000000000 ), mkexpr( tmp64 ) ) );
+
+ /* Scater 16-bit float values from returned 64-bit value
+ * of V128 result.
+ */
+ assign( result,
+ binop( Iop_Perm8x16,
+ binop( Iop_64HLtoV128,
+ mkU64( 0 ),
+ mkexpr( tmp64 ) ),
+ binop ( Iop_64HLtoV128,
+ mkU64( 0x0000080900000A0B ),
+ mkU64( 0x00000C0D00000E0F ) ) ) );
+ putVSReg( XT, mkexpr( result ) );
+
} else if ( inst_select == 31 ) {
int i;
int shift_left = 8;
@@ -18741,9 +19285,9 @@
mkU8( 63 ) ),
mkU64( 0 ) ) ) );
- assign( NaN[i], unop( Iop_1Uto64, is_NaN( value[i] ) ) );
- assign( inf[i], unop( Iop_1Uto64, is_Inf( value[i], False ) ) );
- assign( zero[i], unop( Iop_1Uto64, is_Zero( value[i], False ) ) );
+ assign( NaN[i], unop( Iop_1Uto64, is_NaN( Ity_I64, value[i] ) ) );
+ assign( inf[i], unop( Iop_1Uto64, is_Inf( Ity_I64, value[i] ) ) );
+ assign( zero[i], unop( Iop_1Uto64, is_Zero( Ity_I64, value[i] ) ) );
assign( dnorm[i], unop( Iop_1Uto64, is_Denorm( Ity_I64,
value[i] ) ) );
@@ -20390,41 +20934,456 @@
return True;
}
-/* VSX Scalar Quad-Precision instructions */
static Bool
-dis_vx_scalar_quad_precision ( UInt theInstr )
+dis_vx_Scalar_Round_to_quad_integer( UInt theInstr )
{
+ /* The ISA 3.0 instructions supported in this function require
+ * the underlying hardware platform that supports the ISA3.0
+ * instruction set.
+ */
/* XX1-Form */
UChar opc1 = ifieldOPC( theInstr );
- UInt opc2 = ifieldOPClo10( theInstr );
- UChar vT_addr = ifieldRegDS( theInstr ) + 32;
- UChar vA_addr = ifieldRegA( theInstr ) + 32;
- UChar vB_addr = ifieldRegB( theInstr ) + 32;
- IRTemp vA = newTemp( Ity_V128 );
- IRTemp vB = newTemp( Ity_V128 );
- IRTemp vT = newTemp( Ity_V128 );
-
- assign( vB, getVSReg(vB_addr));
+ UInt opc2 = IFIELD( theInstr, 1, 8 );
+ UChar vT_addr = ifieldRegDS( theInstr );
+ UChar vB_addr = ifieldRegB( theInstr );
+ IRTemp vB = newTemp( Ity_F128 );
+ IRTemp vT = newTemp( Ity_F128 );
+ UChar EX = IFIELD( theInstr, 0, 1 );
+ assign( vB, getF128Reg( vB_addr ) );
if (opc1 != 0x3F) {
- vex_printf( "dis_vx_scalar_quad_precision(ppc)(instr)\n" );
+ vex_printf( "dis_vx_Scalar_Round_to_quad_integer(ppc)(instr)\n" );
return False;
}
-
switch (opc2) {
-
- case 0x064: // xscpsgnqp (VSX Scalar Copy Sign Quad-Precision)
+ case 0x005: // VSX Scalar Round to Quad-Precision Integer [with Inexact]
{
- IRTemp sign_vA = newTemp( Ity_I64 );
- IRTemp vB_hi = newTemp( Ity_I64 );
+ UChar R = IFIELD( theInstr, 16, 1 );
+ UChar RMC = IFIELD( theInstr, 9, 2 );
- DIP("xscpsgnqp v%d,v%d,v%d\n", vT_addr, vA_addr, vB_addr);
+ /* Store the rm specification bits. Will extract them later when
+ * the isntruction is issued.
+ */
+ IRExpr* rm = mkU...
[truncated message content] |