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 )
{
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);
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;
+ }
-// Infinity: exp = 7ff and fraction is zero; s = 0/1
-static IRExpr * is_Inf(IRTemp src, Bool sp)
-{
- IRExpr * Inf_exp, * hi32, * low32;
- IRTemp frac_part;
+ if( size == Ity_V128 ) {
+ return binop( opCmpEQ,
+ binop ( opAND,
+ unop( Iop_V128HIto64, mkexpr( src ) ),
+ mkexpr( exp_mask ) ),
+ exp_val );
- if (sp)
- return is_Inf_sp(src);
+ } else if( ( size == Ity_I16 ) || ( size == Ity_I32 ) ) {
+ return binop( opCmpEQ,
+ binop ( opAND, mkexpr( src ), mkexpr( exp_mask ) ),
+ exp_val );
+ } else {
+ /* 64-bit operands */
- 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 (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 ) ) );
+ }
+ }
}
-/* Quad precision floating point number is infinit:
- * exp is 32767 and fraction is zero; sign = 0/1
- */
-static IRExpr * is_Inf_V128 ( IRTemp src )
+static IRExpr *fractional_part_compare( IRType size, IRTemp src,
+ IRTemp frac_mask, IRExpr *zero )
{
- IRExpr * frac_part_hi, * frac_part_low, *Inf_exp;
+ IROp opAND, opCmpEQ;
- Inf_exp = binop( Iop_CmpEQ64,
- binop( Iop_And64,
- binop( Iop_Shr64,
- unop( Iop_V128HIto64,
- mkexpr( src ) ),
- mkU8( 48 ) ),
- mkU64( 0x7FFF ) ),
- mkU64( 0x7FFF ) );
+ 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;
- frac_part_hi = binop( Iop_And64,
- unop( Iop_V128HIto64, mkexpr( src ) ),
- mkU64( 0x0000FFFFFFFFFFFF ) );
- frac_part_low = unop( Iop_V128to64, mkexpr( src ) );
+ } else {
+ opAND = Iop_And64;
+ opCmpEQ = Iop_CmpEQ64;
+ }
- return mkAND1( Inf_exp,
- mkAND1( binop( Iop_CmpEQ64, frac_part_hi, mkU64( 0 ) ),
- binop( Iop_CmpEQ64, frac_part_low, mkU64( 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 ) ) );
+ }
+ }
}
-static IRExpr * is_Zero_sp(IRTemp src)
+// Infinity: exp has all bits set, and fraction is zero; s = 0/1
+static IRExpr * is_Inf( IRType size, 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 ) );
+ IRExpr *max_exp, *zero_frac;
+ IRTemp exp_mask, frac_mask, zero;
+
+ 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 ) ) );
-}
-
-/* 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 exponent is all ones, i.e. (exp AND exp_mask) = exp_mask */
+ max_exp = exponent_compare( size, src, exp_mask, mkexpr( exp_mask ) );
- 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 ) );
+ /* 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, 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 );
+ 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( binop( opCmpEQ, exp_part, mkexpr( zero ) ),
- binop( opCmpNE,
- frac,
- mkexpr( zero ) ) );
+ 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
/* 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 ) ),
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,
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,
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);
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 );
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 )
{
/*
* 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
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 //////////////////////
* (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;
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 ) ));
* 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;
/*
* 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 ),
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;
}
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
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),
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 . . . */
#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 ) ) ) );
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,
* 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 */
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,
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);
/* 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,
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;
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);
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] ) ) );
// 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);
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,
/* 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);
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;
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] ) ) );
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 = mkU32( R << 3 | RMC << 1 | EX);
- assign( vA, getVSReg(vA_addr) );
+ if ( EX == 0 ) { // xsrqpi
+ DIP("xsrqpi %d,v%d,v%d,%d\n", R, vT_addr, vB_addr, RMC);
+ assign( vT, binop( Iop_F128toI128S, rm, mkexpr( vB ) ) );
- assign( sign_vA, binop( Iop_And64,
- unop( Iop_V128HIto64,
- mkexpr( vA ) ),
- mkU64( 0x8000000000000000ULL ) ) );
- assign( vB_hi, binop( Iop_Or64,
- binop( Iop_And64,
- unop( Iop_V128HIto64,
+ } else { // xsrqpix
+ DIP("xsrqpix %d,v%d,v%d,%d\n", R, vT_addr, vB_addr, RMC);
+ assign( vT, binop( Iop_F128toI128S, rm, mkexpr( vB ) ) );
+ }
+ generate_store_FPRF( Ity_F128, vT );
+ } /* case 0x005 */
+ break;
+ case 0x025: // xsrqpxp VSX Scalar Round Quad-Precision to
+ // Double-Extended Precision
+ {
+ UChar R = IFIELD( theInstr, 16, 1 );
+ UChar RMC = IFIELD( theInstr, 9, 2 );
+
+ /* Store the rm specification bits. Will extract them later when
+ * the isntruction is issued.
+ */
+ IRExpr* rm = mkU32( R << 3 | RMC << 1 );
+
+ DIP("xsrqpxp %d,v%d,v%d,%d\n", R, vT_addr, vB_addr, RMC);
+ assign( vT, binop( Iop_RndF128, rm, mkexpr( vB ) ) );
+ generate_store_FPRF( Ity_F128, vT );
+ } /* case 0x025 */
+ break;
+ default:
+ vex_printf( "dis_vx_Scalar_Round_to_quad_integer(ppc)(opc2)\n" );
+ return False;
+ } /* switch opc2 */
+ putF128Reg( vT_addr, mkexpr( vT ) );
+ return True;
+}
+
+static Bool
+dis_vx_Floating_Point_Arithmetic_quad_precision( UInt theInstr )
+{
+ /* The ISA 3.0 instructions supported in this function require
+ * the underlying hardware platform that supports the ISA 3.0
+ * instruction set.
+ */
+ /* XX1-Form */
+ UChar opc1 = ifieldOPC( theInstr );
+ UInt opc2 = ifieldOPClo10( theInstr );
+ UChar vT_addr = ifieldRegDS( theInstr );
+ UChar vA_addr = ifieldRegA( theInstr );
+ UChar vB_addr = ifieldRegB( theInstr );
+ IRTemp vA = newTemp( Ity_F128 );
+ IRTemp vB = newTemp( Ity_F128 );
+ IRTemp vT = newTemp( Ity_F128 );
+ IRExpr* rm = get_IR_roundingmode();
+ UChar R0 = IFIELD( theInstr, 0, 1 );
+
+ assign( vB, getF128Reg( vB_addr ) );
+
+ if ( opc1 != 0x3F ) {
+ vex_printf( "Erorr, dis_vx_Floating_Point_Arithmetic_quad_precision(ppc)(instr)\n" );
+ return False;
+ }
+ switch ( opc2 ) {
+ case 0x004: // xsaddqp (VSX Scalar Add Quad-Precision[using round to Odd])
+ {
+ assign( vA, getF128Reg( vA_addr ) );
+
+ if ( R0 == 0 ) {
+ /* rounding mode specified by RN. Issue inst with R0 = 0 */
+ DIP("xsaddqp v%d,v%d,v%d\n", vT_addr, vA_addr, vB_addr);
+ assign( vT, triop( Iop_AddF128, rm, mkexpr( vA ), mkexpr( vB ) ) );
+
+ } else {
+ /* rounding mode specified by Round to odd. Issue inst with R0 = 1 */
+ DIP("xsaddqpo v%d,v%d,v%d\n", vT_addr, vA_addr, vB_addr);
+ assign( vT, triop( Iop_AddF128, set_round_to_Oddmode(),
+ mkexpr( vA ), mkexpr( vB ) ) );
+ }
+ generate_store_FPRF( Ity_F128, vT );
+ break;
+ }
+ case 0x024: // xsmulqp (VSX Scalar Multiply Quad-Precision[using round to Odd])
+ {
+ assign( vA, getF128Reg( vA_addr ) );
+
+ if ( R0 == 0 ) {
+ /* rounding mode specified by RN. Issue inst with R0 = 0 */
+ DIP("xsmulqp v%d,v%d,v%d\n", vT_addr, vA_addr, vB_addr);
+ assign( vT, triop( Iop_MulF128, rm, mkexpr( vA ), mkexpr( vB ) ) );
+
+ } else {
+ /* rounding mode specified by Round to odd. Issue inst with R0 = 1 */
+ DIP("xsmulqpo v%d,v%d,v%d\n", vT_addr, vA_addr, vB_addr);
+ assign( vT, triop( Iop_MulF128, set_round_to_Oddmode(), mkexpr( vA ),
+ mkexpr( vB ) ) );
+ }
+ generate_store_FPRF( Ity_F128, vT );
+ break;
+ }
+ case 0x184: // xsmaddqp (VSX Scalar Multiply add Quad-Precision[using round to Odd])
+ {
+ /* instruction computes (vA * vB) + vC */
+ IRTemp vC = newTemp( Ity_F128 );
+
+ assign( vA, getF128Reg( vA_addr ) );
+ assign( vC, getF128Reg( vT_addr ) );
+
+ if ( R0 == 0 ) {
+ /* rounding mode specified by RN. Issue inst with R0 = 0 */
+ DIP("xsmaddqp v%d,v%d,v%d\n", vT_addr, vA_addr, vB_addr);
+ assign( vT,
+ qop( Iop_MAddF128, rm, mkexpr( vA ),
+ mkexpr( vC ), mkexpr( vB ) ) );
+
+ } else {
+ /* rounding mode specified by Round to odd. Issue inst with R0 = 1 */
+ DIP("xsmaddqpo v%d,v%d,v%d\n", vT_addr, vA_addr, vB_addr);
+ assign( vT,
+ qop( Iop_MAddF128, set_round_to_Oddmode(), mkexpr( vA ),
+ mkexpr( vC ), mkexpr( vB ) ) );
+ }
+ generate_store_FPRF( Ity_F128, vT );
+ break;
+ }
+ case 0x1A4: // xsmsubqp (VSX Scalar Multiply Subtract Quad-Precision[using round to Odd])
+ {
+ IRTemp vC = newTemp( Ity_F128 );
+
+ assign( vA, getF128Reg( vA_addr ) );
+ assign( vC, getF128Reg( vT_addr ) );
+
+ if ( R0 == 0 ) {
+ /* rounding mode specified by RN. Issue inst with R0 = 0 */
+ DIP("xsmsubqp v%d,v%d,v%d\n", vT_addr, vA_addr, vB_addr);
+ assign( vT,
+ qop( Iop_MSubF128, rm, mkexpr( vA ),
+ mkexpr( vC ), mkexpr( vB ) ) );
+
+ } else {
+ /* rounding mode specified by Round to odd. Issue inst with R0 = 1 */
+ DIP("xsmsubqpo v%d,v%d,v%d\n", vT_addr, vA_addr, vB_addr);
+ assign( vT,
+ qop( Iop_MSubF128, set_round_to_Oddmode(),
+ mkexpr( vA ), mkexpr( vC ), mkexpr( vB ) ) );
+ }
+ generate_store_FPRF( Ity_F128, vT );
+ break;
+ }
+ case 0x1C4: // xsnmaddqp (VSX Scalar Negative Multiply Add Quad-Precision[using round to Odd])
+ {
+ IRTemp vC = newTemp( Ity_F128 );
+
+ assign( vA, getF128Reg( vA_addr ) );
+ assign( vC, getF128Reg( vT_addr ) );
+
+ if ( R0 == 0 ) {
+ /* rounding mode specified by RN. Issue inst with R0 = 0 */
+ DIP("xsnmaddqp v%d,v%d,v%d\n", vT_addr, vA_addr, vB_addr);
+ assign( vT,
+ qop( Iop_NegMAddF128, rm, mkexpr( vA ),
+ mkexpr( vC ), mkexpr( vB ) ) );
+
+ } else {
+ /* rounding mode specified by Round to odd. Issue inst with R0 = 1 */
+ DIP("xsnmaddqpo v%d,v%d,v%d\n", vT_addr, vA_addr, vB_addr);
+ assign( vT,
+ qop( Iop_NegMAddF128, set_round_to_Oddmode(),
+ mkexpr( vA ), mkexpr( vC ), mkexpr( vB ) ) );
+ }
+ generate_store_FPRF( Ity_F128, vT );
+ break;
+ }
+ case 0x1E4: // xsmsubqp (VSX Scalar Negatve Multiply Subtract Quad-Precision[using round to Odd])
+ {
+ IRTemp vC = newTemp( Ity_F128 );
+
+ assign( vA, getF128Reg( vA_addr ) );
+ assign( vC, getF128Reg( vT_addr ) );
+
+ if ( R0 == 0 ) {
+ /* rounding mode specified by RN. Issue inst with R0 = 0 */
+ DIP("xsnmsubqp v%d,v%d,v%d\n", vT_addr, vA_addr, vB_addr);
+ assign( vT,
+ qop( Iop_NegMSubF128, rm, mkexpr( vA ),
+ mkexpr( vC ), mkexpr( vB ) ) );
+
+ } else {
+ /* rounding mode specified by Round to odd. Issue inst with R0 = 1 */
+ DIP("xsnmsubqpo v%d,v%d,v%d\n", vT_addr, vA_addr, vB_addr);
+ assign( vT,
+ qop( Iop_NegMSubF128, set_round_to_Oddmode(),
+ mkexpr( vA ), mkexpr( vC ), mkexpr( vB ) ) );
+ }
+ generate_store_FPRF( Ity_F128, vT );
+ break;
+ }
+ case 0x204: // xssubqp (VSX Scalar Subtract Quad-Precision[using round to Odd])
+ {
+ assign( vA, getF128Reg( vA_addr ) );
+ if ( R0 == 0 ) {
+ /* use rounding mode specified by RN. Issue inst with R0 = 0 */
+ DIP("xssubqp v%d,v%d,v%d\n", vT_addr, vA_addr, vB_addr);
+ assign( vT, triop( Iop_SubF128, rm, mkexpr( vA ), mkexpr( vB ) ) );
+
+ } else {
+ /* use rounding mode specified by Round to odd. Issue inst with R0 = 1 */
+ DIP("xssubqpo v%d,v%d,v%d\n", vT_addr, vA_addr, vB_addr);
+ assign( vT, triop( Iop_SubF128, set_round_to_Oddmode(), mkexpr( vA ),
+ mkexpr( vB ) ) );
+ }
+ generate_store_FPRF( Ity_F128, vT );
+ break;
+ }
+ case 0x224: // xsdivqp (VSX Scalar Divide Quad-Precision[using round to Odd])
+ {
+ assign( vA, getF128Reg( vA_addr ) );
+ if ( R0 == 0 ) {
+ /* use rounding mode specified by RN. Issue inst with R0 = 0 */
+ DIP("xsdivqp v%d,v%d,v%d\n", vT_addr, vA_addr, vB_addr);
+ assign( vT, triop( Iop_DivF128, rm, mkexpr( vA ), mkexpr( vB ) ) );
+
+ } else {
+ /* use rounding mode specified by Round to odd. Issue inst with R0 = 1 */
+ DIP("xsdivqpo v%d,v%d,v%d\n", vT_addr, vA_addr, vB_addr);
+ assign( vT, triop( Iop_DivF128, set_round_to_Oddmode(), mkexpr( vA ),
+ mkexpr( vB ) ) );
+ }
+ generate_store_FPRF( Ity_F128, vT );
+ break;
+ }
+ case 0x324: // xssqrtqp (VSX Scalar Square root Quad-Precision[using round to Odd])
+ {
+ UInt inst_select = IFIELD( theInstr, 16, 5 );
+
+ switch (inst_select) {
+ case 27:
+ {
+ if ( R0 == 0 ) { // xssqrtqp
+ /* rounding mode specified by RN. Issue inst with R0 = 0 */
+ DIP("xssqrtqp v%d,v%d\n", vT_addr, vB_addr);
+ assign( vT, binop( Iop_SqrtF128, rm, mkexpr( vB ) ) );
+
+ } else { // xssqrtqpo
+ /* rounding mode is Round to odd. Issue inst with R0 = 1 */
+ DIP("xssqrtqpo v%d,v%d\n", vT_addr, vB_addr);
+ assign( vT, binop( Iop_SqrtF128, set_round_to_Oddmode(),
+ mkexpr( vB ) ) );
+ }
+ generate_store_FPRF( Ity_F128, vT );
+ break;
+ } /* end case 27 */
+ default:
+ vex_printf("dis_vx_Floating_Point_Arithmetic_quad_precision(0x324 unknown inst_select)\n");
+ return False;
+ } /* end switch inst_select */
+ break;
+ } /* end case 0x324 */
+
+ case 0x344:
+ {
+ UInt inst_select = IFIELD( theInstr, 16, 5);
+
+ switch (inst_select) {
+ case 1: // xscvqpuwz VSX Scalar Truncate & Convert Quad-Precision
+ // format to Unsigned Word format
+ {
+ DIP("xscvqpuwz v%d,v%d\n", vT_addr, vB_addr);
+ assign( vT, unop( Iop_TruncF128toI32U, mkexpr( vB ) ) );
+ break;
+ }
+ case 2: // xscvudqp VSX Scalar Convert from Unsigned Doubleword
+ // format to Quad-Precision format
+ {
+ IRTemp tmp = newTemp( Ity_I64 );
+
+ DIP("xscvudqp v%d,v%d\n", vT_addr, vB_addr);
+ assign( tmp, unop( Iop_ReinterpF64asI64,
+ unop( Iop_F128HItoF64, mkexpr( vB ) ) ) );
+ assign( vT, unop( Iop_I64UtoF128, mkexpr( tmp ) ) );
+ generate_store_FPRF( Ity_F128, vT );
+ break;
+ }
+ case 9: // xsvqpswz VSX Scalar Truncate & Convert Quad-Precision
+ // format to Signed Word format
+ {
+ DIP("xscvqpswz v%d,v%d\n", vT_addr, vB_addr);
+ assign( vT, unop( Iop_TruncF128toI32S, mkexpr( vB ) ) );
+ break;
+ }
+ case 10: // xscvsdqp VSX Scalar from Signed Doubleword format
+ // Quad-Precision format
+ {
+ IRTemp tmp = newTemp( Ity_I64 );
+
+ DIP("xscvsdqp v%d,v%d\n", vT_addr, vB_addr);
+
+ assign( tmp, unop( Iop_ReinterpF64asI64,
+ unop( Iop_F128HItoF64, mkexpr( vB ) ) ) );
+ assign( vT, unop( Iop_I64StoF128, mkexpr( tmp ) ) );
+ generate_store_FPRF( Ity_F128, vT );
+ break;
+ }
+ case 17: // xsvqpudz VSX Scalar Truncate & Convert Quad-Precision
+ // format to Unigned Doubleword format
+ {
+ DIP("xscvqpudz v%d,v%d\n", vT_addr, vB_addr);
+ assign( vT, unop( Iop_TruncF128toI64U, mkexpr( vB ) ) );
+ break;
+ }
+ case 20: // xscvqpdp Scalar round & Conver Quad-Precision
+ // format to Double-Precision format [using round to Odd]
+ {
+ IRTemp ftmp = newTemp( Ity_F64 );
+ IRTemp tmp = newTemp( Ity_I64 );
+
+ /* This instruction takes a 128-bit floating point value and
+ * converts it to a 64-bit floating point value. The 64-bit
+ * result is stored in the upper 64-bit of the 128-bit result
+ * register. The lower 64-bit are undefined.
+ */
+ if (R0 == 0) { // xscvqpdp
+ /* rounding mode specified by RN. Issue inst with R0 = 0 */
+ DIP("xscvqpdp v%d,v%d\n", vT_addr, vB_addr);
+
+ assign( ftmp, binop( Iop_F128toF64, rm, mkexpr( vB ) ) );
+
+ } else { // xscvqpdpo
+ /* rounding mode is Round to odd. Issue inst with R0 = 1 */
+ DIP("xscvqpdpo v%d,v%d\n", vT_addr, vB_addr);
+ assign( ftmp,
+ binop( Iop_F128toF64,
+ set_round_to_Oddmode(), mkexpr( vB ) ) );
+ }
+
+ /* store 64-bit float in upper 64-bits of 128-bit register,
+ * lower 64-bits are zero.
+ */
+ assign( vT,
+ binop( Iop_F64HLtoF128,
+ mkexpr( ftmp ),
+ unop( Iop_ReinterpI64asF64, mkU64( 0 ) ) ) );
+
+ assign( tmp, unop( Iop_ReinterpF64asI64,
+ unop( Iop_F128HItoF64, mkexpr( vT ) ) ) );
+ generate_store_FPRF( Ity_I64, tmp );
+ break;
+ }
+ case 22: // xscvdpqp VSX Scalar Convert from Double-Precision
+ // format to Quad-Precision format
+ {
+ DIP("xscvdpqp v%d,v%d\n", vT_addr, vB_addr);
+ /* The 64-bit value is in the upper 64 bit of the src */
+ assign( vT, unop( Iop_F64toF128,
+ unop( Iop_F128HItoF64, mkexpr( vB ) ) ) );
+
+ generate_store_FPRF( Ity_F128, vT );
+ break;
+ }
+ case 25: // xsvqpsdz VSX Scalar Truncate & Convert Quad-Precision
+ // format to Signed Doubleword format
+ {
+ DIP("xscvqpsdz v%d,v%d\n", vT_addr, vB_addr);
+ assign( vT, unop( Iop_TruncF128toI64S, mkexpr( vB ) ) );
+ break;
+ }
+ default:
+ vex_printf( "dis_vx_Floating_Point_Arithmetic_quad_precision invalid inst_select (ppc)(opc2)\n" );
+ return False;
+ } /* switch inst_select */
+ } /* end case 0x344 */
+ break;
+ default: /* switch opc2 */
+ vex_printf( "dis_vx_Floating_Point_Arithmetic_quad_precision(ppc)(opc2)\n" );
+ return False;
+ }
+ putF128Reg( vT_addr, mkexpr( vT ) );
+ return True;
+}
+
+
+/* VSX Scalar Quad-Precision instructions */
+static Bool
+dis_vx_scalar_quad_precision ( UInt theInstr )
+{
+ /* This function emulates the 128-bit floating point instructions
+ * using existing 128-bit vector instructions (Iops). The 128-bit
+ * floating point instructions use the same 128-bit vector register
+ * 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 ) );
+
+ if (opc1 != 0x3F) {
+ vex_printf( "dis_vx_scalar_quad_precision(ppc)(instr)\n" );
+ return False;
+ }
+
+ switch (opc2) {
+
+ case 0x064: // xscpsgnqp (VSX Scalar Copy Sign Quad-Precision)
+ {
+ IRTemp sign_vA = newTemp( Ity_I64 );
+ IRTemp vB_hi = newTemp( Ity_I64 );
+
+ DIP("xscpsgnqp v%d,v%d,v%d\n", vT_addr, vA_addr, vB_addr);
+
+ assign( vA, getVSReg(vA_addr) );
+
+ assign( sign_vA, binop( Iop_And64,
+ unop( Iop_V128HIto64,
+ mkexpr( vA ) ),
+ mkU64( 0x8000000000000000ULL ) ) );
+ assign( vB_hi, binop( Iop_Or64,
+ binop( Iop_And64,
+ unop( Iop_V128HIto64,
mkexpr( vB ) ),
mkU64( 0x7FFFFFFFFFFFFFFFULL ) ),
mkexpr( sign_vA ) ) );
IRExpr *bit4, *bit5, *bit6, *bit7;
IRExpr *bit_zero, *bit_inf, *same_sign;
UInt BF = IFIELD( theInstr, 23, 3 );
-
IRTemp eq_lt_gt = newTemp( Ity_I32 );
IRTemp CC = newTemp( Ity_I32 );
mkexpr( vB ) ) ) );
/* test both zero don't care about sign */
- bit_zero = mkAND1( is_Zero_V128( vA ), is_Zero_V128( vB ) );
+ bit_zero = mkAND1( is_Zero( Ity_V128, vA ), is_Zero( Ity_V128, vB ) );
- /* test both infinit don't care about sign */
+ /* test both for infinity, don't care about sign */
bit_inf = mkAND1(
- mkAND1( is_Inf_V128( vA ), is_Inf_V128( vB ) ),
+ mkAND1( is_Inf( Ity_V128, vA ), is_Inf( Ity_V128, vB ) ),
binop( Iop_CmpEQ64,
binop( Iop_And64,
unop( Iop_V128to64,
mkU64( 0x80000000) ) ) );
/* 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_Or32,
+ binop( Iop_Shl32,
+ unop( Iop_1Uto32, bit4 ),
+ mkU8( 3 ) ),
+ binop( Iop_Shl32,
+ unop( Iop_1Uto32, bit5 ),
+ mkU8( 2 ) ) ),
+ binop( Iop_Or32,
+ binop( Iop_Shl32,
+ unop( Iop_1Uto32, bit6 ),
+ mkU8( 1 ) ),
+ binop( Iop_Or32,
+ binop( Iop_Shl32,
+ unop( Iop_1Uto32,
+ bit_zero ),
+ mkU8( 1 ) ),
+ binop( Iop_Shl32,
+ unop( Iop_1Uto32,
+ mkAND1( bit_inf, same_sign ) ),
+ mkU8( 1 ) ) ) ) ) );
- assign( eq_lt_gt, binop( Iop_Or32,
- binop( Iop_Or32,
- binop( Iop_Shl32,
- unop( Iop_1Uto32, bit4 ),
- mkU8( 3) ),
- binop( Iop_Shl32,
- unop( Iop_1Uto32, bit5 ),
- mkU8( 2) ) ),
- binop( Iop_Or32,
- binop( Iop_Shl32,
- unop( Iop_1Uto32, bit6 ),
- mkU8( 1 ) ),
- binop( Iop_Or32,
- binop( Iop_Shl32,
- unop( Iop_1Uto32,
- bit_zero ),
- mkU8( 1 ) ),
- binop( Iop_Shl32,
- unop( Iop_1Uto32,
- mkAND1( bit_inf, same_sign ) ),
- mkU8( 1 ) ) ) ) ) );
assign(CC, binop( Iop_Or32,
binop( Iop_And32,
unop( Iop_Not32,
mkU64( 0x7FFF000000000000 ) ) );
/* 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 ) );
/* NaN over rules the other comparisons */
assign( eq_lt_gt, binop( Iop_Or32,
unop( Iop_1Uto32, bit6 ),
mkU8( 1 ) ) ) ) );
assign(CC, binop( Iop_Or32,
- binop( Iop_And32,
- unop( Iop_Not32,
- unop( Iop_1Sto32, bit7 ) ),
- mkexpr( eq_lt_gt ) ),
- unop( Iop_1Uto32, bit7 ) ) );
+ binop( Iop_And32,
+ unop( Iop_Not32,
+ unop( Iop_1Sto32, bit7 ) ),
+ mkexpr( eq_lt_gt ) ),
+ unop( Iop_1Uto32, bit7 ) ) );
/* put result of the comparison into CC and FPCC */
putGST_field( PPC_GST_CR, mkexpr( CC ), BF );
DIP("xststdcqp %d,v%d,%d\n", BF, vB_addr, DCMX_mask);
- assign( zero, unop( Iop_1Uto64, is_Zero_V128( vB ) ) );
+ assign( zero, unop( Iop_1Uto64, is_Zero( Ity_V128, vB ) ) );
assign( pos, unop( Iop_1Uto64,
binop( Iop_CmpEQ64,
binop( Iop_Shr64,
mkU8( 63 ) ),
mkU64( 0 ) ) ) );
- assign( NaN, unop( Iop_1Uto64, is_NaN_V128( vB ) ) );
- assign( inf, unop( Iop_1Uto64, is_Inf_V128( vB ) ) );
+ assign( NaN, unop( Iop_1Uto64, is_NaN( Ity_V128, vB ) ) );
+ assign( inf, unop( Iop_1Uto64, is_Inf( Ity_V128, vB ) ) );
- assign( dnorm, unop( Iop_1Uto64, is_Denorm_V128( vB ) ) );
+ assign( dnorm, unop( Iop_1Uto64, is_Denorm( Ity_V128, vB ) ) );
assign( DCM, create_DCM( Ity_I64, NaN, inf, zero, dnorm, pos ) );
assign( CC, binop( Iop_Or64,
binop( Iop_And64, /* vB sign bit */
case 0:
DIP("xsabsqp v%d,v%d\n", vT_addr, vB_addr);
assign( vT, binop( Iop_AndV128, mkexpr( vB ),
- binop( Iop_64HLtoV128,
- mkU64( 0x7FFFFFFFFFFFFFFF ),
- mkU64( 0xFFFFFFFFFFFFFFFF ) ) ) );
+ binop( Iop_64HLtoV128,
+ mkU64( 0x7FFFFFFFFFFFFFFF ),
+ mkU64( 0xFFFFFFFFFFFFFFFF ) ) ) );
break;
case 2:
a7 = a6 = a5 = a4 = a3 = a2 = a1 = a0 = IRTemp_INVALID;
b3 = b2 = b1 = b0 = IRTemp_INVALID;
- assign( vA, getVReg(vA_addr));
- assign( vB, getVReg(vB_addr));
+ assign( vA, getVReg( vA_addr ) );
+ assign( vB, getVReg( vB_addr ) );
if (opc1 != 0x4) {
vex_printf("dis_av_arith(ppc)(opc1 != 0x4)\n");
case 0x180: { // vaddcuw (Add Carryout Unsigned Word, AV p136)
DIP("vaddcuw v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
/* unsigned_ov(x+y) = (y >u not(x)) */
- putVReg( vD_addr, binop(Iop_ShrN32x4,
- binop(Iop_CmpGT32Ux4, mkexpr(vB),
- unop(Iop_NotV128, mkexpr(vA))),
- mkU8(31)) );
+ putVReg( vD_addr, binop( Iop_ShrN32x4,
+ binop( Iop_CmpGT32Ux4, mkexpr( vB ),
+ unop( Iop_NotV128, mkexpr( vA ) ) ),
+ mkU8( 31 ) ) );
break;
}
case 0x000: // vaddubm (Add Unsigned Byte Modulo, AV p141)
switch (opc2) {
/* Polynomial Multiply-Add */
- case 0x408: // vpmsumb Vector Polynomial Multipy-sum Byte
+ case 0x408: // vpmsumb Vector Polynomial Multiply-sum Byte
DIP("vpmsumb v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
putVReg( vD_addr, binop(Iop_PolynomialMulAdd8x16,
mkexpr(vA), mkexpr(vB)) );
break;
- case 0x448: // vpmsumd Vector Polynomial Multipy-sum Double Word
+ case 0x448: // vpmsumd Vector Polynomial Multiply-sum Double Word
DIP("vpmsumd v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
putVReg( vD_addr, binop(Iop_PolynomialMulAdd64x2,
mkexpr(vA), mkexpr(vB)) );
break;
- case 0x488: // vpmsumw Vector Polynomial Multipy-sum Word
+ case 0x488: // vpmsumw Vector Polynomial Multiply-sum Word
DIP("vpmsumw v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
putVReg( vD_addr, binop(Iop_PolynomialMulAdd32x4,
mkexpr(vA), mkexpr(vB)) );
break;
- case 0x4C8: // vpmsumh Vector Polynomial Multipy-sum Half Word
+ case 0x4C8: // vpmsumh Vector Polynomial Multiply-sum Half Word
DIP("vpmsumh v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
putVReg( vD_addr, binop(Iop_PolynomialMulAdd16x8,
mkexpr(vA), mkexpr(vB)) );
return True;
}
+/*
+ AltiVec 128 bit integer multiply by 10 Instructions
+*/
+static Bool dis_av_mult10 ( UInt theInstr )
+{
+ /* VX-Form */
+ UChar opc1 = ifieldOPC(theInstr);
+ UChar vT_addr = ifieldRegDS(theInstr);
+ UChar vA_addr = ifieldRegA(theInstr);
+ UChar vB_addr = ifieldRegB(theInstr);
+ UInt opc2 = IFIELD( theInstr, 0, 11 );
+
+ IRTemp vA = newTemp(Ity_V128);
+ assign( vA, getVReg(vA_addr));
+
+ if (opc1 != 0x4) {
+ vex_printf("dis_av_mult10(ppc)(instr)\n");
+ return False;
+ }
+ switch (opc2) {
+ case 0x001: { // vmul10cuq (Vector Multiply-by-10 and write carry
+ DIP("vmul10cuq v%d,v%d\n", vT_addr, vA_addr);
+ putVReg( vT_addr,
+ unop( Iop_MulI128by10Carry, mkexpr( vA ) ) );
+ break;
+ }
+ case 0x041: { // vmul10uq (Vector Multiply-by-10 Extended and write carry
+ // Unsigned Quadword VX form)
+ IRTemp vB = newTemp(Ity_V128);
+ assign( vB, getVReg(vB_addr));
+ DIP("vmul10ecuq v%d,v%d,v%d\n", vT_addr, vA_addr, vB_addr);
+ putVReg( vT_addr,
+ binop( Iop_MulI128by10ECarry, mkexpr( vA ), mkexpr( vB ) ) );
+ break;
+ }
+ case 0x201: { // vmul10uq (Vector Multiply-by-10 Unsigned Quadword VX form)
+ DIP("vmul10uq v%d,v%d\n", vT_addr, vA_addr);
+ putVReg( vT_addr,
+ unop( Iop_MulI128by10, mkexpr( vA ) ) );
+ break;
+ }
+ case 0x241: { // vmul10uq (Vector Multiply-by-10 Extended
+ // Unsigned Quadword VX form)
+ IRTemp vB = newTemp(Ity_V128);
+ assign( vB, getVReg(vB_addr));
+ DIP("vmul10euq v%d,v%d,v%d\n", vT_addr, vA_addr, vB_addr);
+ putVReg( vT_addr,
+ binop( Iop_MulI128by10E, mkexpr( vA ), mkexpr( vB ) ) );
+ break;
+ }
+ default:
+ vex_printf("dis_av_mult10(ppc)(opc2)\n");
+ return False;
+ }
+ return True;
+}
+
/*
AltiVec Pack/Unpack Instructions
*/
mkU64( value_mask_low ) ),
mkexpr( vB ) );
- /* Check if all of the non-sign digits are zero */
- zero = BCDstring_zero( binop( Iop_AndV128,
- binop( Iop_64HLtoV128,
- mkU64( 0xFFFFFFFFFFFFFFFF ),
- mkU64( 0xFFFFFFFFFFFFFFF0 ) ),
- value ) );
- if ( opc2 == 0x101) { // bcdtrunc.
+ if ( opc2 == 0x101 ) { // bcdtrunc.
+ /* Check if all of the non-sign digits are zero */
+ zero = BCDstring_zero( binop( Iop_AndV128,
+ binop( Iop_64HLtoV128,
+ mkU64( 0xFFFFFFFFFFFFFFFF ),
+ mkU64( 0xFFFFFFFFFFFFFFF0 ) ),
+ value ) );
+
/* Sign codes of 0xA, 0xC, 0xE or 0xF are positive, sign
* codes 0xB and 0xD are negative.
*/
/* Pos position AKA gt = 1 if ((not neg) & (not eq zero)) */
pos = mkAND1( mkNOT1( sign ), mkNOT1( zero ) );
- /* if PS = 0
- vB positive, sign is C
- vB negative, sign is D
- if PS = 1
- vB positive, sign is F
- vB negative, sign is D
- Note can't use pos or neg here since they are ANDed with zero,
+ /* Note can't use pos or neg here since they are ANDed with zero,
use sign instead.
*/
if (ps == 0) {
is_BCDstring128( /* Signed */True, mkexpr( vB ) ) );
} else { // bcdutrunc.
+ /* Check if all of the digits are zero */
+ zero = BCDstring_zero( value );
+
/* unsigned value, need to make CC code happy */
neg = mkU1( 0 );
- /* Pos position AKA gt = 1 if ((not neg) & (not eq zero)) */
- pos = mkAND1( mkNOT1( neg ), mkNOT1( zero ) );
+
+ /* Pos position AKA gt = 1 if (not eq zero) */
+ pos = mkNOT1( zero );
valid =
unop( Iop_64to32,
- is_BCDstring128( /* Signed */True, mkexpr( vB ) ) );
+ is_BCDstring128( /* Unsigned */False, mkexpr( vB ) ) );
}
/* If vB is not valid, the result is undefined, but we need to
}
break;
- case 0x181: // bcdctz., bcdctn., bcdcfz., bcdcfn., bcdsetsgn.
+ case 0x181: // bcdctz., bcdctn., bcdcfz., bcdcfn., bcdsetsgn.,
+ // bcdcfsq., bcdctsq.
{
UInt inst_select = IFIELD( theInstr, 16, 5);
switch (inst_select) {
+ case 0: // bcdctsq. (Decimal Convert to Signed Quadword VX-form)
+ {
+ IRExpr *sign;
+
+ /* The instruction takes a 32-bit integer in a vector source
+ * register and returns the signed packed decimal number
+ * in a vector register. The source integer needs to be moved
+ * from the V128 to an I32 for the Iop.
+ */
+
+ DIP("bcdctsq v%d, v%d\n", vRT_addr, vRB_addr);
+
+ putVReg( vRT_addr, unop( Iop_BCD128toI128S, mkexpr( vB ) ) );
+
+ sign = binop( Iop_And64,
+ unop( Iop_V128to64, mkexpr( vB ) ),
+ mkU64( 0xF ) );
+ zero = mkAND1( binop( Iop_CmpEQ64,
+ unop( Iop_V128HIto64, mkexpr( vB ) ),
+ mkU64( 0x0 ) ),
+ binop( Iop_CmpEQ64,
+ binop( Iop_And64,
+ unop( Iop_V128to64, mkexpr( vB ) ),
+ mkU64( 0xFFFFFFF0 ) ),
+ mkU64( 0x0 ) ) );
+ pos = mkAND1( mkNOT1( zero ),
+ mkOR1( mkOR1( binop( Iop_CmpEQ64,
+ sign, mkU64( 0xA ) ),
+ binop( Iop_CmpEQ64,
+ sign, mkU64( 0xC ) ) ),
+ mkOR1( binop( Iop_CmpEQ64,
+ sign, mkU64( 0xE ) ),
+ binop( Iop_CmpEQ64,
+ sign, mkU64( 0xF ) ) ) ) );
+ neg = mkAND1( mkNOT1( zero ),
+ mkOR1( binop( Iop_CmpEQ64, sign, mkU64( 0xB ) ),
+ binop( Iop_CmpEQ64, sign, mkU64( 0xD ) ) ) );
+
+ /* Check each of the nibbles for a valid digit 0 to 9 */
+ valid =
+ unop( Iop_64to32,
+ is_BCDstring128( /* Signed */True, mkexpr( vB ) ) );
+ overflow = mkU1( 0 ); // not used
+ }
+ break;
+
+ case 2: // bcdcfsq. (Decimal Convert from Signed Quadword VX-form)
+ {
+ IRExpr *pos_upper_gt, *pos_upper_eq, *pos_lower_gt;
+ IRExpr *neg_upper_lt, *neg_upper_eq, *neg_lower_lt;
+
+ DIP("bcdcfsq v%d, v%d, %d\n", vRT_addr, vRB_addr, ps);
+
+ /* The instruction takes a signed packed decimal number and
+ * returns the integer value in the vector register. The Iop
+ * returns an I32 which needs to be moved to the destination
+ * vector register.
+ */
+ putVReg( vRT_addr,
+ binop( Iop_I128StoBCD128, mkexpr( vB ), mkU8( ps ) ) );
+
+ zero = mkAND1( binop( Iop_CmpEQ64, mkU64( 0 ),
+ unop( Iop_V128to64, mkexpr( vB ) ) ),
+ binop( Iop_CmpEQ64, mkU64( 0 ),
+ unop( Iop_V128HIto64, mkexpr( vB ) ) ) );
+ pos = mkAND1( mkNOT1 ( zero ),
+ binop( Iop_CmpEQ64, mkU64( 0 ),
+ binop( Iop_And64,
+ unop( Iop_V128HIto64,
+ mkexpr( vB ) ),
+ mkU64( 0x8000000000000000UL ) ) ) );
+ neg = mkAND1( mkNOT1 ( zero ),
+ binop( Iop_CmpEQ64, mkU64( 0x8000000000000000UL ),
+ binop( Iop_And64,
+ unop( Iop_V128HIto64,
+ mkexpr( vB ) ),
+ mkU64( 0x8000000000000000UL ) ) ) );
+
+ /* Overflow occurs if: vB > 10^31-1 OR vB < -10^31-1
+ * do not have a 128 bit compare. Will have to compare the
+ * upper 64 bit and athe lower 64 bits. If the upper 64-bits
+ * are equal then overflow if the lower 64 bits of vB is greater
+ * otherwise if the upper bits of vB is greater then the max
+ * for the upper 64-bits then overflow
+ *
+ * 10^31-1 = 0x7E37BE2022C0914B267FFFFFFF
+ */
+ pos_upper_gt = binop( Iop_CmpLT64U,
+ mkU64( 0x7E37BE2022 ),
+ unop( Iop_V128HIto64, mkexpr( vB ) ) );
+ pos_upper_eq = binop( Iop_CmpEQ64,
+ unop( Iop_V128HIto64, mkexpr( vB ) ),
+ mkU64( 0x7E37BE2022 ) );
+ pos_lower_gt = binop( Iop_CmpLT64U,
+ mkU64( 0x0914B267FFFFFFF ),
+ unop( Iop_V128to64, mkexpr( vB ) ) );
+ /* -10^31-1 = 0X81C841DFDD3F6EB4D97FFFFFFF */
+ neg_upper_lt = binop( Iop_CmpLT64U,
+ mkU64( 0X81C841DFDD ),
+ unop( Iop_V128HIto64, mkexpr( vB ) ) );
+ neg_upper_eq = binop( Iop_CmpEQ64,
+ unop( Iop_V128HIto64, mkexpr( vB ) ),
+ mkU64( 0X81C841DFDD ) );
+ neg_lower_lt = binop( Iop_CmpLT64U,
+ mkU64( 0x3F6EB4D97FFFFFFF ),
+ unop( Iop_V128to64, mkexpr( vB ) ) );
+
+ /* calculate overflow, masking for positive and negative */
+ overflow = mkOR1( mkAND1( pos,
+ mkOR1( pos_upper_gt,
+ mkAND1( pos_upper_eq,
+ pos_lower_gt ) ) ),
+ mkAND1( neg,
+ mkOR1( neg_upper_lt,
+ mkAND1( neg_upper_eq,
+ neg_lower_lt )
+ ) ) );
+ valid = mkU32( 1 );
+ }
+ break;
+
case 4: // bcdctz. (Decimal Convert to Zoned VX-form)
{
IRExpr *ox_flag, *sign, *vrb_nibble30;
{ 0x3ac, "xvcmpgtdp." },
{ 0x3b0, "xvcvdpsxds" },
{ 0x3b2, "xvabsdp" },
- { 0x3b6, "xxbr[h|w|d|q]|xvxexpdp|xvxexpsp|xvxsigdp|xvxsigsp" },
+ { 0x3b6, "xxbr[h|w|d|q]|xvxexpdp|xvxexpsp|xvxsigdp|xvxsigsp|xvcvhpsp|xvcvsphp|xscvdphp|xscvhpdp" },
{ 0x3c0, "xvcpsgndp" },
{ 0x3c4, "xvnmsubadp" },
{ 0x3cc, "xvcmpgedp." },
UInt vsxOpc2 = get_VSX60_opc2(opc2);
if (( opc2hi == 13 ) && ( opc2lo == 5)) { //xvtstdcsp
- if (dis_vxs_misc(theInstr, 0x354))
+ if (dis_vxs_misc(theInstr, 0x354, allow_isa_3_0))
goto decode_success;
goto decode_failure;
}
if (( opc2hi == 15 ) && ( opc2lo == 5)) { //xvtstdcdp
- if (dis_vxs_misc(theInstr, 0x3D4))
+ if (dis_vxs_misc(theInstr, 0x3D4, allow_isa_3_0))
goto decode_success;
goto decode_failure;
}
/* This is a special case of the XX1 form where the RA, RB
* fields hold an immediate value.
*/
- if (dis_vxs_misc(theInstr, opc2)) goto decode_success;
+ if (dis_vxs_misc(theInstr, opc2, allow_isa_3_0)) goto decode_success;
goto decode_failure;
}
case 0x0D6: case 0x0B2: // xsrdpic, xsrdpiz
case 0x092: case 0x232: // xsrdpi, xsrsp
case 0x3B6: // xxbrh, xvxexpdp, xvxexpsp, xvxsigdp
- // xvxsigsp
+ // xvxsigsp, xvcvhpsp
case 0x2b6: // xsxexpdp, xsxsigdp
case 0x254: case 0x2d4: // xststdcsp, xststdcdp
case 0x354: // xvtstdcsp
case 0x360:case 0x396: // xviexpsp, xsiexpdp
case 0x3D4: case 0x3E0: // xvtstdcdp, xviexpdp
- if (dis_vxs_misc(theInstr, vsxOpc2)) goto decode_success;
+ if (dis_vxs_misc(theInstr, vsxOpc2, allow_isa_3_0))
+ goto decode_success;
goto decode_failure;
case 0x08C: case 0x0AC: // xscmpudp, xscmpodp
if (dis_vx_cmp(theInstr, vsxOpc2)) goto decode_success;
break; // Fall through
}
+ opc2 = IFIELD(theInstr, 1, 8);
+ switch (opc2) {
+ case 0x5: // xsrqpi, xsrqpix
+ case 0x25: // xsrqpxp
+ if ( !mode64 || !allow_isa_3_0 ) goto decode_failure;
+ if ( dis_vx_Scalar_Round_to_quad_integer( theInstr ) )
+ goto decode_success;
+ goto decode_failure;
+ default:
+ break; // Fall through
+ }
+
opc2 = IFIELD(theInstr, 1, 10);
+ UInt inst_select = IFIELD( theInstr, 16, 5 );
+
switch (opc2) {
/* 128-bit DFP instructions */
case 0x2: // daddq - DFP Add
if (dis_fp_scr( theInstr, allow_GX )) goto decode_success;
goto decode_failure;
- /* VSX Scalar Quad-Precision instructions */
+ case 0x324: // xsabsqp, xsxexpqp,xsnabsqp, xsnegqp, xsxsigqp
+ if ( inst_select == 27 ) { // xssqrtqp
+ if ( dis_vx_Floating_Point_Arithmetic_quad_precision( theInstr ) )
+ goto decode_success;
+ }
+
+ /* Instructions implemented with Pre ISA 3.0 Iops */
+ /* VSX Scalar Quad-Precision instructions */
case 0x064: // xscpsgnqp
case 0x0A4: // xscmpexpqp
case 0x084: // xscmpoqp
case 0x284: // xscmpuqp
case 0x2C4: // xststdcqp
- case 0x324: // xsabsqp, xsxexpqp,xsnabsqp, xsnegqp, xsxsigqp
case 0x364: // xsiexpqp
if (dis_vx_scalar_quad_precision( theInstr )) goto decode_success;
goto decode_failure;
+ /* Instructions implemented using ISA 3.0 instructions */
+ // xsaddqpo (VSX Scalar Add Quad-Precision [using round to ODD]
+ case 0x004: // xsaddqp (VSX Scalar Add Quad-Precision [using RN mode]
+ // xsmulqpo (VSX Scalar Multiply Quad-Precision [using round to ODD]
+ case 0x024: // xsmulqp (VSX Scalar Multiply Quad-Precision [using RN mode]
+ // xsmaddqpo (VSX Scalar Multiply Add Quad-Precision [using round to ODD]
+ case 0x184: // xsmaddqp (VSX Scalar Multiply Add Quad-Precision [using RN mode]
+ // xsmsubqpo (VSX Scalar Multiply Sub Quad-Precision [using round to ODD]
+ case 0x1A4: // xsmsubqp (VSX Scalar Multiply Sub Quad-Precision [using RN mode]
+ // xsnmaddqpo (VSX Scalar Negative Multiply Add Quad-Precision [using round to ODD]
+ case 0x1C4: // xsnmaddqp (VSX Scalar Negative Multiply Add Quad-Precision [using RN mode]
+ // xsnmsubqpo (VSX Scalar Negative Multiply Sub Quad-Precision [using round to ODD]
+ case 0x1E4: // xsnmsubqp (VSX Scalar Negative Multiply Sub Quad-Precision [usin RN mode]
+ // xssubqpo (VSX Scalar Subrtact Quad-Precision [using round to ODD]
+ case 0x204: // xssubqp (VSX Scalar Subrtact Quad-Precision [using RN mode]
+ // xsdivqpo (VSX Scalar Divde Quad-Precision [using round to ODD]
+ case 0x224: // xsdivqp (VSX Scalar Divde Quad-Precision [using RN mode]
+ case 0x344: // xscvudqp, xscvsdqp, xscvqpdp, xscvqpdpo, xsvqpdp
+ // xscvqpswz, xscvqpuwz, xscvqpudz, xscvqpsdz
+ if ( !mode64 || !allow_isa_3_0 ) goto decode_failure;
+ if ( dis_vx_Floating_Point_Arithmetic_quad_precision( theInstr ) )
+ goto decode_success;
+ goto decode_failure;
+
default:
break; // Fall through...
}
case 0x10B: case 0x30B: // moduw, modsw
case 0x109: case 0x309: // modsd, modud
+ case 0x21A: case 0x23A: // cnttzw, cnttzd
if (dis_modulo_int( theInstr )) goto decode_success;
goto decode_failure;
}
opc2 = IFIELD(theInstr, 0, 9);
- switch (opc2) {
- /* BCD arithmetic */
- case 0x001: case 0x041: // bcdadd, bcdsub
- case 0x101: case 0x141: // bcdtrunc., bcdutrunc.
- case 0x081: case 0x0C1: case 0x1C1: // bcdus., bcds., bcdsr.
- case 0x181: // bcdcfn., bcdcfz.
-
- /* These instructions must have bit 21 set to 1 for a correct
- * opcode match.
+ if (IFIELD(theInstr, 10, 1) == 1) {
+ /* The following instructions have bit 21 set and a PS bit (bit 22)
+ * Bit 21 distinquishes them from instructions with an 11 bit opc2
+ * field.
*/
- if ((theInstr & 0x400) != 0x400)
- break; /* keep looking */
-
- if (!allow_isa_2_07) goto decode_noP8;
- if (dis_av_bcd( theInstr )) goto decode_success;
- goto decode_failure;
-
- if (!allow_isa_2_07) goto decode_noP8;
- if (dis_av_bcd( theInstr )) goto decode_success;
- goto decode_failure;
-
- default:
- break; // Fall through...
+ switch (opc2) {
+ /* BCD arithmetic */
+ case 0x001: case 0x041: // bcdadd, bcdsub
+ case 0x101: case 0x141: // bcdtrunc., bcdutrunc.
+ case 0x081: case 0x0C1: case 0x1C1: // bcdus., bcds., bcdsr.
+ case 0x181: // bcdcfn., bcdcfz.
+ // bcdctz., bcdcfsq., bcdctsq.
+ if (!allow_isa_2_07) goto decode_noP8;
+ if (dis_av_bcd( theInstr )) goto decode_success;
+ goto decode_failure;
+ default:
+ break; // Fall through...
+ }
}
opc2 = IFIELD(theInstr, 0, 11);
if (dis_av_permute( theInstr )) goto decode_success;
goto decode_failure;
+ /* AltiVec 128 bit integer multiply by 10 Instructions */
+ case 0x201: case 0x001: //vmul10uq, vmul10cuq
+ case 0x241: case 0x041: //vmul10euq, vmul10ceuq
+ if (!allow_V) goto decode_noV;
+ if (!allow_isa_3_0) goto decode_noP9;
+ if (dis_av_mult10( theInstr )) goto decode_success;
+ goto decode_failure;
+
/* AV Pack, Unpack */
case 0x00E: case 0x04E: case 0x08E: // vpkuhum, vpkuwum, vpkuhus
case 0x0CE: // vpkuwus
theInstr);
goto not_supported;
+ decode_noP9:
+ vassert(!allow_isa_3_0);
+ vex_printf("disInstr(ppc): found the Power 9 instruction 0x%x that can't be handled\n"
+ "by Valgrind on this host. This instruction requires a host that\n"
+ "supports Power 9 instructions.\n",
+ theInstr);
+ goto not_supported;
decode_failure:
/* All decode failures end up here. */
case Pun_NEG: return "neg";
case Pun_CLZ32: return "cntlzw";
case Pun_CLZ64: return "cntlzd";
+ case Pun_CTZ32: return "cnttzw";
+ case Pun_CTZ64: return "cnttzd";
case Pun_EXTSW: return "extsw";
default: vpanic("showPPCUnaryOp");
}
case Pfp_FRIN: return "frin";
case Pfp_FRIP: return "frip";
case Pfp_FRIZ: return "friz";
+ case Pfp_FPADDQ: return "xsaddqp";
+ case Pfp_FPSUBQ: return "xsubqp";
+ case Pfp_FPMULQ: return "xsmulqp";
+ case Pfp_FPDIVQ: return "xsdivqp";
+ case Pfp_FPMULADDQ: return "xsmaddqp";
+ case Pfp_FPMULSUBQ: return "xsmsubqp";
+ case Pfp_FPNEGMULADDQ: return "xsnmaddqp";
+ case Pfp_FPNEGMULSUBQ: return "xsnmsubqp";
+ case Pfp_FPADDQRNDODD: return "xsaddqpo";
+ case Pfp_FPSUBQRNDODD: return "xsubqpo";
+ case Pfp_FPMULQRNDODD: return "xsmulqpo";
+ case Pfp_FPDIVQRNDODD: return "xsaddqpo";
+ case Pfp_FPMULADDQRNDODD: return "xsmaddqpo";
+ case Pfp_FPMULSUBQRNDODD: return "xsmsubqpo";
+ case Pfp_FPNEGMULADDQRNDODD: return "xsnmaddqpo";
+ case Pfp_FPNEGMULSUBQRNDODD: return "xsnmsubqpo";
+ case Pfp_FPQTOD: return "xscvqpdp";
+ case Pfp_FPQTODRNDODD: return "xscvqpdpo";
+ case Pfp_FPDTOQ: return "xscvdpqp";
+ case Pfp_IDSTOQ: return "xscvsdqp";
+ case Pfp_IDUTOQ: return "xscvudqp";
+ case Pfp_TRUNCFPQTOISD: return "xscvqpsdz";
+ case Pfp_TRUNCFPQTOISW: return "xscvqpswz";
+ case Pfp_TRUNCFPQTOIUD: return "xscvqpudz";
+ case Pfp_TRUNCFPQTOIUW: return "xscvqpuwz";
case Pfp_DFPADD: return "dadd";
case Pfp_DFPADDQ: return "daddq";
case Pfp_DFPSUB: return "dsub";
/* BCD */
case Pav_BCDAdd: return "bcdadd."; // qw
case Pav_BCDSub: return "bcdsub."; // qw
+ case Pav_I128StoBCD128: return "bcdcfsq."; //qw
+ case Pav_BCD128toI128S: return "bcdctsq."; //qw
+
+ /* I128 mult by 10 */
+ case Pav_MulI128by10: return "vmul10uq"; //qw
+ case Pav_MulI128by10Carry: return "vmul10cuq"; //qw
+ case Pav_MulI128by10E: return "vmul10euq"; //qw
+ case Pav_MulI128by10ECarry: return "vmul10ecuq"; //qw
+
+ /* F128 to I128 signed */
+ case Pav_F128toI128S: return "xsrqpi|x"; //qw
+
+ /* F128 round to F128 */
+ case Pav_ROUNDFPQ: return "xsrqpxp";
/* Polynomial arith */
case Pav_POLYMULADD: return "vpmsum"; // b, h, w, d
case Pav_ZEROCNTHALF: case Pav_ZEROCNTDBL:
return "vclz_"; // b, h, w, d
+ /* trailing zero count */
+ case Pav_TRAILINGZEROCNTBYTE: case Pav_TRAILINGZEROCNTWORD:
+ case Pav_TRAILINGZEROCNTHALF: case Pav_TRAILINGZEROCNTDBL:
+ return "vctz_"; // b, h, w, d
+
/* vector gather (byte-by-byte bit matrix transpose) */
case Pav_BITMTXXPOSE:
return "vgbbd";
+ /* Vector Half-precision format to single precision conversion */
+ case Pav_F16toF32x4:
+ return"xvcvhpsp";
+
+ /* Vector Single-precision format to Half-precision conversion */
+ case Pav_F32toF16x4:
+ return"xvcvsphp";
+
+ /* Vector Half-precision format to Double precision conversion */
+ case Pav_F16toF64x2:
+ return"xvcvhpdp";
+
+ /* Vector Half-precision format to Double precision conversion */
+ case Pav_F64toF16x2:
+ return"xvcvdphp";
+
default: vpanic("showPPCAvOp");
}
}
i->Pin.FpBinary.srcR = srcR;
return i;
}
+PPCInstr* PPCInstr_Fp128Unary(PPCFpOp op, HReg dst, HReg src) {
+ PPCInstr* i = LibVEX_Alloc_inline( sizeof(PPCInstr) );
+ i->tag = Pin_Fp128Unary;
+ i->Pin.Fp128Unary.op = op;
+ i->Pin.Fp128Unary.dst = dst;
+ i->Pin.Fp128Unary.src = src;
+ return i;
+}
+PPCInstr* PPCInstr_Fp128Binary(PPCFpOp op, HReg dst, HReg srcL, HReg srcR) {
+ PPCInstr* i = LibVEX_Alloc_inline( sizeof(PPCInstr) );
+ i->tag = Pin_Fp128Binary;
+ i->Pin.Fp128Binary.op = op;
+ i->Pin.Fp128Binary.dst = dst;
+ i->Pin.Fp128Binary.srcL = srcL;
+ i->Pin.Fp128Binary.srcR = srcR;
+ return i;
+}
+PPCInstr* PPCInstr_Fp128Trinary(PPCFpOp op, HReg dst, HReg srcL, HReg srcR) {
+ PPCInstr* i = LibVEX_Alloc_inline( sizeof(PPCInstr) );
+ i->tag = Pin_Fp128Trinary;
+ i->Pin.Fp128Trinary.op = op;
+ i->Pin.Fp128Trinary.dst = dst;
+ i->Pin.Fp128Trinary.srcL = srcL;
+ i->Pin.Fp128Trinary.srcR = srcR;
+ return i;
+}
PPCInstr* PPCInstr_FpMulAcc ( PPCFpOp op, HReg dst, HReg srcML,
HReg srcMR, HReg srcAcc )
{
i->Pin.AvBinary.srcR = srcR;
return i;
}
+PPCInstr* PPCInstr_AvBinaryInt ( PPCAvOp op, HReg dst,
+ HReg src, PPCRI* val ) {
+ PPCInstr* i = LibVEX_Alloc_inline(sizeof(PPCInstr));
+ i->tag = Pin_AvBinaryInt;
+ i->Pin.AvBinaryInt.op = op;
+ i->Pin.AvBinaryInt.dst = dst;
+ i->Pin.AvBinaryInt.src = src;
+ i->Pin.AvBinaryInt.val = val;
+ return i;
+}
PPCInstr* PPCInstr_AvBin8x16 ( PPCAvOp op, HReg dst,
HReg srcL, HReg srcR ) {
PPCInstr* i = LibVEX_Alloc_inline(sizeof(PPCInstr));
vex_printf(",");
ppHRegPPC(i->Pin.FpBinary.srcR);
return;
+ case Pin_Fp128Unary:
+ vex_printf("%s ", showPPCFpOp(i->Pin.Fp128Unary.op));
+ ppHRegPPC(i->Pin.Fp128Unary.dst);
+ vex_printf(",");
+ ppHRegPPC(i->Pin.Fp128Unary.src);
+ return;
+ case Pin_Fp128Binary:
+ vex_printf("%s ", showPPCFpOp(i->Pin.Fp128Binary.op));
+ ppHRegPPC(i->Pin.Fp128Binary.dst);
+ vex_printf(",");
+ ppHRegPPC(i->Pin.Fp128Binary.srcL);
+ vex_printf(",");
+ ppHRegPPC(i->Pin.Fp128Binary.srcR);
+ return;
+ case Pin_Fp128Trinary:
+ vex_printf("%s ", showPPCFpOp(i->Pin.Fp128Trinary.op));
+ ppHRegPPC(i->Pin.Fp128Trinary.dst);
+ vex_printf(",");
+ ppHRegPPC(i->Pin.Fp128Trinary.srcL);
+ vex_printf(",");
+ ppHRegPPC(i->Pin.Fp128Trinary.srcR);
+ return;
case Pin_FpMulAcc:
vex_printf("%s ", showPPCFpOp(i->Pin.FpMulAcc.op));
ppHRegPPC(i->Pin.FpMulAcc.dst);
vex_printf(",");
ppHRegPPC(i->Pin.AvBinary.srcR);
return;
+ case Pin_AvBinaryInt:
+ vex_printf("%s ", showPPCAvOp(i->Pin.AvBinaryInt.op));
+ ppHRegPPC(i->Pin.AvBinaryInt.dst);
+ vex_printf(",");
+ ppHRegPPC(i->Pin.AvBinaryInt.src);
+ vex_printf(",");
+ ppPPCRI(i->Pin.AvBinaryInt.val);
+ return;
case Pin_AvBin8x16:
vex_printf("%s(b) ", showPPCAvOp(i->Pin.AvBin8x16.op));
ppHRegPPC(i->Pin.AvBin8x16.dst);
addHRegUse(u, HRmRead, i->Pin.FpBinary.srcL);
addHRegUse(u, HRmRead, i->Pin.FpBinary.srcR);
return;
+
+ case Pin_Fp128Unary:
+ addHRegUse(u, HRmWrite, i->Pin.Fp128Unary.dst);
+ addHRegUse(u, HRmRead, i->Pin.Fp128Unary.src);
+ return;
+ case Pin_Fp128Binary:
+ addHRegUse(u, HRmWrite, i->Pin.Fp128Binary.dst);
+ addHRegUse(u, HRmRead, i->Pin.Fp128Binary.srcL);
+ addHRegUse(u, HRmRead, i->Pin.Fp128Binary.srcR);
+ return;
+ case Pin_Fp128Trinary:
+ addHRegUse(u, HRmModify, i->Pin.Fp128Trinary.dst);
+ addHRegUse(u, HRmRead, i->Pin.Fp128Trinary.srcL);
+ addHRegUse(u, HRmRead, i->Pin.Fp128Trinary.srcR);
+ return;
case Pin_FpMulAcc:
addHRegUse(u, HRmWrite, i->Pin.FpMulAcc.dst);
addHRegUse(u, HRmRead, i->Pin.FpMulAcc.srcML);
addHRegUse(u, HRmRead, i->Pin.AvBinary.srcR);
}
return;
+ case Pin_AvBinaryInt:
+ addHRegUse(u, HRmWrite, i->Pin.AvBinaryInt.dst);
+ addHRegUse(u, HRmRead, i->Pin.AvBinaryInt.src);
+ return;
case Pin_AvBin8x16:
addHRegUse(u, HRmWrite, i->Pin.AvBin8x16.dst);
addHRegUse(u, HRmRead, i->Pin.AvBin8x16.srcL);
mapReg(m, &i->Pin.FpBinary.srcL);
mapReg(m, &i->Pin.FpBinary.srcR);
return;
+ case Pin_Fp128Unary:
+ mapReg(m, &i->Pin.Fp128Unary.dst);
+ mapReg(m, &i->Pin.Fp128Unary.src);
+ return;
+ case Pin_Fp128Binary:
+ mapReg(m, &i->Pin.Fp128Binary.dst);
+ mapReg(m, &i->Pin.Fp128Binary.srcL);
+ mapReg(m, &i->Pin.Fp128Binary.srcR);
+ return;
+ case Pin_Fp128Trinary:
+ mapReg(m, &i->Pin.Fp128Trinary.dst);
+ mapReg(m, &i->Pin.Fp128Trinary.srcL);
+ mapReg(m, &i->Pin.Fp128Trinary.srcR);
+ return;
case Pin_FpMulAcc:
mapReg(m, &i->Pin.FpMulAcc.dst);
mapReg(m, &i->Pin.FpMulAcc.srcML);
mapReg(m, &i->Pin.AvBinary.srcL);
mapReg(m, &i->Pin.AvBinary.srcR);
return;
+ case Pin_AvBinaryInt:
+ mapReg(m, &i->Pin.AvBinaryInt.dst);
+ mapReg(m, &i->Pin.AvBinaryInt.src);
+ return;
case Pin_AvBin8x16:
mapReg(m, &i->Pin.AvBin8x16.dst);
mapReg(m, &i->Pin.AvBin8x16.srcL);
return emit32(p, theInstr, endness_host);
}
+static UChar* mkFormVSXRND ( UChar* p, UInt opc1, UInt R, UInt r1,
+ UInt r2, UInt RMC, UInt opc2, UChar EX,
+ VexEndness endness_host )
+{
+ /* The register mapping is all done using VR register numbers for the
+ * V128 support. This means that the operands for this instruction have
+ * been loaded into a VR register. The 32 VR registers map to VSR registers
+ * 32 to 63. For these instructions, the hardware adds 32 to the source
+ * and destination register numbers. Do not need to adjust the register
+ * numbers for these instructions.
+ */
+
+ UInt theInstr;
+
+ vassert(opc1 < 0x40);
+ vassert(r1 < 0x20);
+ vassert(r2 < 0x20);
+ vassert(opc2 < 0x100);
+ vassert(EX < 0x2);
+ vassert(R < 0x2);
+ vassert(RMC < 0x4);
+
+ theInstr = ((opc1<<26) | (r1<<21) | (R<<16) | (r2<<11) | (RMC<<9) |
+ (opc2 << 1) | EX);
+ return emit32(p, theInstr, endness_host);
+}
+
+static UChar* mkFormVX_BX_TX ( UChar* p, UInt opc1, UInt r1, UInt r2,
+ UInt r3, UInt opc2, VexEndness endness_host )
+{
+ /* The register mapping is all done using VR register numbers for the
+ * V128 support. This means that the operands for this instruction have
+ * been loaded into a VR register. The 32 VR registers map to VSR registers
+ * 32 to 63. So to make the issued instruction reference the
+ * corresponding VR register we have to add 32 to the source and
+ * destination operand numbers, then load the new operand number into the
+ * correct bit fields.
+ *
+ * r1 = 32xTX + T; r3 = 32xBX + B;
+ * TX is bit 0, BX is bit 1, T is in bits [25:21], B is in bit [14:11]
+ * opc2 is in bits [10:2]
+ */
+ UInt T, TX, B, BX;
+
+ UInt theInstr;
+
+ r1 += 32; // adjust the VSR register number to map to the VR number
+ r3 += 32;
+
+ vassert(opc1 < 0x40);
+ vassert(r1 < 0x40);
+ vassert(r2 < 0x20);
+ vassert(r3 < 0x40);
+ vassert(opc2 < 0x800);
+
+ T = r1 & 0x1F;
+ TX = r1 >> 5;
+ B = r3 & 0x1F;
+ BX = r3 >> 5;
+ theInstr = ((opc1<<26) | (T<<21) | (r2<<16) | (B<<11) | (opc2<<2)
+ | (BX<<1) | TX);
+ return emit32(p, theInstr, endness_host);
+}
+
+static UChar* mkFormVXR0 ( UChar* p, UInt opc1, UInt r1, UInt r2,
+ UInt r3, UInt opc2, UChar R0,
+ VexEndness endness_host )
+{
+ /* The register mapping is all done using VR register numbers for the
+ * V128 support. This means that the operands for this instruction have
+ * been loaded into a VR register. The 32 VR registers map to VSR registers
+ * 32 to 63. For these instructions, the hardware adds 32 to the source
+ * and destination register numbers. Do not need to adjust the register
+ * numbers for these instructions.
+ */
+
+ UInt theInstr;
+
+ vassert(opc1 < 0x40);
+ vassert(r1 < 0x20); // register numbers are between 0 and 31 (5-bits)
+ vassert(r2 < 0x20);
+ vassert(r3 < 0x20);
+ vassert(opc2 < 0x800);
+ vassert(R0 < 0x2);
+
+ theInstr = ((opc1<<26) | (r1<<21) | (r2<<16) | (r3<<11) | (opc2<<1) | R0);
+ return emit32(p, theInstr, endness_host);
+}
+
static UChar* mkFormVXI ( UChar* p, UInt opc1, UInt r1, UInt r2,
UInt r3, UInt opc2, VexEndness endness_host )
{
vassert(mode64);
p = mkFormX(p, 31, r_src, r_dst, 0, 58, 0, endness_host);
break;
+ case Pun_CTZ32: // cnttzw r_dst, r_src
+ /* Note oder of src and dst is backwards from normal */
+ p = mkFormX(p, 31, r_src, r_dst, 0, 538, 0, endness_host);
+ break;
+ case Pun_CTZ64: // cnttzd r_dst, r_src
+ /* Note oder of src and dst is backwards from normal */
+ vassert(mode64);
+ p = mkFormX(p, 31, r_src, r_dst, 0, 570, 0, endness_host);
+ break;
case Pun_EXTSW: // extsw r_dst, r_src
vassert(mode64);
p = mkFormX(p, 31, r_src, r_dst, 0, 986, 0, endness_host);
goto done;
}
+ case Pin_Fp128Unary: {
+ /* Note Fp128 instructions use the vector scalar registers. The register
+ * mapping for the V128 type assumes the a vector instruction. The
+ * PPC hardware has a single register file that the vector scalar
+ * registers and the vector registers map to. The 32 vector
+ * registers instructions map to the same registers as the vector
+ * scalar registers 32 to 63. mkFormVXR0 does the needed
+ * adjustment.
+ */
+ UInt fr_dst = vregEnc(i->Pin.Fp128Unary.dst);
+ UInt fr_src = vregEnc(i->Pin.Fp128Unary.src);
+
+ switch (i->Pin.Fp128Unary.op) {
+ case Pfp_FPSQRTQ: // xssqrtqp, use rounding specified by RN
+ p = mkFormVXR0( p, 63, fr_dst, 27, fr_src, 804, 0, endness_host );
+ break;
+ case Pfp_FPSQRTQRNDODD: // xssqrtqpo, use rounding specified by RN
+ p = mkFormVXR0( p, 63, fr_dst, 27, fr_src, 804, 1, endness_host );
+ break;
+ case Pfp_FPQTOD: // xscvqpdp, use rounding specified by RN
+ p = mkFormVXR0( p, 63, fr_dst, 20, fr_src, 836, 0, endness_host );
+ break;
+ case Pfp_FPQTODRNDODD: // xscvqpdpo, use rounding specified by RN
+ p = mkFormVXR0( p, 63, fr_dst, 20, fr_src, 836, 1, endness_host );
+ break;
+ case Pfp_FPDTOQ: // xscvdpqp
+ p = mkFormVXR0( p, 63, fr_dst, 22, fr_src, 836, 0, endness_host );
+ break;
+ case Pfp_IDSTOQ: // xscvsdqp
+ p = mkFormVXR0( p, 63, fr_dst, 10, fr_src, 836, 0, endness_host );
+ break;
+ case Pfp_IDUTOQ: // xscvudqp
+ p = mkFormVXR0( p, 63, fr_dst, 2, fr_src, 836, 0, endness_host );
+ break;
+ case Pfp_TRUNCFPQTOISD: // xscvqpsdz
+ p = mkFormVXR0( p, 63, fr_dst, 25, fr_src, 836, 0, endness_host );
+ break;
+ case Pfp_TRUNCFPQTOISW: // xscvqpswz
+ p = mkFormVXR0( p, 63, fr_dst, 9, fr_src, 836, 0, endness_host );
+ break;
+ case Pfp_TRUNCFPQTOIUD: // xscvqpudz
+ p = mkFormVXR0( p, 63, fr_dst, 17, fr_src, 836, 0, endness_host );
+ break;
+ case Pfp_TRUNCFPQTOIUW: // xscvqpuwz
+ p = mkFormVXR0( p, 63, fr_dst, 1, fr_src, 836, 0, endness_host );
+ break;
+ default:
+ goto bad;
+ }
+ goto done;
+ }
+
+ case Pin_Fp128Binary: {
+ /* Note Fp128 instructions use the vector registers */
+ UInt fr_dst = vregEnc(i->Pin.Fp128Binary.dst);
+ UInt fr_srcL = vregEnc(i->Pin.Fp128Binary.srcL);
+ UInt fr_srcR = vregEnc(i->Pin.Fp128Binary.srcR);
+
+ /* Note this issues a Vector scalar instruction. The register
+ * mapping for the V128 type assumes the a vector instruction. The
+ * PPC hardware has a single register file that the vector scalar
+ * registers and the vector registers map to. The 32 vector
+ * registers instructions map to the same registers as the vector
+ * scalar registers 32 to 63. For these instructions the HW adds
+ * 32 to the register numbers to access the VSRR register. No need
+ * to adjust the numbers to map to the VR register that contians the
+ * operands.
+ */
+
+ switch (i->Pin.Fp128Binary.op) {
+ case Pfp_FPADDQ: // xsaddqp, use rounding specified by RN
+ p = mkFormVXR0( p, 63, fr_dst, fr_srcL, fr_srcR, 4, 0, endness_host );
+ break;
+ case Pfp_FPADDQRNDODD: // xsaddqpo, round to odd
+ p = mkFormVXR0( p, 63, fr_dst, fr_srcL, fr_srcR, 4, 1, endness_host );
+ break;
+ case Pfp_FPSUBQ: // xssubqp, use rounding specified by RN
+ p = mkFormVXR0( p, 63, fr_dst, fr_srcL, fr_srcR, 516, 0, endness_host );
+ break;
+ case Pfp_FPSUBQRNDODD: // xssubqpo, round to odd
+ p = mkFormVXR0( p, 63, fr_dst, fr_srcL, fr_srcR, 516, 1, endness_host );
+ break;
+ case Pfp_FPMULQ: // xsmulqp, use rounding specified by RN
+ p = mkFormVXR0( p, 63, fr_dst, fr_srcL, fr_srcR, 36, 0, endness_host );
+ break;
+ case Pfp_FPMULQRNDODD: // xsmulqpo, round to odd
+ p = mkFormVXR0( p, 63, fr_dst, fr_srcL, fr_srcR, 36, 1, endness_host );
+ break;
+ case Pfp_FPDIVQ: // xsdivqp, use rounding specified by RN
+ p = mkFormVXR0( p, 63, fr_dst, fr_srcL, fr_srcR, 548, 0, endness_host );
+ break;
+ case Pfp_FPDIVQRNDODD: // xsdivqpo, round to odd
+ p = mkFormVXR0( p, 63, fr_dst, fr_srcL, fr_srcR, 548, 1, endness_host );
+ break;
+ case Pfp_FPMULADDQ: // xsmaddqp, use rounding specified by RN
+ p = mkFormVXR0( p, 63, fr_dst, fr_srcL, fr_srcR, 388, 0, endness_host );
+ break;
+ case Pfp_FPMULADDQRNDODD: // xsmaddqpo, round to odd
+ p = mkFormVXR0( p, 63, fr_dst, fr_srcL, fr_srcR, 388, 1, endness_host );
+ break;
+ case Pfp_FPMULSUBQ: // xsmsubqp, use rounding specified by RN
+ p = mkFormVXR0( p, 63, fr_dst, fr_srcL, fr_srcR, 420, 0, endness_host );
+ break;
+ case Pfp_FPMULSUBQRNDODD: // xsmsubsqpo, round to odd
+ p = mkFormVXR0( p, 63, fr_dst, fr_srcL, fr_srcR, 420, 1, endness_host );
+ break;
+ case Pfp_FPNEGMULADDQ: // xsnmaddqp, use rounding specified by RN
+ p = mkFormVXR0( p, 63, fr_dst, fr_srcL, fr_srcR, 452, 0, endness_host );
+ break;
+ case Pfp_FPNEGMULADDQRNDODD: // xsnmaddqpo, round to odd
+ p = mkFormVXR0( p, 63, fr_dst, fr_srcL, fr_srcR, 452, 1, endness_host );
+ break;
+ case Pfp_FPNEGMULSUBQ: // xsnmsubqp, use rounding specified by RN
+ p = mkFormVXR0( p, 63, fr_dst, fr_srcL, fr_srcR, 484, 0, endness_host );
+ break;
+ case Pfp_FPNEGMULSUBQRNDODD: // xsnmsubsqpo, round to odd
+ p = mkFormVXR0( p, 63, fr_dst, fr_srcL, fr_srcR, 484, 1, endness_host );
+ break;
+ default:
+ goto bad;
+ }
+ goto done;
+ }
+
+ case Pin_Fp128Trinary: {
+ /* Note Fp128 instructions use the vector registers */
+ UInt fr_dst = vregEnc(i->Pin.Fp128Binary.dst);
+ UInt fr_srcL = vregEnc(i->Pin.Fp128Binary.srcL);
+ UInt fr_srcR = vregEnc(i->Pin.Fp128Binary.srcR);
+
+ /* Note this issues a Vector scalar instruction. The register
+ * mapping for the V128 type assumes the a vector instruction. The
+ * PPC hardware has a single register file that the vector scalar
+ * registers and the vector registers map to. The 32 vector
+ * registers instructions map to the same registers as the vector
+ * scalar registers 32 to 63. For these instructions the HW adds
+ * 32 to the register numbers to access the VSRR register. No need
+ * to adjust the numbers to map to the VR register that contians the
+ * operands.
+ */
+
+ switch (i->Pin.Fp128Binary.op) {
+ case Pfp_FPMULADDQ: // xsmaddqp, use rounding specified by RN
+ p = mkFormVXR0( p, 63, fr_dst, fr_srcL, fr_srcR, 388, 0, endness_host );
+ break;
+ case Pfp_FPMULADDQRNDODD: // xsmaddqpo, round to odd
+ p = mkFormVXR0( p, 63, fr_dst, fr_srcL, fr_srcR, 388, 1, endness_host );
+ break;
+ case Pfp_FPMULSUBQ: // xsmsubqp, use rounding specified by RN
+ p = mkFormVXR0( p, 63, fr_dst, fr_srcL, fr_srcR, 420, 0, endness_host );
+ break;
+ case Pfp_FPMULSUBQRNDODD: // xsmsubsqpo, round to odd
+ p = mkFormVXR0( p, 63, fr_dst, fr_srcL, fr_srcR, 420, 1, endness_host );
+ break;
+ case Pfp_FPNEGMULADDQ: // xsnmaddqp, use rounding specified by RN
+ p = mkFormVXR0( p, 63, fr_dst, fr_srcL, fr_srcR, 452, 0, endness_host );
+ break;
+ case Pfp_FPNEGMULADDQRNDODD: // xsnmaddqpo, round to odd
+ p = mkFormVXR0( p, 63, fr_dst, fr_srcL, fr_srcR, 452, 1, endness_host );
+ break;
+ case Pfp_FPNEGMULSUBQ: // xsnmsubqp, use rounding specified by RN
+ p = mkFormVXR0( p, 63, fr_dst, fr_srcL, fr_srcR, 484, 0, endness_host );
+ break;
+ case Pfp_FPNEGMULSUBQRNDODD: // xsnmsubsqpo, round to odd
+ p = mkFormVXR0( p, 63, fr_dst, fr_srcL, fr_srcR, 484, 1, endness_host );
+ break;
+ default:
+ goto bad;
+ }
+ goto done;
+ }
+
case Pin_FpMulAcc: {
UInt fr_dst = fregEnc(i->Pin.FpMulAcc.dst);
UInt fr_srcML = fregEnc(i->Pin.FpMulAcc.srcML);
case Pin_AvUnary: {
UInt v_dst = vregEnc(i->Pin.AvUnary.dst);
UInt v_src = vregEnc(i->Pin.AvUnary.src);
- UInt opc2;
+ UInt opc2, opc3;
+
switch (i->Pin.AvUnary.op) {
case Pav_MOV: opc2 = 1156; break; // vor vD,vS,vS
case Pav_NOT: opc2 = 1284; break; // vnor vD,vS,vS
case Pav_ZEROCNTHALF: opc2 = 1858; break; // vclzh
case Pav_ZEROCNTWORD: opc2 = 1922; break; // vclzw
case Pav_ZEROCNTDBL: opc2 = 1986; break; // vclzd
+ case Pav_TRAILINGZEROCNTBYTE: opc2 = 1538; break; // vctzb
+ case Pav_TRAILINGZEROCNTHALF: opc2 = 1538; break; // vctzh
+ case Pav_TRAILINGZEROCNTWORD: opc2 = 1538; break; // vctzw
+ case Pav_TRAILINGZEROCNTDBL: opc2 = 1538; break; // vctzd
case Pav_BITMTXXPOSE: opc2 = 1292; break; // vgbbd
+ case Pav_BCD128toI128S: opc2 = 385; break; //bcdctsq.
+ case Pav_MulI128by10: opc2 = 513; break; // vmul10uq
+ case Pav_MulI128by10Carry: opc2 = 1; break; // vmul10cuq
+ case Pav_F16toF64x2: opc2 = 347; opc3 = 16; break; // xvcvhpdp
+ case Pav_F64toF16x2: opc2 = 347; opc3 = 17; break; // xvcvdphp
+ case Pav_F16toF32x4: opc2 = 475; opc3 = 24; break; // xvcvhpsp
+ case Pav_F32toF16x4: opc2 = 475; opc3 = 25; break; // xvcvsphp
+
default:
goto bad;
}
case Pav_NOT:
p = mkFormVX( p, 4, v_dst, v_src, v_src, opc2, endness_host );
break;
+ case Pav_F16toF32x4:
+ {
+ /* I64 source has four 16-bit float values in the upper 64-bit
+ * of the source vector register, lower 64-bits are undefined.
+ */
+ /* Scatter the four F16 values in the Vector register */
+ p = mkFormVX( p, 4, v_dst, 0, v_src, 590, endness_host );// vupkhsh
+
+ /* The layout of the vector register is now: S0F0 S1F1 S2F2 S3F3
+ * where S is the sign extension of the 16-bit F value. We don't
+ * care about the extended signs.
+ */
+
+ /* Input, in v_dst, is now correct for the xvcvhpsp instruction */
+ p = mkFormVX_BX_TX( p, 60, v_dst, opc3, v_dst, opc2,
+ endness_host );
+ }
+ break;
+ case Pav_F64toF16x2:
+ case Pav_F16toF64x2:
+ case Pav_F32toF16x4:
+ /* Note this issues a Vector scalar instruction. The register
+ * mapping for the V128 type assumes the a vector instruction. The
+ * PPC hardware has a single register file that the vector scalar
+ * registers and the vector registers map to. The 32 vector registers
+ * instructions map to the same registers as the vector scalar
+ * registers 32 to 63. mkFormVX_BX_TX does the needed adjustment.
+ */
+ p = mkFormVX_BX_TX( p, 60, v_dst, opc3, v_src, opc2, endness_host );
+ break;
+ case Pav_BCD128toI128S: // bcdctsq
+ p = mkFormVX( p, 4, v_dst, 0, v_src, (1<<10 | 385), endness_host );
+ break;
+ case Pav_MulI128by10:
+ case Pav_MulI128by10Carry:
+ p = mkFormVX( p, 4, v_dst, v_src, 0, opc2, endness_host );
+ break;
+ case Pav_TRAILINGZEROCNTBYTE:
+ p = mkFormVX( p, 4, v_dst, 28, v_src, opc2, endness_host );
+ break;
+ case Pav_TRAILINGZEROCNTHALF:
+ p = mkFormVX( p, 4, v_dst, 29, v_src, opc2, endness_host );
+ break;
+ case Pav_TRAILINGZEROCNTWORD:
+ p = mkFormVX( p, 4, v_dst, 30, v_src, opc2, endness_host );
+ break;
+ case Pav_TRAILINGZEROCNTDBL:
+ p = mkFormVX( p, 4, v_dst, 31, v_src, opc2, endness_host );
+ break;
default:
p = mkFormVX( p, 4, v_dst, 0, v_src, opc2, endness_host );
break;
case Pav_AND: opc2 = 1028; break; // vand
case Pav_OR: opc2 = 1156; break; // vor
case Pav_XOR: opc2 = 1220; break; // vxor
+ /* Mult by 10 */
+ case Pav_MulI128by10E: opc2 = 577; break; // vmul10euq
+ case Pav_MulI128by10ECarry: opc2 = 65; break; // vmul10ecuq
default:
goto bad;
}
goto done;
}
+ case Pin_AvBinaryInt: {
+ UInt ps = i->Pin.AvBinaryInt.val->Pri.Imm;
+ UInt dst = vregEnc(i->Pin.AvBinaryInt.dst);
+ UInt src = vregEnc(i->Pin.AvBinaryInt.src);
+
+ switch (i->Pin.AvBinaryInt.op) {
+ /* BCD */
+ case Pav_I128StoBCD128: // bcdcfsq
+ {
+ /* v_srcR actually contains the value of the one-bit ps field */
+ int opc2 = 385;
+ p = mkFormVX( p, 4, dst, 2, src,
+ (1 << 10 | (ps << 9) | opc2), endness_host );
+ }
+ break;
+
+ case Pav_F128toI128S: // xsrqpi, xsrqpix
+ {
+ int opc2 = 5;
+ UInt EX = ps & 0x1;
+ UInt R = (ps >> 3) & 0x1;
+ UInt RMC = (ps >> 1) & 0x3;
+ /* Note this issues a Vector scalar instruction. The register
+ * mapping for the V128 type assumes the a vector instruction. The
+ * PPC hardware has a single register file that the vector scalar
+ * registers and the vector registers map to. The 32 vector
+ * registers instructions map to the same registers as the vector
+ * scalar registers 32 to 63. For these instructions the HW adds
+ * 32 to the register numbers to access the VSRR register. No need
+ * to adjust the numbers to map to the VR register that contians
+ * the operands.
+ */
+ p = mkFormVSXRND( p, 63, R, dst, src, RMC, opc2, EX,
+ endness_host );
+ }
+ break;
+
+ case Pav_ROUNDFPQ: // xsrqpxp
+ {
+ int opc2 = 37;
+ UInt EX = ps & 0x1;
+ UInt RMC = (ps >> 1) & 0x3;
+ UInt R = (ps >> 3) & 0x1;
+ p = mkFormVSXRND( p, 63, R, dst, src, RMC, opc2, EX,
+ endness_host );
+ }
+ break;
+
+ default:
+ goto bad;
+
+ }
+ goto done;
+ }
+
case Pin_AvBin8x16: {
UInt v_dst = vregEnc(i->Pin.AvBin8x16.dst);
UInt v_srcL = vregEnc(i->Pin.AvBin8x16.srcL);
IREndness IEndianess );
static HReg iselDfp64Expr ( ISelEnv* env, IRExpr* e,
IREndness IEndianess );
+static HReg iselFp128Expr_wrk ( ISelEnv* env, IRExpr* e, IREndness IEndianess);
+static HReg iselFp128Expr ( ISelEnv* env, IRExpr* e, IREndness IEndianess);
/* 64-bit mode ONLY: compute an D128 into a GPR64 pair. */
static void iselDfp128Expr_wrk ( HReg* rHi, HReg* rLo, ISelEnv* env,
_set_FPU_rounding_mode(env, mode, True, IEndianess);
}
+static
+Bool FPU_rounding_mode_isOdd (IRExpr* mode) {
+ /* If the rounding mode is set to odd, the the expr must be a constant U8
+ * value equal to 8. Otherwise, it must be a bin op expressiong that
+ * calculates the value.
+ */
+
+ if (mode->tag != Iex_Const)
+ return False;
+
+ vassert(mode->Iex.Const.con->tag == Ico_U32);
+ vassert(mode->Iex.Const.con->Ico.U8 == 0x8);
+ return True;
+}
/*---------------------------------------------------------*/
/*--- ISEL: vector helpers ---*/
return r_dst;
}
+ case Iop_Ctz32:
+ case Iop_Ctz64: {
+ HReg r_src, r_dst;
+ PPCUnaryOp op_clz = (op_unop == Iop_Ctz32) ? Pun_CTZ32 :
+ Pun_CTZ64;
+ if (op_unop == Iop_Ctz64 && !mode64)
+ goto irreducible;
+ /* Count trailing zeroes. */
+ r_dst = newVRegI(env);
+ r_src = iselWordExpr_R(env, e->Iex.Unop.arg, IEndianess);
+ addInstr(env, PPCInstr_Unary(op_clz,r_dst,r_src));
+ return r_dst;
+ }
+
case Iop_Left8:
case Iop_Left16:
case Iop_Left32:
addInstr(env, PPCInstr_Call( cc, (Addr)h_calc_DPBtoBCD,
argiregs,
mk_RetLoc_simple(RLPri_Int) ) );
- } else {
+ } else {
HWord* fdescr;
fdescr = (HWord*)h_calc_DPBtoBCD;
addInstr(env, PPCInstr_Call( cc, (Addr64)(fdescr[0]),
addInstr(env, mk_iMOVds_RR(r_dst, argregs[0]));
return r_dst;
}
+ case Iop_F32toF16x4: {
+ HReg vdst = newVRegV(env); /* V128 */
+ HReg dst = newVRegI(env); /* I64*/
+ HReg r0 = newVRegI(env); /* I16*/
+ HReg r1 = newVRegI(env); /* I16*/
+ HReg r2 = newVRegI(env); /* I16*/
+ HReg r3 = newVRegI(env); /* I16*/
+ HReg vsrc = iselVecExpr(env, e->Iex.Unop.arg, IEndianess);
+ PPCAMode *am_off0, *am_off2, *am_off4, *am_off6, *am_off8, *am_off12;
+ HReg r_aligned16;
+
+ sub_from_sp( env, 32 ); // Move SP down
+
+ /* issue instruction */
+ addInstr(env, PPCInstr_AvUnary(Pav_F32toF16x4, vdst, vsrc));
+
+ /* Get a quadword aligned address within our stack space */
+ r_aligned16 = get_sp_aligned16( env );
+ am_off0 = PPCAMode_IR( 0, r_aligned16 );
+ am_off2 = PPCAMode_IR( 2, r_aligned16 );
+ am_off4 = PPCAMode_IR( 4, r_aligned16 );
+ am_off6 = PPCAMode_IR( 6, r_aligned16 );
+ am_off8 = PPCAMode_IR( 8, r_aligned16 );
+ am_off12 = PPCAMode_IR( 12, r_aligned16 );
+
+ /* Store v128 result to stack. */
+ if (IEndianess == Iend_LE) {
+ addInstr(env, PPCInstr_AvLdSt(False/*store*/, 16, vdst, am_off0));
+ } else {
+ addInstr(env, PPCInstr_AvLdSt(False/*store*/, 16, vdst, am_off8));
+ }
+
+ /* fetch four I16 from V128, store into contiguous I64 via stack, */
+
+ /* get 16-bit values */
+ addInstr(env, PPCInstr_Load( 2, r3, am_off12, mode64));
+ addInstr(env, PPCInstr_Load( 2, r2, am_off8, mode64));
+ addInstr(env, PPCInstr_Load( 2, r1, am_off4, mode64));
+ addInstr(env, PPCInstr_Load( 2, r0, am_off0, mode64));
+
+ /* store in contiguous 64-bit values */
+ addInstr(env, PPCInstr_Store( 2, am_off6, r3, mode64));
+ addInstr(env, PPCInstr_Store( 2, am_off4, r2, mode64));
+ addInstr(env, PPCInstr_Store( 2, am_off2, r1, mode64));
+ addInstr(env, PPCInstr_Store( 2, am_off0, r0, mode64));
+
+ /* Fetch I64 */
+ if (IEndianess == Iend_LE) {
+ addInstr(env, PPCInstr_Load(8, dst, am_off0, mode64));
+ } else {
+ addInstr(env, PPCInstr_Load(8, dst, am_off8, mode64));
+ }
+ add_to_sp( env, 32 ); // Reset SP
+ return dst;
+ }
default:
break;
static void iselInt128Expr_wrk ( HReg* rHi, HReg* rLo,
ISelEnv* env, IRExpr* e, IREndness IEndianess )
{
+ Bool mode64 = env->mode64;
+
vassert(e);
vassert(typeOfIRExpr(env->type_env,e) == Ity_I128);
return;
}
+ /* 128-bit GET */
+ if (e->tag == Iex_Get) {
+ PPCAMode* am_addr = PPCAMode_IR( e->Iex.Get.offset,
+ GuestStatePtr(mode64) );
+ PPCAMode* am_addr4 = advance4(env, am_addr);
+ HReg tLo = newVRegI(env);
+ HReg tHi = newVRegI(env);
+
+ addInstr(env, PPCInstr_Load( 8, tHi, am_addr, mode64));
+ addInstr(env, PPCInstr_Load( 8, tLo, am_addr4, mode64));
+ *rHi = tHi;
+ *rLo = tLo;
+ return;
+ }
+
/* --------- BINARY ops --------- */
if (e->tag == Iex_Binop) {
switch (e->Iex.Binop.op) {
if (e->tag == Iex_Binop) {
+ if (e->Iex.Binop.op == Iop_F128toF64) {
+ HReg fr_dst = newVRegF(env);
+ HReg fr_src = iselFp128Expr(env, e->Iex.Binop.arg2, IEndianess);
+ HReg tmp = newVRegV(env);
+ PPCAMode* zero_r1 = PPCAMode_IR( 0, StackFramePtr(env->mode64) );
+ PPCAMode* eight_r1 = PPCAMode_IR( 8, StackFramePtr(env->mode64) );
+ PPCAvFpOp fpop = Pavfp_INVALID;
+
+ if (FPU_rounding_mode_isOdd(e->Iex.Binop.arg1)) {
+ /* use rounding mode specified by RN. Issue inst with R0 = 0 */
+ fpop = Pfp_FPQTODRNDODD;
+ } else {
+ set_FPU_rounding_mode( env, e->Iex.Binop.arg1, IEndianess );
+ fpop = Pfp_FPQTOD;
+ }
+
+ addInstr(env, PPCInstr_Fp128Unary(fpop, tmp, fr_src));
+
+ /* result is in a 128-bit vector register, move to 64-bit reg to
+ * match the Iop specification. The result will get moved back
+ * to a 128-bit register and stored once the value is returned.
+ */
+ sub_from_sp( env, 16 );
+ addInstr(env, PPCInstr_AvLdSt(False/*store*/, 16, tmp, zero_r1));
+ addInstr(env, PPCInstr_FpLdSt(True/*load*/, 8, fr_dst, eight_r1));
+ add_to_sp( env, 16 );
+
+ return fr_dst;
+ }
+
if (e->Iex.Binop.op == Iop_RoundF64toF32) {
HReg r_dst = newVRegF(env);
HReg r_src = iselDblExpr(env, e->Iex.Binop.arg2, IEndianess);
if (e->tag == Iex_Unop) {
switch (e->Iex.Unop.op) {
+ case Iop_F128HItoF64:
+ case Iop_F128LOtoF64:
+ {
+ /* put upper/lower 64-bits of F128 into an F64. */
+ HReg r_aligned16;
+ HReg fdst = newVRegF(env);
+ HReg fsrc = iselFp128Expr(env, e->Iex.Unop.arg, IEndianess);
+ PPCAMode *am_off0, *am_off8, *am_off_arg;
+ sub_from_sp( env, 32 ); // Move SP down 32 bytes
+
+ // get a quadword aligned address within our stack space
+ r_aligned16 = get_sp_aligned16( env );
+ am_off0 = PPCAMode_IR( 0, r_aligned16 );
+ am_off8 = PPCAMode_IR( 8 ,r_aligned16 );
+
+ /* store 128-bit floating point value to memory, load low word
+ * or high to 64-bit destination floating point register
+ */
+ addInstr(env, PPCInstr_AvLdSt(False/*store*/, 16, fsrc, am_off0));
+ if (IEndianess == Iend_LE) {
+ if (e->Iex.Binop.op == Iop_F128HItoF64)
+ am_off_arg = am_off8;
+ else
+ am_off_arg = am_off0;
+ } else {
+ if (e->Iex.Binop.op == Iop_F128HItoF64)
+ am_off_arg = am_off0;
+ else
+ am_off_arg = am_off8;
+ }
+ addInstr(env,
+ PPCInstr_FpLdSt( True /*load*/,
+ 8, fdst,
+ am_off_arg ));
+ add_to_sp( env, 32 ); // Reset SP
+ return fdst;
+ }
case Iop_ReinterpI64asF64: {
/* Given an I64, produce an IEEE754 double with the same
bit pattern. */
vpanic( "iselDfp32Expr_wrk(ppc)" );
}
+static HReg iselFp128Expr( ISelEnv* env, IRExpr* e, IREndness IEndianess )
+{
+ HReg r = iselFp128Expr_wrk( env, e, IEndianess );
+ vassert(hregClass(r) == HRcVec128);
+ vassert(hregIsVirtual(r));
+ return r;
+}
+
+/* DO NOT CALL THIS DIRECTLY */
+static HReg iselFp128Expr_wrk( ISelEnv* env, IRExpr* e, IREndness IEndianess)
+{
+ Bool mode64 = env->mode64;
+ PPCAvFpOp fpop = Pavfp_INVALID;
+ IRType ty = typeOfIRExpr(env->type_env,e);
+
+ vassert(e);
+ vassert( ty == Ity_F128 );
+
+ /* read 128-bit IRTemp */
+ if (e->tag == Iex_RdTmp) {
+ return lookupIRTemp(env, e->Iex.RdTmp.tmp);
+ }
+
+ if (e->tag == Iex_Get) {
+ /* Guest state vectors are 16byte aligned,
+ so don't need to worry here */
+ HReg dst = newVRegV(env);
+
+ addInstr(env,
+ PPCInstr_AvLdSt( True/*load*/, 16, dst,
+ PPCAMode_IR( e->Iex.Get.offset,
+ GuestStatePtr(mode64) )));
+ return dst;
+ }
+
+ if (e->tag == Iex_Unop) {
+ switch (e->Iex.Unop.op) {
+ case Iop_TruncF128toI64S:
+ fpop = Pfp_TRUNCFPQTOISD; goto do_Un_F128;
+ case Iop_TruncF128toI32S:
+ fpop = Pfp_TRUNCFPQTOISW; goto do_Un_F128;
+ case Iop_TruncF128toI64U:
+ fpop = Pfp_TRUNCFPQTOIUD; goto do_Un_F128;
+ case Iop_TruncF128toI32U:
+ fpop = Pfp_TRUNCFPQTOIUW; goto do_Un_F128;
+
+ do_Un_F128: {
+ HReg r_dst = newVRegV(env);
+ HReg r_src = iselFp128Expr(env, e->Iex.Unop.arg, IEndianess);
+ addInstr(env, PPCInstr_Fp128Unary(fpop, r_dst, r_src));
+ return r_dst;
+ }
+
+ case Iop_F64toF128: {
+ fpop = Pfp_FPDTOQ;
+ HReg r_dst = newVRegV(env);
+ HReg r_src = iselDblExpr(env, e->Iex.Unop.arg, IEndianess);
+ HReg v128tmp = newVRegV(env);
+ PPCAMode* zero_r1 = PPCAMode_IR( 0, StackFramePtr(env->mode64) );
+
+ /* value is in 64-bit float reg, need to move to 128-bit vector reg */
+ sub_from_sp( env, 16 );
+ addInstr(env, PPCInstr_FpLdSt(False/*store*/, 8, r_src, zero_r1));
+ addInstr(env, PPCInstr_AvLdSt(True/*load*/, 16, v128tmp, zero_r1));
+ add_to_sp( env, 16 );
+
+ addInstr(env, PPCInstr_Fp128Unary(fpop, r_dst, v128tmp));
+ return r_dst;
+ }
+
+ case Iop_I64StoF128:
+ fpop = Pfp_IDSTOQ; goto do_Un_int_F128;
+ case Iop_I64UtoF128:
+ fpop = Pfp_IDUTOQ; goto do_Un_int_F128;
+
+ do_Un_int_F128: {
+ HReg r_dst = newVRegV(env);
+ HReg tmp = newVRegV(env);
+ HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg, IEndianess);
+ PPCAMode *am_offhi, *am_offlo;
+ HReg r_aligned16;
+
+ /* source is in a 64-bit integer reg, move to 128-bit float reg
+ * do this via the stack (easy, convenient, etc).
+ */
+ sub_from_sp( env, 32 ); // Move SP down
+
+ /* Get a quadword aligned address within our stack space */
+ r_aligned16 = get_sp_aligned16( env );
+
+ am_offlo = PPCAMode_IR( 0, r_aligned16 );
+ am_offhi = PPCAMode_IR( 8, r_aligned16 );
+
+ /* Inst only uses the upper 64-bit of the source */
+ addInstr(env, PPCInstr_Load(8, r_src, am_offhi, mode64));
+
+ /* Fetch result back from stack. */
+ addInstr(env, PPCInstr_AvLdSt(True/*load*/, 16, tmp, am_offlo));
+
+ add_to_sp( env, 32 ); // Reset SP
+
+ addInstr(env, PPCInstr_Fp128Unary(fpop, r_dst, tmp));
+ return r_dst;
+ }
+
+ default:
+ break;
+ } /* switch (e->Iex.Unop.op) */
+ } /* if (e->tag == Iex_Unop) */
+
+ if (e->tag == Iex_Binop) {
+ switch (e->Iex.Binop.op) {
+
+ case Iop_F64HLtoF128:
+ {
+ HReg dst = newVRegV(env);
+ HReg r_src_hi = iselDblExpr(env, e->Iex.Binop.arg1, IEndianess);
+ HReg r_src_lo = iselDblExpr(env, e->Iex.Binop.arg2, IEndianess);
+ PPCAMode *am_offhi, *am_offlo;
+ HReg r_aligned16;
+
+ /* do this via the stack (easy, convenient, etc) */
+ sub_from_sp( env, 16 ); // Move SP down
+
+ /* Get a quadword aligned address within our stack space */
+ r_aligned16 = get_sp_aligned16( env );
+
+ am_offlo = PPCAMode_IR( 0, r_aligned16 );
+ am_offhi = PPCAMode_IR( 8, r_aligned16 );
+
+ addInstr(env, PPCInstr_FpLdSt(False/*store*/, 8,
+ r_src_lo, am_offlo));
+ addInstr(env, PPCInstr_FpLdSt(False/*store*/, 8,
+ r_src_hi, am_offhi));
+
+ /* Fetch result back from stack. */
+ addInstr(env, PPCInstr_AvLdSt(True/*load*/, 16,
+ dst, am_offlo));
+
+ add_to_sp( env, 16 ); // Reset SP
+ return dst;
+ }
+ case Iop_F128toI128S:
+ {
+ HReg dst = newVRegV(env);
+ HReg r_src = iselFp128Expr(env, e->Iex.Binop.arg2, IEndianess);
+ PPCRI* rm = iselWordExpr_RI(env, e->Iex.Binop.arg1, IEndianess);
+ /* Note: rm is a set of three bit fields that specify the
+ * rounding mode and which of the two instructions to issue.
+ */
+ addInstr(env, PPCInstr_AvBinaryInt(Pav_F128toI128S, dst,
+ r_src, rm));
+ return dst;
+ }
+ case Iop_RndF128:
+ {
+ HReg dst = newVRegV(env);
+ HReg r_src = iselFp128Expr(env, e->Iex.Binop.arg2, IEndianess);
+ PPCRI* rm = iselWordExpr_RI(env, e->Iex.Binop.arg1, IEndianess);
+ /* Note: rm is a set of three bit fields that specify the
+ * rounding mode and which of the two instructions to issue.
+ */
+ addInstr(env, PPCInstr_AvBinaryInt(Pav_ROUNDFPQ, dst,
+ r_src, rm));
+ return dst;
+ }
+ case Iop_SqrtF128:
+ if (FPU_rounding_mode_isOdd(e->Iex.Binop.arg1)) {
+ /* use rounding mode specified by RN. Issue inst with R0 = 0 */
+ fpop = Pfp_FPSQRTQRNDODD;
+ goto do_Bin_F128;
+ } else {
+ set_FPU_rounding_mode( env, e->Iex.Binop.arg1, IEndianess );
+ fpop = Pfp_FPSQRTQ;
+ goto do_Bin_F128;
+ }
+ case Iop_F128toF32:
+ if (FPU_rounding_mode_isOdd(e->Iex.Binop.arg1)) {
+ /* use rounding mode specified by RN. Issue inst with R0 = 0 */
+ fpop = Pfp_FPQTOWRNDODD;
+ goto do_Bin_F128;
+ } else {
+ set_FPU_rounding_mode( env, e->Iex.Binop.arg1, IEndianess );
+ fpop = Pfp_FPQTOW;
+ goto do_Bin_F128;
+ }
+ do_Bin_F128: {
+ HReg r_dst = newVRegV(env);
+ HReg r_src = iselFp128Expr(env, e->Iex.Binop.arg2, IEndianess);
+ addInstr(env, PPCInstr_Fp128Unary(fpop, r_dst, r_src));
+ return r_dst;
+ }
+
+ default:
+ break;
+ } /* switch (e->Iex.Binop.op) */
+ } /* if (e->tag == Iex_Binop) */
+
+ if (e->tag == Iex_Triop) {
+ IRTriop *triop = e->Iex.Triop.details;
+
+ switch (triop->op) {
+ case Iop_AddF128:
+ if (FPU_rounding_mode_isOdd(triop->arg1)) {
+ /* use rounding mode specified by RN. Issue inst with R0 = 0 */
+ fpop = Pfp_FPADDQRNDODD; goto do_Tri_F128;
+ } else {
+ set_FPU_rounding_mode( env, triop->arg1, IEndianess );
+ fpop = Pfp_FPADDQ; goto do_Tri_F128;
+ }
+ case Iop_SubF128:
+ if (FPU_rounding_mode_isOdd(triop->arg1)) {
+ /* use rounding mode specified by RN. Issue inst with R0 = 0 */
+ fpop = Pfp_FPSUBQRNDODD; goto do_Tri_F128;
+ } else {
+ set_FPU_rounding_mode( env, triop->arg1, IEndianess );
+ fpop = Pfp_FPSUBQ; goto do_Tri_F128;
+ }
+ case Iop_MulF128:
+ if (FPU_rounding_mode_isOdd(triop->arg1)) {
+ /* use rounding mode specified by RN. Issue inst with R0 = 0 */
+ fpop = Pfp_FPMULQRNDODD; goto do_Tri_F128;
+ } else {
+ set_FPU_rounding_mode( env, triop->arg1, IEndianess );
+ fpop = Pfp_FPMULQ; goto do_Tri_F128;
+ }
+ case Iop_DivF128:
+ if (FPU_rounding_mode_isOdd(triop->arg1)) {
+ /* use rounding mode specified by RN. Issue inst with R0 = 0 */
+ fpop = Pfp_FPDIVQRNDODD; goto do_Tri_F128;
+ } else {
+ set_FPU_rounding_mode( env, triop->arg1, IEndianess );
+ fpop = Pfp_FPDIVQ; goto do_Tri_F128;
+ }
+ case Iop_MAddF128:
+ if (FPU_rounding_mode_isOdd(triop->arg1)) {
+ /* use rounding mode specified by RN. Issue inst with R0 = 0 */
+ fpop = Pfp_FPMULADDQRNDODD; goto do_Tri_F128;
+ } else {
+ set_FPU_rounding_mode( env, triop->arg1, IEndianess );
+ fpop = Pfp_FPMULADDQ; goto do_Tri_F128;
+ }
+
+ do_Tri_F128: {
+ HReg r_dst = newVRegV(env);
+ HReg r_srcL = iselFp128Expr(env, triop->arg2, IEndianess);
+ HReg r_srcR = iselFp128Expr(env, triop->arg3, IEndianess);
+
+ addInstr(env, PPCInstr_Fp128Binary(fpop, r_dst, r_srcL, r_srcR));
+ return r_dst;
+ }
+
+ default:
+ break;
+ } /* switch (e->Iex.Triop.op) */
+
+ } /* if (e->tag == Iex_Trinop) */
+
+ if (e->tag == Iex_Qop) {
+ IRQop *qop = e->Iex.Qop.details;
+
+ switch (qop->op) {
+ case Iop_MAddF128:
+ if (FPU_rounding_mode_isOdd(qop->arg1)) {
+ /* use rounding mode specified by RN. Issue inst with R0 = 0 */
+ fpop = Pfp_FPMULADDQRNDODD; goto do_Quad_F128;
+ } else {
+ set_FPU_rounding_mode( env, qop->arg1, IEndianess );
+ fpop = Pfp_FPMULADDQ; goto do_Quad_F128;
+ }
+ case Iop_MSubF128:
+ if (FPU_rounding_mode_isOdd(qop->arg1)) {
+ /* use rounding mode specified by RN. Issue inst with R0 = 0 */
+ fpop = Pfp_FPMULSUBQRNDODD; goto do_Quad_F128;
+ } else {
+ set_FPU_rounding_mode( env, qop->arg1, IEndianess );
+ fpop = Pfp_FPMULSUBQ; goto do_Quad_F128;
+ }
+ case Iop_NegMAddF128:
+ if (FPU_rounding_mode_isOdd(qop->arg1)) {
+ /* use rounding mode specified by RN. Issue inst with R0 = 0 */
+ fpop = Pfp_FPNEGMULADDQRNDODD; goto do_Quad_F128;
+ } else {
+ set_FPU_rounding_mode( env, qop->arg1, IEndianess );
+ fpop = Pfp_FPNEGMULADDQ; goto do_Quad_F128;
+ }
+ case Iop_NegMSubF128:
+ if (FPU_rounding_mode_isOdd(qop->arg1)) {
+ /* use rounding mode specified by RN. Issue inst with R0 = 0 */
+ fpop = Pfp_FPNEGMULSUBQRNDODD; goto do_Quad_F128;
+ } else {
+ set_FPU_rounding_mode( env, qop->arg1, IEndianess );
+ fpop = Pfp_FPNEGMULSUBQ; goto do_Quad_F128;
+ }
+
+ do_Quad_F128: {
+ HReg r_dst = iselFp128Expr(env, qop->arg3,
+ IEndianess);
+ HReg r_srcL = iselFp128Expr(env, qop->arg2,
+ IEndianess);
+ HReg r_srcR = iselFp128Expr(env, qop->arg4,
+ IEndianess);
+
+ addInstr(env, PPCInstr_Fp128Trinary(fpop, r_dst, r_srcL, r_srcR));
+ return r_dst;
+ }
+
+ default:
+ break;
+ }
+ } /* if (e->tag == Iex_Qop) */
+
+ ppIRExpr( e );
+ vpanic( "iselFp128Expr(ppc64)" );
+}
+
static HReg iselDfp64Expr(ISelEnv* env, IRExpr* e, IREndness IEndianess)
{
HReg r = iselDfp64Expr_wrk( env, e, IEndianess );
if (e->tag == Iex_Unop) {
switch (e->Iex.Unop.op) {
+ case Iop_F16toF64x2:
+ {
+ HReg dst = newVRegV(env);
+ HReg arg = iselVecExpr(env, e->Iex.Unop.arg, IEndianess);
+ /* Note: PPC only coverts the 16-bt value in the upper word
+ * to a 64-bit value stored in the upper word. The
+ * contents of the lower word is undefined.
+ */
+ addInstr(env, PPCInstr_AvUnary(Pav_F16toF64x2, dst, arg));
+ return dst;
+ }
+
+ case Iop_F64toF16x2:
+ {
+ HReg dst = newVRegV(env);
+ HReg arg = iselVecExpr(env, e->Iex.Unop.arg, IEndianess);
+ /* Note: PPC only coverts the 64-bt value in the upper 64-bit of V128
+ * to a 16-bit value stored in the upper 64-bits of the result
+ * V128. The contents of the lower 64-bits is undefined.
+ */
+ addInstr(env, PPCInstr_AvUnary(Pav_F64toF16x2, dst, arg));
+ return dst;
+ }
+
+ case Iop_F16toF32x4:
+ {
+ HReg src = newVRegV(env);
+ HReg dst = newVRegV(env);
+ HReg arg = iselWordExpr_R(env, e->Iex.Unop.arg, IEndianess);
+ PPCAMode *am_off0, *am_off8;
+ HReg r_aligned16;
+
+ vassert(mode64);
+ /* need to put I64 src into upper 64-bits of vector register,
+ use stack */
+ sub_from_sp( env, 32 ); // Move SP down
+
+ /* Get a quadword aligned address within our stack space */
+ r_aligned16 = get_sp_aligned16( env );
+ am_off0 = PPCAMode_IR( 0, r_aligned16 );
+ am_off8 = PPCAMode_IR( 8, r_aligned16 );
+
+ /* Store I64 to stack */
+
+ if (IEndianess == Iend_LE) {
+ addInstr(env, PPCInstr_Store( 8, am_off8, arg, mode64 ));
+ } else {
+ addInstr(env, PPCInstr_Store( 8, am_off0, arg, mode64 ));
+ }
+
+ /* Fetch new v128 src back from stack. */
+ addInstr(env, PPCInstr_AvLdSt(True/*ld*/, 16, src, am_off0));
+
+ /* issue instruction */
+ addInstr(env, PPCInstr_AvUnary(Pav_F16toF32x4, dst, src));
+ add_to_sp( env, 32 ); // Reset SP
+
+ return dst;
+ }
+
+ case Iop_F32toF16x4:
+ {
+ HReg dst = newVRegI(env);
+ HReg tmp = newVRegV(env);
+ HReg arg = iselVecExpr(env, e->Iex.Unop.arg, IEndianess);
+ PPCAMode *am_off0, *am_off8;
+ HReg r_aligned16;
+
+ /* Instruction returns a V128, the Iop_F32toF16x4 needs to return
+ * I64. Move the upper 64-bits from the instruction to an I64 via
+ * the stack and return it.
+ */
+ sub_from_sp( env, 32 ); // Move SP down
+
+ addInstr(env, PPCInstr_AvUnary(Pav_F32toF16x4, tmp, arg));
+
+ /* Get a quadword aligned address within our stack space */
+ r_aligned16 = get_sp_aligned16( env );
+ am_off0 = PPCAMode_IR( 0, r_aligned16 );
+ am_off8 = PPCAMode_IR( 8, r_aligned16 );
+
+ /* Store v128 tmp to stack. */
+ addInstr(env, PPCInstr_AvLdSt(False/*store*/, 16, tmp, am_off0));
+
+ /* Fetch I64 from stack */
+ if (IEndianess == Iend_LE) {
+ addInstr(env, PPCInstr_Load( 8, dst, am_off8, mode64 ));
+ } else {
+ addInstr(env, PPCInstr_Load( 8, dst, am_off0, mode64 ));
+ }
+
+ add_to_sp( env, 32 ); // Reset SP
+ return dst;
+ }
+
case Iop_NotV128: {
HReg arg = iselVecExpr(env, e->Iex.Unop.arg, IEndianess);
HReg dst = newVRegV(env);
case Iop_Clz16x8: op = Pav_ZEROCNTHALF; goto do_zerocnt;
case Iop_Clz32x4: op = Pav_ZEROCNTWORD; goto do_zerocnt;
case Iop_Clz64x2: op = Pav_ZEROCNTDBL; goto do_zerocnt;
+ case Iop_Ctz8x16: op = Pav_TRAILINGZEROCNTBYTE; goto do_zerocnt;
+ case Iop_Ctz16x8: op = Pav_TRAILINGZEROCNTHALF; goto do_zerocnt;
+ case Iop_Ctz32x4: op = Pav_TRAILINGZEROCNTWORD; goto do_zerocnt;
+ case Iop_Ctz64x2: op = Pav_TRAILINGZEROCNTDBL; goto do_zerocnt;
case Iop_PwBitMtxXpose64x2: op = Pav_BITMTXXPOSE; goto do_zerocnt;
do_zerocnt:
{
return dst;
}
+ /* BCD Iops */
+ case Iop_BCD128toI128S:
+ {
+ HReg dst = newVRegV(env);
+ HReg arg = iselVecExpr(env, e->Iex.Unop.arg, IEndianess);
+ addInstr(env, PPCInstr_AvUnary( Pav_BCD128toI128S, dst, arg ) );
+ return dst;
+ }
+
+ case Iop_MulI128by10: op = Pav_MulI128by10; goto do_MulI128;
+ case Iop_MulI128by10Carry: op = Pav_MulI128by10Carry; goto do_MulI128;
+ do_MulI128: {
+ HReg dst = newVRegV(env);
+ HReg arg = iselVecExpr(env, e->Iex.Unop.arg, IEndianess);
+ addInstr(env, PPCInstr_AvUnary(op, dst, arg));
+ return dst;
+ }
+
default:
break;
} /* switch (e->Iex.Unop.op) */
return dst;
}
+ /* BCD Iops */
+ case Iop_I128StoBCD128:
+ {
+ HReg dst = newVRegV(env);
+ HReg arg = iselVecExpr(env, e->Iex.Binop.arg1, IEndianess);
+ PPCRI* ps = iselWordExpr_RI(env, e->Iex.Binop.arg2, IEndianess);
+
+ addInstr(env, PPCInstr_AvBinaryInt( Pav_I128StoBCD128, dst, arg,
+ ps ) );
+ return dst;
+ }
+
+ case Iop_MulI128by10E: op = Pav_MulI128by10E; goto do_MulI128E;
+ case Iop_MulI128by10ECarry: op = Pav_MulI128by10ECarry; goto do_MulI128E;
+ do_MulI128E: {
+ HReg dst = newVRegV(env);
+ HReg argL = iselVecExpr(env, e->Iex.Binop.arg1, IEndianess);
+ HReg argR = iselVecExpr(env, e->Iex.Binop.arg2, IEndianess);
+ addInstr(env, PPCInstr_AvBinary(op, dst, argL, argR));
+ return dst;
+ }
+
case Iop_BCDAdd:op = Pav_BCDAdd; goto do_AvBCDV128;
case Iop_BCDSub:op = Pav_BCDSub; goto do_AvBCDV128;
do_AvBCDV128: {
addInstr(env, PPCInstr_Store( 4, am_addr, rHi, mode64 ));
addInstr(env, PPCInstr_Store( 4, am_addr4, rLo, mode64 ));
return;
- }
- if (ty == Ity_V128) {
+ }
+ if (ty == Ity_I128) {
+ HReg rHi, rLo;
+ PPCAMode* am_addr = PPCAMode_IR( stmt->Ist.Put.offset,
+ GuestStatePtr(mode64) );
+ PPCAMode* am_addr4 = advance4(env, am_addr);
+
+ iselInt128Expr(&rHi,&rLo, env, stmt->Ist.Put.data, IEndianess);
+ addInstr(env, PPCInstr_Store( 4, am_addr, rHi, mode64 ));
+ addInstr(env, PPCInstr_Store( 4, am_addr4, rLo, mode64 ));
+ return;
+ }
+ if (ty == Ity_F128) {
+ /* Guest state vectors are 16byte aligned,
+ so don't need to worry here */
+ HReg v_src = iselFp128Expr(env, stmt->Ist.Put.data, IEndianess);
+
+ PPCAMode* am_addr = PPCAMode_IR( stmt->Ist.Put.offset,
+ GuestStatePtr(mode64) );
+ addInstr(env,
+ PPCInstr_AvLdSt(False/*store*/, 16, v_src, am_addr));
+ return;
+ }
+ if (ty == Ity_V128) {
/* Guest state vectors are 16byte aligned,
so don't need to worry here */
HReg v_src = iselVecExpr(env, stmt->Ist.Put.data, IEndianess);
addInstr(env, PPCInstr_Dfp64Unary(Pfp_MOV, fr_dst, fr_src));
return;
}
+ if (ty == Ity_F128) {
+ HReg v_dst = lookupIRTemp(env, tmp);
+ HReg v_src = iselFp128Expr(env, stmt->Ist.WrTmp.data, IEndianess);
+ addInstr(env, PPCInstr_AvUnary(Pav_MOV, v_dst, v_src));
+ return;
+ }
if (ty == Ity_V128) {
HReg v_dst = lookupIRTemp(env, tmp);
HReg v_src = iselVecExpr(env, stmt->Ist.WrTmp.data, IEndianess);
case Ity_F64:
hregLo = mkHReg(True, HRcFlt64, 0, j++);
break;
+ case Ity_F128:
case Ity_V128:
hregLo = mkHReg(True, HRcVec128, 0, j++);
break;