|
From: <sv...@va...> - 2012-06-02 23:47:14
|
sewardj 2012-06-03 00:47:02 +0100 (Sun, 03 Jun 2012)
New Revision: 2367
Log:
POWER Processor decimal FP support, part 5 (VEX side). Bug #299694.
(Carl Love, ca...@us... and Maynard Johnson, may...@us...)
This patch adds support for Power Decimal Floating Point (DFP) . This
is the fifth patch set in the series of five to add the DFP
instruction support to Valgrind. Adds support for the ddedpd,
ddedpdq, denbcd, denbcdq, dtstsf, and dtstsfq instructions.
Modified files:
trunk/priv/guest_ppc_toIR.c
trunk/priv/host_generic_simd64.c
trunk/priv/host_generic_simd64.h
trunk/priv/host_ppc_isel.c
trunk/priv/ir_defs.c
trunk/pub/libvex_ir.h
Modified: trunk/priv/host_ppc_isel.c (+135 -8)
===================================================================
--- trunk/priv/host_ppc_isel.c 2012-06-02 21:29:22 +01:00 (rev 2366)
+++ trunk/priv/host_ppc_isel.c 2012-06-03 00:47:02 -23:00 (rev 2367)
@@ -42,6 +42,7 @@
#include "main_util.h"
#include "main_globals.h"
#include "host_generic_regs.h"
+#include "host_generic_simd64.h"
#include "host_ppc_defs.h"
/* GPR register class for ppc32/64 */
@@ -2002,9 +2003,58 @@
add_to_sp( env, 16 ); // Reset SP
return r_dst;
}
-
break;
+ case Iop_BCDtoDPB: {
+ PPCCondCode cc;
+ UInt argiregs;
+ HReg argregs[1];
+ HReg r_dst = newVRegI(env);
+ Int argreg;
+ HWord* fdescr;
+
+ argiregs = 0;
+ argreg = 0;
+ argregs[0] = hregPPC_GPR3(mode64);
+
+ argiregs |= (1 << (argreg+3));
+ addInstr(env, mk_iMOVds_RR( argregs[argreg++],
+ iselWordExpr_R(env, e->Iex.Unop.arg) ) );
+
+ cc = mk_PPCCondCode( Pct_ALWAYS, Pcf_NONE );
+
+ fdescr = (HWord*)h_BCDtoDPB;
+ addInstr(env, PPCInstr_Call( cc, (Addr64)(fdescr[0]), argiregs ) );
+
+ addInstr(env, mk_iMOVds_RR(r_dst, argregs[0]));
+ return r_dst;
+ }
+
+ case Iop_DPBtoBCD: {
+ PPCCondCode cc;
+ UInt argiregs;
+ HReg argregs[1];
+ HReg r_dst = newVRegI(env);
+ Int argreg;
+ HWord* fdescr;
+
+ argiregs = 0;
+ argreg = 0;
+ argregs[0] = hregPPC_GPR3(mode64);
+
+ argiregs |= (1 << (argreg+3));
+ addInstr(env, mk_iMOVds_RR( argregs[argreg++],
+ iselWordExpr_R(env, e->Iex.Unop.arg) ) );
+
+ cc = mk_PPCCondCode( Pct_ALWAYS, Pcf_NONE );
+
+ fdescr = (HWord*)h_DPBtoBCD;
+ addInstr(env, PPCInstr_Call( cc, (Addr64)(fdescr[0]), argiregs ) );
+
+ addInstr(env, mk_iMOVds_RR(r_dst, argregs[0]));
+ return r_dst;
+ }
+
default:
break;
}
@@ -3154,10 +3204,10 @@
}
case Iop_ReinterpD64asI64: {
- HReg fr_src = iselDfp64Expr(env, e->Iex.Unop.arg);
- PPCAMode *am_addr0, *am_addr1;
- HReg r_dstLo = newVRegI(env);
- HReg r_dstHi = newVRegI(env);
+ HReg fr_src = iselDfp64Expr(env, e->Iex.Unop.arg);
+ PPCAMode *am_addr0, *am_addr1;
+ HReg r_dstLo = newVRegI(env);
+ HReg r_dstHi = newVRegI(env);
sub_from_sp( env, 16 ); // Move SP down 16 bytes
@@ -3167,7 +3217,7 @@
// store as D64
addInstr(env, PPCInstr_FpLdSt( False/*store*/, 8,
fr_src, am_addr0 ));
-
+
// load hi,lo as Ity_I32's
addInstr(env, PPCInstr_Load( 4, r_dstHi,
am_addr0, False/*mode32*/ ));
@@ -3175,12 +3225,89 @@
am_addr1, False/*mode32*/ ));
*rHi = r_dstHi;
*rLo = r_dstLo;
-
+
add_to_sp( env, 16 ); // Reset SP
return;
}
+ case Iop_BCDtoDPB: {
+ PPCCondCode cc;
+ UInt argiregs;
+ HReg argregs[2];
+ Int argreg;
+ HReg tLo = newVRegI(env);
+ HReg tHi = newVRegI(env);
+ HReg tmpHi;
+ HReg tmpLo;
+ ULong target;
+ Bool mode64 = env->mode64;
+
+ argregs[0] = hregPPC_GPR3(mode64);
+ argregs[1] = hregPPC_GPR4(mode64);
+
+ argiregs = 0;
+ argreg = 0;
+
+ iselInt64Expr( &tmpHi, &tmpLo, env, e->Iex.Unop.arg );
+
+ argiregs |= ( 1 << (argreg+3 ) );
+ addInstr( env, mk_iMOVds_RR( argregs[argreg++], tmpHi ) );
+
+ argiregs |= ( 1 << (argreg+3 ) );
+ addInstr( env, mk_iMOVds_RR( argregs[argreg], tmpLo ) );
+
+ cc = mk_PPCCondCode( Pct_ALWAYS, Pcf_NONE );
+ target = toUInt( Ptr_to_ULong(h_BCDtoDPB ) );
+
+ addInstr( env, PPCInstr_Call( cc, (Addr64)target, argiregs ) );
+ addInstr( env, mk_iMOVds_RR( tHi, argregs[argreg-1] ) );
+ addInstr( env, mk_iMOVds_RR( tLo, argregs[argreg] ) );
+
+ *rHi = tHi;
+ *rLo = tLo;
+ return;
+ }
+
+ case Iop_DPBtoBCD: {
+ PPCCondCode cc;
+ UInt argiregs;
+ HReg argregs[2];
+ Int argreg;
+ HReg tLo = newVRegI(env);
+ HReg tHi = newVRegI(env);
+ HReg tmpHi;
+ HReg tmpLo;
+ ULong target;
+ Bool mode64 = env->mode64;
+
+ argregs[0] = hregPPC_GPR3(mode64);
+ argregs[1] = hregPPC_GPR4(mode64);
+
+ argiregs = 0;
+ argreg = 0;
+
+ iselInt64Expr(&tmpHi, &tmpLo, env, e->Iex.Unop.arg);
+
+ argiregs |= (1 << (argreg+3));
+ addInstr(env, mk_iMOVds_RR( argregs[argreg++], tmpHi ));
+
+ argiregs |= (1 << (argreg+3));
+ addInstr(env, mk_iMOVds_RR( argregs[argreg], tmpLo));
+
+ cc = mk_PPCCondCode( Pct_ALWAYS, Pcf_NONE );
+
+ target = toUInt( Ptr_to_ULong( h_DPBtoBCD ) );
+
+ addInstr(env, PPCInstr_Call( cc, (Addr64)target, argiregs ) );
+ addInstr(env, mk_iMOVds_RR(tHi, argregs[argreg-1]));
+ addInstr(env, mk_iMOVds_RR(tLo, argregs[argreg]));
+
+ *rHi = tHi;
+ *rLo = tLo;
+ return;
+ }
+
default:
break;
}
@@ -4089,7 +4216,7 @@
HReg r_dstLo = newVRegF(env);
HReg r_srcHi = newVRegF(env);
HReg r_srcLo = newVRegF(env);
- PPCRI* rmc = iselWordExpr_RI(env, e->Iex.Binop.arg1);
+ PPCRI* rmc = iselWordExpr_RI(env, triop->arg1);
/* dst will be used to pass in the left operand and get the result */
iselDfp128Expr(&r_dstHi, &r_dstLo, env, triop->arg2);
Modified: trunk/pub/libvex_ir.h (+10 -0)
===================================================================
--- trunk/pub/libvex_ir.h 2012-06-02 21:29:22 +01:00 (rev 2366)
+++ trunk/pub/libvex_ir.h 2012-06-03 00:47:02 -23:00 (rev 2367)
@@ -1105,6 +1105,16 @@
/* Support for 128-bit DFP type */
Iop_D64HLtoD128, Iop_D128HItoD64, Iop_D128LOtoD64,
+ /* I64 -> I64
+ * Convert 50-bit densely packed BCD string to 60 bit BCD string
+ */
+ Iop_DPBtoBCD,
+
+ /* I64 -> I64
+ * Convert 60 bit BCD string to 50-bit densely packed BCD string
+ */
+ Iop_BCDtoDPB,
+
/* Conversion I64 -> D64 */
Iop_ReinterpI64asD64,
Modified: trunk/priv/ir_defs.c (+6 -0)
===================================================================
--- trunk/priv/ir_defs.c 2012-06-02 21:29:22 +01:00 (rev 2366)
+++ trunk/priv/ir_defs.c 2012-06-03 00:47:02 -23:00 (rev 2367)
@@ -982,6 +982,8 @@
case Iop_V256to64_2: vex_printf("V256to64_2"); return;
case Iop_V256to64_3: vex_printf("V256to64_3"); return;
case Iop_64x4toV256: vex_printf("64x4toV256"); return;
+ case Iop_DPBtoBCD: vex_printf("Iop_DPBtoBCD"); return;
+ case Iop_BCDtoDPB: vex_printf("Iop_BCDtoDPB"); return;
default: vpanic("ppIROp(1)");
}
@@ -2716,6 +2718,10 @@
case Iop_I64StoD128: /* I64 bit pattern stored in Float register */
UNARY(Ity_D64, Ity_D128);
+ case Iop_DPBtoBCD:
+ case Iop_BCDtoDPB:
+ UNARY(Ity_I64, Ity_I64);
+
case Iop_D128HItoD64:
case Iop_D128LOtoD64:
UNARY(Ity_D128, Ity_D64);
Modified: trunk/priv/host_generic_simd64.h (+6 -0)
===================================================================
--- trunk/priv/host_generic_simd64.h 2012-06-02 21:29:22 +01:00 (rev 2366)
+++ trunk/priv/host_generic_simd64.h 2012-06-03 00:47:02 -23:00 (rev 2367)
@@ -156,6 +156,12 @@
extern UInt h_generic_calc_CmpNEZ16x2 ( UInt );
extern UInt h_generic_calc_CmpNEZ8x4 ( UInt );
+extern ULong h_DPBtoBCD( ULong dpb );
+extern ULong h_BCDtoDPB( ULong bcd );
+
+ULong dpb_to_bcd(ULong chunk); // helper for h_DPBtoBCD
+ULong bcd_to_dpb(ULong chunk); // helper for h_BCDtoDPB
+
#endif /* ndef __VEX_HOST_GENERIC_SIMD64_H */
/*---------------------------------------------------------------*/
Modified: trunk/priv/host_generic_simd64.c (+125 -0)
===================================================================
--- trunk/priv/host_generic_simd64.c 2012-06-02 21:29:22 +01:00 (rev 2366)
+++ trunk/priv/host_generic_simd64.c 2012-06-03 00:47:02 -23:00 (rev 2367)
@@ -1379,7 +1379,132 @@
+ absdiff8U( sel8x4_0(xx), sel8x4_0(yy) );
}
+/*------------------------------------------------------------------*/
+/* Decimal Floating Point (DFP) externally visible helper functions */
+/* that implement Iop_BCDtoDPB and Iop_DPBtoBCD */
+/*------------------------------------------------------------------*/
+#define NOT( x ) ( ( ( x ) == 0) ? 1 : 0)
+#define GET( x, y ) ( ( ( x ) & ( 0x1UL << ( y ) ) ) >> ( y ) )
+#define PUT( x, y ) ( ( x )<< ( y ) )
+
+ULong dpb_to_bcd( ULong chunk )
+{
+ Short a, b, c, d, e, f, g, h, i, j, k, m;
+ Short p, q, r, s, t, u, v, w, x, y;
+ ULong value;
+
+ /* convert 10 bit densely packed BCD to BCD */
+ p = GET( chunk, 9 );
+ q = GET( chunk, 8 );
+ r = GET( chunk, 7 );
+ s = GET( chunk, 6 );
+ t = GET( chunk, 5 );
+ u = GET( chunk, 4 );
+ v = GET( chunk, 3 );
+ w = GET( chunk, 2 );
+ x = GET( chunk, 1 );
+ y = GET( chunk, 0 );
+
+ /* The BCD bit values are given by the following boolean equations.*/
+ a = ( NOT(s) & v & w ) | ( t & v & w & s ) | ( v & w & NOT(x) );
+ b = ( p & s & x & NOT(t) ) | ( p & NOT(w) ) | ( p & NOT(v) );
+ c = ( q & s & x & NOT(t) ) | ( q & NOT(w) ) | ( q & NOT(v) );
+ d = r;
+ e = ( v & NOT(w) & x ) | ( s & v & w & x ) | ( NOT(t) & v & x & w );
+ f = ( p & t & v & w & x & NOT(s) ) | ( s & NOT(x) & v ) | ( s & NOT(v) );
+ g = ( q & t & w & v & x & NOT(s) ) | ( t & NOT(x) & v ) | ( t & NOT(v) );
+ h = u;
+ i = ( t & v & w & x ) | ( s & v & w & x ) | ( v & NOT(w) & NOT(x) );
+ j = ( p & NOT(s) & NOT(t) & w & v ) | ( s & v & NOT(w) & x )
+ | ( p & w & NOT(x) & v ) | ( w & NOT(v) );
+ k = ( q & NOT(s) & NOT(t) & v & w ) | ( t & v & NOT(w) & x )
+ | ( q & v & w & NOT(x) ) | ( x & NOT(v) );
+ m = y;
+
+ value = PUT(a, 11) | PUT(b, 10) | PUT(c, 9) | PUT(d, 8) | PUT(e, 7)
+ | PUT(f, 6) | PUT(g, 5) | PUT(h, 4) | PUT(i, 3) | PUT(j, 2)
+ | PUT(k, 1) | PUT(m, 0);
+ return value;
+}
+
+ULong bcd_to_dpb( ULong chunk )
+{
+ Short a, b, c, d, e, f, g, h, i, j, k, m;
+ Short p, q, r, s, t, u, v, w, x, y;
+ ULong value;
+ /* Convert a 3 digit BCD value to a 10 bit Densely Packed Binary (DPD) value
+ The boolean equations to calculate the value of each of the DPD bit
+ is given in Appendix B of Book 1: Power ISA User Instruction set. The
+ bits for the DPD number are [abcdefghijkm]. The bits for the BCD value
+ are [pqrstuvwxy]. The boolean logic equations in psuedo C code are:
+ */
+ a = GET( chunk, 11 );
+ b = GET( chunk, 10 );
+ c = GET( chunk, 9 );
+ d = GET( chunk, 8 );
+ e = GET( chunk, 7 );
+ f = GET( chunk, 6 );
+ g = GET( chunk, 5 );
+ h = GET( chunk, 4 );
+ i = GET( chunk, 3 );
+ j = GET( chunk, 2 );
+ k = GET( chunk, 1 );
+ m = GET( chunk, 0 );
+
+ p = ( f & a & i & NOT(e) ) | ( j & a & NOT(i) ) | ( b & NOT(a) );
+ q = ( g & a & i & NOT(e) ) | ( k & a & NOT(i) ) | ( c & NOT(a) );
+ r = d;
+ s = ( j & NOT(a) & e & NOT(i) ) | ( f & NOT(i) & NOT(e) )
+ | ( f & NOT(a) & NOT(e) ) | ( e & i );
+ t = ( k & NOT(a) & e & NOT(i) ) | ( g & NOT(i) & NOT(e) )
+ | ( g & NOT(a) & NOT(e) ) | ( a & i );
+ u = h;
+ v = a | e | i;
+ w = ( NOT(e) & j & NOT(i) ) | ( e & i ) | a;
+ x = ( NOT(a) & k & NOT(i) ) | ( a & i ) | e;
+ y = m;
+
+ value = PUT(p, 9) | PUT(q, 8) | PUT(r, 7) | PUT(s, 6) | PUT(t, 5)
+ | PUT(u, 4) | PUT(v, 3) | PUT(w, 2) | PUT(x, 1) | y;
+
+ return value;
+}
+
+ULong h_DPBtoBCD( ULong dpb )
+{
+ ULong result, chunk;
+ Int i;
+
+ result = 0;
+
+ for (i = 0; i < 5; i++) {
+ chunk = dpb >> ( 4 - i ) * 10;
+ result = result << 12;
+ result |= dpb_to_bcd( chunk & 0x3FF );
+ }
+ return result;
+}
+
+ULong h_BCDtoDPB( ULong bcd )
+{
+ ULong result, chunk;
+ Int i;
+
+ result = 0;
+
+ for (i = 0; i < 5; i++) {
+ chunk = bcd >> ( 4 - i ) * 12;
+ result = result << 10;
+ result |= bcd_to_dpb( chunk & 0xFFF );
+ }
+ return result;
+}
+#undef NOT
+#undef GET
+#undef PUT
+
/*---------------------------------------------------------------*/
/*--- end host_generic_simd64.c ---*/
/*---------------------------------------------------------------*/
+
Modified: trunk/priv/guest_ppc_toIR.c (+1419 -6)
===================================================================
--- trunk/priv/guest_ppc_toIR.c 2012-06-02 21:29:22 +01:00 (rev 2366)
+++ trunk/priv/guest_ppc_toIR.c 2012-06-03 00:47:02 -23:00 (rev 2367)
@@ -8513,7 +8513,9 @@
/*------------------------------------------------------------*/
#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
@@ -8522,28 +8524,111 @@
#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 AND4(w, x, y, z) AND( AND( w, x ), AND( y, z ) )
#define OR(x, y) binop( Iop_Or32, x, y )
-#define AND4(w, x, y, z) AND( AND( w, x ), AND( y, z ) )
#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].
*/
@@ -8618,11 +8703,450 @@
) ) );
}
+#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 AND4
#undef OR
-#undef AND4
#undef OR3
#undef OR4
+#undef NOT
+#undef SHR
#undef SHL
#undef BITS5
@@ -9925,7 +10449,7 @@
unop( Iop_1Sto32,
binop( Iop_CmpNE32,
mkexpr( lmd ),
- mkU32( 0 ) ) ) ),
+ mkU32( 0 ) ) ) ),
mkU32( 0x1 ) ),
mkU8( 1 ) ) );
@@ -9991,7 +10515,868 @@
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 si...
[truncated message content] |