/*------------------------------------------------------------*/
#define DFP_LONG 1
#define DFP_EXTND 2
+#define DFP_LONG_BIAS 398
#define DFP_LONG_ENCODED_FIELD_MASK 0x1F00
+#define DFP_EXTND_BIAS 6176
#define DFP_EXTND_ENCODED_FIELD_MASK 0x1F000
#define DFP_LONG_EXP_MSK 0XFF
#define DFP_EXTND_EXP_MSK 0XFFF
#define DFP_LONG_GFIELD_RT_SHIFT (63 - 13 - 32) // adj for upper 32-bits
#define DFP_G_FIELD_EXTND_MASK 0x7FFFC000 // upper 32-bits only
#define DFP_EXTND_GFIELD_RT_SHIFT (63 - 17 - 32) //adj for upper 32 bits
-
#define DFP_T_FIELD_LONG_MASK 0x3FFFF // mask for upper 32-bits
#define DFP_T_FIELD_EXTND_MASK 0x03FFFF // mask for upper 32-bits
-
#define DFP_LONG_EXP_MAX 369 // biased max
#define DFP_LONG_EXP_MIN 0 // biased min
#define DFP_EXTND_EXP_MAX 6111 // biased max
#define DFP_EXTND_EXP_MIN 0 // biased min
+#define DFP_LONG_MAX_SIG_DIGITS 16
+#define DFP_EXTND_MAX_SIG_DIGITS 34
+#define MAX_DIGITS_IN_STRING 8
+
#define AND(x, y) binop( Iop_And32, x, y )
-#define OR(x, y) binop( Iop_Or32, x, y )
#define AND4(w, x, y, z) AND( AND( w, x ), AND( y, z ) )
+#define OR(x, y) binop( Iop_Or32, x, y )
#define OR3(x, y, z) OR( x, OR( y, z ) )
#define OR4(w, x, y, z) OR( OR( w, x ), OR( y, z ) )
+#define NOT(x) unop( Iop_1Uto32, unop( Iop_Not1, unop( Iop_32to1, mkexpr( x ) ) ) )
+
#define SHL(value, by) binop( Iop_Shl32, value, mkU8( by ) )
+#define SHR(value, by) binop( Iop_Shr32, value, mkU8( by ) )
+
#define BITS5(_b4,_b3,_b2,_b1,_b0) \
(((_b4) << 4) | ((_b3) << 3) | ((_b2) << 2) | \
((_b1) << 1) | ((_b0) << 0))
-static void Get_lmd(IRTemp * lmd, IRExpr * gfield_0_4 )
+static IRExpr * Gfield_encoding( IRExpr * lmexp, IRExpr * lmd32 )
{
+ IRTemp lmd_07_mask = newTemp( Ity_I32 );
+ IRTemp lmd_8_mask = newTemp( Ity_I32 );
+ IRTemp lmd_9_mask = newTemp( Ity_I32 );
+ IRTemp lmexp_00_mask = newTemp( Ity_I32 );
+ IRTemp lmexp_01_mask = newTemp( Ity_I32 );
+ IRTemp lmexp_10_mask = newTemp( Ity_I32 );
+ IRTemp lmd_07_val = newTemp( Ity_I32 );
+ IRTemp lmd_8_val = newTemp( Ity_I32 );
+ IRTemp lmd_9_val = newTemp( Ity_I32 );
+
+ /* The encodig is as follows:
+ * lmd - left most digit
+ * lme - left most 2-bits of the exponent
+ *
+ * lmd
+ * 0 - 7 (lmexp << 3) | lmd
+ * 8 0b11000 (24 decimal) if lme=0b00;
+ * 0b11010 (26 decimal) if lme=0b01;
+ * 0b11100 (28 decimal) if lme=0b10;
+ * 9 0b11001 (25 decimal) if lme=0b00;
+ * 0b11011 (27 decimal) if lme=0b01;
+ * 0b11101 (29 decimal) if lme=0b10;
+ */
+
+ /* Generate the masks for each condition */
+ assign( lmd_07_mask,
+ unop( Iop_1Sto32, binop( Iop_CmpLE32U, lmd32, mkU32( 7 ) ) ) );
+ assign( lmd_8_mask,
+ unop( Iop_1Sto32, binop( Iop_CmpEQ32, lmd32, mkU32( 8 ) ) ) );
+ assign( lmd_9_mask,
+ unop( Iop_1Sto32, binop( Iop_CmpEQ32, lmd32, mkU32( 9 ) ) ) );
+ assign( lmexp_00_mask,
+ unop( Iop_1Sto32, binop( Iop_CmpEQ32, lmexp, mkU32( 0 ) ) ) );
+ assign( lmexp_01_mask,
+ unop( Iop_1Sto32, binop( Iop_CmpEQ32, lmexp, mkU32( 1 ) ) ) );
+ assign( lmexp_10_mask,
+ unop( Iop_1Sto32, binop( Iop_CmpEQ32, lmexp, mkU32( 2 ) ) ) );
+ /* Generate the values for each LMD condition, assuming the condition
+ * is TRUE.
+ */
+ assign( lmd_07_val,
+ binop( Iop_Or32, binop( Iop_Shl32, lmexp, mkU8( 3 ) ), lmd32 ) );
+ assign( lmd_8_val,
+ binop( Iop_Or32,
+ binop( Iop_Or32,
+ binop( Iop_And32,
+ mkexpr( lmexp_00_mask ),
+ mkU32( 24 ) ),
+ binop( Iop_And32,
+ mkexpr( lmexp_01_mask ),
+ mkU32( 26 ) ) ),
+ binop( Iop_And32, mkexpr( lmexp_10_mask ), mkU32( 28 ) ) ) );
+ assign( lmd_9_val,
+ binop( Iop_Or32,
+ binop( Iop_Or32,
+ binop( Iop_And32,
+ mkexpr( lmexp_00_mask ),
+ mkU32( 25 ) ),
+ binop( Iop_And32,
+ mkexpr( lmexp_01_mask ),
+ mkU32( 27 ) ) ),
+ binop( Iop_And32, mkexpr( lmexp_10_mask ), mkU32( 29 ) ) ) );
+
+ /* generate the result from the possible LMD values */
+ return binop( Iop_Or32,
+ binop( Iop_Or32,
+ binop( Iop_And32,
+ mkexpr( lmd_07_mask ),
+ mkexpr( lmd_07_val ) ),
+ binop( Iop_And32,
+ mkexpr( lmd_8_mask ),
+ mkexpr( lmd_8_val ) ) ),
+ binop( Iop_And32, mkexpr( lmd_9_mask ), mkexpr( lmd_9_val ) ) );
+}
+
+static void Get_lmd( IRTemp * lmd, IRExpr * gfield_0_4 )
+{
/* Extract the exponent and the left most digit of the mantissa
* from the G field bits [0:4].
*/
) ) );
}
+#define DIGIT1_SHR 4 // shift digit 1 to bottom 4 bits
+#define DIGIT2_SHR 8 // shift digit 2 to bottom 4 bits
+#define DIGIT3_SHR 12
+#define DIGIT4_SHR 16
+#define DIGIT5_SHR 20
+#define DIGIT6_SHR 24
+#define DIGIT7_SHR 28
+
+static IRExpr * bcd_digit_inval( IRExpr * bcd_u, IRExpr * bcd_l )
+{
+ /* 60-bit BCD string stored in two 32-bit values. Check that each,
+ * digit is a valid BCD number, i.e. less then 9.
+ */
+ IRTemp valid = newTemp( Ity_I32 );
+
+ assign( valid,
+ AND4( AND4 ( unop( Iop_1Sto32,
+ binop( Iop_CmpLE32U,
+ binop( Iop_And32,
+ bcd_l,
+ mkU32 ( 0xF ) ),
+ mkU32( 0x9 ) ) ),
+ unop( Iop_1Sto32,
+ binop( Iop_CmpLE32U,
+ binop( Iop_And32,
+ binop( Iop_Shr32,
+ bcd_l,
+ mkU8 ( DIGIT1_SHR ) ),
+ mkU32 ( 0xF ) ),
+ mkU32( 0x9 ) ) ),
+ unop( Iop_1Sto32,
+ binop( Iop_CmpLE32U,
+ binop( Iop_And32,
+ binop( Iop_Shr32,
+ bcd_l,
+ mkU8 ( DIGIT2_SHR ) ),
+ mkU32 ( 0xF ) ),
+ mkU32( 0x9 ) ) ),
+ unop( Iop_1Sto32,
+ binop( Iop_CmpLE32U,
+ binop( Iop_And32,
+ binop( Iop_Shr32,
+ bcd_l,
+ mkU8 ( DIGIT3_SHR ) ),
+ mkU32 ( 0xF ) ),
+ mkU32( 0x9 ) ) ) ),
+ AND4 ( unop( Iop_1Sto32,
+ binop( Iop_CmpLE32U,
+ binop( Iop_And32,
+ binop( Iop_Shr32,
+ bcd_l,
+ mkU8 ( DIGIT4_SHR ) ),
+ mkU32 ( 0xF ) ),
+ mkU32( 0x9 ) ) ),
+ unop( Iop_1Sto32,
+ binop( Iop_CmpLE32U,
+ binop( Iop_And32,
+ binop( Iop_Shr32,
+ bcd_l,
+ mkU8 ( DIGIT5_SHR ) ),
+ mkU32 ( 0xF ) ),
+ mkU32( 0x9 ) ) ),
+ unop( Iop_1Sto32,
+ binop( Iop_CmpLE32U,
+ binop( Iop_And32,
+ binop( Iop_Shr32,
+ bcd_l,
+ mkU8 ( DIGIT6_SHR ) ),
+ mkU32 ( 0xF ) ),
+ mkU32( 0x9 ) ) ),
+ unop( Iop_1Sto32,
+ binop( Iop_CmpLE32U,
+ binop( Iop_And32,
+ binop( Iop_Shr32,
+ bcd_l,
+ mkU8 ( DIGIT7_SHR ) ),
+ mkU32 ( 0xF ) ),
+ mkU32( 0x9 ) ) ) ),
+ AND4( unop( Iop_1Sto32,
+ binop( Iop_CmpLE32U,
+ binop( Iop_And32,
+ bcd_u,
+ mkU32 ( 0xF ) ),
+ mkU32( 0x9 ) ) ),
+ unop( Iop_1Sto32,
+ binop( Iop_CmpLE32U,
+ binop( Iop_And32,
+ binop( Iop_Shr32,
+ bcd_u,
+ mkU8 ( DIGIT1_SHR ) ),
+ mkU32 ( 0xF ) ),
+ mkU32( 0x9 ) ) ),
+ unop( Iop_1Sto32,
+ binop( Iop_CmpLE32U,
+ binop( Iop_And32,
+ binop( Iop_Shr32,
+ bcd_u,
+ mkU8 ( DIGIT2_SHR ) ),
+ mkU32 ( 0xF ) ),
+ mkU32( 0x9 ) ) ),
+ unop( Iop_1Sto32,
+ binop( Iop_CmpLE32U,
+ binop( Iop_And32,
+ binop( Iop_Shr32,
+ bcd_u,
+ mkU8 ( DIGIT3_SHR ) ),
+ mkU32 ( 0xF ) ),
+ mkU32( 0x9 ) ) ) ),
+ AND4( unop( Iop_1Sto32,
+ binop( Iop_CmpLE32U,
+ binop( Iop_And32,
+ binop( Iop_Shr32,
+ bcd_u,
+ mkU8 ( DIGIT4_SHR ) ),
+ mkU32 ( 0xF ) ),
+ mkU32( 0x9 ) ) ),
+ unop( Iop_1Sto32,
+ binop( Iop_CmpLE32U,
+ binop( Iop_And32,
+ binop( Iop_Shr32,
+ bcd_u,
+ mkU8 ( DIGIT5_SHR ) ),
+ mkU32 ( 0xF ) ),
+ mkU32( 0x9 ) ) ),
+ unop( Iop_1Sto32,
+ binop( Iop_CmpLE32U,
+ binop( Iop_And32,
+ binop( Iop_Shr32,
+ bcd_u,
+ mkU8 ( DIGIT6_SHR ) ),
+ mkU32 ( 0xF ) ),
+ mkU32( 0x9 ) ) ),
+ unop( Iop_1Sto32,
+ binop( Iop_CmpLE32U,
+ binop( Iop_And32,
+ binop( Iop_Shr32,
+ bcd_u,
+ mkU8 ( DIGIT7_SHR ) ),
+ mkU32 ( 0xF ) ),
+ mkU32( 0x9 ) ) ) ) ) );
+
+ return unop( Iop_Not32, mkexpr( valid ) );
+}
+#undef DIGIT1_SHR
+#undef DIGIT2_SHR
+#undef DIGIT3_SHR
+#undef DIGIT4_SHR
+#undef DIGIT5_SHR
+#undef DIGIT6_SHR
+#undef DIGIT7_SHR
+
+static IRExpr * Generate_neg_sign_mask( IRExpr * sign )
+{
+ return binop( Iop_Or32,
+ unop( Iop_1Sto32, binop( Iop_CmpEQ32, sign, mkU32( 0xB ) ) ),
+ unop( Iop_1Sto32, binop( Iop_CmpEQ32, sign, mkU32( 0xD ) ) )
+ );
+}
+
+static IRExpr * Generate_pos_sign_mask( IRExpr * sign )
+{
+ return binop( Iop_Or32,
+ binop( Iop_Or32,
+ unop( Iop_1Sto32,
+ binop( Iop_CmpEQ32, sign, mkU32( 0xA ) ) ),
+ unop( Iop_1Sto32,
+ binop( Iop_CmpEQ32, sign, mkU32( 0xC ) ) ) ),
+ binop( Iop_Or32,
+ unop( Iop_1Sto32,
+ binop( Iop_CmpEQ32, sign, mkU32( 0xE ) ) ),
+ unop( Iop_1Sto32,
+ binop( Iop_CmpEQ32, sign, mkU32( 0xF ) ) ) ) );
+}
+
+static IRExpr * Generate_sign_bit( IRExpr * pos_sign_mask,
+ IRExpr * neg_sign_mask )
+{
+ return binop( Iop_Or32,
+ binop( Iop_And32, neg_sign_mask, mkU32( 0x80000000 ) ),
+ binop( Iop_And32, pos_sign_mask, mkU32( 0x00000000 ) ) );
+}
+
+static IRExpr * Generate_inv_mask( IRExpr * invalid_bcd_mask,
+ IRExpr * pos_sign_mask,
+ IRExpr * neg_sign_mask )
+/* first argument is all 1's if the BCD string had an invalid digit in it. */
+{
+ return binop( Iop_Or32,
+ invalid_bcd_mask,
+ unop( Iop_1Sto32,
+ binop( Iop_CmpEQ32,
+ binop( Iop_Or32, pos_sign_mask, neg_sign_mask ),
+ mkU32( 0x0 ) ) ) );
+}
+
+static void Generate_132_bit_bcd_string( IRExpr * frBI64_hi, IRExpr * frBI64_lo,
+ IRTemp * top_12_l, IRTemp * mid_60_u,
+ IRTemp * mid_60_l, IRTemp * low_60_u,
+ IRTemp * low_60_l)
+{
+ IRTemp tmplow60 = newTemp( Ity_I64 );
+ IRTemp tmpmid60 = newTemp( Ity_I64 );
+ IRTemp tmptop12 = newTemp( Ity_I64 );
+ IRTemp low_50 = newTemp( Ity_I64 );
+ IRTemp mid_50 = newTemp( Ity_I64 );
+ IRTemp top_10 = newTemp( Ity_I64 );
+ IRTemp top_12_u = newTemp( Ity_I32 ); // only needed for a dummy arg
+
+ /* Convert the 110-bit densely packed BCD string to a 128-bit BCD string */
+
+ /* low_50[49:0] = ((frBI64_lo[49:32] << 14) | frBI64_lo[31:0]) */
+ assign( low_50,
+ binop( Iop_32HLto64,
+ binop( Iop_And32,
+ unop( Iop_64HIto32, frBI64_lo ),
+ mkU32( 0x3FFFF ) ),
+ unop( Iop_64to32, frBI64_lo ) ) );
+
+ /* Convert the 50 bit densely packed BCD string to a 60 bit
+ * BCD string.
+ */
+ assign( tmplow60, unop( Iop_DPBtoBCD, mkexpr( low_50 ) ) );
+ assign( *low_60_u, unop( Iop_64HIto32, mkexpr( tmplow60 ) ) );
+ assign( *low_60_l, unop( Iop_64to32, mkexpr( tmplow60 ) ) );
+
+ /* mid_50[49:0] = ((frBI64_hi[35:32] << 14) | frBI64_hi[31:18]) |
+ * ((frBI64_hi[17:0] << 14) | frBI64_lo[63:50])
+ */
+ assign( mid_50,
+ binop( Iop_32HLto64,
+ binop( Iop_Or32,
+ binop( Iop_Shl32,
+ binop( Iop_And32,
+ unop( Iop_64HIto32, frBI64_hi ),
+ mkU32( 0xF ) ),
+ mkU8( 14 ) ),
+ binop( Iop_Shr32,
+ unop( Iop_64to32, frBI64_hi ),
+ mkU8( 18 ) ) ),
+ binop( Iop_Or32,
+ binop( Iop_Shl32,
+ unop( Iop_64to32, frBI64_hi ),
+ mkU8( 14 ) ),
+ binop( Iop_Shr32,
+ unop( Iop_64HIto32, frBI64_lo ),
+ mkU8( 18 ) ) ) ) );
+
+ /* Convert the 50 bit densely packed BCD string to a 60 bit
+ * BCD string.
+ */
+ assign( tmpmid60, unop( Iop_DPBtoBCD, mkexpr( mid_50 ) ) );
+ assign( *mid_60_u, unop( Iop_64HIto32, mkexpr( tmpmid60 ) ) );
+ assign( *mid_60_l, unop( Iop_64to32, mkexpr( tmpmid60 ) ) );
+
+ /* top_10[49:0] = frBI64_hi[45:36]) | */
+ assign( top_10,
+ binop( Iop_32HLto64,
+ mkU32( 0 ),
+ binop( Iop_And32,
+ binop( Iop_Shr32,
+ unop( Iop_64HIto32, frBI64_hi ),
+ mkU8( 4 ) ),
+ mkU32( 0x3FF ) ) ) );
+
+ /* Convert the 10 bit densely packed BCD string to a 12 bit
+ * BCD string.
+ */
+ assign( tmptop12, unop( Iop_DPBtoBCD, mkexpr( top_10 ) ) );
+ assign( top_12_u, unop( Iop_64HIto32, mkexpr( tmptop12 ) ) );
+ assign( *top_12_l, unop( Iop_64to32, mkexpr( tmptop12 ) ) );
+}
+
+static void Count_zeros( int start, IRExpr * init_cnt, IRExpr * init_flag,
+ IRTemp * final_cnt, IRTemp * final_flag,
+ IRExpr * string )
+{
+ IRTemp cnt[MAX_DIGITS_IN_STRING + 1];IRTemp flag[MAX_DIGITS_IN_STRING+1];
+ int digits = MAX_DIGITS_IN_STRING;
+ int i;
+
+ cnt[start-1] = newTemp( Ity_I8 );
+ flag[start-1] = newTemp( Ity_I8 );
+ assign( cnt[start-1], init_cnt);
+ assign( flag[start-1], init_flag);
+
+ for ( i = start; i <= digits; i++) {
+ cnt[i] = newTemp( Ity_I8 );
+ flag[i] = newTemp( Ity_I8 );
+ assign( cnt[i],
+ binop( Iop_Add8,
+ mkexpr( cnt[i-1] ),
+ binop(Iop_And8,
+ unop( Iop_1Uto8,
+ binop(Iop_CmpEQ32,
+ binop(Iop_And32,
+ string,
+ mkU32( 0xF <<
+ ( ( digits - i ) * 4) ) ),
+ mkU32( 0 ) ) ),
+ binop( Iop_Xor8, /* complement flag */
+ mkexpr( flag[i - 1] ),
+ mkU8( 0xFF ) ) ) ) );
+
+ /* set flag to 1 if digit was not a zero */
+ assign( flag[i],
+ binop(Iop_Or8,
+ unop( Iop_1Sto8,
+ binop(Iop_CmpNE32,
+ binop(Iop_And32,
+ string,
+ mkU32( 0xF <<
+ ( (digits - i) * 4) ) ),
+ mkU32( 0 ) ) ),
+ mkexpr( flag[i - 1] ) ) );
+ }
+
+ *final_cnt = cnt[digits];
+ *final_flag = flag[digits];
+}
+
+static IRExpr * Count_leading_zeros_60( IRExpr * lmd, IRExpr * upper_28,
+ IRExpr * low_32 )
+{
+ IRTemp num_lmd = newTemp( Ity_I8 );
+ IRTemp num_upper = newTemp( Ity_I8 );
+ IRTemp num_low = newTemp( Ity_I8 );
+ IRTemp lmd_flag = newTemp( Ity_I8 );
+ IRTemp upper_flag = newTemp( Ity_I8 );
+ IRTemp low_flag = newTemp( Ity_I8 );
+
+ assign( num_lmd, unop( Iop_1Uto8, binop( Iop_CmpEQ32, lmd, mkU32( 0 ) ) ) );
+ assign( lmd_flag, unop( Iop_Not8, mkexpr( num_lmd ) ) );
+
+ Count_zeros( 2,
+ mkexpr( num_lmd ),
+ mkexpr( lmd_flag ),
+ &num_upper,
+ &upper_flag,
+ upper_28 );
+
+ Count_zeros( 1,
+ mkexpr( num_upper ),
+ mkexpr( upper_flag ),
+ &num_low,
+ &low_flag,
+ low_32 );
+
+ return mkexpr( num_low );
+}
+
+static IRExpr * Count_leading_zeros_128( IRExpr * lmd, IRExpr * top_12_l,
+ IRExpr * mid_60_u, IRExpr * mid_60_l,
+ IRExpr * low_60_u, IRExpr * low_60_l)
+{
+ IRTemp num_lmd = newTemp( Ity_I8 );
+ IRTemp num_top = newTemp( Ity_I8 );
+ IRTemp num_mid_u = newTemp( Ity_I8 );
+ IRTemp num_mid_l = newTemp( Ity_I8 );
+ IRTemp num_low_u = newTemp( Ity_I8 );
+ IRTemp num_low_l = newTemp( Ity_I8 );
+
+ IRTemp lmd_flag = newTemp( Ity_I8 );
+ IRTemp top_flag = newTemp( Ity_I8 );
+ IRTemp mid_u_flag = newTemp( Ity_I8 );
+ IRTemp mid_l_flag = newTemp( Ity_I8 );
+ IRTemp low_u_flag = newTemp( Ity_I8 );
+ IRTemp low_l_flag = newTemp( Ity_I8 );
+
+ /* Check the LMD, digit 16, to see if it is zero. */
+ assign( num_lmd, unop( Iop_1Uto8, binop( Iop_CmpEQ32, lmd, mkU32( 0 ) ) ) );
+
+ assign( lmd_flag, unop( Iop_Not8, mkexpr( num_lmd ) ) );
+
+ Count_zeros( 6,
+ mkexpr( num_lmd ),
+ mkexpr( lmd_flag ),
+ &num_top,
+ &top_flag,
+ top_12_l );
+
+ Count_zeros( 1,
+ mkexpr( num_top ),
+ mkexpr( top_flag ),
+ &num_mid_u,
+ &mid_u_flag,
+ binop( Iop_Or32,
+ binop( Iop_Shl32, mid_60_u, mkU8( 2 ) ),
+ binop( Iop_Shr32, mid_60_l, mkU8( 30 ) ) ) );
+
+ Count_zeros( 2,
+ mkexpr( num_mid_u ),
+ mkexpr( mid_u_flag ),
+ &num_mid_l,
+ &mid_l_flag,
+ mid_60_l );
+
+ Count_zeros( 1,
+ mkexpr( num_mid_l ),
+ mkexpr( mid_l_flag ),
+ &num_low_u,
+ &low_u_flag,
+ binop( Iop_Or32,
+ binop( Iop_Shl32, low_60_u, mkU8( 2 ) ),
+ binop( Iop_Shr32, low_60_l, mkU8( 30 ) ) ) );
+
+ Count_zeros( 2,
+ mkexpr( num_low_u ),
+ mkexpr( low_u_flag ),
+ &num_low_l,
+ &low_l_flag,
+ low_60_l );
+
+ return mkexpr( num_low_l );
+}
+
+static IRExpr * Check_unordered(IRExpr * val)
+{
+ IRTemp gfield0to5 = newTemp( Ity_I32 );
+
+ /* Extract G[0:4] */
+ assign( gfield0to5,
+ binop( Iop_And32,
+ binop( Iop_Shr32, unop( Iop_64HIto32, val ), mkU8( 26 ) ),
+ mkU32( 0x1F ) ) );
+
+ /* Check for unordered, return all 1'x if true */
+ return binop( Iop_Or32, /* QNaN check */
+ unop( Iop_1Sto32,
+ binop( Iop_CmpEQ32,
+ mkexpr( gfield0to5 ),
+ mkU32( 0x1E ) ) ),
+ unop( Iop_1Sto32, /* SNaN check */
+ binop( Iop_CmpEQ32,
+ mkexpr( gfield0to5 ),
+ mkU32( 0x1F ) ) ) );
+}
+
#undef AND
-#undef OR
#undef AND4
+#undef OR
#undef OR3
#undef OR4
+#undef NOT
+#undef SHR
#undef SHL
#undef BITS5
unop( Iop_1Sto32,
binop( Iop_CmpNE32,
mkexpr( lmd ),
- mkU32( 0 ) ) ) ),
+ mkU32( 0 ) ) ) ),
mkU32( 0x1 ) ),
mkU8( 1 ) ) );
return True;
}
+static Bool dis_dfp_bcd(UInt theInstr) {
+ UInt opc2 = ifieldOPClo10( theInstr );
+ ULong sp = IFIELD(theInstr, 19, 2);
+ ULong s = IFIELD(theInstr, 20, 1);
+ UChar frT_addr = ifieldRegDS( theInstr );
+ UChar frB_addr = ifieldRegB( theInstr );
+ IRTemp frB = newTemp( Ity_D64 );
+ IRTemp frBI64 = newTemp( Ity_I64 );
+ IRTemp result = newTemp( Ity_I64 );
+ IRTemp resultD64 = newTemp( Ity_D64 );
+ IRTemp bcd64 = newTemp( Ity_I64 );
+ IRTemp bcd_u = newTemp( Ity_I32 );
+ IRTemp bcd_l = newTemp( Ity_I32 );
+ IRTemp dbcd_u = newTemp( Ity_I32 );
+ IRTemp dbcd_l = newTemp( Ity_I32 );
+ IRTemp lmd = newTemp( Ity_I32 );
+
+ assign( frB, getDReg( frB_addr ) );
+ assign( frBI64, unop( Iop_ReinterpD64asI64, mkexpr( frB ) ) );
+
+ switch ( opc2 ) {
+ case 0x142: // ddedpd DFP Decode DPD to BCD
+ DIP( "ddedpd %llu,r%u,r%u\n", sp, frT_addr, frB_addr );
+
+ assign( bcd64, unop( Iop_DPBtoBCD, mkexpr( frBI64 ) ) );
+ assign( bcd_u, unop( Iop_64HIto32, mkexpr( bcd64 ) ) );
+ assign( bcd_l, unop( Iop_64to32, mkexpr( bcd64 ) ) );
+
+ if ( ( sp == 0 ) || ( sp == 1 ) ) {
+ /* Unsigned BCD string */
+ Get_lmd( &lmd,
+ binop( Iop_Shr32,
+ unop( Iop_64HIto32, mkexpr( frBI64 ) ),
+ mkU8( 31 - 5 ) ) ); // G-field[0:4]
+
+ assign( result,
+ binop( Iop_32HLto64,
+ binop( Iop_Or32,
+ binop( Iop_Shl32, mkexpr( lmd ), mkU8( 28 ) ),
+ mkexpr( bcd_u ) ),
+ mkexpr( bcd_l ) ) );
+
+ } else {
+ /* Signed BCD string, the cases for sp 2 and 3 only differ in how
+ * the positive and negative values are encoded in the least
+ * significant bits.
+ */
+ IRTemp sign = newTemp( Ity_I32 );
+
+ if (sp == 2) {
+ /* Positive sign = 0xC, negative sign = 0xD */
+
+ assign( sign,
+ binop( Iop_Or32,
+ binop( Iop_Shr32,
+ unop( Iop_64HIto32, mkexpr( frBI64 ) ),
+ mkU8( 31 ) ),
+ mkU32( 0xC ) ) );
+
+ } else if ( sp == 3 ) {
+ /* Positive sign = 0xF, negative sign = 0xD */
+ IRTemp tmp32 = newTemp( Ity_I32 );
+
+ /* Complement sign bit then OR into bit position 1 */
+ assign( tmp32,
+ binop( Iop_Xor32,
+ binop( Iop_Shr32,
+ unop( Iop_64HIto32, mkexpr( frBI64 ) ),
+ mkU8( 30 ) ),
+ mkU32( 0x2 ) ) );
+
+ assign( sign, binop( Iop_Or32, mkexpr( tmp32 ), mkU32( 0xD ) ) );
+
+ } else {
+ vpanic( "The impossible happened: dis_dfp_bcd(ppc), undefined SP field" );
+ }
+
+ /* Put sign in bottom 4 bits, move most significant 4-bits from
+ * bcd_l to bcd_u.
+ */
+ assign( result,
+ binop( Iop_32HLto64,
+ binop( Iop_Or32,
+ binop( Iop_Shr32,
+ mkexpr( bcd_l ),
+ mkU8( 28 ) ),
+ binop( Iop_Shl32,
+ mkexpr( bcd_u ),
+ mkU8( 4 ) ) ),
+ binop( Iop_Or32,
+ mkexpr( sign ),
+ binop( Iop_Shl32,
+ mkexpr( bcd_l ),
+ mkU8( 4 ) ) ) ) );
+ }
+
+ putDReg( frT_addr, unop( Iop_ReinterpI64asD64, mkexpr( result ) ) );
+ break;
+
+ case 0x342: // denbcd DFP Encode BCD to DPD
+ {
+ IRTemp valid_mask = newTemp( Ity_I32 );
+ IRTemp invalid_mask = newTemp( Ity_I32 );
+ IRTemp without_lmd = newTemp( Ity_I64 );
+ IRTemp tmp64 = newTemp( Ity_I64 );
+ IRTemp dbcd64 = newTemp( Ity_I64 );
+ IRTemp left_exp = newTemp( Ity_I32 );
+ IRTemp g0_4 = newTemp( Ity_I32 );
+
+ DIP( "denbcd %llu,r%u,r%u\n", s, frT_addr, frB_addr );
+
+ if ( s == 0 ) {
+ /* Unsigned BCD string */
+ assign( dbcd64, unop( Iop_BCDtoDPB, mkexpr(frBI64 ) ) );
+ assign( dbcd_u, unop( Iop_64HIto32, mkexpr( dbcd64 ) ) );
+ assign( dbcd_l, unop( Iop_64to32, mkexpr( dbcd64 ) ) );
+
+ assign( lmd,
+ binop( Iop_Shr32,
+ binop( Iop_And32,
+ unop( Iop_64HIto32, mkexpr( frBI64 ) ),
+ mkU32( 0xF0000000 ) ),
+ mkU8( 28 ) ) );
+
+ assign( invalid_mask,
+ bcd_digit_inval( unop( Iop_64HIto32, mkexpr( frBI64 ) ),
+ unop( Iop_64to32, mkexpr( frBI64 ) ) ) );
+ assign( valid_mask, unop( Iop_Not32, mkexpr( invalid_mask ) ) );
+
+ assign( without_lmd,
+ unop( Iop_ReinterpD64asI64,
+ binop( Iop_InsertExpD64,
+ unop( Iop_ReinterpI64asD64,
+ mkU64( DFP_LONG_BIAS ) ),
+ unop( Iop_ReinterpI64asD64,
+ binop( Iop_32HLto64,
+ mkexpr( dbcd_u ),
+ mkexpr( dbcd_l ) ) ) ) ) );
+ assign( left_exp,
+ binop( Iop_Shr32,
+ binop( Iop_And32,
+ unop( Iop_64HIto32, mkexpr( without_lmd ) ),
+ mkU32( 0x60000000 ) ),
+ mkU8( 29 ) ) );
+
+ assign( g0_4,
+ binop( Iop_Shl32,
+ Gfield_encoding( mkexpr( left_exp ), mkexpr( lmd ) ),
+ mkU8( 26 ) ) );
+
+ assign( tmp64,
+ binop( Iop_32HLto64,
+ binop( Iop_Or32,
+ binop( Iop_And32,
+ unop( Iop_64HIto32,
+ mkexpr( without_lmd ) ),
+ mkU32( 0x83FFFFFF ) ),
+ mkexpr( g0_4 ) ),
+ unop( Iop_64to32, mkexpr( without_lmd ) ) ) );
+
+ } else if ( s == 1 ) {
+ IRTemp sign = newTemp( Ity_I32 );
+ IRTemp sign_bit = newTemp( Ity_I32 );
+ IRTemp pos_sign_mask = newTemp( Ity_I32 );
+ IRTemp neg_sign_mask = newTemp( Ity_I32 );
+ IRTemp tmp = newTemp( Ity_I64 );
+
+ /* Signed BCD string, least significant 4 bits are sign bits
+ * positive sign = 0xC, negative sign = 0xD
+ */
+ assign( tmp, unop( Iop_BCDtoDPB,
+ binop( Iop_32HLto64,
+ binop( Iop_Shr32,
+ unop( Iop_64HIto32,
+ mkexpr( frBI64 ) ),
+ mkU8( 4 ) ),
+ binop( Iop_Or32,
+ binop( Iop_Shr32,
+ unop( Iop_64to32,
+ mkexpr( frBI64 ) ),
+ mkU8( 4 ) ),
+ binop( Iop_Shl32,
+ unop( Iop_64HIto32,
+ mkexpr( frBI64 ) ),
+ mkU8( 28 ) ) ) ) ) );
+
+ assign( dbcd_u, unop( Iop_64HIto32, mkexpr( tmp ) ) );
+ assign( dbcd_l, unop( Iop_64to32, mkexpr( tmp ) ) );
+
+ /* Get the sign of the BCD string. */
+ assign( sign,
+ binop( Iop_And32,
+ unop( Iop_64to32, mkexpr( frBI64 ) ),
+ mkU32( 0xF ) ) );
+
+ assign( neg_sign_mask, Generate_neg_sign_mask( mkexpr( sign ) ) );
+ assign( pos_sign_mask, Generate_pos_sign_mask( mkexpr( sign ) ) );
+ assign( sign_bit,
+ Generate_sign_bit( mkexpr( pos_sign_mask ),
+ mkexpr( neg_sign_mask ) ) );
+
+ /* Check for invalid sign and BCD digit. Don't check the bottom
+ * four bits of bcd_l as that is the sign value.
+ */
+ assign( invalid_mask,
+ Generate_inv_mask(
+ bcd_digit_inval( unop( Iop_64HIto32,
+ mkexpr( frBI64 ) ),
+ binop( Iop_Shr32,
+ unop( Iop_64to32,
+ mkexpr( frBI64 ) ),
+ mkU8( 4 ) ) ),
+ mkexpr( pos_sign_mask ),
+ mkexpr( neg_sign_mask ) ) );
+
+ assign( valid_mask, unop( Iop_Not32, mkexpr( invalid_mask ) ) );
+
+ /* Generate the result assuming the sign value was valid. */
+ assign( tmp64,
+ unop( Iop_ReinterpD64asI64,
+ binop( Iop_InsertExpD64,
+ unop( Iop_ReinterpI64asD64,
+ mkU64( DFP_LONG_BIAS ) ),
+ unop( Iop_ReinterpI64asD64,
+ binop( Iop_32HLto64,
+ binop( Iop_Or32,
+ mkexpr( dbcd_u ),
+ mkexpr( sign_bit ) ),
+ mkexpr( dbcd_l ) ) ) ) ) );
+ }
+
+ /* Generate the value to store depending on the validity of the
+ * sign value and the validity of the BCD digits.
+ */
+ assign( resultD64,
+ unop( Iop_ReinterpI64asD64,
+ binop( Iop_32HLto64,
+ binop( Iop_Or32,
+ binop( Iop_And32,
+ mkexpr( valid_mask ),
+ unop( Iop_64HIto32,
+ mkexpr( tmp64 ) ) ),
+ binop( Iop_And32,
+ mkU32( 0x7C000000 ),
+ mkexpr( invalid_mask ) ) ),
+ binop( Iop_Or32,
+ binop( Iop_And32,
+ mkexpr( valid_mask ),
+ unop( Iop_64to32, mkexpr( tmp64 ) ) ),
+ binop( Iop_And32,
+ mkU32( 0x0 ),
+ mkexpr( invalid_mask ) ) ) ) ) );
+ putDReg( frT_addr, mkexpr( resultD64 ) );
+ }
+ break;
+ default:
+ vpanic( "ERROR: dis_dfp_bcd(ppc), undefined opc2 case " );
+ return False;
+ }
+ return True;
+}
+
+static Bool dis_dfp_bcdq( UInt theInstr )
+{
+ UInt opc2 = ifieldOPClo10( theInstr );
+ ULong sp = IFIELD(theInstr, 19, 2);
+ ULong s = IFIELD(theInstr, 20, 1);
+ IRTemp frB_hi = newTemp( Ity_D64 );
+ IRTemp frB_lo = newTemp( Ity_D64 );
+ IRTemp frBI64_hi = newTemp( Ity_I64 );
+ IRTemp frBI64_lo = newTemp( Ity_I64 );
+ UChar frT_addr = ifieldRegDS( theInstr );
+ UChar frB_addr = ifieldRegB( theInstr );
+
+ IRTemp lmd = newTemp( Ity_I32 );
+ IRTemp result_hi = newTemp( Ity_I64 );
+ IRTemp result_lo = newTemp( Ity_I64 );
+
+ assign( frB_hi, getDReg( frB_addr ) );
+ assign( frB_lo, getDReg( frB_addr + 1 ) );
+ assign( frBI64_hi, unop( Iop_ReinterpD64asI64, mkexpr( frB_hi ) ) );
+ assign( frBI64_lo, unop( Iop_ReinterpD64asI64, mkexpr( frB_lo ) ) );
+
+ switch ( opc2 ) {
+ case 0x142: // ddedpdq DFP Decode DPD to BCD
+ {
+ IRTemp low_60_u = newTemp( Ity_I32 );
+ IRTemp low_60_l = newTemp( Ity_I32 );
+ IRTemp mid_60_u = newTemp( Ity_I32 );
+ IRTemp mid_60_l = newTemp( Ity_I32 );
+ IRTemp top_12_l = newTemp( Ity_I32 );
+
+ DIP( "ddedpdq %llu,r%u,r%u\n", sp, frT_addr, frB_addr );
+
+ /* Note, instruction only stores the lower 32 BCD digits in
+ * the result
+ */
+ Generate_132_bit_bcd_string( mkexpr( frBI64_hi ),
+ mkexpr( frBI64_lo ),
+ &top_12_l,
+ &mid_60_u,
+ &mid_60_l,
+ &low_60_u,
+ &low_60_l );
+
+ if ( ( sp == 0 ) || ( sp == 1 ) ) {
+ /* Unsigned BCD string */
+ assign( result_hi,
+ binop( Iop_32HLto64,
+ binop( Iop_Or32,
+ binop( Iop_Shl32,
+ mkexpr( top_12_l ),
+ mkU8( 24 ) ),
+ binop( Iop_Shr32,
+ mkexpr( mid_60_u ),
+ mkU8( 4 ) ) ),
+ binop( Iop_Or32,
+ binop( Iop_Shl32,
+ mkexpr( mid_60_u ),
+ mkU8( 28 ) ),
+ binop( Iop_Shr32,
+ mkexpr( mid_60_l ),
+ mkU8( 4 ) ) ) ) );
+
+ assign( result_lo,
+ binop( Iop_32HLto64,
+ binop( Iop_Or32,
+ binop( Iop_Shl32,
+ mkexpr( mid_60_l ),
+ mkU8( 28 ) ),
+ mkexpr( low_60_u ) ),
+ mkexpr( low_60_l ) ) );
+
+ } else {
+ /* Signed BCD string, the cases for sp 2 and 3 only differ in how
+ * the positive and negative values are encoded in the least
+ * significant bits.
+ */
+ IRTemp sign = newTemp( Ity_I32 );
+
+ if ( sp == 2 ) {
+ /* Positive sign = 0xC, negative sign = 0xD */
+ assign( sign,
+ binop( Iop_Or32,
+ binop( Iop_Shr32,
+ unop( Iop_64HIto32, mkexpr( frBI64_hi ) ),
+ mkU8( 31 ) ),
+ mkU32( 0xC ) ) );
+
+ } else if ( sp == 3 ) {
+ IRTemp tmp32 = newTemp( Ity_I32 );
+
+ /* Positive sign = 0xF, negative sign = 0xD.
+ * Need to complement sign bit then OR into bit position 1.
+ */
+ assign( tmp32,
+ binop( Iop_Xor32,
+ binop( Iop_Shr32,
+ unop( Iop_64HIto32, mkexpr( frBI64_hi ) ),
+ mkU8( 30 ) ),
+ mkU32( 0x2 ) ) );
+
+ assign( sign, binop( Iop_Or32, mkexpr( tmp32 ), mkU32( 0xD ) ) );
+
+ } else {
+ vpanic( "The impossible happened: dis_dfp_bcd(ppc), undefined SP field" );
+ }
+
+ assign( result_hi,
+ binop( Iop_32HLto64,
+ binop( Iop_Or32,
+ binop( Iop_Shl32,
+ mkexpr( top_12_l ),
+ mkU8( 28 ) ),
+ mkexpr( mid_60_u ) ),
+ mkexpr( mid_60_l ) ) );
+
+ assign( result_lo,
+ binop( Iop_32HLto64,
+ binop( Iop_Or32,
+ binop( Iop_Shl32,
+ mkexpr( low_60_u ),
+ mkU8( 4 ) ),
+ binop( Iop_Shr32,
+ mkexpr( low_60_l ),
+ mkU8( 28 ) ) ),
+ binop( Iop_Or32,
+ binop( Iop_Shl32,
+ mkexpr( low_60_l ),
+ mkU8( 4 ) ),
+ mkexpr( sign ) ) ) );
+ }
+
+ putDReg( frT_addr, unop( Iop_ReinterpI64asD64, mkexpr( result_hi ) ) );
+ putDReg( frT_addr + 1,
+ unop( Iop_ReinterpI64asD64, mkexpr( result_lo ) ) );
+ }
+ break;
+ case 0x342: // denbcdq DFP Encode BCD to DPD
+ {
+ IRTemp valid_mask = newTemp( Ity_I32 );
+ IRTemp invalid_mask = newTemp( Ity_I32 );
+ IRTemp result128 = newTemp( Ity_D128 );
+ IRTemp dfp_significand = newTemp( Ity_D128 );
+ IRTemp tmp_hi = newTemp( Ity_I64 );
+ IRTemp tmp_lo = newTemp( Ity_I64 );
+ IRTemp dbcd_top_l = newTemp( Ity_I32 );
+ IRTemp dbcd_mid_u = newTemp( Ity_I32 );
+ IRTemp dbcd_mid_l = newTemp( Ity_I32 );
+ IRTemp dbcd_low_u = newTemp( Ity_I32 );
+ IRTemp dbcd_low_l = newTemp( Ity_I32 );
+ IRTemp bcd_top_8 = newTemp( Ity_I64 );
+ IRTemp bcd_mid_60 = newTemp( Ity_I64 );
+ IRTemp bcd_low_60 = newTemp( Ity_I64 );
+ IRTemp sign_bit = newTemp( Ity_I32 );
+ IRTemp tmptop10 = newTemp( Ity_I64 );
+ IRTemp tmpmid50 = newTemp( Ity_I64 );
+ IRTemp tmplow50 = newTemp( Ity_I64 );
+ IRTemp inval_bcd_digit_mask = newTemp( Ity_I32 );
+
+ DIP( "denbcd %llu,r%u,r%u\n", s, frT_addr, frB_addr );
+
+ if ( s == 0 ) {
+ /* Unsigned BCD string */
+ assign( sign_bit, mkU32( 0 ) ); // set to zero for unsigned string
+
+ assign( bcd_top_8,
+ binop( Iop_32HLto64,
+ mkU32( 0 ),
+ binop( Iop_And32,
+ binop( Iop_Shr32,
+ unop( Iop_64HIto32,
+ mkexpr( frBI64_hi ) ),
+ mkU8( 24 ) ),
+ mkU32( 0xFF ) ) ) );
+ assign( bcd_mid_60,
+ binop( Iop_32HLto64,
+ binop( Iop_Or32,
+ binop( Iop_Shr32,
+ unop( Iop_64to32,
+ mkexpr( frBI64_hi ) ),
+ mkU8( 28 ) ),
+ binop( Iop_Shl32,
+ unop( Iop_64HIto32,
+ mkexpr( frBI64_hi ) ),
+ mkU8( 4 ) ) ),
+ binop( Iop_Or32,
+ binop( Iop_Shl32,
+ unop( Iop_64to32,
+ mkexpr( frBI64_hi ) ),
+ mkU8( 4 ) ),
+ binop( Iop_Shr32,
+ unop( Iop_64HIto32,
+ mkexpr( frBI64_lo ) ),
+ mkU8( 28 ) ) ) ) );
+
+ /* Note, the various helper functions ignores top 4-bits */
+ assign( bcd_low_60, mkexpr( frBI64_lo ) );
+
+ assign( tmptop10, unop( Iop_BCDtoDPB, mkexpr( bcd_top_8 ) ) );
+ assign( dbcd_top_l, unop( Iop_64to32, mkexpr( tmptop10 ) ) );
+
+ assign( tmpmid50, unop( Iop_BCDtoDPB, mkexpr( bcd_mid_60 ) ) );
+ assign( dbcd_mid_u, unop( Iop_64HIto32, mkexpr( tmpmid50 ) ) );
+ assign( dbcd_mid_l, unop( Iop_64to32, mkexpr( tmpmid50 ) ) );
+
+ assign( tmplow50, unop( Iop_BCDtoDPB, mkexpr( bcd_low_60 ) ) );
+ assign( dbcd_low_u, unop( Iop_64HIto32, mkexpr( tmplow50 ) ) );
+ assign( dbcd_low_l, unop( Iop_64to32, mkexpr( tmplow50 ) ) );
+
+ /* The entire BCD string fits in lower 110-bits. The LMD = 0,
+ * value is not part of the final result. Only the right most
+ * BCD digits are stored.
+ */
+ assign( lmd, mkU32( 0 ) );
+
+ assign( invalid_mask,
+ binop( Iop_Or32,
+ bcd_digit_inval( mkU32( 0 ),
+ unop( Iop_64to32,
+ mkexpr( bcd_top_8 ) ) ),
+ binop( Iop_Or32,
+ bcd_digit_inval( unop( Iop_64HIto32,
+ mkexpr( bcd_mid_60 ) ),
+ unop( Iop_64to32,
+ mkexpr( bcd_mid_60 ) ) ),
+ bcd_digit_inval( unop( Iop_64HIto32,
+ mkexpr( bcd_low_60 ) ),
+ unop( Iop_64to32,
+ mkexpr( bcd_low_60 ) )
+ ) ) ) );
+
+ } else if ( s == 1 ) {
+ IRTemp sign = newTemp( Ity_I32 );
+ IRTemp zero = newTemp( Ity_I32 );
+ IRTemp pos_sign_mask = newTemp( Ity_I32 );
+ IRTemp neg_sign_mask = newTemp( Ity_I32 );
+
+ /* The sign of the BCD string is stored in lower 4 bits */
+ assign( sign,
+ binop( Iop_And32,
+ unop( Iop_64to32, mkexpr( frBI64_lo ) ),
+ mkU32( 0xF ) ) );
+ assign( neg_sign_mask, Generate_neg_sign_mask( mkexpr( sign ) ) );
+ assign( pos_sign_mask, Generate_pos_sign_mask( mkexpr( sign ) ) );
+ assign( sign_bit,
+ Generate_sign_bit( mkexpr( pos_sign_mask ),
+ mkexpr( neg_sign_mask ) ) );
+
+ /* Generate the value assuminig the sign and BCD digits are vaild */
+ assign( bcd_top_8,
+ binop( Iop_32HLto64,
+ mkU32( 0x0 ),
+ binop( Iop_Shr32,
+ unop( Iop_64HIto32, mkexpr( frBI64_hi ) ),
+ mkU8( 28 ) ) ) );
+
+ /* The various helper routines ignore the upper 4-bits */
+ assign( bcd_mid_60, mkexpr( frBI64_hi ) );
+
+ /* Remove bottom four sign bits */
+ assign( bcd_low_60,
+ binop( Iop_32HLto64,
+ binop( Iop_Shr32,
+ unop( Iop_64HIto32,
+ mkexpr( frBI64_lo ) ),
+ mkU8( 4 ) ),
+ binop( Iop_Or32,
+ binop( Iop_Shl32,
+ unop( Iop_64HIto32,
+ mkexpr( frBI64_lo ) ),
+ mkU8( 28 ) ),
+ binop( Iop_Shr32,
+ unop( Iop_64to32,
+ mkexpr( frBI64_lo ) ),
+ mkU8( 4 ) ) ) ) );
+ assign( tmptop10, unop( Iop_BCDtoDPB, mkexpr(bcd_top_8 ) ) );
+ assign( dbcd_top_l, unop( Iop_64to32, mkexpr( tmptop10 ) ) );
+
+ assign( tmpmid50, unop( Iop_BCDtoDPB, mkexpr(bcd_mid_60 ) ) );
+ assign( dbcd_mid_u, unop( Iop_64HIto32, mkexpr( tmpmid50 ) ) );
+ assign( dbcd_mid_l, unop( Iop_64to32, mkexpr( tmpmid50 ) ) );
+
+ assign( tmplow50, unop( Iop_BCDtoDPB, mkexpr( bcd_low_60 ) ) );
+ assign( dbcd_low_u, unop( Iop_64HIto32, mkexpr( tmplow50 ) ) );
+ assign( dbcd_low_l, unop( Iop_64to32, mkexpr( tmplow50 ) ) );
+
+ /* The entire BCD string fits in lower 110-bits. The LMD value
+ * is not stored in the final result for the DFP Long instruction.
+ */
+ assign( lmd, mkU32( 0 ) );
+
+ /* Check for invalid sign and invalid BCD digit. Don't check the
+ * bottom four bits of frBI64_lo as that is the sign value.
+ */
+ assign( zero, mkU32( 0 ) );
+ assign( inval_bcd_digit_mask,
+ binop( Iop_Or32,
+ bcd_digit_inval( mkexpr( zero ),
+ unop( Iop_64to32,
+ mkexpr( bcd_top_8 ) ) ),
+ binop( Iop_Or32,
+ bcd_digit_inval( unop( Iop_64HIto32,
+ mkexpr( bcd_mid_60 ) ),
+ unop( Iop_64to32,
+ mkexpr( bcd_mid_60 ) ) ),
+ bcd_digit_inval( unop( Iop_64HIto32,
+ mkexpr( frBI64_lo ) ),
+ binop( Iop_Shr32,
+ unop( Iop_64to32,
+ mkexpr( frBI64_lo ) ),
+ mkU8( 4 ) ) ) ) ) );
+ assign( invalid_mask,
+ Generate_inv_mask( mkexpr( inval_bcd_digit_mask ),
+ mkexpr( pos_sign_mask ),
+ mkexpr( neg_sign_mask ) ) );
+
+ }
+
+ assign( valid_mask, unop( Iop_Not32, mkexpr( invalid_mask ) ) );
+
+ /* Calculate the value of the result assuming sign and BCD digits
+ * are all valid.
+ */
+ assign( dfp_significand,
+ binop( Iop_D64HLtoD128,
+ unop( Iop_ReinterpI64asD64,
+ binop( Iop_32HLto64,
+ binop( Iop_Or32,
+ mkexpr( sign_bit ),
+ mkexpr( dbcd_top_l ) ),
+ binop( Iop_Or32,
+ binop( Iop_Shl32,
+ mkexpr( dbcd_mid_u ),
+ mkU8( 18 ) ),
+ binop( Iop_Shr32,
+ mkexpr( dbcd_mid_l ),
+ mkU8( 14 ) ) ) ) ),
+ unop( Iop_ReinterpI64asD64,
+ binop( Iop_32HLto64,
+ binop( Iop_Or32,
+ mkexpr( dbcd_low_u ),
+ binop( Iop_Shl32,
+ mkexpr( dbcd_mid_l ),
+ mkU8( 18 ) ) ),
+ mkexpr( dbcd_low_l ) ) ) ) );
+
+ /* Break the result back down to 32-bit chunks and replace chunks.
+ * If there was an invalid BCD digit or invalid sign value, replace
+ * the calculated result with the invalid bit string.
+ */
+ assign( result128,
+ binop( Iop_InsertExpD128,
+ unop( Iop_ReinterpI64asD64, mkU64( DFP_EXTND_BIAS ) ),
+ mkexpr( dfp_significand ) ) );
+
+ assign( tmp_hi,
+ unop( Iop_ReinterpD64asI64,
+ unop( Iop_D128HItoD64, mkexpr( result128 ) ) ) );
+
+ assign( tmp_lo,
+ unop( Iop_ReinterpD64asI64,
+ unop( Iop_D128LOtoD64, mkexpr( result128 ) ) ) );
+
+ assign( result_hi,
+ binop( Iop_32HLto64,
+ binop( Iop_Or32,
+ binop( Iop_And32,
+ mkexpr( valid_mask ),
+ unop( Iop_64HIto32, mkexpr( tmp_hi ) ) ),
+ binop( Iop_And32,
+ mkU32( 0x7C000000 ),
+ mkexpr( invalid_mask ) ) ),
+ binop( Iop_Or32,
+ binop( Iop_And32,
+ mkexpr( valid_mask ),
+ unop( Iop_64to32, mkexpr( tmp_hi ) ) ),
+ binop( Iop_And32,
+ mkU32( 0x0 ),
+ mkexpr( invalid_mask ) ) ) ) );
+
+ assign( result_lo,
+ binop( Iop_32HLto64,
+ binop( Iop_Or32,
+ binop( Iop_And32,
+ mkexpr( valid_mask ),
+ unop( Iop_64HIto32, mkexpr( tmp_lo ) ) ),
+ binop( Iop_And32,
+ mkU32( 0x0 ),
+ mkexpr( invalid_mask ) ) ),
+ binop( Iop_Or32,
+ binop( Iop_And32,
+ mkexpr( valid_mask ),
+ unop( Iop_64to32, mkexpr( tmp_lo ) ) ),
+ binop( Iop_And32,
+ mkU32( 0x0 ),
+ mkexpr( invalid_mask ) ) ) ) );
+
+ putDReg( frT_addr, unop( Iop_ReinterpI64asD64, mkexpr( result_hi ) ) );
+ putDReg( frT_addr + 1,
+ unop( Iop_ReinterpI64asD64, mkexpr( result_lo ) ) );
+
+ }
+ break;
+ default:
+ vpanic( "ERROR: dis_dfp_bcdq(ppc), undefined opc2 case " );
+ break;
+ }
+ return True;
+}
+
+static Bool dis_dfp_significant_digits( UInt theInstr )
+{
+ UChar frA_addr = ifieldRegA( theInstr );
+ UChar frB_addr = ifieldRegB( theInstr );
+ IRTemp frA = newTemp( Ity_D64 );
+ UInt opc1 = ifieldOPC( theInstr );
+ IRTemp B_sig = newTemp( Ity_I8 );
+ IRTemp K = newTemp( Ity_I8 );
+ IRTemp lmd_B = newTemp( Ity_I32 );
+ IRTemp field = newTemp( Ity_I32 );
+ UChar crfD = toUChar( IFIELD( theInstr, 23, 3 ) ); // AKA BF
+ IRTemp Unordered_true = newTemp( Ity_I32 );
+ IRTemp Eq_true_mask = newTemp( Ity_I32 );
+ IRTemp Lt_true_mask = newTemp( Ity_I32 );
+ IRTemp Gt_true_mask = newTemp( Ity_I32 );
+ IRTemp KisZero_true_mask = newTemp( Ity_I32 );
+ IRTemp KisZero_false_mask = newTemp( Ity_I32 );
+
+ /* Get the reference singificance stored in frA */
+ assign( frA, getDReg( frA_addr ) );
+
+ /* Convert from 64 bit to 8 bits in two steps. The Iop_64to8 is not
+ * supported in 32-bit mode.
+ */
+ assign( K, unop( Iop_32to8,
+ binop( Iop_And32,
+ unop( Iop_64to32,
+ unop( Iop_ReinterpD64asI64,
+ mkexpr( frA ) ) ),
+ mkU32( 0x3F ) ) ) );
+
+ switch ( opc1 ) {
+ case 0x3b: // dtstsf DFP Test Significance
+ {
+ IRTemp frB = newTemp( Ity_D64 );
+ IRTemp frBI64 = newTemp( Ity_I64 );
+ IRTemp B_bcd_u = newTemp( Ity_I32 );
+ IRTemp B_bcd_l = newTemp( Ity_I32 );
+ IRTemp tmp64 = newTemp( Ity_I64 );
+
+ DIP( "dtstsf %u,r%u,r%u\n", crfD, frA_addr, frB_addr );
+
+ assign( frB, getDReg( frB_addr ) );
+ assign( frBI64, unop( Iop_ReinterpD64asI64, mkexpr( frB ) ) );
+
+ /* Get the BCD string for the value stored in a series of I32 values.
+ * Count the number of leading zeros. Subtract the number of leading
+ * zeros from 16 (maximum number of significant digits in DFP
+ * Long).
+ */
+ Get_lmd( &lmd_B,
+ binop( Iop_Shr32,
+ unop( Iop_64HIto32, mkexpr( frBI64 ) ),
+ mkU8( 31 - 5 ) ) ); // G-field[0:4]
+
+ assign( tmp64, unop( Iop_DPBtoBCD, mkexpr( frBI64 ) ) );
+ assign( B_bcd_u, unop( Iop_64HIto32, mkexpr( tmp64 ) ) );
+ assign( B_bcd_l, unop( Iop_64to32, mkexpr( tmp64 ) ) );
+
+ assign( B_sig,
+ binop( Iop_Sub8,
+ mkU8( DFP_LONG_MAX_SIG_DIGITS ),
+ Count_leading_zeros_60( mkexpr( lmd_B ),
+ mkexpr( B_bcd_u ),
+ mkexpr( B_bcd_l ) ) ) );
+ assign( Unordered_true, Check_unordered( mkexpr( frBI64 ) ) );
+ }
+ break;
+ case 0x3F: // dtstsfq DFP Test Significance
+ {
+ IRTemp frB_hi = newTemp( Ity_D64 );
+ IRTemp frB_lo = newTemp( Ity_D64 );
+ IRTemp frBI64_hi = newTemp( Ity_I64 );
+ IRTemp frBI64_lo = newTemp( Ity_I64 );
+ IRTemp B_low_60_u = newTemp( Ity_I32 );
+ IRTemp B_low_60_l = newTemp( Ity_I32 );
+ IRTemp B_mid_60_u = newTemp( Ity_I32 );
+ IRTemp B_mid_60_l = newTemp( Ity_I32 );
+ IRTemp B_top_12_l = newTemp( Ity_I32 );
+
+ DIP( "dtstsfq %u,r%u,r%u\n", crfD, frA_addr, frB_addr );
+
+ assign( frB_hi, getDReg( frB_addr ) );
+ assign( frB_lo, getDReg( frB_addr + 1 ) );
+
+ assign( frBI64_hi, unop( Iop_ReinterpD64asI64, mkexpr( frB_hi ) ) );
+ assign( frBI64_lo, unop( Iop_ReinterpD64asI64, mkexpr( frB_lo ) ) );
+
+ /* Get the BCD string for the value stored in a series of I32 values.
+ * Count the number of leading zeros. Subtract the number of leading
+ * zeros from 32 (maximum number of significant digits in DFP
+ * extended).
+ */
+ Get_lmd( &lmd_B,
+ binop( Iop_Shr32,
+ unop( Iop_64HIto32, mkexpr( frBI64_hi ) ),
+ mkU8( 31 - 5 ) ) ); // G-field[0:4]
+
+ Generate_132_bit_bcd_string( mkexpr( frBI64_hi ),
+ mkexpr( frBI64_lo ),
+ &B_top_12_l,
+ &B_mid_60_u,
+ &B_mid_60_l,
+ &B_low_60_u,
+ &B_low_60_l );
+
+ assign( B_sig,
+ binop( Iop_Sub8,
+ mkU8( DFP_EXTND_MAX_SIG_DIGITS ),
+ Count_leading_zeros_128( mkexpr( lmd_B ),
+ mkexpr( B_top_12_l ),
+ mkexpr( B_mid_60_u ),
+ mkexpr( B_mid_60_l ),
+ mkexpr( B_low_60_u ),
+ mkexpr( B_low_60_l ) ) ) );
+
+ assign( Unordered_true, Check_unordered( mkexpr( frBI64_hi ) ) );
+ }
+ break;
+ }
+
+ /* Compare (16 - cnt[0]) against K and set the condition code field
+ * accordingly.
+ *
+ * The field layout is as follows:
+ *
+ * bit[3:0] Description
+ * 3 K != 0 and K < Number of significant digits if FRB
+ * 2 K != 0 and K > Number of significant digits if FRB OR K = 0
+ * 1 K != 0 and K = Number of significant digits if FRB
+ * 0 K ? Number of significant digits if FRB
+ */
+ assign( Eq_true_mask,
+ unop( Iop_1Sto32,
+ binop( Iop_CmpEQ32,
+ unop( Iop_8Uto32, mkexpr( K ) ),
+ unop( Iop_8Uto32, mkexpr( B_sig ) ) ) ) );
+ assign( Lt_true_mask,
+ unop( Iop_1Sto32,
+ binop( Iop_CmpLT32U,
+ unop( Iop_8Uto32, mkexpr( K ) ),
+ unop( Iop_8Uto32, mkexpr( B_sig ) ) ) ) );
+ assign( Gt_true_mask,
+ unop( Iop_1Sto32,
+ binop( Iop_CmpLT32U,
+ unop( Iop_8Uto32, mkexpr( B_sig ) ),
+ unop( Iop_8Uto32, mkexpr( K ) ) ) ) );
+
+ assign( KisZero_true_mask,
+ unop( Iop_1Sto32,
+ binop( Iop_CmpEQ32,
+ unop( Iop_8Uto32, mkexpr( K ) ),
+ mkU32( 0 ) ) ) );
+ assign( KisZero_false_mask,
+ unop( Iop_1Sto32,
+ binop( Iop_CmpNE32,
+ unop( Iop_8Uto32, mkexpr( K ) ),
+ mkU32( 0 ) ) ) );
+
+ assign( field,
+ binop( Iop_Or32,
+ binop( Iop_And32,
+ mkexpr( KisZero_false_mask ),
+ binop( Iop_Or32,
+ binop( Iop_And32,
+ mkexpr( Lt_true_mask ),
+ mkU32( 0x8 ) ),
+ binop( Iop_Or32,
+ binop( Iop_And32,
+ mkexpr( Gt_true_mask ),
+ mkU32( 0x4 ) ),
+ binop( Iop_And32,
+ mkexpr( Eq_true_mask ),
+ mkU32( 0x2 ) ) ) ) ),
+ binop( Iop_And32,
+ mkexpr( KisZero_true_mask ),
+ mkU32( 0x4 ) ) ) );
+
+ putGST_field( PPC_GST_CR,
+ binop( Iop_Or32,
+ binop( Iop_And32,
+ mkexpr( Unordered_true ),
+ mkU32( 0x1 ) ),
+ binop( Iop_And32,
+ unop( Iop_Not32, mkexpr( Unordered_true ) ),
+ mkexpr( field ) ) ),
+ crfD );
+
+ return True;
+}
/*------------------------------------------------------------*/
/*--- AltiVec Instruction Translation ---*/
if (dis_dfp_fmt_conv( theInstr ))
goto decode_success;
goto decode_failure;
+ case 0x2A2: // dtstsf - DFP number of significant digits
+ if (!allow_DFP)
+ goto decode_failure;
+ if (dis_dfp_significant_digits(theInstr))
+ goto decode_success;
+ goto decode_failure;
+ case 0x142: // ddedpd DFP Decode DPD to BCD
+ case 0x342: // denbcd DFP Encode BCD to DPD
+ if (!allow_DFP)
+ goto decode_failure;
+ if (dis_dfp_bcd(theInstr))
+ goto decode_success;
+ goto decode_failure;
case 0x162: // dxex - Extract exponent
case 0x362: // diex - Insert exponent
if (!allow_DFP)
goto decode_success;
goto decode_failure;
+ case 0x2A2: // dtstsfq - DFP number of significant digits
+ if (!allow_DFP)
+ goto decode_failure;
+ if (dis_dfp_significant_digits(theInstr))
+ goto decode_success;
+ goto decode_failure;
+
+ case 0x142: // ddedpdq DFP Decode DPD to BCD
+ case 0x342: // denbcdq DFP Encode BCD to DPD
+ if (!allow_DFP)
+ goto decode_failure;
+ if (dis_dfp_bcdq(theInstr))
+ goto decode_success;
+ goto decode_failure;
+
/* Floating Point Compare Instructions */
case 0x000: // fcmpu
case 0x020: // fcmpo