]> rtime.felk.cvut.cz Git - l4.git/blobdiff - l4/pkg/valgrind/src/valgrind-3.6.0-svn/VEX/priv/guest_ppc_toIR.c
update
[l4.git] / l4 / pkg / valgrind / src / valgrind-3.6.0-svn / VEX / priv / guest_ppc_toIR.c
index b9b11753ecda7920ef9d0fabfaa805bf42304f5a..738fd13963b805d2773c989e691137bc625ad06f 100644 (file)
@@ -1,4 +1,5 @@
 
+
 /*--------------------------------------------------------------------*/
 /*--- begin                                       guest_ppc_toIR.c ---*/
 /*--------------------------------------------------------------------*/
@@ -257,22 +258,52 @@ static UChar ifieldRegDS( UInt instr ) {
    return toUChar( IFIELD( instr, 21, 5 ) );
 }
 
+/* Extract XT (destination register) field, instr[0,25:21] */
+static UChar ifieldRegXT ( UInt instr )
+{
+  UChar upper_bit = toUChar (IFIELD (instr, 0, 1));
+  UChar lower_bits = toUChar (IFIELD (instr, 21, 5));
+  return (upper_bit << 5) | lower_bits;
+}
+
+/* Extract XS (store source register) field, instr[0,25:21] */
+static inline UChar ifieldRegXS ( UInt instr )
+{
+  return ifieldRegXT ( instr );
+}
+
 /* Extract RA (1st source register) field, instr[20:16] */
 static UChar ifieldRegA ( UInt instr ) {
    return toUChar( IFIELD( instr, 16, 5 ) );
 }
 
+/* Extract XA (1st source register) field, instr[2,20:16] */
+static UChar ifieldRegXA ( UInt instr )
+{
+  UChar upper_bit = toUChar (IFIELD (instr, 2, 1));
+  UChar lower_bits = toUChar (IFIELD (instr, 16, 5));
+  return (upper_bit << 5) | lower_bits;
+}
+
 /* Extract RB (2nd source register) field, instr[15:11] */
 static UChar ifieldRegB ( UInt instr ) {
    return toUChar( IFIELD( instr, 11, 5 ) );
 }
 
+/* Extract XB (2nd source register) field, instr[1,15:11] */
+static UChar ifieldRegXB ( UInt instr )
+{
+  UChar upper_bit = toUChar (IFIELD (instr, 1, 1));
+  UChar lower_bits = toUChar (IFIELD (instr, 11, 5));
+  return (upper_bit << 5) | lower_bits;
+}
+
 /* Extract RC (3rd source register) field, instr[10:6] */
 static UChar ifieldRegC ( UInt instr ) {
    return toUChar( IFIELD( instr, 6, 5 ) );
 }
 
-/* Extract 2nd lowest bit, instr[1] */
+/* Extract bit 10, instr[10] */
 static UChar ifieldBIT10 ( UInt instr ) {
    return toUChar( IFIELD( instr, 10, 1 ) );
 }
@@ -297,6 +328,16 @@ static UInt ifieldUIMM26 ( UInt instr ) {
    return instr & 0x3FFFFFF;
 }
 
+/* Extract DM field, instr[9:8] */
+static UChar ifieldDM ( UInt instr ) {
+   return toUChar( IFIELD( instr, 8, 2 ) );
+}
+
+/* Extract SHW field, instr[9:8] */
+static inline UChar ifieldSHW ( UInt instr )
+{
+  return ifieldDM ( instr );
+}
 
 /*------------------------------------------------------------*/
 /*--- Guest-state identifiers                              ---*/
@@ -320,6 +361,7 @@ typedef enum {
 } PPC_GST;
 
 #define MASK_FPSCR_RN   0x3
+#define MASK_FPSCR_FPRF 0x1F000
 #define MASK_VSCR_VALID 0x00010001
 
 
@@ -505,6 +547,12 @@ static IRExpr* mkU64 ( ULong i )
    return IRExpr_Const(IRConst_U64(i));
 }
 
+static IRExpr* mkV128 ( UShort i )
+{
+   vassert(i == 0 || i == 0xffff);
+   return IRExpr_Const(IRConst_V128(i));
+}
+
 /* This generates a normal (non load-linked) load. */
 static IRExpr* loadBE ( IRType ty, IRExpr* addr )
 {
@@ -931,43 +979,44 @@ static void putIReg ( UInt archreg, IRExpr* e )
 }
 
 
+/* Floating point egisters are mapped to VSX registers[0..31]. */
 static Int floatGuestRegOffset ( UInt archreg )
 {
    vassert(archreg < 32);
    
    switch (archreg) {
-   case  0: return offsetofPPCGuestState(guest_FPR0);
-   case  1: return offsetofPPCGuestState(guest_FPR1);
-   case  2: return offsetofPPCGuestState(guest_FPR2);
-   case  3: return offsetofPPCGuestState(guest_FPR3);
-   case  4: return offsetofPPCGuestState(guest_FPR4);
-   case  5: return offsetofPPCGuestState(guest_FPR5);
-   case  6: return offsetofPPCGuestState(guest_FPR6);
-   case  7: return offsetofPPCGuestState(guest_FPR7);
-   case  8: return offsetofPPCGuestState(guest_FPR8);
-   case  9: return offsetofPPCGuestState(guest_FPR9);
-   case 10: return offsetofPPCGuestState(guest_FPR10);
-   case 11: return offsetofPPCGuestState(guest_FPR11);
-   case 12: return offsetofPPCGuestState(guest_FPR12);
-   case 13: return offsetofPPCGuestState(guest_FPR13);
-   case 14: return offsetofPPCGuestState(guest_FPR14);
-   case 15: return offsetofPPCGuestState(guest_FPR15);
-   case 16: return offsetofPPCGuestState(guest_FPR16);
-   case 17: return offsetofPPCGuestState(guest_FPR17);
-   case 18: return offsetofPPCGuestState(guest_FPR18);
-   case 19: return offsetofPPCGuestState(guest_FPR19);
-   case 20: return offsetofPPCGuestState(guest_FPR20);
-   case 21: return offsetofPPCGuestState(guest_FPR21);
-   case 22: return offsetofPPCGuestState(guest_FPR22);
-   case 23: return offsetofPPCGuestState(guest_FPR23);
-   case 24: return offsetofPPCGuestState(guest_FPR24);
-   case 25: return offsetofPPCGuestState(guest_FPR25);
-   case 26: return offsetofPPCGuestState(guest_FPR26);
-   case 27: return offsetofPPCGuestState(guest_FPR27);
-   case 28: return offsetofPPCGuestState(guest_FPR28);
-   case 29: return offsetofPPCGuestState(guest_FPR29);
-   case 30: return offsetofPPCGuestState(guest_FPR30);
-   case 31: return offsetofPPCGuestState(guest_FPR31);
+   case  0: return offsetofPPCGuestState(guest_VSR0);
+   case  1: return offsetofPPCGuestState(guest_VSR1);
+   case  2: return offsetofPPCGuestState(guest_VSR2);
+   case  3: return offsetofPPCGuestState(guest_VSR3);
+   case  4: return offsetofPPCGuestState(guest_VSR4);
+   case  5: return offsetofPPCGuestState(guest_VSR5);
+   case  6: return offsetofPPCGuestState(guest_VSR6);
+   case  7: return offsetofPPCGuestState(guest_VSR7);
+   case  8: return offsetofPPCGuestState(guest_VSR8);
+   case  9: return offsetofPPCGuestState(guest_VSR9);
+   case 10: return offsetofPPCGuestState(guest_VSR10);
+   case 11: return offsetofPPCGuestState(guest_VSR11);
+   case 12: return offsetofPPCGuestState(guest_VSR12);
+   case 13: return offsetofPPCGuestState(guest_VSR13);
+   case 14: return offsetofPPCGuestState(guest_VSR14);
+   case 15: return offsetofPPCGuestState(guest_VSR15);
+   case 16: return offsetofPPCGuestState(guest_VSR16);
+   case 17: return offsetofPPCGuestState(guest_VSR17);
+   case 18: return offsetofPPCGuestState(guest_VSR18);
+   case 19: return offsetofPPCGuestState(guest_VSR19);
+   case 20: return offsetofPPCGuestState(guest_VSR20);
+   case 21: return offsetofPPCGuestState(guest_VSR21);
+   case 22: return offsetofPPCGuestState(guest_VSR22);
+   case 23: return offsetofPPCGuestState(guest_VSR23);
+   case 24: return offsetofPPCGuestState(guest_VSR24);
+   case 25: return offsetofPPCGuestState(guest_VSR25);
+   case 26: return offsetofPPCGuestState(guest_VSR26);
+   case 27: return offsetofPPCGuestState(guest_VSR27);
+   case 28: return offsetofPPCGuestState(guest_VSR28);
+   case 29: return offsetofPPCGuestState(guest_VSR29);
+   case 30: return offsetofPPCGuestState(guest_VSR30);
+   case 31: return offsetofPPCGuestState(guest_VSR31);
    default: break;
    }
    vpanic("floatGuestRegOffset(ppc)"); /*notreached*/
@@ -987,44 +1036,117 @@ static void putFReg ( UInt archreg, IRExpr* e )
    stmt( IRStmt_Put(floatGuestRegOffset(archreg), e) );
 }
 
+static Int vsxGuestRegOffset ( UInt archreg )
+{
+   vassert(archreg < 64);
+   switch (archreg) {
+   case  0: return offsetofPPCGuestState(guest_VSR0);
+   case  1: return offsetofPPCGuestState(guest_VSR1);
+   case  2: return offsetofPPCGuestState(guest_VSR2);
+   case  3: return offsetofPPCGuestState(guest_VSR3);
+   case  4: return offsetofPPCGuestState(guest_VSR4);
+   case  5: return offsetofPPCGuestState(guest_VSR5);
+   case  6: return offsetofPPCGuestState(guest_VSR6);
+   case  7: return offsetofPPCGuestState(guest_VSR7);
+   case  8: return offsetofPPCGuestState(guest_VSR8);
+   case  9: return offsetofPPCGuestState(guest_VSR9);
+   case 10: return offsetofPPCGuestState(guest_VSR10);
+   case 11: return offsetofPPCGuestState(guest_VSR11);
+   case 12: return offsetofPPCGuestState(guest_VSR12);
+   case 13: return offsetofPPCGuestState(guest_VSR13);
+   case 14: return offsetofPPCGuestState(guest_VSR14);
+   case 15: return offsetofPPCGuestState(guest_VSR15);
+   case 16: return offsetofPPCGuestState(guest_VSR16);
+   case 17: return offsetofPPCGuestState(guest_VSR17);
+   case 18: return offsetofPPCGuestState(guest_VSR18);
+   case 19: return offsetofPPCGuestState(guest_VSR19);
+   case 20: return offsetofPPCGuestState(guest_VSR20);
+   case 21: return offsetofPPCGuestState(guest_VSR21);
+   case 22: return offsetofPPCGuestState(guest_VSR22);
+   case 23: return offsetofPPCGuestState(guest_VSR23);
+   case 24: return offsetofPPCGuestState(guest_VSR24);
+   case 25: return offsetofPPCGuestState(guest_VSR25);
+   case 26: return offsetofPPCGuestState(guest_VSR26);
+   case 27: return offsetofPPCGuestState(guest_VSR27);
+   case 28: return offsetofPPCGuestState(guest_VSR28);
+   case 29: return offsetofPPCGuestState(guest_VSR29);
+   case 30: return offsetofPPCGuestState(guest_VSR30);
+   case 31: return offsetofPPCGuestState(guest_VSR31);
+   case 32: return offsetofPPCGuestState(guest_VSR32);
+   case 33: return offsetofPPCGuestState(guest_VSR33);
+   case 34: return offsetofPPCGuestState(guest_VSR34);
+   case 35: return offsetofPPCGuestState(guest_VSR35);
+   case 36: return offsetofPPCGuestState(guest_VSR36);
+   case 37: return offsetofPPCGuestState(guest_VSR37);
+   case 38: return offsetofPPCGuestState(guest_VSR38);
+   case 39: return offsetofPPCGuestState(guest_VSR39);
+   case 40: return offsetofPPCGuestState(guest_VSR40);
+   case 41: return offsetofPPCGuestState(guest_VSR41);
+   case 42: return offsetofPPCGuestState(guest_VSR42);
+   case 43: return offsetofPPCGuestState(guest_VSR43);
+   case 44: return offsetofPPCGuestState(guest_VSR44);
+   case 45: return offsetofPPCGuestState(guest_VSR45);
+   case 46: return offsetofPPCGuestState(guest_VSR46);
+   case 47: return offsetofPPCGuestState(guest_VSR47);
+   case 48: return offsetofPPCGuestState(guest_VSR48);
+   case 49: return offsetofPPCGuestState(guest_VSR49);
+   case 50: return offsetofPPCGuestState(guest_VSR50);
+   case 51: return offsetofPPCGuestState(guest_VSR51);
+   case 52: return offsetofPPCGuestState(guest_VSR52);
+   case 53: return offsetofPPCGuestState(guest_VSR53);
+   case 54: return offsetofPPCGuestState(guest_VSR54);
+   case 55: return offsetofPPCGuestState(guest_VSR55);
+   case 56: return offsetofPPCGuestState(guest_VSR56);
+   case 57: return offsetofPPCGuestState(guest_VSR57);
+   case 58: return offsetofPPCGuestState(guest_VSR58);
+   case 59: return offsetofPPCGuestState(guest_VSR59);
+   case 60: return offsetofPPCGuestState(guest_VSR60);
+   case 61: return offsetofPPCGuestState(guest_VSR61);
+   case 62: return offsetofPPCGuestState(guest_VSR62);
+   case 63: return offsetofPPCGuestState(guest_VSR63);
+   default: break;
+   }
+   vpanic("vsxGuestRegOffset(ppc)"); /*notreached*/
+}
 
+/* Vector registers are mapped to VSX registers[32..63]. */
 static Int vectorGuestRegOffset ( UInt archreg )
 {
    vassert(archreg < 32);
    
    switch (archreg) {
-   case  0: return offsetofPPCGuestState(guest_VR0);
-   case  1: return offsetofPPCGuestState(guest_VR1);
-   case  2: return offsetofPPCGuestState(guest_VR2);
-   case  3: return offsetofPPCGuestState(guest_VR3);
-   case  4: return offsetofPPCGuestState(guest_VR4);
-   case  5: return offsetofPPCGuestState(guest_VR5);
-   case  6: return offsetofPPCGuestState(guest_VR6);
-   case  7: return offsetofPPCGuestState(guest_VR7);
-   case  8: return offsetofPPCGuestState(guest_VR8);
-   case  9: return offsetofPPCGuestState(guest_VR9);
-   case 10: return offsetofPPCGuestState(guest_VR10);
-   case 11: return offsetofPPCGuestState(guest_VR11);
-   case 12: return offsetofPPCGuestState(guest_VR12);
-   case 13: return offsetofPPCGuestState(guest_VR13);
-   case 14: return offsetofPPCGuestState(guest_VR14);
-   case 15: return offsetofPPCGuestState(guest_VR15);
-   case 16: return offsetofPPCGuestState(guest_VR16);
-   case 17: return offsetofPPCGuestState(guest_VR17);
-   case 18: return offsetofPPCGuestState(guest_VR18);
-   case 19: return offsetofPPCGuestState(guest_VR19);
-   case 20: return offsetofPPCGuestState(guest_VR20);
-   case 21: return offsetofPPCGuestState(guest_VR21);
-   case 22: return offsetofPPCGuestState(guest_VR22);
-   case 23: return offsetofPPCGuestState(guest_VR23);
-   case 24: return offsetofPPCGuestState(guest_VR24);
-   case 25: return offsetofPPCGuestState(guest_VR25);
-   case 26: return offsetofPPCGuestState(guest_VR26);
-   case 27: return offsetofPPCGuestState(guest_VR27);
-   case 28: return offsetofPPCGuestState(guest_VR28);
-   case 29: return offsetofPPCGuestState(guest_VR29);
-   case 30: return offsetofPPCGuestState(guest_VR30);
-   case 31: return offsetofPPCGuestState(guest_VR31);
+   case  0: return offsetofPPCGuestState(guest_VSR32);
+   case  1: return offsetofPPCGuestState(guest_VSR33);
+   case  2: return offsetofPPCGuestState(guest_VSR34);
+   case  3: return offsetofPPCGuestState(guest_VSR35);
+   case  4: return offsetofPPCGuestState(guest_VSR36);
+   case  5: return offsetofPPCGuestState(guest_VSR37);
+   case  6: return offsetofPPCGuestState(guest_VSR38);
+   case  7: return offsetofPPCGuestState(guest_VSR39);
+   case  8: return offsetofPPCGuestState(guest_VSR40);
+   case  9: return offsetofPPCGuestState(guest_VSR41);
+   case 10: return offsetofPPCGuestState(guest_VSR42);
+   case 11: return offsetofPPCGuestState(guest_VSR43);
+   case 12: return offsetofPPCGuestState(guest_VSR44);
+   case 13: return offsetofPPCGuestState(guest_VSR45);
+   case 14: return offsetofPPCGuestState(guest_VSR46);
+   case 15: return offsetofPPCGuestState(guest_VSR47);
+   case 16: return offsetofPPCGuestState(guest_VSR48);
+   case 17: return offsetofPPCGuestState(guest_VSR49);
+   case 18: return offsetofPPCGuestState(guest_VSR50);
+   case 19: return offsetofPPCGuestState(guest_VSR51);
+   case 20: return offsetofPPCGuestState(guest_VSR52);
+   case 21: return offsetofPPCGuestState(guest_VSR53);
+   case 22: return offsetofPPCGuestState(guest_VSR54);
+   case 23: return offsetofPPCGuestState(guest_VSR55);
+   case 24: return offsetofPPCGuestState(guest_VSR56);
+   case 25: return offsetofPPCGuestState(guest_VSR57);
+   case 26: return offsetofPPCGuestState(guest_VSR58);
+   case 27: return offsetofPPCGuestState(guest_VSR59);
+   case 28: return offsetofPPCGuestState(guest_VSR60);
+   case 29: return offsetofPPCGuestState(guest_VSR61);
+   case 30: return offsetofPPCGuestState(guest_VSR62);
+   case 31: return offsetofPPCGuestState(guest_VSR63);
    default: break;
    }
    vpanic("vextorGuestRegOffset(ppc)"); /*notreached*/
@@ -1044,6 +1166,22 @@ static void putVReg ( UInt archreg, IRExpr* e )
    stmt( IRStmt_Put(vectorGuestRegOffset(archreg), e) );
 }
 
+/* Get contents of VSX guest register */
+static IRExpr* getVSReg ( UInt archreg )
+{
+   vassert(archreg < 64);
+   return IRExpr_Get( vsxGuestRegOffset(archreg), Ity_V128 );
+}
+
+/* Ditto, but write to a VSX reg instead. */
+static void putVSReg ( UInt archreg, IRExpr* e )
+{
+   vassert(archreg < 64);
+   vassert(typeOfIRExpr(irsb->tyenv, e) == Ity_V128);
+   stmt( IRStmt_Put(vsxGuestRegOffset(archreg), e) );
+}
+
+
 static Int guestCR321offset ( UInt cr )
 {
    switch (cr) {
@@ -1074,6 +1212,42 @@ static Int guestCR0offset ( UInt cr )
    }
 }
 
+/* Generate an IR sequence to do a popcount operation on the supplied
+ * IRTemp, and return an IRTemp holding the result.
+ */
+static IRTemp gen_POPCOUNT ( IRTemp src )
+{
+   Int i, shift[6];
+   IRTemp old = IRTemp_INVALID;
+   IRTemp nyu = IRTemp_INVALID;
+   IRTemp mask[6];
+
+   vassert(typeOfIRExpr(irsb->tyenv,mkexpr(src)) == Ity_I64);
+   for (i = 0; i < 6; i++) {
+      mask[i] = newTemp( Ity_I64 );
+      shift[i] = 1 << i;
+   }
+   assign( mask[0], mkU64( 0x5555555555555555ULL ) );
+   assign( mask[1], mkU64( 0x3333333333333333ULL ) );
+   assign( mask[2], mkU64( 0x0F0F0F0F0F0F0F0FULL ) );
+   assign( mask[3], mkU64( 0x00FF00FF00FF00FFULL ) );
+   assign( mask[4], mkU64( 0x0000FFFF0000FFFFULL ) );
+   assign( mask[5], mkU64( 0x00000000FFFFFFFFULL ) );
+   old = src;
+   for (i = 0; i < 6; i++) {
+      nyu = newTemp( Ity_I64 );
+      assign( nyu,
+              binop( Iop_Add64,
+                     binop( Iop_And64, mkexpr( old ), mkexpr( mask[i] ) ),
+                     binop( Iop_And64,
+                            binop( Iop_Shr64, mkexpr( old ), mkU8( shift[i] ) ),
+                            mkexpr( mask[i] ) ) ) );
+      old = nyu;
+   }
+   return nyu;
+}
+
+
 // ROTL(src32/64, rot_amt5/6)
 static IRExpr* /* :: Ity_I32/64 */ ROTL ( IRExpr* src,
                                           IRExpr* rot_amt )
@@ -2143,7 +2317,7 @@ static IRExpr* /* ::Ity_I32 */ getGST_masked ( PPC_GST reg, UInt mask )
 
       /* We're only keeping track of the rounding mode,
          so if the mask isn't asking for this, just return 0x0 */
-      if (mask & 0x3) {
+      if (mask & (MASK_FPSCR_RN|MASK_FPSCR_FPRF)) {
          assign( val, IRExpr_Get( OFFB_FPROUND, Ity_I32 ) );
       } else {
          assign( val, mkU32(0x0) );
@@ -2267,7 +2441,7 @@ static void putGST_masked ( PPC_GST reg, IRExpr* src, UInt mask )
    switch (reg) {
    case PPC_GST_FPSCR: {
       /* Allow writes to Rounding Mode */
-      if (mask & 0x3) {
+      if (mask & (MASK_FPSCR_RN|MASK_FPSCR_FPRF)) {
          /* construct new fpround from new and old values as per mask:
             new fpround = (src & (3 & mask)) | (fpround & (3 & ~mask)) */
          stmt( 
@@ -2275,11 +2449,11 @@ static void putGST_masked ( PPC_GST reg, IRExpr* src, UInt mask )
                OFFB_FPROUND,
                binop(
                   Iop_Or32, 
-                  binop(Iop_And32, src, mkU32(3 & mask)),
+                  binop(Iop_And32, src, mkU32((MASK_FPSCR_RN|MASK_FPSCR_FPRF) & mask)),
                   binop(
                      Iop_And32, 
                      IRExpr_Get(OFFB_FPROUND,Ity_I32),
-                     mkU32(3 & ~mask)
+                     mkU32((MASK_FPSCR_RN|MASK_FPSCR_FPRF) & ~mask)
                   )
                )
             )
@@ -2344,6 +2518,80 @@ static void putGST_field ( PPC_GST reg, IRExpr* src, UInt fld )
    }
 }
 
+/*------------------------------------------------------------*/
+/* Helpers for VSX instructions that do floating point
+ * operations and need to determine if a src contains a
+ * special FP value.
+ *
+ *------------------------------------------------------------*/
+
+#define NONZERO_FRAC_MASK 0x000fffffffffffffULL
+#define FP_FRAC_PART(x) binop( Iop_And64, \
+                               mkexpr( x ), \
+                               mkU64( NONZERO_FRAC_MASK ) )
+
+// Returns exponent part of floating point as I32
+static IRExpr * fp_exp_part(IRTemp src)
+{
+   IRExpr * exp;
+   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;
+}
+
+
+// Infinity: exp = 7ff and fraction is zero; s = 0/1
+static IRExpr * is_Inf(IRTemp src)
+{
+   IRExpr * Inf_exp, * hi32, * low32;
+   IRTemp frac_part = newTemp(Ity_I64);
+
+   assign( frac_part, FP_FRAC_PART(src) );
+   Inf_exp = binop( Iop_CmpEQ32, fp_exp_part( src ), 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 ) ) );
+}
+
+// Zero: exp is zero and fraction is zero; s = 0/1
+static IRExpr * is_Zero(IRTemp src)
+{
+#define SIGN_MASK 0x7fffffffffffffffULL
+   IRExpr * hi32, * low32;
+   IRTemp sign_less_part = newTemp(Ity_I64);
+
+   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 ) );
+}
+
+/*  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.
+ */
+static IRExpr * is_NaN(IRTemp src)
+{
+   IRExpr * NaN_exp, * hi32, * low32;
+   IRTemp frac_part = newTemp(Ity_I64);
+
+   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 ), mkU32( 0x7ffULL ) );
+
+   return mkAND1( NaN_exp, binop( Iop_CmpNE32, binop( Iop_Or32, low32, hi32 ),
+                                               mkU32( 0 ) ) );
+}
 
 
 /*------------------------------------------------------------*/
@@ -3220,6 +3468,57 @@ static Bool dis_int_logic ( UInt theInstr )
          // TODO: alternatively: assign(rA, verbose_Clz64(rS));
          break;
 
+      case 0x1FC: // cmpb (Power6: compare bytes)
+         DIP("cmpb r%u,r%u,r%u\n", rA_addr, rS_addr, rB_addr);
+
+         if (mode64)
+            assign( rA, unop( Iop_V128to64,
+                              binop( Iop_CmpEQ8x16,
+                                     binop( Iop_64HLtoV128, mkU64(0), mkexpr(rS) ),
+                                     binop( Iop_64HLtoV128, mkU64(0), mkexpr(rB) )
+                                     )) );
+         else
+            assign( rA, unop( Iop_V128to32,
+                              binop( Iop_CmpEQ8x16,
+                                     unop( Iop_32UtoV128, mkexpr(rS) ),
+                                     unop( Iop_32UtoV128, mkexpr(rB) )
+                                     )) );
+         break;
+
+      case 0x2DF: { // mftgpr (move floating-point to general purpose register)
+         IRTemp frB = newTemp(Ity_F64);
+         DIP("mftgpr r%u,fr%u\n", rS_addr, rB_addr);
+
+         assign( frB, getFReg(rB_addr));  // always F64
+         if (mode64)
+            assign( rA, unop( Iop_ReinterpF64asI64, mkexpr(frB)) );
+         else
+            assign( rA, unop( Iop_64to32, unop( Iop_ReinterpF64asI64, mkexpr(frB))) );
+
+         putIReg( rS_addr, mkexpr(rA));
+         return True;
+      }
+
+      case 0x25F: { // mffgpr (move floating-point from general purpose register)
+         IRTemp frA = newTemp(Ity_F64);
+         DIP("mffgpr fr%u,r%u\n", rS_addr, rB_addr);
+
+         if (mode64)
+            assign( frA, unop( Iop_ReinterpI64asF64, mkexpr(rB)) );
+         else
+            assign( frA, unop( Iop_ReinterpI64asF64, unop( Iop_32Uto64, mkexpr(rB))) );
+
+         putFReg( rS_addr, mkexpr(frA));
+         return True;
+      }
+      case 0x1FA: // popcntd (population count doubleword
+      {
+         DIP("popcntd r%u,r%u\n", rA_addr, rS_addr);
+        IRTemp result = gen_POPCOUNT(rS);
+         putIReg( rA_addr, mkexpr(result) );
+         return True;
+      }
+
       default:
          vex_printf("dis_int_logic(ppc)(opc2)\n");
          return False;
@@ -3239,6 +3538,133 @@ static Bool dis_int_logic ( UInt theInstr )
    return True;
 }
 
+/*
+  Integer Parity Instructions
+*/
+static Bool dis_int_parity ( UInt theInstr )
+{
+   /* X-Form */
+   UChar opc1    = ifieldOPC(theInstr);
+   UChar rS_addr = ifieldRegDS(theInstr);
+   UChar rA_addr = ifieldRegA(theInstr);
+   UChar rB_addr = ifieldRegB(theInstr);
+   UInt  opc2    = ifieldOPClo10(theInstr);
+   UChar b0      = ifieldBIT0(theInstr);
+   IRType ty     = mode64 ? Ity_I64 : Ity_I32;
+
+   IRTemp rS     = newTemp(ty);
+   IRTemp rA     = newTemp(ty);
+   IRTemp iTot1  = newTemp(Ity_I32);
+   IRTemp iTot2  = newTemp(Ity_I32);
+   IRTemp iTot3  = newTemp(Ity_I32);
+   IRTemp iTot4  = newTemp(Ity_I32);
+   IRTemp iTot5  = newTemp(Ity_I32);
+   IRTemp iTot6  = newTemp(Ity_I32);
+   IRTemp iTot7  = newTemp(Ity_I32);
+   IRTemp iTot8  = newTemp(Ity_I32);
+   IRTemp rS1    = newTemp(ty);
+   IRTemp rS2    = newTemp(ty);
+   IRTemp rS3    = newTemp(ty);
+   IRTemp rS4    = newTemp(ty);
+   IRTemp rS5    = newTemp(ty);
+   IRTemp rS6    = newTemp(ty);
+   IRTemp rS7    = newTemp(ty);
+   IRTemp iHi    = newTemp(Ity_I32);
+   IRTemp iLo    = newTemp(Ity_I32);
+   IROp to_bit   = (mode64 ? Iop_64to1 : Iop_32to1);
+   IROp shr_op   = (mode64 ? Iop_Shr64 : Iop_Shr32);
+
+   if (opc1 != 0x1f || rB_addr || b0) {
+      vex_printf("dis_int_parity(ppc)(0x1F,opc1:rB|b0)\n");
+      return False;
+   }
+
+   assign( rS, getIReg(rS_addr) );
+
+   switch (opc2) {
+   case 0xba:  // prtyd (Parity Doubleword, ISA 2.05 p320)
+      DIP("prtyd r%u,r%u\n", rA_addr, rS_addr);
+      assign( iTot1, unop(Iop_1Uto32, unop(to_bit, mkexpr(rS))) );
+      assign( rS1, binop(shr_op, mkexpr(rS), mkU8(8)) );
+      assign( iTot2, binop(Iop_Add32,
+                           unop(Iop_1Uto32, unop(to_bit, mkexpr(rS1))),
+                           mkexpr(iTot1)) );
+      assign( rS2, binop(shr_op, mkexpr(rS1), mkU8(8)) );
+      assign( iTot3, binop(Iop_Add32,
+                           unop(Iop_1Uto32, unop(to_bit, mkexpr(rS2))),
+                           mkexpr(iTot2)) );
+      assign( rS3, binop(shr_op, mkexpr(rS2), mkU8(8)) );
+      assign( iTot4, binop(Iop_Add32,
+                           unop(Iop_1Uto32, unop(to_bit, mkexpr(rS3))),
+                           mkexpr(iTot3)) );
+      if (mode64) {
+         assign( rS4, binop(shr_op, mkexpr(rS3), mkU8(8)) );
+         assign( iTot5, binop(Iop_Add32,
+                              unop(Iop_1Uto32, unop(to_bit, mkexpr(rS4))),
+                              mkexpr(iTot4)) );
+         assign( rS5, binop(shr_op, mkexpr(rS4), mkU8(8)) );
+         assign( iTot6, binop(Iop_Add32,
+                              unop(Iop_1Uto32, unop(to_bit, mkexpr(rS5))),
+                              mkexpr(iTot5)) );
+         assign( rS6, binop(shr_op, mkexpr(rS5), mkU8(8)) );
+         assign( iTot7, binop(Iop_Add32,
+                              unop(Iop_1Uto32, unop(to_bit, mkexpr(rS6))),
+                              mkexpr(iTot6)) );
+         assign( rS7, binop(shr_op, mkexpr(rS6), mkU8(8)) );
+         assign( iTot8, binop(Iop_Add32,
+                              unop(Iop_1Uto32, unop(to_bit, mkexpr(rS7))),
+                              mkexpr(iTot7)) );
+         assign( rA, unop(Iop_32Uto64,
+                          binop(Iop_And32, mkexpr(iTot8), mkU32(1))) );
+      } else
+         assign( rA, mkexpr(iTot4) );
+
+      break;
+   case 0x9a:  // prtyw (Parity Word, ISA 2.05 p320)
+      assign( iTot1, unop(Iop_1Uto32, unop(to_bit, mkexpr(rS))) );
+      assign( rS1, binop(shr_op, mkexpr(rS), mkU8(8)) );
+      assign( iTot2, binop(Iop_Add32,
+                           unop(Iop_1Uto32, unop(to_bit, mkexpr(rS1))),
+                           mkexpr(iTot1)) );
+      assign( rS2, binop(shr_op, mkexpr(rS1), mkU8(8)) );
+      assign( iTot3, binop(Iop_Add32,
+                           unop(Iop_1Uto32, unop(to_bit, mkexpr(rS2))),
+                           mkexpr(iTot2)) );
+      assign( rS3, binop(shr_op, mkexpr(rS2), mkU8(8)) );
+      assign( iTot4, binop(Iop_Add32,
+                           unop(Iop_1Uto32, unop(to_bit, mkexpr(rS3))),
+                           mkexpr(iTot3)) );
+      assign( iLo, unop(Iop_1Uto32, unop(Iop_32to1, mkexpr(iTot4) )) );
+
+      if (mode64) {
+         assign( rS4, binop(shr_op, mkexpr(rS3), mkU8(8)) );
+         assign( iTot5, unop(Iop_1Uto32, unop(to_bit, mkexpr(rS4))) );
+         assign( rS5, binop(shr_op, mkexpr(rS4), mkU8(8)) );
+         assign( iTot6, binop(Iop_Add32,
+                              unop(Iop_1Uto32, unop(to_bit, mkexpr(rS5))),
+                              mkexpr(iTot5)) );
+         assign( rS6, binop(shr_op, mkexpr(rS5), mkU8(8)) );
+         assign( iTot7, binop(Iop_Add32,
+                              unop(Iop_1Uto32, unop(to_bit, mkexpr(rS6))),
+                              mkexpr(iTot6)) );
+         assign( rS7, binop(shr_op, mkexpr(rS6), mkU8(8)));
+         assign( iTot8, binop(Iop_Add32,
+                              unop(Iop_1Uto32, unop(to_bit, mkexpr(rS7))),
+                              mkexpr(iTot7)) );
+         assign( iHi, binop(Iop_And32, mkU32(1), mkexpr(iTot8)) ),
+            assign( rA, binop(Iop_32HLto64, mkexpr(iHi), mkexpr(iLo)) );
+      } else
+         assign( rA, binop(Iop_Or32, mkU32(0), mkexpr(iLo)) );
+      break;
+   default:
+      vex_printf("dis_int_parity(ppc)(opc2)\n");
+      return False;
+   }
+
+   putIReg( rA_addr, mkexpr(rA) );
+
+   return True;
+}
 
 
 /*
@@ -5313,7 +5739,23 @@ static Bool dis_int_ldst_rev ( UInt theInstr )
          putIReg( rD_addr, mkWidenFrom32(ty, mkexpr(w2),
                                          /* Signed */False) );
          break;
-      
+
+      case 0x214: // ldbrx (Load Doubleword Byte-Reverse Indexed)
+      {
+         IRExpr * nextAddr;
+         IRTemp w3 = newTemp( Ity_I32 );
+         IRTemp w4 = newTemp( Ity_I32 );
+         DIP("ldbrx r%u,r%u,r%u\n", rD_addr, rA_addr, rB_addr);
+         assign( w1, loadBE( Ity_I32, mkexpr( EA ) ) );
+         assign( w2, gen_byterev32( w1 ) );
+         nextAddr = binop( mkSzOp( ty, Iop_Add8 ), mkexpr( EA ),
+                           ty == Ity_I64 ? mkU64( 4 ) : mkU32( 4 ) );
+         assign( w3, loadBE( Ity_I32, nextAddr ) );
+         assign( w4, gen_byterev32( w3 ) );
+         putIReg( rD_addr, binop( Iop_32HLto64, mkexpr( w4 ), mkexpr( w2 ) ) );
+         break;
+      }
+
       case 0x396: // sthbrx (Store Half Word Byte-Reverse Indexed, PPC32 p523)
          DIP("sthbrx r%u,r%u,r%u\n", rS_addr, rA_addr, rB_addr);
          assign( w1, mkNarrowTo32(ty, getIReg(rS_addr)) );
@@ -5604,6 +6046,7 @@ static Bool dis_cache_manage ( UInt         theInstr,
    UInt  opc2    = ifieldOPClo10(theInstr);
    UChar b0      = ifieldBIT0(theInstr);
    UInt  lineszB = guest_archinfo->ppc_cache_line_szB;
+   Bool  is_dcbzl = False;
 
    IRType ty     = mode64 ? Ity_I64 : Ity_I32;
 
@@ -5615,6 +6058,16 @@ static Bool dis_cache_manage ( UInt         theInstr,
      /* b21to25 &= ~3; */ /* if the docs were true */
      b21to25 = 0; /* blunt instrument */
    }
+   if (opc1 == 0x1F && opc2 == 0x3F6) { // dcbz
+      if (b21to25 == 1) {
+         is_dcbzl = True;
+         b21to25 = 0;
+         if (!(guest_archinfo->ppc_dcbzl_szB)) {
+            vex_printf("dis_cache_manage(ppc)(dcbzl not supported by host)\n");
+            return False;
+         }
+      }
+   }
 
    if (opc1 != 0x1F || b21to25 != 0 || b0 != 0) {
       if (0) vex_printf("dis_cache_manage %d %d %d\n", 
@@ -5654,12 +6107,21 @@ static Bool dis_cache_manage ( UInt         theInstr,
       break;
       
    case 0x3F6: { // dcbz (Data Cache Block Clear to Zero, PPC32 p387)
+                 // dcbzl (Data Cache Block Clear to Zero Long, bug#135264)
       /* Clear all bytes in cache block at (rA|0) + rB. */
       IRTemp  EA   = newTemp(ty);
       IRTemp  addr = newTemp(ty);
       IRExpr* irx_addr;
       UInt    i;
-      DIP("dcbz r%u,r%u\n", rA_addr, rB_addr);
+      UInt clearszB;
+      if (is_dcbzl) {
+          clearszB = guest_archinfo->ppc_dcbzl_szB;
+          DIP("dcbzl r%u,r%u\n", rA_addr, rB_addr);
+      }
+      else {
+          clearszB = guest_archinfo->ppc_dcbz_szB;
+          DIP("dcbz r%u,r%u\n", rA_addr, rB_addr);
+      }
 
       assign( EA, ea_rAor0_idxd(rA_addr, rB_addr) );
 
@@ -5667,9 +6129,9 @@ static Bool dis_cache_manage ( UInt         theInstr,
          /* Round EA down to the start of the containing block. */
          assign( addr, binop( Iop_And64,
                               mkexpr(EA),
-                              mkU64( ~((ULong)lineszB-1) )) );
+                              mkU64( ~((ULong)clearszB-1) )) );
          
-         for (i = 0; i < lineszB / 8; i++) {
+         for (i = 0; i < clearszB / 8; i++) {
             irx_addr = binop( Iop_Add64, mkexpr(addr), mkU64(i*8) );
             storeBE( irx_addr, mkU64(0) );
          }
@@ -5677,9 +6139,9 @@ static Bool dis_cache_manage ( UInt         theInstr,
          /* Round EA down to the start of the containing block. */
          assign( addr, binop( Iop_And32,
                               mkexpr(EA),
-                              mkU32( ~(lineszB-1) )) );
+                              mkU32( ~(clearszB-1) )) );
          
-         for (i = 0; i < lineszB / 4; i++) {
+         for (i = 0; i < clearszB / 4; i++) {
             irx_addr = binop( Iop_Add32, mkexpr(addr), mkU32(i*4) );
             storeBE( irx_addr, mkU32(0) );
          }
@@ -5774,6 +6236,8 @@ static Bool dis_fp_load ( UInt theInstr )
    IRTemp EA     = newTemp(ty);
    IRTemp rA     = newTemp(ty);
    IRTemp rB     = newTemp(ty);
+   IRTemp iHi    = newTemp(Ity_I32);
+   IRTemp iLo    = newTemp(Ity_I32);
 
    assign( rA, getIReg(rA_addr) );
    assign( rB, getIReg(rB_addr) );
@@ -5854,6 +6318,28 @@ static Bool dis_fp_load ( UInt theInstr )
          putIReg( rA_addr, mkexpr(EA) );
          break;
          
+      case 0x357: // lfiwax (Load Float As Integer, Indxd, ISA 2.05 p120)
+         DIP("lfiwax fr%u,r%u,r%u\n", frD_addr, rA_addr, rB_addr);
+         assign( EA, ea_rAor0_idxd( rA_addr, rB_addr ) );
+         assign( iLo, loadBE(Ity_I32, mkexpr(EA)) );
+         assign( iHi, binop(Iop_Sub32,
+                            mkU32(0),
+                            binop(Iop_Shr32, mkexpr(iLo), mkU8(31)))  );
+         putFReg( frD_addr, unop(Iop_ReinterpI64asF64,
+                                 binop(Iop_32HLto64, mkexpr(iHi), mkexpr(iLo))) );
+         break;
+
+      case 0x377: // lfiwzx (Load floating-point as integer word, zero indexed
+      {
+         IRTemp dw = newTemp( Ity_I64 );
+         DIP("lfiwzx fr%u,r%u,r%u\n", frD_addr, rA_addr, rB_addr);
+         assign( EA, ea_rAor0_idxd( rA_addr, rB_addr ) );
+         assign( iLo, loadBE(Ity_I32, mkexpr(EA)) );
+         assign( dw, binop( Iop_32HLto64, mkU32( 0 ), mkexpr( iLo ) ) );
+         putFReg( frD_addr, unop( Iop_ReinterpI64asF64, mkexpr( dw ) ) );
+         break;
+      }
+
       default:
          vex_printf("dis_fp_load(ppc)(opc2)\n");
          return False;
@@ -6386,7 +6872,238 @@ static Bool dis_fp_multadd ( UInt theInstr )
    return True;
 }
 
+/*
+ * fe_flag is set to 1 if any of the following conditions occurs:
+ *  - The double-precision floating-point operand in register FRA is a NaN or an
+ *    Infinity.
+ *  - The double-precision floating-point operand in register FRB is a Zero, a
+ *    NaN, or an Infinity.
+ *  - e_b is less than or equal to -1022.
+ *  - e_b is greater than or equal to 1021.
+ *  - The double-precision floating-point operand in register FRA is not a zero
+ *    and the difference, e_a - e_b, is greater than or equal to 1023.
+ *  - The double-precision floating-point operand in register FRA is not a zero
+ *    and the difference, e_a - e_b, is less than or equal to -1021.
+ *  - The double-precision floating-point operand in register FRA is not a zero
+ *    and e_a is less than or equal to -970
+ *  Otherwise fe_flag is set to 0.
+ *
+ * fg_flag is set to 1 if either of the following conditions occurs.
+ *   - The double-precision floating-point operand in register FRA is an Infinity.
+ *   - The double-precision floating-point operand in register FRB is a Zero, an
+ *     Infinity, or a denormalized value.
+ *  Otherwise fg_flag is set to 0.
+ *
+ */
+static Bool dis_fp_ftdiv ( UInt theInstr )
+{
+   UChar opc1     = ifieldOPC(theInstr);
+   UChar crfD     = toUChar( IFIELD( theInstr, 23, 3 ) );
+   UChar b21to22  = toUChar( IFIELD( theInstr, 21, 2 ) );
+   UChar frA_addr = ifieldRegA(theInstr);
+   UChar frB_addr = ifieldRegB(theInstr);
+   UChar b0       = ifieldBIT0(theInstr);
+
+   // The following temps are for holding intermediate results
+   IRTemp frA_I64     = newTemp(Ity_I64);
+   IRTemp frB_I64     = newTemp(Ity_I64);
+   IRTemp e_a = newTemp(Ity_I32);
+   IRTemp e_b = newTemp(Ity_I32);
+   IRTemp frA_exp_shR = newTemp(Ity_I32);
+   IRTemp frB_exp_shR = newTemp(Ity_I32);
+
+   UInt bias = 1023;
+
+   /* The following variables hold boolean results from tests
+    * that are OR'ed together for setting the fe_ and fg_ flags.
+    * For some cases, the booleans are used more than once, so
+    * I make those IRTemp's instead of IRExpr's.
+    */
+   IRExpr * fraNaN, * frbNaN, * frbDenorm;
+   IRExpr * eb_LTE, * eb_GTE, * ea_eb_GTE, * ea_eb_LTE, * ea_LTE;
+   IRTemp  fraInf_tmp = newTemp(Ity_I1);
+   IRTemp  frbZero_tmp = newTemp(Ity_I1);
+   IRTemp  frbInf_tmp = newTemp(Ity_I1);
+   IRTemp  fraNotZero_tmp = newTemp(Ity_I1);
+
+/* The following are the flags that are set by OR'ing the results of
+ * all the tests done for ftdiv.  These flags are the input to the specified CR.
+ */
+   IRExpr * fe_flag, * fl_flag, * fg_flag;
+
+
+   if (opc1 != 0x3F || b21to22 != 0 || b0 != 0) {
+      vex_printf("dis_fp_ftdiv(ppc)(instr)\n");
+      return False;
+   }
+
+   // Create temps that will be used throughout the following tests.
+   assign( frA_I64, unop( Iop_ReinterpF64asI64, getFReg( frA_addr ) ) );
+   assign( frB_I64, unop( Iop_ReinterpF64asI64, getFReg( frB_addr ) ) );
+   assign( frA_exp_shR, fp_exp_part( frA_I64 ) );
+   assign( frB_exp_shR, fp_exp_part( frB_I64 ) );
+   /* 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 ) ));
+
+
+   //////////////////  fe_flag tests BEGIN //////////////////////
+   /* We first do all tests that may result in setting fe_flag to '1'. */
+
+   /*
+    * Test if the double-precision floating-point operand in register FRA is
+    * a NaN:
+    *    exp = 7ff and fraction is non-zero; s = 0/1
+    */
+   fraNaN = is_NaN(frA_I64);
+   /*
+    * Test if the double-precision floating-point operand in register FRA is
+    * an Infinity.
+    *    exp = 7ff and fraction is zero; s = 0/1
+    */
+   assign(fraInf_tmp, is_Inf(frA_I64));
+
+   /*
+    * Test if the double-precision floating-point operand in register FRB is
+    * a NaN:
+    *    exp = 7ff and fraction is non-zero; s = 0/1
+    */
+   frbNaN = is_NaN(frB_I64);
+   /*
+    * Test if the double-precision floating-point operand in register FRB is
+    * an Infinity.
+    *    exp = 7ff and fraction is zero; s = 0/1
+    */
+   assign( frbInf_tmp, is_Inf(frB_I64) );
+   /*
+    * Test if the double-precision floating-point operand in register FRB is
+    * a Zero.
+    *    exp is zero and fraction is zero; s = 0/1
+    */
+   assign( frbZero_tmp, is_Zero(frB_I64) );
+
+   /*
+    * Test if e_b <= -1022
+    */
+   {
+      UInt test_value = 0xfffffc02;  //Int test_value = -1022;
+      eb_LTE = binop(Iop_CmpLE32S, mkexpr(e_b), mkU32(test_value));
+   }
+
+   /*
+    * Test if e_b >= 1021
+    *   ==> 1021 < e_b
+    */
+   {
+      Int test_value = 1021;
+      eb_GTE = binop(Iop_CmpLT32S, mkU32(test_value), mkexpr(e_b));
+   }
+
+   /*
+    * Test if FRA != Zero and (e_a - e_b) >= 1023
+    *   ==> FRA != Zero && (1023 < (e_a - e_b)
+    */
+   assign( fraNotZero_tmp, unop( Iop_Not1, is_Zero( frA_I64 ) ) );
+   ea_eb_GTE = mkAND1( mkexpr( fraNotZero_tmp ),
+                       binop( Iop_CmpLT32S, mkU32( bias ),
+                              binop( Iop_Sub32, mkexpr( e_a ),
+                                     mkexpr( e_b ) ) ) );
+
+   /*
+    * Test if FRA != Zero and (e_a - e_b) <= -1021
+    */
+   {
+      UInt test_value = 0xfffffc03;  //Int test_value = -1021;
+
+      ea_eb_LTE = mkAND1( mkexpr( fraNotZero_tmp ),
+                          binop( Iop_CmpLE32S,
+                                 binop( Iop_Sub32,
+                                        mkexpr( e_a ),
+                                        mkexpr( e_b ) ),
+                                        mkU32( test_value ) ) );
+   }
+
+   /*
+    * Test if FRA != Zero and e_a <= -970
+    */
+   {
+      UInt test_value = 0xfffffc36;  //Int test_value = -970;
 
+      ea_LTE = mkAND1( mkexpr( fraNotZero_tmp ), binop( Iop_CmpLE32S,
+                                                        mkexpr( e_a ),
+                                                        mkU32( test_value ) ) );
+   }
+   //////////////////  fe_flag tests END //////////////////////
+
+   //////////////////  fg_flag tests BEGIN //////////////////////
+   /*
+    * The following tests were already performed above in the fe_flag
+    * tests.  So these conditions will result in both fe_ and fg_ flags
+    * being set.
+    *   - Test if FRA is an Infinity
+    *   - Test if FRB ix Zero
+    *   - Test if FRB is an Infinity
+    */
+
+   /*
+    * Test if FRB holds a denormalized value.  A denormalized value is one where
+    * the exp is 0 and the fraction is non-zero.
+    */
+   {
+      IRExpr * hi32, * low32, * fraction_is_nonzero;
+      IRTemp frac_part = newTemp(Ity_I64);
+
+      assign( frac_part, FP_FRAC_PART(frB_I64) );
+      hi32 = unop( Iop_64HIto32, mkexpr( frac_part ) );
+      low32 = unop( Iop_64to32, mkexpr( frac_part ) );
+      fraction_is_nonzero = binop( Iop_CmpNE32, binop( Iop_Or32, low32, hi32 ),
+                                                mkU32( 0 ) );
+      frbDenorm = mkAND1( binop( Iop_CmpEQ32, mkexpr( frB_exp_shR ),
+                                 mkU32( 0x0ULL ) ), fraction_is_nonzero );
+
+   }
+   //////////////////  fg_flag tests END //////////////////////
+
+   /////////////////////////
+   /* The CR field consists of fl_flag || fg_flag || fe_flag || 0b0
+    * where fl_flag == 1 on ppc64.
+    */
+   fl_flag = unop(Iop_Not32, mkU32(0xFFFFFE));
+
+
+   fe_flag
+   = mkOR1(
+            fraNaN,
+            mkOR1(
+                   mkexpr( fraInf_tmp ),
+                   mkOR1(
+                          mkexpr( frbZero_tmp ),
+                          mkOR1(
+                                 frbNaN,
+                                 mkOR1(
+                                        mkexpr( frbInf_tmp ),
+                                        mkOR1( eb_LTE,
+                                               mkOR1( eb_GTE,
+                                                      mkOR1( ea_eb_GTE,
+                                                             mkOR1( ea_eb_LTE,
+                                                                    ea_LTE ) ) ) ) ) ) ) ) );
+
+   fe_flag = unop(Iop_1Uto32, fe_flag);
+
+   fg_flag = mkOR1( mkexpr( fraInf_tmp ), mkOR1( mkexpr( frbZero_tmp ),
+                                                 mkOR1( mkexpr( frbInf_tmp ),
+                                                        frbDenorm ) ) );
+   fg_flag = unop(Iop_1Uto32, fg_flag);
+
+   putGST_field( PPC_GST_CR, binop( Iop_Or32,
+                           binop( Iop_Or32,
+                                  binop( Iop_Shl32, fl_flag, mkU8( 3 ) ),
+                                  binop( Iop_Shl32, fg_flag, mkU8( 2 ) ) ),
+                           binop( Iop_Shl32, fe_flag, mkU8( 1 ) ) ), crfD );
+
+   DIP("ftdiv crf%d,fr%u,fr%u\n", crfD, frA_addr, frB_addr);
+   return True;
+}
 
 /*
   Floating Point Compare Instructions
@@ -6494,8 +7211,8 @@ static Bool dis_fp_round ( UInt theInstr )
 {
    /* X-Form */
    UChar opc1     = ifieldOPC(theInstr);
-   UChar frD_addr = ifieldRegDS(theInstr);
    UChar b16to20  = ifieldRegA(theInstr);
+   UChar frD_addr = ifieldRegDS(theInstr);
    UChar frB_addr = ifieldRegB(theInstr);
    UInt  opc2     = ifieldOPClo10(theInstr);
    UChar flag_rC  = ifieldBIT0(theInstr);
@@ -6516,13 +7233,34 @@ static Bool dis_fp_round ( UInt theInstr )
       simulating exceptions, the exception status will appear to be
       zero.  Hence cr1 should be cleared if this is a . form insn. */
    Bool clear_CR1 = True;
-   
-   if (opc1 != 0x3F || b16to20 != 0) {
+   if ((!(opc1 == 0x3F || opc1 == 0x3B)) || b16to20 != 0) {
       vex_printf("dis_fp_round(ppc)(instr)\n");
       return False;
    }
 
    assign( frB, getFReg(frB_addr));
+   // TODO : add support here for fcfdus
+   if (opc1 == 0x3B) {
+      /* The fcfid[u]s instructions (from ISA 2.06) are a bit odd because
+       * they're very similar to the other instructions handled here, but have
+       * a different primary opcode.
+       */
+      switch (opc2) {
+         case 0x34E: // fcfids (Float convert from signed DWord to single precision)
+            DIP("fcfids%s fr%u,fr%u\n", flag_rC ? ".":"", frD_addr, frB_addr);
+            assign( r_tmp64, unop( Iop_ReinterpF64asI64, mkexpr(frB)) );
+            assign( frD, binop( Iop_RoundF64toF32, rm, binop( Iop_I64StoF64, rm,
+                                                              mkexpr( r_tmp64 ) ) ) );
+            goto putFR;
+
+         case 0x3Ce: // fcfidus (Float convert from unsigned DWord to single precision)
+            DIP("fcfidus%s fr%u,fr%u\n", flag_rC ? ".":"", frD_addr, frB_addr);
+            assign( r_tmp64, unop( Iop_ReinterpF64asI64, mkexpr(frB)) );
+            assign( frD, unop( Iop_F32toF64, binop( Iop_I64UtoF32, rm, mkexpr( r_tmp64 ) ) ) );
+            goto putFR;
+      }
+   }
+
 
    switch (opc2) {
    case 0x00C: // frsp (Float Round to Single, PPC32 p423)
@@ -6575,11 +7313,63 @@ static Bool dis_fp_round ( UInt theInstr )
               binop(Iop_I64StoF64, rm, mkexpr(r_tmp64)) );
       break;
 
+   case 0x3CE: // fcfidu (Float convert from unsigned DWord)
+      DIP("fcfidu%s fr%u,fr%u\n", flag_rC ? ".":"", frD_addr, frB_addr);
+      assign( r_tmp64, unop( Iop_ReinterpF64asI64, mkexpr(frB)) );
+      assign( frD, binop( Iop_I64UtoF64, rm, mkexpr( r_tmp64 ) ) );
+      break;
+
+   case 0x188: case 0x1A8: case 0x1C8: case 0x1E8: // frin, friz, frip, frim
+      switch(opc2) {
+      case 0x188: // frin (Floating Round to Integer Nearest)
+         DIP("frin%s fr%u,fr%u\n", flag_rC ? ".":"", frD_addr, frB_addr);
+         assign( r_tmp64,
+                 binop(Iop_F64toI64S, mkU32(Irrm_NEAREST), mkexpr(frB)) );
+         break;
+      case 0x1A8: // friz (Floating Round to Integer Toward Zero)
+         DIP("friz%s fr%u,fr%u\n", flag_rC ? ".":"", frD_addr, frB_addr);
+         assign( r_tmp64,
+                 binop(Iop_F64toI64S, mkU32(Irrm_ZERO), mkexpr(frB)) );
+         break;
+      case 0x1C8: // frip (Floating Round to Integer Plus)
+         DIP("frip%s fr%u,fr%u\n", flag_rC ? ".":"", frD_addr, frB_addr);
+         assign( r_tmp64,
+                 binop(Iop_F64toI64S, mkU32(Irrm_PosINF), mkexpr(frB)) );
+         break;
+      case 0x1E8: // frim (Floating Round to Integer Minus)
+         DIP("frim%s fr%u,fr%u\n", flag_rC ? ".":"", frD_addr, frB_addr);
+         assign( r_tmp64,
+                 binop(Iop_F64toI64S, mkU32(Irrm_NegINF), mkexpr(frB)) );
+         break;
+      }
+
+      /* don't use the rounded integer if frB is outside -9e18..9e18 */
+      /* F64 has only log10(2**52) significant digits anyway */
+      /* need to preserve sign of zero */
+      /*   frD = (fabs(frB) > 9e18) ? frB :
+               (sign(frB)) ? -fabs((double)r_tmp64) : (double)r_tmp64  */
+      assign(frD, IRExpr_Mux0X( unop(Iop_32to8,
+                                     binop(Iop_CmpF64,
+                                           IRExpr_Const(IRConst_F64(9e18)),
+                                           unop(Iop_AbsF64, mkexpr(frB)))),
+                                IRExpr_Mux0X(unop(Iop_32to8,
+                                                  binop(Iop_Shr32,
+                                                        unop(Iop_64HIto32,
+                                                             unop(Iop_ReinterpF64asI64,
+                                                                  mkexpr(frB))), mkU8(31))),
+                                             binop(Iop_I64StoF64, mkU32(0), mkexpr(r_tmp64) ),
+                                             unop(Iop_NegF64,
+                                                  unop( Iop_AbsF64,
+                                                        binop(Iop_I64StoF64, mkU32(0),
+                                                              mkexpr(r_tmp64)) )) ),
+                                mkexpr(frB)));
+      break;
+
    default:
       vex_printf("dis_fp_round(ppc)(opc2)\n");
       return False;
    }
-
+putFR:
    putFReg( frD_addr, mkexpr(frD) );
 
    if (set_FPRF) {
@@ -6595,6 +7385,86 @@ static Bool dis_fp_round ( UInt theInstr )
    return True;
 }
 
+/*
+  Floating Point Pair Instructions
+*/
+static Bool dis_fp_pair ( UInt theInstr )
+{
+   /* X-Form/DS-Form */
+   UChar  opc1         = ifieldOPC(theInstr);
+   UChar  frT_hi_addr  = ifieldRegDS(theInstr);
+   UChar  frT_lo_addr  = frT_hi_addr + 1;
+   UChar  rA_addr      = ifieldRegA(theInstr);
+   UChar  rB_addr      = ifieldRegB(theInstr);
+   UInt  uimm16        = ifieldUIMM16(theInstr);
+   Int    simm16       = extend_s_16to32(uimm16);
+   UInt   opc2         = ifieldOPClo10(theInstr);
+   IRType ty           = mode64 ? Ity_I64 : Ity_I32;
+   IRTemp EA_hi        = newTemp(ty);
+   IRTemp EA_lo        = newTemp(ty);
+   IRTemp frT_hi       = newTemp(Ity_F64);
+   IRTemp frT_lo       = newTemp(Ity_F64);
+   UChar b0            = ifieldBIT0(theInstr);
+   Bool is_load        = 0;
+
+   if ((frT_hi_addr %2) != 0) {
+      vex_printf("dis_fp_pair(ppc) : odd frT register\n");
+      return False;
+   }
+
+   switch (opc1) {
+   case 0x1F: // register offset
+      switch(opc2) {
+      case 0x317:     // lfdpx (FP Load Double Pair X-form, ISA 2.05  p125)
+         DIP("ldpx fr%u,r%u,r%u\n", frT_hi_addr, rA_addr, rB_addr);
+         is_load = 1;
+         break;
+      case 0x397:     // stfdpx (FP STORE Double Pair X-form, ISA 2.05  p125)
+         DIP("stdpx fr%u,r%u,r%u\n", frT_hi_addr, rA_addr, rB_addr);
+         break;
+      default:
+         vex_printf("dis_fp_pair(ppc) : X-form wrong opc2\n");
+         return False;
+      }
+
+      if (b0 != 0) {
+         vex_printf("dis_fp_pair(ppc)(0x1F,b0)\n");
+         return False;
+      }
+      assign( EA_hi, ea_rAor0_idxd( rA_addr, rB_addr ) );
+      break;
+   case 0x39: // lfdp (FP Load Double Pair DS-form, ISA 2.05  p125)
+      DIP("lfdp fr%u,%d(r%u)\n", frT_hi_addr, simm16, rA_addr);
+      assign( EA_hi, ea_rAor0_simm( rA_addr, simm16  ) );
+      is_load = 1;
+      break;
+   case 0x3d: // stfdp (FP Store Double Pair DS-form, ISA 2.05  p125)
+      DIP("stfdp fr%u,%d(r%u)\n", frT_hi_addr, simm16, rA_addr);
+      assign( EA_hi, ea_rAor0_simm( rA_addr, simm16  ) );
+      break;
+   default:   // immediate offset
+      vex_printf("dis_fp_pair(ppc)(instr)\n");
+      return False;
+   }
+
+   if (mode64)
+      assign( EA_lo, binop(Iop_Add64, mkexpr(EA_hi), mkU64(8)) );
+   else
+      assign( EA_lo, binop(Iop_Add32, mkexpr(EA_hi), mkU32(8)) );
+
+   assign( frT_hi, getFReg(frT_hi_addr) );
+   assign( frT_lo, getFReg(frT_lo_addr) );
+
+   if (is_load) {
+      putFReg( frT_hi_addr, loadBE(Ity_F64, mkexpr(EA_hi)) );
+      putFReg( frT_lo_addr, loadBE(Ity_F64, mkexpr(EA_lo)) );
+   } else {
+      storeBE( mkexpr(EA_hi), mkexpr(frT_hi) );
+      storeBE( mkexpr(EA_lo), mkexpr(frT_lo) );
+   }
+
+   return True;
+}
 
 
 /*
@@ -6605,15 +7475,19 @@ static Bool dis_fp_move ( UInt theInstr )
    /* X-Form */
    UChar opc1     = ifieldOPC(theInstr);
    UChar frD_addr = ifieldRegDS(theInstr);
-   UChar b16to20  = ifieldRegA(theInstr);
+   UChar frA_addr = ifieldRegA(theInstr);
    UChar frB_addr = ifieldRegB(theInstr);
    UInt  opc2     = ifieldOPClo10(theInstr);
    UChar flag_rC  = ifieldBIT0(theInstr);
 
    IRTemp frD = newTemp(Ity_F64);
    IRTemp frB = newTemp(Ity_F64);
+   IRTemp itmpB = newTemp(Ity_F64);
+   IRTemp frA;
+   IRTemp signA;
+   IRTemp hiD;
 
-   if (opc1 != 0x3F || b16to20 != 0) {
+   if (opc1 != 0x3F || (frA_addr != 0 && opc2 != 0x008)) {
       vex_printf("dis_fp_move(ppc)(instr)\n");
       return False;
    }
@@ -6621,6 +7495,39 @@ static Bool dis_fp_move ( UInt theInstr )
    assign( frB, getFReg(frB_addr));
 
    switch (opc2) {
+   case 0x008: // fcpsgn (Floating Copy Sign, ISA_V2.05 p126)
+      DIP("fcpsgn%s fr%u,fr%u,fr%u\n", flag_rC ? ".":"", frD_addr, frA_addr,
+          frB_addr);
+      signA = newTemp(Ity_I32);
+      hiD = newTemp(Ity_I32);
+      itmpB = newTemp(Ity_I64);
+      frA = newTemp(Ity_F64);
+      assign( frA, getFReg(frA_addr) );
+
+      /* get A's sign bit */
+      assign(signA, binop(Iop_And32,
+                          unop(Iop_64HIto32, unop(Iop_ReinterpF64asI64,
+                                                  mkexpr(frA))),
+                          mkU32(0x80000000)) );
+
+      assign( itmpB, unop(Iop_ReinterpF64asI64, mkexpr(frB)) );
+
+      /* mask off B's sign bit and or in A's sign bit */
+      assign(hiD, binop(Iop_Or32,
+                        binop(Iop_And32,
+                              unop(Iop_64HIto32,
+                                   mkexpr(itmpB)),  /* frB's high 32 bits */
+                              mkU32(0x7fffffff)),
+                        mkexpr(signA)) );
+
+      /* combine hiD/loB into frD */
+      assign( frD, unop(Iop_ReinterpI64asF64,
+                        binop(Iop_32HLto64,
+                              mkexpr(hiD),
+                              unop(Iop_64to32,
+                                   mkexpr(itmpB)))) );   /* frB's low 32 bits */
+      break;
+
    case 0x028: // fneg (Floating Negate, PPC32 p416)
       DIP("fneg%s fr%u,fr%u\n", flag_rC ? ".":"", frD_addr, frB_addr);
       assign( frD, unop( Iop_NegF64, mkexpr(frB) ));
@@ -6761,27 +7668,34 @@ static Bool dis_fp_scr ( UInt theInstr )
    case 0x2C7: { // mtfsf (Move to FPSCR Fields, PPC32 p480)
       UChar b25      = toUChar( IFIELD(theInstr, 25, 1) );
       UChar FM       = toUChar( IFIELD(theInstr, 17, 8) );
-      UChar b16      = toUChar( IFIELD(theInstr, 16, 1) );
       UChar frB_addr = ifieldRegB(theInstr);
       IRTemp frB   = newTemp(Ity_F64);
       IRTemp rB_32 = newTemp(Ity_I32);
       Int i, mask;
 
-      if (b25 != 0 || b16 != 0) {
-         vex_printf("dis_fp_scr(ppc)(instr,mtfsf)\n");
-         return False;
-      }      
-      DIP("mtfsf%s %d,fr%u\n", flag_rC ? ".":"", FM, frB_addr);
+      if (b25 == 1) {
+         /* new 64 bit move variant for power 6.  If L field (bit 25) is
+          * a one do a full 64 bit move.  Note, the FPSCR is not really
+          * properly modeled.  This instruciton only changes the value of
+          * the rounding mode.  The HW exception bits do not get set in
+          * the simulator.  1/12/09
+          */
+         DIP("mtfsf%s %d,fr%u (L=1)\n", flag_rC ? ".":"", FM, frB_addr);
+         mask = 0xFF;
+
+      } else {
+         DIP("mtfsf%s %d,fr%u\n", flag_rC ? ".":"", FM, frB_addr);
+         // Build 32bit mask from FM:
+         mask = 0;
+         for (i=0; i<8; i++) {
+            if ((FM & (1<<(7-i))) == 1) {
+               mask |= 0xF << (7-i);
+            }
+         }
+      }
       assign( frB, getFReg(frB_addr));
       assign( rB_32, unop( Iop_64to32,
                            unop( Iop_ReinterpF64asI64, mkexpr(frB) )));
-      // Build 32bit mask from FM:
-      mask = 0;
-      for (i=0; i<8; i++) {
-         if ((FM & (1<<(7-i))) == 1) {
-            mask |= 0xF << (7-i);
-         }
-      }
       putGST_masked( PPC_GST_FPSCR, mkexpr(rB_32), mask );
       break;
    }
@@ -6895,6 +7809,722 @@ static Bool dis_av_procctl ( UInt theInstr )
    return True;
 }
 
+/*
+ *
+ */
+static Bool
+dis_vx_conv ( UInt theInstr, UInt opc2 )
+{
+   /* XX2-Form */
+   UChar opc1 = ifieldOPC( theInstr );
+   UChar XT = ifieldRegXT( theInstr );
+   UChar XB = ifieldRegXB( theInstr );
+   IRTemp frB = newTemp(Ity_F64);
+   IRTemp r_tmp64 = newTemp(Ity_I64);
+   IRExpr* rm = get_IR_roundingmode();
+
+   if (opc1 != 0x3C) {
+      vex_printf( "dis_vx_conv(ppc)(instr)\n" );
+      return False;
+   }
+
+   assign(frB, unop(Iop_ReinterpI64asF64, unop(Iop_V128HIto64, getVSReg( XB ))));
+   /* For all the VSX convert instructions, the contents of doubleword element 1
+    * of VSX[XT] are undefined after the operation; therefore, we can simply
+    * move the entire array element where it makes sense to do so.
+    */
+
+   switch (opc2) {
+   case 0x2B0:
+      // xscvdpsxds (VSX Scalar truncate Double-Precision to integer and Convert
+      //             to Signed Integer Doubleword format with Saturate)
+      DIP("xscvdpsxds fr%u,fr%u\n",  (UInt)XT, (UInt)XB);
+      putVSReg( XT,
+                   binop( Iop_64HLtoV128, binop( Iop_F64toI64S,
+                                                 mkU32( Irrm_ZERO ),
+                                                 mkexpr( frB ) ), mkU64( 0 ) ) );
+      break;
+   case 0x2F0:
+      // xscvsxddp (VSX Scalar Convert and round Signed Integer Doubleword to
+      //            Double-Precision format)
+      DIP("xscvsxddp v%u,v%u\n",  (UInt)XT, (UInt)XB);
+
+      assign( r_tmp64, unop( Iop_ReinterpF64asI64, mkexpr(frB)) );
+      putVSReg( XT,
+                   binop( Iop_64HLtoV128, unop( Iop_ReinterpF64asI64,
+                                                binop( Iop_I64StoF64, rm,
+                                                       mkexpr( r_tmp64 ) ) ),
+                          mkU64( 0 ) ) );
+      break;
+   case 0x2D0:
+      // xscvuxddp (VSX Scalar Convert and round Unsigned Integer Doubleword to
+      //            Double-Precision format)
+      DIP("xscvuxddp v%u,v%u\n",  (UInt)XT, (UInt)XB);
+
+      assign( r_tmp64, unop( Iop_ReinterpF64asI64, mkexpr(frB)) );
+      putVSReg( XT,
+                   binop( Iop_64HLtoV128, unop( Iop_ReinterpF64asI64,
+                                                binop( Iop_I64UtoF64, rm,
+                                                       mkexpr( r_tmp64 ) ) ),
+                          mkU64( 0 ) ) );
+      break;
+
+   default:
+      vex_printf( "dis_vx_conv(ppc)(opc2)\n" );
+      return False;
+   }
+   return True;
+}
+
+/*
+ * VSX Scalar Floating Point Arithmetic Instructions
+ */
+static Bool
+dis_vx_arith ( UInt theInstr, UInt opc2 )
+{
+   /* XX3-Form */
+   UChar opc1 = ifieldOPC( theInstr );
+   UChar XT = ifieldRegXT( theInstr );
+   UChar XA = ifieldRegXA( theInstr );
+   UChar XB = ifieldRegXB( theInstr );
+   IRExpr* rm = get_IR_roundingmode();
+   IRTemp frA = newTemp(Ity_F64);
+   IRTemp frB = newTemp(Ity_F64);
+
+   if (opc1 != 0x3C) {
+      vex_printf( "dis_vx_arith(ppc)(instr)\n" );
+      return False;
+   }
+
+   assign(frA, unop(Iop_ReinterpI64asF64, unop(Iop_V128HIto64, getVSReg( XA ))));
+   assign(frB, unop(Iop_ReinterpI64asF64, unop(Iop_V128HIto64, getVSReg( XB ))));
+
+   /* For all the VSX sclar arithmetic instructions, the contents of doubleword element 1
+    * of VSX[XT] are undefined after the operation; therefore, we can simply set
+    * element to zero where it makes sense to do so.
+    */
+   switch (opc2) {
+      case 0x080: // xsadddp (VSX scalar add double-precision)
+         DIP("xsadddp v%d,v%d,v%d\n", (UInt)XT, (UInt)XA, (UInt)XB);
+         putVSReg( XT, binop( Iop_64HLtoV128, unop( Iop_ReinterpF64asI64,
+                                                    triop( Iop_AddF64, rm,
+                                                           mkexpr( frA ),
+                                                           mkexpr( frB ) ) ),
+                              mkU64( 0 ) ) );
+         break;
+      case 0x0E0: // xsdivdp (VSX scalar divide double-precision)
+         DIP("xsdivdp v%d,v%d,v%d\n", (UInt)XT, (UInt)XA, (UInt)XB);
+         putVSReg( XT, binop( Iop_64HLtoV128, unop( Iop_ReinterpF64asI64,
+                                                    triop( Iop_DivF64, rm,
+                                                           mkexpr( frA ),
+                                                           mkexpr( frB ) ) ),
+                              mkU64( 0 ) ) );
+         break;
+      case 0x084: case 0x0A4: // xsmaddadp, xsmaddmdp (VSX scalar multiply-add double-precision)
+      {
+         IRTemp frT = newTemp(Ity_F64);
+         Bool mdp = opc2 == 0x0A4;
+         DIP("xsmadd%sdp v%d,v%d,v%d\n", mdp ? "m" : "a", (UInt)XT, (UInt)XA, (UInt)XB);
+         assign( frT, unop( Iop_ReinterpI64asF64, unop( Iop_V128HIto64,
+                                                        getVSReg( XT ) ) ) );
+         putVSReg( XT, binop( Iop_64HLtoV128, unop( Iop_ReinterpF64asI64,
+                                                    qop( Iop_MAddF64, rm,
+                                                         mkexpr( frA ),
+                                                         mkexpr( mdp ? frT : frB ),
+                                                         mkexpr( mdp ? frB : frT ) ) ),
+                              mkU64( 0 ) ) );
+         break;
+      }
+      case 0x0C4: case 0x0E4: // xsmsubadp, xsmsubmdp (VSX scalar multiply-subtract double-precision)
+      {
+         IRTemp frT = newTemp(Ity_F64);
+         Bool mdp = opc2 == 0x0E4;
+         DIP("xsmsub%sdp v%d,v%d,v%d\n", mdp ? "m" : "a", (UInt)XT, (UInt)XA, (UInt)XB);
+         assign( frT, unop( Iop_ReinterpI64asF64, unop( Iop_V128HIto64,
+                                                        getVSReg( XT ) ) ) );
+         putVSReg( XT, binop( Iop_64HLtoV128, unop( Iop_ReinterpF64asI64,
+                                                    qop( Iop_MSubF64, rm,
+                                                         mkexpr( frA ),
+                                                         mkexpr( mdp ? frT : frB ),
+                                                         mkexpr( mdp ? frB : frT ) ) ),
+                              mkU64( 0 ) ) );
+         break;
+      }
+      case 0x284: case 0x2A4: // xsnmaddadp, xsnmaddmdp (VSX scalar multiply-add double-precision)
+      {
+         /* TODO: mpj -- Naturally, I expected to be able to leverage the implementation
+          * of fnmadd and use pretty much the same code. However, that code has a bug in the
+          * way it blindly negates the signbit, even if the floating point result is a NaN.
+          * So, the TODO is to fix fnmadd (which I'll do in a different patch).
+          */
+         ULong signbit_mask = 0x8000000000000000ULL;
+         Bool mdp = opc2 == 0x2A4;
+         IRTemp frT = newTemp(Ity_F64);
+         IRTemp maddResult = newTemp(Ity_I64);
+         IRTemp negatedResult = newTemp(Ity_I64);
+         IRTemp signbit_32 = newTemp(Ity_I32);
+         IRTemp resultantSignbit = newTemp(Ity_I1);
+
+         DIP("xsnmadd%sdp v%d,v%d,v%d\n", mdp ? "m" : "a", (UInt)XT, (UInt)XA, (UInt)XB);
+         assign( frT, unop( Iop_ReinterpI64asF64, unop( Iop_V128HIto64,
+                                                        getVSReg( XT ) ) ) );
+         assign( maddResult, unop( Iop_ReinterpF64asI64, qop( Iop_MAddF64, rm,
+                                                              mkexpr( frA ),
+                                                              mkexpr( mdp ? frT : frB ),
+                                                              mkexpr( mdp ? frB : frT ) ) ) );
+         assign( signbit_32, binop( Iop_Shr32,
+                                unop( Iop_64HIto32,
+                                       binop( Iop_And64, mkexpr( maddResult ),
+                                              mkU64( signbit_mask ) ) ),
+                                       mkU8( 31 ) ) );
+         /* We negate the signbit if and only if the intermediate result from the
+          * multiply-add was NOT a NaN.  This is an XNOR predicate.
+          */
+         assign( resultantSignbit,
+                 unop( Iop_Not1,
+                       binop( Iop_CmpEQ32,
+                                     binop( Iop_Xor32, mkexpr( signbit_32 ),
+                                            unop( Iop_1Uto32,
+                                                  is_NaN( maddResult ) ) ),
+                                     mkU32( 1 ) ) ) );
+
+         assign( negatedResult,
+                 binop( Iop_Or64, binop( Iop_And64, mkexpr( maddResult ),
+                                         mkU64( ~signbit_mask ) ),
+                        binop( Iop_32HLto64,
+                               binop( Iop_Shl32,
+                                      unop( Iop_1Uto32,
+                                            mkexpr( resultantSignbit ) ),
+                                      mkU8( 31 ) ), mkU32( 0 ) ) ) );
+
+         putVSReg( XT, binop( Iop_64HLtoV128, mkexpr( negatedResult ),
+                              mkU64( 0 ) ) );
+         break;
+      }
+      case 0x0C0: // xsmuldp (VSX Scalar Multiply Double-Precision)
+         DIP("xsmuldp v%d,v%d,v%d\n", (UInt)XT, (UInt)XA, (UInt)XB);
+         putVSReg( XT, binop( Iop_64HLtoV128, unop( Iop_ReinterpF64asI64,
+                                                    triop( Iop_MulF64, rm,
+                                                           mkexpr( frA ),
+                                                           mkexpr( frB ) ) ),
+                              mkU64( 0 ) ) );
+         break;
+      case 0x0A0: // xssubdp (VSX Scalar Subtract Double-Precision)
+         DIP("xssubdp v%d,v%d,v%d\n", (UInt)XT, (UInt)XA, (UInt)XB);
+         putVSReg( XT, binop( Iop_64HLtoV128, unop( Iop_ReinterpF64asI64,
+                                                    triop( Iop_SubF64, rm,
+                                                           mkexpr( frA ),
+                                                           mkexpr( frB ) ) ),
+                              mkU64( 0 ) ) );
+         break;
+
+      default:
+         vex_printf( "dis_vx_arith(ppc)(opc2)\n" );
+         return False;
+   }
+   return True;
+}
+
+/*
+ * VSX Floating Point Compare Instructions
+ */
+static Bool
+dis_vx_cmp( UInt theInstr, UInt opc2 )
+{
+   /* XX3-Form and XX2-Form */
+   UChar opc1 = ifieldOPC( theInstr );
+   UChar crfD     = toUChar( IFIELD( theInstr, 23, 3 ) );
+   IRTemp ccPPC32 = newTemp(Ity_I32);
+   IRTemp ccIR    = newTemp(Ity_I32);
+   UChar XA       = ifieldRegXA ( theInstr );
+   UChar XB       = ifieldRegXB ( theInstr );
+   IRTemp frA     = newTemp(Ity_F64);
+   IRTemp frB     = newTemp(Ity_F64);
+
+   if (opc1 != 0x3C) {
+      vex_printf( "dis_vx_cmp(ppc)(instr)\n" );
+      return False;
+   }
+
+   assign(frA, unop(Iop_ReinterpI64asF64, unop(Iop_V128HIto64, getVSReg( XA ))));
+   assign(frB, unop(Iop_ReinterpI64asF64, unop(Iop_V128HIto64, getVSReg( XB ))));
+   switch (opc2) {
+      case 0x08C: case 0x0AC: // xscmpudp, xscmpodp
+         /* Note: Differences between xscmpudp and xscmpodp are only in
+          * exception flag settings, which aren't supported anyway. */
+         DIP("xscmp%sdp crf%d,fr%u,fr%u\n", opc2 == 0x08c ? "u" : "o",
+                                           crfD, (UInt)XA, (UInt)XB);
+         assign( ccIR, binop(Iop_CmpF64, mkexpr(frA), mkexpr(frB)) );
+
+         /* Map compare result from IR to PPC32 */
+         /*
+           FP cmp result | PPC | IR
+           --------------------------
+           UN            | 0x1 | 0x45
+           EQ            | 0x2 | 0x40
+           GT            | 0x4 | 0x00
+           LT            | 0x8 | 0x01
+         */
+
+         // ccPPC32 = Shl(1, (~(ccIR>>5) & 2)
+         //                    | ((ccIR ^ (ccIR>>6)) & 1)
+         assign(
+            ccPPC32,
+            binop(
+               Iop_Shl32,
+               mkU32(1),
+               unop(
+                  Iop_32to8,
+                  binop(
+                     Iop_Or32,
+                     binop(
+                        Iop_And32,
+                        unop(
+                           Iop_Not32,
+                           binop(Iop_Shr32, mkexpr(ccIR), mkU8(5))
+                        ),
+                        mkU32(2)
+                     ),
+                     binop(
+                        Iop_And32,
+                        binop(
+                           Iop_Xor32,
+                           mkexpr(ccIR),
+                           binop(Iop_Shr32, mkexpr(ccIR), mkU8(6))
+                        ),
+                        mkU32(1)
+                     )
+                  )
+               )
+            )
+         );
+
+         putGST_field( PPC_GST_CR, mkexpr(ccPPC32), crfD );
+
+         break;
+      default:
+         vex_printf( "dis_vx_cmp(ppc)(opc2)\n" );
+         return False;
+   }
+   return True;
+}
+/*
+ * VSX Move Instructions
+ */
+static Bool
+dis_vx_move( UInt theInstr, UInt opc2 )
+{
+   /* XX3-Form and XX2-Form */
+   UChar opc1 = ifieldOPC( theInstr );
+   UChar XT = ifieldRegXT ( theInstr );
+   UChar XA = ifieldRegXA ( theInstr );
+   UChar XB = ifieldRegXB ( theInstr );
+   IRTemp vA = newTemp( Ity_V128 );
+   IRTemp vB = newTemp( Ity_V128 );
+
+   if (opc1 != 0x3C) {
+      vex_printf( "dis_vx_move(ppc)(instr)\n" );
+      return False;
+   }
+
+   assign( vA, getVSReg( XA ) );
+   assign( vB, getVSReg( XB ) );
+
+   /* For all the VSX move instructions, the contents of doubleword element 1
+    * of VSX[XT] are undefined after the operation; therefore, we can simply
+    * move the entire array element where it makes sense to do so.
+    */
+
+   switch (opc2) {
+      case 0x2B2: // xsabsdp (VSX scalar absolute value double-precision
+      {
+         /* Move abs val of dw 0 of VSX[XB] to dw 0 of VSX[XT]. */
+         IRTemp absVal = newTemp(Ity_V128);
+         assign(absVal, binop(Iop_ShrV128, binop(Iop_ShlV128, mkexpr(vB), mkU8(1)), mkU8(1)));
+         DIP("xsabsdp v%d,v%d\n", (UInt)XT, (UInt)XB);
+         putVSReg(XT, mkexpr(absVal));
+         break;
+      }
+      case 0x2C0: // xscpsgndp
+      {
+         /* Scalar copy sign double-precision */
+         IRTemp vecA_signbit = newTemp(Ity_V128);
+         IRTemp vecB_no_signbit = newTemp(Ity_V128);
+         IRTemp vec_result = newTemp(Ity_V128);
+         DIP("xscpsgndp v%d,v%d v%d\n", (UInt)XT, (UInt)XA, (UInt)XB);
+         assign( vecB_no_signbit, binop( Iop_ShrV128, binop( Iop_ShlV128,
+                                                             mkexpr( vB ),
+                                                             mkU8( 1 ) ),
+                                         mkU8( 1 ) ) );
+         assign( vecA_signbit, binop( Iop_ShlV128, binop( Iop_ShrV128,
+                                                          mkexpr( vA ),
+                                                          mkU8( 127 ) ),
+                                      mkU8( 127 ) ) );
+         assign( vec_result, binop( Iop_OrV128, mkexpr(vecA_signbit), mkexpr( vecB_no_signbit ) ) );
+         putVSReg(XT, mkexpr(vec_result));
+         break;
+      }
+      case 0x2D2: // xsnabsdp
+      {
+         /* Scalar negative absolute value double-precision */
+         IRTemp vec_neg_signbit = newTemp(Ity_V128);
+         DIP("xsnabsdp v%d,v%d\n", (UInt)XT, (UInt)XB);
+         assign( vec_neg_signbit, unop( Iop_NotV128, binop( Iop_ShrV128,
+                                                            mkV128( 0xffff ),
+                                                            mkU8( 1 ) ) ) );
+         putVSReg(XT, binop(Iop_OrV128, mkexpr(vec_neg_signbit), mkexpr(vB)));
+         break;
+      }
+      case 0x2F2: // xsnegdp
+      {
+         /* Scalar negate double-precision */
+         IRTemp vecB_no_signbit = newTemp(Ity_V128);
+         IRTemp vecB_signbit_comp = newTemp(Ity_V128);
+         DIP("xsnabsdp v%d,v%d\n", (UInt)XT, (UInt)XB);
+         assign( vecB_no_signbit, binop( Iop_ShrV128, binop( Iop_ShlV128,
+                                                             mkexpr( vB ),
+                                                             mkU8( 1 ) ),
+                                         mkU8( 1 ) ) );
+         assign( vecB_signbit_comp, binop( Iop_ShlV128,
+                                           unop( Iop_NotV128,
+                                                 binop( Iop_ShrV128,
+                                                        mkexpr( vB ),
+                                                        mkU8( 127 ) ) ),
+                                           mkU8( 127 ) ) );
+         putVSReg( XT, binop( Iop_OrV128, mkexpr( vecB_no_signbit ),
+                              mkexpr( vecB_signbit_comp ) ) );
+         break;
+      }
+
+      default:
+         vex_printf( "dis_vx_move(ppc)(opc2)\n" );
+         return False;
+   }
+   return True;
+}
+
+/*
+ * VSX Logical Instructions
+ */
+static Bool
+dis_vx_logic ( UInt theInstr, UInt opc2 )
+{
+   /* XX3-Form */
+   UChar opc1 = ifieldOPC( theInstr );
+   UChar XT = ifieldRegXT ( theInstr );
+   UChar XA = ifieldRegXA ( theInstr );
+   UChar XB = ifieldRegXB ( theInstr );
+   IRTemp vA = newTemp( Ity_V128 );
+   IRTemp vB = newTemp( Ity_V128 );
+
+   if (opc1 != 0x3C) {
+      vex_printf( "dis_vx_logic(ppc)(instr)\n" );
+      return False;
+   }
+
+   assign( vA, getVSReg( XA ) );
+   assign( vB, getVSReg( XB ) );
+
+   switch (opc2) {
+      case 0x268: // xxlxor
+         DIP("xxlxor v%d,v%d,v%d\n", (UInt)XT, (UInt)XA, (UInt)XB);
+         putVSReg( XT, binop( Iop_XorV128, mkexpr( vA ), mkexpr( vB ) ) );
+         break;
+      case 0x248: // xxlor
+         DIP("xxlor v%d,v%d,v%d\n", (UInt)XT, (UInt)XA, (UInt)XB);
+         putVSReg( XT, binop( Iop_OrV128, mkexpr( vA ), mkexpr( vB ) ) );
+         break;
+      case 0x288: // xxlnor
+         DIP("xxlnor v%d,v%d,v%d\n", (UInt)XT, (UInt)XA, (UInt)XB);
+         putVSReg( XT, unop( Iop_NotV128, binop( Iop_OrV128, mkexpr( vA ),
+                                                 mkexpr( vB ) ) ) );
+         break;
+      case 0x208: // xxland
+         DIP("xxland v%d,v%d,v%d\n", (UInt)XT, (UInt)XA, (UInt)XB);
+         putVSReg( XT, binop( Iop_AndV128, mkexpr( vA ), mkexpr( vB ) ) );
+         break;
+      case 0x228: //xxlandc
+         DIP("xxlandc v%d,v%d,v%d\n", (UInt)XT, (UInt)XA, (UInt)XB);
+         putVSReg( XT, binop( Iop_AndV128, mkexpr( vA ), unop( Iop_NotV128,
+                                                               mkexpr( vB ) ) ) );
+         break;
+      default:
+         vex_printf( "dis_vx_logic(ppc)(opc2)\n" );
+         return False;
+   }
+   return True;
+}
+
+/*
+ * VSX Load Instructions
+ * NOTE: VSX supports word-aligned storage access.
+ */
+static Bool
+dis_vx_load ( UInt theInstr )
+{
+   /* XX1-Form */
+   UChar opc1 = ifieldOPC( theInstr );
+   UChar XT = ifieldRegXT ( theInstr );
+   UChar rA_addr = ifieldRegA( theInstr );
+   UChar rB_addr = ifieldRegB( theInstr );
+   UInt opc2 = ifieldOPClo10( theInstr );
+
+   IRType ty = mode64 ? Ity_I64 : Ity_I32;
+   IRTemp EA = newTemp( ty );
+
+   if (opc1 != 0x1F) {
+      vex_printf( "dis_vx_load(ppc)(instr)\n" );
+      return False;
+   }
+
+   assign( EA, ea_rAor0_idxd( rA_addr, rB_addr ) );
+
+   switch (opc2) {
+   case 0x24C: // lxsdx
+   {
+      IRExpr * exp;
+      DIP("lxsdx %d,r%u,r%u\n", (UInt)XT, rA_addr, rB_addr);
+      exp = loadBE( Ity_I64, mkexpr( EA ) );
+      // We need to pass an expression of type Ity_V128 with putVSReg, but the load
+      // we just performed is only a DW.  But since the contents of VSR[XT] element 1
+      // are undefined after this operation, we can just do a splat op.
+      putVSReg( XT, binop( Iop_64HLtoV128, exp, exp ) );
+      break;
+   }
+   case 0x34C: // lxvd2x
+   {
+      IROp addOp = ty == Ity_I64 ? Iop_Add64 : Iop_Add32;
+      IRExpr * high, *low;
+      ULong ea_off = 8;
+      IRExpr* high_addr;
+      DIP("lxvd2x %d,r%u,r%u\n", (UInt)XT, rA_addr, rB_addr);
+      high = loadBE( Ity_I64, mkexpr( EA ) );
+      high_addr = binop( addOp, mkexpr( EA ), ty == Ity_I64 ? mkU64( ea_off )
+            : mkU32( ea_off ) );
+      low = loadBE( Ity_I64, high_addr );
+      putVSReg( XT, binop( Iop_64HLtoV128, high, low ) );
+      break;
+   }
+   case 0x14C: // lxvdsx
+   {
+      IRTemp data = newTemp(Ity_I64);
+      DIP("lxvdsx %d,r%u,r%u\n", (UInt)XT, rA_addr, rB_addr);
+      assign( data, loadBE( Ity_I64, mkexpr( EA ) ) );
+      putVSReg( XT, binop( Iop_64HLtoV128, mkexpr( data ), mkexpr( data ) ) );
+      break;
+   }
+   case 0x30C:
+   {
+      IRExpr * t3, *t2, *t1, *t0;
+      UInt ea_off = 0;
+      IRExpr* irx_addr;
+
+      DIP("lxvw4x %d,r%u,r%u\n", (UInt)XT, rA_addr, rB_addr);
+      t3 = loadBE( Ity_I32,  mkexpr( EA ) );
+      ea_off += 4;
+      irx_addr = binop( mkSzOp( ty, Iop_Add8 ), mkexpr( EA ),
+                        ty == Ity_I64 ? mkU64( ea_off ) : mkU32( ea_off ) );
+      t2 = loadBE( Ity_I32, irx_addr );
+      ea_off += 4;
+      irx_addr = binop( mkSzOp( ty, Iop_Add8 ), mkexpr( EA ),
+                        ty == Ity_I64 ? mkU64( ea_off ) : mkU32( ea_off ) );
+      t1 = loadBE( Ity_I32, irx_addr );
+      ea_off += 4;
+      irx_addr = binop( mkSzOp( ty, Iop_Add8 ), mkexpr( EA ),
+                        ty == Ity_I64 ? mkU64( ea_off ) : mkU32( ea_off ) );
+      t0 = loadBE( Ity_I32, irx_addr );
+      putVSReg( XT, binop( Iop_64HLtoV128, binop( Iop_32HLto64, t3, t2 ),
+                           binop( Iop_32HLto64, t1, t0 ) ) );
+      break;
+   }
+   default:
+      vex_printf( "dis_vx_load(ppc)(opc2)\n" );
+      return False;
+   }
+   return True;
+}
+
+/*
+ * VSX Store Instructions
+ * NOTE: VSX supports word-aligned storage access.
+ */
+static Bool
+dis_vx_store ( UInt theInstr )
+{
+   /* XX1-Form */
+   UChar opc1 = ifieldOPC( theInstr );
+   UChar XS = ifieldRegXS( theInstr );
+   UChar rA_addr = ifieldRegA( theInstr );
+   UChar rB_addr = ifieldRegB( theInstr );
+   IRTemp vS = newTemp( Ity_V128 );
+   UInt opc2 = ifieldOPClo10( theInstr );
+
+   IRType ty = mode64 ? Ity_I64 : Ity_I32;
+   IRTemp EA = newTemp( ty );
+
+   if (opc1 != 0x1F) {
+      vex_printf( "dis_vx_store(ppc)(instr)\n" );
+      return False;
+   }
+
+   assign( EA, ea_rAor0_idxd( rA_addr, rB_addr ) );
+   assign( vS, getVSReg( XS ) );
+
+   switch (opc2) {
+   case 0x2CC:
+   {
+      IRExpr * high64;
+      DIP("stxsdx %d,r%u,r%u\n", (UInt)XS, rA_addr, rB_addr);
+      high64 = unop( Iop_V128HIto64, mkexpr( vS ) );
+      storeBE( mkexpr( EA ), high64 );
+      break;
+   }
+   case 0x3CC:
+   {
+      IRExpr * high64, *low64;
+      DIP("stxvd2x %d,r%u,r%u\n", (UInt)XS, rA_addr, rB_addr);
+      high64 = unop( Iop_V128HIto64, mkexpr( vS ) );
+      low64 = unop( Iop_V128to64, mkexpr( vS ) );
+      storeBE( mkexpr( EA ), high64 );
+      storeBE( binop( mkSzOp( ty, Iop_Add8 ), mkexpr( EA ), ty == Ity_I64 ? mkU64( 8 )
+            : mkU32( 8 ) ), low64 );
+      break;
+   }
+   case 0x38C:
+   {
+      UInt ea_off = 0;
+      IRExpr* irx_addr;
+      IRTemp hi64 = newTemp( Ity_I64 );
+      IRTemp lo64 = newTemp( Ity_I64 );
+
+      DIP("stxvw4x %d,r%u,r%u\n", (UInt)XS, rA_addr, rB_addr);
+
+      // This instruction supports word-aligned stores, so EA may not be
+      // quad-word aligned.  Therefore, do 4 individual word-size stores.
+      assign( hi64, unop( Iop_V128HIto64, mkexpr( vS ) ) );
+      assign( lo64, unop( Iop_V128to64, mkexpr( vS ) ) );
+
+      storeBE( mkexpr( EA ), unop( Iop_64HIto32, mkexpr( hi64 ) ) );
+      ea_off += 4;
+      irx_addr = binop( mkSzOp( ty, Iop_Add8 ), mkexpr( EA ),
+                        ty == Ity_I64 ? mkU64( ea_off ) : mkU32( ea_off ) );
+      storeBE( irx_addr, unop( Iop_64to32, mkexpr( hi64 ) ) );
+      ea_off += 4;
+      irx_addr = binop( mkSzOp( ty, Iop_Add8 ), mkexpr( EA ),
+                        ty == Ity_I64 ? mkU64( ea_off ) : mkU32( ea_off ) );
+      storeBE( irx_addr, unop( Iop_64HIto32, mkexpr( lo64 ) ) );
+      ea_off += 4;
+      irx_addr = binop( mkSzOp( ty, Iop_Add8 ), mkexpr( EA ),
+                        ty == Ity_I64 ? mkU64( ea_off ) : mkU32( ea_off ) );
+      storeBE( irx_addr, unop( Iop_64to32, mkexpr( lo64 ) ) );
+
+      break;
+   }
+   default:
+      vex_printf( "dis_vx_store(ppc)(opc2)\n" );
+      return False;
+   }
+   return True;
+}
+
+/*
+ * VSX Permute Instructions
+ */
+static Bool
+dis_vx_permute( UInt theInstr, UInt opc2 )
+{
+   /* XX3-Form */
+   UChar opc1 = ifieldOPC( theInstr );
+   UChar XT = ifieldRegXT ( theInstr );
+   UChar XA = ifieldRegXA ( theInstr );
+   UChar XB = ifieldRegXB ( theInstr );
+   IRTemp vT = newTemp( Ity_V128 );
+   IRTemp vA = newTemp( Ity_V128 );
+   IRTemp vB = newTemp( Ity_V128 );
+
+   if (opc1 != 0x3C) {
+      vex_printf( "dis_vx_permute(ppc)(instr)\n" );
+      return False;
+   }
+
+   assign( vA, getVSReg( XA ) );
+   assign( vB, getVSReg( XB ) );
+
+   switch (opc2) {
+      case 0x8: // xxsldwi (VSX Shift Left Double by Word Immediate)
+      {
+         UChar SHW = ifieldSHW ( theInstr );
+         IRTemp result = newTemp(Ity_V128);
+         if ( SHW != 0 ) {
+             IRTemp hi = newTemp(Ity_V128);
+             IRTemp lo = newTemp(Ity_V128);
+             assign( hi, binop(Iop_ShlV128, mkexpr(vA), mkU8(SHW*32)) );
+             assign( lo, binop(Iop_ShrV128, mkexpr(vB), mkU8(128-SHW*32)) );
+             assign ( result, binop(Iop_OrV128, mkexpr(hi), mkexpr(lo)) );
+         } else
+             assign ( result, mkexpr(vA) );
+         DIP("xxsldwi v%d,v%d,v%d,%d\n", (UInt)XT, (UInt)XA, (UInt)XB, (UInt)SHW);
+         putVSReg( XT, mkexpr(result) );
+         break;
+      }
+      case 0x28: // xpermdi (VSX Permute Doubleword Immediate)
+      {
+         UChar DM = ifieldDM ( theInstr );
+         IRTemp hi = newTemp(Ity_I64);
+         IRTemp lo = newTemp(Ity_I64);
+
+         if (DM & 0x2)
+           assign( hi, unop(Iop_V128to64, mkexpr(vA)) );
+         else
+           assign( hi, unop(Iop_V128HIto64, mkexpr(vA)) );
+
+         if (DM & 0x1)
+           assign( lo, unop(Iop_V128to64, mkexpr(vB)) );
+         else
+           assign( lo, unop(Iop_V128HIto64, mkexpr(vB)) );
+
+         assign( vT, binop(Iop_64HLtoV128, mkexpr(hi), mkexpr(lo)) );
+
+         DIP("xxpermdi v%d,v%d,v%d,0x%x\n", (UInt)XT, (UInt)XA, (UInt)XB, (UInt)DM);
+         putVSReg( XT, mkexpr( vT ) );
+         break;
+      }
+      case 0x48: // xxmrghw (VSX Merge High Word)
+      case 0xc8: // xxmrglw (VSX Merge Low Word)
+      {
+         char type = (opc2 == 0x48) ? 'h' : 'l';
+         IROp word_op = (opc2 == 0x48) ? Iop_V128HIto64 : Iop_V128to64;
+         IRTemp a64 = newTemp(Ity_I64);
+         IRTemp ahi32 = newTemp(Ity_I32);
+         IRTemp alo32 = newTemp(Ity_I32);
+         IRTemp b64 = newTemp(Ity_I64);
+         IRTemp bhi32 = newTemp(Ity_I32);
+         IRTemp blo32 = newTemp(Ity_I32);
+
+         assign( a64, unop(word_op, mkexpr(vA)) );
+         assign( ahi32, unop(Iop_64HIto32, mkexpr(a64)) );
+         assign( alo32, unop(Iop_64to32, mkexpr(a64)) );
+
+         assign( b64, unop(word_op, mkexpr(vB)) );
+         assign( bhi32, unop(Iop_64HIto32, mkexpr(b64)) );
+         assign( blo32, unop(Iop_64to32, mkexpr(b64)) );
+
+         assign( vT, binop(Iop_64HLtoV128,
+                           binop(Iop_32HLto64, mkexpr(ahi32), mkexpr(bhi32)),
+                           binop(Iop_32HLto64, mkexpr(alo32), mkexpr(blo32))) );
+
+         DIP("xxmrg%cw v%d,v%d,v%d\n", type, (UInt)XT, (UInt)XA, (UInt)XB);
+         putVSReg( XT, mkexpr( vT ) );
+         break;
+      }
+
+      default:
+         vex_printf( "dis_vx_permute(ppc)(opc2)\n" );
+         return False;
+   }
+   return True;
+}
+
 /*
   AltiVec Load Instructions
 */
@@ -7025,7 +8655,6 @@ static Bool dis_av_load ( VexAbiInfo* vbi, UInt theInstr )
    return True;
 }
 
-
 /*
   AltiVec Store Instructions
 */
@@ -8863,72 +10492,222 @@ static Bool dis_av_fp_convert ( UInt theInstr )
 }
 
 
+/* The 0x3C primary opcode (VSX category) uses several different forms of
+ * extended opcodes:
+ *   o XX2-form:
+ *      - [10:2] (IBM notation [21:29])
+ *   o XX3-form variants:
+ *       - variant 1: [10:3] (IBM notation [21:28])
+ *       - variant 2: [9:3] (IBM notation [22:28])
+ *       - variant 3: [7:3] (IBM notation [24:28])
+ *   o XX-4 form:
+ *      - [10:6] (IBM notation [21:25])
+ *
+ * The XX2-form needs bit 0 masked from the standard extended opcode
+ * as returned by ifieldOPClo10; the XX3-form needs bits 0 and 1 masked;
+ * and the XX4-form needs bits 0, 1, and 2 masked.  Additionally, the
+ * XX4 and XX3 (variants 2 and 3) forms need certain bits masked on the
+ * front end since their encoding does not begin at bit 21 like the standard
+ * format.
+ *
+ * The get_VSX60_opc2() function uses the vsx_insn array below to obtain the
+ * secondary opcode for such VSX instructions.
+ *
+*/
 
-/*------------------------------------------------------------*/
-/*--- POWER6 Instruction Translation                       ---*/
-/*------------------------------------------------------------*/
-
-static
-Bool dis_P6 ( UInt theInstr,
-              Bool allow_F, Bool allow_V, Bool allow_FX, Bool allow_GX)
-{
-   UInt opc, rd, ra, rb, opc2, dot;
 
-   /* This is a hack.  We should do P6 capability checking properly.
-      But anyway, make a guess at whether we should even try to handle
-      this instruction.  All P6 capable CPUs should be able to handle
-      F, V, FX and GX, so that seems like a good check. */
-   if (! (allow_F && allow_V && allow_FX && allow_GX) )
-      return False;
-   if (!mode64)
-      return False; /* only support P6 in 64-bit mode for now */
-
-   opc  = ifieldOPC(theInstr);     /* primary opcode */
-   rd   = ifieldRegDS(theInstr);   /* dst reg */
-   ra   = ifieldRegA(theInstr);    /* first source reg */
-   rb   = ifieldRegB(theInstr);    /* second source reg */
-   opc2 = ifieldOPClo10(theInstr); /* secondary opc, 10:1 */
-   dot  = ifieldBIT0(theInstr);    /* Rc field, bit 0 */
-
-   if (opc == 63 && ra == 0/*presumably*/ && opc2 == 488) {
-      /* frim (Floating Round to Integer Minus, PPC ISA 2.05 p137) */
-      if (dot) return False;
-      putFReg( rd, unop(Iop_RoundF64toF64_NegINF, getFReg( rb )) );
-      DIP("frim%s fr%u,fr%u\n", dot ? "." : "", rd, rb);
-      return True;
+struct vsx_insn {
+   UInt opcode;
+   Char * name;
+};
+
+//  ATTENTION:  Keep this array sorted on the opcocde!!!
+static struct vsx_insn vsx_all[] = {
+      { 0x8, "xxsldwi" },
+      { 0x18, "xxsel" },
+      { 0x28, "xxpermdi" },
+      { 0x48, "xxmrghw" },
+      { 0x80, "xsadddp" },
+      { 0x84, "xsmaddadp" },
+      { 0x8c, "xscmpudp" },
+      { 0x90, "xscvdpuxws" },
+      { 0x92, "xsrdpi" },
+      { 0x94, "xsrsqrtedp" },
+      { 0x96, "xssqrtdp" },
+      { 0xa0, "xssubdp" },
+      { 0xa4, "xsmaddmdp" },
+      { 0xac, "xscmpodp" },
+      { 0xb0, "xscvdpsxws" },
+      { 0xb2, "xsrdpiz" },
+      { 0xb4, "xsredp" },
+      { 0xc0, "xsmuldp" },
+      { 0xc4, "xsmsubadp" },
+      { 0xc8, "xxmrglw" },
+      { 0xd2, "xsrdpip" },
+      { 0xd4, "xstsqrtdp" },
+      { 0xd6, "xsrdpic" },
+      { 0xe0, "xsdivdp" },
+      { 0xe4, "xsmsubmdp" },
+      { 0xf2, "xsrdpim" },
+      { 0xf4, "xstdivdp" },
+      { 0x100, "xvaddsp" },
+      { 0x104, "xvmaddasp" },
+      { 0x10c, "xvcmpeqsp" },
+      { 0x110, "xvcvspuxws" },
+      { 0x112, "xvrspi" },
+      { 0x114, "xvrsqrtesp" },
+      { 0x116, "xvsqrtsp" },
+      { 0x120, "xvsubsp" },
+      { 0x124, "xvmaddmsp" },
+      { 0x12c, "xvcmpgtsp" },
+      { 0x130, "xvcvspsxws" },
+      { 0x132, "xvrspiz" },
+      { 0x134, "xvresp" },
+      { 0x140, "xvmulsp" },
+      { 0x144, "xvmsubasp" },
+      { 0x148, "xxspltw" },
+      { 0x14c, "xvcmpgesp" },
+      { 0x150, "xvcvuxwsp" },
+      { 0x152, "xvrspip" },
+      { 0x154, "xvtsqrtsp" },
+      { 0x156, "xvrspic" },
+      { 0x160, "xvdivsp" },
+      { 0x164, "xvmsubmsp" },
+      { 0x170, "xvcvsxwsp" },
+      { 0x172, "xvrspim" },
+      { 0x174, "xvtdivsp" },
+      { 0x180, "xvadddp" },
+      { 0x184, "xvmaddadp" },
+      { 0x18c, "xvcmpeqdp" },
+      { 0x190, "xvcvdpuxws" },
+      { 0x192, "xvrdpi" },
+      { 0x194, "xvrsqrtedp" },
+      { 0x196, "xvsqrtdp" },
+      { 0x1a0, "xvsubdp" },
+      { 0x1a4, "xvmaddmdp" },
+      { 0x1ac, "xvcmpgtdp" },
+      { 0x1b0, "xvcvdpsxws" },
+      { 0x1b2, "xvrdpiz" },
+      { 0x1b4, "xvredp" },
+      { 0x1c0, "xvmuldp" },
+      { 0x1c4, "xvmsubadp" },
+      { 0x1cc, "xvcmpgedp" },
+      { 0x1d0, "xvcvuxwdp" },
+      { 0x1d2, "xvrdpip" },
+      { 0x1d4, "xvtsqrtdp" },
+      { 0x1d6, "xvrdpic" },
+      { 0x1e0, "xvdivdp" },
+      { 0x1e4, "xvmsubmdp" },
+      { 0x1f0, "xvcvsxwdp" },
+      { 0x1f2, "xvrdpim" },
+      { 0x1f4, "xvtdivdp" },
+      { 0x208, "xxland" },
+      { 0x212, "xscvdpsp" },
+      { 0x228, "xxlandc" },
+      { 0x248 , "xxlor" },
+      { 0x268, "xxlxor" },
+      { 0x280, "xsmaxdp" },
+      { 0x284, "xsnmaddadp" },
+      { 0x288, "xxlnor" },
+      { 0x290, "xscvdpuxds" },
+      { 0x292, "xscvspdp" },
+      { 0x2a0, "xsmindp" },
+      { 0x2a4, "xsnmaddmdp" },
+      { 0x2b0, "xscvdpsxds" },
+      { 0x2b2, "xsabsdp" },
+      { 0x2c0, "xscpsgndp" },
+      { 0x2c4, "xsnmsubadp" },
+      { 0x2d0, "xscvuxddp" },
+      { 0x2d2, "xsnabsdp" },
+      { 0x2e4, "xsnmsubmdp" },
+      { 0x2f0, "xscvsxddp" },
+      { 0x2f2, "xsnegdp" },
+      { 0x300, "xvmaxsp" },
+      { 0x304, "xvnmaddasp" },
+      { 0x30c, "xvcmpeqsp." },
+      { 0x310, "xvcvspuxds" },
+      { 0x312, "xvcvdpsp" },
+      { 0x320, "xvminsp" },
+      { 0x324, "xvnmaddmsp" },
+      { 0x32c, "xvcmpgtsp." },
+      { 0x330, "xvcvspsxds" },
+      { 0x332, "xvabssp" },
+      { 0x340, "xvcpsgnsp" },
+      { 0x344, "xvnmsubasp" },
+      { 0x34c, "xvcmpgesp." },
+      { 0x350, "xvcvuxdsp" },
+      { 0x352, "xvnabssp" },
+      { 0x364, "xvnmsubmsp" },
+      { 0x370, "xvcvsxdsp" },
+      { 0x372, "xvnegsp" },
+      { 0x380, "xvmaxdp" },
+      { 0x384, "xvnmaddadp" },
+      { 0x38c, "xvcmpeqdp." },
+      { 0x390, "xvcvdpuxds" },
+      { 0x392, "xvcvspdp" },
+      { 0x3a0, "xvmindp" },
+      { 0x3a4, "xvnmaddmdp" },
+      { 0x3ac, "xvcmpgtdp." },
+      { 0x3b0, "xvcvdpsxds" },
+      { 0x3b2, "xvabsdp" },
+      { 0x3c0, "xvcpsgndp" },
+      { 0x3c4, "xvnmsubadp" },
+      { 0x3cc, "xvcmpgedp." },
+      { 0x3d0, "xvcvuxddp" },
+      { 0x3d2, "xvnabsdp" },
+      { 0x3e4, "xvnmsubmdp" },
+      { 0x3f0, "xvcvsxddp" },
+      { 0x3f2, "xvnegdp" }
+};
+#define VSX_ALL_LEN 135
+
+// ATTENTION: This search function assumes vsx_all array is sorted.
+static Int findVSXextOpCode(UInt opcode)
+{
+   Int low, mid, high;
+   low = 0;
+   high = VSX_ALL_LEN - 1;
+   while (low <= high) {
+      mid = (low + high)/2;
+      if (opcode < vsx_all[mid].opcode)
+         high = mid - 1;
+      else if (opcode > vsx_all[mid].opcode)
+         low = mid + 1;
+      else
+         return mid;
    }
+   return -1;
+}
 
-   if (opc == 63 && ra == 0/*presumably*/ && opc2 == 456) {
-      /* frip (Floating Round to Integer Plus, PPC ISA 2.05 p137) */
-      if (dot) return False;
-      putFReg( rd, unop(Iop_RoundF64toF64_PosINF, getFReg( rb )) );
-      DIP("frip%s fr%u,fr%u\n", dot ? "." : "", rd, rb);
-      return True;
-   }
 
-   if (opc == 63 && ra == 0/*presumably*/ && opc2 == 392) {
-      /* frin (Floating Round to Integer Nearest, PPC ISA 2.05 p137) */
-      if (dot) return False;
-      putFReg( rd, unop(Iop_RoundF64toF64_NEAREST, getFReg( rb )) );
-      DIP("frin%s fr%u,fr%u\n", dot ? "." : "", rd, rb);
-      return True;
-   }
+/* The full 10-bit extended opcode retrieved via ifieldOPClo10 is
+ * passed, and we then try to match it up with one of the above
+ * VSX forms.
+ */
+static UInt get_VSX60_opc2(UInt opc2_full)
+{
+#define XX2_MASK 0x000003FE
+#define XX3_1_MASK 0x000003FC
+#define XX3_2_MASK 0x000001FC
+#define XX3_3_MASK 0x0000007C
+#define XX4_MASK 0x000003E0
+   Int ret;
+   UInt vsxExtOpcode = 0;
 
-   if (opc == 63 && ra == 0/*presumably*/ && opc2 == 424) {
-      /* frin (Floating Round to Integer Zero, PPC ISA 2.05 p137) */
-      if (dot) return False;
-      putFReg( rd, unop(Iop_RoundF64toF64_ZERO, getFReg( rb )) );
-      DIP("friz%s fr%u,fr%u\n", dot ? "." : "", rd, rb);
-      return True;
-   }
+   if (( ret = findVSXextOpCode(opc2_full & XX2_MASK)) >= 0)
+      vsxExtOpcode = vsx_all[ret].opcode;
+   else if (( ret = findVSXextOpCode(opc2_full & XX3_1_MASK)) >= 0)
+      vsxExtOpcode = vsx_all[ret].opcode;
+   else if (( ret = findVSXextOpCode(opc2_full & XX3_2_MASK)) >= 0)
+      vsxExtOpcode = vsx_all[ret].opcode;
+   else if (( ret = findVSXextOpCode(opc2_full & XX3_3_MASK)) >= 0)
+      vsxExtOpcode = vsx_all[ret].opcode;
+   else if (( ret = findVSXextOpCode(opc2_full & XX4_MASK)) >= 0)
+      vsxExtOpcode = vsx_all[ret].opcode;
 
-   if (0)
-      vex_printf("dis_P6: %u %u %u %u %u %u\n", opc, rd, ra, rb, opc2, dot);
-   return False;
+   return vsxExtOpcode;
 }
 
-
-
 /*------------------------------------------------------------*/
 /*--- Disassemble a single instruction                     ---*/
 /*------------------------------------------------------------*/
@@ -8956,6 +10735,7 @@ DisResult disInstr_PPC_WRK (
    Bool      allow_V  = False;
    Bool      allow_FX = False;
    Bool      allow_GX = False;
+   Bool      allow_VX = False;
    UInt      hwcaps = archinfo->hwcaps;
    Long      delta;
 
@@ -8965,11 +10745,13 @@ DisResult disInstr_PPC_WRK (
       allow_V  = (0 != (hwcaps & VEX_HWCAPS_PPC64_V));
       allow_FX = (0 != (hwcaps & VEX_HWCAPS_PPC64_FX));
       allow_GX = (0 != (hwcaps & VEX_HWCAPS_PPC64_GX));
+      allow_VX = (0 != (hwcaps & VEX_HWCAPS_PPC64_VX));
    } else {
       allow_F  = (0 != (hwcaps & VEX_HWCAPS_PPC32_F));
       allow_V  = (0 != (hwcaps & VEX_HWCAPS_PPC32_V));
       allow_FX = (0 != (hwcaps & VEX_HWCAPS_PPC32_FX));
       allow_GX = (0 != (hwcaps & VEX_HWCAPS_PPC32_GX));
+      allow_VX = (0 != (hwcaps & VEX_HWCAPS_PPC32_VX));
    }
 
    /* The running delta */
@@ -9147,6 +10929,12 @@ DisResult disInstr_PPC_WRK (
       if (dis_fp_store( theInstr )) goto decode_success;
       goto decode_failure;
 
+      /* Floating Point Load Double Pair Instructions */
+   case 0x39: case 0x3D:
+      if (!allow_F) goto decode_noF;
+      if (dis_fp_pair( theInstr )) goto decode_success;
+      goto decode_failure;
+
    /* 64bit Integer Loads */
    case 0x3A:  // ld, ldu, lwa
       if (!mode64) goto decode_failure;
@@ -9155,6 +10943,20 @@ DisResult disInstr_PPC_WRK (
 
    case 0x3B:
       if (!allow_F) goto decode_noF;
+      opc2 = ifieldOPClo10(theInstr);
+      switch (opc2) {
+         case 0x3CE: // fcfidus (implemented as native insn
+            if (!allow_VX)
+               goto decode_noVX;
+            if (dis_fp_round( theInstr ))
+               goto decode_success;
+            goto decode_failure;
+         case 0x34E: // fcfids
+            if (dis_fp_round( theInstr ))
+               goto decode_success;
+            goto decode_failure;
+      }
+
       opc2 = IFIELD(theInstr, 1, 5);
       switch (opc2) {
       /* Floating Point Arith Instructions */
@@ -9181,12 +10983,64 @@ DisResult disInstr_PPC_WRK (
          if (!allow_GX) goto decode_noGX;
          if (dis_fp_arith(theInstr)) goto decode_success;
          goto decode_failure;
-         
+
       default:
          goto decode_failure;
       }
       break;
 
+   case 0x3C: // VSX instructions (except load/store)
+   {
+      UInt vsxOpc2 = get_VSX60_opc2(opc2);
+      /* The vsxOpc2 returned is the "normalized" value, representing the
+       * instructions secondary opcode as taken from the standard secondary
+       * opcode field [21:30] (IBM notatition), even if the actual field
+       * is non-standard.  These normalized values are given in the opcode
+       * appendices of the ISA 2.06 document.
+       */
+      if (vsxOpc2 == 0)
+         goto decode_failure;
+
+      switch (vsxOpc2) {
+         case 0x8: case 0x28: case 0x48: case 0xc8: // xxsldwi, xxpermdi, xxmrghw, xxmrglw
+            if (dis_vx_permute(theInstr, vsxOpc2)) goto decode_success;
+            goto decode_failure;
+         case 0x268: case 0x248: case 0x288: case 0x208: case 0x228: // xxlxor, xxlor, xxlnor, xxland, xxlandc
+            if (dis_vx_logic(theInstr, vsxOpc2)) goto decode_success;
+            goto decode_failure;
+         case 0x2B2: // xsabsdp
+            if (dis_vx_move(theInstr, vsxOpc2)) goto decode_success;
+            goto decode_failure;
+         case 0x2C0: // xscpsgndp
+            if (dis_vx_move(theInstr, vsxOpc2)) goto decode_success;
+            goto decode_failure;
+         case 0x2D2: // xsnabsdp
+            if (dis_vx_move(theInstr, vsxOpc2)) goto decode_success;
+            goto decode_failure;
+         case 0x2F2: // xsnegdp
+            if (dis_vx_move(theInstr, vsxOpc2)) goto decode_success;
+            goto decode_failure;
+         case 0x08C: case 0x0AC: // xscmpudp, xscmpodp
+            if (dis_vx_cmp(theInstr, vsxOpc2)) goto decode_success;
+            goto decode_failure;
+         case 0x080: case 0x0E0: // xsadddp, xsdivdp
+         case 0x084: case 0x0A4: // xsmaddadp, xsmaddmdp
+         case 0x0C4: case 0x0E4: // xsmsubadp, xsmsubmdp
+         case 0x284: case 0x2A4: // xsnmaddadp, xsnmaddmdp
+         case 0x0C0: // xsmuldp
+         case 0x0A0: // xssubdp
+            if (dis_vx_arith(theInstr, vsxOpc2)) goto decode_success;
+            goto decode_failure;
+         case 0x2B0: case 0x2F0: case 0x2D0: // xscvdpsxds, xscvsxddp, xscvuxddp
+            if (dis_vx_conv(theInstr, vsxOpc2)) goto decode_success;
+            goto decode_failure;
+
+         default:
+            goto decode_failure;
+      }
+      break;
+   }
+
    /* 64bit Integer Stores */
    case 0x3E:  // std, stdu
       if (!mode64) goto decode_failure;
@@ -9237,6 +11091,10 @@ DisResult disInstr_PPC_WRK (
          if (dis_fp_cmp(theInstr)) goto decode_success;
          goto decode_failure;
          
+      case 0x080: // ftdiv
+         if (dis_fp_ftdiv(theInstr)) goto decode_success;
+         goto decode_failure;
+
       /* Floating Point Rounding/Conversion Instructions */         
       case 0x00C: // frsp
       case 0x00E: // fctiw
@@ -9246,17 +11104,25 @@ DisResult disInstr_PPC_WRK (
       case 0x34E: // fcfid
          if (dis_fp_round(theInstr)) goto decode_success;
          goto decode_failure;
+      case 0x3CE: // fcfidu (implemented as native insn)
+         if (!allow_VX) goto decode_noVX;
+         if (dis_fp_round(theInstr)) goto decode_success;
+         goto decode_failure;
+
 
       /* Power6 rounding stuff */
       case 0x1E8: // frim
       case 0x1C8: // frip
       case 0x188: // frin
       case 0x1A8: // friz
-         if (dis_P6(theInstr, allow_F, allow_V, allow_FX, allow_GX))
+         /* A hack to check for P6 capability . . . */
+         if ((allow_F && allow_V && allow_FX && allow_GX) &&
+             (dis_fp_round(theInstr)))
             goto decode_success;
          goto decode_failure;
          
       /* Floating Point Move Instructions */         
+      case 0x008: // fcpsgn
       case 0x028: // fneg
       case 0x048: // fmr
       case 0x088: // fnabs
@@ -9330,6 +11196,10 @@ DisResult disInstr_PPC_WRK (
          if (dis_int_arith( theInstr )) goto decode_success;
          goto decode_failure;
 
+      case 0x1FC:                         // cmpb
+         if (dis_int_logic( theInstr )) goto decode_success;
+         goto decode_failure;
+
       default:
          break;  // Fall through...
       }
@@ -9348,6 +11218,7 @@ DisResult disInstr_PPC_WRK (
       case 0x11C: case 0x3BA: case 0x39A: // eqv,  extsb, extsh
       case 0x1DC: case 0x07C: case 0x1BC: // nand, nor,   or
       case 0x19C: case 0x13C:             // orc,  xor
+      case 0x2DF: case 0x25F:            // mftgpr, mffgpr
          if (dis_int_logic( theInstr )) goto decode_success;
          goto decode_failure;
 
@@ -9357,6 +11228,11 @@ DisResult disInstr_PPC_WRK (
          if (dis_int_logic( theInstr )) goto decode_success;
          goto decode_failure;
 
+         /* 64bit Integer Parity Instructions */
+      case 0xba: case 0x9a: // prtyd, prtyw
+         if (dis_int_parity( theInstr )) goto decode_success;
+         goto decode_failure;
+
       /* Integer Shift Instructions */
       case 0x018: case 0x318: case 0x338: // slw, sraw, srawi
       case 0x218:                         // srw
@@ -9399,7 +11275,7 @@ DisResult disInstr_PPC_WRK (
 
       /* Integer Load and Store with Byte Reverse Instructions */
       case 0x316: case 0x216: case 0x396: // lhbrx, lwbrx, sthbrx
-      case 0x296:                         // stwbrx
+      case 0x296: case 0x214:             // stwbrx, ldbrx
          if (dis_int_ldst_rev( theInstr )) goto decode_success;
          goto decode_failure;
          
@@ -9472,6 +11348,23 @@ DisResult disInstr_PPC_WRK (
          if (dis_fp_store( theInstr )) goto decode_success;
          goto decode_failure;
 
+         /* Floating Point Double Pair Indexed Instructions */
+      case 0x317: // lfdpx (Power6)
+      case 0x397: // stfdpx (Power6)
+         if (!allow_F) goto decode_noF;
+         if (dis_fp_pair(theInstr)) goto decode_success;
+         goto decode_failure;
+
+      case 0x357:                         // lfiwax
+         if (!allow_F) goto decode_noF;
+         if (dis_fp_load( theInstr )) goto decode_success;
+         goto decode_failure;
+
+      case 0x377:                         // lfiwzx
+         if (!allow_F) goto decode_noF;
+         if (dis_fp_load( theInstr )) goto decode_success;
+         goto decode_failure;
+
       /* AltiVec instructions */
 
       /* AV Cache Control - Data streams */
@@ -9495,6 +11388,26 @@ DisResult disInstr_PPC_WRK (
          if (dis_av_store( theInstr )) goto decode_success;
          goto decode_failure;
 
+      /* VSX Load */
+      case 0x24C: // lxsdx
+      case 0x34C: // lxvd2x
+      case 0x14C: // lxvdsx
+      case 0x30C: // lxvw4x
+         if (dis_vx_load( theInstr )) goto decode_success;
+          goto decode_failure;
+
+      /* VSX Store */
+      case 0x2CC: // stxsdx
+      case 0x3CC: // stxvd2x
+      case 0x38C: // stxvw4x
+         if (dis_vx_store( theInstr )) goto decode_success;
+         goto decode_failure;
+
+      /* Miscellaneous ISA 2.06 instructions */
+      case 0x1FA: // popcntd
+         if (dis_int_logic( theInstr )) goto decode_success;
+         goto decode_failure;
+
       default:
          /* Deal with some other cases that we would otherwise have
             punted on. */
@@ -9680,6 +11593,10 @@ DisResult disInstr_PPC_WRK (
       vassert(!allow_V);
       vex_printf("disInstr(ppc): declined to decode an AltiVec insn.\n");
       goto decode_failure;
+   decode_noVX:
+      vassert(!allow_VX);
+      vex_printf("disInstr(ppc): declined to decode a VSX insn.\n");
+      goto decode_failure;
    decode_noFX:
       vassert(!allow_FX);
       vex_printf("disInstr(ppc): "
@@ -9762,10 +11679,10 @@ DisResult disInstr_PPC ( IRSB*        irsb_IN,
 
    /* do some sanity checks */
    mask32 = VEX_HWCAPS_PPC32_F | VEX_HWCAPS_PPC32_V
-            | VEX_HWCAPS_PPC32_FX | VEX_HWCAPS_PPC32_GX;
+            | VEX_HWCAPS_PPC32_FX | VEX_HWCAPS_PPC32_GX | VEX_HWCAPS_PPC32_VX;
 
-   mask64 = VEX_HWCAPS_PPC64_V
-            | VEX_HWCAPS_PPC64_FX | VEX_HWCAPS_PPC64_GX;
+   mask64 = VEX_HWCAPS_PPC64_V | VEX_HWCAPS_PPC64_FX
+                  | VEX_HWCAPS_PPC64_GX | VEX_HWCAPS_PPC64_VX;
 
    if (mode64) {
       vassert((hwcaps_guest & mask32) == 0);